xref: /haiku/src/apps/webpositive/autocompletion/TextViewCompleter.cpp (revision 21258e2674226d6aa732321b6f8494841895af5f)
1 /*
2  * Copyright 2002-2006, project beam (http://sourceforge.net/projects/beam).
3  * All rights reserved. Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Oliver Tappe <beam@hirschkaefer.de>
7  */
8 
9 #include "TextViewCompleter.h"
10 
11 #include <Looper.h>
12 #include <TextControl.h>
13 #include <stdio.h>
14 
15 #include "AutoCompleterDefaultImpl.h"
16 
17 
18 // #pragma mark - TextViewWrapper
19 
20 
21 TextViewCompleter::TextViewWrapper::TextViewWrapper(BTextView* textView)
22 	:
23 	fTextView(textView)
24 {
25 }
26 
27 
28 void
29 TextViewCompleter::TextViewWrapper::GetEditViewState(BString& text,
30 	int32* caretPos)
31 {
32 	if (fTextView && fTextView->LockLooper()) {
33 		text = fTextView->Text();
34 		if (caretPos) {
35 			int32 end;
36 			fTextView->GetSelection(caretPos, &end);
37 		}
38 		fTextView->UnlockLooper();
39 	}
40 }
41 
42 
43 void
44 TextViewCompleter::TextViewWrapper::SetEditViewState(const BString& text,
45 	int32 caretPos, int32 selectionLength)
46 {
47 	if (fTextView && fTextView->LockLooper()) {
48 		fTextView->SetText(text.String(), text.Length());
49 		fTextView->Select(caretPos, caretPos + selectionLength);
50 		fTextView->ScrollToSelection();
51 		fTextView->UnlockLooper();
52 	}
53 }
54 
55 
56 BRect
57 TextViewCompleter::TextViewWrapper::GetAdjustmentFrame()
58 {
59 	BRect frame = fTextView->Bounds();
60 	frame = fTextView->ConvertToScreen(frame);
61 	frame.InsetBy(0, -3);
62 	return frame;
63 }
64 
65 
66 // #pragma mark -
67 
68 
69 TextViewCompleter::TextViewCompleter(BTextView* textView, ChoiceModel* model,
70 		PatternSelector* patternSelector)
71 	:
72 	BAutoCompleter(new TextViewWrapper(textView), model,
73 		new BDefaultChoiceView(), patternSelector),
74 	BMessageFilter(B_KEY_DOWN),
75 	fTextView(textView),
76 	fModificationsReported(false)
77 {
78 	fTextView->AddFilter(this);
79 }
80 
81 
82 TextViewCompleter::~TextViewCompleter()
83 {
84 	fTextView->RemoveFilter(this);
85 }
86 
87 
88 void
89 TextViewCompleter::SetModificationsReported(bool reported)
90 {
91 	fModificationsReported = reported;
92 }
93 
94 
95 void
96 TextViewCompleter::TextModified(bool updateChoices)
97 {
98 	EditViewStateChanged(updateChoices);
99 }
100 
101 
102 filter_result
103 TextViewCompleter::Filter(BMessage* message, BHandler** target)
104 {
105 	const char* bytes;
106 	int32 modifiers;
107 	if ((!target || message->FindString("bytes", &bytes) != B_OK
108 			|| message->FindInt32("modifiers", &modifiers) != B_OK)
109 		|| (modifiers & (B_CONTROL_KEY | B_COMMAND_KEY | B_OPTION_KEY
110 			| B_SHIFT_KEY)) != 0) {
111 		return B_DISPATCH_MESSAGE;
112 	}
113 
114 	switch (bytes[0]) {
115 		case B_UP_ARROW:
116 			SelectPrevious();
117 			// Insert the current choice into the text view, so the user can
118 			// continue typing. This will not trigger another evaluation, since
119 			// we don't invoke EditViewStateChanged().
120 			ApplyChoice(false);
121 			return B_SKIP_MESSAGE;
122 		case B_DOWN_ARROW:
123 			SelectNext();
124 			// See above.
125 			ApplyChoice(false);
126 			return B_SKIP_MESSAGE;
127 		case B_PAGE_UP:
128 		{
129 			int32 index = SelectedChoiceIndex() - CountVisibleChoices();
130 			index = max_c(index, 0);
131 			Select(index);
132 			ApplyChoice(false);
133 			return B_SKIP_MESSAGE;
134 		}
135 		case B_PAGE_DOWN:
136 		{
137 			int32 index = SelectedChoiceIndex() + CountVisibleChoices();
138 			index = min_c(index, CountChoices() - 1);
139 			Select(index);
140 			ApplyChoice(false);
141 			return B_SKIP_MESSAGE;
142 		}
143 
144 		case B_ESCAPE:
145 			CancelChoice();
146 			return B_DISPATCH_MESSAGE;
147 		case B_RETURN:
148 			if (IsChoiceSelected()) {
149 				ApplyChoice();
150 				EditViewStateChanged();
151 			} else
152 				CancelChoice();
153 			return B_DISPATCH_MESSAGE;
154 		case B_TAB: {
155 			// make sure that the choices-view is closed when tabbing out:
156 			CancelChoice();
157 			return B_DISPATCH_MESSAGE;
158 		}
159 		default:
160 			if (!fModificationsReported) {
161 				// dispatch message to textview manually...
162 				Looper()->DispatchMessage(message, *target);
163 				// ...and propagate the new state to the auto-completer:
164 				EditViewStateChanged();
165 				return B_SKIP_MESSAGE;
166 			}
167 			return B_DISPATCH_MESSAGE;
168 	}
169 }
170