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