2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
7 #include "ProblemWindow.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>
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
;
49 Solution(BSolverProblem
* problem
, const BSolverProblemSolution
* 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
,
66 fClientWaiting(false),
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
)
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
)))
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
);
117 ProblemWindow::Go(BSolver
* solver
, const SolverPackageSet
& packagesAddedByUser
,
118 const SolverPackageSet
& packagesRemovedByUser
)
120 AutoLocker
<ProblemWindow
> locker(this);
122 fPackagesAddedByUser
= &packagesAddedByUser
;
123 fPackagesRemovedByUser
= &packagesRemovedByUser
;
126 _AddProblemsGui(solver
);
128 fCancelButton
->SetEnabled(true);
129 fRetryButton
->SetEnabled(false);
137 fClientWaiting
= true;
141 while (acquire_sem(fDoneSemaphore
) == B_INTERRUPTED
) {
148 if (!locker
.IsLocked() || !fAccepted
|| !_AnySolutionSelected())
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
,
160 throw BFatalErrorException(error
, "failed to set solution");
169 ProblemWindow::QuitRequested()
171 if (fClientWaiting
) {
172 fClientWaiting
= false;
173 release_sem(fDoneSemaphore
);
180 ProblemWindow::MessageReceived(BMessage
* message
)
182 switch (message
->what
) {
185 fClientWaiting
= false;
186 release_sem(fDoneSemaphore
);
189 fCancelButton
->SetEnabled(false);
190 fRetryButton
->SetEnabled(false);
192 fClientWaiting
= false;
193 release_sem(fDoneSemaphore
);
195 case kUpdateRetryButtonMessage
:
196 fRetryButton
->SetEnabled(_AnySolutionSelected());
199 BWindow::MessageReceived(message
);
206 ProblemWindow::_ClearProblemsGui()
210 int32 count
= fContainerView
->CountChildren();
211 for (int32 i
= count
- 1; i
>= 0; i
--) {
212 BView
* child
= fContainerView
->ChildAt(i
);
213 fContainerView
->RemoveChild(child
);
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);
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
);
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
);
282 ProblemWindow::_SolutionElementText(
283 const BSolverProblemSolutionElement
* element
) const
285 // Reword text for B_ALLOW_DEINSTALLATION, if the package has been added
287 BSolverPackage
* package
= element
->SourcePackage();
288 if (element
->Type() == BSolverProblemSolutionElement::B_ALLOW_DEINSTALLATION
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();
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
)