attrib.exe: Add stubbed command.
[wine] / programs / wordpad / registry.c
1 /*
2  * Wordpad implementation - Registry functions
3  *
4  * Copyright 2007 by Alexander N. Sørnes <alex@thehandofagony.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <windows.h>
22 #include <shlobj.h>
23 #include <richedit.h>
24
25 #include "wordpad.h"
26
27 static const WCHAR key_recentfiles[] = {'R','e','c','e','n','t',' ','f','i','l','e',
28                                         ' ','l','i','s','t',0};
29 static const WCHAR key_options[] = {'O','p','t','i','o','n','s',0};
30 static const WCHAR key_settings[] = {'S','e','t','t','i','n','g','s',0};
31 static const WCHAR key_rtf[] = {'R','T','F',0};
32 static const WCHAR key_text[] = {'T','e','x','t',0};
33
34 static const WCHAR var_file[] = {'F','i','l','e','%','d',0};
35 static const WCHAR var_framerect[] = {'F','r','a','m','e','R','e','c','t',0};
36 static const WCHAR var_barstate0[] = {'B','a','r','S','t','a','t','e','0',0};
37 static const WCHAR var_maximized[] = {'M','a','x','i','m','i','z','e','d',0};
38
39 static LRESULT registry_get_handle(HKEY *hKey, LPDWORD action, LPCWSTR subKey)
40 {
41     LONG ret;
42     static const WCHAR wszProgramKey[] = {'S','o','f','t','w','a','r','e','\\',
43         'M','i','c','r','o','s','o','f','t','\\',
44         'W','i','n','d','o','w','s','\\',
45         'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
46         'A','p','p','l','e','t','s','\\',
47         'W','o','r','d','p','a','d',0};
48         LPWSTR key = (LPWSTR)wszProgramKey;
49
50         if(subKey)
51         {
52             WCHAR backslash[] = {'\\',0};
53             key = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
54                             (lstrlenW(wszProgramKey)+lstrlenW(subKey)+lstrlenW(backslash)+1)
55                                     *sizeof(WCHAR));
56
57             if(!key)
58                 return 1;
59
60             lstrcpyW(key, wszProgramKey);
61             lstrcatW(key, backslash);
62             lstrcatW(key, subKey);
63         }
64
65         if(action)
66         {
67             ret = RegCreateKeyExW(HKEY_CURRENT_USER, key, 0, NULL, REG_OPTION_NON_VOLATILE,
68                                   KEY_READ | KEY_WRITE, NULL, hKey, action);
69         } else
70         {
71             ret = RegOpenKeyExW(HKEY_CURRENT_USER, key, 0, KEY_READ | KEY_WRITE, hKey);
72         }
73
74         if(subKey)
75             HeapFree(GetProcessHeap(), 0, key);
76
77         return ret;
78 }
79
80 void registry_set_options(HWND hMainWnd)
81 {
82     HKEY hKey = 0;
83     DWORD action;
84
85     if(registry_get_handle(&hKey, &action, key_options) == ERROR_SUCCESS)
86     {
87         WINDOWPLACEMENT wp;
88         DWORD isMaximized;
89
90         wp.length = sizeof(WINDOWPLACEMENT);
91         GetWindowPlacement(hMainWnd, &wp);
92         isMaximized = (wp.showCmd == SW_SHOWMAXIMIZED);
93
94         RegSetValueExW(hKey, var_framerect, 0, REG_BINARY, (LPBYTE)&wp.rcNormalPosition, sizeof(RECT));
95         RegSetValueExW(hKey, var_maximized, 0, REG_DWORD, (LPBYTE)&isMaximized, sizeof(DWORD));
96
97         registry_set_pagemargins(hKey);
98         RegCloseKey(hKey);
99     }
100
101     if(registry_get_handle(&hKey, &action, key_settings) == ERROR_SUCCESS)
102     {
103         registry_set_previewpages(hKey);
104         RegCloseKey(hKey);
105     }
106 }
107
108 void registry_read_winrect(RECT* rc)
109 {
110     HKEY hKey = 0;
111     DWORD size = sizeof(RECT);
112
113     if(registry_get_handle(&hKey, 0, key_options) != ERROR_SUCCESS ||
114        RegQueryValueExW(hKey, var_framerect, 0, NULL, (LPBYTE)rc, &size) !=
115        ERROR_SUCCESS || size != sizeof(RECT))
116     {
117         rc->top = 0;
118         rc->left = 0;
119         rc->bottom = 300;
120         rc->right = 600;
121     }
122
123     RegCloseKey(hKey);
124 }
125
126 void registry_read_maximized(DWORD *bMaximized)
127 {
128     HKEY hKey = 0;
129     DWORD size = sizeof(DWORD);
130
131     if(registry_get_handle(&hKey, 0, key_options) != ERROR_SUCCESS ||
132        RegQueryValueExW(hKey, var_maximized, 0, NULL, (LPBYTE)bMaximized, &size) !=
133        ERROR_SUCCESS || size != sizeof(DWORD))
134     {
135         *bMaximized = FALSE;
136     }
137
138     RegCloseKey(hKey);
139 }
140
141 static void truncate_path(LPWSTR file, LPWSTR out, LPWSTR pos1, LPWSTR pos2)
142 {
143     static const WCHAR dots[] = {'.','.','.',0};
144
145     *++pos1 = 0;
146
147     lstrcatW(out, file);
148     lstrcatW(out, dots);
149     lstrcatW(out, pos2);
150 }
151
152 static void format_filelist_filename(LPWSTR file, LPWSTR out)
153 {
154     LPWSTR pos_basename;
155     LPWSTR truncpos1, truncpos2;
156     WCHAR myDocs[MAX_STRING_LEN];
157
158     SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, (LPWSTR)&myDocs);
159     pos_basename = file_basename(file);
160     truncpos1 = NULL;
161     truncpos2 = NULL;
162
163     *(pos_basename-1) = 0;
164     if(!lstrcmpiW(file, myDocs) || (lstrlenW(pos_basename) > FILELIST_ENTRY_LENGTH))
165     {
166         truncpos1 = pos_basename;
167         *(pos_basename-1) = '\\';
168     } else
169     {
170         LPWSTR pos;
171         BOOL morespace = FALSE;
172
173         *(pos_basename-1) = '\\';
174
175         for(pos = file; pos < pos_basename; pos++)
176         {
177             if(*pos == '\\' || *pos == '/')
178             {
179                 if(truncpos1)
180                 {
181                     if((pos - file + lstrlenW(pos_basename)) > FILELIST_ENTRY_LENGTH)
182                         break;
183
184                     truncpos1 = pos;
185                     morespace = TRUE;
186                     break;
187                 }
188
189                 if((pos - file + lstrlenW(pos_basename)) > FILELIST_ENTRY_LENGTH)
190                     break;
191
192                 truncpos1 = pos;
193             }
194         }
195
196         if(morespace)
197         {
198             for(pos = pos_basename; pos >= truncpos1; pos--)
199             {
200                 if(*pos == '\\' || *pos == '/')
201                 {
202                     if((truncpos1 - file + lstrlenW(pos_basename) + pos_basename - pos) > FILELIST_ENTRY_LENGTH)
203                         break;
204
205                     truncpos2 = pos;
206                 }
207             }
208         }
209     }
210
211     if(truncpos1 == pos_basename)
212         lstrcatW(out, pos_basename);
213     else if(truncpos1 == truncpos2 || !truncpos2)
214         lstrcatW(out, file);
215     else
216         truncate_path(file, out, truncpos1, truncpos2);
217 }
218
219 void registry_read_filelist(HWND hMainWnd)
220 {
221     HKEY hFileKey;
222
223     if(registry_get_handle(&hFileKey, 0, key_recentfiles) == ERROR_SUCCESS)
224     {
225         WCHAR itemText[MAX_PATH+3], buffer[MAX_PATH];
226         /* The menu item name is not the same as the file name, so we need to store
227         the file name here */
228         static WCHAR file1[MAX_PATH], file2[MAX_PATH], file3[MAX_PATH], file4[MAX_PATH];
229         WCHAR numFormat[] = {'&','%','d',' ',0};
230         LPWSTR pFile[] = {file1, file2, file3, file4};
231         DWORD pathSize = MAX_PATH*sizeof(WCHAR);
232         int i;
233         WCHAR key[6];
234         MENUITEMINFOW mi;
235         HMENU hMenu = GetMenu(hMainWnd);
236
237         mi.cbSize = sizeof(MENUITEMINFOW);
238         mi.fMask = MIIM_ID | MIIM_DATA | MIIM_STRING | MIIM_FTYPE;
239         mi.fType = MFT_STRING;
240         mi.dwTypeData = itemText;
241         mi.wID = ID_FILE_RECENT1;
242
243         RemoveMenu(hMenu, ID_FILE_RECENT_SEPARATOR, MF_BYCOMMAND);
244         for(i = 0; i < FILELIST_ENTRIES; i++)
245         {
246             wsprintfW(key, var_file, i+1);
247             RemoveMenu(hMenu, ID_FILE_RECENT1+i, MF_BYCOMMAND);
248             if(RegQueryValueExW(hFileKey, (LPWSTR)key, 0, NULL, (LPBYTE)pFile[i], &pathSize)
249                != ERROR_SUCCESS)
250                 break;
251
252             mi.dwItemData = (ULONG_PTR)pFile[i];
253             wsprintfW(itemText, numFormat, i+1);
254
255             lstrcpyW(buffer, pFile[i]);
256
257             format_filelist_filename(buffer, itemText);
258
259             InsertMenuItemW(hMenu, ID_FILE_EXIT, FALSE, &mi);
260             mi.wID++;
261             pathSize = MAX_PATH*sizeof(WCHAR);
262         }
263         mi.fType = MFT_SEPARATOR;
264         mi.fMask = MIIM_FTYPE | MIIM_ID;
265         InsertMenuItemW(hMenu, ID_FILE_EXIT, FALSE, &mi);
266
267         RegCloseKey(hFileKey);
268     }
269 }
270
271 void registry_set_filelist(LPCWSTR newFile, HWND hMainWnd)
272 {
273     HKEY hKey;
274     DWORD action;
275
276     if(registry_get_handle(&hKey, &action, key_recentfiles) == ERROR_SUCCESS)
277     {
278         LPCWSTR pFiles[FILELIST_ENTRIES];
279         int i;
280         HMENU hMenu = GetMenu(hMainWnd);
281         MENUITEMINFOW mi;
282         WCHAR buffer[6];
283
284         mi.cbSize = sizeof(MENUITEMINFOW);
285         mi.fMask = MIIM_DATA;
286
287         for(i = 0; i < FILELIST_ENTRIES; i++)
288             pFiles[i] = NULL;
289
290         for(i = 0; GetMenuItemInfoW(hMenu, ID_FILE_RECENT1+i, FALSE, &mi); i++)
291             pFiles[i] = (LPWSTR)mi.dwItemData;
292
293         if(lstrcmpiW(newFile, pFiles[0]))
294         {
295             for(i = 0; pFiles[i] && i < FILELIST_ENTRIES; i++)
296             {
297                 if(!lstrcmpiW(pFiles[i], newFile))
298                 {
299                     int j;
300                     for(j = 0; pFiles[j] && j < i; j++)
301                     {
302                         pFiles[i-j] = pFiles[i-j-1];
303                     }
304                     pFiles[0] = NULL;
305                     break;
306                 }
307             }
308
309             if(!pFiles[0])
310             {
311                 pFiles[0] = newFile;
312             } else
313             {
314                 for(i = 0; i < FILELIST_ENTRIES-1; i++)
315                     pFiles[FILELIST_ENTRIES-1-i] = pFiles[FILELIST_ENTRIES-2-i];
316
317                 pFiles[0] = newFile;
318             }
319
320             for(i = 0; pFiles[i] && i < FILELIST_ENTRIES; i++)
321             {
322                 wsprintfW(buffer, var_file, i+1);
323                 RegSetValueExW(hKey, (LPWSTR)&buffer, 0, REG_SZ, (const BYTE*)pFiles[i],
324                                (lstrlenW(pFiles[i])+1)*sizeof(WCHAR));
325             }
326         }
327         RegCloseKey(hKey);
328     }
329     registry_read_filelist(hMainWnd);
330 }
331
332 int reg_formatindex(WPARAM format)
333 {
334     return (format & SF_TEXT) ? 1 : 0;
335 }
336
337 void registry_read_options(void)
338 {
339     HKEY hKey;
340
341     if(registry_get_handle(&hKey, 0, key_options) != ERROR_SUCCESS)
342         registry_read_pagemargins(NULL);
343     else
344     {
345         registry_read_pagemargins(hKey);
346         RegCloseKey(hKey);
347     }
348
349     if(registry_get_handle(&hKey, 0, key_settings) != ERROR_SUCCESS) {
350         registry_read_previewpages(NULL);
351     } else {
352         registry_read_previewpages(hKey);
353         RegCloseKey(hKey);
354     }
355 }
356
357 static void registry_read_formatopts(int index, LPCWSTR key, DWORD barState[], DWORD wordWrap[])
358 {
359     HKEY hKey;
360     DWORD action = 0;
361     BOOL fetched = FALSE;
362     barState[index] = 0;
363     wordWrap[index] = 0;
364
365     if(registry_get_handle(&hKey, &action, key) != ERROR_SUCCESS)
366         return;
367
368     if(action == REG_OPENED_EXISTING_KEY)
369     {
370         DWORD size = sizeof(DWORD);
371
372         if(RegQueryValueExW(hKey, var_barstate0, 0, NULL, (LPBYTE)&barState[index],
373            &size) == ERROR_SUCCESS)
374             fetched = TRUE;
375     }
376
377     if(!fetched)
378         barState[index] = (1 << BANDID_TOOLBAR) | (1 << BANDID_FORMATBAR) | (1 << BANDID_RULER) | (1 << BANDID_STATUSBAR);
379
380     if(index == reg_formatindex(SF_RTF))
381         wordWrap[index] = ID_WORDWRAP_WINDOW;
382     else if(index == reg_formatindex(SF_TEXT))
383         wordWrap[index] = ID_WORDWRAP_NONE;
384
385     RegCloseKey(hKey);
386 }
387
388 void registry_read_formatopts_all(DWORD barState[], DWORD wordWrap[])
389 {
390     registry_read_formatopts(reg_formatindex(SF_RTF), key_rtf, barState, wordWrap);
391     registry_read_formatopts(reg_formatindex(SF_TEXT), key_text, barState, wordWrap);
392 }
393
394 static void registry_set_formatopts(int index, LPCWSTR key, DWORD barState[])
395 {
396     HKEY hKey;
397     DWORD action = 0;
398
399     if(registry_get_handle(&hKey, &action, key) == ERROR_SUCCESS)
400     {
401         RegSetValueExW(hKey, var_barstate0, 0, REG_DWORD, (LPBYTE)&barState[index],
402                        sizeof(DWORD));
403
404         RegCloseKey(hKey);
405     }
406 }
407
408 void registry_set_formatopts_all(DWORD barState[])
409 {
410     registry_set_formatopts(reg_formatindex(SF_RTF), key_rtf, barState);
411     registry_set_formatopts(reg_formatindex(SF_TEXT), key_text, barState);
412 }