BTRFS: Implement BTree::Path and change _Find.
[haiku.git] / src / apps / packageinstaller / UninstallView.cpp
blob35c021710847523a0d53a4a8be3096ffa8287ad9
1 /*
2 * Copyright (c) 2007-2010, Haiku, Inc.
3 * Distributed under the terms of the MIT license.
5 * Author:
6 * Ɓukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
7 */
10 #include "UninstallView.h"
12 #include <stdio.h>
13 #include <string.h>
15 #include <Alert.h>
16 #include <Box.h>
17 #include <Button.h>
18 #include <Catalog.h>
19 #include <ControlLook.h>
20 #include <Directory.h>
21 #include <Entry.h>
22 #include <File.h>
23 #include <FilePanel.h>
24 #include <FindDirectory.h>
25 #include <LayoutBuilder.h>
26 #include <ListView.h>
27 #include <Locale.h>
28 #include <NodeMonitor.h>
29 #include <ScrollView.h>
30 #include <SeparatorView.h>
31 #include <String.h>
32 #include <StringView.h>
33 #include <SpaceLayoutItem.h>
34 #include <TextView.h>
36 #include "main.h"
39 #undef B_TRANSLATION_CONTEXT
40 #define B_TRANSLATION_CONTEXT "UninstallView"
43 enum {
44 P_MSG_INSTALL = 'umin',
45 P_MSG_REMOVE = 'umrm',
46 P_MSG_SELECT
50 // TODO list:
51 // - B_ENTRY_MOVED
52 // - Right now the installed package info naming convention is the same
53 // as at SoftwareValet. Maybe there would be a better one?
54 // - Add a status window (reuse the one from PackageInstall)
57 class UninstallView::InfoItem : public BStringItem {
58 public:
59 InfoItem(const BString& name, const BString& version,
60 const char* filename, const node_ref& ref)
62 BStringItem(name.String()),
63 fName(name),
64 fVersion(version),
65 fNodeRef(ref)
67 if (fName.Length() == 0)
68 SetText(filename);
71 const char* GetName() { return fName.String(); }
72 const char* GetVersion() { return fVersion.String(); };
73 node_ref GetNodeRef() { return fNodeRef; };
75 private:
76 BString fName;
77 BString fVersion;
78 node_ref fNodeRef;
84 UninstallView::UninstallView()
86 BGroupView(B_VERTICAL),
87 fOpenPanel(new BFilePanel(B_OPEN_PANEL))
89 fNoPackageSelectedString = B_TRANSLATE("No package selected.");
90 _InitView();
94 UninstallView::~UninstallView()
96 // Stop all node watching
97 stop_watching(this);
101 void
102 UninstallView::AttachedToWindow()
104 fAppList->SetTarget(this);
105 fInstallButton->SetTarget(this);
106 fRemoveButton->SetTarget(this);
108 _ReloadAppList();
110 // We loaded the list, but now let's set up a node watcher for the packages
111 // directory, so that we can update the list of installed packages in real
112 // time
113 _CachePathToPackages();
114 node_ref ref;
115 fWatcherRunning = false;
116 BDirectory dir(fToPackages.Path());
117 if (dir.InitCheck() != B_OK) {
118 // The packages/ directory obviously does not exist.
119 // Since this is the case, we need to watch for it to appear first
121 BPath path;
122 fToPackages.GetParent(&path);
123 if (dir.SetTo(path.Path()) != B_OK)
124 return;
125 } else
126 fWatcherRunning = true;
128 dir.GetNodeRef(&ref);
130 if (watch_node(&ref, B_WATCH_DIRECTORY, this) != B_OK) {
131 fWatcherRunning = false;
132 return;
137 void
138 UninstallView::MessageReceived(BMessage* msg)
140 switch (msg->what) {
141 case B_NODE_MONITOR:
143 int32 opcode;
144 if (msg->FindInt32("opcode", &opcode) != B_OK)
145 break;
147 fprintf(stderr, "Got an opcoded node monitor message\n");
148 if (opcode == B_ENTRY_CREATED) {
149 fprintf(stderr, "Created?...\n");
150 BString filename, name, version;
151 node_ref ref;
152 if (msg->FindString("name", &filename) != B_OK
153 || msg->FindInt32("device", &ref.device) != B_OK
154 || msg->FindInt64("node", &ref.node) != B_OK)
155 break;
157 // TODO: This obviously is a hack
158 // The node watcher informs the view a bit to early, and
159 // because of this the data of the node is not ready at this
160 // moment. For this reason, we must give the filesystem some
161 // time before continuing.
162 usleep(10000);
164 if (fWatcherRunning) {
165 _AddFile(filename.String(), ref);
166 } else {
167 // This most likely means we were waiting for
168 // the packages/ dir to appear
169 if (filename == "packages") {
170 if (watch_node(&ref, B_WATCH_DIRECTORY, this) == B_OK)
171 fWatcherRunning = true;
174 } else if (opcode == B_ENTRY_REMOVED) {
175 node_ref ref;
176 if (msg->FindInt32("device", &ref.device) != B_OK
177 || msg->FindInt64("node", &ref.node) != B_OK)
178 break;
180 int32 i, count = fAppList->CountItems();
181 InfoItem* iter;
182 for (i = 0; i < count; i++) {
183 iter = static_cast<InfoItem *>(fAppList->ItemAt(i));
184 if (iter->GetNodeRef() == ref) {
185 if (i == fAppList->CurrentSelection())
186 fDescription->SetText(fNoPackageSelectedString);
187 fAppList->RemoveItem(i);
188 delete iter;
191 } else if (opcode == B_ENTRY_MOVED) {
192 ino_t from, to;
193 if (msg->FindInt64("from directory", &from) != B_OK
194 || msg->FindInt64("to directory", &to) != B_OK)
195 break;
197 BDirectory packagesDir(fToPackages.Path());
198 node_ref ref;
199 packagesDir.GetNodeRef(&ref);
201 if (ref.node == to) {
202 // Package added
203 // TODO
204 } else if (ref.node == from) {
205 // Package removed
206 // TODO
209 break;
211 case P_MSG_SELECT:
213 fRemoveButton->SetEnabled(false);
214 fDescription->SetText(fNoPackageSelectedString);
216 int32 index = fAppList->CurrentSelection();
217 if (index < 0)
218 break;
220 fprintf(stderr, "Another debug message...\n");
222 InfoItem* item = dynamic_cast<InfoItem*>(fAppList->ItemAt(index));
223 if (!item)
224 break;
226 fprintf(stderr, "Uh: %s and %s\n", item->GetName(),
227 item->GetVersion());
229 if (fCurrentSelection.SetTo(item->GetName(),
230 item->GetVersion()) != B_OK)
231 break;
233 fRemoveButton->SetEnabled(true);
234 fDescription->SetText(fCurrentSelection.Description());
235 break;
237 case P_MSG_INSTALL:
239 fOpenPanel->Show();
240 break;
242 case P_MSG_REMOVE:
244 if (fCurrentSelection.InitCheck() != B_OK)
245 break;
247 int32 index = fAppList->CurrentSelection();
248 if (index < 0)
249 break;
251 BAlert* notify;
252 if (fCurrentSelection.Uninstall() == B_OK) {
253 BListItem* item = fAppList->RemoveItem(index);
254 delete item;
256 fDescription->SetText(fNoPackageSelectedString);
258 notify = new BAlert("removal_success",
259 B_TRANSLATE("The package you selected has been "
260 "successfully removed from your system."),
261 B_TRANSLATE("OK"));
262 } else {
263 notify = new BAlert("removal_failed",
264 B_TRANSLATE(
265 "The selected package was not removed from your system. "
266 "The given installed package information file might have "
267 "been corrupted."), B_TRANSLATE("OK"), NULL,
268 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
270 notify->SetFlags(notify->Flags() | B_CLOSE_ON_ESCAPE);
271 notify->Go();
272 break;
274 default:
275 BView::MessageReceived(msg);
276 break;
281 void
282 UninstallView::RefsReceived(BMessage* message)
284 static_cast<PackageInstaller*>(be_app)->RefsReceived(message);
288 void
289 UninstallView::_InitView()
291 SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
293 fAppList = new BListView("pkg_list", B_SINGLE_SELECTION_LIST);
294 fAppList->SetSelectionMessage(new BMessage(P_MSG_SELECT));
295 BScrollView* scrollView = new BScrollView("list_scroll", fAppList,
296 0, false, true, B_NO_BORDER);
298 BStringView* descriptionLabel = new BStringView("desc_label",
299 B_TRANSLATE("Package description"));
300 descriptionLabel->SetFont(be_bold_font);
302 fDescription = new BTextView("description", B_WILL_DRAW);
303 fDescription->MakeSelectable(false);
304 fDescription->MakeEditable(false);
305 fDescription->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
306 fDescription->SetText(fNoPackageSelectedString);
308 fInstallButton = new BButton("install", B_TRANSLATE("Install" B_UTF8_ELLIPSIS),
309 new BMessage(P_MSG_INSTALL));
310 fRemoveButton = new BButton("removal", B_TRANSLATE("Remove"),
311 new BMessage(P_MSG_REMOVE));
312 fRemoveButton->SetEnabled(false);
314 const float spacing = be_control_look->DefaultItemSpacing();
316 BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
317 .Add(scrollView, 10)
318 .Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER))
319 .AddGroup(B_VERTICAL)
320 .SetInsets(spacing)
321 .AddGroup(B_HORIZONTAL, 0)
322 .Add(descriptionLabel)
323 .AddGlue()
324 .End()
325 .AddGroup(B_HORIZONTAL, 0)
326 .Add(BSpaceLayoutItem::CreateHorizontalStrut(10))
327 .Add(fDescription)
328 .End()
329 .End()
330 .Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER))
331 .AddGroup(B_HORIZONTAL)
332 .SetInsets(spacing)
333 .AddGlue()
334 .Add(fInstallButton)
335 .Add(fRemoveButton)
336 .End()
337 .End();
341 status_t
342 UninstallView::_ReloadAppList()
344 _ClearAppList();
346 if (fToPackages.InitCheck() != B_OK)
347 _CachePathToPackages();
349 BDirectory dir(fToPackages.Path());
350 status_t ret = dir.InitCheck();
351 if (ret != B_OK)
352 return ret;
354 BEntry iter;
355 while (dir.GetNextEntry(&iter) == B_OK) {
356 char filename[B_FILE_NAME_LENGTH];
357 if (iter.GetName(filename) != B_OK)
358 continue;
360 node_ref ref;
361 if (iter.GetNodeRef(&ref) != B_OK)
362 continue;
364 BString filenameString(filename);
365 if (!filenameString.IEndsWith(".pdb")) {
366 printf("Ignoring non-package '%s'\n", filename);
367 continue;
370 printf("Found package '%s'\n", filename);
371 _AddFile(filename, ref);
374 if (ret != B_ENTRY_NOT_FOUND)
375 return ret;
377 return B_OK;
381 void
382 UninstallView::_ClearAppList()
384 while (BListItem* item = fAppList->RemoveItem((int32)0))
385 delete item;
389 void
390 UninstallView::_AddFile(const char* filename, const node_ref& ref)
392 BString name;
393 status_t ret = info_get_package_name(filename, name);
394 if (ret != B_OK || name.Length() == 0)
395 fprintf(stderr, "Error extracting package name: %s\n", strerror(ret));
396 BString version;
397 ret = info_get_package_version(filename, version);
398 if (ret != B_OK || version.Length() == 0) {
399 fprintf(stderr, "Error extracting package version: %s\n",
400 strerror(ret));
402 fAppList->AddItem(new InfoItem(name, version, filename, ref));
406 void
407 UninstallView::_CachePathToPackages()
409 if (find_directory(B_USER_CONFIG_DIRECTORY, &fToPackages) != B_OK)
410 return;
411 if (fToPackages.Append(kPackagesDir) != B_OK)
412 return;