2 * Copyright (c) 2007-2010, Haiku, Inc.
3 * Distributed under the terms of the MIT license.
6 * Ćukasz 'Sil2100' Zemczak <sil2100@vexillium.org>
10 #include "UninstallView.h"
19 #include <ControlLook.h>
20 #include <Directory.h>
23 #include <FilePanel.h>
24 #include <FindDirectory.h>
25 #include <LayoutBuilder.h>
28 #include <NodeMonitor.h>
29 #include <ScrollView.h>
30 #include <SeparatorView.h>
32 #include <StringView.h>
33 #include <SpaceLayoutItem.h>
39 #undef B_TRANSLATION_CONTEXT
40 #define B_TRANSLATION_CONTEXT "UninstallView"
44 P_MSG_INSTALL
= 'umin',
45 P_MSG_REMOVE
= 'umrm',
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
{
59 InfoItem(const BString
& name
, const BString
& version
,
60 const char* filename
, const node_ref
& ref
)
62 BStringItem(name
.String()),
67 if (fName
.Length() == 0)
71 const char* GetName() { return fName
.String(); }
72 const char* GetVersion() { return fVersion
.String(); };
73 node_ref
GetNodeRef() { return fNodeRef
; };
84 UninstallView::UninstallView()
86 BGroupView(B_VERTICAL
),
87 fOpenPanel(new BFilePanel(B_OPEN_PANEL
))
89 fNoPackageSelectedString
= B_TRANSLATE("No package selected.");
94 UninstallView::~UninstallView()
96 // Stop all node watching
102 UninstallView::AttachedToWindow()
104 fAppList
->SetTarget(this);
105 fInstallButton
->SetTarget(this);
106 fRemoveButton
->SetTarget(this);
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
113 _CachePathToPackages();
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
122 fToPackages
.GetParent(&path
);
123 if (dir
.SetTo(path
.Path()) != B_OK
)
126 fWatcherRunning
= true;
128 dir
.GetNodeRef(&ref
);
130 if (watch_node(&ref
, B_WATCH_DIRECTORY
, this) != B_OK
) {
131 fWatcherRunning
= false;
138 UninstallView::MessageReceived(BMessage
* msg
)
144 if (msg
->FindInt32("opcode", &opcode
) != B_OK
)
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
;
152 if (msg
->FindString("name", &filename
) != B_OK
153 || msg
->FindInt32("device", &ref
.device
) != B_OK
154 || msg
->FindInt64("node", &ref
.node
) != B_OK
)
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.
164 if (fWatcherRunning
) {
165 _AddFile(filename
.String(), ref
);
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
) {
176 if (msg
->FindInt32("device", &ref
.device
) != B_OK
177 || msg
->FindInt64("node", &ref
.node
) != B_OK
)
180 int32 i
, count
= fAppList
->CountItems();
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
);
191 } else if (opcode
== B_ENTRY_MOVED
) {
193 if (msg
->FindInt64("from directory", &from
) != B_OK
194 || msg
->FindInt64("to directory", &to
) != B_OK
)
197 BDirectory
packagesDir(fToPackages
.Path());
199 packagesDir
.GetNodeRef(&ref
);
201 if (ref
.node
== to
) {
204 } else if (ref
.node
== from
) {
213 fRemoveButton
->SetEnabled(false);
214 fDescription
->SetText(fNoPackageSelectedString
);
216 int32 index
= fAppList
->CurrentSelection();
220 fprintf(stderr
, "Another debug message...\n");
222 InfoItem
* item
= dynamic_cast<InfoItem
*>(fAppList
->ItemAt(index
));
226 fprintf(stderr
, "Uh: %s and %s\n", item
->GetName(),
229 if (fCurrentSelection
.SetTo(item
->GetName(),
230 item
->GetVersion()) != B_OK
)
233 fRemoveButton
->SetEnabled(true);
234 fDescription
->SetText(fCurrentSelection
.Description());
244 if (fCurrentSelection
.InitCheck() != B_OK
)
247 int32 index
= fAppList
->CurrentSelection();
252 if (fCurrentSelection
.Uninstall() == B_OK
) {
253 BListItem
* item
= fAppList
->RemoveItem(index
);
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."),
263 notify
= new BAlert("removal_failed",
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
);
275 BView::MessageReceived(msg
);
282 UninstallView::RefsReceived(BMessage
* message
)
284 static_cast<PackageInstaller
*>(be_app
)->RefsReceived(message
);
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)
318 .Add(new BSeparatorView(B_HORIZONTAL
, B_PLAIN_BORDER
))
319 .AddGroup(B_VERTICAL
)
321 .AddGroup(B_HORIZONTAL
, 0)
322 .Add(descriptionLabel
)
325 .AddGroup(B_HORIZONTAL
, 0)
326 .Add(BSpaceLayoutItem::CreateHorizontalStrut(10))
330 .Add(new BSeparatorView(B_HORIZONTAL
, B_PLAIN_BORDER
))
331 .AddGroup(B_HORIZONTAL
)
342 UninstallView::_ReloadAppList()
346 if (fToPackages
.InitCheck() != B_OK
)
347 _CachePathToPackages();
349 BDirectory
dir(fToPackages
.Path());
350 status_t ret
= dir
.InitCheck();
355 while (dir
.GetNextEntry(&iter
) == B_OK
) {
356 char filename
[B_FILE_NAME_LENGTH
];
357 if (iter
.GetName(filename
) != B_OK
)
361 if (iter
.GetNodeRef(&ref
) != B_OK
)
364 BString
filenameString(filename
);
365 if (!filenameString
.IEndsWith(".pdb")) {
366 printf("Ignoring non-package '%s'\n", filename
);
370 printf("Found package '%s'\n", filename
);
371 _AddFile(filename
, ref
);
374 if (ret
!= B_ENTRY_NOT_FOUND
)
382 UninstallView::_ClearAppList()
384 while (BListItem
* item
= fAppList
->RemoveItem((int32
)0))
390 UninstallView::_AddFile(const char* filename
, const node_ref
& ref
)
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
));
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",
402 fAppList
->AddItem(new InfoItem(name
, version
, filename
, ref
));
407 UninstallView::_CachePathToPackages()
409 if (find_directory(B_USER_CONFIG_DIRECTORY
, &fToPackages
) != B_OK
)
411 if (fToPackages
.Append(kPackagesDir
) != B_OK
)