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