Notepad:
[reactos.git] / reactos / subsys / system / notepad / dialog.c
1 /*
2 * Notepad (dialog.c)
3 *
4 * Copyright 1998,99 Marcel Baur <mbaur@g26.ethz.ch>
5 * Copyright 2002 Sylvain Petreolle <spetreolle@yahoo.fr>
6 * Copyright 2002 Andriy Palamarchuk
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #define UNICODE
24 #define _UNICODE
25
26 #include <assert.h>
27 #include <stdio.h>
28 #include <windows.h>
29 #include <commdlg.h>
30 #include <tchar.h>
31
32 #include "main.h"
33 #include "license.h"
34 #include "dialog.h"
35
36 static const WCHAR helpfileW[] = { 'n','o','t','e','p','a','d','.','h','l','p',0 };
37
38 static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
39
40 VOID ShowLastError(void)
41 {
42 DWORD error = GetLastError();
43 if (error != NO_ERROR)
44 {
45 LPWSTR lpMsgBuf;
46 WCHAR szTitle[MAX_STRING_LEN];
47
48 LoadString(Globals.hInstance, STRING_ERROR, szTitle, SIZEOF(szTitle));
49 FormatMessage(
50 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
51 NULL, error, 0,
52 (LPTSTR) &lpMsgBuf, 0, NULL);
53 MessageBox(NULL, lpMsgBuf, szTitle, MB_OK | MB_ICONERROR);
54 LocalFree(lpMsgBuf);
55 }
56 }
57
58 /**
59 * Sets the caption of the main window according to Globals.szFileTitle:
60 * Notepad - (untitled) if no file is open
61 * Notepad - [filename] if a file is given
62 */
63 static void UpdateWindowCaption(void)
64 {
65 WCHAR szCaption[MAX_STRING_LEN];
66 WCHAR szUntitled[MAX_STRING_LEN];
67
68 LoadString(Globals.hInstance, STRING_NOTEPAD, szCaption, SIZEOF(szCaption));
69
70 if (Globals.szFileTitle[0] != '\0') {
71 static const WCHAR bracket_lW[] = { ' ','-',' ','[',0 };
72 static const WCHAR bracket_rW[] = { ']',0 };
73 lstrcat(szCaption, bracket_lW);
74 lstrcat(szCaption, Globals.szFileTitle);
75 lstrcat(szCaption, bracket_rW);
76 }
77 else
78 {
79 static const WCHAR hyphenW[] = { ' ','-',' ',0 };
80 LoadString(Globals.hInstance, STRING_UNTITLED, szUntitled, SIZEOF(szUntitled));
81 lstrcat(szCaption, hyphenW);
82 lstrcat(szCaption, szUntitled);
83 }
84
85 SetWindowText(Globals.hMainWnd, szCaption);
86 }
87
88 static void AlertFileNotFound(LPCWSTR szFileName)
89 {
90 WCHAR szMessage[MAX_STRING_LEN];
91 WCHAR szResource[MAX_STRING_LEN];
92
93 /* Load and format szMessage */
94 LoadString(Globals.hInstance, STRING_NOTFOUND, szResource, SIZEOF(szResource));
95 wsprintf(szMessage, szResource, szFileName);
96
97 /* Load szCaption */
98 LoadString(Globals.hInstance, STRING_NOTEPAD, szResource, SIZEOF(szResource));
99
100 /* Display Modal Dialog */
101 MessageBox(Globals.hMainWnd, szMessage, szResource, MB_ICONEXCLAMATION);
102 }
103
104 static int AlertFileNotSaved(LPCWSTR szFileName)
105 {
106 WCHAR szMessage[MAX_STRING_LEN];
107 WCHAR szResource[MAX_STRING_LEN];
108 WCHAR szUntitled[MAX_STRING_LEN];
109
110 LoadString(Globals.hInstance, STRING_UNTITLED, szUntitled, SIZEOF(szUntitled));
111
112 /* Load and format Message */
113 LoadString(Globals.hInstance, STRING_NOTSAVED, szResource, SIZEOF(szResource));
114 wsprintf(szMessage, szResource, szFileName[0] ? szFileName : szUntitled);
115
116 /* Load Caption */
117 LoadString(Globals.hInstance, STRING_NOTEPAD, szResource, SIZEOF(szResource));
118
119 /* Display modal */
120 return MessageBox(Globals.hMainWnd, szMessage, szResource, MB_ICONEXCLAMATION|MB_YESNOCANCEL);
121 }
122
123 /**
124 * Returns:
125 * TRUE - if file exists
126 * FALSE - if file does not exist
127 */
128 BOOL FileExists(LPCWSTR szFilename)
129 {
130 WIN32_FIND_DATA entry;
131 HANDLE hFile;
132
133 hFile = FindFirstFile(szFilename, &entry);
134 FindClose(hFile);
135
136 return (hFile != INVALID_HANDLE_VALUE);
137 }
138
139
140 static VOID DoSaveFile(VOID)
141 {
142 HANDLE hFile;
143 LPWSTR pTemp;
144 DWORD size;
145
146 hFile = CreateFile(Globals.szFileName, GENERIC_WRITE, FILE_SHARE_WRITE,
147 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
148 if(hFile == INVALID_HANDLE_VALUE)
149 {
150 ShowLastError();
151 return;
152 }
153
154 size = GetWindowTextLengthW(Globals.hEdit) + 1;
155 pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*pTemp));
156 if (!pTemp)
157 {
158 CloseHandle(hFile);
159 ShowLastError();
160 return;
161 }
162 size = GetWindowTextW(Globals.hEdit, pTemp, size);
163
164 if (!WriteText(hFile, pTemp, size, Globals.iEncoding, Globals.iEoln))
165 ShowLastError();
166 else
167 SendMessage(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
168
169 CloseHandle(hFile);
170 HeapFree(GetProcessHeap(), 0, pTemp);
171 }
172
173 /**
174 * Returns:
175 * TRUE - User agreed to close (both save/don't save)
176 * FALSE - User cancelled close by selecting "Cancel"
177 */
178 BOOL DoCloseFile(void)
179 {
180 int nResult;
181 static const WCHAR empty_strW[] = { 0 };
182
183 if (SendMessage(Globals.hEdit, EM_GETMODIFY, 0, 0))
184 {
185 /* prompt user to save changes */
186 nResult = AlertFileNotSaved(Globals.szFileName);
187 switch (nResult) {
188 case IDYES: DIALOG_FileSave();
189 break;
190
191 case IDNO: break;
192
193 case IDCANCEL: return(FALSE);
194 break;
195
196 default: return(FALSE);
197 break;
198 } /* switch */
199 } /* if */
200
201 SetFileName(empty_strW);
202
203 UpdateWindowCaption();
204 return(TRUE);
205 }
206
207
208 void DoOpenFile(LPCWSTR szFileName)
209 {
210 static const WCHAR dotlog[] = { '.','L','O','G',0 };
211 HANDLE hFile;
212 LPWSTR pszText;
213 DWORD dwTextLen;
214 WCHAR log[5];
215
216 /* Close any files and prompt to save changes */
217 if (!DoCloseFile())
218 return;
219
220 hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
221 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
222 if (hFile == INVALID_HANDLE_VALUE)
223 {
224 ShowLastError();
225 goto done;
226 }
227
228 if (!ReadText(hFile, &pszText, &dwTextLen, &Globals.iEncoding, &Globals.iEoln))
229 {
230 ShowLastError();
231 goto done;
232 }
233
234 SetWindowTextW(Globals.hEdit, pszText);
235
236 SendMessage(Globals.hEdit, EM_SETMODIFY, FALSE, 0);
237 SendMessage(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
238 SetFocus(Globals.hEdit);
239
240 /* If the file starts with .LOG, add a time/date at the end and set cursor after
241 * See http://support.microsoft.com/?kbid=260563
242 */
243 if (GetWindowTextW(Globals.hEdit, log, sizeof(log)/sizeof(log[0])) && !lstrcmp(log, dotlog))
244 {
245 static const WCHAR lfW[] = { '\r','\n',0 };
246 SendMessage(Globals.hEdit, EM_SETSEL, GetWindowTextLength(Globals.hEdit), -1);
247 SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lfW);
248 DIALOG_EditTimeDate();
249 SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lfW);
250 }
251
252 SetFileName(szFileName);
253 UpdateWindowCaption();
254
255 done:
256 if (hFile != INVALID_HANDLE_VALUE)
257 CloseHandle(hFile);
258 if (pszText)
259 HeapFree(GetProcessHeap(), 0, pszText);
260 }
261
262 VOID DIALOG_FileNew(VOID)
263 {
264 static const WCHAR empty_strW[] = { 0 };
265
266 /* Close any files and prompt to save changes */
267 if (DoCloseFile()) {
268 SetWindowText(Globals.hEdit, empty_strW);
269 SendMessage(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0);
270 SetFocus(Globals.hEdit);
271 }
272 }
273
274 VOID DIALOG_FileOpen(VOID)
275 {
276 OPENFILENAME openfilename;
277 WCHAR szDir[MAX_PATH];
278 WCHAR szPath[MAX_PATH];
279 static const WCHAR szDefaultExt[] = { 't','x','t',0 };
280 static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
281
282 ZeroMemory(&openfilename, sizeof(openfilename));
283
284 GetCurrentDirectory(SIZEOF(szDir), szDir);
285 if (Globals.szFileName[0] == 0)
286 lstrcpy(szPath, txt_files);
287 else
288 lstrcpy(szPath, Globals.szFileName);
289
290 openfilename.lStructSize = sizeof(openfilename);
291 openfilename.hwndOwner = Globals.hMainWnd;
292 openfilename.hInstance = Globals.hInstance;
293 openfilename.lpstrFilter = Globals.szFilter;
294 openfilename.lpstrFile = szPath;
295 openfilename.nMaxFile = SIZEOF(szPath);
296 openfilename.lpstrInitialDir = szDir;
297 openfilename.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST |
298 OFN_HIDEREADONLY;
299 openfilename.lpstrDefExt = szDefaultExt;
300
301
302 if (GetOpenFileName(&openfilename)) {
303 if (FileExists(openfilename.lpstrFile))
304 DoOpenFile(openfilename.lpstrFile);
305 else
306 AlertFileNotFound(openfilename.lpstrFile);
307 }
308 }
309
310
311 VOID DIALOG_FileSave(VOID)
312 {
313 if (Globals.szFileName[0] == '\0')
314 DIALOG_FileSaveAs();
315 else
316 DoSaveFile();
317 }
318
319 static UINT_PTR CALLBACK DIALOG_FileSaveAs_Hook(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
320 {
321 WCHAR szText[128];
322 HWND hCombo;
323 OFNOTIFY *pNotify;
324
325 switch(msg)
326 {
327 case WM_INITDIALOG:
328 hCombo = GetDlgItem(hDlg, ID_ENCODING);
329
330 LoadString(Globals.hInstance, STRING_ANSI, szText, SIZEOF(szText));
331 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
332
333 LoadString(Globals.hInstance, STRING_UNICODE, szText, SIZEOF(szText));
334 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
335
336 LoadString(Globals.hInstance, STRING_UNICODE_BE, szText, SIZEOF(szText));
337 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
338
339 LoadString(Globals.hInstance, STRING_UTF8, szText, SIZEOF(szText));
340 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
341
342 SendMessage(hCombo, CB_SETCURSEL, Globals.iEncoding, 0);
343
344 hCombo = GetDlgItem(hDlg, ID_EOLN);
345
346 LoadString(Globals.hInstance, STRING_CRLF, szText, SIZEOF(szText));
347 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
348
349 LoadString(Globals.hInstance, STRING_LF, szText, SIZEOF(szText));
350 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
351
352 LoadString(Globals.hInstance, STRING_CR, szText, SIZEOF(szText));
353 SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM) szText);
354
355 SendMessage(hCombo, CB_SETCURSEL, Globals.iEoln, 0);
356 break;
357
358 case WM_NOTIFY:
359 if (((NMHDR *) lParam)->code == CDN_FILEOK)
360 {
361 pNotify = (OFNOTIFY *) lParam;
362
363 hCombo = GetDlgItem(hDlg, ID_ENCODING);
364 if (hCombo)
365 Globals.iEncoding = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
366
367 hCombo = GetDlgItem(hDlg, ID_EOLN);
368 if (hCombo)
369 Globals.iEoln = SendMessage(hCombo, CB_GETCURSEL, 0, 0);
370 }
371 break;
372 }
373 return 0;
374 }
375
376 VOID DIALOG_FileSaveAs(VOID)
377 {
378 OPENFILENAME saveas;
379 WCHAR szDir[MAX_PATH];
380 WCHAR szPath[MAX_PATH];
381 static const WCHAR szDefaultExt[] = { 't','x','t',0 };
382 static const WCHAR txt_files[] = { '*','.','t','x','t',0 };
383
384 ZeroMemory(&saveas, sizeof(saveas));
385
386 GetCurrentDirectory(SIZEOF(szDir), szDir);
387 if (Globals.szFileName[0] == 0)
388 lstrcpy(szPath, txt_files);
389 else
390 lstrcpy(szPath, Globals.szFileName);
391
392 saveas.lStructSize = sizeof(OPENFILENAME);
393 saveas.hwndOwner = Globals.hMainWnd;
394 saveas.hInstance = Globals.hInstance;
395 saveas.lpstrFilter = Globals.szFilter;
396 saveas.lpstrFile = szPath;
397 saveas.nMaxFile = SIZEOF(szPath);
398 saveas.lpstrInitialDir = szDir;
399 saveas.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT |
400 OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
401 saveas.lpstrDefExt = szDefaultExt;
402 saveas.lpTemplateName = MAKEINTRESOURCE(DIALOG_ENCODING);
403 saveas.lpfnHook = DIALOG_FileSaveAs_Hook;
404
405 if (GetSaveFileName(&saveas)) {
406 SetFileName(szPath);
407 UpdateWindowCaption();
408 DoSaveFile();
409 }
410 }
411
412 VOID DIALOG_FilePrint(VOID)
413 {
414 DOCINFO di;
415 PRINTDLG printer;
416 SIZE szMetric;
417 int cWidthPels, cHeightPels, border;
418 int xLeft, yTop, pagecount, dopage, copycount;
419 unsigned int i;
420 LOGFONT hdrFont;
421 HFONT font, old_font=0;
422 DWORD size;
423 LPWSTR pTemp;
424 static const WCHAR times_new_romanW[] = { 'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0 };
425
426 /* Get a small font and print some header info on each page */
427 hdrFont.lfHeight = 100;
428 hdrFont.lfWidth = 0;
429 hdrFont.lfEscapement = 0;
430 hdrFont.lfOrientation = 0;
431 hdrFont.lfWeight = FW_BOLD;
432 hdrFont.lfItalic = 0;
433 hdrFont.lfUnderline = 0;
434 hdrFont.lfStrikeOut = 0;
435 hdrFont.lfCharSet = ANSI_CHARSET;
436 hdrFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
437 hdrFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
438 hdrFont.lfQuality = PROOF_QUALITY;
439 hdrFont.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN;
440 lstrcpy(hdrFont.lfFaceName, times_new_romanW);
441
442 font = CreateFontIndirect(&hdrFont);
443
444 /* Get Current Settings */
445 ZeroMemory(&printer, sizeof(printer));
446 printer.lStructSize = sizeof(printer);
447 printer.hwndOwner = Globals.hMainWnd;
448 printer.hInstance = Globals.hInstance;
449
450 /* Set some default flags */
451 printer.Flags = PD_RETURNDC;
452 printer.nFromPage = 0;
453 printer.nMinPage = 1;
454 /* we really need to calculate number of pages to set nMaxPage and nToPage */
455 printer.nToPage = 0;
456 printer.nMaxPage = -1;
457
458 /* Let commdlg manage copy settings */
459 printer.nCopies = (WORD)PD_USEDEVMODECOPIES;
460
461 if (!PrintDlg(&printer)) return;
462
463 assert(printer.hDC != 0);
464
465 /* initialize DOCINFO */
466 di.cbSize = sizeof(DOCINFO);
467 di.lpszDocName = Globals.szFileTitle;
468 di.lpszOutput = NULL;
469 di.lpszDatatype = NULL;
470 di.fwType = 0;
471
472 if (StartDoc(printer.hDC, &di) <= 0) return;
473
474 /* Get the page dimensions in pixels. */
475 cWidthPels = GetDeviceCaps(printer.hDC, HORZRES);
476 cHeightPels = GetDeviceCaps(printer.hDC, VERTRES);
477
478 /* Get the file text */
479 size = GetWindowTextLengthW(Globals.hEdit) + 1;
480 pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
481 if (!pTemp)
482 {
483 ShowLastError();
484 return;
485 }
486 size = GetWindowTextW(Globals.hEdit, pTemp, size);
487
488 border = 150;
489 for (copycount=1; copycount <= printer.nCopies; copycount++) {
490 i = 0;
491 pagecount = 1;
492 do {
493 static const WCHAR letterM[] = { 'M',0 };
494
495 if (pagecount >= printer.nFromPage &&
496 /* ((printer.Flags & PD_PAGENUMS) == 0 || pagecount <= printer.nToPage))*/
497 pagecount <= printer.nToPage)
498 dopage = 1;
499 else
500 dopage = 0;
501
502 old_font = SelectObject(printer.hDC, font);
503 GetTextExtentPoint32(printer.hDC, letterM, 1, &szMetric);
504
505 if (dopage) {
506 if (StartPage(printer.hDC) <= 0) {
507 static const WCHAR failedW[] = { 'S','t','a','r','t','P','a','g','e',' ','f','a','i','l','e','d',0 };
508 static const WCHAR errorW[] = { 'P','r','i','n','t',' ','E','r','r','o','r',0 };
509 MessageBox(Globals.hMainWnd, failedW, errorW, MB_ICONEXCLAMATION);
510 return;
511 }
512 /* Write a rectangle and header at the top of each page */
513 Rectangle(printer.hDC, border, border, cWidthPels-border, border+szMetric.cy*2);
514 /* I don't know what's up with this TextOut command. This comes out
515 kind of mangled.
516 */
517 TextOut(printer.hDC, border*2, border+szMetric.cy/2, Globals.szFileTitle, lstrlen(Globals.szFileTitle));
518 }
519
520 /* The starting point for the main text */
521 xLeft = border*2;
522 yTop = border+szMetric.cy*4;
523
524 SelectObject(printer.hDC, old_font);
525 GetTextExtentPoint32(printer.hDC, letterM, 1, &szMetric);
526
527 /* Since outputting strings is giving me problems, output the main
528 text one character at a time.
529 */
530 do {
531 if (pTemp[i] == '\n') {
532 xLeft = border*2;
533 yTop += szMetric.cy;
534 }
535 else if (pTemp[i] != '\r') {
536 if (dopage)
537 TextOut(printer.hDC, xLeft, yTop, &pTemp[i], 1);
538 xLeft += szMetric.cx;
539 }
540 } while (i++<size && yTop<(cHeightPels-border*2));
541
542 if (dopage)
543 EndPage(printer.hDC);
544 pagecount++;
545 } while (i<size);
546 }
547
548 EndDoc(printer.hDC);
549 DeleteDC(printer.hDC);
550 HeapFree(GetProcessHeap(), 0, pTemp);
551 }
552
553 VOID DIALOG_FilePrinterSetup(VOID)
554 {
555 PRINTDLG printer;
556
557 ZeroMemory(&printer, sizeof(printer));
558 printer.lStructSize = sizeof(printer);
559 printer.hwndOwner = Globals.hMainWnd;
560 printer.hInstance = Globals.hInstance;
561 printer.Flags = PD_PRINTSETUP;
562 printer.nCopies = 1;
563
564 PrintDlg(&printer);
565 }
566
567 VOID DIALOG_FileExit(VOID)
568 {
569 PostMessage(Globals.hMainWnd, WM_CLOSE, 0, 0l);
570 }
571
572 VOID DIALOG_EditUndo(VOID)
573 {
574 SendMessage(Globals.hEdit, EM_UNDO, 0, 0);
575 }
576
577 VOID DIALOG_EditCut(VOID)
578 {
579 SendMessage(Globals.hEdit, WM_CUT, 0, 0);
580 }
581
582 VOID DIALOG_EditCopy(VOID)
583 {
584 SendMessage(Globals.hEdit, WM_COPY, 0, 0);
585 }
586
587 VOID DIALOG_EditPaste(VOID)
588 {
589 SendMessage(Globals.hEdit, WM_PASTE, 0, 0);
590 }
591
592 VOID DIALOG_EditDelete(VOID)
593 {
594 SendMessage(Globals.hEdit, WM_CLEAR, 0, 0);
595 }
596
597 VOID DIALOG_EditSelectAll(VOID)
598 {
599 SendMessage(Globals.hEdit, EM_SETSEL, 0, (LPARAM)-1);
600 }
601
602 VOID DIALOG_EditTimeDate(VOID)
603 {
604 SYSTEMTIME st;
605 WCHAR szDate[MAX_STRING_LEN];
606 static const WCHAR spaceW[] = { ' ',0 };
607
608 GetLocalTime(&st);
609
610 GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szDate, MAX_STRING_LEN);
611 SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szDate);
612
613 SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)spaceW);
614
615 GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szDate, MAX_STRING_LEN);
616 SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)szDate);
617 }
618
619 VOID DIALOG_EditWrap(VOID)
620 {
621 static const WCHAR editW[] = { 'e','d','i','t',0 };
622 DWORD dwStyle;
623 RECT rc;
624 DWORD size;
625 LPWSTR pTemp;
626
627 Globals.bWrapLongLines = !Globals.bWrapLongLines;
628
629 size = GetWindowTextLength(Globals.hEdit) + 1;
630 pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
631 if (!pTemp)
632 {
633 ShowLastError();
634 return;
635 }
636 GetWindowText(Globals.hEdit, pTemp, size);
637 DestroyWindow(Globals.hEdit);
638 GetClientRect(Globals.hMainWnd, &rc);
639 dwStyle = Globals.bWrapLongLines ? EDIT_STYLE_WRAP : EDIT_STYLE;
640 Globals.hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, editW, NULL, dwStyle,
641 0, 0, rc.right, rc.bottom, Globals.hMainWnd,
642 NULL, Globals.hInstance, NULL);
643 SendMessage(Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, (LPARAM)FALSE);
644 SendMessage(Globals.hEdit, EM_LIMITTEXT, 0, 0);
645 SetWindowTextW(Globals.hEdit, pTemp);
646 SetFocus(Globals.hEdit);
647 HeapFree(GetProcessHeap(), 0, pTemp);
648 }
649
650 VOID DIALOG_SelectFont(VOID)
651 {
652 CHOOSEFONT cf;
653 LOGFONT lf=Globals.lfFont;
654
655 ZeroMemory( &cf, sizeof(cf) );
656 cf.lStructSize=sizeof(cf);
657 cf.hwndOwner=Globals.hMainWnd;
658 cf.lpLogFont=&lf;
659 cf.Flags=CF_SCREENFONTS;
660
661 if( ChooseFont(&cf) )
662 {
663 HFONT currfont=Globals.hFont;
664
665 Globals.hFont=CreateFontIndirect( &lf );
666 Globals.lfFont=lf;
667 SendMessage( Globals.hEdit, WM_SETFONT, (WPARAM)Globals.hFont, (LPARAM)TRUE );
668 if( currfont!=NULL )
669 DeleteObject( currfont );
670 }
671 }
672
673 typedef HWND (STDCALL *FINDPROC)(LPFINDREPLACE lpfr);
674
675 static VOID DIALOG_SearchDialog(FINDPROC pfnProc)
676 {
677 ZeroMemory(&Globals.find, sizeof(Globals.find));
678 Globals.find.lStructSize = sizeof(Globals.find);
679 Globals.find.hwndOwner = Globals.hMainWnd;
680 Globals.find.hInstance = Globals.hInstance;
681 Globals.find.lpstrFindWhat = Globals.szFindText;
682 Globals.find.wFindWhatLen = SIZEOF(Globals.szFindText);
683 Globals.find.lpstrReplaceWith = Globals.szReplaceText;
684 Globals.find.wReplaceWithLen = SIZEOF(Globals.szReplaceText);
685 Globals.find.Flags = FR_DOWN;
686
687 /* We only need to create the modal FindReplace dialog which will */
688 /* notify us of incoming events using hMainWnd Window Messages */
689
690 Globals.hFindReplaceDlg = pfnProc(&Globals.find);
691 assert(Globals.hFindReplaceDlg !=0);
692 }
693
694 VOID DIALOG_Search(VOID)
695 {
696 DIALOG_SearchDialog(FindText);
697 }
698
699 VOID DIALOG_SearchNext(VOID)
700 {
701 /* FIXME: Search Next */
702 DIALOG_Search();
703 }
704
705 VOID DIALOG_Replace(VOID)
706 {
707 DIALOG_SearchDialog(ReplaceText);
708 }
709
710 static INT_PTR CALLBACK DIALOG_GoTo_DialogProc(HWND hwndDialog, UINT uMsg, WPARAM wParam, LPARAM lParam)
711 {
712 BOOL bResult = FALSE;
713 HWND hTextBox;
714 TCHAR szText[32];
715
716 switch(uMsg) {
717 case WM_INITDIALOG:
718 hTextBox = GetDlgItem(hwndDialog, ID_LINENUMBER);
719 _sntprintf(szText, sizeof(szText) / sizeof(szText[0]), _T("%d"), lParam);
720 SetWindowText(hTextBox, szText);
721 break;
722 case WM_COMMAND:
723 if (HIWORD(wParam) == BN_CLICKED)
724 {
725 if (LOWORD(wParam) == IDOK)
726 {
727 hTextBox = GetDlgItem(hwndDialog, ID_LINENUMBER);
728 GetWindowText(hTextBox, szText, sizeof(szText) / sizeof(szText[0]));
729 EndDialog(hwndDialog, _ttoi(szText));
730 bResult = TRUE;
731 }
732 else if (LOWORD(wParam) == IDCANCEL)
733 {
734 EndDialog(hwndDialog, 0);
735 bResult = TRUE;
736 }
737 }
738 break;
739 }
740
741 return bResult;
742 }
743
744 VOID DIALOG_GoTo(VOID)
745 {
746 INT_PTR nLine;
747 LPTSTR pszText;
748 int nLength, i;
749 DWORD dwStart, dwEnd;
750
751 nLength = GetWindowTextLength(Globals.hEdit);
752 pszText = (LPTSTR) HeapAlloc(GetProcessHeap(), 0, (nLength + 1) * sizeof(*pszText));
753 if (!pszText)
754 return;
755
756 /* Retrieve current text */
757 GetWindowText(Globals.hEdit, pszText, nLength + 1);
758 SendMessage(Globals.hEdit, EM_GETSEL, (WPARAM) &dwStart, (LPARAM) &dwEnd);
759
760 nLine = 1;
761 for (i = 0; pszText[i] && (i < dwStart); i++)
762 {
763 if (pszText[i] == '\n')
764 nLine++;
765 }
766
767 nLine = DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(DIALOG_GOTO),
768 Globals.hMainWnd, DIALOG_GoTo_DialogProc, nLine);
769
770 if (nLine >= 1)
771 {
772 for (i = 0; pszText[i] && (nLine > 1) && (i < nLength - 1); i++)
773 {
774 if (pszText[i] == '\n')
775 nLine--;
776 }
777 SendMessage(Globals.hEdit, EM_SETSEL, i, i);
778 }
779 HeapFree(GetProcessHeap(), 0, pszText);
780 }
781
782 VOID DIALOG_HelpContents(VOID)
783 {
784 WinHelp(Globals.hMainWnd, helpfileW, HELP_INDEX, 0);
785 }
786
787 VOID DIALOG_HelpSearch(VOID)
788 {
789 /* Search Help */
790 }
791
792 VOID DIALOG_HelpHelp(VOID)
793 {
794 WinHelp(Globals.hMainWnd, helpfileW, HELP_HELPONHELP, 0);
795 }
796
797 VOID DIALOG_HelpLicense(VOID)
798 {
799 WineLicense(Globals.hMainWnd);
800 }
801
802 VOID DIALOG_HelpNoWarranty(VOID)
803 {
804 WineWarranty(Globals.hMainWnd);
805 }
806
807 VOID DIALOG_HelpAboutWine(VOID)
808 {
809 static const WCHAR notepadW[] = { 'N','o','t','e','p','a','d','\n',0 };
810 WCHAR szNotepad[MAX_STRING_LEN];
811
812 LoadString(Globals.hInstance, STRING_NOTEPAD, szNotepad, SIZEOF(szNotepad));
813 ShellAbout(Globals.hMainWnd, szNotepad, notepadW, 0);
814 }
815
816
817 /***********************************************************************
818 *
819 * DIALOG_FilePageSetup
820 */
821 VOID DIALOG_FilePageSetup(void)
822 {
823 DialogBox(Globals.hInstance, MAKEINTRESOURCE(DIALOG_PAGESETUP),
824 Globals.hMainWnd, DIALOG_PAGESETUP_DlgProc);
825 }
826
827
828 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
829 *
830 * DIALOG_PAGESETUP_DlgProc
831 */
832
833 static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
834 {
835
836 switch (msg)
837 {
838 case WM_COMMAND:
839 switch (wParam)
840 {
841 case IDOK:
842 /* save user input and close dialog */
843 GetDlgItemText(hDlg, 0x141, Globals.szHeader, SIZEOF(Globals.szHeader));
844 GetDlgItemText(hDlg, 0x143, Globals.szFooter, SIZEOF(Globals.szFooter));
845 GetDlgItemText(hDlg, 0x14A, Globals.szMarginTop, SIZEOF(Globals.szMarginTop));
846 GetDlgItemText(hDlg, 0x150, Globals.szMarginBottom, SIZEOF(Globals.szMarginBottom));
847 GetDlgItemText(hDlg, 0x147, Globals.szMarginLeft, SIZEOF(Globals.szMarginLeft));
848 GetDlgItemText(hDlg, 0x14D, Globals.szMarginRight, SIZEOF(Globals.szMarginRight));
849 EndDialog(hDlg, IDOK);
850 return TRUE;
851
852 case IDCANCEL:
853 /* discard user input and close dialog */
854 EndDialog(hDlg, IDCANCEL);
855 return TRUE;
856
857 case IDHELP:
858 {
859 /* FIXME: Bring this to work */
860 static const WCHAR sorryW[] = { 'S','o','r','r','y',',',' ','n','o',' ','h','e','l','p',' ','a','v','a','i','l','a','b','l','e',0 };
861 static const WCHAR helpW[] = { 'H','e','l','p',0 };
862 MessageBox(Globals.hMainWnd, sorryW, helpW, MB_ICONEXCLAMATION);
863 return TRUE;
864 }
865
866 default:
867 break;
868 }
869 break;
870
871 case WM_INITDIALOG:
872 /* fetch last user input prior to display dialog */
873 SetDlgItemText(hDlg, 0x141, Globals.szHeader);
874 SetDlgItemText(hDlg, 0x143, Globals.szFooter);
875 SetDlgItemText(hDlg, 0x14A, Globals.szMarginTop);
876 SetDlgItemText(hDlg, 0x150, Globals.szMarginBottom);
877 SetDlgItemText(hDlg, 0x147, Globals.szMarginLeft);
878 SetDlgItemText(hDlg, 0x14D, Globals.szMarginRight);
879 break;
880 }
881
882 return FALSE;
883 }