Synchronize with trunk revision 59636 (just before Alex's CreateProcess revamp).
[reactos.git] / base / applications / notepad / dialog.c
1 /*
2 * Notepad (dialog.c)
3 *
4 * Copyright 1998,99 Marcel Baur <mbaur@g26.ethz.ch>
5 * Copyright 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
6 * Copyright 2002 Andriy Palamarchuk
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 Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include "notepad.h"
24
25 LRESULT CALLBACK EDIT_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
26
27 static const TCHAR helpfile[] = _T("notepad.hlp");
28 static const TCHAR empty_str[] = _T("");
29 static const TCHAR szDefaultExt[] = _T("txt");
30 static const TCHAR txt_files[] = _T("*.txt");
31
32 static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
33
34 #ifndef UNICODE
35 static LPSTR ConvertToASCII(LPSTR pszText)
36 {
37 int sz;
38 LPWSTR pszTextW = (LPWSTR)pszText;
39
40 /* default return value */
41 pszText = NULL;
42 do {
43 /* query about requested size for conversion */
44 sz = WideCharToMultiByte(CP_ACP, 0, pszTextW, -1, NULL, 0, NULL, NULL);
45 if (!sz)
46 break;
47
48 /* get space for ASCII buffer */
49 pszText = (LPSTR)HeapAlloc(GetProcessHeap(), 0, sz);
50 if (pszText == NULL)
51 break;
52
53 /* if previous diagnostic call worked fine,
54 * then this one will work too,
55 * so no need to test return value here
56 */
57 WideCharToMultiByte(CP_ACP, 0, pszTextW, -1, pszText, sz, NULL, NULL);
58 } while (0);
59
60 HeapFree(GetProcessHeap(), 0, pszTextW);
61 return pszText;
62 }
63
64 static LPWSTR ConvertToUNICODE(LPSTR pszText, DWORD *pdwSize)
65 {
66 int sz;
67 LPWSTR pszTextW = NULL;
68
69 do {
70 /* query about requested size for conversion */
71 sz = MultiByteToWideChar(CP_ACP, 0, pszText, -1, NULL, 0);
72 if (!sz)
73 break;
74
75 /* get space for UNICODE buffer */
76 pszTextW = HeapAlloc(GetProcessHeap(), 0, sz*sizeof(WCHAR));
77 if (pszText == NULL)
78 break;
79
80 /* if previous diagnostic call worked fine,
81 * then this one will work too,
82 * so no need to test return value here
83 */
84 MultiByteToWideChar(CP_ACP, 0, pszText, -1, pszTextW, sz);
85
86 /* report the new size of the text to the caller */
87 *pdwSize = sz;
88 } while (0);
89
90 HeapFree(GetProcessHeap(), 0, pszText);
91 return pszTextW;
92 }
93 #endif
94
95 VOID ShowLastError(VOID)
96 {
97 DWORD error = GetLastError();
98 if (error != NO_ERROR)
99 {
100 LPTSTR lpMsgBuf = NULL;
101 TCHAR szTitle[MAX_STRING_LEN];
102
103 LoadString(Globals.hInstance, STRING_ERROR, szTitle, SIZEOF(szTitle));
104 FormatMessage(
105 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
106 NULL, error, 0,
107 (LPTSTR) &lpMsgBuf, 0, NULL);
108 MessageBox(NULL, lpMsgBuf, szTitle, MB_OK | MB_ICONERROR);
109 LocalFree(lpMsgBuf);
110 }
111 }
112
113 /**
114 * Sets the caption of the main window according to Globals.szFileTitle:
115 * (untitled) - Notepad if no file is open
116 * [filename] - Notepad if a file is given
117 */
118 static void UpdateWindowCaption(void)
119 {
120 TCHAR szCaption[MAX_STRING_LEN];
121 TCHAR szNotepad[MAX_STRING_LEN];
122
123 LoadString(Globals.hInstance, STRING_NOTEPAD, szNotepad, SIZEOF(szNotepad));
124
125 if (Globals.szFileTitle[0] != 0)
126 {
127 StringCchCopy(szCaption, SIZEOF(szCaption), Globals.szFileTitle);
128 }
129 else
130 {
131 LoadString(Globals.hInstance, STRING_UNTITLED, szCaption, SIZEOF(szCaption));
132 }
133
134 StringCchCat(szCaption, SIZEOF(szCaption), _T(" - "));
135 StringCchCat(szCaption, SIZEOF(szCaption), szNotepad);
136 SetWindowText(Globals.hMainWnd, szCaption);
137 }
138
139 static void AlertFileNotFound(LPCTSTR szFileName)
140 {
141 TCHAR szMessage[MAX_STRING_LEN];
142 TCHAR szResource[MAX_STRING_LEN];
143
144 /* Load and format szMessage */
145 LoadString(Globals.hInstance, STRING_NOTFOUND, szResource, SIZEOF(szResource));
146 wsprintf(szMessage, szResource, szFileName);
147
148 /* Load szCaption */
149 LoadString(Globals.hInstance, STRING_NOTEPAD, szResource, SIZEOF(szResource));
150
151 /* Display Modal Dialog */
152 MessageBox(Globals.hMainWnd, szMessage, szResource, MB_ICONEXCLAMATION);
153 }
154
155 static int AlertFileNotSaved(LPCTSTR szFileName)
156 {
157 TCHAR szMessage[MAX_STRING_LEN];
158 TCHAR szResource[MAX_STRING_LEN];
159 TCHAR szUntitled[MAX_STRING_LEN];
160
161 LoadString(Globals.hInstance, STRING_UNTITLED, szUntitled, SIZEOF(szUntitled));
162
163 /* Load and format Message */
164 LoadString(Globals.hInstance, STRING_NOTSAVED, szResource, SIZEOF(szResource));
165 wsprintf(szMessage, szResource, szFileName[0] ? szFileName : szUntitled);
166
167 /* Load Caption */
168 LoadString(Globals.hInstance, STRING_NOTEPAD, szResource, SIZEOF(szResource));
169
170 /* Display modal */
171 return MessageBox(Globals.hMainWnd, szMessage, szResource, MB_ICONEXCLAMATION|MB_YESNOCANCEL);
172 }
173
174 /**
175 * Returns:
176 * TRUE - if file exists
177 * FALSE - if file does not exist
178 */
179 BOOL FileExists(LPCTSTR szFilename)
180 {
181 WIN32_FIND_DATA entry;
182 HANDLE hFile;
183
184 hFile = FindFirstFile(szFilename, &entry);
185 FindClose(hFile);
186
187 return (hFile != INVALID_HANDLE_VALUE);
188 }
189
190 BOOL HasFileExtension(LPCTSTR szFilename)
191 {
192 LPCTSTR s;
193
194 s = _tcsrchr(szFilename, _T('\\'));
195 if (s)
196 szFilename = s;
197 return _tcsrchr(szFilename, _T('.')) != NULL;
198 }
199
200 static BOOL DoSaveFile(VOID)
201 {
202 BOOL bRet = TRUE;
203 HANDLE hFile;
204 LPTSTR pTemp;
205 DWORD size;
206
207 hFile = CreateFile(Globals.szFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
208 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
209 if(hFile == INVALID_HANDLE_VALUE)
210 {
211 ShowLastError();
212 return FALSE;
213 }
214
215 size = GetWindowTextLength(Globals.hEdit) + 1;
216 pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*pTemp));
217 if (!pTemp)
218 {
219 CloseHandle(hFile);
220 ShowLastError();
221 return FALSE;
222 }
223 size = GetWindowText(Globals.hEdit, pTemp, size);
224
225 #ifndef UNICODE
226 pTemp = (LPTSTR)ConvertToUNICODE(pTemp, &size);
227 if (!pTemp)
228 {
229 /* original "pTemp" already freed */
230 CloseHandle(hFile);
231 ShowLastError();
232 return FALSE;
233 }
234 #endif
235
236 if (size)
237 {
238 if (!WriteText(hFile, (LPWSTR)pTemp, size, Globals.iEncoding, Globals.iEoln))
239 {
240 ShowLastError();
241 bRet = FALSE;
242 }
243 else
244 {
245 SendMessage(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
246 bRet = TRUE;
247 }
248 }
249
250 CloseHandle(hFile);
251 HeapFree(GetProcessHeap(), 0, pTemp);
252 return bRet;
253 }
254
255 /**
256 * Returns:
257 * TRUE - User agreed to close (both save/don't save)
258 * FALSE - User cancelled close by selecting "Cancel"
259 */
260 BOOL DoCloseFile(VOID)
261 {
262 int nResult;
263
264 if (SendMessage(Globals.hEdit, EM_GETMODIFY, 0, 0))
265 {
266 /* prompt user to save changes */
267 nResult = AlertFileNotSaved(Globals.szFileName);
268 switch (nResult)
269 {
270 case IDYES:
271 if(!DIALOG_FileSave())
272 return FALSE;
273 break;
274
275 case IDNO:
276 break;
277
278 case IDCANCEL:
279 return FALSE;
280
281 default:
282 return FALSE;
283 }
284 }
285
286 SetFileName(empty_str);
287 UpdateWindowCaption();
288
289 return TRUE;
290 }
291
292 VOID DoOpenFile(LPCTSTR szFileName)
293 {
294 static const TCHAR dotlog[] = _T(".LOG");
295 HANDLE hFile;
296 LPTSTR pszText = NULL;
297 DWORD dwTextLen;
298 TCHAR log[5];
299
300 /* Close any files and prompt to save changes */
301 if (!DoCloseFile())
302 return;
303
304 hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
305 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
306 if (hFile == INVALID_HANDLE_VALUE)
307 {
308 ShowLastError();
309 goto done;
310 }
311
312 if (!ReadText(hFile, (LPWSTR *)&pszText, &dwTextLen, &Globals.iEncoding, &Globals.iEoln))
313 {
314 ShowLastError();
315 goto done;
316 }
317 #ifndef UNICODE
318 pszText = ConvertToASCII(pszText);
319 if (pszText == NULL) {
320 ShowLastError();
321 goto done;
322 }
323 #endif
324 SetWindowText(Globals.hEdit, pszText);
325
326 SendMessage(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
327 SendMessage(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
328 SetFocus(Globals.hEdit);
329
330 /* If the file starts with .LOG, add a time/date at the end and set cursor after
331 * See http://support.microsoft.com/?kbid=260563
332 */
333 if (GetWindowText(Globals.hEdit, log, SIZEOF(log)) && !_tcscmp(log, dotlog))
334 {
335 static const TCHAR lf[] = _T("\r\n");
336 SendMessage(Globals.hEdit, EM_SETSEL, GetWindowTextLength(Globals.hEdit), -1);
337 SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lf);
338 DIALOG_EditTimeDate();
339 SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lf);
340 }
341
342 SetFileName(szFileName);
343 UpdateWindowCaption();
344 NOTEPAD_EnableSearchMenu();
345 done:
346 if (hFile != INVALID_HANDLE_VALUE)
347 CloseHandle(hFile);
348 if (pszText)
349 HeapFree(GetProcessHeap(), 0, pszText);
350 }
351
352 VOID DIALOG_FileNew(VOID)
353 {
354 /* Close any files and prompt to save changes */
355 if (DoCloseFile()) {
356 SetWindowText(Globals.hEdit, empty_str);
357 SendMessage(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
358 SetFocus(Globals.hEdit);
359 NOTEPAD_EnableSearchMenu();
360 }
361 }
362
363 VOID DIALOG_FileOpen(VOID)
364 {
365 OPENFILENAME openfilename;
366 TCHAR szDir[MAX_PATH];
367 TCHAR szPath[MAX_PATH];
368
369 ZeroMemory(&openfilename, sizeof(openfilename));
370
371 GetCurrentDirectory(SIZEOF(szDir), szDir);
372 if (Globals.szFileName[0] == 0)
373 _tcscpy(szPath, txt_files);
374 else
375 _tcscpy(szPath, Globals.szFileName);
376
377 openfilename.lStructSize = sizeof(openfilename);
378 openfilename.hwndOwner = Globals.hMainWnd;
379 openfilename.hInstance = Globals.hInstance;
380 openfilename.lpstrFilter = Globals.szFilter;
381 openfilename.lpstrFile = szPath;
382 openfilename.nMaxFile = SIZEOF(szPath);
383 openfilename.lpstrInitialDir = szDir;
384 openfilename.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST |
385 OFN_HIDEREADONLY;
386 openfilename.lpstrDefExt = szDefaultExt;
387
388
389 if (GetOpenFileName(&openfilename)) {
390 if (FileExists(openfilename.lpstrFile))
391 DoOpenFile(openfilename.lpstrFile);
392 else
393 AlertFileNotFound(openfilename.lpstrFile);
394 }
395 }
396
397
398 BOOL DIALOG_FileSave(VOID)
399 {
400 if (Globals.szFileName[0] == 0)
401 return DIALOG_FileSaveAs();
402 else
403 return DoSaveFile();
404 }
405
406 static UINT_PTR CALLBACK DIALOG_FileSaveAs_Hook(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
407 {
408 TCHAR szText[128];
409 HWND hCombo;
410
411 UNREFERENCED_PARAMETER(wParam);
412
413 switch(msg)
414 {
415 case WM_INITDIALOG:
416 hCombo = GetDlgItem(hDlg, ID_ENCODING);
417
418 LoadString(Globals.hInstance, STRING_ANSI, szText, SIZEOF(szText));
419 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
420
421 LoadString(Globals.hInstance, STRING_UNICODE, szText, SIZEOF(szText));
422 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
423
424 LoadString(Globals.hInstance, STRING_UNICODE_BE, szText, SIZEOF(szText));
425 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
426
427 LoadString(Globals.hInstance, STRING_UTF8, szText, SIZEOF(szText));
428 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
429
430 SendMessage(hCombo, CB_SETCURSEL, Globals.iEncoding, 0);
431
432 hCombo = GetDlgItem(hDlg, ID_EOLN);
433
434 LoadString(Globals.hInstance, STRING_CRLF, szText, SIZEOF(szText));
435 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
436
437 LoadString(Globals.hInstance, STRING_LF, szText, SIZEOF(szText));
438 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
439
440 LoadString(Globals.hInstance, STRING_CR, szText, SIZEOF(szText));
441 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
442
443 SendMessage(hCombo, CB_SETCURSEL, Globals.iEoln, 0);
444 break;
445
446 case WM_NOTIFY:
447 if (((NMHDR *) lParam)->code == CDN_FILEOK)
448 {
449 hCombo = GetDlgItem(hDlg, ID_ENCODING);
450 if (hCombo)
451 Globals.iEncoding = (int) SendMessage(hCombo, CB_GETCURSEL, 0, 0);
452
453 hCombo = GetDlgItem(hDlg, ID_EOLN);
454 if (hCombo)
455 Globals.iEoln = (int) SendMessage(hCombo, CB_GETCURSEL, 0, 0);
456 }
457 break;
458 }
459 return 0;
460 }
461
462 BOOL DIALOG_FileSaveAs(VOID)
463 {
464 OPENFILENAME saveas;
465 TCHAR szDir[MAX_PATH];
466 TCHAR szPath[MAX_PATH];
467
468 ZeroMemory(&saveas, sizeof(saveas));
469
470 GetCurrentDirectory(SIZEOF(szDir), szDir);
471 if (Globals.szFileName[0] == 0)
472 _tcscpy(szPath, txt_files);
473 else
474 _tcscpy(szPath, Globals.szFileName);
475
476 saveas.lStructSize = sizeof(OPENFILENAME);
477 saveas.hwndOwner = Globals.hMainWnd;
478 saveas.hInstance = Globals.hInstance;
479 saveas.lpstrFilter = Globals.szFilter;
480 saveas.lpstrFile = szPath;
481 saveas.nMaxFile = SIZEOF(szPath);
482 saveas.lpstrInitialDir = szDir;
483 saveas.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT |
484 OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
485 saveas.lpstrDefExt = szDefaultExt;
486 saveas.lpTemplateName = MAKEINTRESOURCE(DIALOG_ENCODING);
487 saveas.lpfnHook = DIALOG_FileSaveAs_Hook;
488
489 if (GetSaveFileName(&saveas))
490 {
491 // HACK: Because in ROS, Save-As boxes don't check the validity
492 // of file names and thus, here, szPath can be invalid !! We only
493 // see its validity when we call DoSaveFile()...
494 SetFileName(szPath);
495 if (DoSaveFile())
496 {
497 UpdateWindowCaption();
498 return TRUE;
499 }
500 else
501 {
502 SetFileName(_T(""));
503 return FALSE;
504 }
505 }
506 else
507 {
508 return FALSE;
509 }
510 }
511
512 VOID DIALOG_FilePrint(VOID)
513 {
514 DOCINFO di;
515 PRINTDLG printer;
516 SIZE szMetric;
517 int cWidthPels, cHeightPels, border;
518 int xLeft, yTop, pagecount, dopage, copycount;
519 unsigned int i;
520 LOGFONT hdrFont;
521 HFONT font, old_font=0;
522 DWORD size;
523 LPTSTR pTemp;
524 static const TCHAR times_new_roman[] = _T("Times New Roman");
525
526 /* Get a small font and print some header info on each page */
527 ZeroMemory(&hdrFont, sizeof(hdrFont));
528 hdrFont.lfHeight = 100;
529 hdrFont.lfWeight = FW_BOLD;
530 hdrFont.lfCharSet = ANSI_CHARSET;
531 hdrFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
532 hdrFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
533 hdrFont.lfQuality = PROOF_QUALITY;
534 hdrFont.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN;
535 _tcscpy(hdrFont.lfFaceName, times_new_roman);
536
537 font = CreateFontIndirect(&hdrFont);
538
539 /* Get Current Settings */
540 ZeroMemory(&printer, sizeof(printer));
541 printer.lStructSize = sizeof(printer);
542 printer.hwndOwner = Globals.hMainWnd;
543 printer.hInstance = Globals.hInstance;
544
545 /* Set some default flags */
546 printer.Flags = PD_RETURNDC;
547 printer.nFromPage = 0;
548 printer.nMinPage = 1;
549 /* we really need to calculate number of pages to set nMaxPage and nToPage */
550 printer.nToPage = 0;
551 printer.nMaxPage = (WORD) -1;
552
553 /* Let commdlg manage copy settings */
554 printer.nCopies = (WORD)PD_USEDEVMODECOPIES;
555
556 if (!PrintDlg(&printer)) return;
557
558 assert(printer.hDC != 0);
559
560 /* initialize DOCINFO */
561 di.cbSize = sizeof(DOCINFO);
562 di.lpszDocName = Globals.szFileTitle;
563 di.lpszOutput = NULL;
564 di.lpszDatatype = NULL;
565 di.fwType = 0;
566
567 if (StartDoc(printer.hDC, &di) <= 0) return;
568
569 /* Get the page dimensions in pixels. */
570 cWidthPels = GetDeviceCaps(printer.hDC, HORZRES);
571 cHeightPels = GetDeviceCaps(printer.hDC, VERTRES);
572
573 /* Get the file text */
574 size = GetWindowTextLength(Globals.hEdit) + 1;
575 pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(TCHAR));
576 if (!pTemp)
577 {
578 ShowLastError();
579 return;
580 }
581 size = GetWindowText(Globals.hEdit, pTemp, size);
582
583 border = 150;
584 for (copycount=1; copycount <= printer.nCopies; copycount++) {
585 i = 0;
586 pagecount = 1;
587 do {
588 static const TCHAR letterM[] = _T("M");
589
590 if (pagecount >= printer.nFromPage &&
591 /* ((printer.Flags & PD_PAGENUMS) == 0 || pagecount <= printer.nToPage))*/
592 pagecount <= printer.nToPage)
593 dopage = 1;
594 else
595 dopage = 0;
596
597 old_font = SelectObject(printer.hDC, font);
598 GetTextExtentPoint32(printer.hDC, letterM, 1, &szMetric);
599
600 if (dopage) {
601 if (StartPage(printer.hDC) <= 0) {
602 static const TCHAR failed[] = _T("StartPage failed");
603 static const TCHAR error[] = _T("Print Error");
604 MessageBox(Globals.hMainWnd, failed, error, MB_ICONEXCLAMATION);
605 return;
606 }
607 /* Write a rectangle and header at the top of each page */
608 Rectangle(printer.hDC, border, border, cWidthPels-border, border+szMetric.cy*2);
609 /* I don't know what's up with this TextOut command. This comes out
610 kind of mangled.
611 */
612 TextOut(printer.hDC, border*2, border+szMetric.cy/2, Globals.szFileTitle, lstrlen(Globals.szFileTitle));
613 }
614
615 /* The starting point for the main text */
616 xLeft = border*2;
617 yTop = border+szMetric.cy*4;
618
619 SelectObject(printer.hDC, old_font);
620 GetTextExtentPoint32(printer.hDC, letterM, 1, &szMetric);
621
622 /* Since outputting strings is giving me problems, output the main
623 text one character at a time.
624 */
625 do {
626 if (pTemp[i] == '\n') {
627 xLeft = border*2;
628 yTop += szMetric.cy;
629 }
630 else if (pTemp[i] != '\r') {
631 if (dopage)
632 TextOut(printer.hDC, xLeft, yTop, &pTemp[i], 1);
633 xLeft += szMetric.cx;
634 }
635 } while (i++<size && yTop<(cHeightPels-border*2));
636
637 if (dopage)
638 EndPage(printer.hDC);
639 pagecount++;
640 } while (i<size);
641 }
642
643 EndDoc(printer.hDC);
644 DeleteDC(printer.hDC);
645 HeapFree(GetProcessHeap(), 0, pTemp);
646 }
647
648 VOID DIALOG_FilePrinterSetup(VOID)
649 {
650 PRINTDLG printer;
651
652 ZeroMemory(&printer, sizeof(printer));
653 printer.lStructSize = sizeof(printer);
654 printer.hwndOwner = Globals.hMainWnd;
655 printer.hInstance = Globals.hInstance;
656 printer.Flags = PD_PRINTSETUP;
657 printer.nCopies = 1;
658
659 PrintDlg(&printer);
660 }
661
662 VOID DIALOG_FileExit(VOID)
663 {
664 PostMessage(Globals.hMainWnd, WM_CLOSE, 0, 0l);
665 }
666
667 VOID DIALOG_EditUndo(VOID)
668 {
669 SendMessage(Globals.hEdit, EM_UNDO, 0, 0);
670 }
671
672 VOID DIALOG_EditCut(VOID)
673 {
674 SendMessage(Globals.hEdit, WM_CUT, 0, 0);
675 }
676
677 VOID DIALOG_EditCopy(VOID)
678 {
679 SendMessage(Globals.hEdit, WM_COPY, 0, 0);
680 }
681
682 VOID DIALOG_EditPaste(VOID)
683 {
684 SendMessage(Globals.hEdit, WM_PASTE, 0, 0);
685 }
686
687 VOID DIALOG_EditDelete(VOID)
688 {
689 SendMessage(Globals.hEdit, WM_CLEAR, 0, 0);
690 }
691
692 VOID DIALOG_EditSelectAll(VOID)
693 {
694 SendMessage(Globals.hEdit, EM_SETSEL, 0, (LPARAM)-1);
695 }
696
697 VOID DIALOG_EditTimeDate(VOID)
698 {
699 SYSTEMTIME st;
700 TCHAR szDate[MAX_STRING_LEN];
701 TCHAR szText[MAX_STRING_LEN * 2 + 2];
702
703 GetLocalTime(&st);
704
705 GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szDate, MAX_STRING_LEN);
706 _tcscpy(szText, szDate);
707 _tcscat(szText, _T(" "));
708 GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szDate, MAX_STRING_LEN);
709 _tcscat(szText, szDate);
710 SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szText);
711 }
712
713 VOID DoCreateStatusBar(VOID)
714 {
715 RECT rc;
716 RECT rcstatus;
717 BOOL bStatusBarVisible;
718
719 // Check if status bar object already exists.
720 if (Globals.hStatusBar == NULL)
721 {
722 // Try to create the status bar
723 Globals.hStatusBar = CreateStatusWindow(
724 WS_CHILD | WS_VISIBLE | WS_EX_STATICEDGE,
725 NULL,
726 Globals.hMainWnd,
727 CMD_STATUSBAR_WND_ID);
728
729 if (Globals.hStatusBar == NULL)
730 {
731 ShowLastError();
732 return;
733 }
734
735 // Load the string for formatting column/row text output
736 LoadString(Globals.hInstance, STRING_LINE_COLUMN, Globals.szStatusBarLineCol, MAX_PATH-1);
737
738 // Set the status bar for single-text output
739 SendMessage(Globals.hStatusBar, SB_SIMPLE, (WPARAM)TRUE, (LPARAM)0);
740 }
741
742 // Set status bar visible or not accordind the the settings.
743 if (Globals.bWrapLongLines == TRUE ||
744 Globals.bShowStatusBar == FALSE)
745 {
746 bStatusBarVisible = FALSE;
747 ShowWindow(Globals.hStatusBar, SW_HIDE);
748 }
749 else
750 {
751 bStatusBarVisible = TRUE;
752 ShowWindow(Globals.hStatusBar, SW_SHOW);
753 SendMessage(Globals.hStatusBar, WM_SIZE, 0, 0);
754 }
755
756 // Set check state in show status bar item.
757 if (Globals.bShowStatusBar == TRUE)
758 {
759 CheckMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_CHECKED);
760 }
761 else
762 {
763 CheckMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_UNCHECKED);
764 }
765
766 // Update menu mar with the previous changes
767 DrawMenuBar(Globals.hMainWnd);
768
769 // Sefety test is edit control exists
770 if (Globals.hEdit != NULL)
771 {
772 // Retrieve the sizes of the controls
773 GetClientRect(Globals.hMainWnd, &rc);
774 GetClientRect(Globals.hStatusBar, &rcstatus);
775
776 // If status bar is currently visible, update dimensions of edir control
777 if (bStatusBarVisible)
778 rc.bottom -= (rcstatus.bottom - rcstatus.top);
779
780 // Resize edit control to right size.
781 MoveWindow(Globals.hEdit, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
782 }
783
784 // Update content with current row/column text
785 DIALOG_StatusBarUpdateCaretPos();
786 }
787
788 VOID DoCreateEditWindow(VOID)
789 {
790 DWORD dwStyle;
791 int iSize;
792 LPTSTR pTemp = NULL;
793
794 iSize = 0;
795
796 // If the edit control already exists, try to save its content
797 if (Globals.hEdit != NULL)
798 {
799 // number of chars currently written into the editor.
800 iSize = GetWindowTextLength(Globals.hEdit);
801
802 if (iSize)
803 {
804 // Allocates temporary buffer.
805 pTemp = HeapAlloc(GetProcessHeap(), 0, (iSize + 1) * sizeof(TCHAR));
806
807 if (!pTemp)
808 {
809 ShowLastError();
810 return;
811 }
812
813 // Recover the text into the control.
814 GetWindowText(Globals.hEdit, pTemp, iSize + 1);
815 }
816
817 // Restore original window procedure
818 SetWindowLongPtr(Globals.hEdit, GWLP_WNDPROC, (LONG_PTR)Globals.EditProc);
819
820 // Destroy the edit control
821 DestroyWindow(Globals.hEdit);
822 }
823
824 // Update wrap status into the main menu and recover style flags
825 if (Globals.bWrapLongLines)
826 {
827 dwStyle = EDIT_STYLE_WRAP;
828 EnableMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
829 } else {
830 dwStyle = EDIT_STYLE;
831 EnableMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_ENABLED);
832 }
833
834 // Update previous changes
835 DrawMenuBar(Globals.hMainWnd);
836
837 // Create the new edit control
838 Globals.hEdit = CreateWindowEx(
839 WS_EX_CLIENTEDGE,
840 EDIT_CLASS,
841 NULL,
842 dwStyle,
843 CW_USEDEFAULT,
844 CW_USEDEFAULT,
845 CW_USEDEFAULT,
846 CW_USEDEFAULT,
847 Globals.hMainWnd,
848 NULL,
849 Globals.hInstance,
850 NULL);
851
852 if (Globals.hEdit == NULL)
853 {
854 ShowLastError();
855 return;
856 }
857
858 SendMessage(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, FALSE);
859 SendMessage(Globals.hEdit, EM_LIMITTEXT, 0, 0);
860
861 // If some text was previously saved, restore it.
862 if (iSize != 0)
863 {
864 SetWindowText(Globals.hEdit, pTemp);
865 HeapFree(GetProcessHeap(), 0, pTemp);
866 }
867
868 // Sub-class a new window callback for row/column detection.
869 Globals.EditProc = (WNDPROC) SetWindowLongPtr(Globals.hEdit, GWLP_WNDPROC, (LONG_PTR)EDIT_WndProc);
870
871 // Create/update status bar
872 DoCreateStatusBar();
873
874 // Finally shows new edit control and set focus into it.
875 ShowWindow(Globals.hEdit, SW_SHOW);
876 SetFocus(Globals.hEdit);
877 }
878
879 VOID DIALOG_EditWrap(VOID)
880 {
881 Globals.bWrapLongLines = !Globals.bWrapLongLines;
882
883 DoCreateEditWindow();
884 }
885
886 VOID DIALOG_SelectFont(VOID)
887 {
888 CHOOSEFONT cf;
889 LOGFONT lf=Globals.lfFont;
890
891 ZeroMemory( &cf, sizeof(cf) );
892 cf.lStructSize=sizeof(cf);
893 cf.hwndOwner=Globals.hMainWnd;
894 cf.lpLogFont=&lf;
895 cf.Flags=CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT;
896
897 if( ChooseFont(&cf) )
898 {
899 HFONT currfont=Globals.hFont;
900
901 Globals.hFont=CreateFontIndirect( &lf );
902 Globals.lfFont=lf;
903 SendMessage( Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, (LPARAM)TRUE );
904 if( currfont!=NULL )
905 DeleteObject( currfont );
906 }
907 }
908
909 typedef HWND (WINAPI *FINDPROC)(LPFINDREPLACE lpfr);
910
911 static VOID DIALOG_SearchDialog(FINDPROC pfnProc)
912 {
913 ZeroMemory(&Globals.find, sizeof(Globals.find));
914 Globals.find.lStructSize = sizeof(Globals.find);
915 Globals.find.hwndOwner = Globals.hMainWnd;
916 Globals.find.hInstance = Globals.hInstance;
917 Globals.find.lpstrFindWhat = Globals.szFindText;
918 Globals.find.wFindWhatLen = SIZEOF(Globals.szFindText);
919 Globals.find.lpstrReplaceWith = Globals.szReplaceText;
920 Globals.find.wReplaceWithLen = SIZEOF(Globals.szReplaceText);
921 Globals.find.Flags = FR_DOWN;
922
923 /* We only need to create the modal FindReplace dialog which will */
924 /* notify us of incoming events using hMainWnd Window Messages */
925
926 Globals.hFindReplaceDlg = pfnProc(&Globals.find);
927 assert(Globals.hFindReplaceDlg !=0);
928 }
929
930 VOID DIALOG_Search(VOID)
931 {
932 DIALOG_SearchDialog(FindText);
933 }
934
935 VOID DIALOG_SearchNext(VOID)
936 {
937 if (Globals.find.lpstrFindWhat != NULL)
938 NOTEPAD_FindNext(&Globals.find, FALSE, TRUE);
939 else
940 DIALOG_Search();
941 }
942
943 VOID DIALOG_Replace(VOID)
944 {
945 DIALOG_SearchDialog(ReplaceText);
946 }
947
948 static INT_PTR CALLBACK DIALOG_GoTo_DialogProc(HWND hwndDialog, UINT uMsg, WPARAM wParam, LPARAM lParam)
949 {
950 BOOL bResult = FALSE;
951 HWND hTextBox;
952 TCHAR szText[32];
953
954 switch(uMsg) {
955 case WM_INITDIALOG:
956 hTextBox = GetDlgItem(hwndDialog, ID_LINENUMBER);
957 _sntprintf(szText, SIZEOF(szText), _T("%d"), lParam);
958 SetWindowText(hTextBox, szText);
959 break;
960 case WM_COMMAND:
961 if (HIWORD(wParam) == BN_CLICKED)
962 {
963 if (LOWORD(wParam) == IDOK)
964 {
965 hTextBox = GetDlgItem(hwndDialog, ID_LINENUMBER);
966 GetWindowText(hTextBox, szText, SIZEOF(szText));
967 EndDialog(hwndDialog, _ttoi(szText));
968 bResult = TRUE;
969 }
970 else if (LOWORD(wParam) == IDCANCEL)
971 {
972 EndDialog(hwndDialog, 0);
973 bResult = TRUE;
974 }
975 }
976 break;
977 }
978
979 return bResult;
980 }
981
982 VOID DIALOG_GoTo(VOID)
983 {
984 INT_PTR nLine;
985 LPTSTR pszText;
986 int nLength, i;
987 DWORD dwStart, dwEnd;
988
989 nLength = GetWindowTextLength(Globals.hEdit);
990 pszText = (LPTSTR) HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(*pszText));
991 if (!pszText)
992 return;
993
994 /* Retrieve current text */
995 GetWindowText(Globals.hEdit, pszText, nLength + 1);
996 SendMessage(Globals.hEdit, EM_GETSEL, (WPARAM) &dwStart, (LPARAM) &dwEnd);
997
998 nLine = 1;
999 for (i = 0; pszText[i] && (i < (int) dwStart); i++)
1000 {
1001 if (pszText[i] == '\n')
1002 nLine++;
1003 }
1004
1005 nLine = DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(DIALOG_GOTO),
1006 Globals.hMainWnd, DIALOG_GoTo_DialogProc, nLine);
1007
1008 if (nLine >= 1)
1009 {
1010 for (i = 0; pszText[i] && (nLine > 1) && (i < nLength - 1); i++)
1011 {
1012 if (pszText[i] == '\n')
1013 nLine--;
1014 }
1015 SendMessage(Globals.hEdit, EM_SETSEL, i, i);
1016 SendMessage(Globals.hEdit, EM_SCROLLCARET, 0, 0);
1017 }
1018 HeapFree(GetProcessHeap(), 0, pszText);
1019 }
1020
1021 VOID DIALOG_StatusBarUpdateCaretPos(VOID)
1022 {
1023 int line, col;
1024 TCHAR buff[MAX_PATH];
1025 DWORD dwStart, dwSize;
1026
1027 SendMessage(Globals.hEdit, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwSize);
1028 line = SendMessage(Globals.hEdit, EM_LINEFROMCHAR, (WPARAM)dwStart, 0);
1029 col = dwStart - SendMessage(Globals.hEdit, EM_LINEINDEX, (WPARAM)line, 0);
1030
1031 _stprintf(buff, Globals.szStatusBarLineCol, line+1, col+1);
1032 SendMessage(Globals.hStatusBar, SB_SETTEXT, SB_SIMPLEID, (LPARAM)buff);
1033 }
1034
1035 VOID DIALOG_ViewStatusBar(VOID)
1036 {
1037 Globals.bShowStatusBar = !Globals.bShowStatusBar;
1038
1039 DoCreateStatusBar();
1040 }
1041
1042 VOID DIALOG_HelpContents(VOID)
1043 {
1044 WinHelp(Globals.hMainWnd, helpfile, HELP_INDEX, 0);
1045 }
1046
1047 VOID DIALOG_HelpSearch(VOID)
1048 {
1049 /* Search Help */
1050 }
1051
1052 VOID DIALOG_HelpHelp(VOID)
1053 {
1054 WinHelp(Globals.hMainWnd, helpfile, HELP_HELPONHELP, 0);
1055 }
1056
1057 #ifdef _MSC_VER
1058 #pragma warning(disable : 4100)
1059 #endif
1060 INT_PTR CALLBACK
1061 AboutDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1062 {
1063 HWND hLicenseEditWnd;
1064 TCHAR *strLicense;
1065
1066 switch (message)
1067 {
1068 case WM_INITDIALOG:
1069
1070 hLicenseEditWnd = GetDlgItem(hDlg, IDC_LICENSE);
1071
1072 /* 0x1000 should be enought */
1073 strLicense = (TCHAR *)_alloca(0x1000);
1074 LoadString(GetModuleHandle(NULL), STRING_LICENSE, strLicense, 0x1000);
1075
1076 SetWindowText(hLicenseEditWnd, strLicense);
1077
1078 return TRUE;
1079
1080 case WM_COMMAND:
1081
1082 if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL))
1083 {
1084 EndDialog(hDlg, LOWORD(wParam));
1085 return TRUE;
1086 }
1087
1088 break;
1089 }
1090
1091 return 0;
1092 }
1093
1094
1095
1096 VOID DIALOG_HelpAboutWine(VOID)
1097 {
1098 TCHAR szNotepad[MAX_STRING_LEN];
1099 HICON notepadIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_NPICON));
1100
1101 LoadString(Globals.hInstance, STRING_NOTEPAD, szNotepad, SIZEOF(szNotepad));
1102 ShellAbout(Globals.hMainWnd, szNotepad, 0, notepadIcon);
1103 DeleteObject(notepadIcon);
1104 }
1105
1106
1107 /***********************************************************************
1108 *
1109 * DIALOG_FilePageSetup
1110 */
1111 VOID DIALOG_FilePageSetup(void)
1112 {
1113 DialogBox(Globals.hInstance, MAKEINTRESOURCE(DIALOG_PAGESETUP),
1114 Globals.hMainWnd, DIALOG_PAGESETUP_DlgProc);
1115 }
1116
1117
1118 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1119 *
1120 * DIALOG_PAGESETUP_DlgProc
1121 */
1122
1123 static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1124 {
1125
1126 switch (msg)
1127 {
1128 case WM_COMMAND:
1129 if (HIWORD(wParam) == BN_CLICKED)
1130 {
1131 switch (LOWORD(wParam))
1132 {
1133 case IDOK:
1134 /* save user input and close dialog */
1135 GetDlgItemText(hDlg, 0x141, Globals.szHeader, SIZEOF(Globals.szHeader));
1136 GetDlgItemText(hDlg, 0x143, Globals.szFooter, SIZEOF(Globals.szFooter));
1137 GetDlgItemText(hDlg, 0x14A, Globals.szMarginTop, SIZEOF(Globals.szMarginTop));
1138 GetDlgItemText(hDlg, 0x150, Globals.szMarginBottom, SIZEOF(Globals.szMarginBottom));
1139 GetDlgItemText(hDlg, 0x147, Globals.szMarginLeft, SIZEOF(Globals.szMarginLeft));
1140 GetDlgItemText(hDlg, 0x14D, Globals.szMarginRight, SIZEOF(Globals.szMarginRight));
1141 EndDialog(hDlg, IDOK);
1142 return TRUE;
1143
1144 case IDCANCEL:
1145 /* discard user input and close dialog */
1146 EndDialog(hDlg, IDCANCEL);
1147 return TRUE;
1148
1149 case IDHELP:
1150 {
1151 /* FIXME: Bring this to work */
1152 static const TCHAR sorry[] = _T("Sorry, no help available");
1153 static const TCHAR help[] = _T("Help");
1154 MessageBox(Globals.hMainWnd, sorry, help, MB_ICONEXCLAMATION);
1155 return TRUE;
1156 }
1157
1158 default:
1159 break;
1160 }
1161 }
1162 break;
1163
1164 case WM_INITDIALOG:
1165 /* fetch last user input prior to display dialog */
1166 SetDlgItemText(hDlg, 0x141, Globals.szHeader);
1167 SetDlgItemText(hDlg, 0x143, Globals.szFooter);
1168 SetDlgItemText(hDlg, 0x14A, Globals.szMarginTop);
1169 SetDlgItemText(hDlg, 0x150, Globals.szMarginBottom);
1170 SetDlgItemText(hDlg, 0x147, Globals.szMarginLeft);
1171 SetDlgItemText(hDlg, 0x14D, Globals.szMarginRight);
1172 break;
1173 }
1174
1175 return FALSE;
1176 }