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