1 // This module implements the "official" low-level API.
2 //
3 // Copyright (c) 2021 Riverbank Computing Limited <info@riverbankcomputing.com>
4 //
5 // This file is part of QScintilla.
6 //
7 // This file may be used under the terms of the GNU General Public License
8 // version 3.0 as published by the Free Software Foundation and appearing in
9 // the file LICENSE included in the packaging of this file. Please review the
10 // following information to ensure the GNU General Public License version 3.0
11 // requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 //
13 // If you do not wish to use this file under the terms of the GPL version 3.0
14 // then you may purchase a commercial license. For more information contact
15 // info@riverbankcomputing.com.
16 //
17 // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
18 // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19
20
21 #include "Qsci/qsciscintillabase.h"
22
23 #include <QApplication>
24 #include <QClipboard>
25 #include <QColor>
26 #include <QContextMenuEvent>
27 #include <QDragEnterEvent>
28 #include <QDragMoveEvent>
29 #include <QDropEvent>
30 #include <QDragLeaveEvent>
31 #include <QFocusEvent>
32 #include <QKeyEvent>
33 #include <QList>
34 #include <QMimeData>
35 #include <QMouseEvent>
36 #include <QPaintEvent>
37 #include <QScrollBar>
38 #include <QStyle>
39
40 #include "SciAccessibility.h"
41 #include "ScintillaQt.h"
42
43
44 // The #defines in Scintilla.h and the enums in qsciscintillabase.h conflict
45 // (because we want to use the same names) so we have to undefine those we use
46 // in this file.
47 #undef SCI_SETCARETPERIOD
48 #undef SCK_DOWN
49 #undef SCK_UP
50 #undef SCK_LEFT
51 #undef SCK_RIGHT
52 #undef SCK_HOME
53 #undef SCK_END
54 #undef SCK_PRIOR
55 #undef SCK_NEXT
56 #undef SCK_DELETE
57 #undef SCK_INSERT
58 #undef SCK_ESCAPE
59 #undef SCK_BACK
60 #undef SCK_TAB
61 #undef SCK_RETURN
62 #undef SCK_ADD
63 #undef SCK_SUBTRACT
64 #undef SCK_DIVIDE
65 #undef SCK_WIN
66 #undef SCK_RWIN
67 #undef SCK_MENU
68 #undef SCN_URIDROPPED
69
70
71 // Remember if we have linked the lexers.
72 static bool lexersLinked = false;
73
74 // The list of instances.
75 static QList<QsciScintillaBase *> poolList;
76
77 // Mime support.
78 static const QLatin1String mimeTextPlain("text/plain");
79 static const QLatin1String mimeRectangularWin("MSDEVColumnSelect");
80 static const QLatin1String mimeRectangular("text/x-qscintilla-rectangular");
81
82 #if QT_VERSION < 0x060000 && defined(Q_OS_OSX)
83 extern void initialiseRectangularPasteboardMime();
84 #endif
85
86
87 // The ctor.
QsciScintillaBase(QWidget * parent)88 QsciScintillaBase::QsciScintillaBase(QWidget *parent)
89 : QAbstractScrollArea(parent), preeditPos(-1), preeditNrBytes(0),
90 clickCausedFocus(false)
91 {
92 #if !defined(QT_NO_ACCESSIBILITY)
93 QsciAccessibleScintillaBase::initialise();
94 #endif
95
96 connectVerticalScrollBar();
97 connectHorizontalScrollBar();
98
99 setAcceptDrops(true);
100 setFocusPolicy(Qt::WheelFocus);
101 setAttribute(Qt::WA_KeyCompression);
102 setAttribute(Qt::WA_InputMethodEnabled);
103 setInputMethodHints(
104 Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText|Qt::ImhMultiLine);
105
106 viewport()->setBackgroundRole(QPalette::Base);
107 viewport()->setMouseTracking(true);
108 viewport()->setAttribute(Qt::WA_NoSystemBackground);
109
110 triple_click.setSingleShot(true);
111
112 #if QT_VERSION < 0x060000 && defined(Q_OS_OSX)
113 initialiseRectangularPasteboardMime();
114 #endif
115
116 sci = new QsciScintillaQt(this);
117
118 SendScintilla(SCI_SETCARETPERIOD, QApplication::cursorFlashTime() / 2);
119
120 // Make sure the lexers are linked in.
121 if (!lexersLinked)
122 {
123 Scintilla_LinkLexers();
124 lexersLinked = true;
125 }
126
127 // Add it to the pool.
128 poolList.append(this);
129 }
130
131
132 // The dtor.
~QsciScintillaBase()133 QsciScintillaBase::~QsciScintillaBase()
134 {
135 // The QsciScintillaQt object isn't a child so delete it explicitly.
136 delete sci;
137
138 // Remove it from the pool.
139 poolList.removeAt(poolList.indexOf(this));
140 }
141
142
143 // Return an instance from the pool.
pool()144 QsciScintillaBase *QsciScintillaBase::pool()
145 {
146 return poolList.first();
147 }
148
149
150 // Tell Scintilla to update the scroll bars. Scintilla should be doing this
151 // itself.
setScrollBars()152 void QsciScintillaBase::setScrollBars()
153 {
154 sci->SetScrollBars();
155 }
156
157
158 // Send a message to the real Scintilla widget using the low level Scintilla
159 // API.
SendScintilla(unsigned int msg,unsigned long wParam,long lParam) const160 long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam,
161 long lParam) const
162 {
163 return sci->WndProc(msg, wParam, lParam);
164 }
165
166
167 // Overloaded message send.
SendScintilla(unsigned int msg,unsigned long wParam,void * lParam) const168 long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam,
169 void *lParam) const
170 {
171 return sci->WndProc(msg, wParam, reinterpret_cast<sptr_t>(lParam));
172 }
173
174
175 // Overloaded message send.
SendScintilla(unsigned int msg,uintptr_t wParam,const char * lParam) const176 long QsciScintillaBase::SendScintilla(unsigned int msg, uintptr_t wParam,
177 const char *lParam) const
178 {
179 return sci->WndProc(msg, wParam, reinterpret_cast<sptr_t>(lParam));
180 }
181
182
183 // Overloaded message send.
SendScintilla(unsigned int msg,const char * lParam) const184 long QsciScintillaBase::SendScintilla(unsigned int msg,
185 const char *lParam) const
186 {
187 return sci->WndProc(msg, static_cast<uptr_t>(0),
188 reinterpret_cast<sptr_t>(lParam));
189 }
190
191
192 // Overloaded message send.
SendScintilla(unsigned int msg,const char * wParam,const char * lParam) const193 long QsciScintillaBase::SendScintilla(unsigned int msg, const char *wParam,
194 const char *lParam) const
195 {
196 return sci->WndProc(msg, reinterpret_cast<uptr_t>(wParam),
197 reinterpret_cast<sptr_t>(lParam));
198 }
199
200
201 // Overloaded message send.
SendScintilla(unsigned int msg,long wParam) const202 long QsciScintillaBase::SendScintilla(unsigned int msg, long wParam) const
203 {
204 return sci->WndProc(msg, static_cast<uptr_t>(wParam),
205 static_cast<sptr_t>(0));
206 }
207
208
209 // Overloaded message send.
SendScintilla(unsigned int msg,int wParam) const210 long QsciScintillaBase::SendScintilla(unsigned int msg, int wParam) const
211 {
212 return sci->WndProc(msg, static_cast<uptr_t>(wParam),
213 static_cast<sptr_t>(0));
214 }
215
216
217 // Overloaded message send.
SendScintilla(unsigned int msg,long cpMin,long cpMax,char * lpstrText) const218 long QsciScintillaBase::SendScintilla(unsigned int msg, long cpMin, long cpMax,
219 char *lpstrText) const
220 {
221 Sci_TextRange tr;
222
223 tr.chrg.cpMin = cpMin;
224 tr.chrg.cpMax = cpMax;
225 tr.lpstrText = lpstrText;
226
227 return sci->WndProc(msg, static_cast<uptr_t>(0),
228 reinterpret_cast<sptr_t>(&tr));
229 }
230
231
232 // Overloaded message send.
SendScintilla(unsigned int msg,unsigned long wParam,const QColor & col) const233 long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam,
234 const QColor &col) const
235 {
236 sptr_t lParam = (col.blue() << 16) | (col.green() << 8) | col.red();
237
238 return sci->WndProc(msg, wParam, lParam);
239 }
240
241
242 // Overloaded message send.
SendScintilla(unsigned int msg,const QColor & col) const243 long QsciScintillaBase::SendScintilla(unsigned int msg, const QColor &col) const
244 {
245 uptr_t wParam = (col.blue() << 16) | (col.green() << 8) | col.red();
246
247 return sci->WndProc(msg, wParam, static_cast<sptr_t>(0));
248 }
249
250
251 // Overloaded message send.
SendScintilla(unsigned int msg,unsigned long wParam,QPainter * hdc,const QRect & rc,long cpMin,long cpMax) const252 long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam,
253 QPainter *hdc, const QRect &rc, long cpMin, long cpMax) const
254 {
255 Sci_RangeToFormat rf;
256
257 rf.hdc = rf.hdcTarget = reinterpret_cast<Scintilla::SurfaceID>(hdc);
258
259 rf.rc.left = rc.left();
260 rf.rc.top = rc.top();
261 rf.rc.right = rc.right() + 1;
262 rf.rc.bottom = rc.bottom() + 1;
263
264 rf.chrg.cpMin = cpMin;
265 rf.chrg.cpMax = cpMax;
266
267 return sci->WndProc(msg, wParam, reinterpret_cast<sptr_t>(&rf));
268 }
269
270
271 // Overloaded message send.
SendScintilla(unsigned int msg,unsigned long wParam,const QPixmap & lParam) const272 long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam,
273 const QPixmap &lParam) const
274 {
275 return sci->WndProc(msg, wParam, reinterpret_cast<sptr_t>(&lParam));
276 }
277
278
279 // Overloaded message send.
SendScintilla(unsigned int msg,unsigned long wParam,const QImage & lParam) const280 long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam,
281 const QImage &lParam) const
282 {
283 return sci->WndProc(msg, wParam, reinterpret_cast<sptr_t>(&lParam));
284 }
285
286
287 // Send a message to the real Scintilla widget using the low level Scintilla
288 // API that returns a pointer result.
SendScintillaPtrResult(unsigned int msg) const289 void *QsciScintillaBase::SendScintillaPtrResult(unsigned int msg) const
290 {
291 return reinterpret_cast<void *>(sci->WndProc(msg, static_cast<uptr_t>(0),
292 static_cast<sptr_t>(0)));
293 }
294
295
296 // Re-implemented to handle font changes
changeEvent(QEvent * e)297 void QsciScintillaBase::changeEvent(QEvent *e)
298 {
299 if (e->type() == QEvent::FontChange || e->type() == QEvent::ApplicationFontChange)
300 sci->InvalidateStyleRedraw();
301
302 QAbstractScrollArea::changeEvent(e);
303 }
304
305
306 // Re-implemented to handle the context menu.
contextMenuEvent(QContextMenuEvent * e)307 void QsciScintillaBase::contextMenuEvent(QContextMenuEvent *e)
308 {
309 sci->ContextMenu(Scintilla::Point(e->globalX(), e->globalY()));
310 }
311
312
313 // Re-implemented to tell the widget it has the focus.
focusInEvent(QFocusEvent * e)314 void QsciScintillaBase::focusInEvent(QFocusEvent *e)
315 {
316 sci->SetFocusState(true);
317 clickCausedFocus = (e->reason() == Qt::MouseFocusReason);
318 QAbstractScrollArea::focusInEvent(e);
319 }
320
321
322 // Re-implemented to tell the widget it has lost the focus.
focusOutEvent(QFocusEvent * e)323 void QsciScintillaBase::focusOutEvent(QFocusEvent *e)
324 {
325 if (e->reason() == Qt::ActiveWindowFocusReason)
326 {
327 // Only tell Scintilla we have lost focus if the new active window
328 // isn't our auto-completion list. This is probably only an issue on
329 // Linux and there are still problems because subsequent focus out
330 // events don't always seem to get generated (at least with Qt5).
331
332 QWidget *aw = QApplication::activeWindow();
333
334 if (!aw || aw->parent() != this || !aw->inherits("QsciSciListBox"))
335 sci->SetFocusState(false);
336 }
337 else
338 {
339 sci->SetFocusState(false);
340 }
341
342 QAbstractScrollArea::focusOutEvent(e);
343 }
344
345
346 // Re-implemented to make sure tabs are passed to the editor.
focusNextPrevChild(bool next)347 bool QsciScintillaBase::focusNextPrevChild(bool next)
348 {
349 if (!sci->pdoc->IsReadOnly())
350 return false;
351
352 return QAbstractScrollArea::focusNextPrevChild(next);
353 }
354
355
356 // Handle key presses.
keyPressEvent(QKeyEvent * e)357 void QsciScintillaBase::keyPressEvent(QKeyEvent *e)
358 {
359 int modifiers = 0;
360
361 if (e->modifiers() & Qt::ShiftModifier)
362 modifiers |= SCMOD_SHIFT;
363
364 if (e->modifiers() & Qt::ControlModifier)
365 modifiers |= SCMOD_CTRL;
366
367 if (e->modifiers() & Qt::AltModifier)
368 modifiers |= SCMOD_ALT;
369
370 if (e->modifiers() & Qt::MetaModifier)
371 modifiers |= SCMOD_META;
372
373 int key = commandKey(e->key(), modifiers);
374
375 if (key)
376 {
377 bool consumed = false;
378
379 sci->KeyDownWithModifiers(key, modifiers, &consumed);
380
381 if (consumed)
382 {
383 e->accept();
384 return;
385 }
386 }
387
388 QString text = e->text();
389
390 if (!text.isEmpty() && text[0].isPrint())
391 {
392 ScintillaBytes bytes = textAsBytes(text);
393 sci->AddCharUTF(bytes.data(), bytes.length());
394 e->accept();
395 }
396 else
397 {
398 QAbstractScrollArea::keyPressEvent(e);
399 }
400 }
401
402
403 // Map a Qt key to a valid Scintilla command key, or 0 if none.
commandKey(int qt_key,int & modifiers)404 int QsciScintillaBase::commandKey(int qt_key, int &modifiers)
405 {
406 int key;
407
408 switch (qt_key)
409 {
410 case Qt::Key_Down:
411 key = SCK_DOWN;
412 break;
413
414 case Qt::Key_Up:
415 key = SCK_UP;
416 break;
417
418 case Qt::Key_Left:
419 key = SCK_LEFT;
420 break;
421
422 case Qt::Key_Right:
423 key = SCK_RIGHT;
424 break;
425
426 case Qt::Key_Home:
427 key = SCK_HOME;
428 break;
429
430 case Qt::Key_End:
431 key = SCK_END;
432 break;
433
434 case Qt::Key_PageUp:
435 key = SCK_PRIOR;
436 break;
437
438 case Qt::Key_PageDown:
439 key = SCK_NEXT;
440 break;
441
442 case Qt::Key_Delete:
443 key = SCK_DELETE;
444 break;
445
446 case Qt::Key_Insert:
447 key = SCK_INSERT;
448 break;
449
450 case Qt::Key_Escape:
451 key = SCK_ESCAPE;
452 break;
453
454 case Qt::Key_Backspace:
455 key = SCK_BACK;
456 break;
457
458 case Qt::Key_Tab:
459 key = SCK_TAB;
460 break;
461
462 case Qt::Key_Backtab:
463 // Scintilla assumes a backtab is shift-tab.
464 key = SCK_TAB;
465 modifiers |= SCMOD_SHIFT;
466 break;
467
468 case Qt::Key_Return:
469 case Qt::Key_Enter:
470 key = SCK_RETURN;
471 break;
472
473 case Qt::Key_Super_L:
474 key = SCK_WIN;
475 break;
476
477 case Qt::Key_Super_R:
478 key = SCK_RWIN;
479 break;
480
481 case Qt::Key_Menu:
482 key = SCK_MENU;
483 break;
484
485 default:
486 if ((key = qt_key) > 0x7f)
487 key = 0;
488 }
489
490 return key;
491 }
492
493
494 // Encode a QString as bytes.
textAsBytes(const QString & text) const495 QsciScintillaBase::ScintillaBytes QsciScintillaBase::textAsBytes(const QString &text) const
496 {
497 if (sci->IsUnicodeMode())
498 return text.toUtf8();
499
500 return text.toLatin1();
501 }
502
503
504 // Decode bytes as a QString.
bytesAsText(const char * bytes) const505 QString QsciScintillaBase::bytesAsText(const char *bytes) const
506 {
507 if (sci->IsUnicodeMode())
508 return QString::fromUtf8(bytes);
509
510 return QString::fromLatin1(bytes);
511 }
512
513
514 // Handle a mouse button double click.
mouseDoubleClickEvent(QMouseEvent * e)515 void QsciScintillaBase::mouseDoubleClickEvent(QMouseEvent *e)
516 {
517 if (e->button() != Qt::LeftButton)
518 {
519 e->ignore();
520 return;
521 }
522
523 setFocus();
524
525 // Make sure Scintilla will interpret this as a double-click.
526 unsigned clickTime = sci->lastClickTime + Scintilla::Platform::DoubleClickTime() - 1;
527
528 sci->ButtonDownWithModifiers(Scintilla::Point(e->x(), e->y()), clickTime,
529 eventModifiers(e));
530
531 // Remember the current position and time in case it turns into a triple
532 // click.
533 triple_click_at = e->globalPos();
534 triple_click.start(QApplication::doubleClickInterval());
535 }
536
537
538 // Handle a mouse move.
mouseMoveEvent(QMouseEvent * e)539 void QsciScintillaBase::mouseMoveEvent(QMouseEvent *e)
540 {
541 sci->ButtonMoveWithModifiers(Scintilla::Point(e->x(), e->y()), 0,
542 eventModifiers(e));
543 }
544
545
546 // Handle a mouse button press.
mousePressEvent(QMouseEvent * e)547 void QsciScintillaBase::mousePressEvent(QMouseEvent *e)
548 {
549 setFocus();
550
551 Scintilla::Point pt(e->x(), e->y());
552
553 if (e->button() == Qt::LeftButton || e->button() == Qt::RightButton)
554 {
555 unsigned clickTime;
556
557 // It is a triple click if the timer is running and the mouse hasn't
558 // moved too much.
559 if (triple_click.isActive() && (e->globalPos() - triple_click_at).manhattanLength() < QApplication::startDragDistance())
560 clickTime = sci->lastClickTime + Scintilla::Platform::DoubleClickTime() - 1;
561 else
562 clickTime = sci->lastClickTime + Scintilla::Platform::DoubleClickTime() + 1;
563
564 triple_click.stop();
565
566 // Scintilla uses the Alt modifier to initiate rectangular selection.
567 // However the GTK port (under X11, not Windows) uses the Control
568 // modifier (by default, although it is configurable). It does this
569 // because most X11 window managers hijack Alt-drag to move the window.
570 // We do the same, except that (for the moment at least) we don't allow
571 // the modifier to be configured.
572 bool shift = e->modifiers() & Qt::ShiftModifier;
573 bool ctrl = e->modifiers() & Qt::ControlModifier;
574 #if defined(Q_OS_MAC) || defined(Q_OS_WIN)
575 bool alt = e->modifiers() & Qt::AltModifier;
576 #else
577 bool alt = ctrl;
578 #endif
579
580 if (e->button() == Qt::LeftButton)
581 sci->ButtonDownWithModifiers(pt, clickTime,
582 QsciScintillaQt::ModifierFlags(shift, ctrl, alt));
583 else
584 sci->RightButtonDownWithModifiers(pt, clickTime,
585 QsciScintillaQt::ModifierFlags(shift, ctrl, alt));
586 }
587 else if (e->button() == Qt::MiddleButton)
588 {
589 QClipboard *cb = QApplication::clipboard();
590
591 if (cb->supportsSelection())
592 {
593 int pos = sci->PositionFromLocation(pt);
594
595 sci->sel.Clear();
596 sci->SetSelection(pos, pos);
597
598 sci->pasteFromClipboard(QClipboard::Selection);
599 }
600 }
601 }
602
603
604 // Handle a mouse button releases.
mouseReleaseEvent(QMouseEvent * e)605 void QsciScintillaBase::mouseReleaseEvent(QMouseEvent *e)
606 {
607 if (e->button() != Qt::LeftButton)
608 return;
609
610 Scintilla::Point pt(e->x(), e->y());
611
612 if (sci->HaveMouseCapture())
613 {
614 bool ctrl = e->modifiers() & Qt::ControlModifier;
615
616 sci->ButtonUpWithModifiers(pt, 0,
617 QsciScintillaQt::ModifierFlags(false, ctrl, false));
618 }
619
620 if (!sci->pdoc->IsReadOnly() && !sci->PointInSelMargin(pt) && qApp->autoSipEnabled())
621 {
622 QStyle::RequestSoftwareInputPanel rsip = QStyle::RequestSoftwareInputPanel(style()->styleHint(QStyle::SH_RequestSoftwareInputPanel));
623
624 if (!clickCausedFocus || rsip == QStyle::RSIP_OnMouseClick)
625 qApp->inputMethod()->show();
626 }
627
628 clickCausedFocus = false;
629 }
630
631
632 // Handle paint events.
paintEvent(QPaintEvent * e)633 void QsciScintillaBase::paintEvent(QPaintEvent *e)
634 {
635 sci->paintEvent(e);
636 }
637
638
639 // Handle resize events.
resizeEvent(QResizeEvent *)640 void QsciScintillaBase::resizeEvent(QResizeEvent *)
641 {
642 sci->ChangeSize();
643 }
644
645
646 // Re-implemented to suppress the default behaviour as Scintilla works at a
647 // more fundamental level. Note that this means that replacing the scrollbars
648 // with custom versions does not work.
scrollContentsBy(int,int)649 void QsciScintillaBase::scrollContentsBy(int, int)
650 {
651 }
652
653
654 // Handle the vertical scrollbar.
handleVSb(int value)655 void QsciScintillaBase::handleVSb(int value)
656 {
657 sci->ScrollTo(value);
658 }
659
660
661 // Handle the horizontal scrollbar.
handleHSb(int value)662 void QsciScintillaBase::handleHSb(int value)
663 {
664 sci->HorizontalScrollTo(value);
665 }
666
667
668 // Handle drag enters.
dragEnterEvent(QDragEnterEvent * e)669 void QsciScintillaBase::dragEnterEvent(QDragEnterEvent *e)
670 {
671 QsciScintillaBase::dragMoveEvent(e);
672 }
673
674
675 // Handle drag leaves.
dragLeaveEvent(QDragLeaveEvent *)676 void QsciScintillaBase::dragLeaveEvent(QDragLeaveEvent *)
677 {
678 sci->SetDragPosition(Scintilla::SelectionPosition());
679 }
680
681
682 // Handle drag moves.
dragMoveEvent(QDragMoveEvent * e)683 void QsciScintillaBase::dragMoveEvent(QDragMoveEvent *e)
684 {
685 if (e->mimeData()->hasUrls())
686 {
687 e->acceptProposedAction();
688 }
689 else
690 {
691 sci->SetDragPosition(
692 sci->SPositionFromLocation(
693 Scintilla::Point(e->pos().x(), e->pos().y()), false,
694 false, sci->UserVirtualSpace()));
695
696 acceptAction(e);
697 }
698 }
699
700
701 // Handle drops.
dropEvent(QDropEvent * e)702 void QsciScintillaBase::dropEvent(QDropEvent *e)
703 {
704 if (e->mimeData()->hasUrls())
705 {
706 e->acceptProposedAction();
707
708 foreach (const QUrl &url, e->mimeData()->urls())
709 emit SCN_URIDROPPED(url);
710
711 return;
712 }
713
714 acceptAction(e);
715
716 if (!e->isAccepted())
717 return;
718
719 bool moving;
720 int len;
721 const char *s;
722 bool rectangular;
723
724 moving = (e->dropAction() == Qt::MoveAction);
725
726 QByteArray text = fromMimeData(e->mimeData(), rectangular);
727 len = text.length();
728 s = text.data();
729
730 std::string dest = Scintilla::Document::TransformLineEnds(s, len,
731 sci->pdoc->eolMode);
732
733 sci->DropAt(sci->posDrop, dest.c_str(), dest.length(), moving,
734 rectangular);
735
736 sci->Redraw();
737 }
738
739
acceptAction(QDropEvent * e)740 void QsciScintillaBase::acceptAction(QDropEvent *e)
741 {
742 if (sci->pdoc->IsReadOnly() || !canInsertFromMimeData(e->mimeData()))
743 e->ignore();
744 else
745 e->acceptProposedAction();
746 }
747
748
749 // See if a MIME data object can be decoded.
canInsertFromMimeData(const QMimeData * source) const750 bool QsciScintillaBase::canInsertFromMimeData(const QMimeData *source) const
751 {
752 return source->hasFormat(mimeTextPlain);
753 }
754
755
756 // Create text from a MIME data object.
fromMimeData(const QMimeData * source,bool & rectangular) const757 QByteArray QsciScintillaBase::fromMimeData(const QMimeData *source, bool &rectangular) const
758 {
759 // See if it is rectangular. We try all of the different formats that
760 // Scintilla supports in case we are working across different platforms.
761 if (source->hasFormat(mimeRectangularWin))
762 rectangular = true;
763 else if (source->hasFormat(mimeRectangular))
764 rectangular = true;
765 else
766 rectangular = false;
767
768 // Note that we don't support Scintilla's hack of adding a '\0' as Qt
769 // strips it off under the covers when pasting from another process.
770 QString utf8 = source->text();
771 QByteArray text;
772
773 if (sci->IsUnicodeMode())
774 text = utf8.toUtf8();
775 else
776 text = utf8.toLatin1();
777
778 return text;
779 }
780
781
782 // Create a MIME data object for some text.
toMimeData(const QByteArray & text,bool rectangular) const783 QMimeData *QsciScintillaBase::toMimeData(const QByteArray &text, bool rectangular) const
784 {
785 QMimeData *mime = new QMimeData;
786
787 QString utf8;
788
789 if (sci->IsUnicodeMode())
790 utf8 = QString::fromUtf8(text.constData(), text.size());
791 else
792 utf8 = QString::fromLatin1(text.constData(), text.size());
793
794 mime->setText(utf8);
795
796 if (rectangular)
797 {
798 // Use the platform specific "standard" for specifying a rectangular
799 // selection.
800 #if defined(Q_OS_WIN)
801 mime->setData(mimeRectangularWin, QByteArray());
802 #else
803 mime->setData(mimeRectangular, QByteArray());
804 #endif
805 }
806
807 return mime;
808 }
809
810
811 // Connect up the vertical scroll bar.
connectVerticalScrollBar()812 void QsciScintillaBase::connectVerticalScrollBar()
813 {
814 connect(verticalScrollBar(), SIGNAL(valueChanged(int)),
815 SLOT(handleVSb(int)));
816 }
817
818
819 // Connect up the horizontal scroll bar.
connectHorizontalScrollBar()820 void QsciScintillaBase::connectHorizontalScrollBar()
821 {
822 connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
823 SLOT(handleHSb(int)));
824 }
825
826
827 //! Replace the vertical scroll bar.
replaceVerticalScrollBar(QScrollBar * scrollBar)828 void QsciScintillaBase::replaceVerticalScrollBar(QScrollBar *scrollBar)
829 {
830 setVerticalScrollBar(scrollBar);
831 connectVerticalScrollBar();
832 }
833
834
835 // Replace the horizontal scroll bar.
replaceHorizontalScrollBar(QScrollBar * scrollBar)836 void QsciScintillaBase::replaceHorizontalScrollBar(QScrollBar *scrollBar)
837 {
838 setHorizontalScrollBar(scrollBar);
839 connectHorizontalScrollBar();
840 }
841
842
843 // Return true if a context menu should be displayed. This is provided as a
844 // helper to QsciScintilla::contextMenuEvent(). A proper design would break
845 // backwards compatibility.
contextMenuNeeded(int x,int y) const846 bool QsciScintillaBase::contextMenuNeeded(int x, int y) const
847 {
848 Scintilla::Point pt(x, y);
849
850 // Clear any selection if the mouse is outside.
851 if (!sci->PointInSelection(pt))
852 sci->SetEmptySelection(sci->PositionFromLocation(pt));
853
854 // Respect SC_POPUP_*.
855 return sci->ShouldDisplayPopup(pt);
856 }
857
858
859 // Return the Scintilla keyboard modifiers set for a mouse event.
eventModifiers(QMouseEvent * e)860 int QsciScintillaBase::eventModifiers(QMouseEvent *e)
861 {
862 bool shift = e->modifiers() & Qt::ShiftModifier;
863 bool ctrl = e->modifiers() & Qt::ControlModifier;
864 bool alt = e->modifiers() & Qt::AltModifier;
865
866 return QsciScintillaQt::ModifierFlags(shift, ctrl, alt);
867 }
868