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