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