You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tqscintilla/qt/ScintillaQt.cpp

693 lines
14 KiB

// The implementation of the TQt specific subclass of ScintillaBase.
//
// Copyright (c) 2006
// Riverbank Computing Limited <info@riverbankcomputing.co.uk>
//
// This file is part of TQScintilla.
//
// This copy of TQScintilla 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.
//
// TQScintilla 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
// TQScintilla; see the file LICENSE. If not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <tqapplication.h>
#include <tqscrollbar.h>
#include <tqpopupmenu.h>
#include <tqstring.h>
#include <tqtimer.h>
#include <tqclipboard.h>
#include <tqdragobject.h>
#include <tqpainter.h>
#include "qextscintillabase.h"
#include "ScintillaQt.h"
// We want to use the Scintilla notification names as TQt 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.
ScintillaTQt::ScintillaTQt(QextScintillaBase *qsb_) :
capturedMouse(false), qsb(qsb_)
{
wMain = qsb -> txtarea;
// We aren't a TQObject so we use the API class to do TQObject related
// things for us.
qsb -> connect(&qtimer,TQT_SIGNAL(timeout()),TQT_SLOT(handleTimer()));
Initialise();
}
// The dtor.
ScintillaTQt::~ScintillaTQt()
{
Finalise();
}
// Initialise the instance.
void ScintillaTQt::Initialise()
{
SetTicking(true);
}
// Tidy up the instance.
void ScintillaTQt::Finalise()
{
SetTicking(false);
ScintillaBase::Finalise();
}
// Start a drag.
void ScintillaTQt::StartDrag()
{
// Allow applications to re-implement the drag start.
qsb -> startDrag();
}
// Do the real drag start.
void ScintillaTQt::StartDragImpl()
{
TQDragObject *dobj = new TQTextDrag(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 ScintillaTQt::dragEnterEvent(TQDragEnterEvent *dee)
{
dragMoveEvent(dee);
}
// Handle a drag move event.
void ScintillaTQt::dragMoveEvent(TQDragMoveEvent *dme)
{
dme -> acceptAction(TQTextDrag::canDecode(dme));
SetDragPosition(PositionFromLocation(Point(dme -> pos().x(),dme -> pos().y())));
}
// Handle a drag leave event.
void ScintillaTQt::dragLeaveEvent(TQDragLeaveEvent *dle)
{
SetDragPosition(invalidPosition);
}
// Handle a drop event.
void ScintillaTQt::dropEvent(TQDropEvent *de)
{
TQString text;
if (TQTextDrag::decode(de,text))
{
bool moving = (de -> source() == qsb -> txtarea && de -> action() == TQDropEvent::Move);
de -> acceptAction();
const char *s;
TQCString 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 ScintillaTQt::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 ScintillaTQt::DefWndProc(unsigned int,uptr_t,sptr_t)
{
return 0;
}
// Manage the timer.
void ScintillaTQt::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 ScintillaTQt::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 ScintillaTQt::HaveMouseCapture()
{
return capturedMouse;
}
// Set the position of the vertical scrollbar.
void ScintillaTQt::SetVerticalScrollPos()
{
qsb -> vsb -> setValue(topLine);
}
// Set the position of the horizontal scrollbar.
void ScintillaTQt::SetHorizontalScrollPos()
{
qsb -> hsb -> setValue(xOffset);
}
// Set the extent of the vertical and horizontal scrollbars and return true if
// the view needs re-drawing.
bool ScintillaTQt::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 ScintillaTQt::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 ScintillaTQt::NotifyChange()
{
emit qsb -> SCEN_CHANGE();
}
// Notify interested parties of various events. This is the main mapping
// between Scintilla notifications and TQt signals.
void ScintillaTQt::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 ScintillaTQt::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 TQString.
TQString ScintillaTQt::textRange(const SelectionText *text)
{
TQString qs;
if (text -> s)
if (IsUnicodeMode())
qs = TQString::fromUtf8(text -> s);
else
qs.setLatin1(text -> s);
return qs;
}
// Copy the selected text to the clipboard.
void ScintillaTQt::CopyToClipboard(const SelectionText &selectedText)
{
TQApplication::clipboard() -> setText(textRange(&selectedText));
}
// Implement copy.
void ScintillaTQt::Copy()
{
if (currentPos != anchor)
{
SelectionText text;
CopySelectionRange(&text);
CopyToClipboard(text);
}
}
// Implement paste.
void ScintillaTQt::Paste()
{
TQString str = TQApplication::clipboard() -> text();
if (str.isEmpty())
return;
pdoc -> BeginUndoAction();
ClearSelection();
int len;
if (IsUnicodeMode())
{
TQCString 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 TQWidget sub-class to implement a call tip. No need to bother with
// all the tqmoc stuff.
class TQtCallTip : public TQWidget
{
public:
TQtCallTip(TQWidget *parent,ScintillaTQt *sci_);
~TQtCallTip();
protected:
void paintEvent(TQPaintEvent *);
void mousePressEvent(TQMouseEvent *me);
private:
ScintillaTQt *sci;
};
// Create a call tip.
TQtCallTip::TQtCallTip(TQWidget *parent,ScintillaTQt *sci_) :
TQWidget(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.
TQtCallTip::~TQtCallTip()
{
// Ensure that the main window doesn't receive a focus out event when
// this is destroyed.
setFocusProxy(0);
}
// Paint a call tip.
void TQtCallTip::paintEvent(TQPaintEvent *)
{
Surface *surfaceWindow = Surface::Allocate();
if (surfaceWindow)
{
TQPainter p(this);
surfaceWindow -> Init(&p,0);
sci -> ct.PaintCT(surfaceWindow);
surfaceWindow -> Release();
delete surfaceWindow;
}
}
// Handle a mouse press in a call tip.
void TQtCallTip::mousePressEvent(TQMouseEvent *me)
{
Point pt;
pt.x = me -> x();
pt.y = me -> y();
sci -> ct.MouseClick(pt);
sci -> CallTipClick();
}
// Create a call tip window.
void ScintillaTQt::CreateCallTipWindow(PRectangle rc)
{
if (!ct.wCallTip.Created())
ct.wCallTip = ct.wDraw = new TQtCallTip(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 ScintillaTQt::AddToPopUp(const char *label,int cmd,bool enabled)
{
TQPopupMenu *pm = static_cast<TQPopupMenu *>(popup.GetID());
if (label[0] != '\0')
{
TQString tr_label = tqApp -> translate("ContextMenu",label);
pm -> insertItem(tr_label,qsb,TQT_SLOT(handlePopUp(int)),0,cmd);
pm -> setItemEnabled(cmd,enabled);
}
else
pm -> insertSeparator();
}
// Claim the selection.
void ScintillaTQt::ClaimSelection()
{
bool isSel = (currentPos != anchor);
if (isSel)
{
TQClipboard *cb = TQApplication::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 -> TQSCN_SELCHANGED(isSel);
}
// Unclaim the selection.
void ScintillaTQt::UnclaimSelection()
{
if (primarySelection)
{
primarySelection = false;
qsb -> txtarea -> update();
}
}
// Implemented to provide compatibility with the Windows version.
sptr_t ScintillaTQt::DirectFunction(ScintillaTQt *sciThis,unsigned int iMessage,
uptr_t wParam,sptr_t lParam)
{
return sciThis -> WndProc(iMessage,wParam,lParam);
}
// Draw the contents of the widget.
void ScintillaTQt::paintEvent(TQPaintEvent *pe)
{
bool isUnicodeMode = (pdoc && pdoc -> dbcsCodePage == SC_CP_UTF8);
paintState = painting;
const TQRect &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)
{
TQPainter 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;
}