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