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