driveui.c 23.8 KB
Newer Older
Mike Hearn's avatar
Mike Hearn committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Drive management UI code
 *
 * Copyright 2003 Mark Westcott
 * Copyright 2004 Chris Morgan
 * Copyright 2003-2004 Mike Hearn
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
Mike Hearn's avatar
Mike Hearn committed
21 22 23
 *
 */

24 25
#include <stdio.h>

26
#define WIN32_LEAN_AND_MEAN
27 28
#define COBJMACROS

29
#include <windows.h>
Mike Hearn's avatar
Mike Hearn committed
30 31 32 33 34 35
#include <shellapi.h>
#include <objbase.h>
#include <shlguid.h>
#include <shlwapi.h>
#include <shlobj.h>

36
#include <wine/unicode.h>
Mike Hearn's avatar
Mike Hearn committed
37 38 39 40 41 42 43
#include <wine/debug.h>

#include "winecfg.h"
#include "resource.h"

WINE_DEFAULT_DEBUG_CHANNEL(winecfg);

44 45
#define BOX_MODE_DEVICE 1
#define BOX_MODE_NORMAL 2
Mike Hearn's avatar
Mike Hearn committed
46 47 48 49 50

static BOOL advanced = FALSE;
static BOOL updating_ui = FALSE;
static struct drive* current_drive;

51
static void update_controls(HWND dialog);
Mike Hearn's avatar
Mike Hearn committed
52

53 54 55
static DWORD driveui_msgbox (HWND parent, UINT messageId, DWORD flags)
{
  WCHAR* caption = load_string (IDS_WINECFG_TITLE);
56
  WCHAR* text = load_string (messageId);
57 58 59 60 61 62
  DWORD result = MessageBoxW (parent, text, caption, flags);
  HeapFree (GetProcessHeap(), 0, caption);
  HeapFree (GetProcessHeap(), 0, text);
  return result;
}

63 64 65 66 67
/**** listview helper functions ****/

/* clears the item at index in the listview */
static void lv_clear_curr_select(HWND dialog, int index)
{
68 69 70 71 72 73
    LVITEMW item;

    item.mask = LVIF_STATE;
    item.state = 0;
    item.stateMask = LVIS_SELECTED;
    SendDlgItemMessageW( dialog, IDC_LIST_DRIVES, LVM_SETITEMSTATE, index, (LPARAM)&item );
74 75 76 77 78
}

/* selects the item at index in the listview */
static void lv_set_curr_select(HWND dialog, int index)
{
79 80
    LVITEMW item;

81 82
    /* no more than one item can be selected in our listview */
    lv_clear_curr_select(dialog, -1);
83 84 85 86
    item.mask = LVIF_STATE;
    item.state = LVIS_SELECTED;
    item.stateMask = LVIS_SELECTED;
    SendDlgItemMessageW( dialog, IDC_LIST_DRIVES, LVM_SETITEMSTATE, index, (LPARAM)&item );
87 88 89 90 91
}

/* returns the currently selected item in the listview */
static int lv_get_curr_select(HWND dialog)
{
92
    return SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
93 94 95
}

/* sets the item in the listview at item->iIndex */
96
static void lv_set_item(HWND dialog, LVITEMW *item)
97
{
98
    SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_SETITEMW, 0, (LPARAM) item);
99 100
}

101
/* sets specified item's text */
102
static void lv_set_item_text(HWND dialog, int item, int subItem, WCHAR *text)
103
{
104
    LVITEMW lvItem;
105 106 107 108 109
    if (item < 0 || subItem < 0) return;
    lvItem.mask = LVIF_TEXT;
    lvItem.iItem = item;
    lvItem.iSubItem = subItem;
    lvItem.pszText = text;
110
    lvItem.cchTextMax = lstrlenW(lvItem.pszText);
111 112 113
    lv_set_item(dialog, &lvItem);
}

114
/* inserts an item into the listview */
115
static void lv_insert_item(HWND dialog, LVITEMW *item)
116
{
117
    SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_INSERTITEMW, 0, (LPARAM) item);
118 119 120
}

/* retrieve the item at index item->iIndex */
121
static void lv_get_item(HWND dialog, LVITEMW *item)
122
{
123
    SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_GETITEMW, 0, (LPARAM) item);
124 125
}

