1/* 2 * Copyright (C) 2010 Stephan A��mus <superstippi@gmx.de> 3 * Copyright (C) 2010 Adrien Destugues <pulkomandy@pulkomandy.ath.cx> 4 * 5 * Distributed under the terms of the MIT licence. 6 */ 7 8#include "ApplicationWindow.h" 9 10#include <stdio.h> 11 12#include <Alert.h> 13#include <Button.h> 14#include <Catalog.h> 15#include <ControlLook.h> 16#include <Entry.h> 17#include <File.h> 18#include <FindDirectory.h> 19#include <GroupLayout.h> 20#include <GroupLayoutBuilder.h> 21#include <MenuBar.h> 22#include <MenuItem.h> 23#include <Path.h> 24#include <Roster.h> 25#include <ScrollView.h> 26#include <SeparatorView.h> 27#include <SpaceLayoutItem.h> 28 29#include "ApplicationView.h" 30 31 32enum { 33 INIT = 'init', 34}; 35 36 37class ApplicationsContainerView : public BGroupView { 38public: 39 ApplicationsContainerView() 40 : 41 BGroupView(B_VERTICAL, 0.0) 42 { 43 SetFlags(Flags() | B_PULSE_NEEDED); 44 SetViewColor(245, 245, 245); 45 AddChild(BSpaceLayoutItem::CreateGlue()); 46 } 47 48 virtual BSize MinSize() 49 { 50 BSize minSize = BGroupView::MinSize(); 51 return BSize(minSize.width, 80); 52 } 53 54protected: 55 virtual void DoLayout() 56 { 57 BGroupView::DoLayout(); 58 if (BScrollBar* scrollBar = ScrollBar(B_VERTICAL)) { 59 BSize minSize = BGroupView::MinSize(); 60 float height = Bounds().Height(); 61 float max = minSize.height - height; 62 scrollBar->SetRange(0, max); 63 if (minSize.height > 0) 64 scrollBar->SetProportion(height / minSize.height); 65 else 66 scrollBar->SetProportion(1); 67 } 68 } 69}; 70 71 72class ApplicationContainerScrollView : public BScrollView { 73public: 74 ApplicationContainerScrollView(BView* target) 75 : 76 BScrollView("Applications scroll view", target, 0, false, true, 77 B_NO_BORDER) 78 { 79 } 80 81protected: 82 virtual void DoLayout() 83 { 84 BScrollView::DoLayout(); 85 // Tweak scroll bar layout to hide part of the frame for better looks. 86 BScrollBar* scrollBar = ScrollBar(B_VERTICAL); 87 scrollBar->MoveBy(1, -1); 88 scrollBar->ResizeBy(0, 2); 89 Target()->ResizeBy(1, 0); 90 // Set the scroll steps 91 if (BView* item = Target()->ChildAt(0)) { 92 scrollBar->SetSteps(item->MinSize().height + 1, 93 item->MinSize().height + 1); 94 } 95 } 96}; 97 98 99// #pragma mark - 100 101 102ApplicationWindow::ApplicationWindow(BRect frame, bool visible) 103 : 104 BWindow(frame, B_TRANSLATE_SYSTEM_NAME("PackageManager"), 105 B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 106 B_AUTO_UPDATE_SIZE_LIMITS | B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE), 107 fMinimizeOnClose(false) 108{ 109 SetPulseRate(1000000); 110 111 SetLayout(new BGroupLayout(B_VERTICAL, 0.0)); 112 113 ApplicationsContainerView* downloadsGroupView = new ApplicationsContainerView(); 114 fApplicationViewsLayout = downloadsGroupView->GroupLayout(); 115 116 BMenuBar* menuBar = new BMenuBar("Menu bar"); 117 BMenu* menu = new BMenu("Actions"); 118 menu->AddItem(new BMenuItem("Apply changes", 119 new BMessage('NADA'))); 120 menu->AddItem(new BMenuItem("Exit", new BMessage(B_QUIT_REQUESTED))); 121 menuBar->AddItem(menu); 122 123 fApplicationsScrollView = new ApplicationContainerScrollView(downloadsGroupView); 124 125 fDiscardButton = new BButton("Revert", 126 new BMessage('NADA')); 127 fDiscardButton->SetEnabled(false); 128 129 fApplyChangesButton = new BButton("Apply", 130 new BMessage('NADA')); 131 fApplyChangesButton->SetEnabled(false); 132 133 const float spacing = be_control_look->DefaultItemSpacing(); 134 135 AddChild(BGroupLayoutBuilder(B_VERTICAL, 0.0) 136 .Add(menuBar) 137 .Add(fApplicationsScrollView) 138 .Add(new BSeparatorView(B_HORIZONTAL, B_PLAIN_BORDER)) 139 .Add(BGroupLayoutBuilder(B_HORIZONTAL, spacing) 140 .AddGlue() 141 .Add(fApplyChangesButton) 142 .Add(fDiscardButton) 143 .SetInsets(12, 5, 12, 5) 144 ) 145 ); 146 147 PostMessage(INIT); 148 149 if (!visible) 150 Hide(); 151 Show(); 152} 153 154 155ApplicationWindow::~ApplicationWindow() 156{ 157} 158 159 160void 161ApplicationWindow::DispatchMessage(BMessage* message, BHandler* target) 162{ 163 // We need to intercept mouse down events inside the area of download 164 // progress views (regardless of whether they have children at the click), 165 // so that they may display a context menu. 166 BPoint where; 167 int32 buttons; 168 if (message->what == B_MOUSE_DOWN 169 && message->FindPoint("screen_where", &where) == B_OK 170 && message->FindInt32("buttons", &buttons) == B_OK 171 && (buttons & B_SECONDARY_MOUSE_BUTTON) != 0) { 172 for (int32 i = fApplicationViewsLayout->CountItems() - 1; 173 BLayoutItem* item = fApplicationViewsLayout->ItemAt(i); i--) { 174 ApplicationView* view = dynamic_cast<ApplicationView*>( 175 item->View()); 176 if (!view) 177 continue; 178 BPoint viewWhere(where); 179 view->ConvertFromScreen(&viewWhere); 180 if (view->Bounds().Contains(viewWhere)) { 181 view->ShowContextMenu(where); 182 return; 183 } 184 } 185 } 186 BWindow::DispatchMessage(message, target); 187} 188 189 190void 191ApplicationWindow::MessageReceived(BMessage* message) 192{ 193 switch (message->what) { 194 case INIT: 195 { 196 break; 197 } 198 199 default: 200 BWindow::MessageReceived(message); 201 break; 202 } 203} 204 205 206bool 207ApplicationWindow::QuitRequested() 208{ 209 if (fMinimizeOnClose) { 210 if (!IsMinimized()) 211 Minimize(true); 212 } else { 213 if (!IsHidden()) 214 Hide(); 215 } 216 return false; 217} 218 219 220void 221ApplicationWindow::SetMinimizeOnClose(bool minimize) 222{ 223 if (Lock()) { 224 fMinimizeOnClose = minimize; 225 Unlock(); 226 } 227} 228 229 230// #pragma mark - private 231 232 233void 234ApplicationWindow::AddCategory(const char* name, const char* icon, 235 const char* description) 236{ 237 ApplicationView* category = new ApplicationView(name, icon, description); 238 fApplicationViewsLayout->AddView(0, category); 239} 240 241 242void 243ApplicationWindow::AddApplication(const BMessage* info) 244{ 245 ApplicationView* app = new ApplicationView(info); 246 fApplicationViewsLayout->AddView(0, app); 247} 248 249 250void 251ApplicationWindow::_ValidateButtonStatus() 252{ 253 int32 finishedCount = 0; 254 int32 missingCount = 0; 255 for (int32 i = fApplicationViewsLayout->CountItems() - 1; 256 BLayoutItem* item = fApplicationViewsLayout->ItemAt(i); i--) { 257 ApplicationView* view = dynamic_cast<ApplicationView*>( 258 item->View()); 259 if (!view) 260 continue; 261 } 262 fDiscardButton->SetEnabled(finishedCount > 0); 263 fApplyChangesButton->SetEnabled(missingCount > 0); 264} 265 266