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