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