xref: /haiku/src/preferences/repositories/RepositoriesView.cpp (revision 5bf2b6eb74cbbee276a8050078917e8fbbea11e9)
1*5bf2b6ebSBrian Hill /*
2*5bf2b6ebSBrian Hill  * Copyright 2017 Haiku Inc. All rights reserved.
3*5bf2b6ebSBrian Hill  * Distributed under the terms of the MIT License.
4*5bf2b6ebSBrian Hill  *
5*5bf2b6ebSBrian Hill  * Authors:
6*5bf2b6ebSBrian Hill  *		Brian Hill
7*5bf2b6ebSBrian Hill  */
8*5bf2b6ebSBrian Hill 
9*5bf2b6ebSBrian Hill 
10*5bf2b6ebSBrian Hill #include "RepositoriesView.h"
11*5bf2b6ebSBrian Hill 
12*5bf2b6ebSBrian Hill #include <stdlib.h>
13*5bf2b6ebSBrian Hill #include <Alert.h>
14*5bf2b6ebSBrian Hill #include <Button.h>
15*5bf2b6ebSBrian Hill #include <Catalog.h>
16*5bf2b6ebSBrian Hill #include <ColumnTypes.h>
17*5bf2b6ebSBrian Hill #include <LayoutBuilder.h>
18*5bf2b6ebSBrian Hill #include <MessageRunner.h>
19*5bf2b6ebSBrian Hill #include <ScrollBar.h>
20*5bf2b6ebSBrian Hill #include <SeparatorView.h>
21*5bf2b6ebSBrian Hill #include <package/PackageRoster.h>
22*5bf2b6ebSBrian Hill #include <package/RepositoryConfig.h>
23*5bf2b6ebSBrian Hill 
24*5bf2b6ebSBrian Hill #include "constants.h"
25*5bf2b6ebSBrian Hill 
26*5bf2b6ebSBrian Hill #undef B_TRANSLATION_CONTEXT
27*5bf2b6ebSBrian Hill #define B_TRANSLATION_CONTEXT "RepositoriesView"
28*5bf2b6ebSBrian Hill 
29*5bf2b6ebSBrian Hill 
30*5bf2b6ebSBrian Hill static const BString kTitleEnabled =
31*5bf2b6ebSBrian Hill 	B_TRANSLATE_COMMENT("Enabled", "Column title");
32*5bf2b6ebSBrian Hill static const BString kTitleName = B_TRANSLATE_COMMENT("Name", "Column title");
33*5bf2b6ebSBrian Hill static const BString kTitleUrl = B_TRANSLATE_COMMENT("URL", "Column title");
34*5bf2b6ebSBrian Hill static const BString kLabelRemove =
35*5bf2b6ebSBrian Hill 	B_TRANSLATE_COMMENT("Remove", "Button label");
36*5bf2b6ebSBrian Hill static const BString kLabelRemoveAll =
37*5bf2b6ebSBrian Hill 	B_TRANSLATE_COMMENT("Remove All", "Button label");
38*5bf2b6ebSBrian Hill static const BString kLabelEnable =
39*5bf2b6ebSBrian Hill 	B_TRANSLATE_COMMENT("Enable", "Button label");
40*5bf2b6ebSBrian Hill static const BString kLabelEnableAll =
41*5bf2b6ebSBrian Hill 	B_TRANSLATE_COMMENT("Enable All", "Button label");
42*5bf2b6ebSBrian Hill static const BString kLabelDisable =
43*5bf2b6ebSBrian Hill 	B_TRANSLATE_COMMENT("Disable", "Button label");
44*5bf2b6ebSBrian Hill static const BString kLabelDisableAll =
45*5bf2b6ebSBrian Hill 	B_TRANSLATE_COMMENT("Disable All", "Button label");
46*5bf2b6ebSBrian Hill static const BString kStatusViewText =
47*5bf2b6ebSBrian Hill 	B_TRANSLATE_COMMENT("Changes pending:", "Status view text");
48*5bf2b6ebSBrian Hill static const BString kStatusCompletedText =
49*5bf2b6ebSBrian Hill 	B_TRANSLATE_COMMENT("Changes completed", "Status view text");
50*5bf2b6ebSBrian Hill 
51*5bf2b6ebSBrian Hill 
52*5bf2b6ebSBrian Hill RepositoriesListView::RepositoriesListView(const char* name)
53*5bf2b6ebSBrian Hill 	:
54*5bf2b6ebSBrian Hill 	BColumnListView(name, B_NAVIGABLE, B_PLAIN_BORDER)
55*5bf2b6ebSBrian Hill {
56*5bf2b6ebSBrian Hill }
57*5bf2b6ebSBrian Hill 
58*5bf2b6ebSBrian Hill 
59*5bf2b6ebSBrian Hill void
60*5bf2b6ebSBrian Hill RepositoriesListView::KeyDown(const char* bytes, int32 numBytes)
61*5bf2b6ebSBrian Hill {
62*5bf2b6ebSBrian Hill 	switch (bytes[0]) {
63*5bf2b6ebSBrian Hill 		case B_DELETE:
64*5bf2b6ebSBrian Hill 			Window()->PostMessage(DELETE_KEY_PRESSED);
65*5bf2b6ebSBrian Hill 			break;
66*5bf2b6ebSBrian Hill 
67*5bf2b6ebSBrian Hill 		default:
68*5bf2b6ebSBrian Hill 			BColumnListView::KeyDown(bytes, numBytes);
69*5bf2b6ebSBrian Hill 	}
70*5bf2b6ebSBrian Hill }
71*5bf2b6ebSBrian Hill 
72*5bf2b6ebSBrian Hill 
73*5bf2b6ebSBrian Hill RepositoriesView::RepositoriesView()
74*5bf2b6ebSBrian Hill 	:
75*5bf2b6ebSBrian Hill 	BGroupView("RepositoriesView"),
76*5bf2b6ebSBrian Hill 	fTaskLooper(NULL),
77*5bf2b6ebSBrian Hill 	fShowCompletedStatus(false),
78*5bf2b6ebSBrian Hill 	fRunningTaskCount(0),
79*5bf2b6ebSBrian Hill 	fLastCompletedTimerId(0)
80*5bf2b6ebSBrian Hill {
81*5bf2b6ebSBrian Hill 	// Column list view with 3 columns
82*5bf2b6ebSBrian Hill 	fListView = new RepositoriesListView("list");
83*5bf2b6ebSBrian Hill 	fListView->SetSelectionMessage(new BMessage(LIST_SELECTION_CHANGED));
84*5bf2b6ebSBrian Hill 	float col0width = be_plain_font->StringWidth(kTitleEnabled) + 15;
85*5bf2b6ebSBrian Hill 	float col1width = be_plain_font->StringWidth(kTitleName) + 15;
86*5bf2b6ebSBrian Hill 	float col2width = be_plain_font->StringWidth(kTitleUrl) + 15;
87*5bf2b6ebSBrian Hill 	fListView->AddColumn(new BStringColumn(kTitleEnabled, col0width, col0width,
88*5bf2b6ebSBrian Hill 		col0width, B_TRUNCATE_END, B_ALIGN_CENTER), kEnabledColumn);
89*5bf2b6ebSBrian Hill 	fListView->AddColumn(new BStringColumn(kTitleName, 90, col1width, 300,
90*5bf2b6ebSBrian Hill 		B_TRUNCATE_END), kNameColumn);
91*5bf2b6ebSBrian Hill 	fListView->AddColumn(new BStringColumn(kTitleUrl, 500, col2width, 5000,
92*5bf2b6ebSBrian Hill 		B_TRUNCATE_END), kUrlColumn);
93*5bf2b6ebSBrian Hill 	fListView->SetInvocationMessage(new BMessage(ITEM_INVOKED));
94*5bf2b6ebSBrian Hill 
95*5bf2b6ebSBrian Hill 	// Repository list status view
96*5bf2b6ebSBrian Hill 	fStatusContainerView = new BView("status", B_SUPPORTS_LAYOUT);
97*5bf2b6ebSBrian Hill 	BString templateText(kStatusViewText);
98*5bf2b6ebSBrian Hill 	templateText.Append(" 88");
99*5bf2b6ebSBrian Hill 		// Simulate a status text with two digit queue count
100*5bf2b6ebSBrian Hill 	fListStatusView = new BStringView("status", templateText);
101*5bf2b6ebSBrian Hill 
102*5bf2b6ebSBrian Hill 	// Set a smaller fixed font size and slightly lighten text color
103*5bf2b6ebSBrian Hill 	BFont font(be_plain_font);
104*5bf2b6ebSBrian Hill 	font.SetSize(10.0f);
105*5bf2b6ebSBrian Hill 	fListStatusView->SetFont(&font, B_FONT_SIZE);
106*5bf2b6ebSBrian Hill 	fListStatusView->SetHighUIColor(fListStatusView->HighUIColor(), .9f);
107*5bf2b6ebSBrian Hill 
108*5bf2b6ebSBrian Hill 	// Set appropriate explicit view sizes
109*5bf2b6ebSBrian Hill 	float viewWidth = max(fListStatusView->StringWidth(templateText),
110*5bf2b6ebSBrian Hill 		fListStatusView->StringWidth(kStatusCompletedText));
111*5bf2b6ebSBrian Hill 	BSize statusViewSize(viewWidth + 3, B_H_SCROLL_BAR_HEIGHT - 2);
112*5bf2b6ebSBrian Hill 	fListStatusView->SetExplicitSize(statusViewSize);
113*5bf2b6ebSBrian Hill 	statusViewSize.height += 1;
114*5bf2b6ebSBrian Hill 	fStatusContainerView->SetExplicitSize(statusViewSize);
115*5bf2b6ebSBrian Hill 	BLayoutBuilder::Group<>(fStatusContainerView, B_HORIZONTAL, 0)
116*5bf2b6ebSBrian Hill 		.Add(new BSeparatorView(B_VERTICAL))
117*5bf2b6ebSBrian Hill 		.AddGroup(B_VERTICAL, 0)
118*5bf2b6ebSBrian Hill 			.AddGlue()
119*5bf2b6ebSBrian Hill 			.AddGroup(B_HORIZONTAL, 0)
120*5bf2b6ebSBrian Hill 				.SetInsets(2, 0, 0, 0)
121*5bf2b6ebSBrian Hill 				.Add(fListStatusView)
122*5bf2b6ebSBrian Hill 				.AddGlue()
123*5bf2b6ebSBrian Hill 			.End()
124*5bf2b6ebSBrian Hill 			.Add(new BSeparatorView(B_HORIZONTAL))
125*5bf2b6ebSBrian Hill 		.End()
126*5bf2b6ebSBrian Hill 	.End();
127*5bf2b6ebSBrian Hill 	fListView->AddStatusView(fStatusContainerView);
128*5bf2b6ebSBrian Hill 
129*5bf2b6ebSBrian Hill 	// Standard buttons
130*5bf2b6ebSBrian Hill 	fEnableButton = new BButton(kLabelEnable,
131*5bf2b6ebSBrian Hill 		new BMessage(ENABLE_BUTTON_PRESSED));
132*5bf2b6ebSBrian Hill 	fDisableButton = new BButton(kLabelDisable,
133*5bf2b6ebSBrian Hill 		new BMessage(DISABLE_BUTTON_PRESSED));
134*5bf2b6ebSBrian Hill 
135*5bf2b6ebSBrian Hill 	// Create buttons with fixed size
136*5bf2b6ebSBrian Hill 	font_height fontHeight;
137*5bf2b6ebSBrian Hill 	GetFontHeight(&fontHeight);
138*5bf2b6ebSBrian Hill 	int16 buttonHeight = int16(fontHeight.ascent + fontHeight.descent + 12);
139*5bf2b6ebSBrian Hill 		// button size determined by font size
140*5bf2b6ebSBrian Hill 	BSize btnSize(buttonHeight, buttonHeight);
141*5bf2b6ebSBrian Hill 
142*5bf2b6ebSBrian Hill 	fAddButton = new BButton("plus", "+", new BMessage(ADD_REPO_WINDOW));
143*5bf2b6ebSBrian Hill 	fAddButton->SetExplicitSize(btnSize);
144*5bf2b6ebSBrian Hill 	fRemoveButton = new BButton("minus", "-", new BMessage(REMOVE_REPOS));
145*5bf2b6ebSBrian Hill 	fRemoveButton->SetExplicitSize(btnSize);
146*5bf2b6ebSBrian Hill 
147*5bf2b6ebSBrian Hill 	// Layout
148*5bf2b6ebSBrian Hill 	int16 buttonSpacing = 1;
149*5bf2b6ebSBrian Hill 	BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
150*5bf2b6ebSBrian Hill 		.SetInsets(B_USE_WINDOW_SPACING)
151*5bf2b6ebSBrian Hill 		.AddGroup(B_HORIZONTAL, 0, 0.0)
152*5bf2b6ebSBrian Hill 			.Add(new BStringView("instruction", B_TRANSLATE_COMMENT("Select"
153*5bf2b6ebSBrian Hill 				" repositories to use with Haiku package management:",
154*5bf2b6ebSBrian Hill 				"Label text")), 0.0)
155*5bf2b6ebSBrian Hill 			.AddGlue()
156*5bf2b6ebSBrian Hill 		.End()
157*5bf2b6ebSBrian Hill 		.AddStrut(B_USE_DEFAULT_SPACING)
158*5bf2b6ebSBrian Hill 		.Add(fListView, 1)
159*5bf2b6ebSBrian Hill 		.AddGroup(B_HORIZONTAL, 0, 0.0)
160*5bf2b6ebSBrian Hill 			// Add and Remove buttons
161*5bf2b6ebSBrian Hill 			.AddGroup(B_VERTICAL, 0, 0.0)
162*5bf2b6ebSBrian Hill 				.AddGroup(B_HORIZONTAL, 0, 0.0)
163*5bf2b6ebSBrian Hill 					.Add(new BSeparatorView(B_VERTICAL))
164*5bf2b6ebSBrian Hill 					.AddGroup(B_VERTICAL, 0, 0.0)
165*5bf2b6ebSBrian Hill 						.AddGroup(B_HORIZONTAL, buttonSpacing, 0.0)
166*5bf2b6ebSBrian Hill 							.SetInsets(buttonSpacing)
167*5bf2b6ebSBrian Hill 							.Add(fAddButton)
168*5bf2b6ebSBrian Hill 							.Add(fRemoveButton)
169*5bf2b6ebSBrian Hill 						.End()
170*5bf2b6ebSBrian Hill 						.Add(new BSeparatorView(B_HORIZONTAL))
171*5bf2b6ebSBrian Hill 					.End()
172*5bf2b6ebSBrian Hill 					.Add(new BSeparatorView(B_VERTICAL))
173*5bf2b6ebSBrian Hill 				.End()
174*5bf2b6ebSBrian Hill 				.AddGlue()
175*5bf2b6ebSBrian Hill 			.End()
176*5bf2b6ebSBrian Hill 			// Enable and Disable buttons
177*5bf2b6ebSBrian Hill 			.AddGroup(B_HORIZONTAL)
178*5bf2b6ebSBrian Hill 				.SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING,
179*5bf2b6ebSBrian Hill 					B_USE_DEFAULT_SPACING, 0)
180*5bf2b6ebSBrian Hill 				.AddGlue()
181*5bf2b6ebSBrian Hill 				.Add(fEnableButton)
182*5bf2b6ebSBrian Hill 				.Add(fDisableButton)
183*5bf2b6ebSBrian Hill 			.End()
184*5bf2b6ebSBrian Hill 		.End()
185*5bf2b6ebSBrian Hill 	.End();
186*5bf2b6ebSBrian Hill }
187*5bf2b6ebSBrian Hill 
188*5bf2b6ebSBrian Hill 
189*5bf2b6ebSBrian Hill RepositoriesView::~RepositoriesView()
190*5bf2b6ebSBrian Hill {
191*5bf2b6ebSBrian Hill 	if (fTaskLooper) {
192*5bf2b6ebSBrian Hill 		fTaskLooper->Lock();
193*5bf2b6ebSBrian Hill 		fTaskLooper->Quit();
194*5bf2b6ebSBrian Hill 	}
195*5bf2b6ebSBrian Hill 	_EmptyList();
196*5bf2b6ebSBrian Hill }
197*5bf2b6ebSBrian Hill 
198*5bf2b6ebSBrian Hill 
199*5bf2b6ebSBrian Hill void
200*5bf2b6ebSBrian Hill RepositoriesView::AllAttached()
201*5bf2b6ebSBrian Hill {
202*5bf2b6ebSBrian Hill 	BView::AllAttached();
203*5bf2b6ebSBrian Hill 	fRemoveButton->SetTarget(this);
204*5bf2b6ebSBrian Hill 	fEnableButton->SetTarget(this);
205*5bf2b6ebSBrian Hill 	fDisableButton->SetTarget(this);
206*5bf2b6ebSBrian Hill 	fListView->SetTarget(this);
207*5bf2b6ebSBrian Hill 	fRemoveButton->SetEnabled(false);
208*5bf2b6ebSBrian Hill 	fEnableButton->SetEnabled(false);
209*5bf2b6ebSBrian Hill 	fDisableButton->SetEnabled(false);
210*5bf2b6ebSBrian Hill 	_UpdateStatusView();
211*5bf2b6ebSBrian Hill 	_InitList();
212*5bf2b6ebSBrian Hill }
213*5bf2b6ebSBrian Hill 
214*5bf2b6ebSBrian Hill 
215*5bf2b6ebSBrian Hill void
216*5bf2b6ebSBrian Hill RepositoriesView::AttachedToWindow()
217*5bf2b6ebSBrian Hill {
218*5bf2b6ebSBrian Hill 	fTaskLooper = new TaskLooper(BMessenger(this));
219*5bf2b6ebSBrian Hill }
220*5bf2b6ebSBrian Hill 
221*5bf2b6ebSBrian Hill 
222*5bf2b6ebSBrian Hill void
223*5bf2b6ebSBrian Hill RepositoriesView::MessageReceived(BMessage* message)
224*5bf2b6ebSBrian Hill {
225*5bf2b6ebSBrian Hill 	switch (message->what)
226*5bf2b6ebSBrian Hill 	{
227*5bf2b6ebSBrian Hill 		case REMOVE_REPOS: {
228*5bf2b6ebSBrian Hill 			RepoRow* rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection());
229*5bf2b6ebSBrian Hill 			if (!rowItem || !fRemoveButton->IsEnabled())
230*5bf2b6ebSBrian Hill 				break;
231*5bf2b6ebSBrian Hill 
232*5bf2b6ebSBrian Hill 			BString text;
233*5bf2b6ebSBrian Hill 			// More than one selected row
234*5bf2b6ebSBrian Hill 			if (fListView->CurrentSelection(rowItem)) {
235*5bf2b6ebSBrian Hill 				text.SetTo(B_TRANSLATE_COMMENT("Remove these repositories?",
236*5bf2b6ebSBrian Hill 					"Removal alert confirmation message"));
237*5bf2b6ebSBrian Hill 				text.Append("\n");
238*5bf2b6ebSBrian Hill 			}
239*5bf2b6ebSBrian Hill 			// Only one selected row
240*5bf2b6ebSBrian Hill 			else {
241*5bf2b6ebSBrian Hill 				text.SetTo(B_TRANSLATE_COMMENT("Remove this repository?",
242*5bf2b6ebSBrian Hill 					"Removal alert confirmation message"));
243*5bf2b6ebSBrian Hill 				text.Append("\n");
244*5bf2b6ebSBrian Hill 			}
245*5bf2b6ebSBrian Hill 			float minWidth = 0;
246*5bf2b6ebSBrian Hill 			while (rowItem) {
247*5bf2b6ebSBrian Hill 				BString repoText;
248*5bf2b6ebSBrian Hill 				repoText.Append("\n").Append(rowItem->Name())
249*5bf2b6ebSBrian Hill 					.Append(" (").Append(rowItem->Url()).Append(")");
250*5bf2b6ebSBrian Hill 				minWidth = max(minWidth, StringWidth(repoText.String()));
251*5bf2b6ebSBrian Hill 				text.Append(repoText);
252*5bf2b6ebSBrian Hill 				rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection(rowItem));
253*5bf2b6ebSBrian Hill 			}
254*5bf2b6ebSBrian Hill 			minWidth = min(minWidth, Frame().Width());
255*5bf2b6ebSBrian Hill 				// Ensure alert window isn't much larger than the main window
256*5bf2b6ebSBrian Hill 			BAlert* alert = new BAlert("confirm", text, kRemoveLabel,
257*5bf2b6ebSBrian Hill 				kCancelLabel, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
258*5bf2b6ebSBrian Hill 			alert->TextView()->SetExplicitMinSize(BSize(minWidth, B_SIZE_UNSET));
259*5bf2b6ebSBrian Hill 			alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
260*5bf2b6ebSBrian Hill 			int32 answer = alert->Go();
261*5bf2b6ebSBrian Hill 			// User presses Cancel button
262*5bf2b6ebSBrian Hill 			if (answer)
263*5bf2b6ebSBrian Hill 				break;
264*5bf2b6ebSBrian Hill 
265*5bf2b6ebSBrian Hill 			rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection());
266*5bf2b6ebSBrian Hill 			while (rowItem) {
267*5bf2b6ebSBrian Hill 				RepoRow* oldRow = rowItem;
268*5bf2b6ebSBrian Hill 				rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection(rowItem));
269*5bf2b6ebSBrian Hill 				fListView->RemoveRow(oldRow);
270*5bf2b6ebSBrian Hill 				delete oldRow;
271*5bf2b6ebSBrian Hill 			}
272*5bf2b6ebSBrian Hill 			_SaveList();
273*5bf2b6ebSBrian Hill 			break;
274*5bf2b6ebSBrian Hill 		}
275*5bf2b6ebSBrian Hill 		case LIST_SELECTION_CHANGED:
276*5bf2b6ebSBrian Hill 			_UpdateButtons();
277*5bf2b6ebSBrian Hill 			break;
278*5bf2b6ebSBrian Hill 
279*5bf2b6ebSBrian Hill 		case ITEM_INVOKED: {
280*5bf2b6ebSBrian Hill 			// Simulates pressing whichever is the enabled button
281*5bf2b6ebSBrian Hill 			if (fEnableButton->IsEnabled()) {
282*5bf2b6ebSBrian Hill 				BMessage invokeMessage(ENABLE_BUTTON_PRESSED);
283*5bf2b6ebSBrian Hill 				MessageReceived(&invokeMessage);
284*5bf2b6ebSBrian Hill 			} else if (fDisableButton->IsEnabled()) {
285*5bf2b6ebSBrian Hill 				BMessage invokeMessage(DISABLE_BUTTON_PRESSED);
286*5bf2b6ebSBrian Hill 				MessageReceived(&invokeMessage);
287*5bf2b6ebSBrian Hill 			}
288*5bf2b6ebSBrian Hill 			break;
289*5bf2b6ebSBrian Hill 		}
290*5bf2b6ebSBrian Hill 		case ENABLE_BUTTON_PRESSED: {
291*5bf2b6ebSBrian Hill 			BStringList names;
292*5bf2b6ebSBrian Hill 			bool paramsOK = true;
293*5bf2b6ebSBrian Hill 			// Check if there are multiple selections of the same repository,
294*5bf2b6ebSBrian Hill 			// pkgman won't like that
295*5bf2b6ebSBrian Hill 			RepoRow* rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection());
296*5bf2b6ebSBrian Hill 			while (rowItem) {
297*5bf2b6ebSBrian Hill 				if (names.HasString(rowItem->Name())
298*5bf2b6ebSBrian Hill 					&& kNewRepoDefaultName.Compare(rowItem->Name()) != 0) {
299*5bf2b6ebSBrian Hill 					(new BAlert("duplicate",
300*5bf2b6ebSBrian Hill 						B_TRANSLATE_COMMENT("Only one URL for each repository can "
301*5bf2b6ebSBrian Hill 							"be enabled.  Please change your selections.",
302*5bf2b6ebSBrian Hill 							"Error message"),
303*5bf2b6ebSBrian Hill 						kOKLabel, NULL, NULL,
304*5bf2b6ebSBrian Hill 						B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go(NULL);
305*5bf2b6ebSBrian Hill 					paramsOK = false;
306*5bf2b6ebSBrian Hill 					break;
307*5bf2b6ebSBrian Hill 				} else
308*5bf2b6ebSBrian Hill 					names.Add(rowItem->Name());
309*5bf2b6ebSBrian Hill 				rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection(rowItem));
310*5bf2b6ebSBrian Hill 			}
311*5bf2b6ebSBrian Hill 			if (paramsOK) {
312*5bf2b6ebSBrian Hill 				_AddSelectedRowsToQueue();
313*5bf2b6ebSBrian Hill 				_UpdateButtons();
314*5bf2b6ebSBrian Hill 			}
315*5bf2b6ebSBrian Hill 			break;
316*5bf2b6ebSBrian Hill 		}
317*5bf2b6ebSBrian Hill 		case DISABLE_BUTTON_PRESSED:
318*5bf2b6ebSBrian Hill 			_AddSelectedRowsToQueue();
319*5bf2b6ebSBrian Hill 			_UpdateButtons();
320*5bf2b6ebSBrian Hill 			break;
321*5bf2b6ebSBrian Hill 
322*5bf2b6ebSBrian Hill 		case TASK_STARTED: {
323*5bf2b6ebSBrian Hill 			int16 count;
324*5bf2b6ebSBrian Hill 			status_t result1 = message->FindInt16(key_count, &count);
325*5bf2b6ebSBrian Hill 			RepoRow* rowItem;
326*5bf2b6ebSBrian Hill 			status_t result2 = message->FindPointer(key_rowptr, (void**)&rowItem);
327*5bf2b6ebSBrian Hill 			if (result1 == B_OK && result2 == B_OK)
328*5bf2b6ebSBrian Hill 				_TaskStarted(rowItem, count);
329*5bf2b6ebSBrian Hill 			break;
330*5bf2b6ebSBrian Hill 		}
331*5bf2b6ebSBrian Hill 		case TASK_COMPLETED_WITH_ERRORS: {
332*5bf2b6ebSBrian Hill 			BString errorDetails;
333*5bf2b6ebSBrian Hill 			status_t result = message->FindString(key_details, &errorDetails);
334*5bf2b6ebSBrian Hill 			if (result == B_OK) {
335*5bf2b6ebSBrian Hill 				(new BAlert("error", errorDetails, kOKLabel, NULL, NULL,
336*5bf2b6ebSBrian Hill 					B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go(NULL);
337*5bf2b6ebSBrian Hill 			}
338*5bf2b6ebSBrian Hill 			BString repoName = message->GetString(key_name,
339*5bf2b6ebSBrian Hill 				kNewRepoDefaultName.String());
340*5bf2b6ebSBrian Hill 			int16 count;
341*5bf2b6ebSBrian Hill 			status_t result1 = message->FindInt16(key_count, &count);
342*5bf2b6ebSBrian Hill 			RepoRow* rowItem;
343*5bf2b6ebSBrian Hill 			status_t result2 = message->FindPointer(key_rowptr, (void**)&rowItem);
344*5bf2b6ebSBrian Hill 			if (result1 == B_OK && result2 == B_OK) {
345*5bf2b6ebSBrian Hill 				_TaskCompleted(rowItem, count, repoName);
346*5bf2b6ebSBrian Hill 				// Refresh the enabled status of each row since it is unsure what
347*5bf2b6ebSBrian Hill 				// caused the error
348*5bf2b6ebSBrian Hill 				_RefreshList();
349*5bf2b6ebSBrian Hill 			}
350*5bf2b6ebSBrian Hill 			_UpdateButtons();
351*5bf2b6ebSBrian Hill 			break;
352*5bf2b6ebSBrian Hill 		}
353*5bf2b6ebSBrian Hill 		case TASK_COMPLETED: {
354*5bf2b6ebSBrian Hill 			BString repoName = message->GetString(key_name,
355*5bf2b6ebSBrian Hill 				kNewRepoDefaultName.String());
356*5bf2b6ebSBrian Hill 			int16 count;
357*5bf2b6ebSBrian Hill 			status_t result1 = message->FindInt16(key_count, &count);
358*5bf2b6ebSBrian Hill 			RepoRow* rowItem;
359*5bf2b6ebSBrian Hill 			status_t result2 = message->FindPointer(key_rowptr, (void**)&rowItem);
360*5bf2b6ebSBrian Hill 			if (result1 == B_OK && result2 == B_OK) {
361*5bf2b6ebSBrian Hill 				_TaskCompleted(rowItem, count, repoName);
362*5bf2b6ebSBrian Hill 				// If the completed row has siblings then enabling this row may
363*5bf2b6ebSBrian Hill 				// have disabled one of the other siblings, do full refresh.
364*5bf2b6ebSBrian Hill 				if (rowItem->HasSiblings() && rowItem->IsEnabled())
365*5bf2b6ebSBrian Hill 					_RefreshList();
366*5bf2b6ebSBrian Hill 			}
367*5bf2b6ebSBrian Hill 			_UpdateButtons();
368*5bf2b6ebSBrian Hill 			break;
369*5bf2b6ebSBrian Hill 		}
370*5bf2b6ebSBrian Hill 		case TASK_CANCELED: {
371*5bf2b6ebSBrian Hill 			int16 count;
372*5bf2b6ebSBrian Hill 			status_t result1 = message->FindInt16(key_count, &count);
373*5bf2b6ebSBrian Hill 			RepoRow* rowItem;
374*5bf2b6ebSBrian Hill 			status_t result2 = message->FindPointer(key_rowptr, (void**)&rowItem);
375*5bf2b6ebSBrian Hill 			if (result1 == B_OK && result2 == B_OK)
376*5bf2b6ebSBrian Hill 				_TaskCanceled(rowItem, count);
377*5bf2b6ebSBrian Hill 			// Refresh the enabled status of each row since it is unsure what
378*5bf2b6ebSBrian Hill 			// caused the cancelation
379*5bf2b6ebSBrian Hill 			_RefreshList();
380*5bf2b6ebSBrian Hill 			_UpdateButtons();
381*5bf2b6ebSBrian Hill 			break;
382*5bf2b6ebSBrian Hill 		}
383*5bf2b6ebSBrian Hill 		case UPDATE_LIST:
384*5bf2b6ebSBrian Hill 			_RefreshList();
385*5bf2b6ebSBrian Hill 			_UpdateButtons();
386*5bf2b6ebSBrian Hill 			break;
387*5bf2b6ebSBrian Hill 
388*5bf2b6ebSBrian Hill 		case STATUS_VIEW_COMPLETED_TIMEOUT: {
389*5bf2b6ebSBrian Hill 			int32 timerID;
390*5bf2b6ebSBrian Hill 			status_t result = message->FindInt32(key_ID, &timerID);
391*5bf2b6ebSBrian Hill 			if (result == B_OK && timerID == fLastCompletedTimerId)
392*5bf2b6ebSBrian Hill 				_UpdateStatusView();
393*5bf2b6ebSBrian Hill 			break;
394*5bf2b6ebSBrian Hill 		}
395*5bf2b6ebSBrian Hill 		default:
396*5bf2b6ebSBrian Hill 			BView::MessageReceived(message);
397*5bf2b6ebSBrian Hill 	}
398*5bf2b6ebSBrian Hill }
399*5bf2b6ebSBrian Hill 
400*5bf2b6ebSBrian Hill 
401*5bf2b6ebSBrian Hill void
402*5bf2b6ebSBrian Hill RepositoriesView::_AddSelectedRowsToQueue()
403*5bf2b6ebSBrian Hill {
404*5bf2b6ebSBrian Hill 	RepoRow* rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection());
405*5bf2b6ebSBrian Hill 	while (rowItem) {
406*5bf2b6ebSBrian Hill 		rowItem->SetTaskState(STATE_IN_QUEUE_WAITING);
407*5bf2b6ebSBrian Hill 		BMessage taskMessage(DO_TASK);
408*5bf2b6ebSBrian Hill 		taskMessage.AddPointer(key_rowptr, rowItem);
409*5bf2b6ebSBrian Hill 		fTaskLooper->PostMessage(&taskMessage);
410*5bf2b6ebSBrian Hill 		rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection(rowItem));
411*5bf2b6ebSBrian Hill 	}
412*5bf2b6ebSBrian Hill }
413*5bf2b6ebSBrian Hill 
414*5bf2b6ebSBrian Hill 
415*5bf2b6ebSBrian Hill void
416*5bf2b6ebSBrian Hill RepositoriesView::_TaskStarted(RepoRow* rowItem, int16 count)
417*5bf2b6ebSBrian Hill {
418*5bf2b6ebSBrian Hill 	fRunningTaskCount = count;
419*5bf2b6ebSBrian Hill 	rowItem->SetTaskState(STATE_IN_QUEUE_RUNNING);
420*5bf2b6ebSBrian Hill 	// Only present a status count if there is more than one task in queue
421*5bf2b6ebSBrian Hill 	if (count > 1) {
422*5bf2b6ebSBrian Hill 		_UpdateStatusView();
423*5bf2b6ebSBrian Hill 		fShowCompletedStatus = true;
424*5bf2b6ebSBrian Hill 	}
425*5bf2b6ebSBrian Hill }
426*5bf2b6ebSBrian Hill 
427*5bf2b6ebSBrian Hill 
428*5bf2b6ebSBrian Hill void
429*5bf2b6ebSBrian Hill RepositoriesView::_TaskCompleted(RepoRow* rowItem, int16 count, BString& newName)
430*5bf2b6ebSBrian Hill {
431*5bf2b6ebSBrian Hill 	fRunningTaskCount = count;
432*5bf2b6ebSBrian Hill 	_ShowCompletedStatusIfDone();
433*5bf2b6ebSBrian Hill 
434*5bf2b6ebSBrian Hill 	// Update row state and values
435*5bf2b6ebSBrian Hill 	rowItem->SetTaskState(STATE_NOT_IN_QUEUE);
436*5bf2b6ebSBrian Hill 	if (kNewRepoDefaultName.Compare(rowItem->Name()) == 0
437*5bf2b6ebSBrian Hill 		&& newName.Compare("") != 0)
438*5bf2b6ebSBrian Hill 		rowItem->SetName(newName.String());
439*5bf2b6ebSBrian Hill 	_UpdateFromRepoConfig(rowItem);
440*5bf2b6ebSBrian Hill }
441*5bf2b6ebSBrian Hill 
442*5bf2b6ebSBrian Hill 
443*5bf2b6ebSBrian Hill void
444*5bf2b6ebSBrian Hill RepositoriesView::_TaskCanceled(RepoRow* rowItem, int16 count)
445*5bf2b6ebSBrian Hill {
446*5bf2b6ebSBrian Hill 	fRunningTaskCount = count;
447*5bf2b6ebSBrian Hill 	_ShowCompletedStatusIfDone();
448*5bf2b6ebSBrian Hill 
449*5bf2b6ebSBrian Hill 	// Update row state and values
450*5bf2b6ebSBrian Hill 	rowItem->SetTaskState(STATE_NOT_IN_QUEUE);
451*5bf2b6ebSBrian Hill 	_UpdateFromRepoConfig(rowItem);
452*5bf2b6ebSBrian Hill }
453*5bf2b6ebSBrian Hill 
454*5bf2b6ebSBrian Hill 
455*5bf2b6ebSBrian Hill void
456*5bf2b6ebSBrian Hill RepositoriesView::_ShowCompletedStatusIfDone()
457*5bf2b6ebSBrian Hill {
458*5bf2b6ebSBrian Hill 	// If this is the last task show completed status text for 3 seconds
459*5bf2b6ebSBrian Hill 	if (fRunningTaskCount == 0 && fShowCompletedStatus) {
460*5bf2b6ebSBrian Hill 		fListStatusView->SetText(kStatusCompletedText);
461*5bf2b6ebSBrian Hill 		fLastCompletedTimerId = rand();
462*5bf2b6ebSBrian Hill 		BMessage timerMessage(STATUS_VIEW_COMPLETED_TIMEOUT);
463*5bf2b6ebSBrian Hill 		timerMessage.AddInt32(key_ID, fLastCompletedTimerId);
464*5bf2b6ebSBrian Hill 		new BMessageRunner(this, &timerMessage, 3000000, 1);
465*5bf2b6ebSBrian Hill 		fShowCompletedStatus = false;
466*5bf2b6ebSBrian Hill 	} else
467*5bf2b6ebSBrian Hill 		_UpdateStatusView();
468*5bf2b6ebSBrian Hill }
469*5bf2b6ebSBrian Hill 
470*5bf2b6ebSBrian Hill 
471*5bf2b6ebSBrian Hill void
472*5bf2b6ebSBrian Hill RepositoriesView::_UpdateFromRepoConfig(RepoRow* rowItem)
473*5bf2b6ebSBrian Hill {
474*5bf2b6ebSBrian Hill 	BPackageKit::BPackageRoster pRoster;
475*5bf2b6ebSBrian Hill 	BPackageKit::BRepositoryConfig repoConfig;
476*5bf2b6ebSBrian Hill 	BString repoName(rowItem->Name());
477*5bf2b6ebSBrian Hill 	status_t result = pRoster.GetRepositoryConfig(repoName, &repoConfig);
478*5bf2b6ebSBrian Hill 	// Repo name was found and the URL matches
479*5bf2b6ebSBrian Hill 	if (result == B_OK && repoConfig.BaseURL() == rowItem->Url())
480*5bf2b6ebSBrian Hill 		rowItem->SetEnabled(true);
481*5bf2b6ebSBrian Hill 	else
482*5bf2b6ebSBrian Hill 		rowItem->SetEnabled(false);
483*5bf2b6ebSBrian Hill }
484*5bf2b6ebSBrian Hill 
485*5bf2b6ebSBrian Hill 
486*5bf2b6ebSBrian Hill void
487*5bf2b6ebSBrian Hill RepositoriesView::AddManualRepository(BString url)
488*5bf2b6ebSBrian Hill {
489*5bf2b6ebSBrian Hill 	BString name(kNewRepoDefaultName);
490*5bf2b6ebSBrian Hill 	BString rootUrl = _GetRootUrl(url);
491*5bf2b6ebSBrian Hill 	bool foundRoot = false;
492*5bf2b6ebSBrian Hill 	int32 index;
493*5bf2b6ebSBrian Hill 	int32 listCount = fListView->CountRows();
494*5bf2b6ebSBrian Hill 	for (index = 0; index < listCount; index++) {
495*5bf2b6ebSBrian Hill 		RepoRow* repoItem = dynamic_cast<RepoRow*>(fListView->RowAt(index));
496*5bf2b6ebSBrian Hill 		const char* urlPtr = repoItem->Url();
497*5bf2b6ebSBrian Hill 		// Find an already existing URL
498*5bf2b6ebSBrian Hill 		if (url.ICompare(urlPtr) == 0) {
499*5bf2b6ebSBrian Hill 			(new BAlert("duplicate",
500*5bf2b6ebSBrian Hill 				B_TRANSLATE_COMMENT("This repository URL already exists.",
501*5bf2b6ebSBrian Hill 					"Error message"),
502*5bf2b6ebSBrian Hill 				kOKLabel))->Go(NULL);
503*5bf2b6ebSBrian Hill 			return;
504*5bf2b6ebSBrian Hill 		}
505*5bf2b6ebSBrian Hill 		// Use the same name from another repo with the same root url
506*5bf2b6ebSBrian Hill 		if (foundRoot == false && rootUrl.ICompare(urlPtr,
507*5bf2b6ebSBrian Hill 				rootUrl.Length()) == 0) {
508*5bf2b6ebSBrian Hill 			foundRoot = true;
509*5bf2b6ebSBrian Hill 			name = repoItem->Name();
510*5bf2b6ebSBrian Hill 		}
511*5bf2b6ebSBrian Hill 	}
512*5bf2b6ebSBrian Hill 	RepoRow* newRepo = _AddRepo(name, url, false);
513*5bf2b6ebSBrian Hill 	_FindSiblings();
514*5bf2b6ebSBrian Hill 	fListView->DeselectAll();
515*5bf2b6ebSBrian Hill 	fListView->AddToSelection(newRepo);
516*5bf2b6ebSBrian Hill 	_UpdateButtons();
517*5bf2b6ebSBrian Hill 	_SaveList();
518*5bf2b6ebSBrian Hill }
519*5bf2b6ebSBrian Hill 
520*5bf2b6ebSBrian Hill 
521*5bf2b6ebSBrian Hill BString
522*5bf2b6ebSBrian Hill RepositoriesView::_GetRootUrl(BString url)
523*5bf2b6ebSBrian Hill {
524*5bf2b6ebSBrian Hill 	// Find the protocol if it exists
525*5bf2b6ebSBrian Hill 	int32 ww = url.FindFirst("://");
526*5bf2b6ebSBrian Hill 	if (ww == B_ERROR)
527*5bf2b6ebSBrian Hill 		ww = 0;
528*5bf2b6ebSBrian Hill 	else
529*5bf2b6ebSBrian Hill 		ww += 3;
530*5bf2b6ebSBrian Hill 	// Find second /
531*5bf2b6ebSBrian Hill 	int32 rootEnd = url.FindFirst("/", ww + 1);
532*5bf2b6ebSBrian Hill 	if (rootEnd == B_ERROR)
533*5bf2b6ebSBrian Hill 		return url;
534*5bf2b6ebSBrian Hill 	rootEnd = url.FindFirst("/", rootEnd + 1);
535*5bf2b6ebSBrian Hill 	if (rootEnd == B_ERROR)
536*5bf2b6ebSBrian Hill 		return url;
537*5bf2b6ebSBrian Hill 	else
538*5bf2b6ebSBrian Hill 		return url.Truncate(rootEnd);
539*5bf2b6ebSBrian Hill }
540*5bf2b6ebSBrian Hill 
541*5bf2b6ebSBrian Hill 
542*5bf2b6ebSBrian Hill status_t
543*5bf2b6ebSBrian Hill RepositoriesView::_EmptyList()
544*5bf2b6ebSBrian Hill {
545*5bf2b6ebSBrian Hill 	BRow* row;
546*5bf2b6ebSBrian Hill 	while ((row = fListView->RowAt((int32)0, NULL)) != NULL) {
547*5bf2b6ebSBrian Hill 		fListView->RemoveRow(row);
548*5bf2b6ebSBrian Hill 		delete row;
549*5bf2b6ebSBrian Hill 	}
550*5bf2b6ebSBrian Hill 	return B_OK;
551*5bf2b6ebSBrian Hill }
552*5bf2b6ebSBrian Hill 
553*5bf2b6ebSBrian Hill 
554*5bf2b6ebSBrian Hill void
555*5bf2b6ebSBrian Hill RepositoriesView::_InitList()
556*5bf2b6ebSBrian Hill {
557*5bf2b6ebSBrian Hill 	// Get list of known repositories from the settings file
558*5bf2b6ebSBrian Hill 	int32 index, repoCount;
559*5bf2b6ebSBrian Hill 	BStringList nameList, urlList;
560*5bf2b6ebSBrian Hill 	status_t result = fSettings.GetRepositories(repoCount, nameList, urlList);
561*5bf2b6ebSBrian Hill 	if (result == B_OK) {
562*5bf2b6ebSBrian Hill 		BString name, url;
563*5bf2b6ebSBrian Hill 		for (index = 0; index < repoCount; index++) {
564*5bf2b6ebSBrian Hill 			name = nameList.StringAt(index);
565*5bf2b6ebSBrian Hill 			url = urlList.StringAt(index);
566*5bf2b6ebSBrian Hill 			_AddRepo(name, url, false);
567*5bf2b6ebSBrian Hill 		}
568*5bf2b6ebSBrian Hill 	}
569*5bf2b6ebSBrian Hill 	_UpdateListFromRoster();
570*5bf2b6ebSBrian Hill 	fListView->SetSortColumn(fListView->ColumnAt(kUrlColumn), false, true);
571*5bf2b6ebSBrian Hill 	fListView->ResizeAllColumnsToPreferred();
572*5bf2b6ebSBrian Hill }
573*5bf2b6ebSBrian Hill 
574*5bf2b6ebSBrian Hill 
575*5bf2b6ebSBrian Hill void
576*5bf2b6ebSBrian Hill RepositoriesView::_RefreshList()
577*5bf2b6ebSBrian Hill {
578*5bf2b6ebSBrian Hill 	// Clear enabled status on all rows
579*5bf2b6ebSBrian Hill 	int32 index, listCount = fListView->CountRows();
580*5bf2b6ebSBrian Hill 	for (index = 0; index < listCount; index++) {
581*5bf2b6ebSBrian Hill 		RepoRow* repoItem = dynamic_cast<RepoRow*>(fListView->RowAt(index));
582*5bf2b6ebSBrian Hill 		if (repoItem->TaskState() == STATE_NOT_IN_QUEUE)
583*5bf2b6ebSBrian Hill 			repoItem->SetEnabled(false);
584*5bf2b6ebSBrian Hill 	}
585*5bf2b6ebSBrian Hill 	// Get current list of enabled repositories
586*5bf2b6ebSBrian Hill 	_UpdateListFromRoster();
587*5bf2b6ebSBrian Hill }
588*5bf2b6ebSBrian Hill 
589*5bf2b6ebSBrian Hill 
590*5bf2b6ebSBrian Hill void
591*5bf2b6ebSBrian Hill RepositoriesView::_UpdateListFromRoster()
592*5bf2b6ebSBrian Hill {
593*5bf2b6ebSBrian Hill 	// Get list of currently enabled repositories
594*5bf2b6ebSBrian Hill 	BStringList repositoryNames;
595*5bf2b6ebSBrian Hill 	BPackageKit::BPackageRoster pRoster;
596*5bf2b6ebSBrian Hill 	status_t result = pRoster.GetRepositoryNames(repositoryNames);
597*5bf2b6ebSBrian Hill 	if (result != B_OK) {
598*5bf2b6ebSBrian Hill 		(new BAlert("error",
599*5bf2b6ebSBrian Hill 			B_TRANSLATE_COMMENT("Repositories could not retrieve the names of "
600*5bf2b6ebSBrian Hill 				"the currently enabled repositories.", "Alert error message"),
601*5bf2b6ebSBrian Hill 			kOKLabel, NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(NULL);
602*5bf2b6ebSBrian Hill 		return;
603*5bf2b6ebSBrian Hill 	}
604*5bf2b6ebSBrian Hill 	BPackageKit::BRepositoryConfig repoConfig;
605*5bf2b6ebSBrian Hill 	int16 index, count = repositoryNames.CountStrings();
606*5bf2b6ebSBrian Hill 	for (index = 0; index < count; index++) {
607*5bf2b6ebSBrian Hill 		const BString& repoName = repositoryNames.StringAt(index);
608*5bf2b6ebSBrian Hill 		result = pRoster.GetRepositoryConfig(repoName, &repoConfig);
609*5bf2b6ebSBrian Hill 		if (result == B_OK)
610*5bf2b6ebSBrian Hill 			_AddRepo(repoName, repoConfig.BaseURL(), true);
611*5bf2b6ebSBrian Hill 		else {
612*5bf2b6ebSBrian Hill 			BString text(B_TRANSLATE_COMMENT("Error getting repository"
613*5bf2b6ebSBrian Hill 				" configuration for %name%.", "Alert error message, "
614*5bf2b6ebSBrian Hill 				"do not translate %name%"));
615*5bf2b6ebSBrian Hill 			text.ReplaceFirst("%name%", repoName);
616*5bf2b6ebSBrian Hill 			(new BAlert("error", text, kOKLabel))->Go(NULL);
617*5bf2b6ebSBrian Hill 		}
618*5bf2b6ebSBrian Hill 	}
619*5bf2b6ebSBrian Hill 	_FindSiblings();
620*5bf2b6ebSBrian Hill 	_SaveList();
621*5bf2b6ebSBrian Hill }
622*5bf2b6ebSBrian Hill 
623*5bf2b6ebSBrian Hill 
624*5bf2b6ebSBrian Hill void
625*5bf2b6ebSBrian Hill RepositoriesView::_SaveList()
626*5bf2b6ebSBrian Hill {
627*5bf2b6ebSBrian Hill 	BStringList nameList, urlList;
628*5bf2b6ebSBrian Hill 	int32 index;
629*5bf2b6ebSBrian Hill 	int32 listCount = fListView->CountRows();
630*5bf2b6ebSBrian Hill 	for (index = 0; index < listCount; index++) {
631*5bf2b6ebSBrian Hill 		RepoRow* repoItem = dynamic_cast<RepoRow*>(fListView->RowAt(index));
632*5bf2b6ebSBrian Hill 		nameList.Add(repoItem->Name());
633*5bf2b6ebSBrian Hill 		urlList.Add(repoItem->Url());
634*5bf2b6ebSBrian Hill 	}
635*5bf2b6ebSBrian Hill 	fSettings.SetRepositories(nameList, urlList);
636*5bf2b6ebSBrian Hill }
637*5bf2b6ebSBrian Hill 
638*5bf2b6ebSBrian Hill 
639*5bf2b6ebSBrian Hill RepoRow*
640*5bf2b6ebSBrian Hill RepositoriesView::_AddRepo(BString name, BString url, bool enabled)
641*5bf2b6ebSBrian Hill {
642*5bf2b6ebSBrian Hill 	// URL must have a protocol
643*5bf2b6ebSBrian Hill 	if (url.FindFirst("://") == B_ERROR)
644*5bf2b6ebSBrian Hill 		return NULL;
645*5bf2b6ebSBrian Hill 	RepoRow* addedRow = NULL;
646*5bf2b6ebSBrian Hill 	int32 index;
647*5bf2b6ebSBrian Hill 	int32 listCount = fListView->CountRows();
648*5bf2b6ebSBrian Hill 	// Find if the repo already exists in list
649*5bf2b6ebSBrian Hill 	for (index = 0; index < listCount; index++) {
650*5bf2b6ebSBrian Hill 		RepoRow* repoItem = dynamic_cast<RepoRow*>(fListView->RowAt(index));
651*5bf2b6ebSBrian Hill 		if (url.ICompare(repoItem->Url()) == 0) {
652*5bf2b6ebSBrian Hill 			// update name and enabled values
653*5bf2b6ebSBrian Hill 			if (name.Compare(repoItem->Name()) != 0)
654*5bf2b6ebSBrian Hill 				repoItem->SetName(name.String());
655*5bf2b6ebSBrian Hill 			repoItem->SetEnabled(enabled);
656*5bf2b6ebSBrian Hill 			addedRow = repoItem;
657*5bf2b6ebSBrian Hill 		}
658*5bf2b6ebSBrian Hill 	}
659*5bf2b6ebSBrian Hill 	if (addedRow == NULL) {
660*5bf2b6ebSBrian Hill 		addedRow = new RepoRow(name, url, enabled);
661*5bf2b6ebSBrian Hill 		fListView->AddRow(addedRow);
662*5bf2b6ebSBrian Hill 	}
663*5bf2b6ebSBrian Hill 	return addedRow;
664*5bf2b6ebSBrian Hill }
665*5bf2b6ebSBrian Hill 
666*5bf2b6ebSBrian Hill 
667*5bf2b6ebSBrian Hill void
668*5bf2b6ebSBrian Hill RepositoriesView::_FindSiblings()
669*5bf2b6ebSBrian Hill {
670*5bf2b6ebSBrian Hill 	BStringList namesFound, namesWithSiblings;
671*5bf2b6ebSBrian Hill 	int32 index, listCount = fListView->CountRows();
672*5bf2b6ebSBrian Hill 	// Find repository names that are duplicated
673*5bf2b6ebSBrian Hill 	for (index = 0; index < listCount; index++) {
674*5bf2b6ebSBrian Hill 		RepoRow* repoItem = dynamic_cast<RepoRow*>(fListView->RowAt(index));
675*5bf2b6ebSBrian Hill 		BString name = repoItem->Name();
676*5bf2b6ebSBrian Hill 		// Ignore newly added repos since we don't know the real name yet
677*5bf2b6ebSBrian Hill 		if (name.Compare(kNewRepoDefaultName)==0)
678*5bf2b6ebSBrian Hill 			continue;
679*5bf2b6ebSBrian Hill 		// First time a name is found- no sibling (yet)
680*5bf2b6ebSBrian Hill 		if (!namesFound.HasString(name))
681*5bf2b6ebSBrian Hill 			namesFound.Add(name);
682*5bf2b6ebSBrian Hill 		// Name was already found once so this name has 2 or more siblings
683*5bf2b6ebSBrian Hill 		else if (!namesWithSiblings.HasString(name))
684*5bf2b6ebSBrian Hill 			namesWithSiblings.Add(name);
685*5bf2b6ebSBrian Hill 	}
686*5bf2b6ebSBrian Hill 	// Set sibling values for each row
687*5bf2b6ebSBrian Hill 	for (index = 0; index < listCount; index++) {
688*5bf2b6ebSBrian Hill 		RepoRow* repoItem = dynamic_cast<RepoRow*>(fListView->RowAt(index));
689*5bf2b6ebSBrian Hill 		BString name = repoItem->Name();
690*5bf2b6ebSBrian Hill 		repoItem->SetHasSiblings(namesWithSiblings.HasString(name));
691*5bf2b6ebSBrian Hill 	}
692*5bf2b6ebSBrian Hill }
693*5bf2b6ebSBrian Hill 
694*5bf2b6ebSBrian Hill 
695*5bf2b6ebSBrian Hill void
696*5bf2b6ebSBrian Hill RepositoriesView::_UpdateButtons()
697*5bf2b6ebSBrian Hill {
698*5bf2b6ebSBrian Hill 	RepoRow* rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection());
699*5bf2b6ebSBrian Hill 	// At least one row is selected
700*5bf2b6ebSBrian Hill 	if (rowItem) {
701*5bf2b6ebSBrian Hill 		bool someAreEnabled = false,
702*5bf2b6ebSBrian Hill 			someAreDisabled = false,
703*5bf2b6ebSBrian Hill 			someAreInQueue = false;
704*5bf2b6ebSBrian Hill 		int32 selectedCount = 0;
705*5bf2b6ebSBrian Hill 		RepoRow* rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection());
706*5bf2b6ebSBrian Hill 		while (rowItem) {
707*5bf2b6ebSBrian Hill 			selectedCount++;
708*5bf2b6ebSBrian Hill 			uint32 taskState = rowItem->TaskState();
709*5bf2b6ebSBrian Hill 			if ( taskState == STATE_IN_QUEUE_WAITING
710*5bf2b6ebSBrian Hill 				|| taskState == STATE_IN_QUEUE_RUNNING)
711*5bf2b6ebSBrian Hill 				someAreInQueue = true;
712*5bf2b6ebSBrian Hill 			if (rowItem->IsEnabled())
713*5bf2b6ebSBrian Hill 				someAreEnabled = true;
714*5bf2b6ebSBrian Hill 			else
715*5bf2b6ebSBrian Hill 				someAreDisabled = true;
716*5bf2b6ebSBrian Hill 			rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection(rowItem));
717*5bf2b6ebSBrian Hill 		}
718*5bf2b6ebSBrian Hill 		// Change button labels depending on which rows are selected
719*5bf2b6ebSBrian Hill 		if (selectedCount > 1) {
720*5bf2b6ebSBrian Hill 			fEnableButton->SetLabel(kLabelEnableAll);
721*5bf2b6ebSBrian Hill 			fDisableButton->SetLabel(kLabelDisableAll);
722*5bf2b6ebSBrian Hill 		} else {
723*5bf2b6ebSBrian Hill 			fEnableButton->SetLabel(kLabelEnable);
724*5bf2b6ebSBrian Hill 			fDisableButton->SetLabel(kLabelDisable);
725*5bf2b6ebSBrian Hill 		}
726*5bf2b6ebSBrian Hill 		// Set which buttons should be enabled
727*5bf2b6ebSBrian Hill 		fRemoveButton->SetEnabled(!someAreEnabled && !someAreInQueue);
728*5bf2b6ebSBrian Hill 		if ((someAreEnabled && someAreDisabled) || someAreInQueue) {
729*5bf2b6ebSBrian Hill 			// there are a mix of enabled and disabled repositories selected
730*5bf2b6ebSBrian Hill 			fEnableButton->SetEnabled(false);
731*5bf2b6ebSBrian Hill 			fDisableButton->SetEnabled(false);
732*5bf2b6ebSBrian Hill 		} else {
733*5bf2b6ebSBrian Hill 			fEnableButton->SetEnabled(someAreDisabled);
734*5bf2b6ebSBrian Hill 			fDisableButton->SetEnabled(someAreEnabled);
735*5bf2b6ebSBrian Hill 		}
736*5bf2b6ebSBrian Hill 
737*5bf2b6ebSBrian Hill 	} else {
738*5bf2b6ebSBrian Hill 		// No selected rows
739*5bf2b6ebSBrian Hill 		fEnableButton->SetLabel(kLabelEnable);
740*5bf2b6ebSBrian Hill 		fDisableButton->SetLabel(kLabelDisable);
741*5bf2b6ebSBrian Hill 		fEnableButton->SetEnabled(false);
742*5bf2b6ebSBrian Hill 		fDisableButton->SetEnabled(false);
743*5bf2b6ebSBrian Hill 		fRemoveButton->SetEnabled(false);
744*5bf2b6ebSBrian Hill 	}
745*5bf2b6ebSBrian Hill }
746*5bf2b6ebSBrian Hill 
747*5bf2b6ebSBrian Hill 
748*5bf2b6ebSBrian Hill void
749*5bf2b6ebSBrian Hill RepositoriesView::_UpdateStatusView()
750*5bf2b6ebSBrian Hill {
751*5bf2b6ebSBrian Hill 	if (fRunningTaskCount) {
752*5bf2b6ebSBrian Hill 		BString text(kStatusViewText);
753*5bf2b6ebSBrian Hill 		text.Append(" ");
754*5bf2b6ebSBrian Hill 		text << fRunningTaskCount;
755*5bf2b6ebSBrian Hill 		fListStatusView->SetText(text);
756*5bf2b6ebSBrian Hill 	} else
757*5bf2b6ebSBrian Hill 		fListStatusView->SetText("");
758*5bf2b6ebSBrian Hill }
759