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