Carlo Bramini <carlo DOT bramix AT libero DOT it>
[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 DoCreateStatusBar(VOID)
691 {
692 RECT rc;
693 RECT rcstatus;
694 BOOL bStatusBarVisible;
695
696 // Check if status bar object already exists.
697 if (Globals.hStatusBar == NULL)
698 {
699 // Try to create the status bar
700 Globals.hStatusBar = CreateStatusWindow(
701 WS_CHILD | WS_VISIBLE | WS_EX_STATICEDGE,
702 NULL,
703 Globals.hMainWnd,
704 CMD_STATUSBAR_WND_ID);
705
706 if (Globals.hStatusBar == NULL)
707 {
708 ShowLastError();
709 return;
710 }
711
712 // Load the string for formatting column/row text output
713 LoadString(Globals.hInstance, STRING_LINE_COLUMN, Globals.szStatusBarLineCol, MAX_PATH-1);
714
715 // Set the status bar for single-text output
716 SendMessage(Globals.hStatusBar, SB_SIMPLE, (WPARAM)TRUE, (LPARAM)0);
717 }
718
719 // Set status bar visible or not accordind the the settings.
720 if (Globals.bWrapLongLines == TRUE ||
721 Globals.bShowStatusBar == FALSE)
722 {
723 bStatusBarVisible = FALSE;
724 ShowWindow(Globals.hStatusBar, SW_HIDE);
725 }
726 else
727 {
728 bStatusBarVisible = TRUE;
729 ShowWindow(Globals.hStatusBar, SW_SHOW);
730 SendMessage(Globals.hStatusBar, WM_SIZE, 0, 0);
731 }
732
733 // Set check state in show status bar item.
734 if (Globals.bShowStatusBar == TRUE)
735 {
736 CheckMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_CHECKED);
737 }
738 else
739 {
740 CheckMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_UNCHECKED);
741 }
742
743 // Update menu mar with the previous changes
744 DrawMenuBar(Globals.hMainWnd);
745
746 // Sefety test is edit control exists
747 if (Globals.hEdit != NULL)
748 {
749 // Retrieve the sizes of the controls
750 GetClientRect(Globals.hMainWnd, &rc);
751 GetClientRect(Globals.hStatusBar, &rcstatus);
752
753 // If status bar is currently visible, update dimensions of edir control
754 if (bStatusBarVisible)
755 rc.bottom -= (rcstatus.bottom - rcstatus.top);
756
757 // Resize edit control to right size.
758 MoveWindow(Globals.hEdit, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
759 }
760
761 // Update content with current row/column text
762 DIALOG_StatusBarUpdateCaretPos();
763 }
764
765 VOID DoCreateEditWindow(VOID)
766 {
767 DWORD dwStyle;
768 int iSize;
769 LPTSTR pTemp;
770
771 iSize = 0;
772
773 // If the edit control already exists, try to save its content
774 if (Globals.hEdit != NULL)
775 {
776 // number of chars currently written into the editor.
777 iSize = GetWindowTextLength(Globals.hEdit);
778
779 if (iSize)
780 {
781 // Allocates temporary buffer.
782 pTemp = HeapAlloc(GetProcessHeap(), 0, (iSize + 1) * sizeof(TCHAR));
783
784 if (!pTemp)
785 {
786 ShowLastError();
787 return;
788 }
789
790 // Recover the text into the control.
791 GetWindowText(Globals.hEdit, pTemp, iSize + 1);
792 }
793
794 // Restore original window procedure
795 SetWindowLongPtr(Globals.hEdit, GWLP_WNDPROC, (LONG_PTR)Globals.EditProc);
796
797 // Destroy the edit control
798 DestroyWindow(Globals.hEdit);
799 }
800
801 // Update wrap status into the main menu and recover style flags
802 if (Globals.bWrapLongLines)
803 {
804 dwStyle = EDIT_STYLE_WRAP;
805 EnableMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
806 } else {
807 dwStyle = EDIT_STYLE;
808 EnableMenuItem(Globals.hMenu, CMD_STATUSBAR, MF_BYCOMMAND | MF_ENABLED);
809 }
810
811 // Update previous changes
812 DrawMenuBar(Globals.hMainWnd);
813
814 // Create the new edit control
815 Globals.hEdit = CreateWindowEx(
816 WS_EX_CLIENTEDGE,
817 EDIT_CLASS,
818 NULL,
819 dwStyle,
820 CW_USEDEFAULT,
821 CW_USEDEFAULT,
822 CW_USEDEFAULT,
823 CW_USEDEFAULT,
824 Globals.hMainWnd,
825 NULL,
826 Globals.hInstance,
827 NULL);
828
829 if (Globals.hEdit == NULL)
830 {
831 ShowLastError();
832 return;
833 }
834
835 SendMessage(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, FALSE);
836 SendMessage(Globals.hEdit, EM_LIMITTEXT, 0, 0);
837
838 // If some text was previously saved, restore it.
839 if (iSize != 0)
840 {
841 SetWindowText(Globals.hEdit, pTemp);
842 HeapFree(GetProcessHeap(), 0, pTemp);
843 }
844
845 // Sub-class a new window callback for row/column detection.
846 Globals.EditProc = (WNDPROC) SetWindowLongPtr(Globals.hEdit, GWLP_WNDPROC, (LONG_PTR)EDIT_WndProc);
847
848 // Create/update status bar
849 DoCreateStatusBar();
850
851 // Finally shows new edit control and set focus into it.
852 ShowWindow(Globals.hEdit, SW_SHOW);
853 SetFocus(Globals.hEdit);
854 }
855
856 VOID DIALOG_EditWrap(VOID)
857 {
858 Globals.bWrapLongLines = !Globals.bWrapLongLines;
859
860 DoCreateEditWindow();
861 }
862
863 VOID DIALOG_SelectFont(VOID)
864 {
865 CHOOSEFONT cf;
866 LOGFONT lf=Globals.lfFont;
867
868 ZeroMemory( &cf, sizeof(cf) );
869 cf.lStructSize=sizeof(cf);
870 cf.hwndOwner=Globals.hMainWnd;
871 cf.lpLogFont=&lf;
872 cf.Flags=CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT;
873
874 if( ChooseFont(&cf) )
875 {
876 HFONT currfont=Globals.hFont;
877
878 Globals.hFont=CreateFontIndirect( &lf );
879 Globals.lfFont=lf;
880 SendMessage( Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, (LPARAM)TRUE );
881 if( currfont!=NULL )
882 DeleteObject( currfont );
883 }
884 }
885
886 typedef HWND (WINAPI *FINDPROC)(LPFINDREPLACE lpfr);
887
888 static VOID DIALOG_SearchDialog(FINDPROC pfnProc)
889 {
890 ZeroMemory(&Globals.find, sizeof(Globals.find));
891 Globals.find.lStructSize = sizeof(Globals.find);
892 Globals.find.hwndOwner = Globals.hMainWnd;
893 Globals.find.hInstance = Globals.hInstance;
894 Globals.find.lpstrFindWhat = Globals.szFindText;
895 Globals.find.wFindWhatLen = SIZEOF(Globals.szFindText);
896 Globals.find.lpstrReplaceWith = Globals.szReplaceText;
897 Globals.find.wReplaceWithLen = SIZEOF(Globals.szReplaceText);
898 Globals.find.Flags = FR_DOWN;
899
900 /* We only need to create the modal FindReplace dialog which will */
901 /* notify us of incoming events using hMainWnd Window Messages */
902
903 Globals.hFindReplaceDlg = pfnProc(&Globals.find);
904 assert(Globals.hFindReplaceDlg !=0);
905 }
906
907 VOID DIALOG_Search(VOID)
908 {
909 DIALOG_SearchDialog(FindText);
910 }
911
912 VOID DIALOG_SearchNext(VOID)
913 {
914 if (Globals.find.lpstrFindWhat != NULL)
915 NOTEPAD_FindNext(&Globals.find, FALSE, TRUE);
916 else
917 DIALOG_Search();
918 }
919
920 VOID DIALOG_Replace(VOID)
921 {
922 DIALOG_SearchDialog(ReplaceText);
923 }
924
925 static INT_PTR CALLBACK DIALOG_GoTo_DialogProc(HWND hwndDialog, UINT uMsg, WPARAM wParam, LPARAM lParam)
926 {
927 BOOL bResult = FALSE;
928 HWND hTextBox;
929 TCHAR szText[32];
930
931 switch(uMsg) {
932 case WM_INITDIALOG:
933 hTextBox = GetDlgItem(hwndDialog, ID_LINENUMBER);
934 _sntprintf(szText, SIZEOF(szText), _T("%d"), lParam);
935 SetWindowText(hTextBox, szText);
936 break;
937 case WM_COMMAND:
938 if (HIWORD(wParam) == BN_CLICKED)
939 {
940 if (LOWORD(wParam) == IDOK)
941 {
942 hTextBox = GetDlgItem(hwndDialog, ID_LINENUMBER);
943 GetWindowText(hTextBox, szText, SIZEOF(szText));
944 EndDialog(hwndDialog, _ttoi(szText));
945 bResult = TRUE;
946 }
947 else if (LOWORD(wParam) == IDCANCEL)
948 {
949 EndDialog(hwndDialog, 0);
950 bResult = TRUE;
951 }
952 }
953 break;
954 }
955
956 return bResult;
957 }
958
959 VOID DIALOG_GoTo(VOID)
960 {
961 INT_PTR nLine;
962 LPTSTR pszText;
963 int nLength, i;
964 DWORD dwStart, dwEnd;
965
966 nLength = GetWindowTextLength(Globals.hEdit);
967 pszText = (LPTSTR) HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(*pszText));
968 if (!pszText)
969 return;
970
971 /* Retrieve current text */
972 GetWindowText(Globals.hEdit, pszText, nLength + 1);
973 SendMessage(Globals.hEdit, EM_GETSEL, (WPARAM) &dwStart, (LPARAM) &dwEnd);
974
975 nLine = 1;
976 for (i = 0; pszText[i] && (i < (int) dwStart); i++)
977 {
978 if (pszText[i] == '\n')
979 nLine++;
980 }
981
982 nLine = DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(DIALOG_GOTO),
983 Globals.hMainWnd, DIALOG_GoTo_DialogProc, nLine);
984
985 if (nLine >= 1)
986 {
987 for (i = 0; pszText[i] && (nLine > 1) && (i < nLength - 1); i++)
988 {
989 if (pszText[i] == '\n')
990 nLine--;
991 }
992 SendMessage(Globals.hEdit, EM_SETSEL, i, i);
993 SendMessage(Globals.hEdit, EM_SCROLLCARET, 0, 0);
994 }
995 HeapFree(GetProcessHeap(), 0, pszText);
996 }
997
998 VOID DIALOG_StatusBarUpdateCaretPos(VOID)
999 {
1000 int line, col;
1001 TCHAR buff[MAX_PATH];
1002 DWORD dwStart, dwSize;
1003
1004 SendMessage(Globals.hEdit, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwSize);
1005 line = SendMessage(Globals.hEdit, EM_LINEFROMCHAR, (WPARAM)dwStart, 0);
1006 col = dwStart - SendMessage(Globals.hEdit, EM_LINEINDEX, (WPARAM)line, 0);
1007
1008 _stprintf(buff, Globals.szStatusBarLineCol, line+1, col+1);
1009 SendMessage(Globals.hStatusBar, SB_SETTEXT, SB_SIMPLEID, (LPARAM)buff);
1010 }
1011
1012 VOID DIALOG_ViewStatusBar(VOID)
1013 {
1014 Globals.bShowStatusBar = !Globals.bShowStatusBar;
1015
1016 DoCreateStatusBar();
1017 }
1018
1019 VOID DIALOG_HelpContents(VOID)
1020 {
1021 WinHelp(Globals.hMainWnd, helpfile, HELP_INDEX, 0);
1022 }
1023
1024 VOID DIALOG_HelpSearch(VOID)
1025 {
1026 /* Search Help */
1027 }
1028
1029 VOID DIALOG_HelpHelp(VOID)
1030 {
1031 WinHelp(Globals.hMainWnd, helpfile, HELP_HELPONHELP, 0);
1032 }
1033
1034 #ifdef _MSC_VER
1035 #pragma warning(disable : 4100)
1036 #endif
1037 INT_PTR CALLBACK
1038 AboutDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1039 {
1040 HWND hLicenseEditWnd;
1041 TCHAR *strLicense;
1042
1043 switch (message)
1044 {
1045 case WM_INITDIALOG:
1046
1047 hLicenseEditWnd = GetDlgItem(hDlg, IDC_LICENSE);
1048
1049 /* 0x1000 should be enought */
1050 strLicense = (TCHAR *)_alloca(0x1000);
1051 LoadString(GetModuleHandle(NULL), STRING_LICENSE, strLicense, 0x1000);
1052
1053 SetWindowText(hLicenseEditWnd, strLicense);
1054
1055 return TRUE;
1056
1057 case WM_COMMAND:
1058
1059 if ((LOWORD(wParam) == IDOK) || (LOWORD(wParam) == IDCANCEL))
1060 {
1061 EndDialog(hDlg, LOWORD(wParam));
1062 return TRUE;
1063 }
1064
1065 break;
1066 }
1067
1068 return 0;
1069 }
1070
1071
1072
1073 VOID DIALOG_HelpAboutWine(VOID)
1074 {
1075 TCHAR szNotepad[MAX_STRING_LEN];
1076 HICON notepadIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_NPICON));
1077
1078 LoadString(Globals.hInstance, STRING_NOTEPAD, szNotepad, SIZEOF(szNotepad));
1079 ShellAbout(Globals.hMainWnd, szNotepad, 0, notepadIcon);
1080 DeleteObject(notepadIcon);
1081 }
1082
1083
1084 /***********************************************************************
1085 *
1086 * DIALOG_FilePageSetup
1087 */
1088 VOID DIALOG_FilePageSetup(void)
1089 {
1090 DialogBox(Globals.hInstance, MAKEINTRESOURCE(DIALOG_PAGESETUP),
1091 Globals.hMainWnd, DIALOG_PAGESETUP_DlgProc);
1092 }
1093
1094
1095 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
1096 *
1097 * DIALOG_PAGESETUP_DlgProc
1098 */
1099
1100 static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
1101 {
1102
1103 switch (msg)
1104 {
1105 case WM_COMMAND:
1106 if (HIWORD(wParam) == BN_CLICKED)
1107 {
1108 switch (LOWORD(wParam))
1109 {
1110 case IDOK:
1111 /* save user input and close dialog */
1112 GetDlgItemText(hDlg, 0x141, Globals.szHeader, SIZEOF(Globals.szHeader));
1113 GetDlgItemText(hDlg, 0x143, Globals.szFooter, SIZEOF(Globals.szFooter));
1114 GetDlgItemText(hDlg, 0x14A, Globals.szMarginTop, SIZEOF(Globals.szMarginTop));
1115 GetDlgItemText(hDlg, 0x150, Globals.szMarginBottom, SIZEOF(Globals.szMarginBottom));
1116 GetDlgItemText(hDlg, 0x147, Globals.szMarginLeft, SIZEOF(Globals.szMarginLeft));
1117 GetDlgItemText(hDlg, 0x14D, Globals.szMarginRight, SIZEOF(Globals.szMarginRight));
1118 EndDialog(hDlg, IDOK);
1119 return TRUE;
1120
1121 case IDCANCEL:
1122 /* discard user input and close dialog */
1123 EndDialog(hDlg, IDCANCEL);
1124 return TRUE;
1125
1126 case IDHELP:
1127 {
1128 /* FIXME: Bring this to work */
1129 static const TCHAR sorry[] = _T("Sorry, no help available");
1130 static const TCHAR help[] = _T("Help");
1131 MessageBox(Globals.hMainWnd, sorry, help, MB_ICONEXCLAMATION);
1132 return TRUE;
1133 }
1134
1135 default:
1136 break;
1137 }
1138 }
1139 break;
1140
1141 case WM_INITDIALOG:
1142 /* fetch last user input prior to display dialog */
1143 SetDlgItemText(hDlg, 0x141, Globals.szHeader);
1144 SetDlgItemText(hDlg, 0x143, Globals.szFooter);
1145 SetDlgItemText(hDlg, 0x14A, Globals.szMarginTop);
1146 SetDlgItemText(hDlg, 0x150, Globals.szMarginBottom);
1147 SetDlgItemText(hDlg, 0x147, Globals.szMarginLeft);
1148 SetDlgItemText(hDlg, 0x14D, Globals.szMarginRight);
1149 break;
1150 }
1151
1152 return FALSE;
1153 }