Mike Hearn's avatar
Mike Hearn committed
126 127 128
static void set_advanced(HWND dialog)
{
    int state;
129
    WCHAR text[256];
Mike Hearn's avatar
Mike Hearn committed
130 131 132 133

    if (advanced)
    {
        state = SW_NORMAL;
134
        LoadStringW(GetModuleHandleW(NULL), IDS_HIDE_ADVANCED, text, 256);
Mike Hearn's avatar
Mike Hearn committed
135 136 137 138
    }
    else
    {
        state = SW_HIDE;
139
        LoadStringW(GetModuleHandleW(NULL), IDS_SHOW_ADVANCED, text, 256);
Mike Hearn's avatar
Mike Hearn committed
140 141 142
    }

    ShowWindow(GetDlgItem(dialog, IDC_EDIT_DEVICE), state);
143 144
    ShowWindow(GetDlgItem(dialog, IDC_STATIC_DEVICE), state);
    ShowWindow(GetDlgItem(dialog, IDC_EDIT_LABEL), state);
Mike Hearn's avatar
Mike Hearn committed
145 146 147 148
    ShowWindow(GetDlgItem(dialog, IDC_STATIC_LABEL), state);
    ShowWindow(GetDlgItem(dialog, IDC_BUTTON_BROWSE_DEVICE), state);
    ShowWindow(GetDlgItem(dialog, IDC_EDIT_SERIAL), state);
    ShowWindow(GetDlgItem(dialog, IDC_STATIC_SERIAL), state);
149 150
    ShowWindow(GetDlgItem(dialog, IDC_COMBO_TYPE), state);
    ShowWindow(GetDlgItem(dialog, IDC_STATIC_TYPE), state);
Mike Hearn's avatar
Mike Hearn committed
151 152

    /* update the button text based on the state */
153
    SetWindowTextW(GetDlgItem(dialog, IDC_BUTTON_SHOW_HIDE_ADVANCED), text);
Mike Hearn's avatar
Mike Hearn committed
154 155 156
}

struct drive_typemap {
Steven Edwards's avatar
Steven Edwards committed
157
    unsigned int sCode;
158
    UINT idDesc;
Mike Hearn's avatar
Mike Hearn committed
159 160
};

Steven Edwards's avatar
Steven Edwards committed
161
static const struct drive_typemap type_pairs[] = {
162 163 164 165 166
  { DRIVE_UNKNOWN,    IDS_DRIVE_UNKNOWN   },
  { DRIVE_FIXED,      IDS_DRIVE_FIXED     },
  { DRIVE_REMOTE,     IDS_DRIVE_REMOTE    },
  { DRIVE_REMOVABLE,  IDS_DRIVE_REMOVABLE },
  { DRIVE_CDROM,      IDS_DRIVE_CDROM     }
Mike Hearn's avatar
Mike Hearn committed
167 168
};

169
#define DRIVE_TYPE_DEFAULT 0
Mike Hearn's avatar
Mike Hearn committed
170

171
static void enable_labelserial_box(HWND dialog, int mode)
Mike Hearn's avatar
Mike Hearn committed
172 173 174 175 176
{
    WINE_TRACE("mode=%d\n", mode);

    switch (mode)
    {
177 178
        case BOX_MODE_DEVICE:
            /* FIXME: enable device editing */
Mike Hearn's avatar
Mike Hearn committed
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
            disable(IDC_EDIT_DEVICE);
            disable(IDC_BUTTON_BROWSE_DEVICE);
            disable(IDC_EDIT_SERIAL);
            disable(IDC_EDIT_LABEL);
            break;

        case BOX_MODE_NORMAL:
            disable(IDC_EDIT_DEVICE);
            disable(IDC_BUTTON_BROWSE_DEVICE);
            enable(IDC_EDIT_SERIAL);
            enable(IDC_EDIT_LABEL);
            break;
    }
}

