/* * Notepad (dialog.c) * * Copyright 1998,99 Marcel Baur * Copyright 2002 Sylvain Petreolle * Copyright 2002 Andriy Palamarchuk * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define UNICODE #include #include #include #include #include "main.h" #include "license.h" #include "dialog.h" static const WCHAR helpfileW[] = { 'n','o','t','e','p','a','d','.','h','l','p',0 }; static INT_PTR WINAPI DIALOG_PAGESETUP_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); VOID ShowLastError(void) { DWORD error = GetLastError(); if (error != NO_ERROR) { LPWSTR lpMsgBuf; WCHAR szTitle[MAX_STRING_LEN]; LoadString(Globals.hInstance, STRING_ERROR, szTitle, SIZEOF(szTitle)); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, (LPTSTR) &lpMsgBuf, 0, NULL); MessageBox(NULL, lpMsgBuf, szTitle, MB_OK | MB_ICONERROR); LocalFree(lpMsgBuf); } } /** * Sets the caption of the main window according to Globals.szFileTitle: * Notepad - (untitled) if no file is open * Notepad - [filename] if a file is given */ static void UpdateWindowCaption(void) { WCHAR szCaption[MAX_STRING_LEN]; WCHAR szUntitled[MAX_STRING_LEN]; LoadString(Globals.hInstance, STRING_NOTEPAD, szCaption, SIZEOF(szCaption)); if (Globals.szFileTitle[0] != '\0') { static const WCHAR bracket_lW[] = { ' ','-',' ','[',0 }; static const WCHAR bracket_rW[] = { ']',0 }; lstrcat(szCaption, bracket_lW); lstrcat(szCaption, Globals.szFileTitle); lstrcat(szCaption, bracket_rW); } else { static const WCHAR hyphenW[] = { ' ','-',' ',0 }; LoadString(Globals.hInstance, STRING_UNTITLED, szUntitled, SIZEOF(szUntitled)); lstrcat(szCaption, hyphenW); lstrcat(szCaption, szUntitled); } SetWindowText(Globals.hMainWnd, szCaption); } static void AlertFileNotFound(LPCWSTR szFileName) { WCHAR szMessage[MAX_STRING_LEN]; WCHAR szResource[MAX_STRING_LEN]; /* Load and format szMessage */ LoadString(Globals.hInstance, STRING_NOTFOUND, szResource, SIZEOF(szResource)); wsprintf(szMessage, szResource, szFileName); /* Load szCaption */ LoadString(Globals.hInstance, STRING_ERROR, szResource, SIZEOF(szResource)); /* Display Modal Dialog */ MessageBox(Globals.hMainWnd, szMessage, szResource, MB_ICONEXCLAMATION); } static int AlertFileNotSaved(LPCWSTR szFileName) { WCHAR szMessage[MAX_STRING_LEN]; WCHAR szResource[MAX_STRING_LEN]; WCHAR szUntitled[MAX_STRING_LEN]; LoadString(Globals.hInstance, STRING_UNTITLED, szUntitled, SIZEOF(szUntitled)); /* Load and format Message */ LoadString(Globals.hInstance, STRING_NOTSAVED, szResource, SIZEOF(szResource)); wsprintf(szMessage, szResource, szFileName[0] ? szFileName : szUntitled); /* Load Caption */ LoadString(Globals.hInstance, STRING_ERROR, szResource, SIZEOF(szResource)); /* Display modal */ return MessageBox(Globals.hMainWnd, szMessage, szResource, MB_ICONEXCLAMATION|MB_YESNOCANCEL); } /** * Returns: * TRUE - if file exists * FALSE - if file does not exist */ BOOL FileExists(LPCWSTR szFilename) { WIN32_FIND_DATA entry; HANDLE hFile; hFile = FindFirstFile(szFilename, &entry); FindClose(hFile); return (hFile != INVALID_HANDLE_VALUE); } static VOID DoSaveFile(VOID) { HANDLE hFile; DWORD dwNumWrite; LPSTR pTemp; DWORD size; hFile = CreateFile(Globals.szFileName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { ShowLastError(); return; } size = GetWindowTextLengthA(Globals.hEdit) + 1; pTemp = HeapAlloc(GetProcessHeap(), 0, size); if (!pTemp) { CloseHandle(hFile); ShowLastError(); return; } size = GetWindowTextA(Globals.hEdit, pTemp, size); if (!WriteFile(hFile, pTemp, size, &dwNumWrite, NULL)) ShowLastError(); else SendMessage(Globals.hEdit, EM_SETMODIFY, FALSE, 0); SetEndOfFile(hFile); CloseHandle(hFile); HeapFree(GetProcessHeap(), 0, pTemp); } /** * Returns: * TRUE - User agreed to close (both save/don't save) * FALSE - User cancelled close by selecting "Cancel" */ BOOL DoCloseFile(void) { int nResult; static const WCHAR empty_strW[] = { 0 }; if (SendMessage(Globals.hEdit, EM_GETMODIFY, 0, 0)) { /* prompt user to save changes */ nResult = AlertFileNotSaved(Globals.szFileName); switch (nResult) { case IDYES: DIALOG_FileSave(); break; case IDNO: break; case IDCANCEL: return(FALSE); break; default: return(FALSE); break; } /* switch */ } /* if */ SetFileName(empty_strW); UpdateWindowCaption(); return(TRUE); } void DoOpenFile(LPCWSTR szFileName) { static const WCHAR dotlog[] = { '.','L','O','G',0 }; HANDLE hFile; LPSTR pTemp; DWORD size; DWORD dwNumRead; WCHAR log[5]; /* Close any files and prompt to save changes */ if (!DoCloseFile()) return; hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if(hFile == INVALID_HANDLE_VALUE) { ShowLastError(); return; } size = GetFileSize(hFile, NULL); if (size == INVALID_FILE_SIZE) { CloseHandle(hFile); ShowLastError(); return; } size++; pTemp = HeapAlloc(GetProcessHeap(), 0, size); if (!pTemp) { CloseHandle(hFile); ShowLastError(); return; } if (!ReadFile(hFile, pTemp, size, &dwNumRead, NULL)) { CloseHandle(hFile); HeapFree(GetProcessHeap(), 0, pTemp); ShowLastError(); return; } CloseHandle(hFile); pTemp[dwNumRead] = 0; if (IsTextUnicode(pTemp, dwNumRead, NULL)) { LPWSTR p = (LPWSTR)pTemp; /* We need to strip BOM Unicode character, SetWindowTextW won't do it for us. */ if (*p == 0xFEFF || *p == 0xFFFE) p++; SetWindowTextW(Globals.hEdit, p); } else SetWindowTextA(Globals.hEdit, pTemp); HeapFree(GetProcessHeap(), 0, pTemp); SendMessage(Globals.hEdit, EM_SETMODIFY, FALSE, 0); SendMessage(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0); SetFocus(Globals.hEdit); /* If the file starts with .LOG, add a time/date at the end and set cursor after * See http://support.microsoft.com/?kbid=260563 */ if (GetWindowTextW(Globals.hEdit, log, sizeof(log)/sizeof(log[0])) && !lstrcmp(log, dotlog)) { static const WCHAR lfW[] = { '\r','\n',0 }; SendMessage(Globals.hEdit, EM_SETSEL, GetWindowTextLength(Globals.hEdit), -1); SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lfW); DIALOG_EditTimeDate(); SendMessage(Globals.hEdit, EM_REPLACESEL, TRUE, (LPARAM)lfW); } SetFileName(szFileName); UpdateWindowCaption(); } VOID DIALOG_FileNew(VOID) { static const WCHAR empty_strW[] = { 0 }; /* Close any files and promt to save changes */ if (DoCloseFile()) { SetWindowText(Globals.hEdit, empty_strW); SendMessage(Globals.hEdit, EM_EMPTYUNDOBUFFER, 0, 0); SetFocus(Globals.hEdit); } } VOID DIALOG_FileOpen(VOID) { OPENFILENAME openfilename; WCHAR szPath[MAX_PATH]; WCHAR szDir[MAX_PATH]; static const WCHAR szDefaultExt[] = { 't','x','t',0 }; static const WCHAR txt_files[] = { '*','.','t','x','t',0 }; ZeroMemory(&openfilename, sizeof(openfilename)); GetCurrentDirectory(SIZEOF(szDir), szDir); lstrcpy(szPath, txt_files); openfilename.lStructSize = sizeof(openfilename); openfilename.hwndOwner = Globals.hMainWnd; openfilename.hInstance = Globals.hInstance; openfilename.lpstrFilter = Globals.szFilter; openfilename.lpstrFile = szPath; openfilename.nMaxFile = SIZEOF(szPath); openfilename.lpstrInitialDir = szDir; openfilename.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY; openfilename.lpstrDefExt = szDefaultExt; if (GetOpenFileName(&openfilename)) { if (FileExists(openfilename.lpstrFile)) DoOpenFile(openfilename.lpstrFile); else AlertFileNotFound(openfilename.lpstrFile); } } VOID DIALOG_FileSave(VOID) { if (Globals.szFileName[0] == '\0') DIALOG_FileSaveAs(); else DoSaveFile(); } VOID DIALOG_FileSaveAs(VOID) { OPENFILENAME saveas; WCHAR szPath[MAX_PATH]; WCHAR szDir[MAX_PATH]; static const WCHAR szDefaultExt[] = { 't','x','t',0 }; static const WCHAR txt_files[] = { '*','.','t','x','t',0 }; ZeroMemory(&saveas, sizeof(saveas)); GetCurrentDirectory(SIZEOF(szDir), szDir); lstrcpy(szPath, txt_files); saveas.lStructSize = sizeof(OPENFILENAME); saveas.hwndOwner = Globals.hMainWnd; saveas.hInstance = Globals.hInstance; saveas.lpstrFilter = Globals.szFilter; saveas.lpstrFile = szPath; saveas.nMaxFile = SIZEOF(szPath); saveas.lpstrInitialDir = szDir; saveas.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY; saveas.lpstrDefExt = szDefaultExt; if (GetSaveFileName(&saveas)) { SetFileName(szPath); UpdateWindowCaption(); DoSaveFile(); } } VOID DIALOG_FilePrint(VOID) { DOCINFO di; PRINTDLG printer; SIZE szMetric; int cWidthPels, cHeightPels, border; int xLeft, yTop, pagecount, dopage, copycount; unsigned int i; LOGFONT hdrFont; HFONT font, old_font=0; DWORD size; LPWSTR pTemp; static const WCHAR times_new_romanW[] = { 'T','i','m','e','s',' ','N','e','w',' ','R','o','m','a','n',0 }; /* Get a small font and print some header info on each page */ hdrFont.lfHeight = 100; hdrFont.lfWidth = 0; hdrFont.lfEscapement = 0; hdrFont.lfOrientation = 0; hdrFont.lfWeight = FW_BOLD; hdrFont.lfItalic = 0; hdrFont.lfUnderline = 0; hdrFont.lfStrikeOut = 0; hdrFont.lfCharSet = ANSI_CHARSET; hdrFont.lfOutPrecision = OUT_DEFAULT_PRECIS; hdrFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; hdrFont.lfQuality = PROOF_QUALITY; hdrFont.lfPitchAndFamily = VARIABLE_PITCH | FF_ROMAN; lstrcpy(hdrFont.lfFaceName, times_new_romanW); font = CreateFontIndirect(&hdrFont); /* Get Current Settings */ ZeroMemory(&printer, sizeof(printer)); printer.lStructSize = sizeof(printer); printer.hwndOwner = Globals.hMainWnd; printer.hInstance = Globals.hInstance; /* Set some default flags */ printer.Flags = PD_RETURNDC; printer.nFromPage = 0; printer.nMinPage = 1; /* we really need to calculate number of pages to set nMaxPage and nToPage */ printer.nToPage = 0; printer.nMaxPage = -1; /* Let commdlg manage copy settings */ printer.nCopies = (WORD)PD_USEDEVMODECOPIES; if (!PrintDlg(&printer)) return; assert(printer.hDC != 0); /* initialize DOCINFO */ di.cbSize = sizeof(DOCINFO); di.lpszDocName = Globals.szFileTitle; di.lpszOutput = NULL; di.lpszDatatype = NULL; di.fwType = 0; if (StartDoc(printer.hDC, &di) <= 0) return; /* Get the page dimensions in pixels. */ cWidthPels = GetDeviceCaps(printer.hDC, HORZRES); cHeightPels = GetDeviceCaps(printer.hDC, VERTRES); /* Get the file text */ size = GetWindowTextLength(Globals.hEdit) + 1; pTemp = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)); if (!pTemp) { ShowLastError(); return; } size = GetWindowText(Globals.hEdit, pTemp, size); border = 150; for (copycount=1; copycount <= printer.nCopies; copycount++) { i = 0; pagecount = 1; do { static const WCHAR letterM[] = { 'M',0 }; if (pagecount >= printer.nFromPage && /* ((printer.Flags & PD_PAGENUMS) == 0 || pagecount <= printer.nToPage))*/ pagecount <= printer.nToPage) dopage = 1; else dopage = 0; old_font = SelectObject(printer.hDC, font); GetTextExtentPoint32(printer.hDC, letterM, 1, &szMetric); if (dopage) { if (StartPage(printer.hDC) <= 0) { static const WCHAR failedW[] = { 'S','t','a','r','t','P','a','g','e',' ','f','a','i','l','e','d',0 }; static const WCHAR errorW[] = { 'P','r','i','n','t',' ','E','r','r','o','r',0 }; MessageBox(Globals.hMainWnd, failedW, errorW, MB_ICONEXCLAMATION); return; } /* Write a rectangle and header at the top of each page */ Rectangle(printer.hDC, border, border, cWidthPels-border, border+szMetric.cy*2); /* I don't know what's up with this TextOut command. This comes out kind of mangled. */ TextOut(printer.hDC, border*2, border+szMetric.cy/2, Globals.szFileTitle, lstrlen(Globals.szFileTitle)); } /* The starting point for the main text */ xLeft = border*2; yTop = border+szMetric.cy*4; SelectObject(printer.hDC, old_font); GetTextExtentPoint32(printer.hDC, letterM, 1, &szMetric); /* Since outputting strings is giving me problems, output the main text one character at a time. */ do { if (pTemp[i] == '\n') { xLeft = border*2; yTop += szMetric.cy; } else if (pTemp[i] != '\r') { if (dopage) TextOut(printer.hDC, xLeft, yTop, &pTemp[i], 1); xLeft += szMetric.cx; } } while (i++