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