1/*
2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "ResultWindow.h"
8
9#include <Button.h>
10#include <Catalog.h>
11#include <GroupView.h>
12#include <LayoutBuilder.h>
13#include <ScrollView.h>
14#include <StringView.h>
15#include <package/solver/SolverPackage.h>
16#include <package/solver/SolverRepository.h>
17
18#include <AutoDeleter.h>
19#include <AutoLocker.h>
20#include <ViewPort.h>
21
22
23#undef B_TRANSLATION_CONTEXT
24#define B_TRANSLATION_CONTEXT "PackageResult"
25
26using namespace BPackageKit;
27
28
29static const uint32 kApplyMessage = 'rtry';
30
31
32ResultWindow::ResultWindow()
33	:
34	BWindow(BRect(0, 0, 400, 300), B_TRANSLATE_COMMENT("Package changes",
35			"Window title"), B_TITLED_WINDOW_LOOK,
36		B_NORMAL_WINDOW_FEEL,
37		B_ASYNCHRONOUS_CONTROLS | B_NOT_MINIMIZABLE | B_AUTO_UPDATE_SIZE_LIMITS,
38		B_ALL_WORKSPACES),
39	fDoneSemaphore(-1),
40	fClientWaiting(false),
41	fAccepted(false),
42	fContainerView(NULL),
43	fCancelButton(NULL),
44	fApplyButton(NULL)
45
46{
47	fDoneSemaphore = create_sem(0, "package changes");
48	if (fDoneSemaphore < 0)
49		throw std::bad_alloc();
50
51	BStringView* topTextView = NULL;
52	BViewPort* viewPort = NULL;
53
54	BLayoutBuilder::Group<>(this, B_VERTICAL, B_USE_DEFAULT_SPACING)
55		.SetInsets(B_USE_SMALL_INSETS)
56		.Add(topTextView = new BStringView(NULL, B_TRANSLATE(
57				"The following additional package changes have to be made:")))
58		.Add(new BScrollView(NULL, viewPort = new BViewPort(), 0, false, true))
59		.AddGroup(B_HORIZONTAL)
60			.Add(fCancelButton = new BButton(B_TRANSLATE("Cancel"),
61				new BMessage(B_CANCEL)))
62			.AddGlue()
63			.Add(fApplyButton = new BButton(B_TRANSLATE("Apply changes"),
64				new BMessage(kApplyMessage)))
65		.End();
66
67	topTextView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
68
69	viewPort->SetChildView(fContainerView = new BGroupView(B_VERTICAL, 0));
70
71	// set small scroll step (large step will be set by the view port)
72	font_height fontHeight;
73	topTextView->GetFontHeight(&fontHeight);
74	float smallStep = ceilf(fontHeight.ascent + fontHeight.descent);
75	viewPort->ScrollBar(B_VERTICAL)->SetSteps(smallStep, smallStep);
76}
77
78
79ResultWindow::~ResultWindow()
80{
81	if (fDoneSemaphore >= 0)
82		delete_sem(fDoneSemaphore);
83}
84
85
86bool
87ResultWindow::AddLocationChanges(const char* location,
88	const PackageList& packagesToInstall,
89	const PackageSet& packagesAlreadyAdded,
90	const PackageList& packagesToUninstall,
91	const PackageSet& packagesAlreadyRemoved)
92{
93	BGroupView* locationGroup = new BGroupView(B_VERTICAL);
94	ObjectDeleter<BGroupView> locationGroupDeleter(locationGroup);
95
96	locationGroup->GroupLayout()->SetInsets(B_USE_SMALL_INSETS);
97
98	float backgroundTint = B_NO_TINT;
99	if ((fContainerView->CountChildren() & 1) != 0)
100		backgroundTint = 1.04;
101	locationGroup->SetViewUIColor(B_LIST_BACKGROUND_COLOR, backgroundTint);
102
103	BStringView* locationView = new BStringView(NULL,
104		BString().SetToFormat("in %s:", location));
105	locationGroup->AddChild(locationView);
106	locationView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
107	locationView->AdoptParentColors();
108	BFont locationFont;
109	locationView->GetFont(&locationFont);
110	locationFont.SetFace(B_BOLD_FACE);
111	locationView->SetFont(&locationFont);
112
113	BGroupLayout* packagesGroup = new BGroupLayout(B_VERTICAL);
114	locationGroup->GroupLayout()->AddItem(packagesGroup);
115	packagesGroup->SetInsets(20, 0, 0, 0);
116
117	bool packagesAdded = _AddPackages(packagesGroup, packagesToInstall,
118		packagesAlreadyAdded, true);
119	packagesAdded |= _AddPackages(packagesGroup, packagesToUninstall,
120		packagesAlreadyRemoved, false);
121
122	if (!packagesAdded)
123		return false;
124
125	fContainerView->AddChild(locationGroup);
126	locationGroupDeleter.Detach();
127
128	return true;
129}
130
131
132bool
133ResultWindow::Go()
134{
135	AutoLocker<ResultWindow> locker(this);
136
137	CenterOnScreen();
138	Show();
139
140	fAccepted = false;
141	fClientWaiting = true;
142
143	locker.Unlock();
144
145	while (acquire_sem(fDoneSemaphore) == B_INTERRUPTED) {
146	}
147
148	locker.Lock();
149	bool result = false;
150	if (locker.IsLocked()) {
151		result = fAccepted;
152		Quit();
153		locker.Detach();
154	} else
155		PostMessage(B_QUIT_REQUESTED);
156
157	return result;
158}
159
160
161bool
162ResultWindow::QuitRequested()
163{
164	if (fClientWaiting) {
165		Hide();
166		fClientWaiting = false;
167		release_sem(fDoneSemaphore);
168		return false;
169	}
170
171	return true;
172}
173
174
175void
176ResultWindow::MessageReceived(BMessage* message)
177{
178	switch (message->what) {
179		case B_CANCEL:
180		case kApplyMessage:
181			Hide();
182			fAccepted = message->what == kApplyMessage;
183			fClientWaiting = false;
184			release_sem(fDoneSemaphore);
185			break;
186		default:
187			BWindow::MessageReceived(message);
188			break;
189	}
190}
191
192
193bool
194ResultWindow::_AddPackages(BGroupLayout* packagesGroup,
195	const PackageList& packages, const PackageSet& ignorePackages, bool install)
196{
197	bool packagesAdded = false;
198
199	for (int32 i = 0; BSolverPackage* package = packages.ItemAt(i);
200		i++) {
201		if (ignorePackages.find(package) != ignorePackages.end())
202			continue;
203
204		BString text;
205		if (install) {
206			text.SetToFormat(B_TRANSLATE_COMMENT("install package %s from "
207					"repository %s\n", "Don't change '%s' variables"),
208				package->Info().FileName().String(),
209				package->Repository()->Name().String());
210		} else {
211			text.SetToFormat(B_TRANSLATE_COMMENT("uninstall package %s\n",
212					"Don't change '%s' variable"),
213				package->VersionedName().String());
214		}
215
216		BStringView* packageView = new BStringView(NULL, text);
217		packagesGroup->AddView(packageView);
218		packageView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, B_SIZE_UNSET));
219		packageView->AdoptParentColors();
220
221		packagesAdded = true;
222	}
223
224	return packagesAdded;
225}
226