]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (c) 2005 Brian Dessent | |
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 Brian Dessent <brian@dessent.net> | |
13 | * | |
14 | */ | |
15 | ||
16 | #include "win32.h" | |
17 | #include <commctrl.h> | |
18 | #include <stdio.h> | |
19 | #include <io.h> | |
20 | #include <ctype.h> | |
21 | #include <process.h> | |
22 | #include <queue> | |
23 | ||
24 | #include "prereq.h" | |
25 | #include "dialog.h" | |
26 | #include "resource.h" | |
27 | #include "state.h" | |
28 | #include "propsheet.h" | |
29 | #include "threebar.h" | |
30 | #include "Generic.h" | |
31 | #include "LogSingleton.h" | |
32 | #include "ControlAdjuster.h" | |
33 | #include "package_db.h" | |
34 | #include "package_meta.h" | |
35 | #include "msg.h" | |
36 | #include "Exception.h" | |
37 | #include "getopt++/BoolOption.h" | |
38 | ||
39 | // Sizing information. | |
40 | static ControlAdjuster::ControlInfo PrereqControlsInfo[] = { | |
41 | {IDC_PREREQ_CHECK, CP_LEFT, CP_BOTTOM}, | |
42 | {IDC_PREREQ_EDIT, CP_STRETCH, CP_STRETCH}, | |
43 | {0, CP_LEFT, CP_TOP} | |
44 | }; | |
45 | ||
46 | extern ThreeBarProgressPage Progress; | |
47 | BoolOption IncludeSource (false, 'I', "include-source", "Automatically install source for every package installed"); | |
48 | ||
49 | // --------------------------------------------------------------------------- | |
50 | // implements class PrereqPage | |
51 | // --------------------------------------------------------------------------- | |
52 | ||
53 | PrereqPage::PrereqPage () | |
54 | { | |
55 | sizeProcessor.AddControlInfo (PrereqControlsInfo); | |
56 | } | |
57 | ||
58 | bool | |
59 | PrereqPage::Create () | |
60 | { | |
61 | return PropertyPage::Create (IDD_PREREQ); | |
62 | } | |
63 | ||
64 | void | |
65 | PrereqPage::OnInit () | |
66 | { | |
67 | // start with the checkbox set | |
68 | CheckDlgButton (GetHWND (), IDC_PREREQ_CHECK, BST_CHECKED); | |
69 | ||
70 | // set the edit-area to a larger font | |
71 | SetDlgItemFont(IDC_PREREQ_EDIT, "MS Shell Dlg", 10); | |
72 | } | |
73 | ||
74 | void | |
75 | PrereqPage::OnActivate() | |
76 | { | |
77 | // if we have gotten this far, then PrereqChecker has already run isMet | |
78 | // and found that there were problems; so we can just call | |
79 | // getUnmetString to format the results and display it | |
80 | ||
81 | std::string s; | |
82 | PrereqChecker p; | |
83 | p.getUnmetString (s); | |
84 | SetDlgItemText (GetHWND (), IDC_PREREQ_EDIT, s.c_str ()); | |
85 | ||
86 | SetFocus (GetDlgItem (IDC_PREREQ_CHECK)); | |
87 | } | |
88 | ||
89 | long | |
90 | PrereqPage::OnNext () | |
91 | { | |
92 | HWND h = GetHWND (); | |
93 | ||
94 | if (!IsDlgButtonChecked (h, IDC_PREREQ_CHECK)) | |
95 | { | |
96 | return -1; | |
97 | } | |
98 | ||
99 | return whatNext(); | |
100 | } | |
101 | ||
102 | long | |
103 | PrereqPage::whatNext () | |
104 | { | |
105 | if (source == IDC_SOURCE_LOCALDIR) | |
106 | { | |
107 | // Next, install | |
108 | Progress.SetActivateTask (WM_APP_START_INSTALL); | |
109 | } | |
110 | else | |
111 | { | |
112 | // Next, start download from internet | |
113 | Progress.SetActivateTask (WM_APP_START_DOWNLOAD); | |
114 | } | |
115 | return IDD_INSTATUS; | |
116 | } | |
117 | ||
118 | long | |
119 | PrereqPage::OnBack () | |
120 | { | |
121 | return IDD_CHOOSE; | |
122 | } | |
123 | ||
124 | long | |
125 | PrereqPage::OnUnattended () | |
126 | { | |
127 | // in chooser-only mode, show this page so the user can choose to fix dependency problems or not | |
128 | if (unattended_mode == chooseronly) | |
129 | return -1; | |
130 | ||
131 | return whatNext(); | |
132 | } | |
133 | ||
134 | bool | |
135 | PrereqPage::OnMessageCmd (int id, HWND hwndctl, UINT code) | |
136 | { | |
137 | if ((code == BN_CLICKED) && (id == IDC_PREREQ_CHECK)) | |
138 | { | |
139 | GetOwner ()->SetButtons (PSWIZB_BACK | (IsButtonChecked (id) ? PSWIZB_NEXT : 0)); | |
140 | return true; | |
141 | } | |
142 | ||
143 | return false; | |
144 | } | |
145 | ||
146 | // --------------------------------------------------------------------------- | |
147 | // implements class PrereqChecker | |
148 | // --------------------------------------------------------------------------- | |
149 | ||
150 | // instantiate the static members | |
151 | bool PrereqChecker::upgrade; | |
152 | bool PrereqChecker::use_test_packages; | |
153 | ||
154 | bool | |
155 | PrereqChecker::isMet () | |
156 | { | |
157 | packagedb db; | |
158 | ||
159 | Progress.SetText1 ("Solving dependencies..."); | |
160 | Progress.SetText2 (""); | |
161 | Progress.SetText3 (""); | |
162 | ||
163 | // go through all packages, adding changed ones to the solver task list | |
164 | SolverTasks q; | |
165 | ||
166 | for (packagedb::packagecollection::iterator p = db.packages.begin (); | |
167 | p != db.packages.end (); ++p) | |
168 | { | |
169 | packagemeta *pkg = p->second; | |
170 | ||
171 | // decode UI state to action | |
172 | // skip and keep don't change dependency solution | |
173 | if (pkg->installed != pkg->desired) | |
174 | { | |
175 | if (pkg->desired) | |
176 | q.add(pkg->desired, SolverTasks::taskInstall); // install/upgrade | |
177 | else | |
178 | q.add(pkg->installed, SolverTasks::taskUninstall); // uninstall | |
179 | } | |
180 | else | |
181 | if (pkg->picked()) | |
182 | q.add(pkg->installed, SolverTasks::taskReinstall); // reinstall | |
183 | ||
184 | // only install action makes sense for source packages | |
185 | if (pkg->srcpicked()) | |
186 | { | |
187 | if (pkg->desired) | |
188 | q.add(pkg->desired.sourcePackage(), SolverTasks::taskInstall); | |
189 | else | |
190 | q.add(pkg->installed.sourcePackage(), SolverTasks::taskInstall); | |
191 | } | |
192 | } | |
193 | ||
194 | // apply solver to those tasks and the chooser global state (keep, curr, test) | |
195 | return db.solution.update(q, upgrade, use_test_packages, IncludeSource); | |
196 | } | |
197 | ||
198 | /* Formats problems and solutions as a string for display to the user. */ | |
199 | void | |
200 | PrereqChecker::getUnmetString (std::string &s) | |
201 | { | |
202 | packagedb db; | |
203 | s = db.solution.report(); | |
204 | ||
205 | // | |
206 | size_t pos = 0; | |
207 | while ((pos = s.find("\n", pos)) != std::string::npos) | |
208 | { | |
209 | s.replace(pos, 1, "\r\n"); | |
210 | pos += 2; | |
211 | } | |
212 | } | |
213 | ||
214 | // --------------------------------------------------------------------------- | |
215 | // progress page glue | |
216 | // --------------------------------------------------------------------------- | |
217 | ||
218 | static int | |
219 | do_prereq_check_thread(HINSTANCE h, HWND owner) | |
220 | { | |
221 | PrereqChecker p; | |
222 | int retval; | |
223 | ||
224 | if (p.isMet ()) | |
225 | { | |
226 | if (source == IDC_SOURCE_LOCALDIR) | |
227 | Progress.SetActivateTask (WM_APP_START_INSTALL); // install | |
228 | else | |
229 | Progress.SetActivateTask (WM_APP_START_DOWNLOAD); // start download | |
230 | retval = IDD_INSTATUS; | |
231 | } | |
232 | else | |
233 | { | |
234 | // rut-roh, some required things are not selected | |
235 | retval = IDD_PREREQ; | |
236 | } | |
237 | ||
238 | return retval; | |
239 | } | |
240 | ||
241 | static DWORD WINAPI | |
242 | do_prereq_check_reflector (void *p) | |
243 | { | |
244 | HANDLE *context; | |
245 | context = (HANDLE *) p; | |
246 | ||
247 | try | |
248 | { | |
249 | int next_dialog = do_prereq_check_thread ((HINSTANCE) context[0], (HWND) context[1]); | |
250 | ||
251 | // Tell the progress page that we're done prereq checking | |
252 | Progress.PostMessageNow (WM_APP_PREREQ_CHECK_THREAD_COMPLETE, 0, next_dialog); | |
253 | } | |
254 | TOPLEVEL_CATCH((HWND) context[1], "prereq_check"); | |
255 | ||
256 | ExitThread(0); | |
257 | } | |
258 | ||
259 | static HANDLE context[2]; | |
260 | ||
261 | void | |
262 | do_prereq_check (HINSTANCE h, HWND owner) | |
263 | { | |
264 | context[0] = h; | |
265 | context[1] = owner; | |
266 | ||
267 | DWORD threadID; | |
268 | CreateThread (NULL, 0, do_prereq_check_reflector, context, 0, &threadID); | |
269 | } |