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 // #pragma mark - SelectionWindow 54 55 56 #undef B_TRANSLATION_CONTEXT 57 #define B_TRANSLATION_CONTEXT "SelectionWindow" 58 59 60 SelectionWindow::SelectionWindow(BContainerWindow* window) 61 : 62 BWindow(BRect(0, 0, 270, 0), B_TRANSLATE("Select"), B_TITLED_WINDOW, 63 B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_NOT_V_RESIZABLE 64 | B_NO_WORKSPACE_ACTIVATION | B_ASYNCHRONOUS_CONTROLS 65 | B_NOT_ANCHORED_ON_ACTIVATE), 66 fParentWindow(window) 67 { 68 if (window->Feel() & kPrivateDesktopWindowFeel) { 69 // The window will not show up if we have 70 // B_FLOATING_SUBSET_WINDOW_FEEL and use it with the desktop window 71 // since it's never in front. 72 SetFeel(B_NORMAL_WINDOW_FEEL); 73 } 74 75 AddToSubset(fParentWindow); 76 77 BView* backgroundView = new BView(Bounds(), "bgView", B_FOLLOW_ALL, 78 B_WILL_DRAW); 79 backgroundView->SetViewUIColor(B_PANEL_BACKGROUND_COLOR); 80 AddChild(backgroundView); 81 82 BMenu* menu = new BPopUpMenu(""); 83 menu->AddItem(new BMenuItem(B_TRANSLATE("starts with"), NULL)); 84 menu->AddItem(new BMenuItem(B_TRANSLATE("ends with"), NULL)); 85 menu->AddItem(new BMenuItem(B_TRANSLATE("contains"), NULL)); 86 menu->AddItem(new BMenuItem(B_TRANSLATE("matches wildcard expression"), 87 NULL)); 88 menu->AddItem(new BMenuItem(B_TRANSLATE("matches regular expression"), 89 NULL)); 90 91 menu->SetLabelFromMarked(true); 92 menu->ItemAt(3)->SetMarked(true); 93 // Set wildcard matching to default. 94 95 // Set up the menu field 96 fMatchingTypeMenuField = new BMenuField(BRect(7, 6, 97 Bounds().right - 5, 0), NULL, B_TRANSLATE("Name"), menu); 98 backgroundView->AddChild(fMatchingTypeMenuField); 99 fMatchingTypeMenuField->SetDivider(fMatchingTypeMenuField->StringWidth( 100 B_TRANSLATE("Name")) + 8); 101 fMatchingTypeMenuField->ResizeToPreferred(); 102 103 // Set up the expression text control 104 fExpressionTextControl = new BTextControl(BRect(7, 105 fMatchingTypeMenuField->Bounds().bottom + 11, 106 Bounds().right - 6, 0), 107 NULL, NULL, NULL, NULL, B_FOLLOW_LEFT_RIGHT); 108 backgroundView->AddChild(fExpressionTextControl); 109 fExpressionTextControl->ResizeToPreferred(); 110 fExpressionTextControl->MakeFocus(true); 111 112 // Set up the Invert checkbox 113 fInverseCheckBox = new BCheckBox( 114 BRect(7, fExpressionTextControl->Frame().bottom + 6, 6, 6), NULL, 115 B_TRANSLATE("Invert"), NULL); 116 backgroundView->AddChild(fInverseCheckBox); 117 fInverseCheckBox->ResizeToPreferred(); 118 119 // Set up the Ignore Case checkbox 120 fIgnoreCaseCheckBox = new BCheckBox( 121 BRect(fInverseCheckBox->Frame().right + 10, 122 fInverseCheckBox->Frame().top, 6, 6), 123 NULL, B_TRANSLATE("Ignore case"), NULL); 124 fIgnoreCaseCheckBox->SetValue(1); 125 backgroundView->AddChild(fIgnoreCaseCheckBox); 126 fIgnoreCaseCheckBox->ResizeToPreferred(); 127 128 // Set up the Select button 129 fSelectButton = new BButton(BRect(0, 0, 5, 5), NULL, 130 B_TRANSLATE("Select"), new BMessage(kSelectButtonPressed), 131 B_FOLLOW_RIGHT); 132 133 backgroundView->AddChild(fSelectButton); 134 fSelectButton->ResizeToPreferred(); 135 fSelectButton->MoveTo(Bounds().right - 10 - fSelectButton->Bounds().right, 136 fExpressionTextControl->Frame().bottom + 9); 137 fSelectButton->MakeDefault(true); 138 #if !B_BEOS_VERSION_DANO 139 fSelectButton->SetLowColor(backgroundView->ViewColor()); 140 fSelectButton->SetViewColor(B_TRANSPARENT_COLOR); 141 #endif 142 143 font_height fh; 144 be_plain_font->GetHeight(&fh); 145 // Center the checkboxes vertically to the button 146 float topMiddleButton = 147 (fSelectButton->Bounds().Height() / 2 - 148 (fh.ascent + fh.descent + fh.leading + 4) / 2) 149 + fSelectButton->Frame().top; 150 fInverseCheckBox->MoveTo(fInverseCheckBox->Frame().left, topMiddleButton); 151 fIgnoreCaseCheckBox->MoveTo(fIgnoreCaseCheckBox->Frame().left, 152 topMiddleButton); 153 154 float bottomMinWidth = 32 + fSelectButton->Bounds().Width() 155 + fInverseCheckBox->Bounds().Width() 156 + fIgnoreCaseCheckBox->Bounds().Width(); 157 float topMinWidth = be_plain_font->StringWidth( 158 B_TRANSLATE("Name matches wildcard expression:###")); 159 float minWidth = bottomMinWidth > topMinWidth 160 ? bottomMinWidth : topMinWidth; 161 162 class EscapeFilter : public BMessageFilter { 163 public: 164 EscapeFilter(BWindow* target) 165 : 166 BMessageFilter(B_KEY_DOWN), 167 fTarget(target) 168 { 169 } 170 171 virtual filter_result Filter(BMessage* message, BHandler** _target) 172 { 173 int8 byte; 174 if (message->what == B_KEY_DOWN 175 && message->FindInt8("byte", &byte) == B_OK 176 && byte == B_ESCAPE) { 177 fTarget->Hide(); 178 return B_SKIP_MESSAGE; 179 } 180 return B_DISPATCH_MESSAGE; 181 } 182 183 private: 184 BWindow* fTarget; 185 }; 186 AddCommonFilter(new(std::nothrow) EscapeFilter(this)); 187 188 Run(); 189 190 Lock(); 191 ResizeTo(minWidth, fSelectButton->Frame().bottom + 6); 192 193 SetSizeLimits(minWidth, 1280, Bounds().bottom, Bounds().bottom); 194 195 MoveCloseToMouse(); 196 Unlock(); 197 } 198 199 200 void 201 SelectionWindow::MessageReceived(BMessage* message) 202 { 203 switch (message->what) { 204 case kSelectButtonPressed: 205 { 206 Hide(); 207 // Order of posting and hiding important 208 // since we want to activate the target 209 // window when the message arrives. 210 // (Hide is synhcronous, while PostMessage is not.) 211 // See PoseView::SelectMatchingEntries(). 212 213 BMessage* selectionInfo = new BMessage(kSelectMatchingEntries); 214 selectionInfo->AddInt32("ExpressionType", ExpressionType()); 215 BString expression; 216 Expression(expression); 217 selectionInfo->AddString("Expression", expression.String()); 218 selectionInfo->AddBool("InvertSelection", Invert()); 219 selectionInfo->AddBool("IgnoreCase", IgnoreCase()); 220 fParentWindow->PostMessage(selectionInfo); 221 break; 222 } 223 224 default: 225 _inherited::MessageReceived(message); 226 break; 227 } 228 } 229 230 231 bool 232 SelectionWindow::QuitRequested() 233 { 234 Hide(); 235 return false; 236 } 237 238 239 void 240 SelectionWindow::MoveCloseToMouse() 241 { 242 uint32 buttons; 243 BPoint mousePosition; 244 245 ChildAt((int32)0)->GetMouse(&mousePosition, &buttons); 246 ConvertToScreen(&mousePosition); 247 248 // Position the window centered around the mouse... 249 BPoint windowPosition = BPoint(mousePosition.x - Frame().Width() / 2, 250 mousePosition.y - Frame().Height() / 2); 251 252 // ... unless that's outside of the current screen size: 253 BScreen screen; 254 windowPosition.x 255 = MAX(20, MIN(screen.Frame().right - 20 - Frame().Width(), 256 windowPosition.x)); 257 windowPosition.y = MAX(20, 258 MIN(screen.Frame().bottom - 20 - Frame().Height(), windowPosition.y)); 259 260 MoveTo(windowPosition); 261 SetWorkspaces(1UL << current_workspace()); 262 } 263 264 265 TrackerStringExpressionType 266 SelectionWindow::ExpressionType() const 267 { 268 if (!fMatchingTypeMenuField->LockLooper()) 269 return kNone; 270 271 BMenuItem* item = fMatchingTypeMenuField->Menu()->FindMarked(); 272 if (item == NULL) { 273 fMatchingTypeMenuField->UnlockLooper(); 274 return kNone; 275 } 276 277 int32 index = fMatchingTypeMenuField->Menu()->IndexOf(item); 278 279 fMatchingTypeMenuField->UnlockLooper(); 280 281 if (index < kStartsWith || index > kRegexpMatch) 282 return kNone; 283 284 TrackerStringExpressionType typeArray[] = { kStartsWith, kEndsWith, 285 kContains, kGlobMatch, kRegexpMatch}; 286 287 return typeArray[index]; 288 } 289 290 291 void 292 SelectionWindow::Expression(BString &result) const 293 { 294 if (!fExpressionTextControl->LockLooper()) 295 return; 296 297 result = fExpressionTextControl->Text(); 298 299 fExpressionTextControl->UnlockLooper(); 300 } 301 302 303 bool 304 SelectionWindow::IgnoreCase() const 305 { 306 if (!fIgnoreCaseCheckBox->LockLooper()) { 307 // default action 308 return true; 309 } 310 311 bool ignore = fIgnoreCaseCheckBox->Value() != 0; 312 313 fIgnoreCaseCheckBox->UnlockLooper(); 314 315 return ignore; 316 } 317 318 319 bool 320 SelectionWindow::Invert() const 321 { 322 if (!fInverseCheckBox->LockLooper()) { 323 // default action 324 return false; 325 } 326 327 bool inverse = fInverseCheckBox->Value() != 0; 328 329 fInverseCheckBox->UnlockLooper(); 330 331 return inverse; 332 } 333