194
static int fill_drives_list(HWND dialog)
Mike Hearn's avatar
Mike Hearn committed
195 196 197 198 199 200 201 202 203 204
{
    int count = 0;
    BOOL drivec_present = FALSE;
    int i;
    int prevsel = -1;

    WINE_TRACE("\n");

    updating_ui = TRUE;

205
    prevsel = lv_get_curr_select(dialog); 
Mike Hearn's avatar
Mike Hearn committed
206 207

    /* Clear the listbox */
208
    SendDlgItemMessageW(dialog, IDC_LIST_DRIVES, LVM_DELETEALLITEMS, 0, 0);
Mike Hearn's avatar
Mike Hearn committed
209 210 211

    for(i = 0; i < 26; i++)
    {
212 213
        LVITEMW item;
        WCHAR *path;
214
        char letter[4];
Mike Hearn's avatar
Mike Hearn committed
215 216 217 218 219 220 221 222

        /* skip over any unused drives */
        if (!drives[i].in_use)
            continue;

        if (drives[i].letter == 'C')
            drivec_present = TRUE;

223 224 225
        letter[0] = 'A' + i;
        letter[1] = ':';
        letter[2] = 0;
226

227
        item.mask = LVIF_TEXT | LVIF_PARAM;
228 229
        item.iItem = count;
        item.iSubItem = 0;
230 231
        item.pszText = strdupU2W(letter);
        item.cchTextMax = lstrlenW(item.pszText);
232
        item.lParam = (LPARAM) &drives[i];
Mike Hearn's avatar
Mike Hearn committed
233

234
        lv_insert_item(dialog, &item);
235 236 237 238 239
        HeapFree(GetProcessHeap(), 0, item.pszText);

        path = strdupU2W(drives[i].unixpath);
        lv_set_item_text(dialog, count, 1, path);
        HeapFree(GetProcessHeap(), 0, path);
Mike Hearn's avatar
Mike Hearn committed
240 241 242 243 244 245 246 247 248 249 250 251

        count++;
    }

    WINE_TRACE("loaded %d drives\n", count);

    /* show the warning if there is no Drive C */
    if (!drivec_present)
        ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_NORMAL);
    else
        ShowWindow(GetDlgItem(dialog, IDS_DRIVE_NO_C), SW_HIDE);

252
    lv_set_curr_select(dialog, prevsel == -1 ? 0 : prevsel);
Mike Hearn's avatar
Mike Hearn committed
253 254 255 256 257

    updating_ui = FALSE;
    return count;
}

258
static void on_options_click(HWND dialog)
259 260
{
    if (IsDlgButtonChecked(dialog, IDC_SHOW_DOT_FILES) == BST_CHECKED)
261
        set_reg_key(config_key, "", "ShowDotFiles", "Y");
262
    else
263
        set_reg_key(config_key, "", "ShowDotFiles", "N");
264

265
    SendMessageW(GetParent(dialog), PSM_CHANGED, 0, 0);
266
}
Mike Hearn's avatar
Mike Hearn committed
267

268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
static INT_PTR CALLBACK drivechoose_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static int i, sel;
    char c;
    char drive[] = "X:";

    switch(uMsg)
    {
    case WM_INITDIALOG:
        {
        ULONG mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */
        for( c = 'A'; c<= 'Z'; c++){
            drive[0] = c;
            if(!( mask & (1 << (c - 'A'))))
                SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_ADDSTRING, 0, (LPARAM) drive);
        }
        drive[0] = lParam;
        SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_SELECTSTRING, 0, (LPARAM) drive);
        return TRUE;
        }
    case WM_COMMAND:
        if(HIWORD(wParam) != BN_CLICKED) break;
        switch (LOWORD(wParam))
        {
        case IDOK:
            i = SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_GETCURSEL, 0, 0);
            if( i != CB_ERR){
                SendDlgItemMessageA( hwndDlg, IDC_DRIVESA2Z, CB_GETLBTEXT, i, (LPARAM) drive);
                sel = drive[0];
            } else
                sel = -1;
            EndDialog(hwndDlg, sel);
            return TRUE;
        case IDCANCEL:
            EndDialog(hwndDlg, -1);
            return TRUE;
        }
    }
    return FALSE;
}

