[KERNEL32]
[reactos.git] / reactos / 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 * Notepad - (untitled) if no file is open
116 * Notepad - [filename] if a file is given
117 */
118 static void UpdateWindowCaption(void)
119 {
120 TCHAR szCaption[MAX_STRING_LEN];
121 TCHAR szUntitled[MAX_STRING_LEN];
122
123 LoadString(Globals.hInstance, STRING_NOTEPAD, szCaption, SIZEOF(szCaption));
124
125 if (Globals.szFileTitle[0] != '\0') {
126 static const TCHAR bracket_l[] = _T(" - [");
127 static const TCHAR bracket_r[] = _T("]");
128 _tcscat(szCaption, bracket_l);
129 _tcscat(szCaption, Globals.szFileTitle);
130 _tcscat(szCaption, bracket_r);
131 }
132 else
133 {
134 static const TCHAR hyphen[] = _T(" - ");
135 LoadString(Globals.hInstance, STRING_UNTITLED, szUntitled, SIZEOF(szUntitled));
136 _tcscat(szCaption, hyphen);
137 _tcscat(szCaption, szUntitled);
138 }
139
140 SetWindowText(Globals.hMainWnd, szCaption);
141 }
142
143 static void AlertFileNotFound(LPCTSTR szFileName)
144 {
145 TCHAR szMessage[MAX_STRING_LEN];
146 TCHAR szResource[MAX_STRING_LEN];
147
148 /* Load and format szMessage */
149 LoadString(Globals.hInstance, STRING_NOTFOUND, szResource, SIZEOF(szResource));
150 wsprintf(szMessage, szResource, szFileName);
151
152 /* Load szCaption */
153 LoadString(Globals.hInstance, STRING_NOTEPAD, szResource, SIZEOF(szResource));
154
155 /* Display Modal Dialog */
156 MessageBox(Globals.hMainWnd, szMessage, szResource, MB_ICONEXCLAMATION);
157 }
158
159 static int AlertFileNotSaved(LPCTSTR szFileName)
160 {
161 TCHAR szMessage[MAX_STRING_LEN];
162 TCHAR szResource[MAX_STRING_LEN];
163 TCHAR szUntitled[MAX_STRING_LEN];
164
165 LoadString(Globals.hInstance, STRING_UNTITLED, szUntitled, SIZEOF(szUntitled));
166
167 /* Load and format Message */
168 LoadString(Globals.hInstance, STRING_NOTSAVED, szResource, SIZEOF(szResource));
169 wsprintf(szMessage, szResource, szFileName[0] ? szFileName : szUntitled);
170
171 /* Load Caption */
172 LoadString(Globals.hInstance, STRING_NOTEPAD, szResource, SIZEOF(szResource));
173
174 /* Display modal */
175 return MessageBox(Globals.hMainWnd, szMessage, szResource, MB_ICONEXCLAMATION|MB_YESNOCANCEL);
176 }
177
178 /**
179 * Returns:
180 * TRUE - if file exists
181 * FALSE - if file does not exist
182 */
183 BOOL FileExists(LPCTSTR szFilename)
184 {
185 WIN32_FIND_DATA entry;
186 HANDLE hFile;
187
188 hFile = FindFirstFile(szFilename, &entry);
189 FindClose(hFile);
190
191 return (hFile != INVALID_HANDLE_VALUE);
192 }
193
194
195 BOOL HasFileExtension(LPCTSTR szFilename)
196 {
197 LPCTSTR s;
198
199 s = _tcsrchr(szFilename, _T('\\'));
200 if (s)
201 szFilename = s;
202 return _tcsrchr(szFilename, _T('.')) != NULL;
203 }
204
205
206 static VOID DoSaveFile(VOID)
207 {
208 HANDLE hFile;
209 LPTSTR pTemp;
210 DWORD size;
211
212 hFile = CreateFile(Globals.szFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
213 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
214 if(hFile == INVALID_HANDLE_VALUE)
215 {
216 ShowLastError();
217 return;
218 }
219
220 size = GetWindowTextLength(Globals.hEdit) + 1;
221 pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*pTemp));
222 if (!pTemp)
223 {
224 CloseHandle(hFile);
225 ShowLastError();
226 return;
227 }
228 size = GetWindowText(Globals.hEdit, pTemp, size);
229
230 #ifndef UNICODE
231 pTemp = (LPTSTR)ConvertToUNICODE(pTemp, &size);
232 if (!pTemp) {
233 /* original "pTemp" already freed */
234 CloseHandle(hFile);
235 ShowLastError();
236 return;
237 }
238 #endif
239
240 if (size)
241 {
242 if (!WriteText(hFile, (LPWSTR)pTemp, size, Globals.iEncoding, Globals.iEoln))
243 ShowLastError();
244 else
245 SendMessage(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
246 }
247
248 CloseHandle(hFile);
249 HeapFree(GetProcessHeap(), 0, pTemp);
250 }
251
252 /**
253 * Returns:
254 * TRUE - User agreed to close (both save/don't save)
255 * FALSE - User cancelled close by selecting "Cancel"
256 */
257 BOOL DoCloseFile(void)
258 {
259 int nResult;
260
261 if (SendMessage(Globals.hEdit, EM_GETMODIFY, 0, 0))
262 {
263 /* prompt user to save changes */
264 nResult = AlertFileNotSaved(Globals.szFileName);
265 switch (nResult) {
266 case IDYES: DIALOG_FileSave();
267 break;
268
269 case IDNO: break;
270
271 case IDCANCEL: return(FALSE);
272 break;
273
274 default: return(FALSE);
275 break;
276 } /* switch */
277 } /* if */
278
279 SetFileName(empty_str);
280
281 UpdateWindowCaption();
282 return(TRUE);
283 }
284
285 void DoOpenFile(LPCTSTR szFileName)
286 {
287 static const TCHAR dotlog[] = _T(".LOG");
288 HANDLE hFile;
289 LPTSTR pszText;
290 DWORD dwTextLen;
291 TCHAR log[5];
292
293 /* Close any files and prompt to save changes */
294 if (!DoCloseFile())
295 return;
296
297 hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
298 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
299 if (hFile == INVALID_HANDLE_VALUE)
300 {
301 ShowLastError();
302 goto done;
303 }
304
305 if (!ReadText(hFile, (LPWSTR *)&pszText, &dwTextLen, &Globals.iEncoding, &Globals.iEoln))
306 {
307 ShowLastError();
308 goto done;
309 }
310 #ifndef UNICODE
311 pszText = ConvertToASCII(pszText);
312 if (pszText == NULL) {
313 ShowLastError();
314 goto done;
315 }
316 #endif
317 SetWindowText(Globals.hEdit, pszText);
318
319 SendMessage(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
320 SendMessage(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
321 SetFocus(Globals.hEdit);
322
323 /* If the file starts with .LOG, add a time/date at the end and set cursor after
324 * See http://support.microsoft.com/?kbid=260563
325 */
326 if (GetWindowText(Globals.hEdit, log, SIZEOF(log)) && !_tcscmp(log, dotlog))
327 {
328 static const TCHAR lf[] = _T("\r\n");
329 SendMessage(Globals.hEdit, EM_SETSEL, GetWindowTextLength(Globals.hEdit), -1);
330 SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lf);
331 DIALOG_EditTimeDate();
332 SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lf);
333 }
334
335 SetFileName(szFileName);
336 UpdateWindowCaption();
337 NOTEPAD_EnableSearchMenu();
338 done:
339 if (hFile != INVALID_HANDLE_VALUE)
340 CloseHandle(hFile);
341 if (pszText)
342 HeapFree(GetProcessHeap(), 0, pszText);
343 }
344
345 VOID DIALOG_FileNew(VOID)
346 {
347 /* Close any files and prompt to save changes */
348 if (DoCloseFile()) {
349 SetWindowText(Globals.hEdit, empty_str);
350 SendMessage(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
351 SetFocus(Globals.hEdit);
352 NOTEPAD_EnableSearchMenu();
353 }
354 }
355
356 VOID DIALOG_FileOpen(VOID)
357 {
358 OPENFILENAME openfilename;
359 TCHAR szDir[MAX_PATH];
360 TCHAR szPath[MAX_PATH];
361
362 ZeroMemory(&openfilename, sizeof(openfilename));
363
364 GetCurrentDirectory(SIZEOF(szDir), szDir);
365 if (Globals.szFileName[0] == 0)
366 _tcscpy(szPath, txt_files);
367 else
368 _tcscpy(szPath, Globals.szFileName);
369
370 openfilename.lStructSize = sizeof(openfilename);
371 openfilename.hwndOwner = Globals.hMainWnd;
372 openfilename.hInstance = Globals.hInstance;
373 openfilename.lpstrFilter = Globals.szFilter;
374 openfilename.lpstrFile = szPath;
375 openfilename.nMaxFile = SIZEOF(szPath);
376 openfilename.lpstrInitialDir = szDir;
377 openfilename.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST |
378 OFN_HIDEREADONLY;
379 openfilename.lpstrDefExt = szDefaultExt;
380
381
382 if (GetOpenFileName(&openfilename)) {
383 if (FileExists(openfilename.lpstrFile))
384 DoOpenFile(openfilename.lpstrFile);
385 else
386 AlertFileNotFound(openfilename.lpstrFile);
387 }
388 }
389
390
391 VOID DIALOG_FileSave(VOID)
392 {
393 if (Globals.szFileName[0] == '\0')
394 DIALOG_FileSaveAs();
395 else
396 DoSaveFile();
397 }
398
399 static UINT_PTR CALLBACK DIALOG_FileSaveAs_Hook(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
400 {
401 TCHAR szText[128];
402 HWND hCombo;
403
404 UNREFERENCED_PARAMETER(wParam);
405
406 switch(msg)
407 {
408 case WM_INITDIALOG:
409 hCombo = GetDlgItem(hDlg, ID_ENCODING);
410
411 LoadString(Globals.hInstance, STRING_ANSI, szText, SIZEOF(szText));
412 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
413
414 LoadString(Globals.hInstance, STRING_UNICODE, szText, SIZEOF(szText));
415 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
416
417 LoadString(Globals.hInstance, STRING_UNICODE_BE, szText, SIZEOF(szText));
418 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
419
420 LoadString(Globals.hInstance, STRING_UTF8, szText, SIZEOF(szText));
421 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
422
423 SendMessage(hCombo, CB_SETCURSEL, Globals.iEncoding, 0);
424
425 hCombo = GetDlgItem(hDlg, ID_EOLN);
426
427 LoadString(Globals.hInstance, STRING_CRLF, szText, SIZEOF(szText));
428 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
429
430 LoadString(Globals.hInstance, STRING_LF, szText, SIZEOF(szText));
431 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
432
433 LoadString(Globals.hInstance, STRING_CR, szText, SIZEOF(szText));
434 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
435
436 SendMessage(hCombo, CB_SETCURSEL, Globals.iEoln, 0);
437 break;
438
439 case WM_NOTIFY:
440 if (((NMHDR *) lParam)->code == CDN_FILEOK)
441 {
442 hCombo = GetDlgItem(hDlg, ID_ENCODING);
443 if (hCombo)
444 Globals.iEncoding = (int) SendMessage(hCombo, CB_GETCURSEL, 0, 0);
445
446 hCombo = GetDlgItem(hDlg, ID_EOLN);
447 if (hCombo)
448 Globals.iEoln = (int) SendMessage(hCombo, CB_GETCURSEL, 0, 0);
449 }
450 break;
451 }
452 return 0;
453 }
454
455 VOID DIALOG_FileSaveAs(VOID)
456 {
457 OPENFILENAME saveas;
458 TCHAR szDir[MAX_PATH];
459 TCHAR szPath[MAX_PATH];
460
461 ZeroMemory(&saveas, sizeof(saveas));
462
463 GetCurrentDirectory(SIZEOF(szDir), szDir);
464 if (Globals.szFileName[0] == 0)
465 _tcscpy(szPath, txt_files);
466 else
467 _tcscpy(szPath, Globals.szFileName);
468
469 saveas.lStructSize = sizeof(OPENFILENAME);
470 saveas.hwndOwner = Globals.hMainWnd;
471 saveas.hInstance = Globals.hInstance;
472 saveas.lpstrFilter = Globals.szFilter;
473 saveas.lpstrFile = szPath;
474 saveas.nMaxFile = SIZEOF(szPath);
475 saveas.lpstrInitialDir = szDir;
476 saveas.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT |
477 OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
478 saveas.lpstrDefExt = szDefaultExt;
479 saveas.lpTemplateName = MAKEINTRESOURCE(DIALOG_ENCODING);
480 saveas.lpfnHook = DIALOG_FileSaveAs_Hook;
481
482 if (GetSaveFileName(&saveas)) {
483 SetFileName(szPath);
484 UpdateWindowCaption();
485 DoSaveFile();
486 }
487 }
488
489 VOID DIALOG_FilePrint(VOID)
490 {
491 DOCINFO di;
492 PRINTDLG printer;
493 SIZE szMetric;
494 int cWidthPels, cHeightPels, border;
495 int xLeft, yTop, pagecount, dopage, copycount;
496 unsigned int i;
497 LOGFONT hdrFont;
498 HFONT font, old_font=0;
499 DWORD size;
500 LPTSTR pTemp;
501 static const TCHAR times_new_roman[] = _T("Times New Roman");
502
503 /* Get a small font and print some header info on each page */
504 ZeroMemory(&hdrFont, sizeof(hdrFont));
505 hdrFont.lfHeight = 100;
506 hdrFont.lfWeight = FW_BOLD;
507 hdrFont.lfCharSet = ANSI_CHARSET;
508 hdrFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
509 hdrFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
510 hdrFont.lfQuality = PROOF_QUALITY;
511 hdrFont.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN;
512 _tcscpy(hdrFont.lfFaceName, times_new_roman);
513
514 font = CreateFontIndirect(&hdrFont);
515
516 /* Get Current Settings */
517 ZeroMemory(&printer, sizeof(printer));
518 printer.lStructSize = sizeof(printer);
519 printer.hwndOwner = Globals.hMainWnd;
520 printer.hInstance = Globals.hInstance;
521
522 /* Set some default flags */
523 printer.Flags = PD_RETURNDC;
524 printer.nFromPage = 0;
525 printer.nMinPage = 1;
526 /* we really need to calculate number of pages to set nMaxPage and nToPage */
527 printer.nToPage = 0;
528 printer.nMaxPage = (WORD) -1;
529
530 /* Let commdlg manage copy settings */
531 printer.nCopies = (WORD)PD_USEDEVMODECOPIES;
532
533 if (!PrintDlg(&printer)) return;
534
535 assert(printer.hDC != 0);
536
537 /* initialize DOCINFO */
538 di.cbSize = sizeof(DOCINFO);
539 di.lpszDocName = Globals.szFileTitle;
540 di.lpszOutput = NULL;
541 di.lpszDatatype = NULL;
542 di.fwType = 0;
543
544 if (StartDoc(printer.hDC, &di) <= 0) return;
545
546 /* Get the page dimensions in pixels. */
547 cWidthPels = GetDeviceCaps(printer.hDC, HORZRES);
548 cHeightPels = GetDeviceCaps(printer.hDC, VERTRES);
549
550 /* Get the file text */
551 size = GetWindowTextLength(Globals.hEdit) + 1;
552 pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(TCHAR));
553 if (!pTemp)
554 {
555 ShowLastError();
556 return;
557 }
558 size = GetWindowText(Globals.hEdit, pTemp, size);
559
560 border = 150;
561 for (copycount=1; copycount <= printer.nCopies; copycount++) {
562 i = 0;
563 pagecount = 1;
564 do {
565 static const TCHAR letterM[] = _T("M");
566
567 if (pagecount >= printer.nFromPage &&
568 /* ((printer.Flags & PD_PAGENUMS) == 0 || pagecount <= printer.nToPage))*/
569 pagecount <= printer.nToPage)
570 dopage = 1;
571 else
572 dopage = 0;
573
574 old_font = SelectObject(printer.hDC, font);
575 GetTextExtentPoint32(printer.hDC, letterM, 1, &szMetric);
576
577 if (dopage) {
578 if (StartPage(printer.hDC) <= 0) {
579 static const TCHAR failed[] = _T("StartPage failed");
580 static const TCHAR error[] = _T("Print Error");
581 MessageBox(Globals.hMainWnd, failed, error, MB_ICONEXCLAMATION);
582 return;
583 }
584 /* Write a rectangle and header at the top of each page */
585 Rectangle(printer.hDC, border, border, cWidthPels-border, border+szMetric.cy*2);
586 /* I don't know what's up with this TextOut command. This comes out
587 kind of mangled.
588 */
589 TextOut(printer.hDC, border*2, border+szMetric.cy/2, Globals.szFileTitle, lstrlen(Globals.szFileTitle));
590 }
591
592 /* The starting point for the main text */
593 xLeft = border*2;
594 yTop = border+szMetric.cy*4;
595
596 SelectObject(printer.hDC, old_font);
597 GetTextExtentPoint32(printer.hDC, letterM, 1, &szMetric);
598
599 /* Since outputting strings is giving me problems, output the main
600 text one character at a time.
601 */
602 do {
603 if (pTemp[i] == '\n') {
604 xLeft = border*2;
605 yTop += szMetric.cy;
606 }
607 else if (pTemp[i] != '\r') {
608 if (dopage)
609 TextOut(printer.hDC, xLeft, yTop, &pTemp[i], 1);
610 xLeft += szMetric.cx;
611 }
612 } while (i++<size && yTop<(cHeightPels-border*2));
613
614 if (dopage)
615 EndPage(printer.hDC);
616 pagecount++;
617 } while (i<size);
618 }
619
620 EndDoc(printer.hDC);
621 DeleteDC(printer.hDC);
622 HeapFree(GetProcessHeap(), 0, pTemp);
623 }
624
625 VOID DIALOG_FilePrinterSetup(VOID)
626 {
627 PRINTDLG printer;
628
629 ZeroMemory(&printer, sizeof(printer));
630 printer.lStructSize = sizeof(printer);
631 printer.hwndOwner = Globals.hMainWnd;
632 printer.hInstance = Globals.hInstance;
633 printer.Flags = PD_PRINTSETUP;
634 printer.nCopies = 1;
635
636 PrintDlg(&printer);
637 }
638
639 VOID DIALOG_FileExit(VOID)
640 {
641 PostMessage(Globals.hMainWnd, WM_CLOSE, 0, 0l);
642 }
643
644 VOID DIALOG_EditUndo(VOID)
645 {
646 SendMessage(Globals.hEdit, EM_UNDO, 0, 0);
647 }
648
649 VOID DIALOG_EditCut(VOID)
650 {
651 SendMessage(Globals.hEdit, WM_CUT, 0, 0);
652 }
653
654 VOID DIALOG_EditCopy(VOID)
655 {
656 SendMessage(Globals.hEdit, WM_COPY, 0, 0);
657 }
658
659 VOID DIALOG_EditPaste(VOID)
660 {
661 SendMessage(Globals.hEdit, WM_PASTE, 0, 0);
662 }
663
664 VOID DIALOG_EditDelete(VOID)
665 {
666 SendMessage(Globals.hEdit, WM_CLEAR, 0, 0);
667 }
668
669 VOID DIALOG_EditSelectAll(VOID)
670 {
671 SendMessage(Globals.hEdit, EM_SETSEL, 0, (LPARAM)-1);
672 }
673
674 VOID DIALOG_EditTimeDate(VOID)
675 {
676 SYSTEMTIME st;
677 TCHAR szDate[MAX_STRING_LEN];
678 TCHAR szText[MAX_STRING_LEN * 2 + 2];
679
680 GetLocalTime(&st);
681
682 GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szDate, MAX_STRING_LEN);
683 _tcscpy(szText, szDate);
684 _tcscat(szText, _T(" "));
685 GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szDate, MAX_STRING_LEN);
686 _tcscat(szText, szDate);
687 SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szDate);
688 }
689
690 VOID DIALOG_EditWrap(VOID)
691 {
692 static const TCHAR edit[] = _T("edit");
693 DWORD dwStyle;
694 RECT rc, rcstatus;
695 DWORD size;
696 LPTSTR pTemp;
697 TCHAR buff[MAX_PATH];
698
699 Globals.bWrapLongLines = !Globals.bWrapLongLines;
700
701 size = GetWindowTextLength(Globals.hEdit) + 1;
702 pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
703 if (!pTemp)
704 {
705 ShowLastError();
706 return;
707 }
708 GetWindowText(Globals.hEdit, pTemp, size);
709 DestroyWindow(Globals.hEdit);
710 GetClientRect(Globals.hMainWnd, &rc);
711 dwStyle = Globals.bWrapLongLines ? EDIT_STYLE_WRAP : EDIT_STYLE;
712 EnableMenuItem(GetMenu(Globals.hMainWnd), CMD_STATUSBAR,
713 MF_BYCOMMAND | (Globals.bWrapLongLines ? MF_DISABLED | MF_GRAYED : MF_ENABLED));
714 if ( Globals.hStatusBar )
715 {
716 if ( Globals.bWrapLongLines )
717 ShowWindow(Globals.hStatusBar, SW_HIDE);
718 else if ( Globals.bShowStatusBar )
719 {
720 GetClientRect(Globals.hStatusBar, &rcstatus);
721 rc.bottom -= (rcstatus.bottom - rcstatus.top);
722 ShowWindow(Globals.hStatusBar, SW_SHOW);
723 }
724 }
725 Globals.hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, edit, NULL, dwStyle,
726 0, 0, rc.right, rc.bottom, Globals.hMainWnd,
727 NULL, Globals.hInstance, NULL);
728 SendMessage(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, FALSE);
729 SendMessage(Globals.hEdit, EM_LIMITTEXT, 0, 0);
730 SetWindowText(Globals.hEdit, pTemp);
731 SetFocus(Globals.hEdit);
732 Globals.EditProc = (WNDPROC) SetWindowLongPtr(Globals.hEdit, GWLP_WNDPROC, (LONG_PTR)EDIT_WndProc);
733 _stprintf(buff, Globals.szStatusBarLineCol, 1, 1);
734 SendMessage(Globals.hStatusBar, SB_SETTEXT, SB_SIMPLEID, (LPARAM)buff);
735 HeapFree(GetProcessHeap(), 0, pTemp);
736 DrawMenuBar(Globals.hMainWnd);
737 }
738
739 VOID DIALOG_SelectFont(VOID)
740 {
741 CHOOSEFONT cf;
742 LOGFONT lf=Globals.lfFont;
743
744 ZeroMemory( &cf, sizeof(cf) );
745 cf.lStructSize=sizeof(cf);
746 cf.hwndOwner=Globals.hMainWnd;
747 cf.lpLogFont=&lf;
748 cf.Flags=CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT;
749
750 if( ChooseFont(&cf) )
751 {
752 HFONT currfont=Globals.hFont;
753
754 Globals.hFont=CreateFontIndirect( &lf );
755 Globals.lfFont=lf;
756 SendMessage( Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, (LPARAM)TRUE );
757 if( currfont!=NULL )
758 DeleteObject( currfont );
759 }
760 }
761
762 typedef HWND (WINAPI *FINDPROC)(LPFINDREPLACE lpfr);
763
764 static VOID DIALOG_SearchDialog(FINDPROC pfnProc)
765 {
766 ZeroMemory(&Globals.find, sizeof(Globals.find));
767 Globals.find.lStructSize = sizeof(Globals.find);
768 Globals.find.hwndOwner = Globals.hMainWnd;
769 Globals.find.hInstance = Globals.hInstance;
770 Globals.find.lpstrFindWhat = Globals.szFindText;
771 Globals.find.wFindWhatLen = SIZEOF(Globals.szFindText);
772 Globals.find.lpstrReplaceWith = Globals.szReplaceText;
773 Globals.find.wReplaceWithLen = SIZEOF(Globals.szReplaceText);
774 Globals.find.Flags = FR_DOWN;
775
776 /* We only need to create the modal FindReplace dialog which will */
777 /* notify us of incoming events using hMainWnd Window Messages */
778
779 Globals.hFindReplaceDlg = pfnProc(&Globals.find);
780 assert(Globals.hFindReplaceDlg !=0);
781 }
782
783 VOID DIALOG_Search(VOID)
784 {
785 DIALOG_SearchDialog(FindText);
786 }
787
788 VOID DIALOG_SearchNext(VOID)
789 {
790 if (Globals.find.lpstrFindWhat != NULL)
791 NOTEPAD_FindNext(&Globals.find, FALSE, TRUE);
792 else
793 DIALOG_Search();
794 }
795
796 VOID DIALOG_Replace(VOID)
797 {
798 DIALOG_SearchDialog(ReplaceText);
799 }
800
801 static INT_PTR CALLBACK DIALOG_GoTo_DialogProc(HWND hwndDialog, UINT uMsg, WPARAM wParam, LPARAM lParam)
802 {
803 BOOL bResult = FALSE;
804 HWND hTextBox;
805 TCHAR szText[32];
806
807 switch(uMsg) {
808 case WM_INITDIALOG:
809 hTextBox = GetDlgItem(hwndDialog, ID_LINENUMBER);
810 _sntprintf(szText, SIZEOF(szText), _T("%d"), lParam);
811 SetWindowText(hTextBox, szText);
812 break;
813 case WM_COMMAND:
814 if (HIWORD(wParam) == BN_CLICKED)
815 {
816 if (LOWORD(wParam) == IDOK)
817 {
818 hTextBox = GetDlgItem(hwndDialog, ID_LINENUMBER);
819 GetWindowText(hTextBox, szText, SIZEOF(szText));
820 EndDialog(hwndDialog, _ttoi(szText));
821 bResult = TRUE;
822 }
823 else if (LOWORD(wParam) == IDCANCEL)
824 {
825 EndDialog(hwndDialog, 0);
826 bResult = TRUE;
827 }
828 }
829 break;
830 }
831
832 return bResult;
833 }
834
835 VOID DIALOG_GoTo(VOID)
836 {
837 INT_PTR nLine;
838 LPTSTR pszText;
839 int nLength, i;
840 DWORD dwStart, dwEnd;
841
842 nLength = GetWindowTextLength(Globals.hEdit);
843 pszText = (LPTSTR) HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(*pszText));
844 if (!pszText)
845 return;
846
847 /* Retrieve current text */
848 GetWindowText(Globals.hEdit, pszText, nLength + 1);
849 SendMessage(Globals.hEdit, EM_GETSEL, (WPARAM) &dwStart, (LPARAM) &dwEnd);
850
851 nLine = 1;
852 for (i = 0; pszText[i] && (i < (int) dwStart); i++)
853 {
854 if (pszText[i] == '\n')
855 nLine++;
856 }
857
858 nLine = DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(DIALOG_GOTO),
859 Globals.hMainWnd, DIALOG_GoTo_DialogProc, nLine);
860
861 if (nLine >= 1)
862 {
863 for (i = 0; pszText[i] && (nLine > 1) && (i < nLength - 1); i++)
864 {
865 if (pszText[i] == '\n')
866 nLine--;
867 }
868 SendMessage(Globals.hEdit, EM_SETSEL, i, i);
869 SendMessage(Globals.hEdit, EM_SCROLLCARET, 0, 0);
870 }
871 HeapFree(GetProcessHeap(), 0, pszText);
872 }
873
874 VOID DIALOG_StatusBarUpdateCaretPos(VOID)
875 {
876 int line, col;
877 TCHAR buff[MAX_PATH];
878 DWORD dwStart, dwSize;
879
880 SendMessage(Globals.hEdit, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwSize);
881 line = SendMessage(Globals.hEdit, EM_LINEFROMCHAR, (WPARAM)dwStart, 0);
882 col = dwStart - SendMessage(Globals.hEdit, EM_LINEINDEX, (WPARAM)line, 0);
883
884 _stprintf(buff, Globals.szStatusBarLineCol, line+1, col+1);
885 SendMessage(Globals.hStatusBar, SB_SETTEXT, SB_SIMPLEID, (LPARAM)buff);
886 }
887
888 VOID DIALOG_ViewStatusBar(VOID)
889 {
890 RECT rc;
891 RECT rcstatus;
892
893 Globals.bShowStatusBar = !Globals.bShowStatusBar;
894 if ( !Globals.hStatusBar )
895 {
896 Globals.hStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_EX_STATICEDGE, TEXT("test"), Globals.hMainWnd, CMD_STATUSBAR_WND_ID );
897 LoadString(Globals.hInstance, STRING_LINE_COLUMN, Globals.szStatusBarLineCol, MAX_PATH-1);
898 SendMessage(Globals.hStatusBar, SB_SIMPLE, (WPARAM)TRUE, (LPARAM)0);
899 }
900 CheckMenuItem(GetMenu(Globals.hMainWnd), CMD_STATUSBAR,
901 MF_BYCOMMAND | (Globals.bShowStatusBar ? MF_CHECKED : MF_UNCHECKED));
902 DrawMenuBar(Globals.hMainWnd);
903 GetClientRect(Globals.hMainWnd, &rc);
904 GetClientRect(Globals.hStatusBar, &rcstatus);
905 if ( Globals.bShowStatusBar )
906 rc.bottom -= (rcstatus.bottom - rcstatus.top);
907
908 MoveWindow(Globals.hEdit, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
909 ShowWindow(Globals.hStatusBar, Globals.bShowStatusBar);
910 DIALOG_StatusBarUpdateCaretPos();
911 }
912
913 VOID DIALOG_HelpContents(VOID)
914 {
915 WinHelp(Globals.hMainWnd, helpfile, HELP_INDEX, 0);
916 }
917
918 VOID DIALOG_HelpSearch(VOID)
919 {
920 /* Search Help */
921 }
922
923 VOID DIALOG_HelpHelp(VOID)
924 {
925 WinHelp(Globals.hMainWnd, helpfile, HELP_HELPONHELP, 0);
926 }
927
928 #ifdef _MSC_VER
929 #pragma warning(disable : 4100)
930 #endif
931 INT_PTR CALLBACK
932 AboutDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
933 {
934 HWND hLicenseEditWnd;
935 TCHAR *strLicense;
936
937 switch (message)
938 {
939 case WM_INITDIALOG:
940
941 hLicenseEditWnd = GetDlgItem(hDlg, IDC_LICENSE);
942
943 /* 0x1000 should be enought */
944 strLicense = (TCHAR *)_alloca(0x1000);
945 LoadString(GetModuleHandle(NULL), STRING_LICENSE, strLicense, 0x1000);
946
947 SetWindowText(hLicenseEditWnd, strLicense);
948
949 return TRUE;
950
951 case WM_COMMAND:
952
953 if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL))
954 {
955 EndDialog(hDlg, LOWORD(wParam));
956 return TRUE;
957 }
958
959 break;
960 }
961
962 return 0;
963 }
964
965
966
967 VOID DIALOG_HelpAboutWine(VOID)
968 {
969 TCHAR szNotepad[MAX_STRING_LEN];
970 HICON notepadIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_NPICON));
971
972 LoadString(Globals.hInstance, STRING_NOTEPAD, szNotepad, SIZEOF(szNotepad));
973 ShellAbout(Globals.hMainWnd, szNotepad, 0, notepadIcon);
974 DeleteObject(notepadIcon);
975 }
976
977
978 /***********************************************************************
979 *
980 * DIALOG_FilePageSetup
981 */
982 VOID DIALOG_FilePageSetup(void)
983 {
984 DialogBox(Globals.hInstance, MAKEINTRESOURCE(DIALOG_PAGESETUP),
985 Globals.hMainWnd, DIALOG_PAGESETUP_DlgProc);
986 }
987
988
989 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
990 *
991 * DIALOG_PAGESETUP_DlgProc
992 */
993
994 static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
995 {
996
997 switch (msg)
998 {
999 case WM_COMMAND:
1000 if (HIWORD(wParam) == BN_CLICKED)
1001 {
1002 switch (LOWORD(wParam))
1003 {
1004 case IDOK:
1005 /* save user input and close dialog */
1006 GetDlgItemText(hDlg, 0x141, Globals.szHeader, SIZEOF(Globals.szHeader));
1007 GetDlgItemText(hDlg, 0x143, Globals.szFooter, SIZEOF(Globals.szFooter));
1008 GetDlgItemText(hDlg, 0x14A, Globals.szMarginTop, SIZEOF(Globals.szMarginTop));
1009 GetDlgItemText(hDlg, 0x150, Globals.szMarginBottom, SIZEOF(Globals.szMarginBottom));
1010 GetDlgItemText(hDlg, 0x147, Globals.szMarginLeft, SIZEOF(Globals.szMarginLeft));
1011 GetDlgItemText(hDlg, 0x14D, Globals.szMarginRight, SIZEOF(Globals.szMarginRight));
1012 EndDialog(hDlg, IDOK);
1013 return TRUE;
1014
1015 case IDCANCEL:
1016 /* discard user input and close dialog */
1017 EndDialog(hDlg, IDCANCEL);
1018 return TRUE;
1019
1020 case IDHELP:
1021 {
1022 /* FIXME: Bring this to work */
1023 static const TCHAR sorry[] = _T("Sorry, no help available");
1024 static const TCHAR help[] = _T("Help");
1025 MessageBox(Globals.hMainWnd, sorry, help, MB_ICONEXCLAMATION);
1026 return TRUE;
1027 }
1028
1029 default:
1030 break;
1031 }
1032 }
1033 break;
1034
1035 case WM_INITDIALOG:
1036 /* fetch last user input prior to display dialog */
1037 SetDlgItemText(hDlg, 0x141, Globals.szHeader);
1038 SetDlgItemText(hDlg, 0x143, Globals.szFooter);
1039 SetDlgItemText(hDlg, 0x14A, Globals.szMarginTop);
1040 SetDlgItemText(hDlg, 0x150, Globals.szMarginBottom);
1041 SetDlgItemText(hDlg, 0x147, Globals.szMarginLeft);
1042 SetDlgItemText(hDlg, 0x14D, Globals.szMarginRight);
1043 break;
1044 }
1045
1046 return FALSE;
1047 }