btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / servers / package / ProblemWindow.cpp
blobbc86d24f84f9f22afa7d6fa18a9f78f9b99f3a44
1 /*
2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "ProblemWindow.h"
9 #include <Button.h>
10 #include <Catalog.h>
11 #include <GroupView.h>
12 #include <LayoutBuilder.h>
13 #include <RadioButton.h>
14 #include <ScrollView.h>
15 #include <StringView.h>
16 #include <package/solver/Solver.h>
17 #include <package/solver/SolverPackage.h>
18 #include <package/solver/SolverProblem.h>
19 #include <package/solver/SolverProblemSolution.h>
21 #include <AutoLocker.h>
22 #include <package/manager/Exceptions.h>
23 #include <ViewPort.h>
26 #undef B_TRANSLATION_CONTEXT
27 #define B_TRANSLATION_CONTEXT "PackageProblem"
29 using namespace BPackageKit;
31 using BPackageKit::BManager::BPrivate::BFatalErrorException;
34 static const uint32 kRetryMessage = 'rtry';
35 static const uint32 kUpdateRetryButtonMessage = 'uprt';
38 struct ProblemWindow::Solution {
39 BSolverProblem* fProblem;
40 const BSolverProblemSolution* fSolution;
42 Solution()
44 fProblem(NULL),
45 fSolution(NULL)
49 Solution(BSolverProblem* problem, const BSolverProblemSolution* solution)
51 fProblem(problem),
52 fSolution(solution)
58 ProblemWindow::ProblemWindow()
60 BWindow(BRect(0, 0, 400, 300), B_TRANSLATE_COMMENT("Package problems",
61 "Window title"), B_TITLED_WINDOW_LOOK,
62 B_MODAL_APP_WINDOW_FEEL,
63 B_ASYNCHRONOUS_CONTROLS | B_NOT_MINIMIZABLE | B_AUTO_UPDATE_SIZE_LIMITS,
64 B_ALL_WORKSPACES),
65 fDoneSemaphore(-1),
66 fClientWaiting(false),
67 fAccepted(false),
68 fContainerView(NULL),
69 fCancelButton(NULL),
70 fRetryButton(NULL),
71 fSolutions(),
72 fPackagesAddedByUser(NULL),
73 fPackagesRemovedByUser(NULL)
76 fDoneSemaphore = create_sem(0, "package problems");
77 if (fDoneSemaphore < 0)
78 throw std::bad_alloc();
80 BStringView* topTextView = NULL;
81 BViewPort* viewPort = NULL;
83 BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING)
84 .SetInsets(B_USE_SMALL_INSETS)
85 .Add(topTextView = new BStringView(NULL, B_TRANSLATE(
86 "The following problems have been encountered. Please select "
87 "a solution for each:")))
88 .Add(new BScrollView(NULL, viewPort = new BViewPort(), 0, false, true))
89 .AddGroup(B_HORIZONTAL)
90 .AddGlue()
91 .Add(fCancelButton = new BButton(B_TRANSLATE("Cancel"),
92 new BMessage(B_CANCEL)))
93 .Add(fRetryButton = new BButton(B_TRANSLATE("Retry"),
94 new BMessage(kRetryMessage)))
95 .End();
97 topTextView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
99 viewPort->SetChildView(fContainerView = new BGroupView(B_VERTICAL, 0));
101 // set small scroll step (large step will be set by the view port)
102 font_height fontHeight;
103 topTextView->GetFontHeight(&fontHeight);
104 float smallStep = ceilf(fontHeight.ascent + fontHeight.descent);
105 viewPort->ScrollBar(B_VERTICAL)->SetSteps(smallStep, smallStep);
109 ProblemWindow::~ProblemWindow()
111 if (fDoneSemaphore >= 0)
112 delete_sem(fDoneSemaphore);
116 bool
117 ProblemWindow::Go(BSolver* solver, const SolverPackageSet& packagesAddedByUser,
118 const SolverPackageSet& packagesRemovedByUser)
120 AutoLocker<ProblemWindow> locker(this);
122 fPackagesAddedByUser = &packagesAddedByUser;
123 fPackagesRemovedByUser = &packagesRemovedByUser;
125 _ClearProblemsGui();
126 _AddProblemsGui(solver);
128 fCancelButton->SetEnabled(true);
129 fRetryButton->SetEnabled(false);
131 if (IsHidden()) {
132 CenterOnScreen();
133 Show();
136 fAccepted = false;
137 fClientWaiting = true;
139 locker.Unlock();
141 while (acquire_sem(fDoneSemaphore) == B_INTERRUPTED) {
144 locker.Lock();
146 Hide();
148 if (!locker.IsLocked() || !fAccepted || !_AnySolutionSelected())
149 return false;
151 // set the solutions
152 for (SolutionMap::const_iterator it = fSolutions.begin();
153 it != fSolutions.end(); ++it) {
154 BRadioButton* button = it->first;
155 if (button->Value() == B_CONTROL_ON) {
156 const Solution& solution = it->second;
157 status_t error = solver->SelectProblemSolution(solution.fProblem,
158 solution.fSolution);
159 if (error != B_OK)
160 throw BFatalErrorException(error, "failed to set solution");
164 return true;
168 bool
169 ProblemWindow::QuitRequested()
171 if (fClientWaiting) {
172 fClientWaiting = false;
173 release_sem(fDoneSemaphore);
175 return true;
179 void
180 ProblemWindow::MessageReceived(BMessage* message)
182 switch (message->what) {
183 case B_CANCEL:
184 Hide();
185 fClientWaiting = false;
186 release_sem(fDoneSemaphore);
187 break;
188 case kRetryMessage:
189 fCancelButton->SetEnabled(false);
190 fRetryButton->SetEnabled(false);
191 fAccepted = true;
192 fClientWaiting = false;
193 release_sem(fDoneSemaphore);
194 break;
195 case kUpdateRetryButtonMessage:
196 fRetryButton->SetEnabled(_AnySolutionSelected());
197 break;
198 default:
199 BWindow::MessageReceived(message);
200 break;
205 void
206 ProblemWindow::_ClearProblemsGui()
208 fSolutions.clear();
210 int32 count = fContainerView->CountChildren();
211 for (int32 i = count - 1; i >= 0; i--) {
212 BView* child = fContainerView->ChildAt(i);
213 fContainerView->RemoveChild(child);
214 delete child;
219 void
220 ProblemWindow::_AddProblemsGui(BSolver* solver)
222 int32 problemCount = solver->CountProblems();
223 for (int32 i = 0; i < problemCount; i++) {
224 _AddProblem(solver->ProblemAt(i),
225 (i & 1) == 0 ? B_NO_TINT : 1.04);
230 void
231 ProblemWindow::_AddProblem(BSolverProblem* problem,
232 const float backgroundTint)
234 BGroupView* problemGroup = new BGroupView(B_VERTICAL);
235 fContainerView->AddChild(problemGroup);
236 problemGroup->GroupLayout()->SetInsets(B_USE_SMALL_INSETS);
237 problemGroup->SetViewUIColor(B_LIST_BACKGROUND_COLOR, backgroundTint);
239 BStringView* problemView = new BStringView(NULL, problem->ToString());
240 problemGroup->AddChild(problemView);
241 BFont problemFont;
242 problemView->GetFont(&problemFont);
243 problemFont.SetFace(B_BOLD_FACE);
244 problemView->SetFont(&problemFont);
245 problemView->AdoptParentColors();
247 int32 solutionCount = problem->CountSolutions();
248 for (int k = 0; k < solutionCount; k++) {
249 const BSolverProblemSolution* solution = problem->SolutionAt(k);
250 BRadioButton* solutionButton = new BRadioButton(
251 BString().SetToFormat(B_TRANSLATE_COMMENT("solution %d:",
252 "Don't change the %d variable"), k + 1),
253 new BMessage(kUpdateRetryButtonMessage));
254 problemGroup->AddChild(solutionButton);
256 BGroupLayout* elementsGroup = new BGroupLayout(B_VERTICAL);
257 problemGroup->AddChild(elementsGroup);
258 elementsGroup->SetInsets(20, 0, 0, 0);
260 int32 elementCount = solution->CountElements();
261 for (int32 l = 0; l < elementCount; l++) {
262 const BSolverProblemSolutionElement* element
263 = solution->ElementAt(l);
264 BStringView* elementView = new BStringView(NULL,
265 BString().SetToFormat("- %s",
266 _SolutionElementText(element).String()));
267 elementsGroup->AddView(elementView);
268 elementView->AdoptParentColors();
271 fSolutions[solutionButton] = Solution(problem, solution);
274 BRadioButton* ignoreButton = new BRadioButton(B_TRANSLATE(
275 "ignore problem for now"), new BMessage(kUpdateRetryButtonMessage));
276 problemGroup->AddChild(ignoreButton);
277 ignoreButton->SetValue(B_CONTROL_ON);
281 BString
282 ProblemWindow::_SolutionElementText(
283 const BSolverProblemSolutionElement* element) const
285 // Reword text for B_ALLOW_DEINSTALLATION, if the package has been added
286 // by the user.
287 BSolverPackage* package = element->SourcePackage();
288 if (element->Type() == BSolverProblemSolutionElement::B_ALLOW_DEINSTALLATION
289 && package != NULL
290 && fPackagesAddedByUser->find(package) != fPackagesAddedByUser->end()) {
291 return BString(B_TRANSLATE_COMMENT("don't activate package %source%",
292 "don't change '%source%")).ReplaceAll(
293 "%source%", package->VersionedName());
296 return element->ToString();
300 bool
301 ProblemWindow::_AnySolutionSelected() const
303 for (SolutionMap::const_iterator it = fSolutions.begin();
304 it != fSolutions.end(); ++it) {
305 BRadioButton* button = it->first;
306 if (button->Value() == B_CONTROL_ON)
307 return true;
310 return false;