Windows: roken.h ordering
[openafs.git] / src / WINNT / afssvrmgr / window.cpp
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <winsock2.h>
11 #include <ws2tcpip.h>
12
13 extern "C" {
14 #include <afsconfig.h>
15 #include <afs/param.h>
16 #include <roken.h>
17 }
18
19 #include "svrmgr.h"
20 #include <shellapi.h>
21 #include "display.h"
22 #include "command.h"
23 #include "messages.h"
24 #include "svr_window.h"
25 #include "svr_general.h"
26 #include "svr_security.h"
27 #include "set_repprop.h"
28 #include "set_createrep.h"
29 #include "set_rename.h"
30 #include "columns.h"
31 #include "propcache.h"
32 #include "action.h"
33 #include "creds.h"
34
35
36 /*
37  * RESIZING WINDOWS ___________________________________________________________
38  *
39  */
40
41 #define cxMIN_SERVER   75
42 #define cyMIN_SERVER   70
43
44 #define cxMIN_TABS    100
45 #define cyMIN_TABS    100
46
47 #define cxMIN_WINDOW_PREVIEW  220
48 #define cyMIN_WINDOW_PREVIEW  250
49
50 #define cxMIN_WINDOW  120
51 #define cyMIN_WINDOW  120
52
53 rwWindowData awdMain[] = {
54     { IDC_CELL_BORDER, raSizeX,                 0,      0 },
55     { IDC_CELL,        raSizeX | raRepaint,     0,      0 },
56     { IDC_AFS_ID,      raSizeX | raRepaint,     0,      0 },
57     { IDC_SERVERS,     raSizeX | raSizeY,       MAKELONG(cxMIN_SERVER,cyMIN_SERVER), 0 },
58     { IDC_COVERDLG,    raSizeX | raSizeY,       0,      0 },
59     { IDC_ANIMATE,     raMoveX,                 0,      0 },
60     { idENDLIST,       0,                       0,      0 }
61  };
62
63 rwWindowData awdMainVert[] = {
64     { IDC_CELL_BORDER,     raSizeX,             0,      0 },
65     { IDC_CELL,            raSizeX | raRepaint, 0,      0 },
66     { IDC_AFS_ID,          raSizeX | raRepaint, 0,      0 },
67     { IDC_SERVERS,         raSizeX,             MAKELONG(cxMIN_SERVER,cyMIN_SERVER), 0 },
68     { IDC_SPLITTER_SERVER, raSizeX,             0,      0 },
69     { IDC_TABS,            raSizeX | raSizeY, MAKELONG(cxMIN_TABS,cyMIN_TABS), 0 },
70     { IDC_COVERDLG,        raSizeX,             0,      0 },
71     { IDC_ANIMATE,         raMoveX,             0,      0 },
72     { idENDLIST,           0,                   0,      0  }
73  };
74
75 rwWindowData awdMainHorz[] = {
76     { IDC_CELL_BORDER,     raSizeX,                     0,      0 },
77     { IDC_CELL,            raSizeX  | raRepaint,        0,      0 },
78     { IDC_AFS_ID,          raSizeX  | raRepaint,        0,      0 },
79     { IDC_SERVERS,         raSizeY,                     MAKELONG(cxMIN_SERVER,cyMIN_SERVER), 0 },
80     { IDC_SPLITTER_SERVER, raSizeY,                     0,      0 },
81     { IDC_TABS,            raSizeX | raSizeY,           MAKELONG(cxMIN_TABS,cyMIN_TABS), 0 },
82     { IDC_COVERDLG,        raSizeY,                     0,      0 },
83     { IDC_ANIMATE,         raMoveX,                     0,      0 },
84     { idENDLIST,           0,                           0,      0 }
85  };
86
87 rwWindowData awdSplitServer[] = {
88     { IDC_CELL,            raRepaint,                   0,      0 },
89     { IDC_AFS_ID,          raRepaint,                   0,      0 },
90     { IDC_SERVERS,         raSizeX | raSizeY,           MAKELONG(cxMIN_SERVER,cyMIN_SERVER), 0 },
91     { IDC_SPLITTER_SERVER, raMoveX | raMoveY,           0,      0 },
92     { IDC_TABS,            raMoveX | raMoveY | raSizeXB | raSizeYB, MAKELONG(cxMIN_TABS,cyMIN_TABS), 0 },
93     { IDC_COVERDLG,        raSizeX | raSizeY,           0,      0 },
94     { IDC_ANIMATE,         0,                           0,      0 },
95     { idENDLIST,           0,                           0,      0 }
96  };
97
98
99 /*
100  * PROTOTYPES _________________________________________________________________
101  *
102  */
103
104 void Main_OnNotifyFromDispatch (LPNOTIFYSTRUCT lpns);
105
106 void Main_OnPreviewPane (BOOL fPreviewNew, BOOL fVertNew, BOOL fStoreView);
107 DWORD WINAPI Main_OnOpenServers_ThreadProc (PVOID lp);
108
109 void Main_SubclassServers (HWND hDlg);
110
111 void Main_CreateTabControl (void);
112 void Main_DeleteTabControl (void);
113 void Main_DisplayTab (CHILDTAB iTab);
114 void Main_RearrangeChildren (BOOL fSplitNew, BOOL fVertNew);
115
116 BOOL Main_HandleDialogKeys (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp);
117 void Main_OnKey_CtrlTab (BOOL fForward);
118 void Main_OnKey_Tab (BOOL fForward);
119
120 #ifdef DEBUG
121 void ExportCell (void);
122 #endif
123
124
125 /*
126  * ROUTINES ___________________________________________________________________
127  *
128  */
129
130
131 static BOOL fEnforceMinimumSize = TRUE;
132 static BOOL fNotifyChildrenForResize = TRUE;
133 static LONG nReqWorking = 0;
134 static int  iFrameLast = 0;
135
136 BOOL CALLBACK Main_DialogProc (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
137 {
138    if (HandleColumnNotify (hDlg, msg, wp, lp, (gr.fPreview && !gr.fVert) ? &gr.diHorz.viewSvr : &gr.diVert.viewSvr))
139       return FALSE;
140
141    if (Main_HandleDialogKeys (hDlg, msg, wp, lp))
142       return TRUE;
143
144    if (msg == WM_INITDIALOG)    // get this out of the way.  :)
145       {
146       g.hMain = hDlg;
147       AfsAppLib_SetMainWindow (g.hMain);
148       }
149
150    switch (msg)
151       {
152       case WM_INITDIALOG:
153          {
154          LPRECT prTarget = (gr.fPreview) ? &gr.rMainPreview : &gr.rMain;
155          if (prTarget->right == 0)
156             GetWindowRect (g.hMain, prTarget);
157          ResizeWindow (g.hMain, awdMain, rwaMoveToHere, prTarget);
158
159          Main_SetActionMenus();
160
161          // Subclass the Servers window, so we can watch for focus changes
162          // and context-menu requests
163          //
164          Main_SubclassServers (hDlg);
165          FastList_SetTextCallback (GetDlgItem (hDlg, IDC_SERVERS), GetItemText, ((gr.fPreview && !gr.fVert) ? &gr.diHorz.viewSvr : &gr.diVert.viewSvr));
166
167          // Create the preview pane and rearrange the children of this dialog.
168          // This also fixes the Servers display--was it in Large Icons view?
169          // What columns were shown?
170          //
171          Main_OnPreviewPane (gr.fPreview, gr.fVert, FALSE);
172
173          // Tell our notification dispatcher to let this window know whenever
174          // a cell gets opened or closed (that's what the NULL does--otherwise,
175          // an LPIDENT would go there to indicate we're interested in a
176          // particular server etc).
177          //
178          NotifyMe (WHEN_CELL_OPENED, NULL, hDlg, 0); // tell me about any cell
179
180          // If we weren't around when the cell was created, we might have
181          // missed some notifications.  Send a redraw just in case.
182          //
183          StartThread (Main_Redraw_ThreadProc, FALSE);
184
185          SetTimer (hDlg, ID_DISPATCH_TIMER, 200, NULL); // do all notifications
186          }
187          break;
188
189       case WM_DESTROY:
190          KillTimer (hDlg, ID_DISPATCH_TIMER);
191          break;
192
193       case WM_QUERYENDSESSION:
194          if (Action_fAnyActive())
195             {
196             ShowWindow (g.hMain, SW_SHOW);
197             if (Message (MB_ICONHAND | MB_YESNO, IDS_CANT_QUIT_TITLE, IDS_CANT_QUIT_REBOOT) != IDYES)
198                return TRUE;
199             }
200          break;
201
202       case WM_TIMER:
203          if (wp == ID_DISPATCH_TIMER)
204             {
205             DispatchNotification_OnPump();
206             }
207          break;
208
209       case WM_HELP:
210          if ((lp == 0) || (IsAncestor (g.hMain, (HWND)(((LPHELPINFO)lp)->hItemHandle))))
211             {
212             WinHelp (hDlg, cszHELPFILENAME, HELP_FINDER, 0);
213             }
214          break;
215
216       case WM_NOTIFY_FROM_DISPATCH:
217          Main_OnNotifyFromDispatch ((LPNOTIFYSTRUCT)lp);
218          Delete ((LPNOTIFYSTRUCT)lp);
219          break;
220
221       case WM_ENDTASK:
222          LPTASKPACKET ptp;
223          if ((ptp = (LPTASKPACKET)lp) != NULL)
224             {
225             if (ptp->idTask == taskSVR_GETWINDOWPOS)
226                Server_Open ((LPIDENT)(ptp->lpUser), &TASKDATA(ptp)->rWindow);
227             else if (ptp->idTask == taskSET_REPPROP_INIT)
228                Filesets_OnEndTask_ShowReplication (ptp);
229             else if (ptp->idTask == taskSET_RENAME_INIT)
230                Filesets_OnEndTask_ShowRename (ptp);
231             FreeTaskPacket (ptp);
232             }
233          break;
234
235       case WM_OPEN_SERVERS:
236          StartThread (Main_OnOpenServers_ThreadProc, 0);
237          break;
238
239       case WM_OPEN_SERVER:
240          StartTask (taskSVR_GETWINDOWPOS, g.hMain, (LPIDENT)lp);
241          break;
242
243       case WM_SHOW_CREATEREP_DIALOG:
244          Filesets_CreateReplica ((LPIDENT)wp, (LPIDENT)lp);
245          break;
246
247       case WM_SHOW_YOURSELF:
248          if (lp || g.lpiCell)
249             {
250             ShowWindow (g.hMain, SW_SHOW);
251             BringWindowToTop (g.hMain);
252             Action_WindowToTop (TRUE);
253             }
254          break;
255
256       case WM_OPEN_ACTIONS:
257          Action_OpenWindow();
258          break;
259
260       case WM_REFRESHED_CREDENTIALS:
261          g.hCreds = (UINT_PTR)lp;
262          UpdateDisplay_Cell(FALSE);
263          StartTask (taskREFRESH_CREDS, NULL, g.lpiCell);
264          break;
265
266       case WM_SIZE:
267          // if (lp==0), we're minimizing--don't call ResizeWindow().
268          //
269          Action_WindowToTop ((lp) ? TRUE : FALSE);
270          if (lp != 0)
271             {
272             rwWindowData *pwdResizeInfo;
273
274             if (!gr.fPreview)
275                pwdResizeInfo = awdMain;
276             else if (gr.fVert)
277                pwdResizeInfo = awdMainVert;
278             else // (!gr.fVert)
279                pwdResizeInfo = awdMainHorz;
280
281             if (fNotifyChildrenForResize)
282                ResizeWindow (hDlg, pwdResizeInfo, rwaFixupGuts);
283             else
284                ResizeWindow (hDlg, pwdResizeInfo, rwaJustResync);
285             }
286          break;
287
288       case WM_ACTIVATEAPP:
289          Action_WindowToTop ((wp) ? TRUE : FALSE);
290
291          if (wp)
292             StartTask (taskEXPIRED_CREDS);
293          break;
294
295       case WM_CONTEXTMENU:
296          {
297          POINT ptScreen;
298          POINT ptClient;
299          ptScreen.x = LOWORD(lp);
300          ptScreen.y = HIWORD(lp);
301
302          ptClient = ptScreen;
303          ScreenToClient ((HWND)wp, &ptClient);
304
305          if ((HWND)wp == GetDlgItem (g.hMain, IDC_SERVERS))
306             Server_ShowPopupMenu ((HWND)wp, ptClient, ptScreen);
307          }
308          break;
309
310       case WM_COMMAND:
311          switch (LOWORD(wp))
312             {
313             case IDCANCEL:
314             case M_EXIT:
315                Quit (0);
316                break;
317
318             case M_DIVIDE_NONE:
319                Main_OnPreviewPane (FALSE, gr.fVert, TRUE);
320                UpdateDisplay_Servers (FALSE, NULL, 0);
321                break;
322             case M_DIVIDE_H:
323                Main_OnPreviewPane (TRUE, FALSE, TRUE);
324                UpdateDisplay_Servers (FALSE, NULL, 0);
325                break;
326             case M_DIVIDE_V:
327                Main_OnPreviewPane (TRUE, TRUE, TRUE);
328                UpdateDisplay_Servers (FALSE, NULL, 0);
329                break;
330
331             case M_SVR_VIEW_LARGE:
332                Main_OnServerView (FLS_VIEW_LARGE);
333                break;
334             case M_SVR_VIEW_SMALL:
335                Main_OnServerView (FLS_VIEW_SMALL);
336                break;
337             case M_SVR_VIEW_REPORT:
338                Main_OnServerView (FLS_VIEW_LIST);
339                break;
340
341             case M_COLUMNS:
342                if (!gr.fPreview)
343                   ShowColumnsDialog (hDlg, NULL);
344                else
345                   {
346                   CHILDTAB iTab = Server_GetDisplayedTab (g.hMain);
347                   if (iTab == tabSERVICES)
348                      ShowColumnsDialog (hDlg, &gr.viewSvc);
349                   else if (iTab == tabAGGREGATES)
350                      ShowColumnsDialog (hDlg, &gr.viewAgg);
351                   else if (iTab == tabFILESETS)
352                      ShowColumnsDialog (hDlg, &gr.viewSet);
353                   else
354                      ShowColumnsDialog (hDlg, NULL);
355                   }
356                break;
357
358             case M_ACTIONS:
359                if ((gr.fActions = !gr.fActions) == TRUE)
360                   Action_OpenWindow();
361                else
362                   Action_CloseWindow();
363                Main_SetActionMenus();
364                break;
365
366 #ifdef DEBUG
367             case M_EXPORT:
368                ExportCell();
369                break;
370 #endif
371
372             case IDC_COVER_BUTTON:
373                // The user must have clicked the "Try Again" or "Credentials"
374                // button on the cover we placed over the Servers list.
375                // Refresh the cell or obtain new credentials, as appropriate.
376                //
377                if (g.lpiCell)
378                   {
379                   TCHAR szButton[ cchRESOURCE ];
380                   GetWindowText ((HWND)lp, szButton, cchRESOURCE);
381
382                   TCHAR szTest[ cchRESOURCE ];
383
384                   GetString (szTest, IDS_ALERT_BUTTON_TRYAGAIN);
385                   if (!lstrcmp (szTest, szButton))
386                      {
387                      StartTask (taskREFRESH, NULL, g.lpiCell);
388                      break;
389                      }
390
391                   GetString (szTest, IDS_ALERT_BUTTON_GETCREDS);
392                   if (!lstrcmp (szTest, szButton))
393                      {
394                      NewCredsDialog();
395                      break;
396                      }
397                   }
398                break;
399
400             default:
401                StartContextCommand (g.hMain, NULL, NULL, LOWORD(wp));
402                break;
403             }
404          break;
405
406       case WM_NOTIFY:
407          switch (((LPNMHDR)lp)->code)
408             {
409             case TCN_SELCHANGE:
410                {
411                int iPage = TabCtrl_GetCurSel (GetDlgItem (g.hMain, IDC_TABS));
412                Main_DisplayTab ((CHILDTAB)iPage);
413                }
414                break;
415
416             case FLN_ITEMSELECT:
417                if (gr.fPreview)
418                   {
419                   HWND hServers = GetDlgItem (hDlg, IDC_SERVERS);
420                   LPIDENT lpi = (LPIDENT)FL_GetSelectedData (hServers);
421
422                   Server_SelectServer (SERVERWINDOW_PREVIEWPANE, lpi);
423                   }
424                break;
425
426             case FLN_LDBLCLICK:
427                {
428                HWND hServers = GetDlgItem (g.hMain, IDC_SERVERS);
429
430                if (((LPNMHDR)lp)->hwndFrom == hServers)
431                   {
432                   LPIDENT lpi = (LPIDENT)FL_GetSelectedData (hServers);
433
434                   if (lpi && lpi->fIsServer())
435                      {
436                      BOOL fOpenWindow;
437
438                      if (gr.fDoubleClickOpens == 0)
439                         fOpenWindow = FALSE;
440                      else if (gr.fDoubleClickOpens == 1)
441                         fOpenWindow = TRUE;
442                      else if (gr.fPreview)
443                         fOpenWindow = FALSE;
444                      else // (!gr.Preview)
445                         fOpenWindow = TRUE;
446
447                      if (!fOpenWindow)
448                         {
449                         PostMessage (hServers, WM_COMMAND, M_PROPERTIES, 0);
450                         }
451                      else // (fOpenWindow)
452                         {
453                         PostMessage (g.hMain, WM_OPEN_SERVER, 0, (LPARAM)lpi);
454                         }
455                      }
456                   }
457                }
458                break;
459             }
460          break;
461       }
462
463    return FALSE;
464 }
465
466
467 void Main_OnNotifyFromDispatch (LPNOTIFYSTRUCT lpns)
468 {
469    switch (lpns->evt)
470       {
471       case evtCreate:
472          StartTask (taskOPENEDCELL, NULL, lpns->Params.lpi1);
473          break;
474
475       case evtDestroy:
476          StartTask (taskCLOSEDCELL, NULL, lpns->Params.lpi1);
477          break;
478
479       case evtRefreshStatusEnd:
480       case evtAlertsChanged:
481          if (lpns->Params.lpi1 && lpns->Params.lpi1->fIsCell())
482             {
483             UpdateDisplay_Cell (FALSE);
484             }
485          else if (lpns->Params.lpi1 && lpns->Params.lpi1->fIsServer())
486             {
487             UpdateDisplay_Servers (FALSE, lpns->Params.lpi1, lpns->Params.status);
488             }
489          break;
490
491       case evtRefreshServersEnd:
492          if (g.lpiCell || lpns->Params.status == 0)
493             {
494             UpdateDisplay_Servers (FALSE, NULL, 0);
495             }
496          break;
497       }
498 }
499
500
501 DWORD WINAPI Main_OnOpenServers_ThreadProc (PVOID lp)
502 {
503    AfsClass_Enter();
504
505    if (g.lpiCell != NULL)
506       {
507       LPCELL lpCell;
508       if ((lpCell = g.lpiCell->OpenCell()) != NULL)
509          {
510          HENUM hEnum;
511          for (LPSERVER lpServer = lpCell->ServerFindFirst (&hEnum); lpServer; lpServer = lpCell->ServerFindNext (&hEnum))
512             {
513             LPSERVER_PREF lpsp;
514             if ((lpsp = (LPSERVER_PREF)lpServer->GetUserParam()) != NULL)
515                {
516                if (lpsp->fOpen && !PropCache_Search (pcSERVER, lpServer->GetIdentifier()))
517                   {
518                   PostMessage (g.hMain, WM_OPEN_SERVER, 0, (LPARAM)(lpServer->GetIdentifier()));
519                   }
520                }
521             lpServer->Close();
522             }
523          lpCell->Close();
524          }
525       }
526
527    AfsClass_Leave();
528    return 0;
529 }
530
531
532 DWORD WINAPI Main_Redraw_ThreadProc (PVOID lp)
533 {
534    BOOL fInvalidate = (BOOL)(UINT_PTR)lp;
535    AfsClass_Enter();
536
537    if (g.lpiCell == NULL)
538       {
539       AfsAppLib_Uncover (GetDlgItem (g.hMain, IDC_SERVERS));
540       }
541    else
542       {
543       TCHAR szName[ cchRESOURCE ];
544       g.lpiCell->GetCellName (szName);
545
546       LPTSTR pszCover = FormatString (IDS_SEARCHING_FOR_SERVERS, TEXT("%s"), szName);
547       AfsAppLib_CoverWindow (GetDlgItem (g.hMain, IDC_SERVERS), pszCover);
548       FreeString (pszCover);
549       }
550
551    LPCELL lpCell = NULL;
552    if (g.lpiCell != NULL)
553       lpCell = g.lpiCell->OpenCell();
554
555    if (lpCell)
556       {
557       if (fInvalidate)
558          {
559          lpCell->Invalidate();
560          lpCell->RefreshAll();
561          }
562       else
563          {
564          lpCell->RefreshStatus();
565          lpCell->RefreshServers();
566          }
567       }
568    else // no cell is selected; we'll have to redraw the window directly.
569       {
570       UpdateDisplay_Cell (TRUE);
571       UpdateDisplay_Servers (TRUE, NULL, 0);
572       }
573
574    if (lpCell != NULL)
575       lpCell->Close();
576
577    AfsClass_Leave();
578    return 0;
579 }
580
581
582 void Main_OnPreviewPane (BOOL fPreviewNew, BOOL fVertNew, BOOL fStoreCurrentView)
583 {
584    if (fStoreCurrentView)
585       {
586       if (gr.fPreview && !gr.fVert)
587          FL_StoreView (GetDlgItem (g.hMain, IDC_SERVERS), &gr.diHorz.viewSvr);
588       else
589          FL_StoreView (GetDlgItem (g.hMain, IDC_SERVERS), &gr.diVert.viewSvr);
590
591       if (gr.fPreview)
592          GetWindowRect (g.hMain, &gr.rMainPreview);
593       else
594          GetWindowRect (g.hMain, &gr.rMain);
595       }
596
597    // If switching from having a preview pane to not (or vice-versa),
598    // and we have an alterate gr.rMain* to switch to, resize the window.
599    //
600    if (IsWindowVisible (g.hMain))
601       {
602       RECT rNow;
603       GetWindowRect (g.hMain, &rNow);
604
605       LPRECT prTarget = (fPreviewNew) ? &gr.rMainPreview : &gr.rMain;
606       if (prTarget->right == 0)
607          {
608          *prTarget = rNow;
609          if (gr.fPreview && gr.fVert) // preview pane exists below main window?
610             {
611             RECT rPreview;
612             GetWindowRect (GetDlgItem (g.hMain, IDC_TABS), &rPreview);
613             if (gr.fVert)
614                prTarget->bottom -= cyRECT(rPreview);
615             }
616          }
617       prTarget->right = prTarget->left + cxRECT(rNow); // keep the same width!
618
619       fEnforceMinimumSize = FALSE;
620       fNotifyChildrenForResize = FALSE;
621
622       SetWindowPos (g.hMain, NULL,
623                     0, 0, cxRECT(*prTarget), cyRECT(*prTarget),
624                     SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
625
626       fNotifyChildrenForResize = TRUE;
627       fEnforceMinimumSize = TRUE;
628       }
629
630    // Create a tab control if necessary, or remove it if it should be gone.
631    //
632    if (fPreviewNew && !GetDlgItem (g.hMain, IDC_TABS))
633       {
634       Main_CreateTabControl();
635       }
636    if (!fPreviewNew && GetDlgItem (g.hMain, IDC_TABS))
637       {
638       Main_DeleteTabControl();
639       }
640
641    // If there's a tab control, we'll need a splitter; if not, not.
642    //
643    if (GetDlgItem (g.hMain, IDC_SPLITTER_SERVER))
644       {
645       DeleteSplitter (g.hMain, IDC_SPLITTER_SERVER);
646       }
647
648    Main_RearrangeChildren (fPreviewNew, fVertNew);
649
650    if (fPreviewNew)
651       {
652       CreateSplitter (g.hMain, IDC_SERVERS, IDC_TABS, IDC_SPLITTER_SERVER,
653                       (fVertNew) ? &gr.diVert.cSplitter : &gr.diHorz.cSplitter,
654                       awdSplitServer,
655                       TRUE);
656       }
657
658    if (GetDlgItem (g.hMain, IDC_TABS))
659       {
660       ShowWindow (GetDlgItem (g.hMain, IDC_TABS), SW_SHOW);
661       }
662
663    LPVIEWINFO lpvi = (fPreviewNew && !fVertNew) ? &gr.diHorz.viewSvr : &gr.diVert.viewSvr;
664
665    FL_RestoreView (GetDlgItem (g.hMain, IDC_SERVERS), lpvi);
666
667    CheckMenuRadioItem (GetMenu (g.hMain),
668                        M_DIVIDE_NONE, M_DIVIDE_H,
669                        ( (!fPreviewNew) ? M_DIVIDE_NONE :
670                              (fVertNew) ? M_DIVIDE_V :
671                                           M_DIVIDE_H ),
672                        MF_BYCOMMAND);
673
674    gr.fVert = fVertNew;
675    gr.fPreview = fPreviewNew;
676
677    Main_SetServerViewMenus();
678 }
679
680
681 void Main_OnServerView (int lvsNew)
682 {
683    HWND hServers = GetDlgItem (g.hMain, IDC_SERVERS);
684
685    if (gr.fPreview && !gr.fVert)
686       FL_StoreView (hServers, &gr.diHorz.viewSvr);
687    else
688       FL_StoreView (hServers, &gr.diVert.viewSvr);
689
690    if (gr.fPreview && !gr.fVert)
691       gr.diHorz.viewSvr.lvsView = lvsNew;
692    else
693       gr.diVert.viewSvr.lvsView = lvsNew;
694
695    if (gr.fPreview && !gr.fVert)
696       FL_RestoreView (hServers, &gr.diHorz.viewSvr);
697    else
698       FL_RestoreView (hServers, &gr.diVert.viewSvr);
699
700    Main_SetServerViewMenus();
701    FastList_SetTextCallback (GetDlgItem (g.hMain, IDC_SERVERS), GetItemText, ((gr.fPreview && !gr.fVert) ? &gr.diHorz.viewSvr : &gr.diVert.viewSvr));
702    UpdateDisplay_Servers (FALSE, NULL, 0);
703 }
704
705
706 void Main_SetServerViewMenus (void)
707 {
708    LONG lvs;
709
710    if (gr.fPreview && !gr.fVert)
711       lvs = gr.diHorz.viewSvr.lvsView;
712    else
713       lvs = gr.diVert.viewSvr.lvsView;
714
715    CheckMenuRadioItem (GetMenu (g.hMain),
716                        M_SVR_VIEW_LARGE, M_SVR_VIEW_REPORT,
717                        ( (lvs == FLS_VIEW_SMALL) ? M_SVR_VIEW_SMALL :
718                          (lvs == FLS_VIEW_LIST)  ? M_SVR_VIEW_REPORT :
719                                                    M_SVR_VIEW_LARGE ),
720                        MF_BYCOMMAND);
721
722    ICONVIEW ivSvr = Display_GetServerIconView();
723
724    CheckMenuRadioItem (GetMenu (g.hMain),
725                        M_SVR_VIEW_ONEICON, M_SVR_VIEW_STATUS,
726                        (ivSvr == ivTWOICONS) ? M_SVR_VIEW_TWOICONS :
727                        (ivSvr == ivONEICON)  ? M_SVR_VIEW_ONEICON : M_SVR_VIEW_STATUS,
728                        MF_BYCOMMAND);
729
730    EnableMenu (GetMenu (g.hMain), M_SVR_VIEW_ONEICON,  (lvs == FLS_VIEW_LIST) ? TRUE : FALSE);
731    EnableMenu (GetMenu (g.hMain), M_SVR_VIEW_TWOICONS, (lvs == FLS_VIEW_LIST) ? TRUE : FALSE);
732    EnableMenu (GetMenu (g.hMain), M_SVR_VIEW_STATUS,   (lvs == FLS_VIEW_LIST) ? TRUE : FALSE);
733 }
734
735
736 void Main_SetActionMenus (void)
737 {
738    CheckMenu (GetMenu (g.hMain), M_ACTIONS, gr.fActions);
739 }
740
741
742 void Main_CreateTabControl (void)
743 {
744    HWND hTab = CreateWindowEx (WS_EX_CLIENTEDGE,
745                                WC_TABCONTROL,
746                                TEXT(""),
747                                WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP,
748                                0, 0, 128, 128,   // arbitrary, but not too small
749                                SERVERWINDOW_PREVIEWPANE,
750                                (HMENU)IDC_TABS,
751                                THIS_HINST,
752                                NULL);
753
754    if (hTab != NULL)
755       {
756       HFONT hf = (HFONT)GetStockObject (DEFAULT_GUI_FONT);
757       SendMessage (hTab, WM_SETFONT, (WPARAM)hf, MAKELPARAM(TRUE,0));
758
759       Server_PrepareTabControl (hTab);
760
761       LPIDENT lpi = (LPIDENT)FL_GetSelectedData (GetDlgItem (g.hMain, IDC_SERVERS));
762       Server_SelectServer (SERVERWINDOW_PREVIEWPANE, lpi);
763       }
764 }
765
766
767 void Main_DeleteTabControl (void)
768 {
769    if (GetDlgItem (SERVERWINDOW_PREVIEWPANE, IDC_TABS))
770       {
771       DestroyWindow (GetDlgItem (SERVERWINDOW_PREVIEWPANE, IDC_TABS));
772       }
773 }
774
775
776 void Main_DisplayTab (CHILDTAB iTab)
777 {
778    if (gr.fPreview)
779       {
780       Server_DisplayTab (SERVERWINDOW_PREVIEWPANE, iTab);
781       gr.tabLast = (CHILDTAB)iTab;
782       }
783 }
784
785
786 void Main_RearrangeChildren (BOOL fPreviewNew, BOOL fVertNew)
787 {
788    RECT rServers;
789    RECT rPreview;
790
791    // Start with the Servers window taking up the entire dialog's client area,
792    // leaving a space at the top for the cell combobox.
793    //
794    RECT rCell;
795    GetRectInParent (GetDlgItem (g.hMain, IDC_AFS_ID), &rCell);
796
797    GetClientRect (g.hMain, &rServers);
798    rServers.top = rCell.bottom +3;
799
800    // Then, if the preview tab is to be displayed, make the server window
801    // share the space equally with the tab control (vertically or horizontally)
802    //
803    if (fPreviewNew)
804       {
805       rPreview = rServers;
806
807       if (fVertNew)
808          {
809          rServers.bottom = rServers.top + cyRECT(rServers)/2 - 1;
810          rPreview.top = rServers.bottom + 2;
811          }
812       else
813          {
814          rServers.right = rServers.left + cxRECT(rServers)/2 - 1;
815          rPreview.left = rServers.right + 2;
816          }
817
818       // Adjust the server/tab windows for the Server splitter's position
819       //
820       if (fVertNew)
821          {
822          LONG cyMod = gr.diVert.cSplitter;
823
824          if (cyRECT(rServers) > cyMIN_SERVER)
825             cyMod = min( cyMod, cyRECT(rServers)-cyMIN_SERVER );
826          if (cyRECT(rPreview) > cyMIN_TABS)
827             cyMod = min( cyMod, cyRECT(rPreview)-cyMIN_TABS );
828
829          rServers.bottom += cyMod;
830          rPreview.top += cyMod;
831          }
832       else
833          {
834          LONG cxMod = gr.diHorz.cSplitter;
835
836          if (cxRECT(rServers) > cxMIN_SERVER)
837             cxMod = min( cxMod, cxRECT(rServers)-cxMIN_SERVER );
838          if (cxRECT(rPreview) > cxMIN_TABS)
839             cxMod = min( cxMod, cxRECT(rPreview)-cxMIN_TABS );
840
841          rServers.right += cxMod;
842          rPreview.left += cxMod;
843          }
844       }
845
846    // Now move the children to their new places!
847    //
848    int nWindows = 1;
849    if (GetDlgItem (g.hMain, IDC_COVERDLG))
850       ++nWindows;
851    if (GetDlgItem (g.hMain, IDC_TABS))
852       ++nWindows;
853    HDWP dwp = BeginDeferWindowPos (nWindows);
854
855    DeferWindowPos (dwp, GetDlgItem (g.hMain, IDC_SERVERS), NULL,
856                    rServers.left, rServers.top,
857                    cxRECT(rServers), cyRECT(rServers),
858                    SWP_NOACTIVATE | SWP_NOZORDER);
859
860    if (GetDlgItem (g.hMain, IDC_COVERDLG))
861       {
862       DeferWindowPos (dwp, GetDlgItem (g.hMain, IDC_COVERDLG), NULL,
863                       rServers.left, rServers.top,
864                       cxRECT(rServers), cyRECT(rServers),
865                       SWP_NOACTIVATE | SWP_NOZORDER);
866       }
867
868    if (GetDlgItem (g.hMain, IDC_TABS))
869       {
870       DeferWindowPos (dwp, GetDlgItem (g.hMain, IDC_TABS), NULL,
871                       rPreview.left, rPreview.top,
872                       cxRECT(rPreview), cyRECT(rPreview),
873                       SWP_NOACTIVATE | SWP_NOZORDER);
874       }
875
876    EndDeferWindowPos (dwp);
877 }
878
879
880
881 static LONG_PTR procServers = 0;
882
883 LRESULT CALLBACK Main_SubclassServersProc (HWND hServers, UINT msg, WPARAM wp, LPARAM lp)
884 {
885    LRESULT rc;
886
887    if (procServers == 0)
888       rc = DefWindowProc (hServers, msg, wp, lp);
889    else
890       rc = (LRESULT) CallWindowProc ((WNDPROC)procServers, hServers, msg, wp, lp);
891
892    switch (msg)
893       {
894       case WM_DESTROY:
895          if (procServers != 0)
896             SetWindowLongPtr (hServers, GWLP_WNDPROC, procServers);
897          break;
898
899       case WM_COMMAND:
900          switch (LOWORD(wp))
901             {
902             case M_SVR_VIEW_LARGE:
903             case M_SVR_VIEW_SMALL:
904             case M_SVR_VIEW_REPORT:
905                SendMessage (g.hMain, msg, wp, lp);
906                break;
907
908             case M_VIEW_ONEICON:
909             case M_VIEW_TWOICONS:
910             case M_VIEW_STATUS:
911                SendMessage (g.hMain, msg, wp, lp);
912                break;
913
914             case M_COLUMNS:
915                ShowColumnsDialog (g.hMain, NULL);
916                break;
917
918             default:
919                StartContextCommand (g.hMain,
920                                     NULL,
921                                     (LPIDENT)FL_GetSelectedData (hServers),
922                                     LOWORD(wp));
923                break;
924             }
925          break;
926       }
927
928    return rc;
929 }
930
931
932 void Main_SubclassServers (HWND hDlg)
933 {
934    HWND hServers = GetDlgItem (hDlg, IDC_SERVERS);
935    procServers = GetWindowLongPtr (hServers, GWLP_WNDPROC);
936    SetWindowLongPtr (hServers, GWLP_WNDPROC, (LONG_PTR)Main_SubclassServersProc);
937 }
938
939
940 #ifdef DEBUG
941 void ExportCell (void)
942 {
943    if (!g.lpiCell)
944       return;
945
946    TCHAR szFilter[ cchRESOURCE ];
947    lstrcpy (szFilter, TEXT("Text File|*.TXT|"));
948    TCHAR chFilter = szFilter[ lstrlen(szFilter)-1 ];
949    for (LPTSTR pszFilter = szFilter;
950         (*pszFilter) && ((pszFilter = (LPTSTR)lstrchr (pszFilter, chFilter)) != NULL);
951         ++pszFilter)
952       {
953       *pszFilter = TEXT('\0');
954       }
955
956    TCHAR szSaveAs[ MAX_PATH ] = TEXT("export");
957
958    OPENFILENAME sfn;
959    memset (&sfn, 0x00, sizeof(sfn));
960    sfn.lStructSize = sizeof(sfn);
961    sfn.hwndOwner = g.hMain;
962    sfn.hInstance = THIS_HINST;
963    sfn.lpstrFilter = szFilter;
964    sfn.nFilterIndex = 1;
965    sfn.lpstrFile = szSaveAs;
966    sfn.nMaxFile = MAX_PATH;
967    sfn.Flags = OFN_HIDEREADONLY | OFN_NOREADONLYRETURN |
968                OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST;
969    sfn.lpstrDefExt = TEXT("txt");
970
971    if (GetSaveFileName (&sfn))
972       {
973       LPTSTR psz = CloneString (szSaveAs);
974       StartTask (taskEXPORTCELL, NULL, psz);
975       }
976 }
977 #endif
978
979
980 void Main_StartWorking (void)
981 {
982    if (InterlockedIncrement(&nReqWorking) == 1)
983       {
984       AfsAppLib_StartAnimation (GetDlgItem (g.hMain, IDC_ANIMATE));
985       }
986 }
987
988 void Main_StopWorking (void)
989 {
990    if (InterlockedDecrement(&nReqWorking) == 0)
991       {
992       AfsAppLib_StopAnimation (GetDlgItem (g.hMain, IDC_ANIMATE));
993       }
994 }
995
996
997 void Main_AnimateIcon (HWND hIcon, int *piFrameLast)
998 {
999    static HICON hiStop;
1000    static HICON hiFrame[8];
1001    static BOOL fLoaded = FALSE;
1002
1003    if (!fLoaded)
1004       {
1005       hiStop     = TaLocale_LoadIcon (IDI_SPINSTOP);
1006       hiFrame[0] = TaLocale_LoadIcon (IDI_SPIN1);
1007       hiFrame[1] = TaLocale_LoadIcon (IDI_SPIN2);
1008       hiFrame[2] = TaLocale_LoadIcon (IDI_SPIN3);
1009       hiFrame[3] = TaLocale_LoadIcon (IDI_SPIN4);
1010       hiFrame[4] = TaLocale_LoadIcon (IDI_SPIN5);
1011       hiFrame[5] = TaLocale_LoadIcon (IDI_SPIN6);
1012       hiFrame[6] = TaLocale_LoadIcon (IDI_SPIN7);
1013       hiFrame[7] = TaLocale_LoadIcon (IDI_SPIN8);
1014       fLoaded = TRUE;
1015       }
1016
1017    if (piFrameLast)
1018       {
1019       *piFrameLast = (*piFrameLast == 7) ? 0 : (1+*piFrameLast);
1020       }
1021
1022    SendMessage (hIcon, STM_SETICON, (WPARAM)((piFrameLast) ? hiFrame[ *piFrameLast ] : hiStop), 0);
1023 }
1024
1025
1026 BOOL Main_HandleDialogKeys (HWND hDlg, UINT msg, WPARAM wp, LPARAM lp)
1027 {
1028    if (msg == WM_COMMAND)
1029       {
1030       switch (LOWORD(wp))
1031          {
1032          case M_KEY_RETURN:
1033             Server_OnKey_Return();
1034             return TRUE;
1035
1036          case M_KEY_CTRLTAB:
1037             Main_OnKey_CtrlTab (TRUE);
1038             return TRUE;
1039
1040          case M_KEY_CTRLBACKTAB:
1041             Main_OnKey_CtrlTab (FALSE);
1042             return TRUE;
1043
1044          case M_KEY_TAB:
1045             Main_OnKey_Tab (TRUE);
1046             return TRUE;
1047
1048          case M_KEY_BACKTAB:
1049             Main_OnKey_Tab (FALSE);
1050             return TRUE;
1051
1052          case M_KEY_MENU:
1053             Server_OnKey_Menu();
1054             return TRUE;
1055
1056          case M_KEY_ESC:
1057              Server_OnKey_Esc();
1058             return TRUE;
1059
1060          case M_KEY_PROPERTIES:
1061             Server_OnKey_Properties();
1062             return TRUE;
1063          }
1064       }
1065
1066    return FALSE;
1067 }
1068
1069
1070 void Main_OnKey_Tab (BOOL fForward)
1071 {
1072    // The tab-cycle should go:
1073    //    ServerList <-> TabsOnQuickViewPane <-> TabChildControls
1074    //
1075    // If the quick-view pane isn't showing, there's nowhere to tab to.
1076    //
1077    if (gr.fPreview)
1078       {
1079       HWND hFocus = GetFocus();
1080       HWND hTabChild = GetTabChild (GetDlgItem (g.hMain, IDC_TABS));
1081
1082       if (fForward)
1083          {
1084          if (hFocus == GetDlgItem (g.hMain, IDC_SERVERS))
1085             {
1086             PostMessage (g.hMain, WM_NEXTDLGCTL, (WPARAM)GetDlgItem (g.hMain, IDC_TABS), TRUE);
1087             }
1088          else if (hFocus == GetDlgItem (g.hMain, IDC_TABS))
1089             {
1090             PostMessage (g.hMain, WM_NEXTDLGCTL, (WPARAM)GetNextDlgTabItem (hTabChild, NULL, FALSE), TRUE);
1091             }
1092          else
1093             {
1094             if (GetNextDlgTabItem (hTabChild, hFocus, FALSE) == GetNextDlgTabItem (hTabChild, NULL, FALSE))
1095                PostMessage (g.hMain, WM_NEXTDLGCTL, (WPARAM)GetDlgItem (g.hMain, IDC_SERVERS), TRUE);
1096             else
1097                PostMessage (g.hMain, WM_NEXTDLGCTL, (WPARAM)GetNextDlgTabItem (hTabChild, hFocus, FALSE), TRUE);
1098             }
1099          }
1100       else // (!fForward)
1101          {
1102          if (hFocus == GetDlgItem (g.hMain, IDC_SERVERS))
1103             {
1104             PostMessage (g.hMain, WM_NEXTDLGCTL, (WPARAM)GetLastDlgTabItem (hTabChild), TRUE);
1105             }
1106          else if (hFocus == GetDlgItem (g.hMain, IDC_TABS))
1107             {
1108             PostMessage (g.hMain, WM_NEXTDLGCTL, (WPARAM)GetDlgItem (g.hMain, IDC_SERVERS), TRUE);
1109             }
1110          else
1111             {
1112             if (hFocus == GetNextDlgTabItem (hTabChild, NULL, FALSE))
1113                PostMessage (g.hMain, WM_NEXTDLGCTL, (WPARAM)GetDlgItem (g.hMain, IDC_TABS), TRUE);
1114             else
1115                PostMessage (g.hMain, WM_NEXTDLGCTL, (WPARAM)GetNextDlgTabItem (hTabChild, hFocus, TRUE), TRUE);
1116             }
1117          }
1118       }
1119 }
1120
1121
1122 void Main_OnKey_CtrlTab (BOOL fForward)
1123 {
1124    if (gr.fPreview)
1125       {
1126       Server_OnKey_CtrlTab (SERVERWINDOW_PREVIEWPANE, fForward);
1127       }
1128 }
1129