1d7f7bf2dSAxel Dörfler /*
281f55cc8SStephan Aßmus * Copyright 2013-2015, Stephan Aßmus <superstippi@gmx.de>.
3d7f7bf2dSAxel Dörfler * All rights reserved. Distributed under the terms of the MIT License.
4d7f7bf2dSAxel Dörfler */
5d7f7bf2dSAxel Dörfler
6d7f7bf2dSAxel Dörfler #include "TextDocumentView.h"
7d7f7bf2dSAxel Dörfler
8d7f7bf2dSAxel Dörfler #include <algorithm>
9d7f7bf2dSAxel Dörfler #include <stdio.h>
10d7f7bf2dSAxel Dörfler
11d7f7bf2dSAxel Dörfler #include <Clipboard.h>
12d7f7bf2dSAxel Dörfler #include <Cursor.h>
1381f55cc8SStephan Aßmus #include <MessageRunner.h>
14d7f7bf2dSAxel Dörfler #include <ScrollBar.h>
15d7f7bf2dSAxel Dörfler #include <Shape.h>
16d7f7bf2dSAxel Dörfler #include <Window.h>
17d7f7bf2dSAxel Dörfler
18d7f7bf2dSAxel Dörfler
19c4e439b5SAndrew Lindesay const char* kMimeTypePlainText = "text/plain";
20c4e439b5SAndrew Lindesay
21c4e439b5SAndrew Lindesay
2281f55cc8SStephan Aßmus enum {
2381f55cc8SStephan Aßmus MSG_BLINK_CARET = 'blnk',
2481f55cc8SStephan Aßmus };
2581f55cc8SStephan Aßmus
2681f55cc8SStephan Aßmus
TextDocumentView(const char * name)27d7f7bf2dSAxel Dörfler TextDocumentView::TextDocumentView(const char* name)
28d7f7bf2dSAxel Dörfler :
2981f55cc8SStephan Aßmus BView(name, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_FRAME_EVENTS),
30*73b4c7a6SJohn Scipione fTextDocument(NULL),
31*73b4c7a6SJohn Scipione fTextEditor(NULL),
32d7f7bf2dSAxel Dörfler fInsetLeft(0.0f),
33d7f7bf2dSAxel Dörfler fInsetTop(0.0f),
34d7f7bf2dSAxel Dörfler fInsetRight(0.0f),
35d7f7bf2dSAxel Dörfler fInsetBottom(0.0f),
36d7f7bf2dSAxel Dörfler
37d7f7bf2dSAxel Dörfler fCaretBounds(),
3881f55cc8SStephan Aßmus fCaretBlinker(NULL),
3981f55cc8SStephan Aßmus fCaretBlinkToken(0),
406e2ac177SStephan Aßmus fSelectionEnabled(true),
41*73b4c7a6SJohn Scipione fShowCaret(false)
42d7f7bf2dSAxel Dörfler {
43d7f7bf2dSAxel Dörfler fTextDocumentLayout.SetWidth(_TextLayoutWidth(Bounds().Width()));
44d7f7bf2dSAxel Dörfler
45d7f7bf2dSAxel Dörfler // Set default TextEditor
46d7f7bf2dSAxel Dörfler SetTextEditor(TextEditorRef(new(std::nothrow) TextEditor(), true));
47d7f7bf2dSAxel Dörfler
48fa19dd44Slooncraz SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
49fa19dd44Slooncraz SetLowUIColor(ViewUIColor());
50d7f7bf2dSAxel Dörfler }
51d7f7bf2dSAxel Dörfler
52d7f7bf2dSAxel Dörfler
~TextDocumentView()53d7f7bf2dSAxel Dörfler TextDocumentView::~TextDocumentView()
54d7f7bf2dSAxel Dörfler {
55d7f7bf2dSAxel Dörfler // Don't forget to remove listeners
56d7f7bf2dSAxel Dörfler SetTextEditor(TextEditorRef());
578d611f17SStephan Aßmus delete fCaretBlinker;
58d7f7bf2dSAxel Dörfler }
59d7f7bf2dSAxel Dörfler
60d7f7bf2dSAxel Dörfler
61d7f7bf2dSAxel Dörfler void
MessageReceived(BMessage * message)62d7f7bf2dSAxel Dörfler TextDocumentView::MessageReceived(BMessage* message)
63d7f7bf2dSAxel Dörfler {
64d7f7bf2dSAxel Dörfler switch (message->what) {
65d7f7bf2dSAxel Dörfler case B_COPY:
66d7f7bf2dSAxel Dörfler Copy(be_clipboard);
67d7f7bf2dSAxel Dörfler break;
68c4e439b5SAndrew Lindesay case B_PASTE:
69c4e439b5SAndrew Lindesay Paste(be_clipboard);
70c4e439b5SAndrew Lindesay break;
7196ebc1d6SStephan Aßmus case B_SELECT_ALL:
7296ebc1d6SStephan Aßmus SelectAll();
7396ebc1d6SStephan Aßmus break;
74d7f7bf2dSAxel Dörfler
7581f55cc8SStephan Aßmus case MSG_BLINK_CARET:
7681f55cc8SStephan Aßmus {
7781f55cc8SStephan Aßmus int32 token;
7881f55cc8SStephan Aßmus if (message->FindInt32("token", &token) == B_OK
7981f55cc8SStephan Aßmus && token == fCaretBlinkToken) {
8081f55cc8SStephan Aßmus _BlinkCaret();
8181f55cc8SStephan Aßmus }
8281f55cc8SStephan Aßmus break;
8381f55cc8SStephan Aßmus }
8481f55cc8SStephan Aßmus
85d7f7bf2dSAxel Dörfler default:
86d7f7bf2dSAxel Dörfler BView::MessageReceived(message);
87d7f7bf2dSAxel Dörfler }
88d7f7bf2dSAxel Dörfler }
89d7f7bf2dSAxel Dörfler
90d7f7bf2dSAxel Dörfler
91d7f7bf2dSAxel Dörfler void
Draw(BRect updateRect)92d7f7bf2dSAxel Dörfler TextDocumentView::Draw(BRect updateRect)
93d7f7bf2dSAxel Dörfler {
94d7f7bf2dSAxel Dörfler FillRect(updateRect, B_SOLID_LOW);
95d7f7bf2dSAxel Dörfler
96d7f7bf2dSAxel Dörfler fTextDocumentLayout.SetWidth(_TextLayoutWidth(Bounds().Width()));
97d7f7bf2dSAxel Dörfler fTextDocumentLayout.Draw(this, BPoint(fInsetLeft, fInsetTop), updateRect);
98d7f7bf2dSAxel Dörfler
99779ab335SX512 if (!fSelectionEnabled || !fTextEditor.IsSet())
100d7f7bf2dSAxel Dörfler return;
101d7f7bf2dSAxel Dörfler
102d7f7bf2dSAxel Dörfler bool isCaret = fTextEditor->SelectionLength() == 0;
103d7f7bf2dSAxel Dörfler
104d7f7bf2dSAxel Dörfler if (isCaret) {
105d7f7bf2dSAxel Dörfler if (fShowCaret && fTextEditor->IsEditingEnabled())
106d7f7bf2dSAxel Dörfler _DrawCaret(fTextEditor->CaretOffset());
107d7f7bf2dSAxel Dörfler } else {
108d7f7bf2dSAxel Dörfler _DrawSelection();
109d7f7bf2dSAxel Dörfler }
110d7f7bf2dSAxel Dörfler }
111d7f7bf2dSAxel Dörfler
112d7f7bf2dSAxel Dörfler
113d7f7bf2dSAxel Dörfler void
AttachedToWindow()114d7f7bf2dSAxel Dörfler TextDocumentView::AttachedToWindow()
115d7f7bf2dSAxel Dörfler {
116d7f7bf2dSAxel Dörfler _UpdateScrollBars();
117d7f7bf2dSAxel Dörfler }
118d7f7bf2dSAxel Dörfler
119d7f7bf2dSAxel Dörfler
120d7f7bf2dSAxel Dörfler void
FrameResized(float width,float height)121d7f7bf2dSAxel Dörfler TextDocumentView::FrameResized(float width, float height)
122d7f7bf2dSAxel Dörfler {
123d7f7bf2dSAxel Dörfler fTextDocumentLayout.SetWidth(width);
124d7f7bf2dSAxel Dörfler _UpdateScrollBars();
125d7f7bf2dSAxel Dörfler }
126d7f7bf2dSAxel Dörfler
127d7f7bf2dSAxel Dörfler
128d7f7bf2dSAxel Dörfler void
WindowActivated(bool active)129d7f7bf2dSAxel Dörfler TextDocumentView::WindowActivated(bool active)
130d7f7bf2dSAxel Dörfler {
131d7f7bf2dSAxel Dörfler Invalidate();
132d7f7bf2dSAxel Dörfler }
133d7f7bf2dSAxel Dörfler
134d7f7bf2dSAxel Dörfler
135d7f7bf2dSAxel Dörfler void
MakeFocus(bool focus)136d7f7bf2dSAxel Dörfler TextDocumentView::MakeFocus(bool focus)
137d7f7bf2dSAxel Dörfler {
138d7f7bf2dSAxel Dörfler if (focus != IsFocus())
139d7f7bf2dSAxel Dörfler Invalidate();
140d7f7bf2dSAxel Dörfler BView::MakeFocus(focus);
141d7f7bf2dSAxel Dörfler }
142d7f7bf2dSAxel Dörfler
143d7f7bf2dSAxel Dörfler
144d7f7bf2dSAxel Dörfler void
MouseDown(BPoint where)145d7f7bf2dSAxel Dörfler TextDocumentView::MouseDown(BPoint where)
146d7f7bf2dSAxel Dörfler {
147*73b4c7a6SJohn Scipione if (!fTextEditor.IsSet() || !fTextDocument.IsSet())
148*73b4c7a6SJohn Scipione return BView::MouseDown(where);
149*73b4c7a6SJohn Scipione
1506af13813SPulkoMandy BMessage* currentMessage = NULL;
1516af13813SPulkoMandy if (Window() != NULL)
1526af13813SPulkoMandy currentMessage = Window()->CurrentMessage();
1536af13813SPulkoMandy
1546af13813SPulkoMandy // First of all, check for links and other clickable things
1556af13813SPulkoMandy bool unused;
1566af13813SPulkoMandy int32 offset = fTextDocumentLayout.TextOffsetAt(where.x, where.y, unused);
1576af13813SPulkoMandy const BMessage* message = fTextDocument->ClickMessageAt(offset);
1586af13813SPulkoMandy if (message != NULL) {
1596af13813SPulkoMandy BMessage clickMessage(*message);
1606af13813SPulkoMandy clickMessage.Append(*currentMessage);
1616af13813SPulkoMandy Invoke(&clickMessage);
1626af13813SPulkoMandy }
1636af13813SPulkoMandy
1646e2ac177SStephan Aßmus if (!fSelectionEnabled)
1656e2ac177SStephan Aßmus return;
1666e2ac177SStephan Aßmus
167d7f7bf2dSAxel Dörfler MakeFocus();
168d7f7bf2dSAxel Dörfler
169d7f7bf2dSAxel Dörfler int32 modifiers = 0;
1706af13813SPulkoMandy if (currentMessage != NULL)
1716af13813SPulkoMandy currentMessage->FindInt32("modifiers", &modifiers);
172d7f7bf2dSAxel Dörfler
173d7f7bf2dSAxel Dörfler SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
174d7f7bf2dSAxel Dörfler
175d7f7bf2dSAxel Dörfler bool extendSelection = (modifiers & B_SHIFT_KEY) != 0;
176d7f7bf2dSAxel Dörfler SetCaret(where, extendSelection);
177*73b4c7a6SJohn Scipione
178*73b4c7a6SJohn Scipione BView::MouseDown(where);
179d7f7bf2dSAxel Dörfler }
180d7f7bf2dSAxel Dörfler
181d7f7bf2dSAxel Dörfler
182d7f7bf2dSAxel Dörfler void
MouseMoved(BPoint where,uint32 transit,const BMessage * dragMessage)183*73b4c7a6SJohn Scipione TextDocumentView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
184d7f7bf2dSAxel Dörfler {
185*73b4c7a6SJohn Scipione if (!fTextEditor.IsSet() || !fTextDocument.IsSet())
186*73b4c7a6SJohn Scipione return BView::MouseMoved(where, transit, dragMessage);
187d7f7bf2dSAxel Dörfler
1886af13813SPulkoMandy BCursor cursor(B_CURSOR_ID_I_BEAM);
1896af13813SPulkoMandy
1906af13813SPulkoMandy if (transit != B_EXITED_VIEW) {
1916af13813SPulkoMandy bool unused;
1926af13813SPulkoMandy int32 offset = fTextDocumentLayout.TextOffsetAt(where.x, where.y, unused);
1936af13813SPulkoMandy const BCursor& newCursor = fTextDocument->CursorAt(offset);
1946af13813SPulkoMandy if (newCursor.InitCheck() == B_OK) {
1956af13813SPulkoMandy cursor = newCursor;
1966af13813SPulkoMandy SetViewCursor(&cursor);
1976af13813SPulkoMandy }
1986af13813SPulkoMandy }
1996af13813SPulkoMandy
2006e2ac177SStephan Aßmus if (!fSelectionEnabled)
2016e2ac177SStephan Aßmus return;
2026e2ac177SStephan Aßmus
2036af13813SPulkoMandy SetViewCursor(&cursor);
204d7f7bf2dSAxel Dörfler
205*73b4c7a6SJohn Scipione uint32 buttons = 0;
206*73b4c7a6SJohn Scipione if (Window() != NULL)
207*73b4c7a6SJohn Scipione Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
208*73b4c7a6SJohn Scipione if (buttons > 0)
209d7f7bf2dSAxel Dörfler SetCaret(where, true);
210*73b4c7a6SJohn Scipione
211*73b4c7a6SJohn Scipione BView::MouseMoved(where, transit, dragMessage);
212d7f7bf2dSAxel Dörfler }
213d7f7bf2dSAxel Dörfler
214d7f7bf2dSAxel Dörfler
215d7f7bf2dSAxel Dörfler void
KeyDown(const char * bytes,int32 numBytes)216d7f7bf2dSAxel Dörfler TextDocumentView::KeyDown(const char* bytes, int32 numBytes)
217d7f7bf2dSAxel Dörfler {
218779ab335SX512 if (!fTextEditor.IsSet())
219d7f7bf2dSAxel Dörfler return;
220d7f7bf2dSAxel Dörfler
221d7f7bf2dSAxel Dörfler KeyEvent event;
222d7f7bf2dSAxel Dörfler event.bytes = bytes;
223d7f7bf2dSAxel Dörfler event.length = numBytes;
224d7f7bf2dSAxel Dörfler event.key = 0;
225d7f7bf2dSAxel Dörfler event.modifiers = modifiers();
226d7f7bf2dSAxel Dörfler
227d7f7bf2dSAxel Dörfler if (Window() != NULL && Window()->CurrentMessage() != NULL) {
228d7f7bf2dSAxel Dörfler BMessage* message = Window()->CurrentMessage();
229d7f7bf2dSAxel Dörfler message->FindInt32("raw_char", &event.key);
230d7f7bf2dSAxel Dörfler message->FindInt32("modifiers", &event.modifiers);
231d7f7bf2dSAxel Dörfler }
232d7f7bf2dSAxel Dörfler
2336a0e78e5SAndrew Lindesay float viewHeightPrior = fTextEditor->Layout()->Height();
2346a0e78e5SAndrew Lindesay
235d7f7bf2dSAxel Dörfler fTextEditor->KeyDown(event);
23681f55cc8SStephan Aßmus _ShowCaret(true);
23781f55cc8SStephan Aßmus // TODO: It is necessary to invalidate all, since neither the caret bounds
23881f55cc8SStephan Aßmus // are updated in a way that would work here, nor is the text updated
2396a0e78e5SAndrew Lindesay // correctly which has been edited.
240d7f7bf2dSAxel Dörfler Invalidate();
2416a0e78e5SAndrew Lindesay
2426a0e78e5SAndrew Lindesay if (fTextEditor->Layout()->Height() != viewHeightPrior)
2436a0e78e5SAndrew Lindesay _UpdateScrollBars();
244d7f7bf2dSAxel Dörfler }
245d7f7bf2dSAxel Dörfler
246d7f7bf2dSAxel Dörfler
247d7f7bf2dSAxel Dörfler void
KeyUp(const char * bytes,int32 numBytes)248d7f7bf2dSAxel Dörfler TextDocumentView::KeyUp(const char* bytes, int32 numBytes)
249d7f7bf2dSAxel Dörfler {
250d7f7bf2dSAxel Dörfler }
251d7f7bf2dSAxel Dörfler
252d7f7bf2dSAxel Dörfler
253d7f7bf2dSAxel Dörfler BSize
MinSize()254d7f7bf2dSAxel Dörfler TextDocumentView::MinSize()
255d7f7bf2dSAxel Dörfler {
256d7f7bf2dSAxel Dörfler return BSize(fInsetLeft + fInsetRight + 50.0f, fInsetTop + fInsetBottom);
257d7f7bf2dSAxel Dörfler }
258d7f7bf2dSAxel Dörfler
259d7f7bf2dSAxel Dörfler
260d7f7bf2dSAxel Dörfler BSize
MaxSize()261d7f7bf2dSAxel Dörfler TextDocumentView::MaxSize()
262d7f7bf2dSAxel Dörfler {
263d7f7bf2dSAxel Dörfler return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
264d7f7bf2dSAxel Dörfler }
265d7f7bf2dSAxel Dörfler
266d7f7bf2dSAxel Dörfler
267d7f7bf2dSAxel Dörfler BSize
PreferredSize()268d7f7bf2dSAxel Dörfler TextDocumentView::PreferredSize()
269d7f7bf2dSAxel Dörfler {
270d7f7bf2dSAxel Dörfler return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
271d7f7bf2dSAxel Dörfler }
272d7f7bf2dSAxel Dörfler
273d7f7bf2dSAxel Dörfler
274d7f7bf2dSAxel Dörfler bool
HasHeightForWidth()275d7f7bf2dSAxel Dörfler TextDocumentView::HasHeightForWidth()
276d7f7bf2dSAxel Dörfler {
277d7f7bf2dSAxel Dörfler return true;
278d7f7bf2dSAxel Dörfler }
279d7f7bf2dSAxel Dörfler
280d7f7bf2dSAxel Dörfler
281d7f7bf2dSAxel Dörfler void
GetHeightForWidth(float width,float * min,float * max,float * preferred)282d7f7bf2dSAxel Dörfler TextDocumentView::GetHeightForWidth(float width, float* min, float* max,
283d7f7bf2dSAxel Dörfler float* preferred)
284d7f7bf2dSAxel Dörfler {
285d7f7bf2dSAxel Dörfler TextDocumentLayout layout(fTextDocumentLayout);
286d7f7bf2dSAxel Dörfler layout.SetWidth(_TextLayoutWidth(width));
287d7f7bf2dSAxel Dörfler
288d7f7bf2dSAxel Dörfler float height = layout.Height() + 1 + fInsetTop + fInsetBottom;
289d7f7bf2dSAxel Dörfler
290d7f7bf2dSAxel Dörfler if (min != NULL)
291d7f7bf2dSAxel Dörfler *min = height;
292d7f7bf2dSAxel Dörfler if (max != NULL)
293d7f7bf2dSAxel Dörfler *max = height;
294d7f7bf2dSAxel Dörfler if (preferred != NULL)
295d7f7bf2dSAxel Dörfler *preferred = height;
296d7f7bf2dSAxel Dörfler }
297d7f7bf2dSAxel Dörfler
298d7f7bf2dSAxel Dörfler
299d7f7bf2dSAxel Dörfler // #pragma mark -
300d7f7bf2dSAxel Dörfler
301d7f7bf2dSAxel Dörfler
302d7f7bf2dSAxel Dörfler void
SetTextDocument(const TextDocumentRef & document)303d7f7bf2dSAxel Dörfler TextDocumentView::SetTextDocument(const TextDocumentRef& document)
304d7f7bf2dSAxel Dörfler {
305d7f7bf2dSAxel Dörfler fTextDocument = document;
306d7f7bf2dSAxel Dörfler fTextDocumentLayout.SetTextDocument(fTextDocument);
307779ab335SX512 if (fTextEditor.IsSet())
308d7f7bf2dSAxel Dörfler fTextEditor->SetDocument(document);
309d7f7bf2dSAxel Dörfler
310d7f7bf2dSAxel Dörfler InvalidateLayout();
311d7f7bf2dSAxel Dörfler Invalidate();
312d7f7bf2dSAxel Dörfler _UpdateScrollBars();
313d7f7bf2dSAxel Dörfler }
314d7f7bf2dSAxel Dörfler
315d7f7bf2dSAxel Dörfler
316d7f7bf2dSAxel Dörfler void
SetEditingEnabled(bool enabled)317d7f7bf2dSAxel Dörfler TextDocumentView::SetEditingEnabled(bool enabled)
318d7f7bf2dSAxel Dörfler {
319779ab335SX512 if (fTextEditor.IsSet())
320d7f7bf2dSAxel Dörfler fTextEditor->SetEditingEnabled(enabled);
321d7f7bf2dSAxel Dörfler }
322d7f7bf2dSAxel Dörfler
323d7f7bf2dSAxel Dörfler
324d7f7bf2dSAxel Dörfler void
SetTextEditor(const TextEditorRef & editor)325d7f7bf2dSAxel Dörfler TextDocumentView::SetTextEditor(const TextEditorRef& editor)
326d7f7bf2dSAxel Dörfler {
327d7f7bf2dSAxel Dörfler if (fTextEditor == editor)
328d7f7bf2dSAxel Dörfler return;
329d7f7bf2dSAxel Dörfler
330779ab335SX512 if (fTextEditor.IsSet()) {
331d7f7bf2dSAxel Dörfler fTextEditor->SetDocument(TextDocumentRef());
332d7f7bf2dSAxel Dörfler fTextEditor->SetLayout(TextDocumentLayoutRef());
333d7f7bf2dSAxel Dörfler // TODO: Probably has to remove listeners
334d7f7bf2dSAxel Dörfler }
335d7f7bf2dSAxel Dörfler
336d7f7bf2dSAxel Dörfler fTextEditor = editor;
337d7f7bf2dSAxel Dörfler
338779ab335SX512 if (fTextEditor.IsSet()) {
339d7f7bf2dSAxel Dörfler fTextEditor->SetDocument(fTextDocument);
340d7f7bf2dSAxel Dörfler fTextEditor->SetLayout(TextDocumentLayoutRef(
341d7f7bf2dSAxel Dörfler &fTextDocumentLayout));
342d7f7bf2dSAxel Dörfler // TODO: Probably has to add listeners
343d7f7bf2dSAxel Dörfler }
344d7f7bf2dSAxel Dörfler }
345d7f7bf2dSAxel Dörfler
346d7f7bf2dSAxel Dörfler
347d7f7bf2dSAxel Dörfler void
SetInsets(float inset)348d7f7bf2dSAxel Dörfler TextDocumentView::SetInsets(float inset)
349d7f7bf2dSAxel Dörfler {
350d7f7bf2dSAxel Dörfler SetInsets(inset, inset, inset, inset);
351d7f7bf2dSAxel Dörfler }
352d7f7bf2dSAxel Dörfler
353d7f7bf2dSAxel Dörfler
354d7f7bf2dSAxel Dörfler void
SetInsets(float horizontal,float vertical)355d7f7bf2dSAxel Dörfler TextDocumentView::SetInsets(float horizontal, float vertical)
356d7f7bf2dSAxel Dörfler {
357d7f7bf2dSAxel Dörfler SetInsets(horizontal, vertical, horizontal, vertical);
358d7f7bf2dSAxel Dörfler }
359d7f7bf2dSAxel Dörfler
360d7f7bf2dSAxel Dörfler
361d7f7bf2dSAxel Dörfler void
SetInsets(float left,float top,float right,float bottom)362d7f7bf2dSAxel Dörfler TextDocumentView::SetInsets(float left, float top, float right, float bottom)
363d7f7bf2dSAxel Dörfler {
364d7f7bf2dSAxel Dörfler if (fInsetLeft == left && fInsetTop == top
365d7f7bf2dSAxel Dörfler && fInsetRight == right && fInsetBottom == bottom) {
366d7f7bf2dSAxel Dörfler return;
367d7f7bf2dSAxel Dörfler }
368d7f7bf2dSAxel Dörfler
369d7f7bf2dSAxel Dörfler fInsetLeft = left;
370d7f7bf2dSAxel Dörfler fInsetTop = top;
371d7f7bf2dSAxel Dörfler fInsetRight = right;
372d7f7bf2dSAxel Dörfler fInsetBottom = bottom;
373d7f7bf2dSAxel Dörfler
374d7f7bf2dSAxel Dörfler InvalidateLayout();
375d7f7bf2dSAxel Dörfler Invalidate();
376d7f7bf2dSAxel Dörfler }
377d7f7bf2dSAxel Dörfler
378d7f7bf2dSAxel Dörfler
379d7f7bf2dSAxel Dörfler void
SetSelectionEnabled(bool enabled)3806e2ac177SStephan Aßmus TextDocumentView::SetSelectionEnabled(bool enabled)
3816e2ac177SStephan Aßmus {
3826e2ac177SStephan Aßmus if (fSelectionEnabled == enabled)
3836e2ac177SStephan Aßmus return;
3846e2ac177SStephan Aßmus fSelectionEnabled = enabled;
3856e2ac177SStephan Aßmus Invalidate();
3866e2ac177SStephan Aßmus // TODO: Deselect
3876e2ac177SStephan Aßmus }
3886e2ac177SStephan Aßmus
3896e2ac177SStephan Aßmus
3906e2ac177SStephan Aßmus void
SetCaret(BPoint location,bool extendSelection)391d7f7bf2dSAxel Dörfler TextDocumentView::SetCaret(BPoint location, bool extendSelection)
392d7f7bf2dSAxel Dörfler {
393779ab335SX512 if (!fSelectionEnabled || !fTextEditor.IsSet())
394d7f7bf2dSAxel Dörfler return;
395d7f7bf2dSAxel Dörfler
396d7f7bf2dSAxel Dörfler location.x -= fInsetLeft;
397d7f7bf2dSAxel Dörfler location.y -= fInsetTop;
398d7f7bf2dSAxel Dörfler
399d7f7bf2dSAxel Dörfler fTextEditor->SetCaret(location, extendSelection);
40081f55cc8SStephan Aßmus _ShowCaret(!extendSelection);
401d7f7bf2dSAxel Dörfler Invalidate();
402d7f7bf2dSAxel Dörfler }
403d7f7bf2dSAxel Dörfler
404d7f7bf2dSAxel Dörfler
40596ebc1d6SStephan Aßmus void
SelectAll()40696ebc1d6SStephan Aßmus TextDocumentView::SelectAll()
40796ebc1d6SStephan Aßmus {
408779ab335SX512 if (!fSelectionEnabled || !fTextEditor.IsSet())
40996ebc1d6SStephan Aßmus return;
41096ebc1d6SStephan Aßmus
41196ebc1d6SStephan Aßmus fTextEditor->SelectAll();
41281f55cc8SStephan Aßmus _ShowCaret(false);
4131fa37d5aSStephan Aßmus Invalidate();
41496ebc1d6SStephan Aßmus }
41596ebc1d6SStephan Aßmus
41696ebc1d6SStephan Aßmus
417d7f7bf2dSAxel Dörfler bool
HasSelection() const418d7f7bf2dSAxel Dörfler TextDocumentView::HasSelection() const
419d7f7bf2dSAxel Dörfler {
420779ab335SX512 return fTextEditor.IsSet() && fTextEditor->HasSelection();
421d7f7bf2dSAxel Dörfler }
422d7f7bf2dSAxel Dörfler
423d7f7bf2dSAxel Dörfler
424d7f7bf2dSAxel Dörfler void
GetSelection(int32 & start,int32 & end) const425d7f7bf2dSAxel Dörfler TextDocumentView::GetSelection(int32& start, int32& end) const
426d7f7bf2dSAxel Dörfler {
427779ab335SX512 if (fTextEditor.IsSet()) {
428d7f7bf2dSAxel Dörfler start = fTextEditor->SelectionStart();
429d7f7bf2dSAxel Dörfler end = fTextEditor->SelectionEnd();
430d7f7bf2dSAxel Dörfler }
431d7f7bf2dSAxel Dörfler }
432d7f7bf2dSAxel Dörfler
433d7f7bf2dSAxel Dörfler
434d7f7bf2dSAxel Dörfler void
Paste(BClipboard * clipboard)435c4e439b5SAndrew Lindesay TextDocumentView::Paste(BClipboard* clipboard)
436c4e439b5SAndrew Lindesay {
437c4e439b5SAndrew Lindesay if (!fTextDocument.IsSet() || !fTextEditor.IsSet())
438c4e439b5SAndrew Lindesay return;
439c4e439b5SAndrew Lindesay
440c4e439b5SAndrew Lindesay if (!clipboard->Lock())
441c4e439b5SAndrew Lindesay return;
442c4e439b5SAndrew Lindesay
443c4e439b5SAndrew Lindesay BMessage* clip = clipboard->Data();
444c4e439b5SAndrew Lindesay
445c4e439b5SAndrew Lindesay if (clip != NULL) {
446c4e439b5SAndrew Lindesay const void* plainTextData;
447c4e439b5SAndrew Lindesay ssize_t plainTextDataSize;
448c4e439b5SAndrew Lindesay
449c4e439b5SAndrew Lindesay if (clip->FindData(kMimeTypePlainText, B_MIME_TYPE, &plainTextData, &plainTextDataSize)
450c4e439b5SAndrew Lindesay == B_OK) {
451c4e439b5SAndrew Lindesay
452c4e439b5SAndrew Lindesay if (plainTextDataSize > 0) {
453c4e439b5SAndrew Lindesay if (_PastePossiblyDisallowedChars(static_cast<const char*>(plainTextData),
454c4e439b5SAndrew Lindesay static_cast<int32>(plainTextDataSize)) != B_OK) {
455c4e439b5SAndrew Lindesay fprintf(stderr, "unable to paste text owing to internal error");
456c4e439b5SAndrew Lindesay // don't use HaikuDepot logging system as this is in the text engine
457c4e439b5SAndrew Lindesay }
458c4e439b5SAndrew Lindesay }
459c4e439b5SAndrew Lindesay }
460c4e439b5SAndrew Lindesay }
461c4e439b5SAndrew Lindesay
462c4e439b5SAndrew Lindesay clipboard->Unlock();
463c4e439b5SAndrew Lindesay }
464c4e439b5SAndrew Lindesay
465c4e439b5SAndrew Lindesay
466c4e439b5SAndrew Lindesay /*! This method will check that all of the characters in the provided
467c4e439b5SAndrew Lindesay string are allowed in the text document. Returns true if this is the case.
468c4e439b5SAndrew Lindesay */
469c4e439b5SAndrew Lindesay /*static*/ bool
_AreCharsAllowed(const char * str,int32 maxLength)470c4e439b5SAndrew Lindesay TextDocumentView::_AreCharsAllowed(const char* str, int32 maxLength)
471c4e439b5SAndrew Lindesay {
472c4e439b5SAndrew Lindesay for (int32 i = 0; str[i] != 0 && i < maxLength; i++) {
473c4e439b5SAndrew Lindesay if (!TextDocumentView::_IsAllowedChar(i))
474c4e439b5SAndrew Lindesay return false;
475c4e439b5SAndrew Lindesay }
476c4e439b5SAndrew Lindesay return true;
477c4e439b5SAndrew Lindesay }
478c4e439b5SAndrew Lindesay
479c4e439b5SAndrew Lindesay
480c4e439b5SAndrew Lindesay /*static*/ bool
_IsAllowedChar(char c)481c4e439b5SAndrew Lindesay TextDocumentView::_IsAllowedChar(char c)
482c4e439b5SAndrew Lindesay {
483c4e439b5SAndrew Lindesay return c >= ' '
484c4e439b5SAndrew Lindesay || c == '\t'
485c4e439b5SAndrew Lindesay || c == '\n'
486c4e439b5SAndrew Lindesay || c == 127 // delete
487c4e439b5SAndrew Lindesay ;
488c4e439b5SAndrew Lindesay }
489c4e439b5SAndrew Lindesay
490c4e439b5SAndrew Lindesay
491c4e439b5SAndrew Lindesay void
Copy(BClipboard * clipboard)492d7f7bf2dSAxel Dörfler TextDocumentView::Copy(BClipboard* clipboard)
493d7f7bf2dSAxel Dörfler {
494779ab335SX512 if (!HasSelection() || !fTextDocument.IsSet()) {
495d7f7bf2dSAxel Dörfler // Nothing to copy, don't clear clipboard contents for now reason.
496d7f7bf2dSAxel Dörfler return;
497d7f7bf2dSAxel Dörfler }
498d7f7bf2dSAxel Dörfler
499d7f7bf2dSAxel Dörfler if (clipboard == NULL || !clipboard->Lock())
500d7f7bf2dSAxel Dörfler return;
501d7f7bf2dSAxel Dörfler
502d7f7bf2dSAxel Dörfler clipboard->Clear();
503d7f7bf2dSAxel Dörfler
504d7f7bf2dSAxel Dörfler BMessage* clip = clipboard->Data();
505d7f7bf2dSAxel Dörfler if (clip != NULL) {
506d7f7bf2dSAxel Dörfler int32 start;
507d7f7bf2dSAxel Dörfler int32 end;
508d7f7bf2dSAxel Dörfler GetSelection(start, end);
509d7f7bf2dSAxel Dörfler
510d7f7bf2dSAxel Dörfler BString text = fTextDocument->Text(start, end - start);
511c4e439b5SAndrew Lindesay clip->AddData(kMimeTypePlainText, B_MIME_TYPE, text.String(), text.Length());
512d7f7bf2dSAxel Dörfler
513d7f7bf2dSAxel Dörfler // TODO: Support for "application/x-vnd.Be-text_run_array"
514d7f7bf2dSAxel Dörfler
515d7f7bf2dSAxel Dörfler clipboard->Commit();
516d7f7bf2dSAxel Dörfler }
517d7f7bf2dSAxel Dörfler
518d7f7bf2dSAxel Dörfler clipboard->Unlock();
519d7f7bf2dSAxel Dörfler }
520d7f7bf2dSAxel Dörfler
521d7f7bf2dSAxel Dörfler
5224f9df95dSPulkoMandy void
Relayout()5234f9df95dSPulkoMandy TextDocumentView::Relayout()
5244f9df95dSPulkoMandy {
5254f9df95dSPulkoMandy fTextDocumentLayout.Invalidate();
5264f9df95dSPulkoMandy _UpdateScrollBars();
5274f9df95dSPulkoMandy }
5284f9df95dSPulkoMandy
5294f9df95dSPulkoMandy
530d7f7bf2dSAxel Dörfler // #pragma mark - private
531d7f7bf2dSAxel Dörfler
532d7f7bf2dSAxel Dörfler
533d7f7bf2dSAxel Dörfler float
_TextLayoutWidth(float viewWidth) const534d7f7bf2dSAxel Dörfler TextDocumentView::_TextLayoutWidth(float viewWidth) const
535d7f7bf2dSAxel Dörfler {
536d7f7bf2dSAxel Dörfler return viewWidth - (fInsetLeft + fInsetRight);
537d7f7bf2dSAxel Dörfler }
538d7f7bf2dSAxel Dörfler
539d7f7bf2dSAxel Dörfler
540d7f7bf2dSAxel Dörfler static const float kHorizontalScrollBarStep = 10.0f;
541d7f7bf2dSAxel Dörfler static const float kVerticalScrollBarStep = 12.0f;
542d7f7bf2dSAxel Dörfler
543d7f7bf2dSAxel Dörfler
544d7f7bf2dSAxel Dörfler void
_UpdateScrollBars()545d7f7bf2dSAxel Dörfler TextDocumentView::_UpdateScrollBars()
546d7f7bf2dSAxel Dörfler {
547d7f7bf2dSAxel Dörfler BRect bounds(Bounds());
548d7f7bf2dSAxel Dörfler
549d7f7bf2dSAxel Dörfler BScrollBar* horizontalScrollBar = ScrollBar(B_HORIZONTAL);
550d7f7bf2dSAxel Dörfler if (horizontalScrollBar != NULL) {
551d7f7bf2dSAxel Dörfler long viewWidth = bounds.IntegerWidth();
552d7f7bf2dSAxel Dörfler long dataWidth = (long)ceilf(
553d7f7bf2dSAxel Dörfler fTextDocumentLayout.Width() + fInsetLeft + fInsetRight);
554d7f7bf2dSAxel Dörfler
555d7f7bf2dSAxel Dörfler long maxRange = dataWidth - viewWidth;
556d7f7bf2dSAxel Dörfler maxRange = std::max(maxRange, 0L);
557d7f7bf2dSAxel Dörfler
558d7f7bf2dSAxel Dörfler horizontalScrollBar->SetRange(0, (float)maxRange);
559d7f7bf2dSAxel Dörfler horizontalScrollBar->SetProportion((float)viewWidth / dataWidth);
560d7f7bf2dSAxel Dörfler horizontalScrollBar->SetSteps(kHorizontalScrollBarStep, dataWidth / 10);
561d7f7bf2dSAxel Dörfler }
562d7f7bf2dSAxel Dörfler
563d7f7bf2dSAxel Dörfler BScrollBar* verticalScrollBar = ScrollBar(B_VERTICAL);
564d7f7bf2dSAxel Dörfler if (verticalScrollBar != NULL) {
565d7f7bf2dSAxel Dörfler long viewHeight = bounds.IntegerHeight();
566d7f7bf2dSAxel Dörfler long dataHeight = (long)ceilf(
567d7f7bf2dSAxel Dörfler fTextDocumentLayout.Height() + fInsetTop + fInsetBottom);
568d7f7bf2dSAxel Dörfler
569d7f7bf2dSAxel Dörfler long maxRange = dataHeight - viewHeight;
570d7f7bf2dSAxel Dörfler maxRange = std::max(maxRange, 0L);
571d7f7bf2dSAxel Dörfler
572d7f7bf2dSAxel Dörfler verticalScrollBar->SetRange(0, maxRange);
573d7f7bf2dSAxel Dörfler verticalScrollBar->SetProportion((float)viewHeight / dataHeight);
574d7f7bf2dSAxel Dörfler verticalScrollBar->SetSteps(kVerticalScrollBarStep, viewHeight);
575d7f7bf2dSAxel Dörfler }
576d7f7bf2dSAxel Dörfler }
577d7f7bf2dSAxel Dörfler
578d7f7bf2dSAxel Dörfler
579d7f7bf2dSAxel Dörfler void
_ShowCaret(bool show)58081f55cc8SStephan Aßmus TextDocumentView::_ShowCaret(bool show)
58181f55cc8SStephan Aßmus {
58281f55cc8SStephan Aßmus fShowCaret = show;
58381f55cc8SStephan Aßmus if (fCaretBounds.IsValid())
58481f55cc8SStephan Aßmus Invalidate(fCaretBounds);
58581f55cc8SStephan Aßmus else
58681f55cc8SStephan Aßmus Invalidate();
58781f55cc8SStephan Aßmus // Cancel previous blinker, increment blink token so we only accept
58881f55cc8SStephan Aßmus // the message from the blinker we just created
58981f55cc8SStephan Aßmus fCaretBlinkToken++;
59081f55cc8SStephan Aßmus BMessage message(MSG_BLINK_CARET);
59181f55cc8SStephan Aßmus message.AddInt32("token", fCaretBlinkToken);
59281f55cc8SStephan Aßmus delete fCaretBlinker;
59381f55cc8SStephan Aßmus fCaretBlinker = new BMessageRunner(BMessenger(this), &message,
59481f55cc8SStephan Aßmus 500000, 1);
59581f55cc8SStephan Aßmus }
59681f55cc8SStephan Aßmus
59781f55cc8SStephan Aßmus
59881f55cc8SStephan Aßmus void
_BlinkCaret()59981f55cc8SStephan Aßmus TextDocumentView::_BlinkCaret()
60081f55cc8SStephan Aßmus {
601779ab335SX512 if (!fSelectionEnabled || !fTextEditor.IsSet())
60281f55cc8SStephan Aßmus return;
60381f55cc8SStephan Aßmus
60481f55cc8SStephan Aßmus _ShowCaret(!fShowCaret);
60581f55cc8SStephan Aßmus }
60681f55cc8SStephan Aßmus
60781f55cc8SStephan Aßmus
60881f55cc8SStephan Aßmus void
_DrawCaret(int32 textOffset)609d7f7bf2dSAxel Dörfler TextDocumentView::_DrawCaret(int32 textOffset)
610d7f7bf2dSAxel Dörfler {
611d7f7bf2dSAxel Dörfler if (!IsFocus() || Window() == NULL || !Window()->IsActive())
612d7f7bf2dSAxel Dörfler return;
613d7f7bf2dSAxel Dörfler
614d7f7bf2dSAxel Dörfler float x1;
615d7f7bf2dSAxel Dörfler float y1;
616d7f7bf2dSAxel Dörfler float x2;
617d7f7bf2dSAxel Dörfler float y2;
618d7f7bf2dSAxel Dörfler
619d7f7bf2dSAxel Dörfler fTextDocumentLayout.GetTextBounds(textOffset, x1, y1, x2, y2);
620d7f7bf2dSAxel Dörfler x2 = x1 + 1;
621d7f7bf2dSAxel Dörfler
622d7f7bf2dSAxel Dörfler fCaretBounds = BRect(x1, y1, x2, y2);
623d7f7bf2dSAxel Dörfler fCaretBounds.OffsetBy(fInsetLeft, fInsetTop);
624d7f7bf2dSAxel Dörfler
625d7f7bf2dSAxel Dörfler SetDrawingMode(B_OP_INVERT);
626d7f7bf2dSAxel Dörfler FillRect(fCaretBounds);
627d7f7bf2dSAxel Dörfler }
628d7f7bf2dSAxel Dörfler
629d7f7bf2dSAxel Dörfler
630d7f7bf2dSAxel Dörfler void
_DrawSelection()631d7f7bf2dSAxel Dörfler TextDocumentView::_DrawSelection()
632d7f7bf2dSAxel Dörfler {
633d7f7bf2dSAxel Dörfler int32 start;
634d7f7bf2dSAxel Dörfler int32 end;
635d7f7bf2dSAxel Dörfler GetSelection(start, end);
636d7f7bf2dSAxel Dörfler
637d7f7bf2dSAxel Dörfler BShape shape;
638d7f7bf2dSAxel Dörfler _GetSelectionShape(shape, start, end);
639d7f7bf2dSAxel Dörfler
640d7f7bf2dSAxel Dörfler SetDrawingMode(B_OP_SUBTRACT);
641d7f7bf2dSAxel Dörfler
642d7f7bf2dSAxel Dörfler SetLineMode(B_ROUND_CAP, B_ROUND_JOIN);
643d7f7bf2dSAxel Dörfler MovePenTo(fInsetLeft - 0.5f, fInsetTop - 0.5f);
644d7f7bf2dSAxel Dörfler
645d7f7bf2dSAxel Dörfler if (IsFocus() && Window() != NULL && Window()->IsActive()) {
646d7f7bf2dSAxel Dörfler SetHighColor(30, 30, 30);
647d7f7bf2dSAxel Dörfler FillShape(&shape);
648d7f7bf2dSAxel Dörfler }
649d7f7bf2dSAxel Dörfler
650d7f7bf2dSAxel Dörfler SetHighColor(40, 40, 40);
651d7f7bf2dSAxel Dörfler StrokeShape(&shape);
652d7f7bf2dSAxel Dörfler }
653d7f7bf2dSAxel Dörfler
654d7f7bf2dSAxel Dörfler
655d7f7bf2dSAxel Dörfler void
_GetSelectionShape(BShape & shape,int32 start,int32 end)656d7f7bf2dSAxel Dörfler TextDocumentView::_GetSelectionShape(BShape& shape, int32 start, int32 end)
657d7f7bf2dSAxel Dörfler {
658d7f7bf2dSAxel Dörfler float startX1;
659d7f7bf2dSAxel Dörfler float startY1;
660d7f7bf2dSAxel Dörfler float startX2;
661d7f7bf2dSAxel Dörfler float startY2;
662d7f7bf2dSAxel Dörfler fTextDocumentLayout.GetTextBounds(start, startX1, startY1, startX2,
663d7f7bf2dSAxel Dörfler startY2);
664d7f7bf2dSAxel Dörfler
665d7f7bf2dSAxel Dörfler startX1 = floorf(startX1);
666d7f7bf2dSAxel Dörfler startY1 = floorf(startY1);
667d7f7bf2dSAxel Dörfler startX2 = ceilf(startX2);
668d7f7bf2dSAxel Dörfler startY2 = ceilf(startY2);
669d7f7bf2dSAxel Dörfler
670d7f7bf2dSAxel Dörfler float endX1;
671d7f7bf2dSAxel Dörfler float endY1;
672d7f7bf2dSAxel Dörfler float endX2;
673d7f7bf2dSAxel Dörfler float endY2;
674d7f7bf2dSAxel Dörfler fTextDocumentLayout.GetTextBounds(end, endX1, endY1, endX2, endY2);
675d7f7bf2dSAxel Dörfler
676d7f7bf2dSAxel Dörfler endX1 = floorf(endX1);
677d7f7bf2dSAxel Dörfler endY1 = floorf(endY1);
678d7f7bf2dSAxel Dörfler endX2 = ceilf(endX2);
679d7f7bf2dSAxel Dörfler endY2 = ceilf(endY2);
680d7f7bf2dSAxel Dörfler
681d7f7bf2dSAxel Dörfler int32 startLineIndex = fTextDocumentLayout.LineIndexForOffset(start);
682d7f7bf2dSAxel Dörfler int32 endLineIndex = fTextDocumentLayout.LineIndexForOffset(end);
683d7f7bf2dSAxel Dörfler
684d7f7bf2dSAxel Dörfler if (startLineIndex == endLineIndex) {
685d7f7bf2dSAxel Dörfler // Selection on one line
686d7f7bf2dSAxel Dörfler BPoint lt(startX1, startY1);
687d7f7bf2dSAxel Dörfler BPoint rt(endX1, endY1);
688d7f7bf2dSAxel Dörfler BPoint rb(endX1, endY2);
689d7f7bf2dSAxel Dörfler BPoint lb(startX1, startY2);
690d7f7bf2dSAxel Dörfler
691d7f7bf2dSAxel Dörfler shape.MoveTo(lt);
692d7f7bf2dSAxel Dörfler shape.LineTo(rt);
693d7f7bf2dSAxel Dörfler shape.LineTo(rb);
694d7f7bf2dSAxel Dörfler shape.LineTo(lb);
695d7f7bf2dSAxel Dörfler shape.Close();
696d7f7bf2dSAxel Dörfler } else if (startLineIndex == endLineIndex - 1 && endX1 <= startX1) {
697d7f7bf2dSAxel Dörfler // Selection on two lines, with gap:
698d7f7bf2dSAxel Dörfler // ---------
699d7f7bf2dSAxel Dörfler // ------###
700d7f7bf2dSAxel Dörfler // ##-------
701d7f7bf2dSAxel Dörfler // ---------
702d7f7bf2dSAxel Dörfler float width = ceilf(fTextDocumentLayout.Width());
703d7f7bf2dSAxel Dörfler
704d7f7bf2dSAxel Dörfler BPoint lt(startX1, startY1);
705d7f7bf2dSAxel Dörfler BPoint rt(width, startY1);
706d7f7bf2dSAxel Dörfler BPoint rb(width, startY2);
707d7f7bf2dSAxel Dörfler BPoint lb(startX1, startY2);
708d7f7bf2dSAxel Dörfler
709d7f7bf2dSAxel Dörfler shape.MoveTo(lt);
710d7f7bf2dSAxel Dörfler shape.LineTo(rt);
711d7f7bf2dSAxel Dörfler shape.LineTo(rb);
712d7f7bf2dSAxel Dörfler shape.LineTo(lb);
713d7f7bf2dSAxel Dörfler shape.Close();
714d7f7bf2dSAxel Dörfler
715d7f7bf2dSAxel Dörfler lt = BPoint(0, endY1);
716d7f7bf2dSAxel Dörfler rt = BPoint(endX1, endY1);
717d7f7bf2dSAxel Dörfler rb = BPoint(endX1, endY2);
718d7f7bf2dSAxel Dörfler lb = BPoint(0, endY2);
719d7f7bf2dSAxel Dörfler
720d7f7bf2dSAxel Dörfler shape.MoveTo(lt);
721d7f7bf2dSAxel Dörfler shape.LineTo(rt);
722d7f7bf2dSAxel Dörfler shape.LineTo(rb);
723d7f7bf2dSAxel Dörfler shape.LineTo(lb);
724d7f7bf2dSAxel Dörfler shape.Close();
725d7f7bf2dSAxel Dörfler } else {
726d7f7bf2dSAxel Dörfler // Selection over multiple lines
727d7f7bf2dSAxel Dörfler float width = ceilf(fTextDocumentLayout.Width());
728d7f7bf2dSAxel Dörfler
729d7f7bf2dSAxel Dörfler shape.MoveTo(BPoint(startX1, startY1));
730d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(width, startY1));
731d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(width, endY1));
732d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(endX1, endY1));
733d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(endX1, endY2));
734d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(0, endY2));
735d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(0, startY2));
736d7f7bf2dSAxel Dörfler shape.LineTo(BPoint(startX1, startY2));
737d7f7bf2dSAxel Dörfler shape.Close();
738d7f7bf2dSAxel Dörfler }
739d7f7bf2dSAxel Dörfler }
740d7f7bf2dSAxel Dörfler
741d7f7bf2dSAxel Dörfler
742c4e439b5SAndrew Lindesay /*! The data provided in the `str` parameter may contain characters that are
743c4e439b5SAndrew Lindesay not allowed. This method should filter those out and then apply them to
744c4e439b5SAndrew Lindesay the text body.
745c4e439b5SAndrew Lindesay */
746c4e439b5SAndrew Lindesay status_t
_PastePossiblyDisallowedChars(const char * str,int32 maxLength)747c4e439b5SAndrew Lindesay TextDocumentView::_PastePossiblyDisallowedChars(const char* str, int32 maxLength)
748c4e439b5SAndrew Lindesay {
749c4e439b5SAndrew Lindesay if (maxLength <= 0)
750c4e439b5SAndrew Lindesay return B_OK;
751c4e439b5SAndrew Lindesay
752c4e439b5SAndrew Lindesay if (TextDocumentView::_AreCharsAllowed(str, maxLength)) {
753c4e439b5SAndrew Lindesay _PasteAllowedChars(str, maxLength);
754c4e439b5SAndrew Lindesay } else {
755c4e439b5SAndrew Lindesay char* strFiltered = new(std::nothrow) char[maxLength];
756c4e439b5SAndrew Lindesay
757c4e439b5SAndrew Lindesay if (strFiltered == NULL)
758c4e439b5SAndrew Lindesay return B_NO_MEMORY;
759c4e439b5SAndrew Lindesay
760c4e439b5SAndrew Lindesay int32 strFilteredLength = 0;
761c4e439b5SAndrew Lindesay
762c4e439b5SAndrew Lindesay for (int i = 0; str[i] != '\0' && i < maxLength; i++) {
763c4e439b5SAndrew Lindesay if (_IsAllowedChar(str[i])) {
764c4e439b5SAndrew Lindesay strFiltered[strFilteredLength] = str[i];
765c4e439b5SAndrew Lindesay strFilteredLength++;
766c4e439b5SAndrew Lindesay }
767c4e439b5SAndrew Lindesay }
768c4e439b5SAndrew Lindesay
769c4e439b5SAndrew Lindesay strFiltered[strFilteredLength] = '\0';
770c4e439b5SAndrew Lindesay _PasteAllowedChars(strFiltered, strFilteredLength);
771c4e439b5SAndrew Lindesay
772c4e439b5SAndrew Lindesay delete[] strFiltered;
773c4e439b5SAndrew Lindesay }
774c4e439b5SAndrew Lindesay
775c4e439b5SAndrew Lindesay return B_OK;
776c4e439b5SAndrew Lindesay }
777c4e439b5SAndrew Lindesay
778c4e439b5SAndrew Lindesay
779c4e439b5SAndrew Lindesay /*! Here the data in `str` should be clean of control characters.
780c4e439b5SAndrew Lindesay */
781c4e439b5SAndrew Lindesay void
_PasteAllowedChars(const char * str,int32 maxLength)782c4e439b5SAndrew Lindesay TextDocumentView::_PasteAllowedChars(const char* str, int32 maxLength)
783c4e439b5SAndrew Lindesay {
784c4e439b5SAndrew Lindesay BString plainText(str, maxLength);
785c4e439b5SAndrew Lindesay
786c4e439b5SAndrew Lindesay if (plainText.IsEmpty())
787c4e439b5SAndrew Lindesay return;
788c4e439b5SAndrew Lindesay
789c4e439b5SAndrew Lindesay if (fTextEditor.IsSet()) {
790c4e439b5SAndrew Lindesay if (fTextEditor->HasSelection()) {
791c4e439b5SAndrew Lindesay int32 start = fTextEditor->SelectionStart();
792c4e439b5SAndrew Lindesay int32 end = fTextEditor->SelectionEnd();
793c4e439b5SAndrew Lindesay fTextEditor->Replace(start, end - start, plainText);
794c4e439b5SAndrew Lindesay Invalidate();
795c4e439b5SAndrew Lindesay _UpdateScrollBars();
796c4e439b5SAndrew Lindesay } else {
797c4e439b5SAndrew Lindesay int32 caretOffset = fTextEditor->CaretOffset();
798c4e439b5SAndrew Lindesay if (caretOffset >= 0) {
799c4e439b5SAndrew Lindesay fTextEditor->Insert(caretOffset, plainText);
800c4e439b5SAndrew Lindesay Invalidate();
801c4e439b5SAndrew Lindesay _UpdateScrollBars();
802c4e439b5SAndrew Lindesay }
803c4e439b5SAndrew Lindesay }
804c4e439b5SAndrew Lindesay }
805c4e439b5SAndrew Lindesay }