309
static void on_add_click(HWND dialog)
Mike Hearn's avatar
Mike Hearn committed
310 311 312 313 314 315 316 317
{
    /* we should allocate a drive letter automatically. We also need
       some way to let the user choose the mapping point, for now we
       will just force them to enter a path automatically, with / being
       the default. In future we should be able to temporarily map /
       then invoke the directory chooser dialog. */

    char new = 'C'; /* we skip A and B, they are historically floppy drives */
318
    ULONG mask = ~drive_available_mask(0); /* the mask is now which drives aren't available */
Mike Hearn's avatar
Mike Hearn committed
319
    int i, c;
320
    INT_PTR ret;
Mike Hearn's avatar
Mike Hearn committed
321 322 323 324 325 326

    while (mask & (1 << (new - 'A')))
    {
        new++;
        if (new > 'Z')
        {
327
            driveui_msgbox (dialog, IDS_DRIVE_LETTERS_EXCEEDED, MB_OK | MB_ICONEXCLAMATION);
Mike Hearn's avatar
Mike Hearn committed
328 329 330 331
            return;
        }
    }

332

333
    ret = DialogBoxParamW(0, MAKEINTRESOURCEW(IDD_DRIVECHOOSE), dialog, drivechoose_dlgproc, new);
334

335 336
    if( ret == -1) return;
    new = ret;
337 338

    WINE_TRACE("selected drive letter %c\n", new);
Mike Hearn's avatar
Mike Hearn committed
339

340 341
    if (new == 'C')
    {
342
        WCHAR label[64];
343
        LoadStringW(GetModuleHandleW(NULL), IDS_SYSTEM_DRIVE_LABEL, label, ARRAY_SIZE(label));
344
        add_drive(new, "../drive_c", NULL, label, 0, DRIVE_FIXED);
345
    }
346
    else add_drive(new, "/", NULL, NULL, 0, DRIVE_UNKNOWN);
Mike Hearn's avatar
Mike Hearn committed
347 348 349 350 351 352 353 354 355 356 357

    fill_drives_list(dialog);

    /* select the newly created drive */
    mask = ~drive_available_mask(0);
    c = 0;
    for (i = 0; i < 26; i++)
    {
        if ('A' + i == new) break;
        if ((1 << i) & mask) c++;
    }
358
    lv_set_curr_select(dialog, c);
Mike Hearn's avatar
Mike Hearn committed
359 360

    SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES));
361 362

    update_controls(dialog);
363
    SendMessageW(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
Mike Hearn's avatar
Mike Hearn committed
364 365
}

