Ticket #13147: 0001-Submitting-new-preflet-Repositories-for-consideratio.patch
File 0001-Submitting-new-preflet-Repositories-for-consideratio.patch, 77.8 KB (added by , 8 years ago) |
---|
-
new file 2001
From 895635b4c0cd4bca2b147f99d8df35a6bc5e9546 Mon Sep 17 00:00:00 2001 From: Brian Hill <supernova@warpmail.net> Date: Sun, 1 Jan 2017 17:01:37 -0500 Subject: [PATCH] Submitting new preflet Repositories for consideration. This preflet allows the user to change repositories used by package management. --- data/artwork/icons/Prefs_Repositories | Bin 0 -> 17417 bytes src/apps/haikudepot/ui/FilterView.cpp | 6 +- src/apps/haikudepot/ui/MainWindow.cpp | 24 +- src/apps/haikudepot/ui/MainWindow.h | 1 + src/preferences/Jamfile | 1 + src/preferences/repositories/AddRepoWindow.cpp | 138 ++++ src/preferences/repositories/AddRepoWindow.h | 34 + src/preferences/repositories/Jamfile | 31 + src/preferences/repositories/RepoRow.cpp | 72 ++ src/preferences/repositories/RepoRow.h | 49 ++ src/preferences/repositories/Repositories.cpp | 57 ++ src/preferences/repositories/Repositories.h | 27 + src/preferences/repositories/Repositories.rdef | 43 ++ .../repositories/RepositoriesSettings.cpp | 131 ++++ .../repositories/RepositoriesSettings.h | 40 ++ src/preferences/repositories/RepositoriesView.cpp | 763 +++++++++++++++++++++ src/preferences/repositories/RepositoriesView.h | 73 ++ .../repositories/RepositoriesWindow.cpp | 183 +++++ src/preferences/repositories/RepositoriesWindow.h | 41 ++ src/preferences/repositories/TaskLooper.cpp | 327 +++++++++ src/preferences/repositories/TaskLooper.h | 66 ++ src/preferences/repositories/TaskTimer.cpp | 174 +++++ src/preferences/repositories/TaskTimer.h | 61 ++ src/preferences/repositories/constants.h | 100 +++ 24 files changed, 2435 insertions(+), 7 deletions(-) create mode 100644 data/artwork/icons/Prefs_Repositories create mode 100644 src/preferences/repositories/AddRepoWindow.cpp create mode 100644 src/preferences/repositories/AddRepoWindow.h create mode 100644 src/preferences/repositories/Jamfile create mode 100644 src/preferences/repositories/RepoRow.cpp create mode 100644 src/preferences/repositories/RepoRow.h create mode 100644 src/preferences/repositories/Repositories.cpp create mode 100644 src/preferences/repositories/Repositories.h create mode 100644 src/preferences/repositories/Repositories.rdef create mode 100644 src/preferences/repositories/RepositoriesSettings.cpp create mode 100644 src/preferences/repositories/RepositoriesSettings.h create mode 100644 src/preferences/repositories/RepositoriesView.cpp create mode 100644 src/preferences/repositories/RepositoriesView.h create mode 100644 src/preferences/repositories/RepositoriesWindow.cpp create mode 100644 src/preferences/repositories/RepositoriesWindow.h create mode 100644 src/preferences/repositories/TaskLooper.cpp create mode 100644 src/preferences/repositories/TaskLooper.h create mode 100644 src/preferences/repositories/TaskTimer.cpp create mode 100644 src/preferences/repositories/TaskTimer.h create mode 100644 src/preferences/repositories/constants.h diff --git a/data/artwork/icons/Prefs_Repositories b/data/artwork/icons/Prefs_Repositories new file mode 100644 index 0000000000000000000000000000000000000000..75691796ba9145a755ed6596f54d2df46460f4f9 GIT binary patch literal 17417 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
-
src/apps/haikudepot/ui/FilterView.cpp
literal 0 HcmV?d00001 diff --git a/src/apps/haikudepot/ui/FilterView.cpp b/src/apps/haikudepot/ui/FilterView.cpp index e8eb056..be2d0ca 100644
a b FilterView::FilterView() 46 46 fShowField = new BMenuField("category", B_TRANSLATE("Category:"), showMenu); 47 47 48 48 // Construct repository popup 49 BPopUpMenu* repositoryMenu = new BPopUpMenu(B_TRANSLATE(" Depot"));50 fRepositoryField = new BMenuField("repository", B_TRANSLATE(" Depot:"),49 BPopUpMenu* repositoryMenu = new BPopUpMenu(B_TRANSLATE("Repository")); 50 fRepositoryField = new BMenuField("repository", B_TRANSLATE("Repository:"), 51 51 repositoryMenu); 52 52 53 53 // Construct search terms field … … FilterView::AdoptModel(const Model& model) 125 125 BMenu* repositoryMenu = fRepositoryField->Menu(); 126 126 repositoryMenu->RemoveItems(0, repositoryMenu->CountItems(), true); 127 127 128 repositoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All depots"),128 repositoryMenu->AddItem(new BMenuItem(B_TRANSLATE("All repositories"), 129 129 new BMessage(MSG_DEPOT_SELECTED))); 130 130 131 131 repositoryMenu->AddItem(new BSeparatorItem()); -
src/apps/haikudepot/ui/MainWindow.cpp
diff --git a/src/apps/haikudepot/ui/MainWindow.cpp b/src/apps/haikudepot/ui/MainWindow.cpp index 8884f54..207483c 100644
a b 24 24 #include <MenuBar.h> 25 25 #include <MenuItem.h> 26 26 #include <Messenger.h> 27 #include <Roster.h> 27 28 #include <Screen.h> 28 29 #include <ScrollView.h> 29 30 #include <StringList.h> … … 63 64 64 65 enum { 65 66 MSG_MODEL_WORKER_DONE = 'mmwd', 66 MSG_REFRESH_DEPOTS = 'mrdp', 67 MSG_REFRESH_REPOS = 'mrrp', 68 MSG_MANAGE_REPOS = 'mmrp', 67 69 MSG_LOG_IN = 'lgin', 68 70 MSG_LOG_OUT = 'lgot', 69 71 MSG_AUTHORIZATION_CHANGED = 'athc', … … MainWindow::MessageReceived(BMessage* message) 316 318 _StartRefreshWorker(false); 317 319 break; 318 320 319 case MSG_REFRESH_ DEPOTS:321 case MSG_REFRESH_REPOS: 320 322 _StartRefreshWorker(true); 321 323 break; 322 324 325 case MSG_MANAGE_REPOS: 326 _OpenRepositoriesPreflet(); 327 break; 328 323 329 case MSG_LOG_IN: 324 330 _OpenLoginWindow(BMessage()); 325 331 break; … … void 567 573 MainWindow::_BuildMenu(BMenuBar* menuBar) 568 574 { 569 575 BMenu* menu = new BMenu(B_TRANSLATE("Tools")); 570 menu->AddItem(new BMenuItem(B_TRANSLATE("Refresh depots"), 571 new BMessage(MSG_REFRESH_DEPOTS))); 576 menu->AddItem(new BMenuItem(B_TRANSLATE("Refresh repositories"), 577 new BMessage(MSG_REFRESH_REPOS))); 578 menu->AddItem(new BMenuItem(B_TRANSLATE("Manage repositories"), 579 new BMessage(MSG_MANAGE_REPOS))); 572 580 573 581 menuBar->AddItem(menu); 574 582 … … MainWindow::_StartRefreshWorker(bool force) 1100 1108 } 1101 1109 1102 1110 1111 void 1112 MainWindow::_OpenRepositoriesPreflet() 1113 { 1114 BRoster roster; 1115 roster.Launch("application/x-vnd.Haiku-Repositories"); 1116 } 1117 1118 1103 1119 status_t 1104 1120 MainWindow::_RefreshModelThreadWorker(void* arg) 1105 1121 { -
src/apps/haikudepot/ui/MainWindow.h
diff --git a/src/apps/haikudepot/ui/MainWindow.h b/src/apps/haikudepot/ui/MainWindow.h index 784350a..5064763 100644
a b private: 75 75 void _RefreshPackageList(bool force); 76 76 77 77 void _StartRefreshWorker(bool force = false); 78 void _OpenRepositoriesPreflet(); 78 79 static status_t _RefreshModelThreadWorker(void* arg); 79 80 static status_t _PackageActionWorker(void* arg); 80 81 static status_t _PopulatePackageWorker(void* arg); -
src/preferences/Jamfile
diff --git a/src/preferences/Jamfile b/src/preferences/Jamfile index 39254de..f152be4 100644
a b SubInclude HAIKU_TOP src preferences mouse ; 17 17 SubInclude HAIKU_TOP src preferences network ; 18 18 SubInclude HAIKU_TOP src preferences notifications ; 19 19 SubInclude HAIKU_TOP src preferences printers ; 20 SubInclude HAIKU_TOP src preferences repositories ; 20 21 SubInclude HAIKU_TOP src preferences screen ; 21 22 SubInclude HAIKU_TOP src preferences screensaver ; 22 23 SubInclude HAIKU_TOP src preferences shortcuts ; -
new file src/preferences/repositories/AddRepoWindow.cpp
diff --git a/src/preferences/repositories/AddRepoWindow.cpp b/src/preferences/repositories/AddRepoWindow.cpp new file mode 100644 index 0000000..9fefa56
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 9 10 #include "AddRepoWindow.h" 11 12 #include <Alert.h> 13 #include <Application.h> 14 #include <Catalog.h> 15 #include <Clipboard.h> 16 #include <LayoutBuilder.h> 17 18 #include "constants.h" 19 20 #undef B_TRANSLATION_CONTEXT 21 #define B_TRANSLATION_CONTEXT "AddRepoWindow" 22 23 static float sAddWindowWidth = 500.0; 24 25 26 AddRepoWindow::AddRepoWindow(BRect size, BLooper* looper) 27 : 28 BWindow(BRect(0, 0, sAddWindowWidth, 10), "AddWindow", B_MODAL_WINDOW, 29 B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS | B_CLOSE_ON_ESCAPE), 30 fReplyLooper(looper) 31 { 32 fView = new BView("view", B_SUPPORTS_LAYOUT); 33 fText = new BTextControl("text", B_TRANSLATE_COMMENT("Repository URL:", 34 "Text box label"), "", new BMessage(ADD_BUTTON_PRESSED)); 35 fAddButton = new BButton(B_TRANSLATE_COMMENT("Add", "Button label"), 36 new BMessage(ADD_BUTTON_PRESSED)); 37 fAddButton->MakeDefault(true); 38 fCancelButton = new BButton(kCancelLabel, 39 new BMessage(CANCEL_BUTTON_PRESSED)); 40 41 BLayoutBuilder::Group<>(fView, B_VERTICAL) 42 .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING, 43 B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING) 44 .Add(fText) 45 .AddGroup(B_HORIZONTAL, B_USE_DEFAULT_SPACING) 46 .AddGlue() 47 .Add(fCancelButton) 48 .Add(fAddButton); 49 BLayoutBuilder::Group<>(this, B_VERTICAL) 50 .Add(fView); 51 _GetClipboardData(); 52 fText->MakeFocus(); 53 54 // Move to the center of the preflet window 55 CenterIn(size); 56 float widthDifference = size.Width() - Frame().Width(); 57 if (widthDifference < 0) 58 MoveBy(widthDifference / 2.0, 0); 59 Show(); 60 } 61 62 63 void 64 AddRepoWindow::Quit() 65 { 66 fReplyLooper->PostMessage(ADD_WINDOW_CLOSED); 67 BWindow::Quit(); 68 } 69 70 71 void 72 AddRepoWindow::MessageReceived(BMessage* message) 73 { 74 switch (message->what) 75 { 76 case CANCEL_BUTTON_PRESSED: { 77 if (QuitRequested()) 78 Quit(); 79 break; 80 } 81 case ADD_BUTTON_PRESSED: { 82 BString url(fText->Text()); 83 if (url != "") { 84 // URL must have a protocol 85 if (url.FindFirst("://") == B_ERROR) { 86 BAlert* alert = new BAlert("error", 87 B_TRANSLATE_COMMENT("The URL must start with a " 88 "protocol, for example http:// or https://", 89 "Add URL error message"), 90 kOKLabel, NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); 91 alert->SetFeel(B_MODAL_APP_WINDOW_FEEL); 92 alert->Go(NULL); 93 // Center the alert to this window and move down some 94 alert->CenterIn(Frame()); 95 alert->MoveBy(0, kAddWindowOffset); 96 } else { 97 BMessage* addMessage = new BMessage(ADD_REPO_URL); 98 addMessage->AddString(key_url, url); 99 fReplyLooper->PostMessage(addMessage); 100 Quit(); 101 } 102 } 103 break; 104 } 105 default: 106 BWindow::MessageReceived(message); 107 } 108 } 109 110 111 void 112 AddRepoWindow::FrameResized(float newWidth, float newHeight) 113 { 114 sAddWindowWidth = newWidth; 115 } 116 117 118 status_t 119 AddRepoWindow::_GetClipboardData() 120 { 121 if (be_clipboard->Lock()) { 122 const char* string; 123 ssize_t stringLen; 124 BMessage* clip = be_clipboard->Data(); 125 clip->FindData("text/plain", B_MIME_TYPE, (const void **)&string, 126 &stringLen); 127 be_clipboard->Unlock(); 128 129 // The string must contain a web protocol 130 BString clipString(string, stringLen); 131 int32 ww = clipString.FindFirst("://"); 132 if (ww == B_ERROR) 133 return B_ERROR; 134 else 135 fText->SetText(clipString); 136 } 137 return B_OK; 138 } -
new file src/preferences/repositories/AddRepoWindow.h
diff --git a/src/preferences/repositories/AddRepoWindow.h b/src/preferences/repositories/AddRepoWindow.h new file mode 100644 index 0000000..8a9f092
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 #ifndef ADD_REPO_WINDOW_H 9 #define ADD_REPO_WINDOW_H 10 11 12 #include <Button.h> 13 #include <TextControl.h> 14 #include <View.h> 15 #include <Window.h> 16 17 18 class AddRepoWindow : public BWindow { 19 public: 20 AddRepoWindow(BRect size, BLooper* looper); 21 virtual void MessageReceived(BMessage*); 22 virtual void Quit(); 23 virtual void FrameResized(float newWidth, float newHeight); 24 25 private: 26 BView *fView; 27 BTextControl *fText; 28 BButton *fAddButton, *fCancelButton; 29 BLooper *fReplyLooper; 30 status_t _GetClipboardData(); 31 }; 32 33 34 #endif -
new file src/preferences/repositories/Jamfile
diff --git a/src/preferences/repositories/Jamfile b/src/preferences/repositories/Jamfile new file mode 100644 index 0000000..c53e076
- + 1 SubDir HAIKU_TOP src preferences repositories ; 2 3 UsePrivateHeaders interface ; 4 UsePrivateHeaders package ; 5 6 Preference Repositories : 7 AddRepoWindow.cpp 8 RepoRow.cpp 9 Repositories.cpp 10 RepositoriesView.cpp 11 RepositoriesWindow.cpp 12 RepositoriesSettings.cpp 13 TaskLooper.cpp 14 TaskTimer.cpp 15 : be translation package libcolumnlistview.a [ TargetLibstdc++ ] localestub 16 : Repositories.rdef 17 ; 18 19 Depends Repositories : libcolumnlistview.a ; 20 21 DoCatalogs Repositories : 22 x-vnd.Haiku-Repositories 23 : 24 AddRepoWindow.cpp 25 constants.h 26 Repositories.cpp 27 RepositoriesView.cpp 28 RepositoriesWindow.cpp 29 TaskLooper.cpp 30 TaskTimer.cpp 31 ; -
new file src/preferences/repositories/RepoRow.cpp
diff --git a/src/preferences/repositories/RepoRow.cpp b/src/preferences/repositories/RepoRow.cpp new file mode 100644 index 0000000..32768f7
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 9 10 #include "RepoRow.h" 11 12 #include <ColumnTypes.h> 13 14 #include "constants.h" 15 16 17 #undef B_TRANSLATION_CONTEXT 18 #define B_TRANSLATION_CONTEXT "RepoRow" 19 20 21 RepoRow::RepoRow(const char* repo_name, const char* repo_url, bool enabled) 22 : 23 BRow(), 24 fName(repo_name), 25 fUrl(repo_url), 26 fEnabled(enabled), 27 fTaskState(STATE_NOT_IN_QUEUE) 28 { 29 SetField(new BStringField(""), kEnabledColumn); 30 SetField(new BStringField(fName.String()), kNameColumn); 31 SetField(new BStringField(fUrl.String()), kUrlColumn); 32 if (enabled) 33 SetEnabled(enabled); 34 } 35 36 37 void 38 RepoRow::SetName(const char* name) 39 { 40 BStringField* field = (BStringField*)GetField(kNameColumn); 41 field->SetString(name); 42 fName.SetTo(name); 43 Invalidate(); 44 } 45 46 47 void 48 RepoRow::SetEnabled(bool enabled) 49 { 50 fEnabled = enabled; 51 RefreshEnabledField(); 52 } 53 54 55 void 56 RepoRow::RefreshEnabledField() 57 { 58 BStringField* field = (BStringField*)GetField(kEnabledColumn); 59 if (fTaskState == STATE_NOT_IN_QUEUE) 60 field->SetString(fEnabled ? "\xE2\x9C\x94" : ""); 61 else 62 field->SetString(B_UTF8_ELLIPSIS); 63 Invalidate(); 64 } 65 66 67 void 68 RepoRow::SetTaskState(uint32 state) 69 { 70 fTaskState = state; 71 RefreshEnabledField(); 72 } -
new file src/preferences/repositories/RepoRow.h
diff --git a/src/preferences/repositories/RepoRow.h b/src/preferences/repositories/RepoRow.h new file mode 100644 index 0000000..d19c8cc
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 #ifndef REPO_ROW_H 9 #define REPO_ROW_H 10 11 12 #include <ColumnListView.h> 13 #include <String.h> 14 15 16 enum { 17 kEnabledColumn, 18 kNameColumn, 19 kUrlColumn 20 }; 21 22 23 class RepoRow : public BRow { 24 public: 25 RepoRow(const char* repo_name, 26 const char* repo_url, bool enabled); 27 28 const char* Name() const { return fName.String(); } 29 void SetName(const char* name); 30 const char* Url() const { return fUrl.String(); } 31 void SetEnabled(bool enabled); 32 void RefreshEnabledField(); 33 bool IsEnabled() { return fEnabled; } 34 void SetTaskState(uint32 state); 35 uint32 TaskState() { return fTaskState; } 36 void SetHasSiblings(bool hasSiblings) 37 { fHasSiblings = hasSiblings; } 38 bool HasSiblings() { return fHasSiblings; } 39 40 private: 41 BString fName; 42 BString fUrl; 43 bool fEnabled; 44 uint32 fTaskState; 45 bool fHasSiblings; 46 }; 47 48 49 #endif -
new file src/preferences/repositories/Repositories.cpp
diff --git a/src/preferences/repositories/Repositories.cpp b/src/preferences/repositories/Repositories.cpp new file mode 100644 index 0000000..ae09388
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 9 10 #include "Repositories.h" 11 12 #include <Alert.h> 13 #include <Catalog.h> 14 #include <Cursor.h> 15 #include <LayoutBuilder.h> 16 #include <Roster.h> 17 18 #include "constants.h" 19 20 #undef B_TRANSLATION_CONTEXT 21 #define B_TRANSLATION_CONTEXT "RepositoriesApplication" 22 23 const char* kAppSignature = "application/x-vnd.Haiku-Repositories"; 24 25 26 RepositoriesApplication::RepositoriesApplication() 27 : 28 BApplication(kAppSignature) 29 { 30 fWindow = new RepositoriesWindow(); 31 } 32 33 34 void 35 RepositoriesApplication::AboutRequested() 36 { 37 BString text(B_TRANSLATE_COMMENT("Repositories, written by Brian Hill", 38 "About box line 1")); 39 text.Append("\n\n") 40 .Append(B_TRANSLATE_COMMENT("Copyright ©2017, Haiku.", 41 "About box line 2")) 42 .Append("\n\n") 43 .Append(B_TRANSLATE_COMMENT("This preflet will enable and disable " 44 "repositories used with Haiku package management.", "About box line 3")); 45 BAlert* aboutAlert = new BAlert("About", text, kOKLabel); 46 aboutAlert->SetFlags(aboutAlert->Flags() | B_CLOSE_ON_ESCAPE); 47 aboutAlert->Go(); 48 } 49 50 51 int 52 main() 53 { 54 RepositoriesApplication myApp; 55 myApp.Run(); 56 return 0; 57 } -
new file src/preferences/repositories/Repositories.h
diff --git a/src/preferences/repositories/Repositories.h b/src/preferences/repositories/Repositories.h new file mode 100644 index 0000000..3ccde25
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 #ifndef REPOSITORIES_H 9 #define REPOSITORIES_H 10 11 12 #include <Application.h> 13 14 #include "RepositoriesWindow.h" 15 16 17 class RepositoriesApplication : public BApplication { 18 public: 19 RepositoriesApplication(); 20 virtual void AboutRequested(); 21 22 private: 23 RepositoriesWindow *fWindow; 24 }; 25 26 27 #endif -
new file src/preferences/repositories/Repositories.rdef
diff --git a/src/preferences/repositories/Repositories.rdef b/src/preferences/repositories/Repositories.rdef new file mode 100644 index 0000000..e1b1be7
- + 1 2 resource app_signature "application/x-vnd.Haiku-Repositories"; 3 4 resource app_name_catalog_entry "x-vnd.Haiku-Repositories:System name:Repositories"; 5 6 resource app_flags B_SINGLE_LAUNCH; 7 8 resource app_version { 9 major = 1, 10 middle = 0, 11 minor = 0, 12 13 /* 0 = development 1 = alpha 2 = beta 14 3 = gamma 4 = golden master 5 = final */ 15 variety = 2, 16 17 internal = 0, 18 19 short_info = "Repositories", 20 long_info = "Repositories ©2017 Haiku" 21 }; 22 23 24 resource vector_icon { 25 $"6E6369660C03010000020006023B9FE037664CBA16573E39B04A01E3449F7E00" 26 $"FFFFFFFFEBEFFF020006023C96323A4D3FBAFC013D5A974B57A549844D00C1CC" 27 $"FFFFFFFFFF02000602BA40DA3C98EBBD5E1FBAEBF04A3DF04AD89600C1CCFFFF" 28 $"FDFDFD0401800500020006023C43C6B9E5E23A85A83CEE414268F44A445900C6" 29 $"D7F5FF6B94DD020006023C71E33A0C78BA15E43C7D2149055549455700E3EDFF" 30 $"FF9EC2FF03003CB0030D29640401740401D30B0A062235224044525A3A5A3139" 31 $"250A04223544465A3139250A04444644525A3A5A310A0422352240445244460A" 32 $"0544544955603C593A593C0A05305E376046513B4E3E510A0622422254325C3E" 33 $"513E402E3A0A0422422254325C32490A04224232493E402E3A0A043249325C3E" 34 $"513E400604672645264426464B284C46120A04010420202B0A00010030202B01" 35 $"178300040A01010120202B0A02010220202B0A03010320202B0A0A010502403F" 36 $"3500000000000040268D4707E6C919420A0501061A403F350000000000004026" 37 $"8D4707E6C9194215FF01178400040A0501061A403F3500000000000040268D47" 38 $"07E6C91942001501178600040A06010702403F3500000000000040268D4707E6" 39 $"C919420A08010902403F3500000000000040268D4707E6C919420A0701080240" 40 $"3F3500000000000040268D4707E6C919420A0B010A000A0B010A2024220A0B01" 41 $"0A2028240A0B010A202C260A0B010A2030280A0B010A20342A0A0B010A20382C" 42 }; 43 -
new file src/preferences/repositories/RepositoriesSettings.cpp
diff --git a/src/preferences/repositories/RepositoriesSettings.cpp b/src/preferences/repositories/RepositoriesSettings.cpp new file mode 100644 index 0000000..ab21133
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 9 10 #include "RepositoriesSettings.h" 11 12 #include <FindDirectory.h> 13 #include <StringList.h> 14 15 #include "constants.h" 16 17 #undef B_TRANSLATION_CONTEXT 18 #define B_TRANSLATION_CONTEXT "RepositoriesSettings" 19 20 const char* settingsFilename = "Repositories_settings"; 21 22 23 RepositoriesSettings::RepositoriesSettings() 24 { 25 status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &fFilePath); 26 if (status == B_OK) 27 status = fFilePath.Append(settingsFilename); 28 BEntry fileEntry(fFilePath.Path()); 29 if (!fileEntry.Exists()) { 30 // Create default repos 31 BStringList nameList, urlList; 32 int32 count = (sizeof(kDefaultRepos) / sizeof(Repository)); 33 for (int16 index = 0; index < count; index++) { 34 nameList.Add(kDefaultRepos[index].name); 35 urlList.Add(kDefaultRepos[index].url); 36 } 37 SetRepositories(nameList, urlList); 38 } 39 fInitStatus = status; 40 } 41 42 43 BRect 44 RepositoriesSettings::GetFrame() 45 { 46 BMessage settings(_ReadFromFile()); 47 BRect frame; 48 status_t status = settings.FindRect(key_frame, &frame); 49 // Set default off screen so it will center itself 50 if (status != B_OK) 51 frame.Set(-10, -10, 750, 300); 52 return frame; 53 } 54 55 56 void 57 RepositoriesSettings::SetFrame(BRect frame) 58 { 59 BMessage settings(_ReadFromFile()); 60 settings.RemoveData(key_frame); 61 settings.AddRect(key_frame, frame); 62 _SaveToFile(settings); 63 } 64 65 66 status_t 67 RepositoriesSettings::GetRepositories(int32& repoCount, BStringList& nameList, 68 BStringList& urlList) 69 { 70 BMessage settings(_ReadFromFile()); 71 type_code type; 72 int32 count; 73 settings.GetInfo(key_name, &type, &count); 74 75 status_t result = B_OK; 76 int32 index, total = 0; 77 BString foundName, foundUrl; 78 // get each repository and add to lists 79 for (index = 0; index < count; index++) { 80 status_t result1 = settings.FindString(key_name, index, &foundName); 81 status_t result2 = settings.FindString(key_url, index, &foundUrl); 82 if (result1 == B_OK && result2 == B_OK) { 83 nameList.Add(foundName); 84 urlList.Add(foundUrl); 85 total++; 86 } else 87 result = B_ERROR; 88 } 89 repoCount = total; 90 return result; 91 } 92 93 94 void 95 RepositoriesSettings::SetRepositories(BStringList& nameList, BStringList& urlList) 96 { 97 BMessage settings(_ReadFromFile()); 98 settings.RemoveName(key_name); 99 settings.RemoveName(key_url); 100 101 int32 index, count = nameList.CountStrings(); 102 for (index = 0; index < count; index++) { 103 settings.AddString(key_name, nameList.StringAt(index)); 104 settings.AddString(key_url, urlList.StringAt(index)); 105 } 106 _SaveToFile(settings); 107 } 108 109 110 BMessage 111 RepositoriesSettings::_ReadFromFile() 112 { 113 BMessage settings; 114 status_t status = fFile.SetTo(fFilePath.Path(), B_READ_ONLY); 115 if (status == B_OK) 116 status = settings.Unflatten(&fFile); 117 fFile.Unset(); 118 return settings; 119 } 120 121 122 status_t 123 RepositoriesSettings::_SaveToFile(BMessage settings) 124 { 125 status_t status = fFile.SetTo(fFilePath.Path(), 126 B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); 127 if (status == B_OK) 128 status = settings.Flatten(&fFile); 129 fFile.Unset(); 130 return status; 131 } -
new file src/preferences/repositories/RepositoriesSettings.h
diff --git a/src/preferences/repositories/RepositoriesSettings.h b/src/preferences/repositories/RepositoriesSettings.h new file mode 100644 index 0000000..8ceae1f
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 #ifndef REPOSITORIES_SETTINGS_H 9 #define REPOSITORIES_SETTINGS_H 10 11 12 #include <File.h> 13 #include <Message.h> 14 #include <Path.h> 15 #include <Point.h> 16 #include <Rect.h> 17 #include <String.h> 18 #include <StringList.h> 19 20 21 class RepositoriesSettings { 22 public: 23 RepositoriesSettings(); 24 BRect GetFrame(); 25 void SetFrame(BRect frame); 26 status_t GetRepositories(int32& repoCount, 27 BStringList& nameList, BStringList& urlList); 28 void SetRepositories(BStringList& nameList, 29 BStringList& urlList); 30 31 private: 32 BPath fFilePath; 33 BFile fFile; 34 status_t fInitStatus; 35 BMessage _ReadFromFile(); 36 status_t _SaveToFile(BMessage settings); 37 }; 38 39 40 #endif -
new file src/preferences/repositories/RepositoriesView.cpp
diff --git a/src/preferences/repositories/RepositoriesView.cpp b/src/preferences/repositories/RepositoriesView.cpp new file mode 100644 index 0000000..a4b2a71
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 9 10 #include "RepositoriesView.h" 11 12 #include <stdlib.h> 13 #include <Alert.h> 14 #include <Button.h> 15 #include <Catalog.h> 16 #include <ColumnTypes.h> 17 #include <LayoutBuilder.h> 18 #include <MessageRunner.h> 19 #include <ScrollBar.h> 20 #include <SeparatorView.h> 21 #include <package/PackageRoster.h> 22 #include <package/RepositoryConfig.h> 23 24 #include "constants.h" 25 26 #undef B_TRANSLATION_CONTEXT 27 #define B_TRANSLATION_CONTEXT "RepositoriesView" 28 29 30 static const BString kTitleEnabled = 31 B_TRANSLATE_COMMENT("Enabled", "Column title"); 32 static const BString kTitleName = B_TRANSLATE_COMMENT("Name", "Column title"); 33 static const BString kTitleUrl = B_TRANSLATE_COMMENT("URL", "Column title"); 34 static const BString kLabelRemove = 35 B_TRANSLATE_COMMENT("Remove", "Button label"); 36 static const BString kLabelRemoveAll = 37 B_TRANSLATE_COMMENT("Remove All", "Button label"); 38 static const BString kLabelEnable = 39 B_TRANSLATE_COMMENT("Enable", "Button label"); 40 static const BString kLabelEnableAll = 41 B_TRANSLATE_COMMENT("Enable All", "Button label"); 42 static const BString kLabelDisable = 43 B_TRANSLATE_COMMENT("Disable", "Button label"); 44 static const BString kLabelDisableAll = 45 B_TRANSLATE_COMMENT("Disable All", "Button label"); 46 static const BString kStatusViewText = 47 B_TRANSLATE_COMMENT("Changes pending:", "Status view text"); 48 static const BString kStatusCompletedText = 49 B_TRANSLATE_COMMENT("Changes completed", "Status view text"); 50 51 52 RepositoriesListView::RepositoriesListView(const char* name) 53 : 54 BColumnListView(name, B_NAVIGABLE, B_PLAIN_BORDER) 55 { 56 } 57 58 59 void 60 RepositoriesListView::KeyDown (const char* bytes, int32 numBytes) 61 { 62 switch (bytes[0]) { 63 case B_DELETE: 64 { 65 Window()->PostMessage(DELETE_KEY_PRESSED); 66 break; 67 } 68 default: 69 BColumnListView::KeyDown(bytes, numBytes); 70 } 71 } 72 73 74 RepositoriesView::RepositoriesView() 75 : 76 BView("RepositoriesView", B_SUPPORTS_LAYOUT), 77 fTaskLooper(NULL), 78 fShowCompletedStatus(false), 79 fRunningTaskCount(0), 80 fLastCompletedTimerId(0) 81 { 82 // Column list view with 3 columns 83 fListView = new RepositoriesListView("list"); 84 fListView->SetSelectionMessage(new BMessage(LIST_SELECTION_CHANGED)); 85 float col0width = be_plain_font->StringWidth(kTitleEnabled) + 15; 86 float col1width = be_plain_font->StringWidth(kTitleName) + 15; 87 float col2width = be_plain_font->StringWidth(kTitleUrl) + 15; 88 fListView->AddColumn(new BStringColumn(kTitleEnabled, col0width, col0width, 89 col0width, B_TRUNCATE_END, B_ALIGN_CENTER), kEnabledColumn); 90 fListView->AddColumn(new BStringColumn(kTitleName, 90, col1width, 300, 91 B_TRUNCATE_END), kNameColumn); 92 fListView->AddColumn(new BStringColumn(kTitleUrl, 500, col2width, 5000, 93 B_TRUNCATE_END), kUrlColumn); 94 fListView->SetInvocationMessage(new BMessage(ITEM_INVOKED)); 95 96 // Repository list status view 97 fStatusContainerView = new BView("status", B_SUPPORTS_LAYOUT); 98 BString templateText(kStatusViewText); 99 templateText.Append(" 88"); 100 // Simulate a status text with two digit queue count 101 fListStatusView = new BStringView("status", templateText); 102 103 // Set a smaller fixed font size and slightly lighten text color 104 BFont font(be_plain_font); 105 font.SetSize(10.0f); 106 fListStatusView->SetFont(&font, B_FONT_SIZE); 107 fListStatusView->SetHighUIColor(fListStatusView->HighUIColor(), .9f); 108 109 // Set appropriate explicit view sizes 110 float viewWidth = max_c(fListStatusView->StringWidth(templateText), 111 fListStatusView->StringWidth(kStatusCompletedText)); 112 BSize statusViewSize(viewWidth + 3, B_H_SCROLL_BAR_HEIGHT - 2); 113 fListStatusView->SetExplicitSize(statusViewSize); 114 statusViewSize.height += 1; 115 fStatusContainerView->SetExplicitSize(statusViewSize); 116 BLayoutBuilder::Group<>(fStatusContainerView, B_HORIZONTAL, 0) 117 .Add(new BSeparatorView(B_VERTICAL)) 118 .AddGroup(B_VERTICAL, 0) 119 .AddGlue() 120 .AddGroup(B_HORIZONTAL, 0) 121 .SetInsets(2, 0, 0, 0) 122 .Add(fListStatusView) 123 .AddGlue() 124 .End() 125 .Add(new BSeparatorView(B_HORIZONTAL)) 126 .End(); 127 fListView->AddStatusView(fStatusContainerView); 128 129 // Standard buttons 130 fEnableButton = new BButton(kLabelEnable, 131 new BMessage(ENABLE_BUTTON_PRESSED)); 132 fDisableButton = new BButton(kLabelDisable, 133 new BMessage(DISABLE_BUTTON_PRESSED)); 134 135 // Create buttons with fixed size 136 font_height fontHeight; 137 GetFontHeight(&fontHeight); 138 int16 buttonHeight = int16(fontHeight.ascent + fontHeight.descent + 12); 139 // button size determined by font size 140 BSize btnSize(buttonHeight, buttonHeight); 141 142 fAddButton = new BButton("plus", "+", new BMessage(ADD_REPO_WINDOW)); 143 fAddButton->SetExplicitSize(btnSize); 144 fRemoveButton = new BButton("minus", "-", new BMessage(REMOVE_REPOS)); 145 fRemoveButton->SetExplicitSize(btnSize); 146 fAboutButton = new BButton("about", "?", new BMessage(SHOW_ABOUT)); 147 fAboutButton->SetExplicitSize(btnSize); 148 149 // Layout 150 int16 buttonSpacing = 1; 151 BLayoutBuilder::Group<>(this, B_VERTICAL, 0) 152 .SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING, 153 B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING) 154 .AddGroup(B_HORIZONTAL, 0, 0.0) 155 .Add(new BStringView("instruction", 156 B_TRANSLATE_COMMENT("Select repositories to use with Haiku package "\ 157 "management:", "Label text")), 0.0) 158 .AddGlue() 159 .Add(fAboutButton, 0.0) 160 .End() 161 .AddStrut(3) 162 .Add(fListView, 1) 163 .AddGroup(B_HORIZONTAL, 0, 0.0) 164 // Add and Remove buttons 165 .AddGroup(B_VERTICAL, 0, 0.0) 166 .AddGroup(B_HORIZONTAL, 0, 0.0) 167 .Add(new BSeparatorView(B_VERTICAL)) 168 .AddGroup(B_VERTICAL, 0, 0.0) 169 .AddGroup(B_HORIZONTAL, buttonSpacing, 0.0) 170 .SetInsets(buttonSpacing) 171 .Add(fAddButton) 172 .Add(fRemoveButton) 173 .End() 174 .Add(new BSeparatorView(B_HORIZONTAL)) 175 .End() 176 .Add(new BSeparatorView(B_VERTICAL)) 177 .End() 178 .AddGlue() 179 .End() 180 // Enable and Disable buttons 181 .AddGroup(B_HORIZONTAL) 182 .SetInsets(B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, 183 B_USE_DEFAULT_SPACING, 0) 184 .AddGlue() 185 .Add(fEnableButton) 186 .Add(fDisableButton) 187 .End() 188 .End(); 189 } 190 191 192 RepositoriesView::~RepositoriesView() 193 { 194 if (fTaskLooper) { 195 fTaskLooper->Lock(); 196 fTaskLooper->Quit(); 197 } 198 _EmptyList(); 199 } 200 201 202 void 203 RepositoriesView::AllAttached() 204 { 205 BView::AllAttached(); 206 fRemoveButton->SetTarget(this); 207 fEnableButton->SetTarget(this); 208 fDisableButton->SetTarget(this); 209 fListView->SetTarget(this); 210 fRemoveButton->SetEnabled(false); 211 fEnableButton->SetEnabled(false); 212 fDisableButton->SetEnabled(false); 213 _UpdateStatusView(); 214 _InitList(); 215 } 216 217 218 void 219 RepositoriesView::AttachedToWindow() 220 { 221 fTaskLooper = new TaskLooper(Window()); 222 } 223 224 225 void 226 RepositoriesView::MessageReceived(BMessage* message) 227 { 228 switch (message->what) 229 { 230 case REMOVE_REPOS :{ 231 RepoRow* rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection()); 232 if (!rowItem || !fRemoveButton->IsEnabled()) 233 break; 234 235 BString text; 236 // More than one selected row 237 if (fListView->CurrentSelection(rowItem)) { 238 text.SetTo(B_TRANSLATE_COMMENT("Remove these repositories?", 239 "Removal alert confirmation message")); 240 text.Append("\n"); 241 } 242 // Only one selected row 243 else { 244 text.SetTo(B_TRANSLATE_COMMENT("Remove this repository?", 245 "Removal alert confirmation message")); 246 text.Append("\n"); 247 } 248 float minWidth = 0; 249 while (rowItem) { 250 BString repoText; 251 repoText.Append("\n").Append(rowItem->Name()) 252 .Append(" (").Append(rowItem->Url()).Append(")"); 253 minWidth = max_c(minWidth, StringWidth(repoText.String())); 254 text.Append(repoText); 255 rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection(rowItem)); 256 } 257 minWidth = min_c(minWidth, Frame().Width()); 258 // Ensure alert window isn't much larger than the main window 259 BAlert* alert = new BAlert("confirm", text, kRemoveLabel, 260 kCancelLabel, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 261 alert->TextView()->SetExplicitMinSize(BSize(minWidth, B_SIZE_UNSET)); 262 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 263 int32 answer = alert->Go(); 264 // User presses Cancel button 265 if (answer) 266 break; 267 268 rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection()); 269 while (rowItem) { 270 RepoRow* oldRow = rowItem; 271 rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection(rowItem)); 272 fListView->RemoveRow(oldRow); 273 delete oldRow; 274 } 275 _SaveList(); 276 break; 277 } 278 case LIST_SELECTION_CHANGED: { 279 _UpdateButtons(); 280 break; 281 } 282 case ITEM_INVOKED: { 283 // Simulates pressing whichever is the enabled button 284 if (fEnableButton->IsEnabled()) { 285 BMessage invokeMessage(ENABLE_BUTTON_PRESSED); 286 MessageReceived(&invokeMessage); 287 } else if (fDisableButton->IsEnabled()) { 288 BMessage invokeMessage(DISABLE_BUTTON_PRESSED); 289 MessageReceived(&invokeMessage); 290 } 291 break; 292 } 293 case ENABLE_BUTTON_PRESSED: { 294 BStringList names; 295 bool paramsOK = true; 296 // Check if there are multiple selections of the same repository, 297 // pkgman won't like that 298 RepoRow* rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection()); 299 while (rowItem) 300 { 301 if (names.HasString(rowItem->Name()) 302 && kNewRepoDefaultName.Compare(rowItem->Name()) != 0) { 303 (new BAlert("duplicate", 304 B_TRANSLATE_COMMENT("Only one URL for each repository can " 305 "be enabled. Please change your selections.", 306 "Error message"), 307 kOKLabel, NULL, NULL, 308 B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go(NULL); 309 paramsOK = false; 310 break; 311 } else 312 names.Add(rowItem->Name()); 313 rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection(rowItem)); 314 } 315 if (paramsOK) { 316 _AddSelectedRowsToQueue(); 317 _UpdateButtons(); 318 } 319 break; 320 } 321 case DISABLE_BUTTON_PRESSED: { 322 _AddSelectedRowsToQueue(); 323 _UpdateButtons(); 324 break; 325 } 326 case TASK_STARTED: { 327 int16 count; 328 status_t result1 = message->FindInt16(key_count, &count); 329 RepoRow* rowItem; 330 status_t result2 = message->FindPointer(key_rowptr, (void**)&rowItem); 331 if (result1 == B_OK && result2 == B_OK) 332 _TaskStarted(rowItem, count); 333 break; 334 } 335 case TASK_COMPLETED_WITH_ERRORS: { 336 BString errorDetails; 337 status_t result = message->FindString(key_details, &errorDetails); 338 if (result == B_OK) { 339 (new BAlert("error", errorDetails, kOKLabel, NULL, NULL, 340 B_WIDTH_AS_USUAL, B_STOP_ALERT))->Go(NULL); 341 } 342 BString repoName = message->GetString(key_name, 343 kNewRepoDefaultName.String()); 344 int16 count; 345 status_t result1 = message->FindInt16(key_count, &count); 346 RepoRow* rowItem; 347 status_t result2 = message->FindPointer(key_rowptr, (void**)&rowItem); 348 if (result1 == B_OK && result2 == B_OK) { 349 _TaskCompleted(rowItem, count, repoName); 350 // Refresh the enabled status of each row since it is unsure what 351 // caused the error 352 _RefreshList(); 353 } 354 _UpdateButtons(); 355 break; 356 } 357 case TASK_COMPLETED: { 358 BString repoName = message->GetString(key_name, 359 kNewRepoDefaultName.String()); 360 int16 count; 361 status_t result1 = message->FindInt16(key_count, &count); 362 RepoRow* rowItem; 363 status_t result2 = message->FindPointer(key_rowptr, (void**)&rowItem); 364 if (result1 == B_OK && result2 == B_OK) { 365 _TaskCompleted(rowItem, count, repoName); 366 // If the completed row has siblings then enabling this row may 367 // have disabled one of the other siblings, do full refresh. 368 if (rowItem->HasSiblings() && rowItem->IsEnabled()) 369 _RefreshList(); 370 } 371 _UpdateButtons(); 372 break; 373 } 374 case TASK_CANCELED: { 375 int16 count; 376 status_t result1 = message->FindInt16(key_count, &count); 377 RepoRow* rowItem; 378 status_t result2 = message->FindPointer(key_rowptr, (void**)&rowItem); 379 if (result1 == B_OK && result2 == B_OK) 380 _TaskCanceled(rowItem, count); 381 // Refresh the enabled status of each row since it is unsure what 382 // caused the cancelation 383 _RefreshList(); 384 _UpdateButtons(); 385 break; 386 } 387 case UPDATE_LIST: { 388 _RefreshList(); 389 _UpdateButtons(); 390 break; 391 } 392 case STATUS_VIEW_COMPLETED_TIMEOUT: { 393 int32 timerID; 394 status_t result = message->FindInt32(key_ID, &timerID); 395 if (result == B_OK && timerID == fLastCompletedTimerId) 396 _UpdateStatusView(); 397 break; 398 } 399 default: 400 BView::MessageReceived(message); 401 } 402 } 403 404 405 void 406 RepositoriesView::_AddSelectedRowsToQueue() 407 { 408 RepoRow* rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection()); 409 while (rowItem) { 410 rowItem->SetTaskState(STATE_IN_QUEUE_WAITING); 411 BMessage taskMessage(DO_TASK); 412 taskMessage.AddPointer(key_rowptr, rowItem); 413 fTaskLooper->PostMessage(&taskMessage); 414 rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection(rowItem)); 415 } 416 } 417 418 419 void 420 RepositoriesView::_TaskStarted(RepoRow* rowItem, int16 count) 421 { 422 fRunningTaskCount = count; 423 rowItem->SetTaskState(STATE_IN_QUEUE_RUNNING); 424 // Only present a status count if there is more than one task in queue 425 if (count > 1) { 426 _UpdateStatusView(); 427 fShowCompletedStatus = true; 428 } 429 } 430 431 432 void 433 RepositoriesView::_TaskCompleted(RepoRow* rowItem, int16 count, BString& newName) 434 { 435 fRunningTaskCount = count; 436 _ShowCompletedStatusIfDone(); 437 438 // Update row state and values 439 rowItem->SetTaskState(STATE_NOT_IN_QUEUE); 440 if (kNewRepoDefaultName.Compare(rowItem->Name()) == 0 441 && newName.Compare("") != 0) 442 rowItem->SetName(newName.String()); 443 _UpdateFromRepoConfig(rowItem); 444 } 445 446 447 void 448 RepositoriesView::_TaskCanceled(RepoRow* rowItem, int16 count) 449 { 450 fRunningTaskCount = count; 451 _ShowCompletedStatusIfDone(); 452 453 // Update row state and values 454 rowItem->SetTaskState(STATE_NOT_IN_QUEUE); 455 _UpdateFromRepoConfig(rowItem); 456 } 457 458 459 void 460 RepositoriesView::_ShowCompletedStatusIfDone() 461 { 462 // If this is the last task show completed status text for 3 seconds 463 if (fRunningTaskCount == 0 && fShowCompletedStatus) { 464 fListStatusView->SetText(kStatusCompletedText); 465 fLastCompletedTimerId = rand(); 466 BMessage timerMessage(STATUS_VIEW_COMPLETED_TIMEOUT); 467 timerMessage.AddInt32(key_ID, fLastCompletedTimerId); 468 new BMessageRunner(this, &timerMessage, 3000000, 1); 469 fShowCompletedStatus = false; 470 } else 471 _UpdateStatusView(); 472 } 473 474 475 void 476 RepositoriesView::_UpdateFromRepoConfig(RepoRow* rowItem) 477 { 478 BPackageKit::BPackageRoster pRoster; 479 BPackageKit::BRepositoryConfig repoConfig; 480 BString repoName(rowItem->Name()); 481 status_t result = pRoster.GetRepositoryConfig(repoName, &repoConfig); 482 // Repo name was found and the URL matches 483 if (result == B_OK && repoConfig.BaseURL().Compare(rowItem->Url())==0) 484 rowItem->SetEnabled(true); 485 else 486 rowItem->SetEnabled(false); 487 } 488 489 490 void 491 RepositoriesView::AddManualRepository(BString url) 492 { 493 BString name(kNewRepoDefaultName); 494 BString rootUrl = _GetRootUrl(url); 495 bool foundRoot = false; 496 int32 index; 497 int32 listCount = fListView->CountRows(); 498 for (index = 0; index < listCount; index++) 499 { 500 RepoRow* repoItem = dynamic_cast<RepoRow*>((fListView->RowAt(index))); 501 const char* urlPtr = repoItem->Url(); 502 // Find an already existing URL 503 if (url.ICompare(urlPtr) == 0) { 504 (new BAlert("duplicate", 505 B_TRANSLATE_COMMENT("This repository URL already exists.", 506 "Error message"), 507 kOKLabel))->Go(NULL); 508 return; 509 } 510 // Use the same name from another repo with the same root url 511 if (foundRoot == false && rootUrl.ICompare(urlPtr, 512 rootUrl.Length()) == 0) { 513 foundRoot = true; 514 name = repoItem->Name(); 515 } 516 } 517 RepoRow* newRepo = _AddRepo(name, url, false); 518 _FindSiblings(); 519 fListView->DeselectAll(); 520 fListView->AddToSelection(newRepo); 521 _UpdateButtons(); 522 _SaveList(); 523 } 524 525 526 BString 527 RepositoriesView::_GetRootUrl(BString url) 528 { 529 // Find the protocol if it exists 530 int32 ww = url.FindFirst("://"); 531 if (ww == B_ERROR) 532 ww = 0; 533 else 534 ww += 3; 535 // Find second / 536 int32 rootEnd = url.FindFirst("/", ww + 1); 537 if (rootEnd == B_ERROR) 538 return url; 539 rootEnd = url.FindFirst("/", rootEnd + 1); 540 if (rootEnd == B_ERROR) 541 return url; 542 else 543 return url.Truncate(rootEnd); 544 } 545 546 547 status_t 548 RepositoriesView::_EmptyList() 549 { 550 BRow* row; 551 while ((row = fListView->RowAt((int32)0, NULL)) != NULL) { 552 fListView->RemoveRow(row); 553 delete row; 554 } 555 return B_OK; 556 } 557 558 559 void 560 RepositoriesView::_InitList() 561 { 562 // Get list of known repositories from the settings file 563 int32 index, repoCount; 564 BStringList nameList, urlList; 565 status_t result = fSettings.GetRepositories(repoCount, nameList, urlList); 566 if (result == B_OK) { 567 BString name, url; 568 for (index = 0; index < repoCount; index++) 569 { 570 name = nameList.StringAt(index); 571 url = urlList.StringAt(index); 572 _AddRepo(name, url, false); 573 } 574 } 575 _UpdateListFromRoster(); 576 fListView->SetSortColumn(fListView->ColumnAt(kUrlColumn), false, true); 577 fListView->ResizeAllColumnsToPreferred(); 578 } 579 580 581 void 582 RepositoriesView::_RefreshList() 583 { 584 // Clear enabled status on all rows 585 int32 index, listCount = fListView->CountRows(); 586 for (index = 0; index < listCount; index++) 587 { 588 RepoRow* repoItem = dynamic_cast<RepoRow*>((fListView->RowAt(index))); 589 if (repoItem->TaskState() == STATE_NOT_IN_QUEUE) 590 repoItem->SetEnabled(false); 591 } 592 // Get current list of enabled repositories 593 _UpdateListFromRoster(); 594 } 595 596 597 void 598 RepositoriesView::_UpdateListFromRoster() 599 { 600 // Get list of currently enabled repositories 601 BStringList repositoryNames; 602 BPackageKit::BPackageRoster pRoster; 603 status_t result = pRoster.GetRepositoryNames(repositoryNames); 604 if (result != B_OK) { 605 (new BAlert("error", 606 B_TRANSLATE_COMMENT("Repositories could not retrieve the names of the " 607 "currently enabled repositories.", "Alert error message"), 608 "OK", NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go(NULL); 609 return; 610 } 611 BPackageKit::BRepositoryConfig repoConfig; 612 int16 index, count = repositoryNames.CountStrings(); 613 for (index = 0; index < count; index++) { 614 const BString& repoName = repositoryNames.StringAt(index); 615 result = pRoster.GetRepositoryConfig(repoName, &repoConfig); 616 if (result == B_OK) 617 _AddRepo(repoName, repoConfig.BaseURL(), true); 618 // else 619 // (new BAlert("error", "Error getting repo config", "OK"))->Go(NULL); 620 } 621 _FindSiblings(); 622 _SaveList(); 623 } 624 625 626 void 627 RepositoriesView::_SaveList() 628 { 629 BStringList nameList, urlList; 630 int32 index; 631 int32 listCount = fListView->CountRows(); 632 for (index = 0; index < listCount; index++) { 633 RepoRow* repoItem = dynamic_cast<RepoRow*>((fListView->RowAt(index))); 634 nameList.Add(repoItem->Name()); 635 urlList.Add(repoItem->Url()); 636 } 637 fSettings.SetRepositories(nameList, urlList); 638 } 639 640 641 RepoRow* 642 RepositoriesView::_AddRepo(BString name, BString url, bool enabled) 643 { 644 // URL must have a protocol 645 if (url.FindFirst("://") == B_ERROR) 646 return NULL; 647 RepoRow* addedRow = NULL; 648 int32 index; 649 int32 listCount = fListView->CountRows(); 650 // Find if the repo already exists in list 651 for (index = 0; index < listCount; index++) { 652 RepoRow* repoItem = dynamic_cast<RepoRow*>((fListView->RowAt(index))); 653 if (url.ICompare(repoItem->Url()) == 0) { 654 // update name and enabled values 655 if (name.Compare(repoItem->Name()) != 0) 656 repoItem->SetName(name.String()); 657 repoItem->SetEnabled(enabled); 658 addedRow = repoItem; 659 } 660 } 661 if (addedRow == NULL) { 662 addedRow = new RepoRow(name, url, enabled); 663 fListView->AddRow(addedRow); 664 } 665 return addedRow; 666 } 667 668 669 void 670 RepositoriesView::_FindSiblings() 671 { 672 BStringList namesFound, namesWithSiblings; 673 int32 index, listCount = fListView->CountRows(); 674 // Find repository names that are duplicated 675 for (index = 0; index < listCount; index++) { 676 RepoRow* repoItem = dynamic_cast<RepoRow*>((fListView->RowAt(index))); 677 BString name = repoItem->Name(); 678 // Ignore newly added repos since we don't know the real name yet 679 if (name.Compare(kNewRepoDefaultName)==0) 680 continue; 681 // First time a name is found- no sibling (yet) 682 if (!namesFound.HasString(name)) 683 namesFound.Add(name); 684 // Name was already found once so this name has 2 or more siblings 685 else if (!namesWithSiblings.HasString(name)) 686 namesWithSiblings.Add(name); 687 } 688 // Set sibling values for each row 689 for (index = 0; index < listCount; index++) { 690 RepoRow* repoItem = dynamic_cast<RepoRow*>((fListView->RowAt(index))); 691 BString name = repoItem->Name(); 692 repoItem->SetHasSiblings(namesWithSiblings.HasString(name)); 693 } 694 } 695 696 697 void 698 RepositoriesView::_UpdateButtons() 699 { 700 RepoRow* rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection()); 701 // At least one row is selected 702 if (rowItem) { 703 bool someAreEnabled = false, 704 someAreDisabled = false, 705 someAreInQueue = false; 706 int32 selectedCount = 0; 707 RepoRow* rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection()); 708 while (rowItem) { 709 selectedCount++; 710 switch (rowItem->TaskState()) 711 { 712 case STATE_IN_QUEUE_WAITING: 713 case STATE_IN_QUEUE_RUNNING: { 714 someAreInQueue = true; 715 break; 716 } 717 } 718 if (rowItem->IsEnabled()) 719 someAreEnabled = true; 720 else 721 someAreDisabled = true; 722 rowItem = dynamic_cast<RepoRow*>(fListView->CurrentSelection(rowItem)); 723 } 724 // Change button labels depending on which rows are selected 725 if (selectedCount > 1) { 726 fEnableButton->SetLabel(kLabelEnableAll); 727 fDisableButton->SetLabel(kLabelDisableAll); 728 } else { 729 fEnableButton->SetLabel(kLabelEnable); 730 fDisableButton->SetLabel(kLabelDisable); 731 } 732 // Set which buttons should be enabled 733 fRemoveButton->SetEnabled(!someAreEnabled && !someAreInQueue); 734 if ((someAreEnabled && someAreDisabled) || someAreInQueue) { 735 // there are a mix of enabled and disabled repositories selected 736 fEnableButton->SetEnabled(false); 737 fDisableButton->SetEnabled(false); 738 } else { 739 fEnableButton->SetEnabled(someAreDisabled); 740 fDisableButton->SetEnabled(someAreEnabled); 741 } 742 743 } else {// No selected rows 744 fEnableButton->SetLabel(kLabelEnable); 745 fDisableButton->SetLabel(kLabelDisable); 746 fEnableButton->SetEnabled(false); 747 fDisableButton->SetEnabled(false); 748 fRemoveButton->SetEnabled(false); 749 } 750 } 751 752 753 void 754 RepositoriesView::_UpdateStatusView() 755 { 756 if (fRunningTaskCount) { 757 BString text(kStatusViewText); 758 text.Append(" "); 759 text<<fRunningTaskCount; 760 fListStatusView->SetText(text); 761 } else 762 fListStatusView->SetText(""); 763 } -
new file src/preferences/repositories/RepositoriesView.h
diff --git a/src/preferences/repositories/RepositoriesView.h b/src/preferences/repositories/RepositoriesView.h new file mode 100644 index 0000000..37de3a3
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 #ifndef REPOSITORIES_VIEW_H 9 #define REPOSITORIES_VIEW_H 10 11 12 #include <ColumnListView.h> 13 #include <String.h> 14 #include <StringView.h> 15 #include <View.h> 16 17 #include "RepositoriesSettings.h" 18 #include "RepoRow.h" 19 #include "TaskLooper.h" 20 21 22 class RepositoriesListView : public BColumnListView { 23 public: 24 RepositoriesListView(const char* name); 25 virtual void KeyDown(const char* bytes, int32 numBytes); 26 }; 27 28 29 class RepositoriesView : public BView { 30 public: 31 RepositoriesView(); 32 ~RepositoriesView(); 33 virtual void AllAttached(); 34 virtual void AttachedToWindow(); 35 virtual void MessageReceived(BMessage*); 36 void AddManualRepository(BString url); 37 bool IsTaskRunning() { return fRunningTaskCount > 0; } 38 39 private: 40 RepositoriesSettings fSettings; 41 RepositoriesListView *fListView; 42 BView *fStatusContainerView; 43 BStringView *fListStatusView; 44 TaskLooper *fTaskLooper; 45 bool fShowCompletedStatus; 46 int fRunningTaskCount, fLastCompletedTimerId; 47 BButton *fAboutButton, *fAddButton, *fRemoveButton, 48 *fEnableButton, *fDisableButton; 49 50 // Message helpers 51 void _AddSelectedRowsToQueue(); 52 void _TaskStarted(RepoRow* rowItem, int16 count); 53 void _TaskCompleted(RepoRow* rowItem, int16 count, 54 BString& newName); 55 void _TaskCanceled(RepoRow* rowItem, int16 count); 56 void _ShowCompletedStatusIfDone(); 57 void _UpdateFromRepoConfig(RepoRow* rowItem); 58 59 // GUI functions 60 BString _GetRootUrl(BString url); 61 status_t _EmptyList(); 62 void _InitList(); 63 void _RefreshList(); 64 void _UpdateListFromRoster(); 65 void _SaveList(); 66 RepoRow* _AddRepo(BString name, BString url, bool enabled); 67 void _FindSiblings(); 68 void _UpdateButtons(); 69 void _UpdateStatusView(); 70 }; 71 72 73 #endif -
new file src/preferences/repositories/RepositoriesWindow.cpp
diff --git a/src/preferences/repositories/RepositoriesWindow.cpp b/src/preferences/repositories/RepositoriesWindow.cpp new file mode 100644 index 0000000..5c6549b
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 9 10 #include "RepositoriesWindow.h" 11 12 #include <Alert.h> 13 #include <Application.h> 14 #include <Catalog.h> 15 #include <FindDirectory.h> 16 #include <LayoutBuilder.h> 17 #include <NodeMonitor.h> 18 #include <Region.h> 19 #include <Screen.h> 20 21 #include "AddRepoWindow.h" 22 #include "constants.h" 23 24 25 #undef B_TRANSLATION_CONTEXT 26 #define B_TRANSLATION_CONTEXT "RepositoriesWindow" 27 28 29 RepositoriesWindow::RepositoriesWindow() 30 : 31 BWindow(BRect(50, 50, 500, 400), B_TRANSLATE_SYSTEM_NAME("Repositories"), 32 B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS), 33 fAddWindow(NULL), 34 fPackageNodeStatus(B_ERROR) 35 { 36 fView = new RepositoriesView(); 37 BLayoutBuilder::Group<>(this, B_VERTICAL).Add(fView); 38 39 // Size and location on screen 40 BSize viewSize(fView->MinSize()); 41 SetSizeLimits(viewSize.Width(), 9999, viewSize.Height(), 9999); 42 BRect frame = fSettings.GetFrame(); 43 ResizeTo(frame.Width(), frame.Height()); 44 BScreen screen; 45 BRect screenFrame = screen.Frame(); 46 if (screenFrame.right < frame.right || screenFrame.left > frame.left 47 || screenFrame.top > frame.top || screenFrame.bottom < frame.bottom) 48 CenterOnScreen(); 49 else 50 MoveTo(frame.left, frame.top); 51 Show(); 52 53 // Find the pkgman settings or cache directory 54 BPath packagePath; 55 // /boot/system/settings/package-repositories 56 status_t status = find_directory(B_SYSTEM_SETTINGS_DIRECTORY, 57 &packagePath); 58 if (status == B_OK) 59 status = packagePath.Append("package-repositories"); 60 else { 61 // /boot/system/cache/package-repositories 62 status = find_directory(B_SYSTEM_CACHE_DIRECTORY, &packagePath); 63 if (status == B_OK) 64 status = packagePath.Append("package-repositories"); 65 } 66 if (status == B_OK) { 67 BNode packageNode(packagePath.Path()); 68 if (packageNode.InitCheck()==B_OK && packageNode.IsDirectory()) 69 fPackageNodeStatus = packageNode.GetNodeRef(&fPackageNodeRef); 70 } 71 72 // watch the pkgman settings or cache directory for changes 73 _StartWatching(); 74 } 75 76 77 RepositoriesWindow::~RepositoriesWindow() 78 { 79 _StopWatching(); 80 } 81 82 83 void 84 RepositoriesWindow::_StartWatching() 85 { 86 if (fPackageNodeStatus == B_OK) { 87 status_t result = watch_node(&fPackageNodeRef, B_WATCH_DIRECTORY, this); 88 fWatchingPackageNode = (result == B_OK); 89 } 90 } 91 92 93 void 94 RepositoriesWindow::_StopWatching() 95 { 96 if (fPackageNodeStatus == B_OK && fWatchingPackageNode) { 97 watch_node(&fPackageNodeRef, B_STOP_WATCHING, this); 98 fWatchingPackageNode = false; 99 } 100 } 101 102 103 bool 104 RepositoriesWindow::QuitRequested() 105 { 106 if (fView->IsTaskRunning()) { 107 BAlert *alert = new BAlert("tasks", 108 B_TRANSLATE_COMMENT("Some tasks are still running. Stop these " 109 "tasks and quit?", "Application quit alert message"), 110 B_TRANSLATE_COMMENT("Stop and quit", "Button label"), 111 kCancelLabel, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT); 112 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 113 int32 result = alert->Go(); 114 if (result != 0) 115 return false; 116 } 117 fSettings.SetFrame(Frame()); 118 be_app->PostMessage(B_QUIT_REQUESTED); 119 return BWindow::QuitRequested(); 120 } 121 122 123 void 124 RepositoriesWindow::MessageReceived(BMessage* message) 125 { 126 switch (message->what) 127 { 128 case ADD_REPO_WINDOW: { 129 BRect frame = Frame(); 130 fAddWindow = new AddRepoWindow(frame, this); 131 break; 132 } 133 case ADD_REPO_URL: { 134 BString url; 135 status_t result = message->FindString(key_url, &url); 136 if (result == B_OK) 137 fView->AddManualRepository(url); 138 break; 139 } 140 case ADD_WINDOW_CLOSED: { 141 fAddWindow = NULL; 142 break; 143 } 144 case DELETE_KEY_PRESSED: { 145 BMessage message(REMOVE_REPOS); 146 fView->MessageReceived(&message); 147 break; 148 } 149 case TASK_STARTED: 150 case TASK_COMPLETED_WITH_ERRORS: 151 case TASK_COMPLETED: 152 case TASK_CANCELED: { 153 fView->MessageReceived(message); 154 break; 155 } 156 case SHOW_ABOUT: { 157 be_app->AboutRequested(); 158 break; 159 } 160 // captures pkgman changes while the Repositories application is running 161 case B_NODE_MONITOR: { 162 // This preflet is making the changes, so ignore this message 163 if (fView->IsTaskRunning()) 164 break; 165 166 int32 opcode; 167 if (message->FindInt32("opcode", &opcode) == B_OK) { 168 switch (opcode) 169 { 170 case B_ATTR_CHANGED: 171 case B_ENTRY_CREATED: 172 case B_ENTRY_REMOVED: { 173 PostMessage(UPDATE_LIST, fView); 174 break; 175 } 176 } 177 } 178 break; 179 } 180 default: 181 BWindow::MessageReceived(message); 182 } 183 } -
new file src/preferences/repositories/RepositoriesWindow.h
diff --git a/src/preferences/repositories/RepositoriesWindow.h b/src/preferences/repositories/RepositoriesWindow.h new file mode 100644 index 0000000..cc0b8c6
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 #ifndef REPOSITORIES_WINDOW_H 9 #define REPOSITORIES_WINDOW_H 10 11 12 #include <Node.h> 13 #include <Window.h> 14 15 #include "AddRepoWindow.h" 16 #include "RepositoriesSettings.h" 17 #include "RepositoriesView.h" 18 19 20 class RepositoriesWindow : public BWindow { 21 public: 22 RepositoriesWindow(); 23 ~RepositoriesWindow(); 24 virtual bool QuitRequested(); 25 virtual void MessageReceived(BMessage*); 26 27 private: 28 RepositoriesSettings fSettings; 29 RepositoriesView *fView; 30 AddRepoWindow *fAddWindow; 31 node_ref fPackageNodeRef; 32 // node_ref to watch for changes to package-repositories directory 33 status_t fPackageNodeStatus; 34 bool fWatchingPackageNode; 35 // true when package-repositories directory is being watched 36 void _StartWatching(); 37 void _StopWatching(); 38 }; 39 40 41 #endif -
new file src/preferences/repositories/TaskLooper.cpp
diff --git a/src/preferences/repositories/TaskLooper.cpp b/src/preferences/repositories/TaskLooper.cpp new file mode 100644 index 0000000..f76815b
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 9 10 #include "TaskLooper.h" 11 12 #include <Catalog.h> 13 #include <MessageQueue.h> 14 #include <package/AddRepositoryRequest.h> 15 #include <package/DropRepositoryRequest.h> 16 #include <package/RefreshRepositoryRequest.h> 17 #include <package/PackageRoster.h> 18 #include <package/RepositoryConfig.h> 19 20 #include "constants.h" 21 22 #define DEBUGTASK 0 23 24 #undef B_TRANSLATION_CONTEXT 25 #define B_TRANSLATION_CONTEXT "TaskLooper" 26 27 static const BString kLogResultIndicator = "***"; 28 static const BString kCompletedText = 29 B_TRANSLATE_COMMENT("Completed", "Completed task status message"); 30 static const BString kFailedText = 31 B_TRANSLATE_COMMENT("Failed", "Failed task status message"); 32 static const BString kAbortedText = 33 B_TRANSLATE_COMMENT("Aborted", "Aborted task status message"); 34 static const BString kDescriptionText = 35 B_TRANSLATE_COMMENT("Description", "Failed task error description"); 36 static const BString kDetailsText = 37 B_TRANSLATE_COMMENT("Details", "Job log details header"); 38 39 using BSupportKit::BJob; 40 41 42 void 43 JobStateListener::JobStarted(BJob* job) 44 { 45 fJobLog.Add(job->Title()); 46 } 47 48 49 void 50 JobStateListener::JobSucceeded(BJob* job) 51 { 52 BString resultText(kLogResultIndicator); 53 fJobLog.Add(resultText.Append(kCompletedText)); 54 } 55 56 57 void 58 JobStateListener::JobFailed(BJob* job) 59 { 60 BString resultText(kLogResultIndicator); 61 resultText.Append(kFailedText).Append(": ") 62 .Append(strerror(job->Result())); 63 fJobLog.Add(resultText); 64 if (job->ErrorString().Length() > 0) { 65 resultText.SetTo(kLogResultIndicator); 66 resultText.Append(kDescriptionText).Append(": ") 67 .Append(job->ErrorString()); 68 fJobLog.Add(resultText); 69 } 70 } 71 72 73 void 74 JobStateListener::JobAborted(BJob* job) 75 { 76 BString resultText(kLogResultIndicator); 77 resultText.Append(kAbortedText).Append(": ") 78 .Append(strerror(job->Result())); 79 fJobLog.Add(resultText); 80 if (job->ErrorString().Length() > 0) { 81 resultText.SetTo(kLogResultIndicator); 82 resultText.Append(kDescriptionText).Append(": ") 83 .Append(job->ErrorString()); 84 fJobLog.Add(resultText); 85 } 86 } 87 88 89 BString 90 JobStateListener::GetJobLog() 91 { 92 return fJobLog.Join("\n"); 93 } 94 95 96 TaskLooper::TaskLooper(BLooper* target) 97 :BLooper("TaskLooper"), 98 fReplyTarget(target) 99 { 100 Run(); 101 } 102 103 104 bool 105 TaskLooper::QuitRequested() 106 { 107 return MessageQueue()->IsEmpty(); 108 } 109 110 111 void 112 TaskLooper::MessageReceived(BMessage* message) 113 { 114 switch (message->what) 115 { 116 case DO_TASK: { 117 RepoRow* rowItem; 118 status_t result = message->FindPointer(key_rowptr, (void**)&rowItem); 119 if (result == B_OK) { 120 // Check to make sure there isn't already an existing task for this 121 int16 queueCount = fTaskQueue.CountItems(); 122 for (int16 index = 0; index<queueCount; index++) { 123 Task* task = fTaskQueue.ItemAt(index); 124 if (rowItem == task->rowItem) 125 break; 126 } 127 128 // Initialize task 129 Task* newTask = new Task(); 130 newTask->rowItem = rowItem; 131 newTask->name = rowItem->Name(); 132 newTask->resultName = newTask->name; 133 if (rowItem->IsEnabled()) { 134 newTask->taskType = DISABLE_REPO; 135 newTask->taskParam = newTask->name; 136 } else { 137 newTask->taskType = ENABLE_REPO; 138 newTask->taskParam = rowItem->Url(); 139 } 140 newTask->owner = this; 141 newTask->fTimer = NULL; 142 143 // Add to queue and start 144 fTaskQueue.AddItem(newTask); 145 BString threadName(newTask->taskType == ENABLE_REPO ? 146 "enable_task" : "disable_task"); 147 newTask->threadId = spawn_thread(_DoTask, threadName.String(), 148 B_NORMAL_PRIORITY, (void*)newTask); 149 status_t threadResult; 150 if (newTask->threadId < B_OK) 151 threadResult = B_ERROR; 152 else { 153 threadResult = resume_thread(newTask->threadId); 154 if (threadResult == B_OK) { 155 newTask->fTimer = new TaskTimer(this, newTask); 156 newTask->fTimer->Start(newTask->name); 157 // Reply to view 158 BMessage reply(*message); 159 reply.what = TASK_STARTED; 160 reply.AddInt16(key_count, fTaskQueue.CountItems()); 161 fReplyTarget->PostMessage(&reply); 162 } else 163 kill_thread(newTask->threadId); 164 } 165 if (threadResult != B_OK) { 166 _RemoveAndDelete(newTask); 167 } 168 } 169 break; 170 } 171 case TASK_COMPLETED: 172 case TASK_COMPLETED_WITH_ERRORS: 173 case TASK_CANCELED: { 174 Task* task; 175 status_t result = message->FindPointer(key_taskptr, (void**)&task); 176 if (result == B_OK && fTaskQueue.HasItem(task)) { 177 task->fTimer->Stop(task->resultName); 178 BMessage reply(message->what); 179 reply.AddInt16(key_count, fTaskQueue.CountItems()-1); 180 reply.AddPointer(key_rowptr, task->rowItem); 181 if (message->what == TASK_COMPLETED_WITH_ERRORS) 182 reply.AddString(key_details, task->resultErrorDetails); 183 if (task->taskType == ENABLE_REPO 184 && task->name.Compare(task->resultName) != 0) 185 reply.AddString(key_name, task->resultName); 186 fReplyTarget->PostMessage(&reply); 187 _RemoveAndDelete(task); 188 } 189 break; 190 } 191 case TASK_KILL_REQUEST: { 192 Task* task; 193 status_t result = message->FindPointer(key_taskptr, (void**)&task); 194 if (result == B_OK && fTaskQueue.HasItem(task)) { 195 kill_thread(task->threadId); 196 BMessage reply(TASK_CANCELED); 197 reply.AddInt16(key_count, fTaskQueue.CountItems()-1); 198 reply.AddPointer(key_rowptr, task->rowItem); 199 fReplyTarget->PostMessage(&reply); 200 _RemoveAndDelete(task); 201 } 202 break; 203 } 204 } 205 } 206 207 208 void 209 TaskLooper::_RemoveAndDelete(Task* task) 210 { 211 fTaskQueue.RemoveItem(task); 212 if (task->fTimer) 213 { 214 task->fTimer->Lock(); 215 task->fTimer->Quit(); 216 task->fTimer = NULL; 217 } 218 delete task; 219 } 220 221 222 status_t 223 TaskLooper::_DoTask(void* data) 224 { 225 Task* task = (Task*)data; 226 BString errorDetails, repoName(""); 227 status_t returnResult = B_OK; 228 DecisionProvider decisionProvider; 229 JobStateListener listener; 230 switch (task->taskType) 231 { 232 case DISABLE_REPO: { 233 BString nameParam(task->taskParam); 234 BPackageKit::BContext context(decisionProvider, listener); 235 BPackageKit::DropRepositoryRequest dropRequest(context, nameParam); 236 status_t result = dropRequest.Process(); 237 if (result != B_OK) { 238 returnResult = result; 239 if (result != B_CANCELED) { 240 errorDetails.Append(B_TRANSLATE_COMMENT("There was an " 241 "error disabling the repository %name%", 242 "Error message, do not translate %name%")); 243 BString nameString("\""); 244 nameString.Append(nameParam).Append("\""); 245 errorDetails.ReplaceFirst("%name%", nameString); 246 _AppendErrorDetails(errorDetails, &listener); 247 } 248 } 249 break; 250 } 251 case ENABLE_REPO: { 252 BString urlParam(task->taskParam); 253 BPackageKit::BContext context(decisionProvider, listener); 254 // Add repository 255 bool asUserRepository = false; 256 // TODO does this ever change? 257 BPackageKit::AddRepositoryRequest addRequest(context, urlParam, 258 asUserRepository); 259 status_t result = addRequest.Process(); 260 if (result != B_OK) { 261 returnResult = result; 262 if (result != B_CANCELED) { 263 errorDetails.Append(B_TRANSLATE_COMMENT("There was an " 264 "error enabling the repository %url%", 265 "Error message, do not translate %url%")); 266 errorDetails.ReplaceFirst("%url%", urlParam); 267 _AppendErrorDetails(errorDetails, &listener); 268 } 269 break; 270 } 271 // Continue on to refresh repo cache 272 repoName = addRequest.RepositoryName(); 273 BPackageKit::BPackageRoster roster; 274 BPackageKit::BRepositoryConfig repoConfig; 275 roster.GetRepositoryConfig(repoName, &repoConfig); 276 BPackageKit::BRefreshRepositoryRequest refreshRequest(context, 277 repoConfig); 278 result = refreshRequest.Process(); 279 if (result != B_OK) { 280 returnResult = result; 281 if (result != B_CANCELED) { 282 errorDetails.Append(B_TRANSLATE_COMMENT("There was an " 283 "error refreshing the repository cache for %name%", 284 "Error message, do not translate %name%")); 285 BString nameString("\""); 286 nameString.Append(repoName).Append("\""); 287 errorDetails.ReplaceFirst("%name%", nameString); 288 _AppendErrorDetails(errorDetails, &listener); 289 } 290 } 291 break; 292 } 293 } 294 // Report completion status 295 BMessage reply; 296 if (returnResult == B_OK) { 297 reply.what = TASK_COMPLETED; 298 // Add the repo name if we need to update the list row value 299 if (task->taskType == ENABLE_REPO) 300 task->resultName = repoName; 301 } else if (returnResult == B_CANCELED) 302 reply.what = TASK_CANCELED; 303 else { 304 reply.what = TASK_COMPLETED_WITH_ERRORS; 305 task->resultErrorDetails = errorDetails; 306 if (task->taskType == ENABLE_REPO) 307 task->resultName = repoName; 308 } 309 reply.AddPointer(key_taskptr, task); 310 task->owner->PostMessage(&reply); 311 #if DEBUGTASK 312 if (returnResult == B_OK || returnResult == B_CANCELED) { 313 BString degubDetails("Debug info:\n"); 314 degubDetails.Append(listener.GetJobLog()); 315 (new BAlert("debug", degubDetails, "OK"))->Go(NULL); 316 } 317 #endif // DEBUGTASK 318 return 0; 319 } 320 321 322 void 323 TaskLooper::_AppendErrorDetails(BString& details, JobStateListener* listener) 324 { 325 details.Append("\n\n").Append(kDetailsText).Append(":\n"); 326 details.Append(listener->GetJobLog()); 327 } -
new file src/preferences/repositories/TaskLooper.h
diff --git a/src/preferences/repositories/TaskLooper.h b/src/preferences/repositories/TaskLooper.h new file mode 100644 index 0000000..5192289
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 #ifndef TASK_LOOPER_H 9 #define TASK_LOOPER_H 10 11 12 #include <Job.h> 13 #include <Looper.h> 14 #include <ObjectList.h> 15 #include <String.h> 16 #include <StringList.h> 17 #include <package/Context.h> 18 19 #include "TaskTimer.h" 20 21 22 class DecisionProvider : public BPackageKit::BDecisionProvider { 23 public: 24 DecisionProvider() {} 25 26 virtual bool YesNoDecisionNeeded(const BString& description, 27 const BString& question, 28 const BString& yes, 29 const BString& no, 30 const BString& defaultChoice) 31 { return true; } 32 }; 33 34 35 class JobStateListener : public BSupportKit::BJobStateListener { 36 public: 37 JobStateListener() {} 38 39 virtual void JobStarted(BSupportKit::BJob* job); 40 virtual void JobSucceeded(BSupportKit::BJob* job); 41 virtual void JobFailed(BSupportKit::BJob* job); 42 virtual void JobAborted(BSupportKit::BJob* job); 43 BString GetJobLog(); 44 45 private: 46 BStringList fJobLog; 47 }; 48 49 50 class TaskLooper : public BLooper { 51 public: 52 TaskLooper(BLooper* target); 53 virtual bool QuitRequested(); 54 virtual void MessageReceived(BMessage*); 55 56 private: 57 BObjectList<Task> fTaskQueue; 58 void _RemoveAndDelete(Task* task); 59 static status_t _DoTask(void* data); 60 static void _AppendErrorDetails(BString& details, 61 JobStateListener* listener); 62 BLooper *fReplyTarget; 63 }; 64 65 66 #endif -
new file src/preferences/repositories/TaskTimer.cpp
diff --git a/src/preferences/repositories/TaskTimer.cpp b/src/preferences/repositories/TaskTimer.cpp new file mode 100644 index 0000000..e010351
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 9 10 #include "TaskTimer.h" 11 12 #include <Application.h> 13 #include <Catalog.h> 14 15 #include "constants.h" 16 17 #undef B_TRANSLATION_CONTEXT 18 #define B_TRANSLATION_CONTEXT "TaskTimer" 19 20 static int32 sAlertStackCount = 0; 21 22 23 TaskTimer::TaskTimer(BLooper* target, Task* owner) 24 : 25 BLooper(), 26 fTimeoutMicroSeconds(kTimerTimeoutSeconds * 1000000), 27 fTimerIsRunning(false), 28 fReplyTarget(target), 29 fMessageRunner(NULL), 30 fTimeoutMessage(TASK_TIMEOUT), 31 fTimeoutAlert(NULL), 32 fOwner(owner) 33 { 34 Run(); 35 36 // Messenger for the Message Runner to use to send its message to the timer 37 fMessenger.SetTo(this); 38 // Invoker for the Alerts to use to send their messages to the timer 39 fTimeoutAlertInvoker.SetMessage( 40 new BMessage(TIMEOUT_ALERT_BUTTON_SELECTION)); 41 fTimeoutAlertInvoker.SetTarget(this); 42 } 43 44 45 TaskTimer::~TaskTimer() 46 { 47 if (fTimeoutAlert) { 48 fTimeoutAlert->Lock(); 49 fTimeoutAlert->Quit(); 50 } 51 if (fMessageRunner) 52 fMessageRunner->SetCount(0); 53 } 54 55 56 bool 57 TaskTimer::QuitRequested() 58 { 59 return true; 60 } 61 62 63 void 64 TaskTimer::MessageReceived(BMessage* message) 65 { 66 switch (message->what) 67 { 68 case TASK_TIMEOUT: { 69 fMessageRunner = NULL; 70 if (fTimerIsRunning) { 71 BString text(B_TRANSLATE_COMMENT("The task for repository" 72 " %name% is taking a long time to complete.", 73 "Alert message. Do not translate %name%")); 74 BString nameString("\""); 75 nameString.Append(fRepositoryName).Append("\""); 76 text.ReplaceFirst("%name%", nameString); 77 fTimeoutAlert = new BAlert("timeout", text, 78 B_TRANSLATE_COMMENT("Keep trying", "Button label"), 79 B_TRANSLATE_COMMENT("Cancel task", "Button label"), 80 NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT); 81 fTimeoutAlert->SetShortcut(0, B_ESCAPE); 82 // Calculate the position to correctly stack this alert 83 BRect windowFrame = be_app->WindowAt(0)->Frame(); 84 int32 stackPos = _NextAlertStackCount(); 85 float xPos = windowFrame.left 86 + windowFrame.Width()/2 + stackPos * kTimerAlertOffset; 87 float yPos = windowFrame.top 88 + (stackPos + 1) * kTimerAlertOffset; 89 fTimeoutAlert->Go(&fTimeoutAlertInvoker); 90 xPos -= fTimeoutAlert->Frame().Width()/2; 91 // The correct frame for the alert is not available until 92 // after Go is called 93 fTimeoutAlert->MoveTo(xPos, yPos); 94 } 95 break; 96 } 97 case TIMEOUT_ALERT_BUTTON_SELECTION: { 98 fTimeoutAlert = NULL; 99 // Timeout alert was invoked by user and timer still has not 100 // been stopped 101 if (fTimerIsRunning) { 102 // find which button was pressed 103 int32 selection = -1; 104 message->FindInt32("which", &selection); 105 if (selection == 1) { 106 BMessage reply(TASK_KILL_REQUEST); 107 reply.AddPointer(key_taskptr, fOwner); 108 fReplyTarget->PostMessage(&reply); 109 } else if (selection == 0) { 110 // Create new timer 111 fMessageRunner = new BMessageRunner(fMessenger, 112 &fTimeoutMessage, kTimerRetrySeconds * 1000000, 1); 113 } 114 } 115 break; 116 } 117 } 118 } 119 120 121 void 122 TaskTimer::Start(const char* name) 123 { 124 fTimerIsRunning = true; 125 fRepositoryName.SetTo(name); 126 127 // Create a message runner that will send a TASK_TIMEOUT message if the 128 // timer is not stopped 129 if (fMessageRunner == NULL) 130 fMessageRunner = new BMessageRunner(fMessenger, &fTimeoutMessage, 131 fTimeoutMicroSeconds, 1); 132 else 133 fMessageRunner->SetInterval(fTimeoutMicroSeconds); 134 } 135 136 137 void 138 TaskTimer::Stop(const char* name) 139 { 140 fTimerIsRunning = false; 141 142 // Reset max timeout so we can reuse the runner at the next Start call 143 if (fMessageRunner != NULL) 144 fMessageRunner->SetInterval(LLONG_MAX); 145 146 // If timeout alert is showing replace it 147 if (fTimeoutAlert) { 148 // Remove current alert 149 BRect frame = fTimeoutAlert->Frame(); 150 fTimeoutAlert->Quit(); 151 fTimeoutAlert = NULL; 152 153 // Display new alert that won't send a message 154 BString text(B_TRANSLATE_COMMENT("Good news! The task for repository " 155 "%name% completed.", "Alert message. Do not translate %name%")); 156 BString nameString("\""); 157 nameString.Append(name).Append("\""); 158 text.ReplaceFirst("%name%", nameString); 159 BAlert* newAlert = new BAlert("timeout", text, kOKLabel, NULL, NULL, 160 B_WIDTH_AS_USUAL, B_WARNING_ALERT); 161 newAlert->SetShortcut(0, B_ESCAPE); 162 newAlert->MoveTo(frame.left, frame.top); 163 newAlert->Go(NULL); 164 } 165 } 166 167 168 int32 169 TaskTimer::_NextAlertStackCount() 170 { 171 if (sAlertStackCount > 9) 172 sAlertStackCount = 0; 173 return sAlertStackCount++; 174 } -
new file src/preferences/repositories/TaskTimer.h
diff --git a/src/preferences/repositories/TaskTimer.h b/src/preferences/repositories/TaskTimer.h new file mode 100644 index 0000000..86eb10f
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 #ifndef TASKTIMER_H 9 #define TASKTIMER_H 10 11 12 #include <Alert.h> 13 #include <Invoker.h> 14 #include <Looper.h> 15 #include <Message.h> 16 #include <MessageRunner.h> 17 #include <Messenger.h> 18 #include <String.h> 19 20 #include "RepoRow.h" 21 22 class TaskTimer; 23 class TaskLooper; 24 25 26 typedef struct { 27 RepoRow* rowItem; 28 int32 taskType; 29 BString name, taskParam; 30 thread_id threadId; 31 TaskLooper* owner; 32 BString resultName, resultErrorDetails; 33 TaskTimer* fTimer; 34 } Task; 35 36 37 class TaskTimer : public BLooper { 38 public: 39 TaskTimer(BLooper* target, Task* owner); 40 ~TaskTimer(); 41 virtual bool QuitRequested(); 42 virtual void MessageReceived(BMessage*); 43 void Start(const char* name); 44 void Stop(const char* name); 45 46 private: 47 int32 fTimeoutMicroSeconds; 48 bool fTimerIsRunning; 49 BString fRepositoryName; 50 BLooper *fReplyTarget; 51 BMessenger fMessenger; 52 BMessageRunner *fMessageRunner; 53 BMessage fTimeoutMessage; 54 BAlert *fTimeoutAlert; 55 BInvoker fTimeoutAlertInvoker; 56 Task *fOwner; 57 int32 _NextAlertStackCount(); 58 }; 59 60 61 #endif -
new file src/preferences/repositories/constants.h
diff --git a/src/preferences/repositories/constants.h b/src/preferences/repositories/constants.h new file mode 100644 index 0000000..181b584
- + 1 /* 2 * Copyright 2017 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Brian Hill 7 */ 8 #ifndef REPOSITORIES_CONSTANTS_H 9 #define REPOSITORIES_CONSTANTS_H 10 11 12 #include <Catalog.h> 13 #include <String.h> 14 15 #undef B_TRANSLATION_CONTEXT 16 #define B_TRANSLATION_CONTEXT "Constants" 17 18 static const float kAddWindowOffset = 10.0; 19 static const int16 kTimerAlertOffset = 15; 20 static const int16 kTimerTimeoutSeconds = 10; 21 static const int16 kTimerRetrySeconds = 20; 22 23 static const BString kOKLabel = B_TRANSLATE_COMMENT("OK", "Button label"); 24 static const BString kCancelLabel = B_TRANSLATE_COMMENT("Cancel", 25 "Button label"); 26 static const BString kRemoveLabel = B_TRANSLATE_COMMENT("Remove", 27 "Button label"); 28 static const BString kNewRepoDefaultName = B_TRANSLATE_COMMENT("Unknown", 29 "Unknown repository name"); 30 31 32 typedef struct { 33 const char* name; 34 const char* url; 35 } Repository; 36 37 38 static const Repository kDefaultRepos[] = { 39 { "Haiku", "http://packages.haiku-os.org/haiku/master/"B_HAIKU_ABI_NAME 40 "/current"}, 41 { "Haikuports", "http://packages.haiku-os.org/haikuports/master/repo/" 42 B_HAIKU_ABI_NAME"/current" }, 43 { "BeSly Software Solutions", "http://software.besly.de/repo"}, 44 { "clasqm's repo", "http://clasquin-johnson.co.za/michel/repo"}, 45 { "clasqm's x86_64 repo", "http://clasquin-johnson.co.za/michel/repo_64"}, 46 { "FatElk", "http://coquillemartialarts.com/fatelk/repo"} 47 }; 48 49 50 // Message keys 51 #define key_frame "frame" 52 #define key_name "repo_name" 53 #define key_url "repo_url" 54 #define key_text "text" 55 #define key_details "details" 56 #define key_rowptr "row_ptr" 57 #define key_taskptr "task_ptr" 58 #define key_count "count" 59 #define key_ID "ID" 60 61 62 // Messages 63 enum { 64 ADD_REPO_WINDOW = 'BHDa', 65 ADD_BUTTON_PRESSED, 66 CANCEL_BUTTON_PRESSED, 67 ADD_REPO_URL, 68 ADD_WINDOW_CLOSED, 69 REMOVE_REPOS, 70 LIST_SELECTION_CHANGED, 71 ENABLE_BUTTON_PRESSED, 72 DISABLE_BUTTON_PRESSED, 73 ITEM_INVOKED, 74 DELETE_KEY_PRESSED, 75 DO_TASK, 76 STATUS_VIEW_COMPLETED_TIMEOUT, 77 TASK_STARTED, 78 TASK_COMPLETED, 79 TASK_COMPLETED_WITH_ERRORS, 80 TASK_CANCELED, 81 UPDATE_LIST, 82 SHOW_ABOUT, 83 NO_TASKS, 84 ENABLE_REPO, 85 DISABLE_REPO, 86 TASK_TIMEOUT, 87 TIMEOUT_ALERT_BUTTON_SELECTION, 88 TASK_KILL_REQUEST 89 }; 90 91 92 // Repo row task state 93 enum { 94 STATE_NOT_IN_QUEUE = 0, 95 STATE_IN_QUEUE_WAITING, 96 STATE_IN_QUEUE_RUNNING 97 }; 98 99 100 #endif