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