1/*
2 * Copyright 2002-2009, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Mattias Sundblad
7 *		Andrew Bachmann
8 */
9
10
11#include "Constants.h"
12#include "ReplaceWindow.h"
13
14#include <Button.h>
15#include <Catalog.h>
16#include <CheckBox.h>
17#include <GroupLayoutBuilder.h>
18#include <GridLayoutBuilder.h>
19#include <Handler.h>
20#include <Locale.h>
21#include <LayoutBuilder.h>
22#include <Message.h>
23#include <Messenger.h>
24#include <String.h>
25#include <TextControl.h>
26
27
28#undef B_TRANSLATION_CONTEXT
29#define B_TRANSLATION_CONTEXT "FindandReplaceWindow"
30
31ReplaceWindow::ReplaceWindow(BRect frame, BHandler* _handler,
32	BString* searchString, 	BString* replaceString,
33	bool caseState, bool wrapState, bool backState)
34	: BWindow(frame, B_TRANSLATE("Replace"), B_FLOATING_WINDOW,
35		B_NOT_RESIZABLE |  B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS
36		| B_AUTO_UPDATE_SIZE_LIMITS, B_CURRENT_WORKSPACE)
37{
38	AddShortcut('W', B_COMMAND_KEY, new BMessage(MSG_HIDE_WINDOW));
39
40	fSearchString = new BTextControl("", B_TRANSLATE("Find:"), NULL, NULL);
41	fReplaceString = new BTextControl("", B_TRANSLATE("Replace with:"),
42		NULL, NULL);
43	fCaseSensBox = new BCheckBox("", B_TRANSLATE("Case-sensitive"), NULL);
44	fWrapBox = new BCheckBox("", B_TRANSLATE("Wrap-around search"), NULL);
45	fBackSearchBox = new BCheckBox("", B_TRANSLATE("Search backwards"), NULL);
46	fAllWindowsBox = new BCheckBox("", B_TRANSLATE("Replace in all windows"),
47		new BMessage(CHANGE_WINDOW));
48	fUIchange = false;
49
50	fReplaceAllButton = new BButton("", B_TRANSLATE("Replace all"),
51		new BMessage(MSG_REPLACE_ALL));
52	fCancelButton = new BButton("", B_TRANSLATE("Cancel"),
53		new BMessage(MSG_HIDE_WINDOW));
54	fReplaceButton = new BButton("", B_TRANSLATE("Replace"),
55		new BMessage(MSG_REPLACE));
56
57	SetLayout(new BGroupLayout(B_HORIZONTAL));
58	AddChild(BGroupLayoutBuilder(B_VERTICAL, 4)
59		.Add(BGridLayoutBuilder(6, 2)
60				.Add(fSearchString->CreateLabelLayoutItem(), 0, 0)
61				.Add(fSearchString->CreateTextViewLayoutItem(), 1, 0)
62				.Add(fReplaceString->CreateLabelLayoutItem(), 0, 1)
63				.Add(fReplaceString->CreateTextViewLayoutItem(), 1, 1)
64				.Add(fCaseSensBox, 1, 2)
65				.Add(fWrapBox, 1, 3)
66				.Add(fBackSearchBox, 1, 4)
67				.Add(fAllWindowsBox, 1, 5)
68				)
69		.AddGroup(B_HORIZONTAL, 10)
70			.Add(fReplaceAllButton)
71			.AddGlue()
72			.Add(fCancelButton)
73			.Add(fReplaceButton)
74		.End()
75		.SetInsets(10, 10, 10, 10)
76	);
77
78	fReplaceButton->MakeDefault(true);
79
80	fHandler = _handler;
81
82	const char* searchtext = searchString->String();
83	const char* replacetext = replaceString->String();
84
85	fSearchString->SetText(searchtext);
86	fReplaceString->SetText(replacetext);
87	fSearchString->MakeFocus(true);
88
89	fCaseSensBox->SetValue(caseState ? B_CONTROL_ON : B_CONTROL_OFF);
90	fWrapBox->SetValue(wrapState ? B_CONTROL_ON : B_CONTROL_OFF);
91	fBackSearchBox->SetValue(backState ? B_CONTROL_ON : B_CONTROL_OFF);
92}
93
94
95void
96ReplaceWindow::MessageReceived(BMessage* msg)
97{
98	switch (msg->what) {
99		case MSG_REPLACE:
100			_SendMessage(MSG_REPLACE);
101			break;
102		case CHANGE_WINDOW:
103			_ChangeUI();
104			break;
105		case MSG_REPLACE_ALL:
106			_SendMessage(MSG_REPLACE_ALL);
107			break;
108
109		case MSG_HIDE_WINDOW:
110			if (!IsHidden())
111				Hide();
112			break;
113		default:
114			BWindow::MessageReceived(msg);
115			break;
116	}
117}
118
119
120void
121ReplaceWindow::_ChangeUI()
122{
123	fWrapBox->SetEnabled(fUIchange);
124	fWrapBox->SetValue(fUIchange ? B_CONTROL_OFF : B_CONTROL_ON);
125
126	fBackSearchBox->SetEnabled(fUIchange);
127
128	fReplaceButton->SetEnabled(fUIchange);
129	if (fUIchange)
130		fReplaceButton->MakeDefault(true);
131	else
132		fReplaceAllButton->MakeDefault(true);
133
134	fUIchange = !fUIchange;
135}
136
137
138void
139ReplaceWindow::DispatchMessage(BMessage* message, BHandler* handler)
140{
141	if (message->what == B_KEY_DOWN) {
142		int8 key;
143		if (message->FindInt8("byte", 0, &key) == B_OK) {
144			if (key == B_ESCAPE) {
145				message->MakeEmpty();
146				message->what = MSG_HIDE_WINDOW;
147
148				// This is a hack, but it actually does what is expected,
149				// unlike the hack above. This kind of key filtering probably
150				// ought to be handled by a BMessageFilter, though.
151				BMessenger (this).SendMessage(MSG_HIDE_WINDOW);
152			}
153		}
154	}
155
156	BWindow::DispatchMessage(message, handler);
157}
158
159
160bool
161ReplaceWindow::QuitRequested()
162{
163	BMessenger messenger(fHandler);
164	messenger.SendMessage(MSG_REPLACE_WINDOW_QUIT);
165
166	return true;
167}
168
169
170void
171ReplaceWindow::Show()
172{
173	fSearchString->TextView()->SelectAll();
174	BWindow::Show();
175}
176
177
178void
179ReplaceWindow::_SendMessage(uint32 what)
180{
181	BMessage message(what);
182
183	// Add the strings
184	message.AddString("FindText", fSearchString->Text());
185	message.AddString("ReplaceText", fReplaceString->Text());
186
187	// Add searchparameters from checkboxes
188	message.AddBool("casesens", fCaseSensBox->Value() == B_CONTROL_ON);
189	message.AddBool("wrap", fWrapBox->Value() == B_CONTROL_ON);
190	message.AddBool("backsearch", fBackSearchBox->Value() == B_CONTROL_ON);
191	message.AddBool("allwindows", fAllWindowsBox->Value() == B_CONTROL_ON);
192
193	fHandler->Looper()->PostMessage(&message, fHandler);
194
195	PostMessage(MSG_HIDE_WINDOW);
196}
197
198