1 /* 2 Open Tracker License 3 4 Terms and Conditions 5 6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy of 9 this software and associated documentation files (the "Software"), to deal in 10 the Software without restriction, including without limitation the rights to 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 of the Software, and to permit persons to whom the Software is furnished to do 13 so, subject to the following conditions: 14 15 The above copyright notice and this permission notice applies to all licensees 16 and shall be included in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name of Be Incorporated shall not be 26 used in advertising or otherwise to promote the sale, use or other dealings in 27 this Software without prior written authorization from Be Incorporated. 28 29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30 of Be Incorporated in the United States and other countries. Other brand product 31 names are registered trademarks or trademarks of their respective holders. 32 All rights reserved. 33 */ 34 35 36 #include <Alert.h> 37 #include <Box.h> 38 #include <Catalog.h> 39 #include <Locale.h> 40 #include <MenuItem.h> 41 #include <MessageFilter.h> 42 43 #include "AutoLock.h" 44 #include "ContainerWindow.h" 45 #include "Commands.h" 46 #include "Screen.h" 47 #include "SelectionWindow.h" 48 49 50 const uint32 kSelectButtonPressed = 'sbpr'; 51 52 53 #undef B_TRANSLATION_CONTEXT 54 #define B_TRANSLATION_CONTEXT "SelectionWindow" 55 56 57 SelectionWindow::SelectionWindow(BContainerWindow* window) 58 : 59 BWindow(BRect(0, 0, 270, 0), B_TRANSLATE("Select"), B_TITLED_WINDOW, 60 B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_NOT_V_RESIZABLE 61 | B_NO_WORKSPACE_ACTIVATION | B_ASYNCHRONOUS_CONTROLS 62 | B_NOT_ANCHORED_ON_ACTIVATE), 63 fParentWindow(window) 64 { 65 if (window->Feel() & kPrivateDesktopWindowFeel) { 66 // The window will not show up if we have B_FLOATING_SUBSET_WINDOW_FEEL 67 // and use it with the desktop window since it's never in front. 68 SetFeel(B_NORMAL_WINDOW_FEEL); 69 } 70 71 AddToSubset(fParentWindow); 72 73 BView *backgroundView = new BView(Bounds(), "bgView", B_FOLLOW_ALL, B_WILL_DRAW); 74 backgroundView->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 75 AddChild(backgroundView); 76 77 BMenu *menu = new BPopUpMenu(""); 78 menu->AddItem(new BMenuItem(B_TRANSLATE("starts with"), NULL)); 79 menu->AddItem(new BMenuItem(B_TRANSLATE("ends with"), NULL)); 80 menu->AddItem(new BMenuItem(B_TRANSLATE("contains"), NULL)); 81 menu->AddItem(new BMenuItem(B_TRANSLATE("matches wildcard expression"), 82 NULL)); 83 menu->AddItem(new BMenuItem(B_TRANSLATE("matches regular expression"), 84 NULL)); 85 86 menu->SetLabelFromMarked(true); 87 menu->ItemAt(3)->SetMarked(true); 88 // Set wildcard matching to default. 89 90 // Set up the menu field 91 fMatchingTypeMenuField = new BMenuField(BRect(7, 6, Bounds().right - 5, 0), 92 NULL, B_TRANSLATE("Name"), menu); 93 backgroundView->AddChild(fMatchingTypeMenuField); 94 fMatchingTypeMenuField->SetDivider(fMatchingTypeMenuField->StringWidth( 95 B_TRANSLATE("Name")) + 8); 96 fMatchingTypeMenuField->ResizeToPreferred(); 97 98 // Set up the expression text control 99 fExpressionTextControl = new BTextControl(BRect(7, fMatchingTypeMenuField-> 100 Bounds().bottom + 11, Bounds().right - 6, 0), NULL, NULL, NULL, NULL, 101 B_FOLLOW_LEFT_RIGHT); 102 backgroundView->AddChild(fExpressionTextControl); 103 fExpressionTextControl->ResizeToPreferred(); 104 fExpressionTextControl->MakeFocus(true); 105 106 // Set up the Invert checkbox 107 fInverseCheckBox = new BCheckBox( 108 BRect(7, fExpressionTextControl->Frame().bottom + 6, 6, 6), NULL, 109 B_TRANSLATE("Invert"), NULL); 110 backgroundView->AddChild(fInverseCheckBox); 111 fInverseCheckBox->ResizeToPreferred(); 112 113 // Set up the Ignore Case checkbox 114 fIgnoreCaseCheckBox = new BCheckBox( 115 BRect(fInverseCheckBox->Frame().right + 10, 116 fInverseCheckBox->Frame().top, 6, 6), NULL, B_TRANSLATE("Ignore case"), 117 NULL); 118 fIgnoreCaseCheckBox->SetValue(1); 119 backgroundView->AddChild(fIgnoreCaseCheckBox); 120 fIgnoreCaseCheckBox->ResizeToPreferred(); 121 122 // Set up the Select button 123 fSelectButton = new BButton(BRect(0, 0, 5, 5), NULL, B_TRANSLATE("Select"), 124 new BMessage(kSelectButtonPressed), B_FOLLOW_RIGHT); 125 126 backgroundView->AddChild(fSelectButton); 127 fSelectButton->ResizeToPreferred(); 128 fSelectButton->MoveTo(Bounds().right - 10 - fSelectButton->Bounds().right, 129 fExpressionTextControl->Frame().bottom + 9); 130 fSelectButton->MakeDefault(true); 131 #if !B_BEOS_VERSION_DANO 132 fSelectButton->SetLowColor(backgroundView->ViewColor()); 133 fSelectButton->SetViewColor(B_TRANSPARENT_COLOR); 134 #endif 135 136 font_height fh; 137 be_plain_font->GetHeight(&fh); 138 // Center the checkboxes vertically to the button 139 float topMiddleButton = 140 (fSelectButton->Bounds().Height() / 2 - 141 (fh.ascent + fh.descent + fh.leading + 4) / 2) + fSelectButton->Frame().top; 142 fInverseCheckBox->MoveTo(fInverseCheckBox->Frame().left, topMiddleButton); 143 fIgnoreCaseCheckBox->MoveTo(fIgnoreCaseCheckBox->Frame().left, 144 topMiddleButton); 145 146 float bottomMinWidth = 32 + fSelectButton->Bounds().Width() + 147 fInverseCheckBox->Bounds().Width() + fIgnoreCaseCheckBox->Bounds().Width(); 148 float topMinWidth = be_plain_font->StringWidth( 149 B_TRANSLATE("Name matches wildcard expression:###")); 150 float minWidth = bottomMinWidth > topMinWidth ? bottomMinWidth : topMinWidth; 151 152 class EscapeFilter : public BMessageFilter { 153 public: 154 EscapeFilter(BWindow* target) 155 : 156 BMessageFilter(B_KEY_DOWN), 157 fTarget(target) 158 { 159 } 160 161 virtual filter_result Filter(BMessage* message, BHandler** _target) 162 { 163 int8 byte; 164 if (message->what == B_KEY_DOWN 165 && message->FindInt8("byte", &byte) == B_OK 166 && byte == B_ESCAPE) { 167 fTarget->Hide(); 168 return B_SKIP_MESSAGE; 169 } 170 return B_DISPATCH_MESSAGE; 171 } 172 173 private: 174 BWindow* fTarget; 175 }; 176 AddCommonFilter(new(std::nothrow) EscapeFilter(this)); 177 178 Run(); 179 180 Lock(); 181 ResizeTo(minWidth, fSelectButton->Frame().bottom + 6); 182 183 SetSizeLimits(minWidth, 1280, Bounds().bottom, Bounds().bottom); 184 185 MoveCloseToMouse(); 186 Unlock(); 187 } 188 189 190 void 191 SelectionWindow::MessageReceived(BMessage *message) 192 { 193 switch (message->what) { 194 case kSelectButtonPressed: 195 { 196 Hide(); 197 // Order of posting and hiding important 198 // since we want to activate the target 199 // window when the message arrives. 200 // (Hide is synhcronous, while PostMessage is not.) 201 // See PoseView::SelectMatchingEntries(). 202 203 BMessage *selectionInfo = new BMessage(kSelectMatchingEntries); 204 selectionInfo->AddInt32("ExpressionType", ExpressionType()); 205 BString expression; 206 Expression(expression); 207 selectionInfo->AddString("Expression", expression.String()); 208 selectionInfo->AddBool("InvertSelection", Invert()); 209 selectionInfo->AddBool("IgnoreCase", IgnoreCase()); 210 fParentWindow->PostMessage(selectionInfo); 211 break; 212 } 213 214 default: 215 _inherited::MessageReceived(message); 216 } 217 } 218 219 220 bool 221 SelectionWindow::QuitRequested() 222 { 223 Hide(); 224 return false; 225 } 226 227 228 void 229 SelectionWindow::MoveCloseToMouse() 230 { 231 uint32 buttons; 232 BPoint mousePosition; 233 234 ChildAt((int32)0)->GetMouse(&mousePosition, &buttons); 235 ConvertToScreen(&mousePosition); 236 237 // Position the window centered around the mouse... 238 BPoint windowPosition = BPoint(mousePosition.x - Frame().Width() / 2, 239 mousePosition.y - Frame().Height() / 2); 240 241 // ... unless that's outside of the current screen size: 242 BScreen screen; 243 windowPosition.x = MAX(20, MIN(screen.Frame().right - 20 - Frame().Width(), 244 windowPosition.x)); 245 windowPosition.y = MAX(20, 246 MIN(screen.Frame().bottom - 20 - Frame().Height(), windowPosition.y)); 247 248 MoveTo(windowPosition); 249 SetWorkspaces(1UL << current_workspace()); 250 } 251 252 253 TrackerStringExpressionType 254 SelectionWindow::ExpressionType() const 255 { 256 if (!fMatchingTypeMenuField->LockLooper()) 257 return kNone; 258 259 BMenuItem *item = fMatchingTypeMenuField->Menu()->FindMarked(); 260 if (!item) { 261 fMatchingTypeMenuField->UnlockLooper(); 262 return kNone; 263 } 264 265 int32 index = fMatchingTypeMenuField->Menu()->IndexOf(item); 266 267 fMatchingTypeMenuField->UnlockLooper(); 268 269 if (index < kStartsWith || index > kRegexpMatch) 270 return kNone; 271 272 TrackerStringExpressionType typeArray[] = { kStartsWith, kEndsWith, 273 kContains, kGlobMatch, kRegexpMatch}; 274 275 return typeArray[index]; 276 } 277 278 279 void 280 SelectionWindow::Expression(BString &result) const 281 { 282 if (!fExpressionTextControl->LockLooper()) 283 return; 284 285 result = fExpressionTextControl->Text(); 286 287 fExpressionTextControl->UnlockLooper(); 288 } 289 290 291 bool 292 SelectionWindow::IgnoreCase() const 293 { 294 if (!fIgnoreCaseCheckBox->LockLooper()) { 295 // default action. 296 return true; 297 } 298 299 bool ignore = fIgnoreCaseCheckBox->Value() != 0; 300 301 fIgnoreCaseCheckBox->UnlockLooper(); 302 303 return ignore; 304 } 305 306 307 bool 308 SelectionWindow::Invert() const 309 { 310 if (!fInverseCheckBox->LockLooper()) { 311 // default action. 312 return false; 313 } 314 315 bool inverse = fInverseCheckBox->Value() != 0; 316 317 fInverseCheckBox->UnlockLooper(); 318 319 return inverse; 320 } 321