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
TextViewWrapper(BTextView * textView)21 TextViewCompleter::TextViewWrapper::TextViewWrapper(BTextView* textView)
22 :
23 fTextView(textView)
24 {
25 }
26
27
28 void
GetEditViewState(BString & text,int32 * caretPos)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
SetEditViewState(const BString & text,int32 caretPos,int32 selectionLength)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
GetAdjustmentFrame()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
TextViewCompleter(BTextView * textView,ChoiceModel * model,PatternSelector * patternSelector)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
~TextViewCompleter()82 TextViewCompleter::~TextViewCompleter()
83 {
84 fTextView->RemoveFilter(this);
85 }
86
87
88 void
SetModificationsReported(bool reported)89 TextViewCompleter::SetModificationsReported(bool reported)
90 {
91 fModificationsReported = reported;
92 }
93
94
95 void
TextModified(bool updateChoices)96 TextViewCompleter::TextModified(bool updateChoices)
97 {
98 EditViewStateChanged(updateChoices);
99 }
100
101
102 filter_result
Filter(BMessage * message,BHandler ** target)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