123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732 |
- // The implementation of the Qt specific subclass of ScintillaBase.
- //
- // Copyright (c) 2017 Riverbank Computing Limited <info@riverbankcomputing.com>
- //
- // This file is part of QScintilla.
- //
- // This file may be used under the terms of the GNU General Public License
- // version 3.0 as published by the Free Software Foundation and appearing in
- // the file LICENSE included in the packaging of this file. Please review the
- // following information to ensure the GNU General Public License version 3.0
- // requirements will be met: http://www.gnu.org/copyleft/gpl.html.
- //
- // If you do not wish to use this file under the terms of the GPL version 3.0
- // then you may purchase a commercial license. For more information contact
- // info@riverbankcomputing.com.
- //
- // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
- // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- #include <string.h>
- #include <qapplication.h>
- #include <qbytearray.h>
- #include <qdrag.h>
- #include <qevent.h>
- #include <qmimedata.h>
- #include <qpainter.h>
- #include <qscrollbar.h>
- #include <qstring.h>
- #include "Qsci/qsciscintillabase.h"
- #include "ScintillaQt.h"
- #include "SciClasses.h"
- // We want to use the Scintilla notification names as Qt signal names.
- #undef SCEN_CHANGE
- #undef SCN_AUTOCCANCELLED
- #undef SCN_AUTOCCHARDELETED
- #undef SCN_AUTOCCOMPLETED
- #undef SCN_AUTOCSELECTION
- #undef SCN_CALLTIPCLICK
- #undef SCN_CHARADDED
- #undef SCN_DOUBLECLICK
- #undef SCN_DWELLEND
- #undef SCN_DWELLSTART
- #undef SCN_FOCUSIN
- #undef SCN_FOCUSOUT
- #undef SCN_HOTSPOTCLICK
- #undef SCN_HOTSPOTDOUBLECLICK
- #undef SCN_HOTSPOTRELEASECLICK
- #undef SCN_INDICATORCLICK
- #undef SCN_INDICATORRELEASE
- #undef SCN_MACRORECORD
- #undef SCN_MARGINCLICK
- #undef SCN_MARGINRIGHTCLICK
- #undef SCN_MODIFIED
- #undef SCN_MODIFYATTEMPTRO
- #undef SCN_NEEDSHOWN
- #undef SCN_PAINTED
- #undef SCN_SAVEPOINTLEFT
- #undef SCN_SAVEPOINTREACHED
- #undef SCN_STYLENEEDED
- #undef SCN_UPDATEUI
- #undef SCN_USERLISTSELECTION
- #undef SCN_ZOOM
- enum
- {
- SCEN_CHANGE = 768,
- SCN_AUTOCCANCELLED = 2025,
- SCN_AUTOCCHARDELETED = 2026,
- SCN_AUTOCCOMPLETED = 2030,
- SCN_AUTOCSELECTION = 2022,
- SCN_CALLTIPCLICK = 2021,
- SCN_CHARADDED = 2001,
- SCN_DOUBLECLICK = 2006,
- SCN_DWELLEND = 2017,
- SCN_DWELLSTART = 2016,
- SCN_FOCUSIN = 2028,
- SCN_FOCUSOUT = 2029,
- SCN_HOTSPOTCLICK = 2019,
- SCN_HOTSPOTDOUBLECLICK = 2020,
- SCN_HOTSPOTRELEASECLICK = 2027,
- SCN_INDICATORCLICK = 2023,
- SCN_INDICATORRELEASE = 2024,
- SCN_MACRORECORD = 2009,
- SCN_MARGINCLICK = 2010,
- SCN_MARGINRIGHTCLICK = 2031,
- SCN_MODIFIED = 2008,
- SCN_MODIFYATTEMPTRO = 2004,
- SCN_NEEDSHOWN = 2011,
- SCN_PAINTED = 2013,
- SCN_SAVEPOINTLEFT = 2003,
- SCN_SAVEPOINTREACHED = 2002,
- SCN_STYLENEEDED = 2000,
- SCN_UPDATEUI = 2007,
- SCN_USERLISTSELECTION = 2014,
- SCN_ZOOM = 2018
- };
- // The ctor.
- QsciScintillaQt::QsciScintillaQt(QsciScintillaBase *qsb_)
- : vMax(0), hMax(0), vPage(0), hPage(0), capturedMouse(false), qsb(qsb_)
- {
- wMain = qsb->viewport();
- // This is ignored.
- imeInteraction = imeInline;
- for (int i = 0; i <= static_cast<int>(tickPlatform); ++i)
- timers[i] = 0;
- Initialise();
- }
- // The dtor.
- QsciScintillaQt::~QsciScintillaQt()
- {
- Finalise();
- }
- // Initialise the instance.
- void QsciScintillaQt::Initialise()
- {
- }
- // Tidy up the instance.
- void QsciScintillaQt::Finalise()
- {
- for (int i = 0; i <= static_cast<int>(tickPlatform); ++i)
- FineTickerCancel(static_cast<TickReason>(i));
- ScintillaBase::Finalise();
- }
- // Start a drag.
- void QsciScintillaQt::StartDrag()
- {
- inDragDrop = ddDragging;
- QDrag *qdrag = new QDrag(qsb);
- qdrag->setMimeData(mimeSelection(drag));
- #if QT_VERSION >= 0x040300
- Qt::DropAction action = qdrag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
- #else
- Qt::DropAction action = qdrag->start(Qt::MoveAction);
- #endif
- // Remove the dragged text if it was a move to another widget or
- // application.
- if (action == Qt::MoveAction && qdrag->target() != qsb->viewport())
- ClearSelection();
- SetDragPosition(QSCI_SCI_NAMESPACE(SelectionPosition)());
- inDragDrop = ddNone;
- }
- // Re-implement to trap certain messages.
- sptr_t QsciScintillaQt::WndProc(unsigned int iMessage, uptr_t wParam,
- sptr_t lParam)
- {
- switch (iMessage)
- {
- case SCI_GETDIRECTFUNCTION:
- return reinterpret_cast<sptr_t>(DirectFunction);
-
- case SCI_GETDIRECTPOINTER:
- return reinterpret_cast<sptr_t>(this);
- }
- return ScintillaBase::WndProc(iMessage, wParam, lParam);
- }
- // Windows nonsense.
- sptr_t QsciScintillaQt::DefWndProc(unsigned int, uptr_t, sptr_t)
- {
- return 0;
- }
- // Grab or release the mouse (and keyboard).
- void QsciScintillaQt::SetMouseCapture(bool on)
- {
- if (mouseDownCaptures)
- if (on)
- qsb->viewport()->grabMouse();
- else
- qsb->viewport()->releaseMouse();
- capturedMouse = on;
- }
- // Return true if the mouse/keyboard are currently grabbed.
- bool QsciScintillaQt::HaveMouseCapture()
- {
- return capturedMouse;
- }
- // Set the position of the vertical scrollbar.
- void QsciScintillaQt::SetVerticalScrollPos()
- {
- QScrollBar *sb = qsb->verticalScrollBar();
- bool was_blocked = sb->blockSignals(true);
- sb->setValue(topLine);
- sb->blockSignals(was_blocked);
- }
- // Set the position of the horizontal scrollbar.
- void QsciScintillaQt::SetHorizontalScrollPos()
- {
- QScrollBar *sb = qsb->horizontalScrollBar();
- bool was_blocked = sb->blockSignals(true);
- sb->setValue(xOffset);
- sb->blockSignals(was_blocked);
- }
- // Set the extent of the vertical and horizontal scrollbars and return true if
- // the view needs re-drawing.
- bool QsciScintillaQt::ModifyScrollBars(int nMax,int nPage)
- {
- bool modified = false;
- QScrollBar *sb;
- int vNewPage = nPage;
- int vNewMax = nMax - vNewPage + 1;
- if (vMax != vNewMax || vPage != vNewPage)
- {
- vMax = vNewMax;
- vPage = vNewPage;
- modified = true;
- sb = qsb->verticalScrollBar();
- sb->setMaximum(vMax);
- sb->setPageStep(vPage);
- }
- int hNewPage = GetTextRectangle().Width();
- int hNewMax = (scrollWidth > hNewPage) ? scrollWidth - hNewPage : 0;
- int charWidth = vs.styles[STYLE_DEFAULT].aveCharWidth;
- sb = qsb->horizontalScrollBar();
- if (hMax != hNewMax || hPage != hNewPage || sb->singleStep() != charWidth)
- {
- hMax = hNewMax;
- hPage = hNewPage;
- modified = true;
- sb->setMaximum(hMax);
- sb->setPageStep(hPage);
- sb->setSingleStep(charWidth);
- }
- return modified;
- }
- // Called after SCI_SETWRAPMODE and SCI_SETHSCROLLBAR.
- void QsciScintillaQt::ReconfigureScrollBars()
- {
- // Hide or show the scrollbars if needed.
- bool hsb = (horizontalScrollBarVisible && !Wrapping());
- qsb->setHorizontalScrollBarPolicy(hsb ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff);
- qsb->setVerticalScrollBarPolicy(verticalScrollBarVisible ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff);
- }
- // Notify interested parties of any change in the document.
- void QsciScintillaQt::NotifyChange()
- {
- emit qsb->SCEN_CHANGE();
- }
- // Notify interested parties of various events. This is the main mapping
- // between Scintilla notifications and Qt signals.
- void QsciScintillaQt::NotifyParent(SCNotification scn)
- {
- switch (scn.nmhdr.code)
- {
- case SCN_CALLTIPCLICK:
- emit qsb->SCN_CALLTIPCLICK(scn.position);
- break;
- case SCN_AUTOCCANCELLED:
- emit qsb->SCN_AUTOCCANCELLED();
- break;
- case SCN_AUTOCCHARDELETED:
- emit qsb->SCN_AUTOCCHARDELETED();
- break;
- case SCN_AUTOCCOMPLETED:
- emit qsb->SCN_AUTOCCOMPLETED(scn.text, scn.lParam, scn.ch,
- scn.listCompletionMethod);
- break;
- case SCN_AUTOCSELECTION:
- emit qsb->SCN_AUTOCSELECTION(scn.text, scn.lParam, scn.ch,
- scn.listCompletionMethod);
- emit qsb->SCN_AUTOCSELECTION(scn.text, scn.lParam);
- break;
- case SCN_CHARADDED:
- emit qsb->SCN_CHARADDED(scn.ch);
- break;
- case SCN_DOUBLECLICK:
- emit qsb->SCN_DOUBLECLICK(scn.position, scn.line, scn.modifiers);
- break;
- case SCN_DWELLEND:
- emit qsb->SCN_DWELLEND(scn.position, scn.x, scn.y);
- break;
- case SCN_DWELLSTART:
- emit qsb->SCN_DWELLSTART(scn.position, scn.x, scn.y);
- break;
- case SCN_FOCUSIN:
- emit qsb->SCN_FOCUSIN();
- break;
- case SCN_FOCUSOUT:
- emit qsb->SCN_FOCUSOUT();
- break;
- case SCN_HOTSPOTCLICK:
- emit qsb->SCN_HOTSPOTCLICK(scn.position, scn.modifiers);
- break;
- case SCN_HOTSPOTDOUBLECLICK:
- emit qsb->SCN_HOTSPOTDOUBLECLICK(scn.position, scn.modifiers);
- break;
- case SCN_HOTSPOTRELEASECLICK:
- emit qsb->SCN_HOTSPOTRELEASECLICK(scn.position, scn.modifiers);
- break;
- case SCN_INDICATORCLICK:
- emit qsb->SCN_INDICATORCLICK(scn.position, scn.modifiers);
- break;
- case SCN_INDICATORRELEASE:
- emit qsb->SCN_INDICATORRELEASE(scn.position, scn.modifiers);
- break;
- case SCN_MACRORECORD:
- emit qsb->SCN_MACRORECORD(scn.message, scn.wParam,
- reinterpret_cast<void *>(scn.lParam));
- break;
- case SCN_MARGINCLICK:
- emit qsb->SCN_MARGINCLICK(scn.position, scn.modifiers, scn.margin);
- break;
- case SCN_MARGINRIGHTCLICK:
- emit qsb->SCN_MARGINRIGHTCLICK(scn.position, scn.modifiers,
- scn.margin);
- break;
- case SCN_MODIFIED:
- {
- char *text;
- // Give some protection to the Python bindings.
- if (scn.text && (scn.modificationType & (SC_MOD_INSERTTEXT|SC_MOD_DELETETEXT) != 0))
- {
- text = new char[scn.length + 1];
- memcpy(text, scn.text, scn.length);
- text[scn.length] = '\0';
- }
- else
- {
- text = 0;
- }
- emit qsb->SCN_MODIFIED(scn.position, scn.modificationType, text,
- scn.length, scn.linesAdded, scn.line, scn.foldLevelNow,
- scn.foldLevelPrev, scn.token, scn.annotationLinesAdded);
- if (text)
- delete[] text;
- break;
- }
- case SCN_MODIFYATTEMPTRO:
- emit qsb->SCN_MODIFYATTEMPTRO();
- break;
- case SCN_NEEDSHOWN:
- emit qsb->SCN_NEEDSHOWN(scn.position, scn.length);
- break;
- case SCN_PAINTED:
- emit qsb->SCN_PAINTED();
- break;
- case SCN_SAVEPOINTLEFT:
- emit qsb->SCN_SAVEPOINTLEFT();
- break;
- case SCN_SAVEPOINTREACHED:
- emit qsb->SCN_SAVEPOINTREACHED();
- break;
- case SCN_STYLENEEDED:
- emit qsb->SCN_STYLENEEDED(scn.position);
- break;
- case SCN_UPDATEUI:
- emit qsb->SCN_UPDATEUI(scn.updated);
- break;
- case SCN_USERLISTSELECTION:
- emit qsb->SCN_USERLISTSELECTION(scn.text, scn.wParam, scn.ch,
- scn.listCompletionMethod);
- emit qsb->SCN_USERLISTSELECTION(scn.text, scn.wParam);
- break;
- case SCN_ZOOM:
- emit qsb->SCN_ZOOM();
- break;
- default:
- qWarning("Unknown notification: %u", scn.nmhdr.code);
- }
- }
- // Convert a selection to mime data.
- QMimeData *QsciScintillaQt::mimeSelection(
- const QSCI_SCI_NAMESPACE(SelectionText) &text) const
- {
- return qsb->toMimeData(QByteArray(text.Data()), text.rectangular);
- }
- // Copy the selected text to the clipboard.
- void QsciScintillaQt::CopyToClipboard(
- const QSCI_SCI_NAMESPACE(SelectionText) &selectedText)
- {
- QApplication::clipboard()->setMimeData(mimeSelection(selectedText));
- }
- // Implement copy.
- void QsciScintillaQt::Copy()
- {
- if (!sel.Empty())
- {
- QSCI_SCI_NAMESPACE(SelectionText) text;
- CopySelectionRange(&text);
- CopyToClipboard(text);
- }
- }
- // Implement pasting text.
- void QsciScintillaQt::Paste()
- {
- pasteFromClipboard(QClipboard::Clipboard);
- }
- // Paste text from either the clipboard or selection.
- void QsciScintillaQt::pasteFromClipboard(QClipboard::Mode mode)
- {
- int len;
- const char *s;
- bool rectangular;
- const QMimeData *source = QApplication::clipboard()->mimeData(mode);
- if (!source || !qsb->canInsertFromMimeData(source))
- return;
- QByteArray text = qsb->fromMimeData(source, rectangular);
- len = text.length();
- s = text.data();
- std::string dest = QSCI_SCI_NAMESPACE(Document)::TransformLineEnds(s, len,
- pdoc->eolMode);
- QSCI_SCI_NAMESPACE(SelectionText) selText;
- selText.Copy(dest, (IsUnicodeMode() ? SC_CP_UTF8 : 0),
- vs.styles[STYLE_DEFAULT].characterSet, rectangular, false);
- QSCI_SCI_NAMESPACE(UndoGroup) ug(pdoc);
- ClearSelection();
- InsertPasteShape(selText.Data(), selText.Length(),
- selText.rectangular ? pasteRectangular : pasteStream);
- EnsureCaretVisible();
- }
- // Create a call tip window.
- void QsciScintillaQt::CreateCallTipWindow(QSCI_SCI_NAMESPACE(PRectangle) rc)
- {
- if (!ct.wCallTip.Created())
- ct.wCallTip = ct.wDraw = new QsciSciCallTip(qsb, this);
- QsciSciCallTip *w = reinterpret_cast<QsciSciCallTip *>(ct.wCallTip.GetID());
- w->resize(rc.right - rc.left, rc.bottom - rc.top);
- ct.wCallTip.Show();
- }
- // Add an item to the right button menu.
- void QsciScintillaQt::AddToPopUp(const char *label, int cmd, bool enabled)
- {
- QsciSciPopup *pm = static_cast<QsciSciPopup *>(popup.GetID());
- if (*label)
- pm->addItem(qApp->translate("ContextMenu", label), cmd, enabled, this);
- else
- pm->addSeparator();
- }
- // Claim the selection.
- void QsciScintillaQt::ClaimSelection()
- {
- bool isSel = !sel.Empty();
- if (isSel)
- {
- QClipboard *cb = QApplication::clipboard();
- // If we support X11 style selection then make it available now.
- if (cb->supportsSelection())
- {
- QSCI_SCI_NAMESPACE(SelectionText) text;
- CopySelectionRange(&text);
- if (text.Data())
- cb->setMimeData(mimeSelection(text), QClipboard::Selection);
- }
- primarySelection = true;
- }
- else
- primarySelection = false;
- emit qsb->QSCN_SELCHANGED(isSel);
- }
- // Unclaim the selection.
- void QsciScintillaQt::UnclaimSelection()
- {
- if (primarySelection)
- {
- primarySelection = false;
- qsb->viewport()->update();
- }
- }
- // Implemented to provide compatibility with the Windows version.
- sptr_t QsciScintillaQt::DirectFunction(QsciScintillaQt *sciThis, unsigned int iMessage,
- uptr_t wParam, sptr_t lParam)
- {
- return sciThis->WndProc(iMessage,wParam,lParam);
- }
- // Draw the contents of the widget.
- void QsciScintillaQt::paintEvent(QPaintEvent *e)
- {
- QSCI_SCI_NAMESPACE(Surface) *sw;
- const QRect &qr = e->rect();
- rcPaint.left = qr.left();
- rcPaint.top = qr.top();
- rcPaint.right = qr.right() + 1;
- rcPaint.bottom = qr.bottom() + 1;
- QSCI_SCI_NAMESPACE(PRectangle) rcClient = GetClientRectangle();
- paintingAllText = rcPaint.Contains(rcClient);
- sw = QSCI_SCI_NAMESPACE(Surface)::Allocate(SC_TECHNOLOGY_DEFAULT);
- if (!sw)
- return;
- QPainter painter(qsb->viewport());
- paintState = painting;
- sw->Init(&painter);
- sw->SetUnicodeMode(CodePage() == SC_CP_UTF8);
- Paint(sw, rcPaint);
- delete sw;
- // If the painting area was insufficient to cover the new style or brace
- // highlight positions then repaint the whole thing.
- if (paintState == paintAbandoned)
- {
- // Do a full re-paint immediately. This may only be needed on OS X (to
- // avoid flicker).
- paintingAllText = true;
- sw = QSCI_SCI_NAMESPACE(Surface)::Allocate(SC_TECHNOLOGY_DEFAULT);
- if (!sw)
- return;
- QPainter painter(qsb->viewport());
- paintState = painting;
- sw->Init(&painter);
- sw->SetUnicodeMode(CodePage() == SC_CP_UTF8);
- Paint(sw, rcPaint);
- delete sw;
- qsb->viewport()->update();
- }
- paintState = notPainting;
- }
- // Re-implemented to drive the tickers.
- void QsciScintillaQt::timerEvent(QTimerEvent *e)
- {
- for (int i = 0; i <= static_cast<int>(tickPlatform); ++i)
- if (timers[i] == e->timerId())
- TickFor(static_cast<TickReason>(i));
- }
- // Re-implemented to say we support fine tickers.
- bool QsciScintillaQt::FineTickerAvailable()
- {
- return true;
- }
- // Re-implemented to stop a ticker.
- void QsciScintillaQt::FineTickerCancel(TickReason reason)
- {
- int &ticker = timers[static_cast<int>(reason)];
- if (ticker != 0)
- {
- killTimer(ticker);
- ticker = 0;
- }
- }
- // Re-implemented to check if a particular ticker is running.
- bool QsciScintillaQt::FineTickerRunning(TickReason reason)
- {
- return (timers[static_cast<int>(reason)] != 0);
- }
- // Re-implemented to start a ticker.
- void QsciScintillaQt::FineTickerStart(TickReason reason, int ms, int)
- {
- int &ticker = timers[static_cast<int>(reason)];
- if (ticker != 0)
- killTimer(ticker);
- ticker = startTimer(ms);
- }
- // Re-implemented to support idle processing.
- bool QsciScintillaQt::SetIdle(bool on)
- {
- if (on)
- {
- if (!idler.state)
- {
- QTimer *timer = reinterpret_cast<QTimer *>(idler.idlerID);
- if (!timer)
- {
- idler.idlerID = timer = new QTimer(this);
- connect(timer, SIGNAL(timeout()), this, SLOT(onIdle()));
- }
- timer->start(0);
- idler.state = true;
- }
- }
- else if (idler.state)
- {
- reinterpret_cast<QTimer *>(idler.idlerID)->stop();
- idler.state = false;
- }
- return true;
- }
- // Invoked to trigger any idle processing.
- void QsciScintillaQt::onIdle()
- {
- if (!Idle())
- SetIdle(false);
- }
|