summaryrefslogtreecommitdiffstats
path: root/qt/ScintillaQt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qt/ScintillaQt.cpp')
-rw-r--r--qt/ScintillaQt.cpp692
1 files changed, 692 insertions, 0 deletions
diff --git a/qt/ScintillaQt.cpp b/qt/ScintillaQt.cpp
new file mode 100644
index 0000000..4753785
--- /dev/null
+++ b/qt/ScintillaQt.cpp
@@ -0,0 +1,692 @@
+// The implementation of the Qt specific subclass of ScintillaBase.
+//
+// Copyright (c) 2006
+// Riverbank Computing Limited <info@riverbankcomputing.co.uk>
+//
+// This file is part of QScintilla.
+//
+// This copy of QScintilla is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2, or (at your option) any
+// later version.
+//
+// QScintilla is supplied in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+// details.
+//
+// You should have received a copy of the GNU General Public License along with
+// QScintilla; see the file LICENSE. If not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+#include <qapplication.h>
+#include <qscrollbar.h>
+#include <qpopupmenu.h>
+#include <qstring.h>
+#include <qtimer.h>
+#include <qclipboard.h>
+#include <qdragobject.h>
+#include <qpainter.h>
+
+#include "qextscintillabase.h"
+#include "ScintillaQt.h"
+
+
+// We want to use the Scintilla notification names as Qt signal names.
+#undef SCEN_CHANGE
+#undef SCN_AUTOCSELECTION
+#undef SCN_CALLTIPCLICK
+#undef SCN_CHARADDED
+#undef SCN_DOUBLECLICK
+#undef SCN_DWELLEND
+#undef SCN_DWELLSTART
+#undef SCN_HOTSPOTCLICK
+#undef SCN_HOTSPOTDOUBLECLICK
+#undef SCN_MACRORECORD
+#undef SCN_MARGINCLICK
+#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_AUTOCSELECTION = 2022,
+ SCN_CALLTIPCLICK = 2021,
+ SCN_CHARADDED = 2001,
+ SCN_DOUBLECLICK = 2006,
+ SCN_DWELLEND = 2017,
+ SCN_DWELLSTART = 2016,
+ SCN_HOTSPOTCLICK = 2019,
+ SCN_HOTSPOTDOUBLECLICK = 2020,
+ SCN_MACRORECORD = 2009,
+ SCN_MARGINCLICK = 2010,
+ 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.
+ScintillaQt::ScintillaQt(QextScintillaBase *qsb_) :
+ capturedMouse(false), qsb(qsb_)
+{
+ wMain = qsb -> txtarea;
+
+ // We aren't a QObject so we use the API class to do QObject related
+ // things for us.
+ qsb -> connect(&qtimer,SIGNAL(timeout()),SLOT(handleTimer()));
+
+ Initialise();
+}
+
+
+// The dtor.
+ScintillaQt::~ScintillaQt()
+{
+ Finalise();
+}
+
+
+// Initialise the instance.
+void ScintillaQt::Initialise()
+{
+ SetTicking(true);
+}
+
+
+// Tidy up the instance.
+void ScintillaQt::Finalise()
+{
+ SetTicking(false);
+ ScintillaBase::Finalise();
+}
+
+
+// Start a drag.
+void ScintillaQt::StartDrag()
+{
+ // Allow applications to re-implement the drag start.
+ qsb -> startDrag();
+}
+
+
+// Do the real drag start.
+void ScintillaQt::StartDragImpl()
+{
+ QDragObject *dobj = new QTextDrag(textRange(&drag),qsb -> txtarea);
+
+ // Remove the dragged text if it was a move to another widget or
+ // application.
+ if (dobj -> drag() && dobj -> target() != qsb -> txtarea)
+ ClearSelection();
+
+ inDragDrop = false;
+ SetDragPosition(invalidPosition);
+}
+
+
+// Handle a drag enter event.
+void ScintillaQt::dragEnterEvent(QDragEnterEvent *dee)
+{
+ dragMoveEvent(dee);
+}
+
+
+// Handle a drag move event.
+void ScintillaQt::dragMoveEvent(QDragMoveEvent *dme)
+{
+ dme -> acceptAction(QTextDrag::canDecode(dme));
+ SetDragPosition(PositionFromLocation(Point(dme -> pos().x(),dme -> pos().y())));
+}
+
+
+// Handle a drag leave event.
+void ScintillaQt::dragLeaveEvent(QDragLeaveEvent *dle)
+{
+ SetDragPosition(invalidPosition);
+}
+
+
+// Handle a drop event.
+void ScintillaQt::dropEvent(QDropEvent *de)
+{
+ QString text;
+
+ if (QTextDrag::decode(de,text))
+ {
+ bool moving = (de -> source() == qsb -> txtarea && de -> action() == QDropEvent::Move);
+
+ de -> acceptAction();
+
+ const char *s;
+ QCString us;
+
+ if (IsUnicodeMode())
+ {
+ us = text.utf8();
+ s = us.data();
+ }
+ else
+ s = text.latin1();
+
+ DropAt(posDrop,s,moving,false);
+ SetDragPosition(invalidPosition);
+ Redraw();
+ }
+}
+
+
+// Re-implement to trap certain messages.
+sptr_t ScintillaQt::WndProc(unsigned int iMessage,uptr_t wParam,sptr_t lParam)
+{
+ switch (iMessage)
+ {
+ case SCI_GRABFOCUS:
+ PWindow(wMain) -> setFocus();
+ return 0;
+
+ 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 ScintillaQt::DefWndProc(unsigned int,uptr_t,sptr_t)
+{
+ return 0;
+}
+
+
+// Manage the timer.
+void ScintillaQt::SetTicking(bool on)
+{
+ if (timer.ticking != on)
+ {
+ timer.ticking = on;
+
+ if (timer.ticking)
+ qtimer.start(timer.tickSize);
+ else
+ qtimer.stop();
+ }
+
+ timer.ticksToWait = caret.period;
+}
+
+
+// Grab or release the mouse (and keyboard).
+void ScintillaQt::SetMouseCapture(bool on)
+{
+ if (mouseDownCaptures)
+ if (on)
+ PWindow(wMain) -> grabMouse();
+ else
+ PWindow(wMain) -> releaseMouse();
+
+ capturedMouse = on;
+}
+
+
+// Return true if the mouse/keyboard are currently grabbed.
+bool ScintillaQt::HaveMouseCapture()
+{
+ return capturedMouse;
+}
+
+
+// Set the position of the vertical scrollbar.
+void ScintillaQt::SetVerticalScrollPos()
+{
+ qsb -> vsb -> setValue(topLine);
+}
+
+
+// Set the position of the horizontal scrollbar.
+void ScintillaQt::SetHorizontalScrollPos()
+{
+ qsb -> hsb -> setValue(xOffset);
+}
+
+
+// Set the extent of the vertical and horizontal scrollbars and return true if
+// the view needs re-drawing.
+bool ScintillaQt::ModifyScrollBars(int nMax,int nPage)
+{
+ qsb -> vsb -> setMinValue(0);
+ qsb -> vsb -> setMaxValue(nMax - nPage + 1);
+ qsb -> vsb -> setLineStep(1);
+ qsb -> vsb -> setPageStep(nPage);
+
+ qsb -> hsb -> setMinValue(0);
+ qsb -> hsb -> setMaxValue(scrollWidth);
+ qsb -> hsb -> setPageStep(scrollWidth / 10);
+
+ return true;
+}
+
+
+// Called after SCI_SETWRAPMODE and SCI_SETHSCROLLBAR.
+void ScintillaQt::ReconfigureScrollBars()
+{
+ // Hide or show the scrollbars if needed.
+ if (horizontalScrollBarVisible && wrapState == eWrapNone)
+ qsb->hsb->show();
+ else
+ qsb->hsb->hide();
+
+ if (verticalScrollBarVisible)
+ qsb->vsb->show();
+ else
+ qsb->vsb->hide();
+}
+
+
+// Notify interested parties of any change in the document.
+void ScintillaQt::NotifyChange()
+{
+ emit qsb -> SCEN_CHANGE();
+}
+
+
+// Notify interested parties of various events. This is the main mapping
+// between Scintilla notifications and Qt signals.
+void ScintillaQt::NotifyParent(SCNotification scn)
+{
+ switch (scn.nmhdr.code)
+ {
+ case SCN_CALLTIPCLICK:
+ emit qsb -> SCN_CALLTIPCLICK(scn.position);
+ break;
+
+ case SCN_AUTOCSELECTION:
+ 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();
+ 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_HOTSPOTCLICK:
+ emit qsb -> SCN_HOTSPOTCLICK(scn.position,scn.modifiers);
+ break;
+
+ case SCN_HOTSPOTDOUBLECLICK:
+ emit qsb -> SCN_HOTSPOTDOUBLECLICK(scn.position,scn.modifiers);
+ break;
+
+ case SCN_MACRORECORD:
+ emit qsb -> SCN_MACRORECORD(scn.message,scn.wParam,scn.lParam);
+ break;
+
+ case SCN_MARGINCLICK:
+ emit qsb -> SCN_MARGINCLICK(scn.position,scn.modifiers,
+ scn.margin);
+ break;
+
+ case SCN_MODIFIED:
+ emit qsb -> SCN_MODIFIED(scn.position,scn.modificationType,
+ scn.text,scn.length,scn.linesAdded,
+ scn.line,scn.foldLevelNow,
+ scn.foldLevelPrev);
+ 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();
+ break;
+
+ case SCN_USERLISTSELECTION:
+ 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);
+ }
+}
+
+
+// Handle a key that hasn't been filtered out as a command key. Return 0 if we
+// haven't handled it.
+int ScintillaQt::KeyDefault(int key,int modifiers)
+{
+ // On Windows Alt Gr is returned as Ctrl-Alt (on X11 it seems to be the
+ // Meta key). We therefore ignore that combination.
+#if defined(Q_OS_WIN)
+ modifiers &= (SCI_CTRL | SCI_ALT);
+
+ if (modifiers == SCI_CTRL || modifiers == SCI_ALT)
+ return 0;
+#else
+ if (modifiers & (SCI_CTRL | SCI_ALT))
+ return 0;
+#endif
+
+ AddChar(key);
+
+ return 1;
+}
+
+
+// Convert a text range to a QString.
+QString ScintillaQt::textRange(const SelectionText *text)
+{
+ QString qs;
+
+ if (text -> s)
+ if (IsUnicodeMode())
+ qs = QString::fromUtf8(text -> s);
+ else
+ qs.setLatin1(text -> s);
+
+ return qs;
+}
+
+
+// Copy the selected text to the clipboard.
+void ScintillaQt::CopyToClipboard(const SelectionText &selectedText)
+{
+ QApplication::clipboard() -> setText(textRange(&selectedText));
+}
+
+
+// Implement copy.
+void ScintillaQt::Copy()
+{
+ if (currentPos != anchor)
+ {
+ SelectionText text;
+
+ CopySelectionRange(&text);
+ CopyToClipboard(text);
+ }
+}
+
+
+// Implement paste.
+void ScintillaQt::Paste()
+{
+ QString str = QApplication::clipboard() -> text();
+
+ if (str.isEmpty())
+ return;
+
+ pdoc -> BeginUndoAction();
+
+ ClearSelection();
+
+ int len;
+
+ if (IsUnicodeMode())
+ {
+ QCString s = str.utf8();
+
+ len = s.length();
+
+ if (len)
+ pdoc -> InsertString(currentPos,s.data(),len);
+ }
+ else
+ {
+ const char *s = str.latin1();
+
+ len = (s ? strlen(s) : 0);
+
+ if (len)
+ pdoc -> InsertString(currentPos,s,len);
+ }
+
+ SetEmptySelection(currentPos + len);
+
+ pdoc -> EndUndoAction();
+
+ NotifyChange();
+ Redraw();
+}
+
+
+// A simple QWidget sub-class to implement a call tip. No need to bother with
+// all the moc stuff.
+class QtCallTip : public QWidget
+{
+public:
+ QtCallTip(QWidget *parent,ScintillaQt *sci_);
+ ~QtCallTip();
+
+protected:
+ void paintEvent(QPaintEvent *);
+ void mousePressEvent(QMouseEvent *me);
+
+private:
+ ScintillaQt *sci;
+};
+
+
+// Create a call tip.
+QtCallTip::QtCallTip(QWidget *parent,ScintillaQt *sci_) :
+ QWidget(parent,0,WType_Popup|WStyle_Customize|WStyle_NoBorder), sci(sci_)
+{
+ // Ensure that the main window keeps the focus (and the caret flashing)
+ // when this is displayed.
+ setFocusProxy(parent);
+}
+
+
+// Destroy a call tip.
+QtCallTip::~QtCallTip()
+{
+ // Ensure that the main window doesn't receive a focus out event when
+ // this is destroyed.
+ setFocusProxy(0);
+}
+
+
+// Paint a call tip.
+void QtCallTip::paintEvent(QPaintEvent *)
+{
+ Surface *surfaceWindow = Surface::Allocate();
+
+ if (surfaceWindow)
+ {
+ QPainter p(this);
+
+ surfaceWindow -> Init(&p,0);
+ sci -> ct.PaintCT(surfaceWindow);
+ surfaceWindow -> Release();
+
+ delete surfaceWindow;
+ }
+}
+
+
+// Handle a mouse press in a call tip.
+void QtCallTip::mousePressEvent(QMouseEvent *me)
+{
+ Point pt;
+
+ pt.x = me -> x();
+ pt.y = me -> y();
+
+ sci -> ct.MouseClick(pt);
+ sci -> CallTipClick();
+}
+
+
+// Create a call tip window.
+void ScintillaQt::CreateCallTipWindow(PRectangle rc)
+{
+ if (!ct.wCallTip.Created())
+ ct.wCallTip = ct.wDraw = new QtCallTip(qsb,this);
+
+ PWindow(ct.wCallTip) -> resize(rc.right - rc.left,rc.bottom - rc.top);
+ ct.wCallTip.Show();
+}
+
+
+// Add an item to the right button menu.
+void ScintillaQt::AddToPopUp(const char *label,int cmd,bool enabled)
+{
+ QPopupMenu *pm = static_cast<QPopupMenu *>(popup.GetID());
+
+ if (label[0] != '\0')
+ {
+ QString tr_label = qApp -> translate("ContextMenu",label);
+
+ pm -> insertItem(tr_label,qsb,SLOT(handlePopUp(int)),0,cmd);
+ pm -> setItemEnabled(cmd,enabled);
+ }
+ else
+ pm -> insertSeparator();
+}
+
+
+// Claim the selection.
+void ScintillaQt::ClaimSelection()
+{
+ bool isSel = (currentPos != anchor);
+
+ if (isSel)
+ {
+ QClipboard *cb = QApplication::clipboard();
+
+ // If we support X11 style selection then make it available
+ // now.
+ if (cb -> supportsSelection())
+ {
+ SelectionText text;
+
+ CopySelectionRange(&text);
+
+ if (text.s)
+ {
+ cb -> setSelectionMode(TRUE);
+ cb -> setText(text.s);
+ cb -> setSelectionMode(FALSE);
+ }
+ }
+
+ primarySelection = true;
+ }
+ else
+ primarySelection = false;
+
+ emit qsb -> QSCN_SELCHANGED(isSel);
+}
+
+
+// Unclaim the selection.
+void ScintillaQt::UnclaimSelection()
+{
+ if (primarySelection)
+ {
+ primarySelection = false;
+ qsb -> txtarea -> update();
+ }
+}
+
+
+// Implemented to provide compatibility with the Windows version.
+sptr_t ScintillaQt::DirectFunction(ScintillaQt *sciThis,unsigned int iMessage,
+ uptr_t wParam,sptr_t lParam)
+{
+ return sciThis -> WndProc(iMessage,wParam,lParam);
+}
+
+
+// Draw the contents of the widget.
+void ScintillaQt::paintEvent(QPaintEvent *pe)
+{
+ bool isUnicodeMode = (pdoc && pdoc -> dbcsCodePage == SC_CP_UTF8);
+
+ paintState = painting;
+
+ const QRect &qr = pe -> rect();
+
+ rcPaint.left = qr.left();
+ rcPaint.top = qr.top();
+ rcPaint.right = qr.right() + 1;
+ rcPaint.bottom = qr.bottom() + 1;
+
+ PRectangle rcText = GetTextRectangle();
+ paintingAllText = rcPaint.Contains(rcText);
+
+ Surface *sw = Surface::Allocate();
+
+ if (sw)
+ {
+ QPainter painter(PWindow(wMain));
+
+ sw -> Init(&painter,0);
+ sw -> SetUnicodeMode(isUnicodeMode);
+ Paint(sw,rcPaint);
+ sw -> Release();
+ 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)
+ PWindow(wMain) -> update();
+ }
+
+ paintState = notPainting;
+}