clock: Update Turkish resources.
[wine] / programs / winecfg / driveui.c
1 /*
2  * Drive management UI code
3  *
4  * Copyright 2003 Mark Westcott
5  * Copyright 2004 Chris Morgan
6  * Copyright 2003-2004 Mike Hearn
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  *
22  */
23
24 #include <stdio.h>
25
26 #define WIN32_LEAN_AND_MEAN
27 #define COBJMACROS
28
29 #include <windows.h>
30 #include <shellapi.h>
31 #include <objbase.h>
32 #include <shlguid.h>
33 #include <shlwapi.h>
34 #include <shlobj.h>
35
36 #include <wine/debug.h>
37
38 #include "winecfg.h"
39 #include "resource.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(winecfg);
42
43 #define BOX_MODE_CD_ASSIGN 1
44 #define BOX_MODE_CD_AUTODETECT 2
45 #define BOX_MODE_NONE 3
46 #define BOX_MODE_NORMAL 4
47
48 static BOOL advanced = FALSE;
49 static BOOL updating_ui = FALSE;
50 static struct drive* current_drive;
51
52 static void get_etched_rect(HWND dialog, RECT *rect);
53 static void update_controls(HWND dialog);
54
55 static DWORD driveui_msgbox (HWND parent, UINT messageId, DWORD flags)
56 {
57   WCHAR* caption = load_string (IDS_WINECFG_TITLE);
58   WCHAR* text = load_string (messageId);
59   DWORD result = MessageBoxW (parent, text, caption, flags);
60   HeapFree (GetProcessHeap(), 0, caption);
61   HeapFree (GetProcessHeap(), 0, text);
62   return result;
63 }
64
65 /**** listview helper functions ****/
66
67 /* clears the item at index in the listview */
68 static void lv_clear_curr_select(HWND dialog, int index)
69 {
70     ListView_SetItemState(GetDlgItem(dialog, IDC_LIST_DRIVES), index, 0, LVIS_SELECTED);
71 }
72
73 /* selects the item at index in the listview */
74 static void lv_set_curr_select(HWND dialog, int index)
75 {
76     /* no more than one item can be selected in our listview */
77     lv_clear_curr_select(dialog, -1);
78     ListView_SetItemState(GetDlgItem(dialog, IDC_LIST_DRIVES), index, LVIS_SELECTED, LVIS_SELECTED);
79 }
80
81 /* returns the currently selected item in the listview */
82 static int lv_get_curr_select(HWND dialog)
83 {
84     return SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
85 }
86
87 /* sets the item in the listview at item->iIndex */
88 static void lv_set_item(HWND dialog, LVITEM *item)
89 {
90     SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_SETITEM, 0, (LPARAM) item);
91 }
92
93 /* sets specified item's text */
94 static void lv_set_item_text(HWND dialog, int item, int subItem, char *text)
95 {
96     LVITEM lvItem;
97     if (item < 0 || subItem < 0) return;
98     lvItem.mask = LVIF_TEXT;
99     lvItem.iItem = item;
100     lvItem.iSubItem = subItem;
101     lvItem.pszText = text;
102     lvItem.cchTextMax = lstrlen(lvItem.pszText);
103     lv_set_item(dialog, &lvItem);
104 }
105
106 /* inserts an item into the listview */
107 static void lv_insert_item(HWND dialog, LVITEM *item)
108 {
109     SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_INSERTITEM, 0, (LPARAM) item);
110 }
111
112 /* retrieve the item at index item->iIndex */
113 static void lv_get_item(HWND dialog, LVITEM *item)
114 {
115     SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_GETITEM, 0, (LPARAM) item);
116 }
117
118 static void set_advanced(HWND dialog)
119 {
120     int state;
121     char text[256];
122     RECT rect;
123
124     if (advanced)
125     {
126         state = SW_NORMAL;
127         LoadString(GetModuleHandle(NULL), IDS_HIDE_ADVANCED, text, 256);
128     }
129     else
130     {
131         state = SW_HIDE;
132         LoadString(GetModuleHandle(NULL), IDS_SHOW_ADVANCED, text, 256);
133     }
134
135     ShowWindow(GetDlgItem(dialog, IDC_RADIO_AUTODETECT), state);
136     ShowWindow(GetDlgItem(dialog, IDC_RADIO_ASSIGN), state);
137     ShowWindow(GetDlgItem(dialog, IDC_EDIT_LABEL), state);
138     ShowWindow(GetDlgItem(dialog, IDC_EDIT_DEVICE), state);
139     ShowWindow(GetDlgItem(dialog, IDC_STATIC_LABEL), state);
140     ShowWindow(GetDlgItem(dialog, IDC_BUTTON_BROWSE_DEVICE), state);
141     ShowWindow(GetDlgItem(dialog, IDC_EDIT_SERIAL), state);
142     ShowWindow(GetDlgItem(dialog, IDC_STATIC_SERIAL), state);
143     ShowWindow(GetDlgItem(dialog, IDC_LABELSERIAL_STATIC), state);
144     ShowWindow(GetDlgItem(dialog, IDC_COMBO_TYPE), state);
145     ShowWindow(GetDlgItem(dialog, IDC_STATIC_TYPE), state);
146
147     /* update the button text based on the state */
148     SetWindowText(GetDlgItem(dialog, IDC_BUTTON_SHOW_HIDE_ADVANCED), text);
149
150     /* redraw for the etched line */
151     get_etched_rect(dialog, &rect);
152     InflateRect(&rect, 5, 5);
153     InvalidateRect(dialog, &rect, TRUE);
154 }
155
156 struct drive_typemap {
157     unsigned int sCode;
158     UINT idDesc;
159 };
160
161 static const struct drive_typemap type_pairs[] = {
162   { DRIVE_UNKNOWN,    IDS_DRIVE_UNKNOWN   },
163   { DRIVE_FIXED,      IDS_DRIVE_FIXED     },
164   { DRIVE_REMOTE,     IDS_DRIVE_REMOTE    },
165   { DRIVE_REMOVABLE,  IDS_DRIVE_REMOVABLE },
166   { DRIVE_CDROM,      IDS_DRIVE_CDROM     }
167 };
168
169 #define DRIVE_TYPE_DEFAULT 0
170
171 static void fill_drive_droplist(long mask, char curletter, HWND dialog)
172 {
173     int i;
174     int selection;
175     int count;
176     int next_letter;
177     char sName[4];
178
179     strcpy(sName, "A:");
180     for (i = 0, count = 0, selection = -1, next_letter = -1; i <= 'Z'-'A'; ++i)
181     {
182         if (mask & DRIVE_MASK_BIT('A' + i))
183         {
184             int index;
185
186             sName[0] = 'A' + i;
187             index = SendDlgItemMessage(dialog, IDC_COMBO_LETTER, CB_ADDSTRING, 0, (LPARAM) sName);
188
189             if (toupper(curletter) == 'A' + i)
190             {
191                 selection = count;
192             }
193
194             if (i >= 2 && next_letter == -1)
195             {
196                 /* default drive is first one of C-Z */
197                 next_letter = count;
198             }
199
200             count++;
201         }
202     }
203
204     if (selection == -1)
205     {
206         selection = next_letter;
207     }
208
209     SendDlgItemMessage(dialog, IDC_COMBO_LETTER, CB_SETCURSEL, selection, 0);
210 }
211
212
213 static void enable_labelserial_box(HWND dialog, int mode)
214 {
215     WINE_TRACE("mode=%d\n", mode);
216
217     switch (mode)
218     {
219         case BOX_MODE_CD_ASSIGN:
220             enable(IDC_RADIO_ASSIGN);
221             disable(IDC_EDIT_DEVICE);
222             disable(IDC_BUTTON_BROWSE_DEVICE);
223             enable(IDC_EDIT_SERIAL);
224             enable(IDC_EDIT_LABEL);
225             enable(IDC_STATIC_SERIAL);
226             enable(IDC_STATIC_LABEL);
227             break;
228
229         case BOX_MODE_CD_AUTODETECT:
230             enable(IDC_RADIO_ASSIGN);
231             enable(IDC_EDIT_DEVICE);
232             enable(IDC_BUTTON_BROWSE_DEVICE);
233             disable(IDC_EDIT_SERIAL);
234             disable(IDC_EDIT_LABEL);
235             disable(IDC_STATIC_SERIAL);
236             disable(IDC_STATIC_LABEL);
237             break;
238
239         case BOX_MODE_NONE:
240             disable(IDC_RADIO_ASSIGN);
241             disable(IDC_EDIT_DEVICE);
242             disable(IDC_BUTTON_BROWSE_DEVICE);
243             disable(IDC_EDIT_SERIAL);
244             disable(IDC_EDIT_LABEL);
245             disable(IDC_STATIC_SERIAL);
246             disable(IDC_STATIC_LABEL);
247             break;
248
249         case BOX_MODE_NORMAL:
250             enable(IDC_RADIO_ASSIGN);
251             disable(IDC_EDIT_DEVICE);
252             disable(IDC_BUTTON_BROWSE_DEVICE);
253             enable(IDC_EDIT_SERIAL);
254             enable(IDC_EDIT_LABEL);
255             enable(IDC_STATIC_SERIAL);
256             enable(IDC_STATIC_LABEL);
257             break;
258     }
259 }
260
261 static int fill_drives_list(HWND dialog)
262 {
263     int count = 0;
264     BOOL drivec_present = FALSE;
265     int i;
266     int prevsel = -1;
267
268     WINE_TRACE("\n");
269
270     updating_ui = TRUE;
271
272     prevsel = lv_get_curr_select(dialog); 
273
274     /* Clear the listbox */
275     SendDlgItemMessage(dialog, IDC_LIST_DRIVES, LVM_DELETEALLITEMS, 0, 0);
276
277     for(i = 0; i < 26; i++)
278     {
279         LVITEM item;
280         char letter[4];
281
282         /* skip over any unused drives */
283         if (!drives[i].in_use)
284             continue;
285
286         if (drives[i].letter == 'C')
287             drivec_present = TRUE;
288
289         letter[0] = 'A' + i;
290         letter[1] = ':';
291         letter[2] = 0;
292
293         memset(&item, 0, sizeof(item));
294         item.mask = LVIF_TEXT | LVIF_PARAM;
295         item.iItem = count;
296         item.iSubItem = 0;
297         item.pszText = letter;
298         item.cchTextMax = lstrlen(item.pszText);
299         item.lParam = (LPARAM) &drives[i];
300
301         lv_insert_item(dialog, &item);
302         lv_set_item_text(dialog, count, 1, drives[i].unixpath);
303
304         count++;
305     }
306
307     WINE_TRACE("loaded %d drives\n", count);
308
309     /* show the warning if there is no Drive C */
310     if (!drivec_present)
311         ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_NORMAL);
312     else
313         ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_HIDE);
314
315     lv_set_curr_select(dialog, prevsel == -1 ? 0 : prevsel);
316
317     updating_ui = FALSE;
318     return count;
319 }
320
321 static void on_options_click(HWND dialog)
322 {
323     if (IsDlgButtonChecked(dialog, IDC_SHOW_DOT_FILES) == BST_CHECKED)
324         set_reg_key(config_key, "", "ShowDotFiles", "Y");
325     else
326         set_reg_key(config_key, "", "ShowDotFiles", "N");
327
328     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
329 }
330
331 static void on_add_click(HWND dialog)
332 {
333     /* we should allocate a drive letter automatically. We also need
334        some way to let the user choose the mapping point, for now we
335        will just force them to enter a path automatically, with / being
336        the default. In future we should be able to temporarily map /
337        then invoke the directory chooser dialog. */
338
339     char new = 'C'; /* we skip A and B, they are historically floppy drives */
340     long mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */
341     int i, c;
342
343     while (mask & (1 << (new - 'A')))
344     {
345         new++;
346         if (new > 'Z')
347         {
348             driveui_msgbox (dialog, IDS_DRIVE_LETTERS_EXCEEDED, MB_OK | MB_ICONEXCLAMATION);
349             return;
350         }
351     }
352
353     WINE_TRACE("allocating drive letter %c\n", new);
354
355     if (new == 'C')
356     {
357         char label[64];
358         LoadStringA (GetModuleHandle (NULL), IDS_SYSTEM_DRIVE_LABEL, label,
359             sizeof(label)/sizeof(label[0])); 
360         add_drive(new, "../drive_c", label, "", DRIVE_FIXED);
361     }
362     else add_drive(new, "/", "", "", DRIVE_UNKNOWN);
363
364     fill_drives_list(dialog);
365
366     /* select the newly created drive */
367     mask = ~drive_available_mask(0);
368     c = 0;
369     for (i = 0; i < 26; i++)
370     {
371         if ('A' + i == new) break;
372         if ((1 << i) & mask) c++;
373     }
374     lv_set_curr_select(dialog, c);
375
376     SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES));
377
378     update_controls(dialog);
379 }
380
381 static void on_remove_click(HWND dialog)
382 {
383     int itemIndex;
384     struct drive *drive;
385     LVITEM item;
386
387     itemIndex = lv_get_curr_select(dialog);
388     if (itemIndex == -1) return; /* no selection */
389
390     memset(&item, 0, sizeof(item));
391     item.mask = LVIF_PARAM;
392     item.iItem = itemIndex;
393     item.iSubItem = 0;
394
395     lv_get_item(dialog, &item);
396
397     drive = (struct drive *) item.lParam;
398
399     WINE_ERR("unixpath: %s\n", drive->unixpath);
400
401     if (drive->letter == 'C')
402     {
403         DWORD result = driveui_msgbox (dialog, IDS_CONFIRM_DELETE_C, MB_YESNO | MB_ICONEXCLAMATION);
404         if (result == IDNO) return;
405     }
406
407     delete_drive(drive);
408
409     fill_drives_list(dialog);
410
411     itemIndex = itemIndex - 1;
412     if (itemIndex < 0) itemIndex = 0;
413     lv_set_curr_select(dialog, itemIndex);   /* previous item */
414
415     SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES));
416
417     update_controls(dialog);
418 }
419
420 static void update_controls(HWND dialog)
421 {
422     char *path;
423     unsigned int type;
424     char *label;
425     char *serial;
426     const char *device;
427     int i, selection = -1;
428     LVITEM item;
429
430     updating_ui = TRUE;
431
432     i = lv_get_curr_select(dialog);
433     if (i == -1)
434     {
435         /* no selection? let's select something for the user. this will re-enter */
436         lv_set_curr_select(dialog, i);
437         return;
438     }
439
440     memset(&item, 0, sizeof(item));
441     item.mask = LVIF_PARAM;
442     item.iItem = i;
443     item.iSubItem = 0;
444
445     lv_get_item(dialog, &item);
446     current_drive = (struct drive *) item.lParam;
447
448     WINE_TRACE("Updating sheet for drive %c\n", current_drive->letter);
449
450     /* Drive letters */
451     fill_drive_droplist(drive_available_mask(current_drive->letter), current_drive->letter, dialog);
452
453     /* path */
454     path = current_drive->unixpath;
455     WINE_TRACE("set path control text to '%s'\n", path);
456     set_text(dialog, IDC_EDIT_PATH, path);
457
458     /* drive type */
459     type = current_drive->type;
460     SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_RESETCONTENT, 0, 0);
461
462     for (i = 0; i < sizeof(type_pairs) / sizeof(struct drive_typemap); i++)
463     {
464         WCHAR driveDesc[64];
465         LoadStringW (GetModuleHandle (NULL), type_pairs[i].idDesc, driveDesc,
466             sizeof(driveDesc)/sizeof(driveDesc[0]));
467         SendDlgItemMessageW (dialog, IDC_COMBO_TYPE, CB_ADDSTRING, 0, (LPARAM)driveDesc);
468
469         if (type_pairs[i].sCode ==  type)
470         {
471             selection = i;
472         }
473     }
474
475     if (selection == -1) selection = DRIVE_TYPE_DEFAULT;
476     SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_SETCURSEL, selection, 0);
477
478     /* removeable media properties */
479     label = current_drive->label;
480     set_text(dialog, IDC_EDIT_LABEL, label);
481
482     /* set serial edit text */
483     serial = current_drive->serial;
484     set_text(dialog, IDC_EDIT_SERIAL, serial);
485
486     /* TODO: get the device here to put into the edit box */
487     device = "Not implemented yet";
488     set_text(dialog, IDC_EDIT_DEVICE, device);
489     device = NULL;
490
491     selection = IDC_RADIO_ASSIGN;
492     if ((type == DRIVE_CDROM) || (type == DRIVE_REMOVABLE))
493     {
494         if (device)
495         {
496             selection = IDC_RADIO_AUTODETECT;
497             enable_labelserial_box(dialog, BOX_MODE_CD_AUTODETECT);
498         }
499         else
500         {
501             selection = IDC_RADIO_ASSIGN;
502             enable_labelserial_box(dialog, BOX_MODE_CD_ASSIGN);
503         }
504     }
505     else
506     {
507         enable_labelserial_box(dialog, BOX_MODE_NORMAL);
508         selection = IDC_RADIO_ASSIGN;
509     }
510
511     CheckRadioButton(dialog, IDC_RADIO_AUTODETECT, IDC_RADIO_ASSIGN, selection);
512
513     updating_ui = FALSE;
514
515     return;
516 }
517
518 static void on_edit_changed(HWND dialog, WORD id)
519 {
520     if (updating_ui) return;
521
522     WINE_TRACE("edit id %d changed\n", id);
523
524     switch (id)
525     {
526         case IDC_EDIT_LABEL:
527         {
528             char *label;
529
530             label = get_text(dialog, id);
531             HeapFree(GetProcessHeap(), 0, current_drive->label);
532             current_drive->label = label ? label :  strdupA("");
533
534             WINE_TRACE("set label to %s\n", current_drive->label);
535
536             /* enable the apply button  */
537             SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
538             break;
539         }
540
541         case IDC_EDIT_PATH:
542         {
543             char *path;
544
545             path = get_text(dialog, id);
546             HeapFree(GetProcessHeap(), 0, current_drive->unixpath);
547             current_drive->unixpath = path ? path : strdupA("drive_c");
548
549             WINE_TRACE("set path to %s\n", current_drive->unixpath);
550
551             lv_set_item_text(dialog, lv_get_curr_select(dialog), 1,
552                              current_drive->unixpath);
553
554             /* enable the apply button  */
555             SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
556             break;
557         }
558
559         case IDC_EDIT_SERIAL:
560         {
561             char *serial;
562
563             serial = get_text(dialog, id);
564             HeapFree(GetProcessHeap(), 0, current_drive->serial);
565             current_drive->serial = serial ? serial : strdupA("");
566
567             WINE_TRACE("set serial to %s", current_drive->serial);
568
569             /* enable the apply button  */
570             SendMessage(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
571             break;
572         }
573
574         case IDC_EDIT_DEVICE:
575         {
576             char *device = get_text(dialog, id);
577             /* TODO: handle device if/when it makes sense to do so.... */
578             HeapFree(GetProcessHeap(), 0, device);
579             break;
580         }
581     }
582 }
583
584 static void get_etched_rect(HWND dialog, RECT *rect)
585 {
586     GetClientRect(dialog, rect);
587
588     /* these dimensions from the labelserial static in En.rc  */
589     rect->top = 265;
590     rect->bottom = 265;
591     rect->left += 25;
592     rect->right -= 25;
593 }
594
595 /* this just draws a nice line to separate the advanced gui from the n00b gui :) */
596 static void paint(HWND dialog)
597 {
598     PAINTSTRUCT ps;
599
600     BeginPaint(dialog, &ps);
601
602     if (advanced)
603     {
604         RECT rect;
605
606         get_etched_rect(dialog, &rect);
607
608         DrawEdge(ps.hdc, &rect, EDGE_ETCHED, BF_TOP);
609     }
610
611     EndPaint(dialog, &ps);
612 }
613
614 BOOL browse_for_unix_folder(HWND dialog, char *pszPath)
615 {
616     static WCHAR wszUnixRootDisplayName[] = 
617         { ':',':','{','C','C','7','0','2','E','B','2','-','7','D','C','5','-','1','1','D','9','-',
618           'C','6','8','7','-','0','0','0','4','2','3','8','A','0','1','C','D','}', 0 };
619     char pszChoosePath[256];
620     BROWSEINFOA bi = {
621         dialog,
622         NULL,
623         NULL,
624         pszChoosePath,
625         0,
626         NULL,
627         0,
628         0
629     };
630     IShellFolder *pDesktop;
631     LPITEMIDLIST pidlUnixRoot, pidlSelectedPath;
632     HRESULT hr;
633    
634     LoadString(GetModuleHandle(NULL), IDS_CHOOSE_PATH, pszChoosePath, 256);
635     
636     hr = SHGetDesktopFolder(&pDesktop);
637     if (!SUCCEEDED(hr)) return FALSE;
638
639     hr = IShellFolder_ParseDisplayName(pDesktop, NULL, NULL, wszUnixRootDisplayName, NULL, 
640                                        &pidlUnixRoot, NULL);
641     if (!SUCCEEDED(hr)) {
642         IShellFolder_Release(pDesktop);
643         return FALSE;
644     }
645
646     bi.pidlRoot = pidlUnixRoot;
647     pidlSelectedPath = SHBrowseForFolderA(&bi);
648     SHFree(pidlUnixRoot);
649     
650     if (pidlSelectedPath) {
651         STRRET strSelectedPath;
652         char *pszSelectedPath;
653         HRESULT hr;
654         
655         hr = IShellFolder_GetDisplayNameOf(pDesktop, pidlSelectedPath, SHGDN_FORPARSING, 
656                                            &strSelectedPath);
657         IShellFolder_Release(pDesktop);
658         if (!SUCCEEDED(hr)) {
659             SHFree(pidlSelectedPath);
660             return FALSE;
661         }
662
663         hr = StrRetToStr(&strSelectedPath, pidlSelectedPath, &pszSelectedPath);
664         SHFree(pidlSelectedPath);
665         if (!SUCCEEDED(hr)) return FALSE;
666
667         lstrcpy(pszPath, pszSelectedPath);
668         
669         CoTaskMemFree(pszSelectedPath);
670         return TRUE;
671     }
672     return FALSE;
673 }
674
675 static void init_listview_columns(HWND dialog)
676 {
677     LVCOLUMNW listColumn;
678     RECT viewRect;
679     int width;
680     WCHAR column[64];
681
682     GetClientRect(GetDlgItem(dialog, IDC_LIST_DRIVES), &viewRect);
683     width = (viewRect.right - viewRect.left) / 6 - 5;
684
685     LoadStringW (GetModuleHandle (NULL), IDS_COL_DRIVELETTER, column,
686         sizeof(column)/sizeof(column[0]));
687     listColumn.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
688     listColumn.pszText = column;
689     listColumn.cchTextMax = lstrlenW (listColumn.pszText);
690     listColumn.cx = width;
691
692     SendDlgItemMessageW (dialog, IDC_LIST_DRIVES, LVM_INSERTCOLUMNW, 0, (LPARAM) &listColumn);
693
694     LoadStringW (GetModuleHandle (NULL), IDS_COL_DRIVEMAPPING, column,
695         sizeof(column)/sizeof(column[0]));
696     listColumn.cx = viewRect.right - viewRect.left - width;
697     listColumn.pszText = column;
698     listColumn.cchTextMax = lstrlenW (listColumn.pszText);
699
700     SendDlgItemMessageW (dialog, IDC_LIST_DRIVES, LVM_INSERTCOLUMNW, 1, (LPARAM) &listColumn);
701 }
702
703 static void load_drive_options(HWND dialog)
704 {
705     if (!strcmp(get_reg_key(config_key, "", "ShowDotFiles", "N"), "Y"))
706         CheckDlgButton(dialog, IDC_SHOW_DOT_FILES, BST_CHECKED);
707 }
708
709 INT_PTR CALLBACK
710 DriveDlgProc (HWND dialog, UINT msg, WPARAM wParam, LPARAM lParam)
711 {
712     int item;
713     struct drive *drive;
714
715     switch (msg)
716     {
717         case WM_INITDIALOG:
718             init_listview_columns(dialog);
719             load_drives();
720             load_drive_options(dialog);
721
722             if (!drives[2].in_use)
723                 driveui_msgbox (dialog, IDS_NO_DRIVE_C, MB_OK | MB_ICONEXCLAMATION);
724
725             fill_drives_list(dialog);
726             update_controls(dialog);
727             /* put in non-advanced mode by default  */
728             set_advanced(dialog);
729             break;
730
731         case WM_SHOWWINDOW:
732             set_window_title(dialog);
733             break;
734
735         case WM_PAINT:
736             paint(dialog);
737             break;
738
739         case WM_COMMAND:
740             switch (HIWORD(wParam))
741             {
742                 case EN_CHANGE:
743                     on_edit_changed(dialog, LOWORD(wParam));
744                     break;
745
746                 case BN_CLICKED:
747                     switch (LOWORD(wParam))
748                     {
749                         case IDC_SHOW_DOT_FILES:
750                             on_options_click(dialog);
751                         break;
752                     }
753                     break;
754
755                 case CBN_SELCHANGE:
756                     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
757                     break;
758             }
759
760             switch (LOWORD(wParam))
761             {
762                 case IDC_BUTTON_ADD:
763                     if (HIWORD(wParam) != BN_CLICKED) break;
764                     on_add_click(dialog);
765                     break;
766
767                 case IDC_BUTTON_REMOVE:
768                     if (HIWORD(wParam) != BN_CLICKED) break;
769                     on_remove_click(dialog);
770                     break;
771
772                 case IDC_BUTTON_EDIT:
773                     if (HIWORD(wParam) != BN_CLICKED) break;
774                     item = SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES),  LB_GETCURSEL, 0, 0);
775                     drive = (struct drive *) SendMessage(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_GETITEMDATA, item, 0);
776                     /*DialogBoxParam(NULL, MAKEINTRESOURCE(IDD_DRIVE_EDIT), NULL, (DLGPROC) DriveEditDlgProc, (LPARAM) drive); */
777                     break;
778
779                 case IDC_BUTTON_AUTODETECT:
780                     autodetect_drives();
781                     fill_drives_list(dialog);
782                     SendMessage(GetParent(dialog), PSM_CHANGED, 0, 0);
783                     break;
784
785                 case IDC_BUTTON_SHOW_HIDE_ADVANCED:
786                     advanced = !advanced;
787                     set_advanced(dialog);
788                     break;
789
790                 case IDC_BUTTON_BROWSE_PATH:
791                 {
792                     char szTargetPath[FILENAME_MAX];
793                     if (browse_for_unix_folder(dialog, szTargetPath)) 
794                         set_text(dialog, IDC_EDIT_PATH, szTargetPath);
795                     break;
796                 }
797
798                 case IDC_RADIO_ASSIGN:
799                 {
800                     char *str;
801
802                     str = get_text(dialog, IDC_EDIT_LABEL);
803                     HeapFree(GetProcessHeap(), 0, current_drive->label);
804                     current_drive->label = str ? str : strdupA("");
805
806                     str = get_text(dialog, IDC_EDIT_SERIAL);
807                     HeapFree(GetProcessHeap(), 0, current_drive->serial);
808                     current_drive->serial = str ? str : strdupA("");
809
810                     /* TODO: we don't have a device at this point */
811
812                     enable_labelserial_box(dialog, BOX_MODE_CD_ASSIGN);
813
814                     break;
815                 }
816
817
818                 case IDC_COMBO_TYPE:
819                 {
820                     int mode = BOX_MODE_NORMAL;
821                     int selection;
822
823                     if (HIWORD(wParam) != CBN_SELCHANGE) break;
824
825                     selection = SendDlgItemMessage(dialog, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0);
826
827                     if (selection >= 0 &&
828                         (type_pairs[selection].sCode == DRIVE_CDROM ||
829                          type_pairs[selection].sCode == DRIVE_REMOVABLE))
830                     {
831                         if (IsDlgButtonChecked(dialog, IDC_RADIO_AUTODETECT))
832                             mode = BOX_MODE_CD_AUTODETECT;
833                         else
834                             mode = BOX_MODE_CD_ASSIGN;
835                     }
836
837                     enable_labelserial_box(dialog, mode);
838
839                     current_drive->type = type_pairs[selection].sCode;
840                     break;
841                 }
842
843             }
844             break;
845
846         case WM_NOTIFY:
847             switch (((LPNMHDR)lParam)->code)
848             {
849                 case PSN_KILLACTIVE:
850                     WINE_TRACE("PSN_KILLACTIVE\n");
851                     SetWindowLongPtr(dialog, DWLP_MSGRESULT, FALSE);
852                     break;
853                 case PSN_APPLY:
854                     apply_drive_changes();
855                     SetWindowLongPtr(dialog, DWLP_MSGRESULT, PSNRET_NOERROR);
856                     break;
857                 case PSN_SETACTIVE:
858                     break;
859                 case LVN_ITEMCHANGED:
860                 {
861                     LPNMLISTVIEW lpnm = (LPNMLISTVIEW)lParam;
862                     if (!(lpnm->uOldState & LVIS_SELECTED) &&
863                          (lpnm->uNewState & LVIS_SELECTED))
864                     update_controls(dialog);
865                     break;
866                 }
867             }
868             break;
869     }
870
871     return FALSE;
872 }