366
static void on_remove_click(HWND dialog)
Mike Hearn's avatar
Mike Hearn committed
367
{
368
    int itemIndex;
Mike Hearn's avatar
Mike Hearn committed
369
    struct drive *drive;
370
    LVITEMW item;
371 372 373 374 375 376 377 378 379 380 381

    itemIndex = lv_get_curr_select(dialog);
    if (itemIndex == -1) return; /* no selection */

    item.mask = LVIF_PARAM;
    item.iItem = itemIndex;
    item.iSubItem = 0;

    lv_get_item(dialog, &item);

    drive = (struct drive *) item.lParam;
Mike Hearn's avatar
Mike Hearn committed
382

383
    WINE_TRACE("unixpath: %s\n", drive->unixpath);
Mike Hearn's avatar
Mike Hearn committed
384 385 386

    if (drive->letter == 'C')
    {
387
        DWORD result = driveui_msgbox (dialog, IDS_CONFIRM_DELETE_C, MB_YESNO | MB_ICONEXCLAMATION);
Mike Hearn's avatar
Mike Hearn committed
388 389 390 391 392 393 394
        if (result == IDNO) return;
    }

    delete_drive(drive);

    fill_drives_list(dialog);

395 396 397
    itemIndex = itemIndex - 1;
    if (itemIndex < 0) itemIndex = 0;
    lv_set_curr_select(dialog, itemIndex);   /* previous item */
Mike Hearn's avatar
Mike Hearn committed
398 399

    SetFocus(GetDlgItem(dialog, IDC_LIST_DRIVES));
400 401

    update_controls(dialog);
402
    SendMessageW(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
Mike Hearn's avatar
Mike Hearn committed
403 404
}

405 406
static void update_controls(HWND dialog)
{
407
    static const WCHAR emptyW[1];
408
    WCHAR *path;
Steven Edwards's avatar
Steven Edwards committed
409
    unsigned int type;
410
    char serial[16];
Mike Hearn's avatar
Mike Hearn committed
411
    int i, selection = -1;
412
    LVITEMW item;
Mike Hearn's avatar
Mike Hearn committed
413 414 415

    updating_ui = TRUE;

416
    i = lv_get_curr_select(dialog);
Mike Hearn's avatar
Mike Hearn committed
417 418 419
    if (i == -1)
    {
        /* no selection? let's select something for the user. this will re-enter */
420
        lv_set_curr_select(dialog, i);
Mike Hearn's avatar
Mike Hearn committed
421 422
        return;
    }
423 424 425 426 427 428 429

    item.mask = LVIF_PARAM;
    item.iItem = i;
    item.iSubItem = 0;

    lv_get_item(dialog, &item);
    current_drive = (struct drive *) item.lParam;
Mike Hearn's avatar
Mike Hearn committed
430 431 432 433

    WINE_TRACE("Updating sheet for drive %c\n", current_drive->letter);

    /* path */
434 435 436 437
    WINE_TRACE("set path control text to '%s'\n", current_drive->unixpath);
    path = strdupU2W(current_drive->unixpath);
    set_textW(dialog, IDC_EDIT_PATH, path);
    HeapFree(GetProcessHeap(), 0, path);
Mike Hearn's avatar
Mike Hearn committed
438 439 440

    /* drive type */
    type = current_drive->type;
441
    SendDlgItemMessageW(dialog, IDC_COMBO_TYPE, CB_RESETCONTENT, 0, 0);
442

443
    for (i = 0; i < ARRAY_SIZE(type_pairs); i++)
Mike Hearn's avatar
Mike Hearn committed
444
    {
445
        WCHAR driveDesc[64];
446
        LoadStringW(GetModuleHandleW(NULL), type_pairs[i].idDesc, driveDesc, ARRAY_SIZE(driveDesc));
447
        SendDlgItemMessageW (dialog, IDC_COMBO_TYPE, CB_ADDSTRING, 0, (LPARAM)driveDesc);
Mike Hearn's avatar
Mike Hearn committed
448

449 450 451
        if (type_pairs[i].sCode ==  type)
        {
            selection = i;
Mike Hearn's avatar
Mike Hearn committed
452
        }
453
    }
Mike Hearn's avatar
Mike Hearn committed
454

455
    if (selection == -1) selection = DRIVE_TYPE_DEFAULT;
456
    SendDlgItemMessageW(dialog, IDC_COMBO_TYPE, CB_SETCURSEL, selection, 0);
Mike Hearn's avatar
Mike Hearn committed
457

458 459 460 461 462
    EnableWindow( GetDlgItem( dialog, IDC_BUTTON_REMOVE ), (current_drive->letter != 'C') );
    EnableWindow( GetDlgItem( dialog, IDC_EDIT_PATH ), (current_drive->letter != 'C') );
    EnableWindow( GetDlgItem( dialog, IDC_BUTTON_BROWSE_PATH ), (current_drive->letter != 'C') );
    EnableWindow( GetDlgItem( dialog, IDC_COMBO_TYPE ), (current_drive->letter != 'C') );

463
    /* removable media properties */
464
    set_textW(dialog, IDC_EDIT_LABEL, current_drive->label ? current_drive->label : emptyW);
Mike Hearn's avatar
Mike Hearn committed
465 466

    /* set serial edit text */
467
    sprintf( serial, "%X", current_drive->serial );
Mike Hearn's avatar
Mike Hearn committed
468 469
    set_text(dialog, IDC_EDIT_SERIAL, serial);

470
    set_text(dialog, IDC_EDIT_DEVICE, current_drive->device);
Mike Hearn's avatar
Mike Hearn committed
471 472

    if ((type == DRIVE_CDROM) || (type == DRIVE_REMOVABLE))
473
        enable_labelserial_box(dialog, BOX_MODE_DEVICE);
Mike Hearn's avatar
Mike Hearn committed
474 475 476 477 478 479 480 481
    else
        enable_labelserial_box(dialog, BOX_MODE_NORMAL);

    updating_ui = FALSE;

    return;
}

482
static void on_edit_changed(HWND dialog, WORD id)
Mike Hearn's avatar
Mike Hearn committed
483 484 485 486 487 488 489 490 491
{
    if (updating_ui) return;

    WINE_TRACE("edit id %d changed\n", id);

    switch (id)
    {
        case IDC_EDIT_LABEL:
        {
492
            WCHAR *label = get_textW(dialog, id);
493
            HeapFree(GetProcessHeap(), 0, current_drive->label);
494
            current_drive->label = label;
495
            current_drive->modified = TRUE;
Mike Hearn's avatar
Mike Hearn committed
496

497
            WINE_TRACE("set label to %s\n", wine_dbgstr_w(current_drive->label));
Mike Hearn's avatar
Mike Hearn committed
498

499
            /* enable the apply button  */
500
            SendMessageW(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
Mike Hearn's avatar
Mike Hearn committed
501 502 503 504 505
            break;
        }

        case IDC_EDIT_PATH:
        {
506
            WCHAR *wpath;
Mike Hearn's avatar
Mike Hearn committed
507
            char *path;
508 509 510 511 512 513 514 515 516 517 518 519 520
            int lenW;

            wpath = get_textW(dialog, id);
            if( (lenW = WideCharToMultiByte(CP_UNIXCP, 0, wpath, -1, NULL, 0, NULL, NULL)) )
            {
                path = HeapAlloc(GetProcessHeap(), 0, lenW);
                WideCharToMultiByte(CP_UNIXCP, 0, wpath, -1, path, lenW, NULL, NULL);
            }
            else
            {
                path = NULL;
                wpath = strdupU2W("drive_c");
            }
Mike Hearn's avatar
Mike Hearn committed
521

522
            HeapFree(GetProcessHeap(), 0, current_drive->unixpath);
Mike Hearn's avatar
Mike Hearn committed
523
            current_drive->unixpath = path ? path : strdupA("drive_c");
524
            current_drive->modified = TRUE;
Mike Hearn's avatar
Mike Hearn committed
525 526 527

            WINE_TRACE("set path to %s\n", current_drive->unixpath);

528
            lv_set_item_text(dialog, lv_get_curr_select(dialog), 1,
529 530
                             wpath);
            HeapFree(GetProcessHeap(), 0, wpath);
531 532

            /* enable the apply button  */
533
            SendMessageW(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
Mike Hearn's avatar
Mike Hearn committed
534 535 536 537 538 539 540 541
            break;
        }

        case IDC_EDIT_SERIAL:
        {
            char *serial;

            serial = get_text(dialog, id);
542 543
            current_drive->serial = serial ? strtoul( serial, NULL, 16 ) : 0;
            HeapFree(GetProcessHeap(), 0, serial);
544
            current_drive->modified = TRUE;
Mike Hearn's avatar
Mike Hearn committed
545

546
            WINE_TRACE("set serial to %08X\n", current_drive->serial);
Mike Hearn's avatar
Mike Hearn committed
547

548
            /* enable the apply button  */
549
            SendMessageW(GetParent(dialog), PSM_CHANGED, (WPARAM) dialog, 0);
Mike Hearn's avatar
Mike Hearn committed
550 551 552 553 554 555 556
            break;
        }

        case IDC_EDIT_DEVICE:
        {
            char *device = get_text(dialog, id);
            /* TODO: handle device if/when it makes sense to do so.... */
557
            HeapFree(GetProcessHeap(), 0, device);
Mike Hearn's avatar
Mike Hearn committed
558 559 560 561 562
            break;
        }
    }
}

563
BOOL browse_for_unix_folder(HWND dialog, WCHAR *pszPath)
564 565 566
{
    static WCHAR wszUnixRootDisplayName[] = 
        { ':',':','{','C','C','7','0','2','E','B','2','-','7','D','C','5','-','1','1','D','9','-',
567
          'C','6','8','7','-','0','0','0','4','2','3','8','A','0','1','C','D','}', 0 };
568 569
    WCHAR pszChoosePath[FILENAME_MAX];
    BROWSEINFOW bi = {
570 571 572
        dialog,
        NULL,
        NULL,
573
        pszChoosePath,
574 575 576 577 578 579 580 581
        0,
        NULL,
        0,
        0
    };
    IShellFolder *pDesktop;
    LPITEMIDLIST pidlUnixRoot, pidlSelectedPath;
    HRESULT hr;
582 583 584

    LoadStringW(GetModuleHandleW(NULL), IDS_CHOOSE_PATH, pszChoosePath, FILENAME_MAX);

585
    hr = SHGetDesktopFolder(&pDesktop);
586
    if (FAILED(hr)) return FALSE;
587

588 589
    hr = IShellFolder_ParseDisplayName(pDesktop, NULL, NULL, wszUnixRootDisplayName, NULL, 
                                       &pidlUnixRoot, NULL);
590
    if (FAILED(hr)) {
591
        IShellFolder_Release(pDesktop);
592
        return FALSE;
593 594 595
    }

    bi.pidlRoot = pidlUnixRoot;
596
    pidlSelectedPath = SHBrowseForFolderW(&bi);
597 598 599 600
    SHFree(pidlUnixRoot);
    
    if (pidlSelectedPath) {
        STRRET strSelectedPath;
601
        WCHAR *pszSelectedPath;
602 603
        HRESULT hr;
        
604 605 606
        hr = IShellFolder_GetDisplayNameOf(pDesktop, pidlSelectedPath, SHGDN_FORPARSING, 
                                           &strSelectedPath);
        IShellFolder_Release(pDesktop);
607
        if (FAILED(hr)) {
608
            SHFree(pidlSelectedPath);
609
            return FALSE;
610 611
        }

612
        hr = StrRetToStrW(&strSelectedPath, pidlSelectedPath, &pszSelectedPath);
613
        SHFree(pidlSelectedPath);
614
        if (FAILED(hr)) return FALSE;
615

616
        lstrcpyW(pszPath, pszSelectedPath);
617 618
        
        CoTaskMemFree(pszSelectedPath);
619
        return TRUE;
620
    }
621
    return FALSE;
622 623
}

624 625
static void init_listview_columns(HWND dialog)
{
626
    LVCOLUMNW listColumn;
627 628
    RECT viewRect;
    int width;
629
    WCHAR column[64];
630 631 632 633

    GetClientRect(GetDlgItem(dialog, IDC_LIST_DRIVES), &viewRect);
    width = (viewRect.right - viewRect.left) / 6 - 5;

634
    LoadStringW(GetModuleHandleW(NULL), IDS_COL_DRIVELETTER, column, ARRAY_SIZE(column));
635
    listColumn.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
636 637
    listColumn.pszText = column;
    listColumn.cchTextMax = lstrlenW (listColumn.pszText);
638 639
    listColumn.cx = width;

640
    SendDlgItemMessageW (dialog, IDC_LIST_DRIVES, LVM_INSERTCOLUMNW, 0, (LPARAM) &listColumn);
641

642
    LoadStringW(GetModuleHandleW(NULL), IDS_COL_DRIVEMAPPING, column, ARRAY_SIZE(column));
643
    listColumn.cx = viewRect.right - viewRect.left - width;
644 645
    listColumn.pszText = column;
    listColumn.cchTextMax = lstrlenW (listColumn.pszText);
646

647
    SendDlgItemMessageW (dialog, IDC_LIST_DRIVES, LVM_INSERTCOLUMNW, 1, (LPARAM) &listColumn);
648 649
}

650 651
static void load_drive_options(HWND dialog)
{
652
    if (!strcmp(get_reg_key(config_key, "", "ShowDotFiles", "N"), "Y"))
653 654
        CheckDlgButton(dialog, IDC_SHOW_DOT_FILES, BST_CHECKED);
}
655

Mike Hearn's avatar
Mike Hearn committed
656 657 658 659 660 661 662 663
INT_PTR CALLBACK
DriveDlgProc (HWND dialog, UINT msg, WPARAM wParam, LPARAM lParam)
{
    int item;

    switch (msg)
    {
        case WM_INITDIALOG:
664
            init_listview_columns(dialog);
665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
            if (!load_drives())
            {
                ShowWindow( GetDlgItem( dialog, IDC_STATIC_MOUNTMGR_ERROR ), SW_SHOW );
                ShowWindow( GetDlgItem( dialog, IDC_LIST_DRIVES ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_BUTTON_ADD ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_BUTTON_REMOVE ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_STATIC_PATH ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_EDIT_PATH ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_BUTTON_BROWSE_PATH ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_COMBO_TYPE ), SW_HIDE );
                ShowWindow( GetDlgItem( dialog, IDC_BUTTON_SHOW_HIDE_ADVANCED ), SW_HIDE );
                set_advanced(dialog);
                break;
            }
            ShowWindow( GetDlgItem( dialog, IDC_STATIC_MOUNTMGR_ERROR ), SW_HIDE );
680
            load_drive_options(dialog);
Mike Hearn's avatar
Mike Hearn committed
681 682

            if (!drives[2].in_use)
683
                driveui_msgbox (dialog, IDS_NO_DRIVE_C, MB_OK | MB_ICONEXCLAMATION);
Mike Hearn's avatar
Mike Hearn committed
684 685 686 687 688 689 690 691 692 693 694 695

            fill_drives_list(dialog);
            update_controls(dialog);
            /* put in non-advanced mode by default  */
            set_advanced(dialog);
            break;

        case WM_SHOWWINDOW:
            set_window_title(dialog);
            break;

        case WM_COMMAND:
696
            switch (HIWORD(wParam))
Mike Hearn's avatar
Mike Hearn committed
697
            {
698 699 700 701 702 703 704 705 706 707 708 709
                case EN_CHANGE:
                    on_edit_changed(dialog, LOWORD(wParam));
                    break;

                case BN_CLICKED:
                    switch (LOWORD(wParam))
                    {
                        case IDC_SHOW_DOT_FILES:
                            on_options_click(dialog);
                        break;
                    }
                    break;
710 711

                case CBN_SELCHANGE:
712
                    SendMessageW(GetParent(dialog), PSM_CHANGED, 0, 0);
713
                    break;
Mike Hearn's avatar
Mike Hearn committed
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
            }

            switch (LOWORD(wParam))
            {
                case IDC_BUTTON_ADD:
                    if (HIWORD(wParam) != BN_CLICKED) break;
                    on_add_click(dialog);
                    break;

                case IDC_BUTTON_REMOVE:
                    if (HIWORD(wParam) != BN_CLICKED) break;
                    on_remove_click(dialog);
                    break;

                case IDC_BUTTON_EDIT:
                    if (HIWORD(wParam) != BN_CLICKED) break;
730 731
                    item = SendMessageW(GetDlgItem(dialog, IDC_LIST_DRIVES),  LB_GETCURSEL, 0, 0);
                    SendMessageW(GetDlgItem(dialog, IDC_LIST_DRIVES), LB_GETITEMDATA, item, 0);
Mike Hearn's avatar
Mike Hearn committed
732 733 734 735 736 737 738 739
                    break;

                case IDC_BUTTON_SHOW_HIDE_ADVANCED:
                    advanced = !advanced;
                    set_advanced(dialog);
                    break;

                case IDC_BUTTON_BROWSE_PATH:
740
                {
741
                    WCHAR szTargetPath[FILENAME_MAX];
742
                    if (browse_for_unix_folder(dialog, szTargetPath)) 
743
                        set_textW(dialog, IDC_EDIT_PATH, szTargetPath);
Mike Hearn's avatar
Mike Hearn committed
744
                    break;
745
                }
Mike Hearn's avatar
Mike Hearn committed
746 747 748 749 750 751 752 753

                case IDC_COMBO_TYPE:
                {
                    int mode = BOX_MODE_NORMAL;
                    int selection;

                    if (HIWORD(wParam) != CBN_SELCHANGE) break;

754
                    selection = SendDlgItemMessageW(dialog, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0);
Mike Hearn's avatar
Mike Hearn committed
755

756 757 758
                    if (selection >= 0 &&
                        (type_pairs[selection].sCode == DRIVE_CDROM ||
                         type_pairs[selection].sCode == DRIVE_REMOVABLE))
759 760 761
                        mode = BOX_MODE_DEVICE;
                    else
                        mode = BOX_MODE_NORMAL;
Mike Hearn's avatar
Mike Hearn committed
762 763 764 765

                    enable_labelserial_box(dialog, mode);

                    current_drive->type = type_pairs[selection].sCode;
766
                    current_drive->modified = TRUE;
Mike Hearn's avatar
Mike Hearn committed
767 768 769 770 771 772 773 774 775 776 777
                    break;
                }

            }
            break;

        case WM_NOTIFY:
            switch (((LPNMHDR)lParam)->code)
            {
                case PSN_KILLACTIVE:
                    WINE_TRACE("PSN_KILLACTIVE\n");
778
                    SetWindowLongPtrW(dialog, DWLP_MSGRESULT, FALSE);
Mike Hearn's avatar
Mike Hearn committed
779 780 781
                    break;
                case PSN_APPLY:
                    apply_drive_changes();
782
                    SetWindowLongPtrW(dialog, DWLP_MSGRESULT, PSNRET_NOERROR);
Mike Hearn's avatar
Mike Hearn committed
783 784 785
                    break;
                case PSN_SETACTIVE:
                    break;
786 787 788 789 790
                case LVN_ITEMCHANGED:
                {
                    LPNMLISTVIEW lpnm = (LPNMLISTVIEW)lParam;
                    if (!(lpnm->uOldState & LVIS_SELECTED) &&
                         (lpnm->uNewState & LVIS_SELECTED))
791 792
                    update_controls(dialog);
                    break;
793
                }
794
            }
Mike Hearn's avatar
Mike Hearn committed
795 796 797 798 799
            break;
    }

    return FALSE;
}