Mercurial > octave
view libgui/languages/build_ts/octave-qsci/qsciscintillabase.cpp @ 31537:5ceb4bfcdb0f stable
add tools and files for updating the gui's language files for translation
* libgui/languages/build_ts/README.md: readme for updating language files
* libgui/languages/build_ts/octave-qsci: QScintilla source files for
languages without translation provided by QScintilla
* libgui/languages/build_ts/octave-qt: Qt source files for languages
without translation provided by Qt
author | Torsten Lilge <ttl-octave@mailbox.org> |
---|---|
date | Thu, 24 Nov 2022 06:48:25 +0100 |
parents | |
children | dd5ece3664ed |
line wrap: on
line source
// This module implements the "official" low-level API. // // Copyright (c) 2019 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 "Qsci/qsciscintillabase.h" #include <QApplication> #include <QClipboard> #include <QColor> #include <QContextMenuEvent> #include <QDragEnterEvent> #include <QDragMoveEvent> #include <QDropEvent> #include <QDragLeaveEvent> #include <QFocusEvent> #include <QKeyEvent> #include <QList> #include <QMimeData> #include <QMouseEvent> #include <QPaintEvent> #include <QScrollBar> #include <QStyle> #include <QTextCodec> #include "SciAccessibility.h" #include "ScintillaQt.h" // The #defines in Scintilla.h and the enums in qsciscintillabase.h conflict // (because we want to use the same names) so we have to undefine those we use // in this file. #undef SCI_SETCARETPERIOD #undef SCK_DOWN #undef SCK_UP #undef SCK_LEFT #undef SCK_RIGHT #undef SCK_HOME #undef SCK_END #undef SCK_PRIOR #undef SCK_NEXT #undef SCK_DELETE #undef SCK_INSERT #undef SCK_ESCAPE #undef SCK_BACK #undef SCK_TAB #undef SCK_RETURN #undef SCK_ADD #undef SCK_SUBTRACT #undef SCK_DIVIDE #undef SCK_WIN #undef SCK_RWIN #undef SCK_MENU #undef SCN_URIDROPPED // Remember if we have linked the lexers. static bool lexersLinked = false; // The list of instances. static QList<QsciScintillaBase *> poolList; // Mime support. static const QLatin1String mimeTextPlain("text/plain"); static const QLatin1String mimeRectangularWin("MSDEVColumnSelect"); static const QLatin1String mimeRectangular("text/x-qscintilla-rectangular"); #if (QT_VERSION >= 0x040200 && QT_VERSION < 0x050000 && defined(Q_OS_MAC)) || (QT_VERSION >= 0x050200 && defined(Q_OS_OSX)) extern void initialiseRectangularPasteboardMime(); #endif // The ctor. QsciScintillaBase::QsciScintillaBase(QWidget *parent) : QAbstractScrollArea(parent), preeditPos(-1), preeditNrBytes(0) #if QT_VERSION >= 0x050000 , clickCausedFocus(false) #endif { #if !defined(QT_NO_ACCESSIBILITY) QsciAccessibleScintillaBase::initialise(); #endif connectVerticalScrollBar(); connectHorizontalScrollBar(); setAcceptDrops(true); setFocusPolicy(Qt::WheelFocus); setAttribute(Qt::WA_KeyCompression); setAttribute(Qt::WA_InputMethodEnabled); #if QT_VERSION >= 0x050100 setInputMethodHints( Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText|Qt::ImhMultiLine); #elif QT_VERSION >= 0x040600 setInputMethodHints(Qt::ImhNoAutoUppercase|Qt::ImhNoPredictiveText); #endif viewport()->setBackgroundRole(QPalette::Base); viewport()->setMouseTracking(true); viewport()->setAttribute(Qt::WA_NoSystemBackground); triple_click.setSingleShot(true); #if (QT_VERSION >= 0x040200 && QT_VERSION < 0x050000 && defined(Q_OS_MAC)) || (QT_VERSION >= 0x050200 && defined(Q_OS_OSX)) initialiseRectangularPasteboardMime(); #endif sci = new QsciScintillaQt(this); SendScintilla(SCI_SETCARETPERIOD, QApplication::cursorFlashTime() / 2); // Make sure the lexers are linked in. if (!lexersLinked) { Scintilla_LinkLexers(); lexersLinked = true; } // Add it to the pool. poolList.append(this); } // The dtor. QsciScintillaBase::~QsciScintillaBase() { // The QsciScintillaQt object isn't a child so delete it explicitly. delete sci; // Remove it from the pool. poolList.removeAt(poolList.indexOf(this)); } // Return an instance from the pool. QsciScintillaBase *QsciScintillaBase::pool() { return poolList.first(); } // Tell Scintilla to update the scroll bars. Scintilla should be doing this // itself. void QsciScintillaBase::setScrollBars() { sci->SetScrollBars(); } // Send a message to the real Scintilla widget using the low level Scintilla // API. long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, long lParam) const { return sci->WndProc(msg, wParam, lParam); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, void *lParam) const { return sci->WndProc(msg, wParam, reinterpret_cast<sptr_t>(lParam)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, uintptr_t wParam, const char *lParam) const { return sci->WndProc(msg, wParam, reinterpret_cast<sptr_t>(lParam)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, const char *lParam) const { return sci->WndProc(msg, static_cast<uptr_t>(0), reinterpret_cast<sptr_t>(lParam)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, const char *wParam, const char *lParam) const { return sci->WndProc(msg, reinterpret_cast<uptr_t>(wParam), reinterpret_cast<sptr_t>(lParam)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, long wParam) const { return sci->WndProc(msg, static_cast<uptr_t>(wParam), static_cast<sptr_t>(0)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, int wParam) const { return sci->WndProc(msg, static_cast<uptr_t>(wParam), static_cast<sptr_t>(0)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, long cpMin, long cpMax, char *lpstrText) const { Sci_TextRange tr; tr.chrg.cpMin = cpMin; tr.chrg.cpMax = cpMax; tr.lpstrText = lpstrText; return sci->WndProc(msg, static_cast<uptr_t>(0), reinterpret_cast<sptr_t>(&tr)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, const QColor &col) const { sptr_t lParam = (col.blue() << 16) | (col.green() << 8) | col.red(); return sci->WndProc(msg, wParam, lParam); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, const QColor &col) const { uptr_t wParam = (col.blue() << 16) | (col.green() << 8) | col.red(); return sci->WndProc(msg, wParam, static_cast<sptr_t>(0)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, QPainter *hdc, const QRect &rc, long cpMin, long cpMax) const { Sci_RangeToFormat rf; rf.hdc = rf.hdcTarget = reinterpret_cast<Scintilla::SurfaceID>(hdc); rf.rc.left = rc.left(); rf.rc.top = rc.top(); rf.rc.right = rc.right() + 1; rf.rc.bottom = rc.bottom() + 1; rf.chrg.cpMin = cpMin; rf.chrg.cpMax = cpMax; return sci->WndProc(msg, wParam, reinterpret_cast<sptr_t>(&rf)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, const QPixmap &lParam) const { return sci->WndProc(msg, wParam, reinterpret_cast<sptr_t>(&lParam)); } // Overloaded message send. long QsciScintillaBase::SendScintilla(unsigned int msg, unsigned long wParam, const QImage &lParam) const { return sci->WndProc(msg, wParam, reinterpret_cast<sptr_t>(&lParam)); } // Send a message to the real Scintilla widget using the low level Scintilla // API that returns a pointer result. void *QsciScintillaBase::SendScintillaPtrResult(unsigned int msg) const { return reinterpret_cast<void *>(sci->WndProc(msg, static_cast<uptr_t>(0), static_cast<sptr_t>(0))); } // Re-implemented to handle font changes void QsciScintillaBase::changeEvent(QEvent *e) { if (e->type() == QEvent::FontChange || e->type() == QEvent::ApplicationFontChange) sci->InvalidateStyleRedraw(); QAbstractScrollArea::changeEvent(e); } // Re-implemented to handle the context menu. void QsciScintillaBase::contextMenuEvent(QContextMenuEvent *e) { sci->ContextMenu(Scintilla::Point(e->globalX(), e->globalY())); } // Re-implemented to tell the widget it has the focus. void QsciScintillaBase::focusInEvent(QFocusEvent *e) { sci->SetFocusState(true); #if QT_VERSION >= 0x050000 clickCausedFocus = (e->reason() == Qt::MouseFocusReason); #endif QAbstractScrollArea::focusInEvent(e); } // Re-implemented to tell the widget it has lost the focus. void QsciScintillaBase::focusOutEvent(QFocusEvent *e) { if (e->reason() == Qt::ActiveWindowFocusReason) { // Only tell Scintilla we have lost focus if the new active window // isn't our auto-completion list. This is probably only an issue on // Linux and there are still problems because subsequent focus out // events don't always seem to get generated (at least with Qt5). QWidget *aw = QApplication::activeWindow(); if (!aw || aw->parent() != this || !aw->inherits("QsciSciListBox")) sci->SetFocusState(false); } else { sci->SetFocusState(false); } QAbstractScrollArea::focusOutEvent(e); } // Re-implemented to make sure tabs are passed to the editor. bool QsciScintillaBase::focusNextPrevChild(bool next) { if (!sci->pdoc->IsReadOnly()) return false; return QAbstractScrollArea::focusNextPrevChild(next); } // Handle key presses. void QsciScintillaBase::keyPressEvent(QKeyEvent *e) { int modifiers = 0; if (e->modifiers() & Qt::ShiftModifier) modifiers |= SCMOD_SHIFT; if (e->modifiers() & Qt::ControlModifier) modifiers |= SCMOD_CTRL; if (e->modifiers() & Qt::AltModifier) modifiers |= SCMOD_ALT; if (e->modifiers() & Qt::MetaModifier) modifiers |= SCMOD_META; int key = commandKey(e->key(), modifiers); if (key) { bool consumed = false; sci->KeyDownWithModifiers(key, modifiers, &consumed); if (consumed) { e->accept(); return; } } QString text = e->text(); if (!text.isEmpty() && text[0].isPrint()) { ScintillaBytes bytes = textAsBytes(text); sci->AddCharUTF(bytes.data(), bytes.length()); e->accept(); } else { QAbstractScrollArea::keyPressEvent(e); } } // Map a Qt key to a valid Scintilla command key, or 0 if none. int QsciScintillaBase::commandKey(int qt_key, int &modifiers) { int key; switch (qt_key) { case Qt::Key_Down: key = SCK_DOWN; break; case Qt::Key_Up: key = SCK_UP; break; case Qt::Key_Left: key = SCK_LEFT; break; case Qt::Key_Right: key = SCK_RIGHT; break; case Qt::Key_Home: key = SCK_HOME; break; case Qt::Key_End: key = SCK_END; break; case Qt::Key_PageUp: key = SCK_PRIOR; break; case Qt::Key_PageDown: key = SCK_NEXT; break; case Qt::Key_Delete: key = SCK_DELETE; break; case Qt::Key_Insert: key = SCK_INSERT; break; case Qt::Key_Escape: key = SCK_ESCAPE; break; case Qt::Key_Backspace: key = SCK_BACK; break; case Qt::Key_Tab: key = SCK_TAB; break; case Qt::Key_Backtab: // Scintilla assumes a backtab is shift-tab. key = SCK_TAB; modifiers |= SCMOD_SHIFT; break; case Qt::Key_Return: case Qt::Key_Enter: key = SCK_RETURN; break; case Qt::Key_Super_L: key = SCK_WIN; break; case Qt::Key_Super_R: key = SCK_RWIN; break; case Qt::Key_Menu: key = SCK_MENU; break; default: if ((key = qt_key) > 0x7f) key = 0; } return key; } // Encode a QString as bytes. QsciScintillaBase::ScintillaBytes QsciScintillaBase::textAsBytes(const QString &text) const { if (sci->IsUnicodeMode()) return text.toUtf8(); return text.toLatin1(); } // Decode bytes as a QString. QString QsciScintillaBase::bytesAsText(const char *bytes) const { if (sci->IsUnicodeMode()) return QString::fromUtf8(bytes); return QString::fromLatin1(bytes); } // Handle a mouse button double click. void QsciScintillaBase::mouseDoubleClickEvent(QMouseEvent *e) { if (e->button() != Qt::LeftButton) { e->ignore(); return; } setFocus(); // Make sure Scintilla will interpret this as a double-click. unsigned clickTime = sci->lastClickTime + Scintilla::Platform::DoubleClickTime() - 1; sci->ButtonDownWithModifiers(Scintilla::Point(e->x(), e->y()), clickTime, eventModifiers(e)); // Remember the current position and time in case it turns into a triple // click. triple_click_at = e->globalPos(); triple_click.start(QApplication::doubleClickInterval()); } // Handle a mouse move. void QsciScintillaBase::mouseMoveEvent(QMouseEvent *e) { sci->ButtonMoveWithModifiers(Scintilla::Point(e->x(), e->y()), 0, eventModifiers(e)); } // Handle a mouse button press. void QsciScintillaBase::mousePressEvent(QMouseEvent *e) { setFocus(); Scintilla::Point pt(e->x(), e->y()); if (e->button() == Qt::LeftButton || e->button() == Qt::RightButton) { unsigned clickTime; // It is a triple click if the timer is running and the mouse hasn't // moved too much. if (triple_click.isActive() && (e->globalPos() - triple_click_at).manhattanLength() < QApplication::startDragDistance()) clickTime = sci->lastClickTime + Scintilla::Platform::DoubleClickTime() - 1; else clickTime = sci->lastClickTime + Scintilla::Platform::DoubleClickTime() + 1; triple_click.stop(); // Scintilla uses the Alt modifier to initiate rectangular selection. // However the GTK port (under X11, not Windows) uses the Control // modifier (by default, although it is configurable). It does this // because most X11 window managers hijack Alt-drag to move the window. // We do the same, except that (for the moment at least) we don't allow // the modifier to be configured. bool shift = e->modifiers() & Qt::ShiftModifier; bool ctrl = e->modifiers() & Qt::ControlModifier; #if defined(Q_OS_MAC) || defined(Q_OS_WIN) bool alt = e->modifiers() & Qt::AltModifier; #else bool alt = ctrl; #endif if (e->button() == Qt::LeftButton) sci->ButtonDownWithModifiers(pt, clickTime, QsciScintillaQt::ModifierFlags(shift, ctrl, alt)); else sci->RightButtonDownWithModifiers(pt, clickTime, QsciScintillaQt::ModifierFlags(shift, ctrl, alt)); } else if (e->button() == Qt::MidButton) { QClipboard *cb = QApplication::clipboard(); if (cb->supportsSelection()) { int pos = sci->PositionFromLocation(pt); sci->sel.Clear(); sci->SetSelection(pos, pos); sci->pasteFromClipboard(QClipboard::Selection); } } } // Handle a mouse button releases. void QsciScintillaBase::mouseReleaseEvent(QMouseEvent *e) { if (e->button() != Qt::LeftButton) return; Scintilla::Point pt(e->x(), e->y()); if (sci->HaveMouseCapture()) { bool ctrl = e->modifiers() & Qt::ControlModifier; sci->ButtonUpWithModifiers(pt, 0, QsciScintillaQt::ModifierFlags(false, ctrl, false)); } #if QT_VERSION >= 0x050000 if (!sci->pdoc->IsReadOnly() && !sci->PointInSelMargin(pt) && qApp->autoSipEnabled()) { QStyle::RequestSoftwareInputPanel rsip = QStyle::RequestSoftwareInputPanel(style()->styleHint(QStyle::SH_RequestSoftwareInputPanel)); if (!clickCausedFocus || rsip == QStyle::RSIP_OnMouseClick) qApp->inputMethod()->show(); } clickCausedFocus = false; #endif } // Handle paint events. void QsciScintillaBase::paintEvent(QPaintEvent *e) { sci->paintEvent(e); } // Handle resize events. void QsciScintillaBase::resizeEvent(QResizeEvent *) { sci->ChangeSize(); } // Re-implemented to suppress the default behaviour as Scintilla works at a // more fundamental level. Note that this means that replacing the scrollbars // with custom versions does not work. void QsciScintillaBase::scrollContentsBy(int, int) { } // Handle the vertical scrollbar. void QsciScintillaBase::handleVSb(int value) { sci->ScrollTo(value); } // Handle the horizontal scrollbar. void QsciScintillaBase::handleHSb(int value) { sci->HorizontalScrollTo(value); } // Handle drag enters. void QsciScintillaBase::dragEnterEvent(QDragEnterEvent *e) { QsciScintillaBase::dragMoveEvent(e); } // Handle drag leaves. void QsciScintillaBase::dragLeaveEvent(QDragLeaveEvent *) { sci->SetDragPosition(Scintilla::SelectionPosition()); } // Handle drag moves. void QsciScintillaBase::dragMoveEvent(QDragMoveEvent *e) { if (e->mimeData()->hasUrls()) { e->acceptProposedAction(); } else { sci->SetDragPosition( sci->SPositionFromLocation( Scintilla::Point(e->pos().x(), e->pos().y()), false, false, sci->UserVirtualSpace())); acceptAction(e); } } // Handle drops. void QsciScintillaBase::dropEvent(QDropEvent *e) { if (e->mimeData()->hasUrls()) { e->acceptProposedAction(); foreach (const QUrl &url, e->mimeData()->urls()) emit SCN_URIDROPPED(url); return; } acceptAction(e); if (!e->isAccepted()) return; bool moving; int len; const char *s; bool rectangular; moving = (e->dropAction() == Qt::MoveAction); QByteArray text = fromMimeData(e->mimeData(), rectangular); len = text.length(); s = text.data(); std::string dest = Scintilla::Document::TransformLineEnds(s, len, sci->pdoc->eolMode); sci->DropAt(sci->posDrop, dest.c_str(), dest.length(), moving, rectangular); sci->Redraw(); } void QsciScintillaBase::acceptAction(QDropEvent *e) { if (sci->pdoc->IsReadOnly() || !canInsertFromMimeData(e->mimeData())) e->ignore(); else e->acceptProposedAction(); } // See if a MIME data object can be decoded. bool QsciScintillaBase::canInsertFromMimeData(const QMimeData *source) const { return source->hasFormat(mimeTextPlain); } // Create text from a MIME data object. QByteArray QsciScintillaBase::fromMimeData(const QMimeData *source, bool &rectangular) const { // See if it is rectangular. We try all of the different formats that // Scintilla supports in case we are working across different platforms. if (source->hasFormat(mimeRectangularWin)) rectangular = true; else if (source->hasFormat(mimeRectangular)) rectangular = true; else rectangular = false; // Note that we don't support Scintilla's hack of adding a '\0' as Qt // strips it off under the covers when pasting from another process. QString utf8 = source->text(); QByteArray text; if (sci->IsUnicodeMode()) text = utf8.toUtf8(); else text = utf8.toLatin1(); return text; } // Create a MIME data object for some text. QMimeData *QsciScintillaBase::toMimeData(const QByteArray &text, bool rectangular) const { QMimeData *mime = new QMimeData; QString utf8; if (sci->IsUnicodeMode()) utf8 = QString::fromUtf8(text.constData(), text.size()); else utf8 = QString::fromLatin1(text.constData(), text.size()); mime->setText(utf8); if (rectangular) { // Use the platform specific "standard" for specifying a rectangular // selection. #if defined(Q_OS_WIN) mime->setData(mimeRectangularWin, QByteArray()); #else mime->setData(mimeRectangular, QByteArray()); #endif } return mime; } // Connect up the vertical scroll bar. void QsciScintillaBase::connectVerticalScrollBar() { connect(verticalScrollBar(), SIGNAL(valueChanged(int)), SLOT(handleVSb(int))); } // Connect up the horizontal scroll bar. void QsciScintillaBase::connectHorizontalScrollBar() { connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), SLOT(handleHSb(int))); } //! Replace the vertical scroll bar. void QsciScintillaBase::replaceVerticalScrollBar(QScrollBar *scrollBar) { setVerticalScrollBar(scrollBar); connectVerticalScrollBar(); } // Replace the horizontal scroll bar. void QsciScintillaBase::replaceHorizontalScrollBar(QScrollBar *scrollBar) { setHorizontalScrollBar(scrollBar); connectHorizontalScrollBar(); } // Return true if a context menu should be displayed. This is provided as a // helper to QsciScintilla::contextMenuEvent(). A proper design would break // backwards compatibility. bool QsciScintillaBase::contextMenuNeeded(int x, int y) const { Scintilla::Point pt(x, y); // Clear any selection if the mouse is outside. if (!sci->PointInSelection(pt)) sci->SetEmptySelection(sci->PositionFromLocation(pt)); // Respect SC_POPUP_*. return sci->ShouldDisplayPopup(pt); } // Return the Scintilla keyboard modifiers set for a mouse event. int QsciScintillaBase::eventModifiers(QMouseEvent *e) { bool shift = e->modifiers() & Qt::ShiftModifier; bool ctrl = e->modifiers() & Qt::ControlModifier; bool alt = e->modifiers() & Qt::AltModifier; return QsciScintillaQt::ModifierFlags(shift, ctrl, alt); }