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