]> cygwin.com Git - cygwin-apps/setup.git/blame_incremental - proppage.cc
Use solver to check for problems and produce a list of package transactions
[cygwin-apps/setup.git] / proppage.cc
... / ...
CommitLineData
1/*
2 * Copyright (c) 2001, 2002, 2003 Gary R. Van Sickle.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Gary R. Van Sickle <g.r.vansickle@worldnet.att.net>
13 *
14 */
15
16// This is the implementation of the PropertyPage class. It works closely with the
17// PropSheet class to implement a single page of the property sheet.
18
19#include "proppage.h"
20#include "propsheet.h"
21#include "win32.h"
22#include <shellapi.h>
23#include "resource.h"
24#include "state.h"
25
26#include "getopt++/BoolOption.h"
27#include "Exception.h"
28#include "LogSingleton.h"
29
30bool PropertyPage::DoOnceForSheet = true;
31
32/*
33 Sizing information for some controls that are common to all pages.
34 */
35static ControlAdjuster::ControlInfo DefaultControlsInfo[] = {
36 {IDC_HEADICON, CP_RIGHT, CP_TOP},
37 {IDC_HEADSEPARATOR, CP_STRETCH, CP_TOP},
38 {0, CP_LEFT, CP_TOP}
39};
40
41PropertyPage::PropertyPage ()
42{
43 proc = NULL;
44 cmdproc = NULL;
45 IsFirst = false;
46 IsLast = false;
47
48 sizeProcessor.AddControlInfo (DefaultControlsInfo);
49}
50
51PropertyPage::~PropertyPage ()
52{
53}
54
55bool PropertyPage::Create (int TemplateID)
56{
57 return Create (NULL, NULL, TemplateID);
58}
59
60bool PropertyPage::Create (DLGPROC dlgproc, int TemplateID)
61{
62 return Create (dlgproc, NULL, TemplateID);
63}
64
65bool
66PropertyPage::Create (DLGPROC dlgproc,
67 BOOL (*cproc) (HWND h, int id, HWND hwndctl,
68 UINT code), int TemplateID)
69{
70 memset(&psp, 0, sizeof (PROPSHEETPAGE));
71 psp.dwSize = sizeof (PROPSHEETPAGE);
72 psp.dwFlags = 0;
73 psp.hInstance = GetInstance ();
74 psp.pfnDlgProc = FirstDialogProcReflector;
75 psp.pszTemplate = MAKEINTRESOURCE(TemplateID);
76 psp.lParam = (LPARAM) this;
77 psp.pfnCallback = NULL;
78
79 proc = dlgproc;
80 cmdproc = cproc;
81
82 return true;
83}
84
85INT_PTR CALLBACK
86PropertyPage::FirstDialogProcReflector (HWND hwnd, UINT message,
87 WPARAM wParam, LPARAM lParam)
88{
89 PropertyPage *This;
90
91 if (message != WM_INITDIALOG)
92 {
93 // Don't handle anything until we get a WM_INITDIALOG message, which
94 // will have our 'this' pointer with it.
95 return FALSE;
96 }
97
98 This = (PropertyPage *) (((PROPSHEETPAGE *) lParam)->lParam);
99
100 SetWindowLongPtr (hwnd, DWLP_USER, (LONG_PTR) This);
101 SetWindowLongPtr (hwnd, DWLP_DLGPROC, (LONG_PTR) DialogProcReflector);
102
103 This->SetHWND (hwnd);
104 return This->DialogProc (message, wParam, lParam);
105}
106
107INT_PTR CALLBACK
108PropertyPage::DialogProcReflector (HWND hwnd, UINT message, WPARAM wParam,
109 LPARAM lParam)
110{
111 PropertyPage *This;
112
113 This = (PropertyPage *) GetWindowLongPtr (hwnd, DWLP_USER);
114
115 return This->DialogProc (message, wParam, lParam);
116}
117
118INT_PTR CALLBACK
119PropertyPage::DialogProc (UINT message, WPARAM wParam, LPARAM lParam)
120{
121 try
122 {
123 if (proc != NULL)
124 {
125 proc (GetHWND (), message, wParam, lParam);
126 }
127
128 switch (message)
129 {
130 case WM_INITDIALOG:
131 {
132 OnInit ();
133
134 setTitleFont ();
135
136 // Call it here so it stores the initial client rect.
137 sizeProcessor.UpdateSize (GetHWND ());
138
139 // TRUE = Set focus to default control (in wParam).
140 return TRUE;
141 }
142 case WM_NOTIFY:
143 switch (((NMHDR FAR *) lParam)->code)
144 {
145 case PSN_APPLY:
146 {
147 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, PSNRET_NOERROR);
148 return TRUE;
149 }
150 case PSN_SETACTIVE:
151 {
152 if (DoOnceForSheet)
153 {
154 // Tell our parent PropSheet what its own HWND is.
155 GetOwner ()->SetHWNDFromPage (((NMHDR FAR *) lParam)->
156 hwndFrom);
157 GetOwner ()->CenterWindow ();
158 DoOnceForSheet = false;
159 }
160
161 GetOwner ()->AdjustPageSize (GetHWND ());
162
163 // Set the wizard buttons apropriately
164 if (IsFirst)
165 {
166 // Disable "Back" on first page.
167 GetOwner ()->SetButtons (PSWIZB_NEXT);
168 }
169 else if (IsLast)
170 {
171 // Disable "Next", enable "Finish" on last page
172 GetOwner ()->SetButtons (PSWIZB_BACK | PSWIZB_FINISH);
173 }
174 else
175 {
176 // Middle page, enable both "Next" and "Back" buttons
177 GetOwner ()->SetButtons (PSWIZB_BACK | PSWIZB_NEXT);
178 }
179
180 if(!wantsActivation())
181 {
182 ::SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, -1);
183 return TRUE;
184 }
185
186 OnActivate ();
187
188 if (unattended_mode)
189 {
190 // -2 == disable unattended mode, display page
191 // -1 == display page but stay in unattended mode (progress bars)
192 // 0 == skip to next page (in propsheet sequence)
193 // IDD_* == skip to specified page
194 long nextwindow = OnUnattended();
195 if (nextwindow == -2)
196 {
197 unattended_mode = attended;
198 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, 0);
199 return TRUE;
200 }
201 else if (nextwindow == -1)
202 {
203 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, 0);
204 return TRUE;
205 }
206 else if (nextwindow == 0)
207 {
208 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, -1);
209 return TRUE;
210 }
211 else
212 {
213 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, nextwindow);
214 return TRUE;
215 }
216 }
217 else
218 {
219 // 0 == Accept activation, -1 = Don't accept
220 ::SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, 0);
221 return TRUE;
222 }
223
224 }
225 break;
226 case PSN_KILLACTIVE:
227 {
228 OnDeactivate ();
229 // FALSE = Allow deactivation
230 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, FALSE);
231 return TRUE;
232 }
233 case PSN_WIZNEXT:
234 {
235 LONG retval;
236 retval = OnNext ();
237 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, retval);
238 return TRUE;
239 }
240 case PSN_WIZBACK:
241 {
242 LONG retval;
243 retval = OnBack ();
244 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, retval);
245 return TRUE;
246 }
247 case PSN_WIZFINISH:
248 {
249 OnFinish ();
250 // False = Allow the wizard to finish
251 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, FALSE);
252 return TRUE;
253 }
254 case TTN_GETDISPINFO:
255 {
256 return TooltipNotificationHandler (lParam);
257 }
258 default:
259 {
260 // Unrecognized notification
261 return FALSE;
262 }
263 }
264 break;
265 case WM_COMMAND:
266 {
267 bool retval;
268
269 retval =
270 OnMessageCmd (LOWORD (wParam), (HWND) lParam, HIWORD (wParam));
271 if (retval == true)
272 {
273 // Handled, return 0
274 SetWindowLongPtr (GetHWND (), DWLP_MSGRESULT, 0);
275 return TRUE;
276 }
277 else if (cmdproc != NULL)
278 {
279 cmdproc (GetHWND(), LOWORD(wParam), (HWND)lParam, HIWORD(wParam));
280 return 0;
281 }
282 break;
283 }
284 case WM_SIZE:
285 {
286 sizeProcessor.UpdateSize (GetHWND ());
287 break;
288 }
289 case WM_CTLCOLORSTATIC:
290 {
291 // check for text controls that we've url-ified that are initializing
292 int id;
293 std::map <int, ClickableURL>::iterator theURL;
294
295 // get the ID of the control, and look it up in our list
296 if ((id = GetDlgCtrlID ((HWND)lParam)) == 0 ||
297 (theURL = urls.find (id)) == urls.end ())
298
299 // nope sorry, don't know nothing about this control
300 return FALSE;
301
302 // set FG = blue, BG = default background for a dialog
303 SetTextColor ((HDC)wParam, RGB (0, 0, 255));
304 SetBkColor ((HDC)wParam, GetSysColor (COLOR_BTNFACE));
305
306 // get the current font, add underline, and set it back
307 if (theURL->second.font == 0)
308 {
309 TEXTMETRIC tm;
310
311 GetTextMetrics ((HDC)wParam, &tm);
312 LOGFONT lf;
313 memset ((void *)&lf, 0, sizeof(LOGFONT));
314 lf.lfUnderline = TRUE;
315 lf.lfHeight = tm.tmHeight;
316 lf.lfWeight = tm.tmWeight;
317 lf.lfItalic = tm.tmItalic;
318 lf.lfStrikeOut = tm.tmStruckOut;
319 lf.lfCharSet = tm.tmCharSet;
320 lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
321 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
322 lf.lfQuality = DEFAULT_QUALITY;
323 lf.lfPitchAndFamily = tm.tmPitchAndFamily;
324 GetTextFace ((HDC)wParam, LF_FACESIZE, lf.lfFaceName);
325 if ((theURL->second.font = CreateFontIndirect (&lf)) == NULL)
326 Log (LOG_PLAIN) << "Warning: unable to set font for url "
327 << theURL->second.url << endLog;
328 }
329
330 // apply the font
331 SelectObject ((HDC)wParam, theURL->second.font);
332
333 // make a brush if we have not yet
334 if (theURL->second.brush == NULL)
335 theURL->second.brush = CreateSolidBrush
336 (GetSysColor (COLOR_BTNFACE));
337
338 return (INT_PTR) theURL->second.brush;
339 }
340 case WM_MOUSEWHEEL:
341 // we do this so that derived classes that wish to process this message
342 // do not need to reimplement the entire WinProc, they can just
343 // provice an OnMouseWheel. (Note that mousewheel events are delivered
344 // to the parent of the window that received the scroll, so it would
345 // not work to just process this message there.)
346 return OnMouseWheel (message, wParam, lParam);
347
348 case WM_TIMER:
349 // similar delegation as with WM_MOUSEWHEEL
350 return OnTimerMessage (message, wParam, lParam);
351
352 default:
353 break;
354 }
355
356 if ((message >= WM_APP) && (message < 0xC000))
357 {
358 // It's a private app message
359 return OnMessageApp (message, wParam, lParam);
360 }
361 }
362 TOPLEVEL_CATCH(GetHWND (), "DialogProc");
363
364 // Wasn't handled
365 return FALSE;
366}
367
368INT_PTR CALLBACK
369PropertyPage::OnMouseWheel (UINT message, WPARAM wParam, LPARAM lParam)
370{
371 return 1; // not handled; define in a derived class to support this
372}
373
374INT_PTR CALLBACK
375PropertyPage::OnTimerMessage (UINT message, WPARAM wParam, LPARAM lParam)
376{
377 return 1; // not handled; define in a derived class to support this
378}
379
380void
381PropertyPage::setTitleFont ()
382{
383 // These font settings will just silently fail when the resource id
384 // is not present on a page.
385 // Set header title font of each internal page
386 SetDlgItemFont(IDC_STATIC_HEADER_TITLE, "MS Shell Dlg", 8, FW_BOLD);
387 // Set the font for the IDC_STATIC_WELCOME_TITLE
388 SetDlgItemFont(IDC_STATIC_WELCOME_TITLE, "Arial", 12, FW_BOLD);
389}
390
391std::map <int, PropertyPage::ClickableURL> PropertyPage::urls;
392
393void
394PropertyPage::makeClickable (int id, std::string link)
395// turns a static text control in this dialog into a hyperlink
396{
397 // get the handle of the specified control
398 HWND hctl = ::GetDlgItem (GetHWND (), id);
399 if (hctl == NULL)
400 return; // invalid ID
401
402 if (urls.find (id) != urls.end ())
403 return; // already done this one
404
405 ClickableURL c;
406 c.url = link;
407 c.font = NULL; // these will be created as needed
408 c.brush = NULL;
409 if ((c.origWinProc = reinterpret_cast<WNDPROC>(SetWindowLongPtr (hctl,
410 GWLP_WNDPROC, (LONG_PTR) & PropertyPage::urlWinProc))) == 0)
411 return; // failure
412
413 // add this to 'urls' so that the dialog and control winprocs know about it
414 urls[id] = c;
415
416 // set a tooltip for the link
417 AddTooltip (id, link.c_str());
418}
419
420LRESULT CALLBACK
421PropertyPage::urlWinProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
422// a winproc that we use to subclass a static text control to make a URL
423{
424 int id;
425 std::map <int, ClickableURL>::iterator theURL;
426
427 // get the ID of the control, and look it up in our list
428 if ((id = GetDlgCtrlID (hwnd)) == 0 ||
429 (theURL = urls.find (id)) == urls.end ())
430
431 // we were called for a control that we weren't installed on
432 // punt to default winproc
433 return DefWindowProc (hwnd, uMsg, wParam, lParam);
434
435 switch (uMsg)
436 {
437 case WM_LBUTTONDOWN:
438 {
439 // they clicked our URL! yay!
440 intptr_t rc = (intptr_t) ShellExecute (hwnd, "open",
441 theURL->second.url.c_str (), NULL, NULL, SW_SHOWNORMAL);
442
443 if (rc <= 32)
444 Log (LOG_PLAIN) << "Unable to launch browser for URL " <<
445 theURL->second.url << " (rc = " << rc << ")" << endLog;
446 break;
447 }
448 case WM_SETCURSOR:
449 {
450 // show the hand cursor when they hover
451 // note: apparently the hand cursor isn't available
452 // on very old versions of win95? So, check return of LoadCursor
453 // and don't attempt SetCursor if it failed
454 HCURSOR c = LoadCursor (NULL, reinterpret_cast<LPCSTR>(IDC_HAND));
455 if (c)
456 SetCursor (c);
457 return TRUE;
458 }
459 case WM_NCHITTEST:
460 {
461 // normally, a static control returns HTTRANSPARENT for this
462 // which means that we would never receive the SETCURSOR message
463 return HTCLIENT;
464 }
465 case WM_DESTROY:
466 {
467 // clean up
468 WNDPROC saveWinProc = theURL->second.origWinProc;
469 DeleteObject (theURL->second.font);
470 DeleteObject (theURL->second.brush);
471 urls.erase (id);
472 return CallWindowProc (saveWinProc, hwnd, uMsg, wParam, lParam);
473 }
474 }
475
476 // pass on control to the previous winproc
477 return CallWindowProc (theURL->second.origWinProc, hwnd, uMsg, wParam, lParam);
478}
This page took 0.030089 seconds and 5 git commands to generate.