1
//============================================================================
3
// File : KviInputEditor.cpp
4
// Creation date : Fri Sep 5 2008 17:26:34 by Elvio Basello
6
// This file is part of the KVIrc irc client distribution
7
// Copyright (C) 2008 Elvio Basello (hellvis69 at netsons dot org)
9
// This program is FREE software. You can redistribute it and/or
10
// modify it under the terms of the GNU General Public License
11
// as published by the Free Software Foundation; either version 2
12
// of the License, or (at your opinion) any later version.
14
// This program is distributed in the HOPE that it will be USEFUL,
15
// but WITHOUT ANY WARRANTY; without even the implied warranty of
16
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
// See the GNU General Public License for more details.
19
// You should have received a copy of the GNU General Public License
20
// along with this program. If not, write to the Free Software Foundation,
21
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
//============================================================================
24
// This file was originally part of KviInput.h
25
//============================================================================
27
#include "KviApplication.h"
28
#include "KviColorSelectionWindow.h"
29
#include "KviConsoleWindow.h"
30
#include "kvi_fileextensions.h"
31
#include "KviMainWindow.h"
33
#include "KviInputEditor.h"
34
#include "KviInputHistory.h"
35
#include "KviIrcView.h"
36
#include "KviKvsScript.h"
37
#include "KviKvsKernel.h"
38
#include "KviLocale.h"
39
#include "KviMdiManager.h"
40
#include "KviControlCodes.h"
41
#include "KviOptions.h"
42
#include "KviPixmapUtils.h"
43
#include "KviQString.h"
45
#include "KviTalPopupMenu.h"
46
#include "KviTextIconWindow.h"
47
#include "KviTextIconManager.h"
48
#include "KviUserInput.h"
49
#include "KviUserListView.h"
50
#include "kvi_shortcuts.h"
51
#include "KviKvsEventTriggers.h"
57
#include <QStyleOption>
60
#include <QFileDialog>
61
#include <QFontMetrics>
63
#include <QDragEnterEvent>
64
#include <QInputContext>
67
// from KviApplication.cpp
68
extern KviTalPopupMenu * g_pInputPopup;
69
extern KviTextIconWindow * g_pTextIconWindow;
70
extern KviColorWindow * g_pColorWindow;
72
#ifdef COMPILE_PSEUDO_TRANSPARENCY
73
extern QPixmap * g_pShadedChildGlobalDesktopBackground;
76
//static members initialization
77
int KviInputEditor::g_iInputInstances = 0;
78
int KviInputEditor::g_iInputFontCharWidth[256];
79
QFontMetrics * KviInputEditor::g_pLastFontMetrics = 0;
81
#define KVI_INPUT_MAX_UNDO_SIZE 256
83
KviInputEditor::KviInputEditor(QWidget * pPar, KviWindow * pWnd, KviUserListView * pView)
86
++KviInputEditor::g_iInputInstances;
87
setObjectName("input_widget");
89
m_pInputParent = pPar;
90
m_iMaxBufferSize = KVI_INPUT_MAX_BUFFER_SIZE;
91
m_iCursorPosition = 0; //Index of the char AFTER the cursor
92
m_iFirstVisibleChar = 0; //Index of the first visible character
93
m_iSelectionBegin = -1; //Index of the first char in the selection
94
m_iSelectionEnd = -1; //Index of the last char in the selection
95
m_bIMComposing = false; //Whether the input method is active (composing).
96
// for input method support
97
m_iIMStart = 0; //Index of the start of the preedit string.
98
m_iIMLength = 0; //Length of the preedit string.
99
m_iIMSelectionBegin = 0; //Index of the start of the selection in preedit string.
100
m_iIMSelectionLength = 0; //Length of the selection in preedit string.
102
m_bCursorOn = false; //Cursor state
103
m_iCursorTimer = 0; //Timer that iverts the cursor state
104
m_iDragTimer = 0; //Timer for drag selection updates
105
m_iLastCursorXPosition = 0; //Calculated in paintEvent
106
m_iSelectionAnchorChar = -1; //Character clicked at the beginning of the selection process
107
m_iCurHistoryIdx = -1; //No data in the history
108
m_bUpdatesEnabled = true;
110
m_pUserListView = pView;
111
m_pHistory = new KviPointerList<QString>;
112
m_pHistory->setAutoDelete(true);
118
setAttribute(Qt::WA_InputMethodEnabled, true);
120
setAutoFillBackground(false);
122
setFocusPolicy(Qt::StrongFocus);
123
setAcceptDrops(true);
125
m_pIconMenu = new KviTalPopupMenu();
126
connect(m_pIconMenu,SIGNAL(activated(int)),this,SLOT(iconPopupActivated(int)));
128
setCursor(Qt::IBeamCursor);
130
setContentsMargins(KVI_INPUT_MARGIN,KVI_INPUT_MARGIN,KVI_INPUT_MARGIN,KVI_INPUT_MARGIN);
131
//set the font and font metrics
137
KviInputEditor::~KviInputEditor()
139
--KviInputEditor::g_iInputInstances;
140
if(KviInputEditor::g_iInputInstances==0 && g_pLastFontMetrics)
142
//last instance, delete shared resources
143
delete g_pLastFontMetrics;
144
g_pLastFontMetrics = 0;
158
killTimer(m_iCursorTimer);
162
void KviInputEditor::applyOptions()
165
QFont newFont(KVI_OPTION_FONT(KviOption_fontInput));
166
newFont.setKerning(false);
169
//then, let font metrics be updated in lazy fashion
170
if(g_pLastFontMetrics)
171
delete g_pLastFontMetrics;
172
g_pLastFontMetrics = 0;
174
//not that lazy, since we force an update :)
178
void KviInputEditor::dragEnterEvent(QDragEnterEvent * e)
180
if(e->mimeData()->hasUrls())
181
e->acceptProposedAction();
184
void KviInputEditor::dropEvent(QDropEvent * e)
187
if(e->mimeData()->hasUrls())
189
list = e->mimeData()->urls();
190
//qDebug("Local files decoded");
193
//qDebug("List not empty");
194
QList<QUrl>::Iterator it = list.begin();
195
for( ; it != list.end(); ++it )
198
QString szPath = url.toLocalFile();
199
if(szPath.endsWith(KVI_FILEEXTENSION_SCRIPT,Qt::CaseInsensitive))
202
KviQString::escapeKvs(&szPath, KviQString::EscapeSpace);
203
szPath.prepend("PARSE ");
205
KviKvsScript::run(szPath,m_pKviWindow);
207
//other file, paste link
216
int KviInputEditor::heightHint() const
218
return sizeHint().height();
221
QSize KviInputEditor::sizeHint() const
224
QFontMetrics *fm = KviInputEditor::getLastFontMetrics(font());
225
int h = qMax(fm->height(), 14) + 2*(KVI_INPUT_MARGIN + KVI_INPUT_PADDING + KVI_INPUT_XTRAPADDING);
226
int w = fm->width(QLatin1Char('x')) * 17 + 2*(KVI_INPUT_MARGIN + KVI_INPUT_PADDING + KVI_INPUT_XTRAPADDING);
228
QStyleOptionFrameV2 option;
229
option.initFrom(this);
230
option.rect = rect();
231
option.lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, this);
232
option.midLineWidth = 0;
234
option.state |= QStyle::State_Sunken;
236
option.state |= QStyle::State_ReadOnly;
237
option.features = QStyleOptionFrameV2::None;
239
return (style()->sizeFromContents(QStyle::CT_LineEdit, &option, QSize(w, h).
240
expandedTo(QApplication::globalStrut()), this));
243
void KviInputEditor::paintEvent(QPaintEvent *)
247
#ifdef COMPILE_PSEUDO_TRANSPARENCY
248
if(KVI_OPTION_BOOL(KviOption_boolUseCompositingForTransparency) && g_pApp->supportsCompositing())
251
p.setCompositionMode(QPainter::CompositionMode_Source);
252
QColor col=KVI_OPTION_COLOR(KviOption_colorGlobalTransparencyFade);
253
col.setAlphaF((float)((float)KVI_OPTION_UINT(KviOption_uintGlobalTransparencyChildFadeFactor) / (float)100));
254
p.fillRect(contentsRect(), col);
256
} else if(g_pShadedChildGlobalDesktopBackground)
258
QPoint pnt = m_pKviWindow->mdiParent() ? mapTo(g_pMainWindow, contentsRect().topLeft() + g_pMainWindow->mdiManager()->scrollBarsOffset()) : mapTo(m_pKviWindow, contentsRect().topLeft());
259
p.drawTiledPixmap(contentsRect(),*(g_pShadedChildGlobalDesktopBackground), pnt);
262
p.fillRect(contentsRect(),KVI_OPTION_COLOR(KviOption_colorInputBackground));
264
QPixmap * pix = KVI_OPTION_PIXMAP(KviOption_pixmapLabelBackground).pixmap();
266
KviPixmapUtils::drawPixmapWithPainter(&p,pix,KVI_OPTION_UINT(KviOption_uintTreeWindowListPixmapAlign),contentsRect(),contentsRect().width(),contentsRect().height());
267
#ifdef COMPILE_PSEUDO_TRANSPARENCY
271
QStyleOptionFrameV2 option;
273
option.initFrom(this);
274
option.rect = rect();
275
option.lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, this);
276
option.midLineWidth = 0;
278
option.state |= QStyle::State_Sunken;
280
option.state |= QStyle::State_ReadOnly;
282
//option.state &= ~(QStyle::State_HasFocus | QStyle::State_Active | QStyle::State_MouseOver); // kill any state that will cause an "active" frame to be painted
283
option.features = QStyleOptionFrameV2::None;
285
style()->drawPrimitive(QStyle::PE_FrameLineEdit, &option, &p, this);
287
QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &option, this);
289
r.setX(r.x() + KVI_INPUT_MARGIN + KVI_INPUT_PADDING);
290
r.setY(r.y() + KVI_INPUT_MARGIN + KVI_INPUT_PADDING);
291
r.setRight(r.right() - KVI_INPUT_MARGIN - KVI_INPUT_PADDING);
292
r.setBottom(r.bottom() - KVI_INPUT_MARGIN - KVI_INPUT_PADDING);
296
p.translate(r.topLeft());
300
void KviInputEditor::drawContents(QPainter * p)
302
QRect rect = p->clipRegion().boundingRect();
303
QFontMetrics * fm = KviInputEditor::getLastFontMetrics(font());
306
int iMaxXPos = rect.width()-1;
307
m_iCurBack = KVI_INPUT_DEF_BACK; //transparent
308
m_iCurFore = KVI_INPUT_DEF_FORE; //normal fore color
310
m_bCurUnderline = false;
312
int iTop = KVI_INPUT_XTRAPADDING;
313
int iBottom = rect.height() - KVI_INPUT_XTRAPADDING;
315
int iTextBaseline = iBottom - fm->descent();
317
runUpToTheFirstVisibleChar();
319
int iCharIdx = m_iFirstVisibleChar;
321
//Control the selection state
322
if((m_iSelectionEnd < m_iSelectionBegin) || (m_iSelectionEnd == -1) || (m_iSelectionBegin == -1))
324
m_iSelectionEnd = -1;
325
m_iSelectionBegin = -1;
328
if((m_iSelectionBegin != -1) && (m_iSelectionEnd >= m_iFirstVisibleChar))
330
int iSelStart = m_iSelectionBegin;
332
if(iSelStart < m_iFirstVisibleChar)
333
iSelStart = m_iFirstVisibleChar;
334
int iXLeft = xPositionFromCharIndex(iSelStart);
335
int iXRight = xPositionFromCharIndex(m_iSelectionEnd + 1);
337
p->fillRect(iXLeft,0,iXRight - iXLeft,rect.height(),KVI_OPTION_COLOR(KviOption_colorInputSelectionBackground));
340
// When m_bIMComposing is true, the text between m_iIMStart and m_iIMStart+m_iIMLength should be highlighted to show that this is the active
341
// preedit area for the input method, and the text outside cannot be edited while
342
// composing. Maybe this can be implemented similarly as painting the selection?
343
// Also notice that inside the preedit, there can also be a selection, given by
344
// m_iSelectionBegin and m_iSelectionLength, and the widget needs to highlight that
345
// while in IM composition mode
346
if(m_bIMComposing && m_iIMLength > 0)
348
int iIMSelectionStart = m_iIMSelectionBegin;
349
if(iIMSelectionStart < m_iFirstVisibleChar)
350
iIMSelectionStart = m_iFirstVisibleChar;
352
int iXIMSelectionLeft = xPositionFromCharIndex(iIMSelectionStart);
353
int iXIMSelectionRight = xPositionFromCharIndex(iIMSelectionStart + m_iIMSelectionLength);
354
p->fillRect(iXIMSelectionLeft,iTop,iXIMSelectionRight - iXIMSelectionLeft, iBottom,KVI_OPTION_COLOR(KviOption_colorInputSelectionBackground));
356
// highlight the IM selection
357
int iIMStart = m_iIMStart;
358
if(m_iIMStart < m_iFirstVisibleChar) m_iIMStart = m_iFirstVisibleChar;
359
int xIMLeft = xPositionFromCharIndex(iIMStart);
360
int xIMRight = xPositionFromCharIndex(iIMStart + m_iIMLength);
362
// underline the IM preedit
363
// Maybe should be put in drawTextBlock, similar to drawing underlined text
364
p->drawLine(xIMLeft, iBottom, xIMRight, iBottom);
367
while((iCharIdx < ((int)(m_szTextBuffer.length()))) && (iCurXPos < iMaxXPos))
369
extractNextBlock(iCharIdx,fm,iCurXPos,iMaxXPos);
373
p->setPen(KVI_OPTION_COLOR(KviOption_colorInputControl));
375
QChar s = getSubstituteChar(m_szTextBuffer[iCharIdx].unicode());
377
// the block width is 4 pixels more than the actual character
379
p->drawText(iCurXPos + 2,iTextBaseline,s);
381
p->drawRect(iCurXPos,iTop,m_iBlockWidth-1,iBottom-1);
383
if(m_iSelectionBegin!=-1)
385
int iBlockEnd = iCharIdx + m_iBlockLen;
386
//block is selected (maybe partially)
387
if( iBlockEnd > m_iSelectionBegin && iCharIdx <= m_iSelectionEnd )
389
int iSubStart,iSubLen;
390
//in common it consists of 3 parts: unselected-selected-unselected
391
//some of thst parts can be empty (for example block is fully selected)
393
//first part start is always equal to the block start
394
iSubStart = iCharIdx;
395
iSubLen = m_iSelectionBegin > iCharIdx ? m_iSelectionBegin-iCharIdx : 0;
399
drawTextBlock(p,iTop,iBottom,iCurXPos,iTextBaseline,iSubStart,iSubLen,FALSE);
400
iCurXPos += m_iBlockWidth;
405
iSubStart += iSubLen;
406
iSubLen = m_iSelectionEnd<iBlockEnd ? m_iSelectionEnd-iSubStart+1 : iBlockEnd-iSubStart;
410
drawTextBlock(p,iTop,iBottom,iCurXPos,iTextBaseline,iSubStart,iSubLen,TRUE);
411
iCurXPos += m_iBlockWidth;
415
if(m_iSelectionEnd<(iBlockEnd-1))
417
iSubStart += iSubLen;
418
iSubLen = iBlockEnd-iSubStart;
419
drawTextBlock(p,iTop,iBottom,iCurXPos,iTextBaseline,iSubStart,iSubLen,FALSE);
422
drawTextBlock(p,iTop,iBottom,iCurXPos,iTextBaseline,iCharIdx,m_iBlockLen);
425
drawTextBlock(p,iTop,iBottom,iCurXPos,iTextBaseline,iCharIdx,m_iBlockLen);
429
iCurXPos += m_iBlockWidth;
430
iCharIdx += m_iBlockLen;
434
m_iLastCursorXPosition = 0;
435
m_iBlockLen = m_iFirstVisibleChar;
437
while(m_iBlockLen < m_iCursorPosition)
439
QChar c = m_szTextBuffer.at(m_iBlockLen);
440
m_iLastCursorXPosition+= (c.unicode() < 256) ? KviInputEditor::g_iInputFontCharWidth[c.unicode()] : fm->width(c);
446
p->setPen(KVI_OPTION_COLOR(KviOption_colorInputCursor));
447
p->drawLine(m_iLastCursorXPosition,iTop,m_iLastCursorXPosition,iBottom);
449
p->setPen(KVI_OPTION_COLOR(KviOption_colorInputForeground));
453
void KviInputEditor::drawTextBlock(QPainter * pa, int iTop, int iBottom, int iCurXPos, int iTextBaseline, int iIdx, int iLen, bool bSelected)
455
QFontMetrics * fm = KviInputEditor::getLastFontMetrics(font());
456
QString szTmp = m_szTextBuffer.mid(iIdx,iLen);
457
m_iBlockWidth = fm->width(szTmp);
459
if(m_iCurFore == KVI_INPUT_DEF_FORE)
461
pa->setPen( bSelected ? KVI_OPTION_COLOR(KviOption_colorInputSelectionForeground) : KVI_OPTION_COLOR(KviOption_colorInputForeground));
463
if(((unsigned char)m_iCurFore) > 16)
465
pa->setPen(KVI_OPTION_COLOR(KviOption_colorInputBackground));
467
pa->setPen(KVI_OPTION_MIRCCOLOR((unsigned char)m_iCurFore));
471
if(m_iCurBack != KVI_INPUT_DEF_BACK)
473
if(((unsigned char)m_iCurBack) > 16)
475
pa->fillRect(iCurXPos,iTop,m_iBlockWidth,iBottom,KVI_OPTION_COLOR(KviOption_colorInputForeground));
477
pa->fillRect(iCurXPos,iTop,m_iBlockWidth,iBottom,KVI_OPTION_MIRCCOLOR((unsigned char)m_iCurBack));
481
pa->drawText(iCurXPos,iTextBaseline,szTmp);
484
pa->drawText(iCurXPos+1,iTextBaseline,szTmp);
486
pa->drawLine(iCurXPos,iTextBaseline + fm->descent(),iCurXPos+m_iBlockWidth,iTextBaseline + fm->descent());
489
QChar KviInputEditor::getSubstituteChar(unsigned short uControlCode)
493
case KviControlCodes::Color:
496
case KviControlCodes::Bold:
499
case KviControlCodes::Reset:
502
case KviControlCodes::Reverse:
505
case KviControlCodes::Underline:
508
case KviControlCodes::CryptEscape:
511
case KviControlCodes::Icon:
515
return QChar(uControlCode);
520
void KviInputEditor::extractNextBlock(int iIdx, QFontMetrics *fm, int iCurXPos, int iMaxXPos)
525
QChar c = m_szTextBuffer[iIdx];
527
if((c.unicode() > 32) ||
528
((c != QChar(KviControlCodes::Color)) &&
529
(c != QChar(KviControlCodes::Bold)) &&
530
(c != QChar(KviControlCodes::Underline)) &&
531
(c != QChar(KviControlCodes::Reset)) &&
532
(c != QChar(KviControlCodes::Reverse)) &&
533
(c != QChar(KviControlCodes::CryptEscape)) &&
534
(c != QChar(KviControlCodes::Icon))))
536
m_bControlBlock = false;
537
//Not a control code...run..
538
while((iIdx < ((int)(m_szTextBuffer.length()))) && (iCurXPos < iMaxXPos))
540
c = m_szTextBuffer[iIdx];
541
if((c.unicode() > 32) ||
542
((c != QChar(KviControlCodes::Color)) &&
543
(c != QChar(KviControlCodes::Bold)) &&
544
(c != QChar(KviControlCodes::Underline)) &&
545
(c != QChar(KviControlCodes::Reset)) &&
546
(c != QChar(KviControlCodes::Reverse)) &&
547
(c != QChar(KviControlCodes::CryptEscape)) &&
548
(c != QChar(KviControlCodes::Icon))))
551
int iXxx = (c.unicode() < 256) ? KviInputEditor::g_iInputFontCharWidth[c.unicode()] : fm->width(c);
552
m_iBlockWidth += iXxx;
559
m_bControlBlock = true;
561
m_iBlockWidth = KviInputEditor::g_iInputFontCharWidth[c.unicode()];
565
case KviControlCodes::Bold:
566
m_bCurBold = ! m_bCurBold;
568
case KviControlCodes::Underline:
569
m_bCurUnderline = ! m_bCurUnderline;
571
case KviControlCodes::Reset:
572
m_iCurFore = KVI_INPUT_DEF_FORE;
573
m_iCurBack = KVI_INPUT_DEF_BACK;
575
m_bCurUnderline = false;
577
case KviControlCodes::Reverse:
579
char cAuxClr = m_iCurFore;
580
m_iCurFore = m_iCurBack;
581
m_iCurBack = cAuxClr;
584
case KviControlCodes::CryptEscape:
585
case KviControlCodes::Icon:
586
// makes a single block
588
case KviControlCodes::Color:
591
if(iIdx >= ((int)(m_szTextBuffer.length())))
596
iIdx = KviControlCodes::getUnicodeColorBytes(m_szTextBuffer,iIdx,&uFore,&uBack);
597
if(uFore != KviControlCodes::NoChange)
600
if(uBack != KviControlCodes::NoChange)
604
m_iCurBack = KVI_INPUT_DEF_BACK;
605
m_iCurFore = KVI_INPUT_DEF_FORE;
617
void KviInputEditor::runUpToTheFirstVisibleChar()
619
register int iIdx = 0;
620
while(iIdx < m_iFirstVisibleChar)
622
unsigned short uChar = m_szTextBuffer[iIdx].unicode();
627
case KviControlCodes::Bold:
628
m_bCurBold = ! m_bCurBold;
630
case KviControlCodes::Underline:
631
m_bCurUnderline = ! m_bCurUnderline;
633
case KviControlCodes::Reset:
634
m_iCurFore = KVI_INPUT_DEF_FORE;
635
m_iCurBack = KVI_INPUT_DEF_BACK;
637
m_bCurUnderline = false;
639
case KviControlCodes::Reverse:
641
char cAuxClr = m_iCurFore;
642
m_iCurFore = m_iCurBack;
643
m_iCurBack = cAuxClr;
646
case KviControlCodes::Color:
649
if(iIdx >= ((int)(m_szTextBuffer.length())))return;
652
iIdx = KviControlCodes::getUnicodeColorBytes(m_szTextBuffer,iIdx,&uFore,&uBack);
654
if(uFore != KviControlCodes::NoChange) m_iCurFore = uFore;
655
else m_iCurFore = KVI_INPUT_DEF_FORE;
656
if(uBack != KviControlCodes::NoChange) m_iCurBack = uBack;
657
else m_iCurBack = KVI_INPUT_DEF_BACK;
661
qDebug("KviInputEditor::Encountered invisible end of the string!");
670
void KviInputEditor::mouseDoubleClickEvent(QMouseEvent * e)
672
//select clicked word
673
if(e->button() & Qt::LeftButton)
675
if(m_szTextBuffer.length()<1)
677
int iCursor = charIndexFromXPosition(e->pos().x());
678
int iLen=m_szTextBuffer.length()-1;
681
if(!m_szTextBuffer.at(iCursor).isLetterOrNumber())
684
m_iSelectionBegin = iCursor;
685
while(m_iSelectionBegin > 0)
687
if(!m_szTextBuffer.at(m_iSelectionBegin-1).isLetterOrNumber())
691
//ensure that the begin of the selection is visible
692
if(m_iFirstVisibleChar>m_iSelectionBegin)
693
m_iFirstVisibleChar=m_iSelectionBegin;
696
m_iSelectionEnd = iCursor;
697
while(m_iSelectionEnd < iLen)
699
if(!m_szTextBuffer.at(m_iSelectionEnd+1).isLetterOrNumber())
703
if(m_iSelectionEnd==((int)(m_szTextBuffer.length())))
705
//all-in-one: move cursor at the end of the selection, ensure it's visible and repaint
706
moveCursorTo(m_iSelectionEnd, true);
712
void KviInputEditor::mousePressEvent(QMouseEvent * e)
714
if(e->button() & Qt::LeftButton)
716
m_iCursorPosition = charIndexFromXPosition(e->pos().x());
718
int iAnchorX = xPositionFromCharIndex(m_iCursorPosition);
719
if(iAnchorX > width()) m_iFirstVisibleChar++;
720
m_iSelectionAnchorChar = m_iCursorPosition;
722
//grabMouse(QCursor(crossCursor));
723
repaintWithCursorOn();
725
m_iDragTimer = startTimer(KVI_INPUT_DRAG_TIMEOUT);
727
} else if(e->button() & Qt::RightButton)
729
int iType = g_pActiveWindow->type();
732
g_pInputPopup->clear();
736
QClipboard * pClip = QApplication::clipboard();
739
szClip = pClip->text(QClipboard::Clipboard);
741
int iOcc = szClip.count(QChar('\n'));
743
if(!szClip.isEmpty())
745
if(szClip.length() > 60)
748
szClip.append("...");
750
szClip.replace(QChar('&'),"&");
751
szClip.replace(QChar('<'),"<");
752
szClip.replace(QChar('>'),">");
753
szClip.replace(QChar('\n'),"<br>");
755
QString szLabel = "<center><b>";
756
szLabel += __tr2qs("Clipboard");
757
szLabel += ":</b><br>";
759
szLabel += "<br><b>";
765
szLabel += QChar(' ');
766
szLabel += (iOcc == 1) ? __tr2qs("line break") : __tr2qs("line breaks");
767
szLabel += "</b></center>";
769
QLabel * pLabel = new QLabel(szLabel,g_pInputPopup);
770
pLabel->setFrameStyle(QFrame::Raised | QFrame::StyledPanel);
771
pLabel->setMargin(5);
777
int iId = g_pInputPopup->insertItem(__tr2qs("&Undo") + ACCEL_KEY(Z),this,SLOT(undo()));
778
g_pInputPopup->setItemEnabled(iId,isUndoAvailable());
779
iId = g_pInputPopup->insertItem(__tr2qs("&Redo") + ACCEL_KEY(Y),this,SLOT(redo()));
780
g_pInputPopup->setItemEnabled(iId,isRedoAvailable());
781
iId = g_pInputPopup->insertItem(__tr2qs("Cu&t") + ACCEL_KEY(X),this,SLOT(cut()));
782
g_pInputPopup->setItemEnabled(iId,hasSelection());
783
iId = g_pInputPopup->insertItem(__tr2qs("&Copy") + ACCEL_KEY(C),this,SLOT(copyToClipboard()));
784
g_pInputPopup->setItemEnabled(iId,hasSelection());
785
iId = g_pInputPopup->insertItem(__tr2qs("&Paste") + ACCEL_KEY(V),this,SLOT(pasteClipboardWithConfirmation()));
786
g_pInputPopup->setItemEnabled(iId,!szClip.isEmpty() && !m_bReadOnly);
787
iId = g_pInputPopup->insertItem(__tr2qs("Paste (Slowly)"),this,SLOT(pasteSlow()));
788
if ((iType == KviWindow::Channel) || (iType == KviWindow::Query) || (iType == KviWindow::DccChat))
789
g_pInputPopup->setItemEnabled(iId,!szClip.isEmpty() && !m_bReadOnly);
791
g_pInputPopup->setItemEnabled(iId,false);
792
iId = g_pInputPopup->insertItem(__tr2qs("Paste &File") + ACCEL_KEY(L),this,SLOT(pasteFile()));
793
if ((iType != KviWindow::Channel) && (iType != KviWindow::Query) && (iType != KviWindow::DccChat))
794
g_pInputPopup->setItemEnabled(iId,false);
796
g_pInputPopup->setItemEnabled(iId,!m_bReadOnly);
797
if(m_bSpSlowFlag ==true)
799
iId = g_pInputPopup->insertItem(__tr2qs("Stop Paste"),this,SLOT(stopPasteSlow())); /*G&N 2005*/
801
iId = g_pInputPopup->insertItem(__tr2qs("Clear"),this,SLOT(clear()));
802
g_pInputPopup->setItemEnabled(iId,!m_szTextBuffer.isEmpty() && !m_bReadOnly);
803
g_pInputPopup->insertSeparator();
804
iId = g_pInputPopup->insertItem(__tr2qs("Select All"),this,SLOT(selectAll()));
805
g_pInputPopup->setItemEnabled(iId,(!m_szTextBuffer.isEmpty()));
807
g_pInputPopup->insertSeparator();
808
m_pIconMenu->clear();
810
KviPointerHashTable<QString,KviTextIcon> * d = g_pTextIconManager->textIconDict();
811
KviPointerHashTableIterator<QString,KviTextIcon> it(*d);
816
szList.append(it.currentKey());
824
for(QStringList::Iterator iter = szList.begin(); iter != szList.end(); ++iter)
826
pIcon = g_pTextIconManager->lookupTextIcon(*iter);
829
pPix = pIcon->pixmap();
830
if(pPix) m_pIconMenu->insertItem(*pPix,*iter);
834
g_pInputPopup->insertItem(*(g_pIconManager->getSmallIcon(KviIconManager::BigGrin)),__tr2qs("Insert Icon"),m_pIconMenu);
836
QInputContext *qic = g_pApp->inputContext();
838
QList<QAction *> imActions = qic->actions();
839
for (int i = 0; i < imActions.size(); ++i)
840
g_pInputPopup->addAction(imActions.at(i));
843
g_pInputPopup->popup(mapToGlobal(e->pos()));
845
pasteSelectionWithConfirmation();
849
void KviInputEditor::iconPopupActivated(int iId)
853
QString szText = m_pIconMenu->text(iId);
854
if(!szText.isEmpty())
856
szText.prepend(KviControlCodes::Icon);
863
bool KviInputEditor::hasSelection()
865
return ((m_iSelectionBegin != -1) && (m_iSelectionEnd != -1));
868
void KviInputEditor::copyToClipboard()
870
if(!hasSelection()) return;
871
QClipboard * pClip = QApplication::clipboard();
873
QString szTxt = m_szTextBuffer.mid(m_iSelectionBegin,(m_iSelectionEnd-m_iSelectionBegin)+1);
874
pClip->setText(szTxt,QClipboard::Clipboard);
875
repaintWithCursorOn();
878
void KviInputEditor::copyToSelection(bool bDonNotCopyToClipboard)
880
if(!hasSelection()) return;
881
QClipboard * pClip = QApplication::clipboard();
883
QString szTxt = m_szTextBuffer.mid(m_iSelectionBegin,(m_iSelectionEnd-m_iSelectionBegin)+1);
884
if(pClip->supportsSelection())
885
pClip->setText(szTxt,QClipboard::Selection);
886
else if(!bDonNotCopyToClipboard)
887
pClip->setText(szTxt,QClipboard::Clipboard);
888
repaintWithCursorOn();
891
void KviInputEditor::moveCursorTo(int iIdx, bool bRepaint)
893
if(iIdx < 0) iIdx = 0;
894
if(iIdx > ((int)(m_szTextBuffer.length()))) iIdx = m_szTextBuffer.length();
895
if(iIdx > m_iCursorPosition)
897
while(m_iCursorPosition < iIdx)
899
moveRightFirstVisibleCharToShowCursor();
903
m_iCursorPosition = iIdx;
904
if(m_iFirstVisibleChar > m_iCursorPosition)m_iFirstVisibleChar = m_iCursorPosition;
907
repaintWithCursorOn();
910
void KviInputEditor::removeSelected()
915
addUndo(new EditCommand(EditCommand::RemoveText,m_szTextBuffer.mid(m_iSelectionBegin, m_iSelectionEnd-m_iSelectionBegin+1),m_iSelectionBegin));
917
m_szTextBuffer.remove(m_iSelectionBegin,(m_iSelectionEnd-m_iSelectionBegin)+1);
918
moveCursorTo(m_iSelectionBegin,false);
920
repaintWithCursorOn();
923
void KviInputEditor::cut()
927
QClipboard * pClip = QApplication::clipboard();
930
pClip->setText(m_szTextBuffer.mid(m_iSelectionBegin,(m_iSelectionEnd-m_iSelectionBegin)+1),QClipboard::Clipboard);
932
addUndo(new EditCommand(EditCommand::RemoveText,m_szTextBuffer.mid(m_iSelectionBegin, m_iSelectionEnd-m_iSelectionBegin+1),m_iSelectionBegin));
934
m_szTextBuffer.remove(m_iSelectionBegin,(m_iSelectionEnd-m_iSelectionBegin)+1);
935
moveCursorTo(m_iSelectionBegin,false);
937
repaintWithCursorOn();
940
void KviInputEditor::insertText(const QString & szTxt)
942
QString szText = szTxt; // crop away constness
943
if(szText.isEmpty())return;
945
szText.replace('\t',QString(KVI_OPTION_UINT(KviOption_uintSpacesToExpandTabulationInput),' ')); //expand tabs to spaces
947
m_bUpdatesEnabled = false;
949
m_bUpdatesEnabled = true;
951
if(szText.indexOf('\n') == -1)
953
addUndo(new EditCommand(EditCommand::InsertText,szText,m_iCursorPosition));
955
m_szTextBuffer.insert(m_iCursorPosition,szText);
956
m_szTextBuffer.truncate(m_iMaxBufferSize);
957
moveCursorTo(m_iCursorPosition + szText.length());
959
//Multiline paste...do not execute commands here
961
while(!szText.isEmpty())
963
int iIdx = szText.indexOf('\n');
966
szBlock = szText.left(iIdx);
967
//else szBlock = QChar(KviControlCodes::Reset);
968
szText.remove(0,iIdx+1);
974
m_szTextBuffer.insert(m_iCursorPosition,szBlock);
975
m_szTextBuffer.truncate(m_iMaxBufferSize);
978
while((iPos < ((int)(m_szTextBuffer.length()))) && (m_szTextBuffer[iPos] < 33)) iPos++;
979
if((iPos < ((int)(m_szTextBuffer.length()))) && (m_szTextBuffer[iPos] == QChar('/')))m_szTextBuffer.insert(iPos,"\\");
981
returnPressed(iIdx != -1);
986
int KviInputEditor::replaceSegment(int iStart, int iLength, const QString & szText)
988
addUndo(new EditCommand(EditCommand::InsertText,m_szTextBuffer.mid(iStart,iLength),iStart));
989
m_szTextBuffer.remove(iStart, iLength);
990
addUndo(new EditCommand(EditCommand::InsertText,szText,iStart));
991
m_szTextBuffer.insert(iStart, szText);
992
m_szTextBuffer.truncate(m_iMaxBufferSize);
993
repaintWithCursorOn();
995
int iInsertedLength = szText.length();
996
int iMaxInsertedLength = m_iMaxBufferSize - iStart;
997
if(iInsertedLength > iMaxInsertedLength) return iMaxInsertedLength;
998
return iInsertedLength;
1001
void KviInputEditor::pasteClipboardWithConfirmation()
1003
QClipboard * pClip = QApplication::clipboard();
1005
QString szText = pClip->text(QClipboard::Clipboard);
1007
if(KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnInputBarPaste,m_pKviWindow,m_pKviWindow->id(),szText))
1010
if(szText.contains(QChar('\n')) > 0)
1012
if(m_pInputParent->inherits("KviInput"))
1013
((KviInput*)(m_pInputParent))->multiLinePaste(szText);
1019
void KviInputEditor::pasteSelectionWithConfirmation()
1021
QClipboard * pClip = QApplication::clipboard();
1023
QString szText = pClip->text(pClip->supportsSelection() ? QClipboard::Selection : QClipboard::Clipboard);
1025
if(KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnInputBarPaste,m_pKviWindow,m_pKviWindow->id(),szText))
1028
if(szText.contains(QChar('\n')) > 0)
1030
if(m_pInputParent->inherits("KviInput"))
1031
((KviInput*)(m_pInputParent))->multiLinePaste(szText);
1037
void KviInputEditor::pasteSlow()
1039
KviKvsScript::run("spaste.clipboard",g_pActiveWindow);
1040
m_bSpSlowFlag = true;
1043
void KviInputEditor::stopPasteSlow()
1045
KviKvsScript::run("spaste.stop",g_pActiveWindow);
1046
m_bSpSlowFlag = false;
1049
void KviInputEditor::pasteFile()
1051
QString szTmp = QFileDialog::getOpenFileName(this,"Choose a file","","");
1052
if(!szTmp.isEmpty())
1054
KviQString::escapeKvs(&szTmp, KviQString::EscapeSpace);
1055
szTmp.prepend("spaste.file ");
1056
KviKvsScript::run(szTmp, g_pActiveWindow);
1057
m_bSpSlowFlag = true;
1061
void KviInputEditor::selectAll()
1063
if(m_szTextBuffer.length() > 0)
1065
m_iSelectionBegin = 0;
1066
m_iSelectionEnd = m_szTextBuffer.length()-1;
1071
void KviInputEditor::clear()
1073
addUndo(new EditCommand(EditCommand::RemoveText,m_szTextBuffer,0));
1074
m_szTextBuffer = "";
1079
void KviInputEditor::setText(const QString szText)
1081
addUndo(new EditCommand(EditCommand::RemoveText,m_szTextBuffer,0));
1082
addUndo(new EditCommand(EditCommand::RemoveText,szText,0));
1083
m_szTextBuffer = szText;
1084
m_szTextBuffer.truncate(m_iMaxBufferSize);
1089
void KviInputEditor::mouseReleaseEvent(QMouseEvent *)
1093
m_iSelectionAnchorChar =-1;
1097
if(hasSelection()) copyToSelection();
1100
void KviInputEditor::killDragTimer()
1104
killTimer(m_iDragTimer);
1109
void KviInputEditor::timerEvent(QTimerEvent * e)
1111
if(e->timerId() == m_iCursorTimer)
1113
if(!hasFocus() || !isVisible())
1115
killTimer(m_iCursorTimer);
1117
m_bCursorOn = false;
1118
} else m_bCursorOn = ! m_bCursorOn;
1122
handleDragSelection();
1126
void KviInputEditor::handleDragSelection()
1128
if(m_iSelectionAnchorChar == -1)
1131
if(m_iSelectionAnchorChar > m_szTextBuffer.length()) // may happen if hitting backspace or del while dragging
1132
m_iSelectionAnchorChar = m_szTextBuffer.length();
1134
QPoint pnt = mapFromGlobal(QCursor::pos());
1138
//Left side dragging
1139
if(m_iFirstVisibleChar > 0)
1140
m_iFirstVisibleChar--;
1141
m_iCursorPosition = m_iFirstVisibleChar;
1142
} else if(pnt.x() >= width()) {
1143
//Right side dragging...add a single character to the selection on the right
1144
if(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
1146
moveRightFirstVisibleCharToShowCursor();
1147
m_iCursorPosition++;
1148
} //else at the end of the selection...don't move anything
1150
//Inside the window...
1151
m_iCursorPosition = charIndexFromXPosition(pnt.x());
1154
if(m_iCursorPosition == m_iSelectionAnchorChar) selectOneChar(-1);
1156
if(m_iCursorPosition > m_iSelectionAnchorChar)
1158
m_iSelectionBegin = m_iSelectionAnchorChar;
1159
m_iSelectionEnd = m_iCursorPosition-1;
1161
m_iSelectionBegin = m_iCursorPosition;
1162
m_iSelectionEnd = m_iSelectionAnchorChar-1;
1165
repaintWithCursorOn();
1168
void KviInputEditor::returnPressed(bool)
1170
if (!m_szTextBuffer.isEmpty() /* && (!m_pHistory->current() || m_szTextBuffer.compare(*(m_pHistory->current())))*/)
1172
if(m_pInputParent->inherits("KviInput"))
1173
KviInputHistory::instance()->add(new QString(m_szTextBuffer));
1175
m_pHistory->insert(0,new QString(m_szTextBuffer));
1178
//ensure the color window is hidden (bug #835)
1180
if(g_pColorWindow->isVisible())
1181
g_pColorWindow->hide();
1183
KVI_ASSERT(KVI_INPUT_MAX_LOCAL_HISTORY_ENTRIES > 1); //ABSOLUTELY NEEDED, if not, pHist will be destroyed...
1184
if(m_pHistory->count() > KVI_INPUT_MAX_LOCAL_HISTORY_ENTRIES)
1185
m_pHistory->removeLast();
1187
m_iCurHistoryIdx = -1;
1189
emit enterPressed();
1192
void KviInputEditor::clearUndoStack()
1196
delete m_pUndoStack;
1197
m_pUndoStack = NULL;
1202
delete m_pRedoStack;
1203
m_pRedoStack = NULL;
1207
void KviInputEditor::focusInEvent(QFocusEvent *)
1209
if(m_iCursorTimer==0)
1211
m_iCursorTimer = startTimer(KVI_INPUT_BLINK_TIME);
1217
void KviInputEditor::focusOutEvent(QFocusEvent *)
1219
if(m_iCursorTimer) killTimer(m_iCursorTimer);
1221
m_bCursorOn = false;
1225
void KviInputEditor::internalCursorRight(bool bShift)
1227
if(m_iCursorPosition >= ((int)(m_szTextBuffer.length()))) return;
1228
moveRightFirstVisibleCharToShowCursor();
1229
//Grow the selection if needed
1232
if((m_iSelectionBegin > -1)&&(m_iSelectionEnd > -1))
1234
if(m_iSelectionEnd == m_iCursorPosition-1)m_iSelectionEnd++;
1235
else if(m_iSelectionBegin == m_iCursorPosition)m_iSelectionBegin++;
1236
else selectOneChar(m_iCursorPosition);
1237
} else selectOneChar(m_iCursorPosition);
1238
} else selectOneChar(-1);
1239
m_iCursorPosition++;
1242
void KviInputEditor::internalCursorLeft(bool bShift)
1244
if(m_iCursorPosition <= 0) return;
1248
if((m_iSelectionBegin > -1) && (m_iSelectionEnd > -1))
1250
if(m_iSelectionBegin == m_iCursorPosition)
1251
m_iSelectionBegin--;
1252
else if(m_iSelectionEnd == m_iCursorPosition-1)
1254
else selectOneChar(m_iCursorPosition - 1);
1255
} else selectOneChar(m_iCursorPosition - 1);
1256
} else selectOneChar(-1);
1258
m_iCursorPosition--;
1259
if(m_iFirstVisibleChar > m_iCursorPosition) m_iFirstVisibleChar--;
1262
void KviInputEditor::inputMethodEvent(QInputMethodEvent * e)
1272
m_iIMStart = m_iIMSelectionBegin = m_iCursorPosition;
1274
m_bIMComposing = true;
1277
m_bUpdatesEnabled = false;
1279
m_iIMLength = replaceSegment(m_iIMStart, m_iIMLength, e->commitString());
1281
// update selection inside the pre-edit
1282
m_iIMSelectionBegin = m_iIMStart + e->replacementStart();
1283
m_iIMSelectionLength = e->replacementLength();
1284
moveCursorTo(m_iIMSelectionBegin);
1286
if (e->commitString().isEmpty())
1288
if(e->preeditString().isEmpty())
1290
m_bIMComposing = false;
1294
// replace the preedit area with the IM result text
1295
m_iIMLength = replaceSegment(m_iIMStart, m_iIMLength, e->preeditString());
1296
// move cursor to after the IM result text
1297
moveCursorTo(m_iIMStart + m_iIMLength);
1300
// replace the preedit area with the IM result text
1301
m_iIMLength = replaceSegment(m_iIMStart, m_iIMLength, e->commitString());
1302
// move cursor to after the IM result text
1303
moveCursorTo(m_iIMStart + m_iIMLength);
1305
m_bIMComposing = false;
1311
m_bUpdatesEnabled = true;
1313
repaintWithCursorOn();
1316
void KviInputEditor::installShortcuts()
1318
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_HISTORY),this,SLOT(openHistory()),0,Qt::WidgetShortcut);
1319
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_HISTORY_PREV),this,SLOT(historyPrev()),0,Qt::WidgetShortcut);
1320
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_HISTORY_NEXT),this,SLOT(historyNext()),0,Qt::WidgetShortcut);
1321
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_PREV_CHAR),this,SLOT(previousChar()),0,Qt::WidgetShortcut);
1322
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_NEXT_CHAR),this,SLOT(nextChar()),0,Qt::WidgetShortcut);
1323
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_PREV_CHAR_SELECT),this,SLOT(previousCharSelection()),0,Qt::WidgetShortcut);
1324
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_NEXT_CHAR_SELECT),this,SLOT(nextCharSelection()),0,Qt::WidgetShortcut);
1325
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_PREV_WORD),this,SLOT(previousWord()),0,Qt::WidgetShortcut);
1326
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_NEXT_WORD),this,SLOT(nextWord()),0,Qt::WidgetShortcut);
1327
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_PREV_WORD_SELECT),this,SLOT(previousWordSelection()),0,Qt::WidgetShortcut);
1328
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_NEXT_WORD_SELECT),this,SLOT(nextWordSelection()),0,Qt::WidgetShortcut);
1329
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_BOLD),this,SLOT(insertBold()),0,Qt::WidgetShortcut);
1330
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_RESET),this,SLOT(insertReset()),0,Qt::WidgetShortcut);
1331
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_UNDERLINE),this,SLOT(insertUnderline()),0,Qt::WidgetShortcut);
1332
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_REVERSE),this,SLOT(insertReverse()),0,Qt::WidgetShortcut);
1333
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_PLAINTEXT),this,SLOT(insertPlainText()),0,Qt::WidgetShortcut);
1334
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_ICON),this,SLOT(insertIcon()),0,Qt::WidgetShortcut);
1335
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_COLOR),this,SLOT(insertColor()),0,Qt::WidgetShortcut);
1336
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_COPY),this,SLOT(copyInternal()),0,Qt::WidgetShortcut);
1337
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_CUT),this,SLOT(cutInternal()),0,Qt::WidgetShortcut);
1338
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_PASTE),this,SLOT(pasteInternal()),0,Qt::WidgetShortcut);
1339
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_PASTE_2),this,SLOT(pasteInternal()),0,Qt::WidgetShortcut);
1340
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_UNDO),this,SLOT(undoInternal()),0,Qt::WidgetShortcut);
1341
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_REDO),this,SLOT(redoInternal()),0,Qt::WidgetShortcut);
1342
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_SELECT_ALL),this,SLOT(selectAllInternal()),0,Qt::WidgetShortcut);
1343
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_DELETE_WORD),this,SLOT(deleteWord()),0,Qt::WidgetShortcut);
1344
new QShortcut(QKeySequence(KVI_SHORTCUTS_WIN_PREV_LINE),this,SLOT(previousLine()),0,Qt::WidgetShortcut);
1345
new QShortcut(QKeySequence(KVI_SHORTCUTS_WIN_NEXT_LINE),this,SLOT(nextLine()),0,Qt::WidgetShortcut);
1346
new QShortcut(QKeySequence(KVI_SHORTCUTS_WIN_PREV_PAGE),this,SLOT(previousPage()),0,Qt::WidgetShortcut);
1347
new QShortcut(QKeySequence(KVI_SHORTCUTS_WIN_NEXT_PAGE),this,SLOT(nextPage()),0,Qt::WidgetShortcut);
1348
new QShortcut(QKeySequence(KVI_SHORTCUTS_WIN_SEARCH),this,SLOT(search()),0,Qt::WidgetShortcut);
1349
new QShortcut(QKeySequence(KVI_SHORTCUTS_WIN_SCROLL_TO_LAST_READ_LINE),this,SLOT(scrollToLastReadLine()),0,Qt::WidgetShortcut);
1350
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_SEND_PLAIN),this,SLOT(sendPlain()),0,Qt::WidgetShortcut);
1351
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_SEND_PLAIN_2),this,SLOT(sendPlain()),0,Qt::WidgetShortcut);
1352
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_HOME),this,SLOT(homeInternal()),0,Qt::WidgetShortcut);
1353
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_END),this,SLOT(endInternal()),0,Qt::WidgetShortcut);
1354
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_HOME_SELECT),this,SLOT(homeInternalSelection()),0,Qt::WidgetShortcut);
1355
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_END_SELECT),this,SLOT(endInternalSelection()),0,Qt::WidgetShortcut);
1356
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_RETURN),this,SLOT(returnHit()),0,Qt::WidgetShortcut);
1357
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_RETURN_2),this,SLOT(returnHit()),0,Qt::WidgetShortcut);
1358
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_RETURN_3),this,SLOT(returnHit()),0,Qt::WidgetShortcut);
1359
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_RETURN_4),this,SLOT(returnHit()),0,Qt::WidgetShortcut);
1360
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_BACKSPACE),this,SLOT(backspaceHit()),0,Qt::WidgetShortcut);
1361
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_BACKSPACE_2),this,SLOT(backspaceHit()),0,Qt::WidgetShortcut);
1362
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_DELETE),this,SLOT(deleteHit()),0,Qt::WidgetShortcut);
1363
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_ESCAPE),this,SLOT(escapeHit()),0,Qt::WidgetShortcut);
1364
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_COMMANDLINE),this,SLOT(toggleCommandMode()),0,Qt::WidgetShortcut);
1365
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_DUMMY),this,SLOT(dummy()),0,Qt::WidgetShortcut);
1366
new QShortcut(QKeySequence(KVI_SHORTCUTS_INPUT_DUMMY_2),this,SLOT(dummy()),0,Qt::WidgetShortcut);
1367
new QShortcut(QKeySequence(KVI_SHORTCUTS_WIN_ZOOM_IN),this,SLOT(zoomIn()),0,Qt::WidgetShortcut);
1368
new QShortcut(QKeySequence(KVI_SHORTCUTS_WIN_ZOOM_OUT),this,SLOT(zoomOut()),0,Qt::WidgetShortcut);
1369
// this is currently ambigous, since we're using it for scripting, too
1370
new QShortcut(QKeySequence(KVI_SHORTCUTS_WIN_ZOOM_DEFAULT),this,SLOT(zoomDefault()),SLOT(zoomDefault()),Qt::WidgetShortcut);
1373
void KviInputEditor::zoomIn()
1376
if(m_pKviWindow->view())
1377
m_pKviWindow->view()->increaseFontSize();
1380
void KviInputEditor::zoomOut()
1383
if(m_pKviWindow->view())
1384
m_pKviWindow->view()->decreaseFontSize();
1387
void KviInputEditor::zoomDefault()
1390
if(m_pKviWindow->view())
1391
m_pKviWindow->view()->resetDefaultFont();
1394
void KviInputEditor::keyPressEvent(QKeyEvent * e)
1397
// disable the keyPress handling when IM is in composition.
1403
// completion thingies
1407
if((e->key() == Qt::Key_Tab) || (e->key() == Qt::Key_Backtab))
1409
completion(e->modifiers() & Qt::ShiftModifier);
1412
m_bLastCompletionFinished=1;
1416
if(e->modifiers() & Qt::ControlModifier)
1422
//avoid Ctrl+J from inserting a linefeed
1426
if(!m_bReadOnly) insertText(e->text());
1431
#if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
1432
if((e->modifiers() & Qt::AltModifier) && (e->modifiers() & Qt::KeypadModifier))
1434
// Qt::Key_Meta seems to substitute Qt::Key_Alt on some keyboards
1435
if((e->key() == Qt::Key_Alt) || (e->key() == Qt::Key_Meta))
1437
m_szAltKeyCode = "";
1439
} else if((e->text().unicode()->toLatin1() >= '0') && (e->text().unicode()->toLatin1() <= '9')) {
1440
m_szAltKeyCode += e->text().unicode()->toLatin1();
1442
} else if((e->key() >= Qt::Key_0) && (e->key() <= Qt::Key_9)) {
1443
m_szAltKeyCode += e->key();
1448
insertText(e->text());
1453
if(!e->text().isEmpty() && !m_bReadOnly)
1454
insertText(e->text());
1457
void KviInputEditor::keyReleaseEvent(QKeyEvent * e)
1459
#if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
1460
if((e->key() == Qt::Key_Alt) || (e->key() == Qt::Key_Meta))
1462
if(m_szAltKeyCode.hasData())
1465
unsigned short uCh = m_szAltKeyCode.toUShort(&bOk);
1468
//qDebug("INSERTING CHAR %c",uCh);
1469
insertChar(QChar(uCh));
1473
m_szAltKeyCode = "";
1480
void KviInputEditor::getWordBeforeCursor(QString & szBuffer, bool * bIsFirstWordInLine)
1482
if(m_szTextBuffer.isEmpty() || m_iCursorPosition <= 0)
1488
szBuffer = m_szTextBuffer.left(m_iCursorPosition);
1490
int iIdx = szBuffer.lastIndexOf(' ');
1491
int iIdx2 = szBuffer.lastIndexOf(','); // This is for comma separated lists...
1492
int iIdx3 = szBuffer.lastIndexOf('(');
1493
int iIdx4 = szBuffer.lastIndexOf('"');
1494
if(iIdx2 > iIdx) iIdx = iIdx2;
1495
if(iIdx3 > iIdx) iIdx = iIdx3;
1496
if(iIdx4 > iIdx) iIdx = iIdx4;
1497
*bIsFirstWordInLine = false;
1498
if(iIdx > -1) szBuffer.remove(0,iIdx+1);
1499
else *bIsFirstWordInLine = true;
1502
void KviInputEditor::completionEscapeUnsafeToken(QString &szToken)
1504
if(!((KviInput *)(m_pInputParent))->isUserFriendly())
1505
KviQString::escapeKvs(&szToken, KviQString::EscapeSpace);
1508
void KviInputEditor::completion(bool bShift)
1510
// FIXME: Spaces in directory completion can mess everything completely
1511
// On windows the characters are breaking everything...
1516
bool bFirstWordInLine;
1518
bool bInCommand = m_szTextBuffer.trimmed().indexOf('/') == 0;
1520
getWordBeforeCursor(szWord,&bFirstWordInLine);
1521
if(szWord.isEmpty())
1523
if(m_szLastCompletedNick.isEmpty())
1524
return; // nothing to complete
1526
// this is standard nick completion continued
1527
standardNickCompletion(bShift,szWord,bFirstWordInLine,bInCommand);
1528
repaintWithCursorOn();
1532
if(KviQString::equalCI(m_szTextBuffer.left(5),"/help") || KviQString::equalCI(m_szTextBuffer.left(5),"/help.open")) iOffset=1;
1535
KviPointerList<QString> tmp;
1536
tmp.setAutoDelete(true);
1538
bool bIsCommand = false;
1539
bool bIsFunction = false;
1540
bool bIsDir = false;
1541
bool bIsNick = false;
1543
unsigned short uc = szWord[0].unicode();
1546
if(uc == '/' || iOffset)
1548
if(szWord[1-iOffset].unicode()=='$')
1550
// function/identifer completion
1551
szWord.remove(0,2-iOffset);
1552
if(szWord.isEmpty()) return;
1553
KviKvsKernel::instance()->completeFunction(szWord,&tmp);
1554
// function names don't need to be escaped
1557
else if(bFirstWordInLine || iOffset)
1559
// command completion
1560
szWord.remove(0,1-iOffset);
1561
if(szWord.isEmpty())return;
1562
KviKvsKernel::instance()->completeCommand(szWord,&tmp);
1563
// commands don't need to be escaped
1566
// directory completion attempt
1567
g_pApp->completeDirectory(szWord,&tmp);
1570
} else if(uc == '$')
1572
// function/identifer completion
1574
if(szWord.isEmpty()) return;
1575
KviKvsKernel::instance()->completeFunction(szWord,&tmp);
1577
} else if(uc == '#' || uc == '&' || uc == '!')
1581
if( (szWord.length()==1) && (m_pKviWindow->windowName()[0].unicode()==uc))
1583
szMatch=m_pKviWindow->windowName();
1584
completionEscapeUnsafeToken(szMatch);
1585
szMatch.append(" ");
1586
replaceWordBeforeCursor(szWord,szMatch,false);
1587
repaintWithCursorOn();
1590
if(m_pKviWindow->console())
1591
m_pKviWindow->console()->completeChannel(szWord,&tmp);
1594
//FIXME: Complete also on irc:// starting strings, not only irc.?
1595
} else if(KviQString::equalCIN(szWord,"irc.",4))
1599
if(m_pKviWindow->console())
1600
m_pKviWindow->console()->completeServer(szWord,&tmp);
1602
// empty word will end up here
1605
if(KVI_OPTION_BOOL(KviOption_boolZshLikeNickCompletion))
1607
if(m_szLastCompletedNick.isEmpty())
1609
//first round of zsh completion
1610
m_pUserListView->completeNickBashLike(szWord,&tmp,bShift);
1612
m_szLastCompletedNick=szWord;
1614
standardNickCompletion(bShift,szWord,bFirstWordInLine,bInCommand);
1615
repaintWithCursorOn();
1618
} else if(KVI_OPTION_BOOL(KviOption_boolBashLikeNickCompletion))
1620
m_pUserListView->completeNickBashLike(szWord,&tmp,bShift);
1623
standardNickCompletion(bShift,szWord,bFirstWordInLine,bInCommand);
1624
repaintWithCursorOn();
1630
// Lookup the longest exact match
1633
if(tmp.count() == 1)
1635
szMatch = *(tmp.first());
1636
if (szMatch.left(1)=='$')szMatch.remove(0,1);
1637
if(bIsCommand && szMatch.right(1)!='.')szMatch.append(' ');
1638
else if(bIsFunction && szMatch.right(1)!='.')szMatch.append('(');
1641
if(!KVI_OPTION_STRING(KviOption_stringNickCompletionPostfix).isEmpty())
1643
if(bFirstWordInLine || (!KVI_OPTION_BOOL(KviOption_boolUseNickCompletionPostfixForFirstWordOnly)))
1644
szMatch.append(KVI_OPTION_STRING(KviOption_stringNickCompletionPostfix));
1648
if(bInCommand && !bIsCommand)
1650
// escape crazy things like Nick\nquit
1651
completionEscapeUnsafeToken(szMatch);
1655
QString * szTmp = tmp.first();
1657
int iWLen = szWord.length();
1658
if (szMatch.left(1)=='$')szMatch.remove(0,1);
1659
for(; szTmp; szTmp = tmp.next())
1661
if(szTmp->length() < szMatch.length())
1662
szMatch.remove(szTmp->length(),szMatch.length() - szTmp->length());
1663
// All the matches here have length >= word.len()!!!
1664
const QChar * b1 = (*szTmp).constData() + iWLen;
1665
const QChar * b2 = szMatch.constData() + iWLen;
1666
const QChar * c1 = b1;
1667
const QChar * c2 = b2;
1668
if(bIsDir)while(c1->unicode() && (c1->unicode() == c2->unicode()))c1++,c2++;
1669
else while(c1->unicode() && (c1->toLower().unicode() == c2->toLower().unicode()))c1++,c2++;
1670
int iLen = iWLen + (c1 - b1);
1671
if(iLen < ((int)(szMatch.length())))szMatch.remove(iLen,szMatch.length() - iLen);
1672
if(!szAll.isEmpty())szAll.append(", ");
1673
szAll.append(*szTmp);
1676
m_pKviWindow->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("%d matches: %Q"),tmp.count(),&szAll);
1680
m_pKviWindow->outputNoFmt(KVI_OUT_SYSTEMMESSAGE,__tr2qs("No matches"));
1682
if(!szMatch.isEmpty())
1684
//if(!bIsDir && !bIsNick)match = match.toLower(); <-- why? It is nice to have
1685
// $module.someFunctionName instad
1686
// of unreadable $module.somefunctionfame
1687
replaceWordBeforeCursor(szWord,szMatch,false);
1690
repaintWithCursorOn();
1693
void KviInputEditor::replaceWordBeforeCursor(const QString & szWord, const QString & szReplacement, bool bRepaint)
1696
m_iCursorPosition -= szWord.length();
1697
m_szTextBuffer.remove(m_iCursorPosition,szWord.length());
1698
m_szTextBuffer.insert(m_iCursorPosition,szReplacement);
1699
m_szTextBuffer.truncate(m_iMaxBufferSize);
1700
moveCursorTo(m_iCursorPosition + szReplacement.length());
1702
repaintWithCursorOn();
1705
void KviInputEditor::standardNickCompletionInsertCompletedText(const QString & szReplacedWord, const QString & szCompletedText, bool bFirstWordInLine, bool bInCommand)
1707
QString szBuffer = szCompletedText;
1709
if(!KVI_OPTION_STRING(KviOption_stringNickCompletionPostfix).isEmpty())
1711
if(bFirstWordInLine || (!KVI_OPTION_BOOL(KviOption_boolUseNickCompletionPostfixForFirstWordOnly)))
1712
szBuffer.append(KVI_OPTION_STRING(KviOption_stringNickCompletionPostfix));
1716
// escape crazy things like Nick\nquit
1717
completionEscapeUnsafeToken(szBuffer);
1719
replaceWordBeforeCursor(szReplacedWord,szBuffer,false);
1722
void KviInputEditor::standardNickCompletion(bool bAddMask,QString & szWord,bool bFirstWordInLine,bool bInCommand)
1724
// FIXME: this could be really simplified...
1725
if(!m_pUserListView)
1731
if(m_szLastCompletedNick.isEmpty())
1733
// New completion session: we NEED sth to complete
1734
if(szWord.isEmpty())
1737
if(m_pUserListView->completeNickStandard(szWord,m_szLastCompletedNick,szBuffer,bAddMask))
1739
// completed: save the buffer
1740
m_szLastCompletionBuffer = m_szTextBuffer;
1741
m_iLastCompletionCursorPosition = m_iCursorPosition;
1742
m_iLastCompletionCursorXPosition = m_iLastCursorXPosition;
1743
m_iLastCompletionFirstVisibleChar = m_iFirstVisibleChar;
1744
m_szLastCompletedNick = szBuffer;
1745
standardNickCompletionInsertCompletedText(szWord,szBuffer,bFirstWordInLine,bInCommand);
1746
m_bLastCompletionFinished=0;
1747
// REPAINT CALLED FROM OUTSIDE!
1748
} // else no match at all
1753
if(!m_bLastCompletionFinished)
1757
m_szTextBuffer = m_szLastCompletionBuffer;
1758
m_iCursorPosition = m_iLastCompletionCursorPosition;
1759
m_iLastCursorXPosition = m_iLastCompletionCursorXPosition;
1760
m_iFirstVisibleChar = m_iLastCompletionFirstVisibleChar;
1762
//word = m_szTextBuffer.left(m_iCursorPosition);
1764
getWordBeforeCursor(szWord,&bFirstWordInLine);
1765
if(szWord.isEmpty())return;
1766
if(m_pUserListView->completeNickStandard(szWord,m_szLastCompletedNick,szBuffer,bAddMask))
1769
m_szLastCompletedNick = szBuffer;
1770
standardNickCompletionInsertCompletedText(szWord,szBuffer,bFirstWordInLine,bInCommand);
1771
m_bLastCompletionFinished=0;
1772
// REPAINT CALLED FROM OUTSIDE!
1774
m_bLastCompletionFinished=1;
1775
m_szLastCompletedNick = "";
1781
// Old session finished
1783
//word = m_szTextBuffer.left(m_iCursorPosition);
1784
//getWordBeforeCursor(word,&bFirstWordInLine);
1785
if(szWord.isEmpty())return;
1786
if(m_pUserListView->completeNickStandard(szWord,"",szBuffer,bAddMask))
1789
m_szLastCompletionBuffer = m_szTextBuffer;
1790
m_iLastCompletionCursorPosition = m_iCursorPosition;
1791
m_iLastCompletionCursorXPosition = m_iLastCursorXPosition;
1792
m_iLastCompletionFirstVisibleChar = m_iFirstVisibleChar;
1793
m_szLastCompletedNick = szBuffer;
1794
standardNickCompletionInsertCompletedText(szWord,szBuffer,bFirstWordInLine,bInCommand);
1795
m_bLastCompletionFinished=0;
1796
// REPAINT CALLED FROM OUTSIDE!
1798
m_bLastCompletionFinished=1;
1799
m_szLastCompletedNick = "";
1804
void KviInputEditor::end()
1806
m_iLastCursorXPosition = 0;
1807
m_iCursorPosition = 0;
1808
m_iFirstVisibleChar = 0;
1809
while(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
1811
moveRightFirstVisibleCharToShowCursor();
1812
m_iCursorPosition++;
1814
repaintWithCursorOn();
1817
void KviInputEditor::home()
1819
m_iFirstVisibleChar = 0;
1820
m_iCursorPosition = 0;
1821
repaintWithCursorOn();
1824
void KviInputEditor::insertChar(QChar c)
1826
if(m_szTextBuffer.length() >= m_iMaxBufferSize)
1829
// Kill the selection
1830
if((m_iSelectionBegin > -1) || (m_iSelectionEnd > -1))
1832
if((m_iCursorPosition >= m_iSelectionBegin) && (m_iCursorPosition <= m_iSelectionEnd))
1834
m_bUpdatesEnabled = false;
1836
m_bUpdatesEnabled = true;
1840
m_szTextBuffer.insert(m_iCursorPosition,c);
1842
addUndo(new EditCommand(EditCommand::InsertText,c,m_iCursorPosition));
1844
moveRightFirstVisibleCharToShowCursor();
1845
m_iCursorPosition++;
1846
repaintWithCursorOn();
1849
void KviInputEditor::moveRightFirstVisibleCharToShowCursor()
1852
QFontMetrics * fm = KviInputEditor::getLastFontMetrics(font());
1854
QChar c = m_szTextBuffer.at(m_iCursorPosition);
1856
m_iLastCursorXPosition += (c.unicode() < 256) ? KviInputEditor::g_iInputFontCharWidth[c.unicode()] : fm->width(c);
1858
while(m_iLastCursorXPosition >= contentsRect().width()-2*KVI_INPUT_MARGIN)
1860
c = m_szTextBuffer.at(m_iFirstVisibleChar);
1862
m_iLastCursorXPosition -= (c.unicode() < 256) ? KviInputEditor::g_iInputFontCharWidth[c.unicode()] : fm->width(c);
1864
m_iFirstVisibleChar++;
1868
void KviInputEditor::repaintWithCursorOn()
1871
if(m_bUpdatesEnabled)
1878
void KviInputEditor::selectOneChar(int iPos)
1880
m_iSelectionBegin = iPos;
1881
m_iSelectionEnd = iPos;
1884
int KviInputEditor::charIndexFromXPosition(int iXPos)
1886
int iCurXPos = KVI_INPUT_MARGIN;
1887
int iCurChar = m_iFirstVisibleChar;
1888
int iBufLen = m_szTextBuffer.length();
1890
QFontMetrics *fm = KviInputEditor::getLastFontMetrics(font());
1891
while(iCurChar < iBufLen)
1893
QChar c = m_szTextBuffer.at(iCurChar);
1894
int iWidthCh = (c.unicode() < 256) ? KviInputEditor::g_iInputFontCharWidth[c.unicode()] : fm->width(c);
1896
if(iXPos < (iCurXPos+(iWidthCh/2)))
1900
if(iXPos < (iCurXPos+iWidthCh))
1902
return (iCurChar+1);
1906
iCurXPos += iWidthCh;
1912
int KviInputEditor::xPositionFromCharIndex(int iChIdx)
1914
QFontMetrics *fm = KviInputEditor::getLastFontMetrics(font());
1916
int iCurChar = m_iFirstVisibleChar;
1918
if(m_szTextBuffer.isEmpty())
1921
while(iCurChar < iChIdx)
1923
QChar c = m_szTextBuffer.at(iCurChar);
1924
iCurXPos += (c.unicode() < 256) ? KviInputEditor::g_iInputFontCharWidth[c.unicode()] : fm->width(c);
1931
void KviInputEditor::undo()
1933
if(!isUndoAvailable())
1937
return; // this should be ensured by isUndoAvailable() but well...
1941
EditCommand * pCommand = m_pUndoStack->takeLast();
1943
Q_ASSERT(pCommand); // should be true: we delete the empty undo stack
1945
if(m_pUndoStack->isEmpty())
1947
delete m_pUndoStack;
1948
m_pUndoStack = NULL;
1951
switch(pCommand->type())
1953
case EditCommand::InsertText:
1954
m_szTextBuffer.remove(pCommand->startPosition(),pCommand->text().length());
1955
moveCursorTo(pCommand->startPosition());
1957
case EditCommand::RemoveText:
1958
m_szTextBuffer.insert(pCommand->startPosition(),pCommand->text());
1959
moveCursorTo(pCommand->startPosition()+pCommand->text().length());
1962
Q_ASSERT_X(false,"KviInputEditor::undo","Unexpected EditCommand type");
1963
delete pCommand; // argh
1970
m_pRedoStack = new KviPointerList<EditCommand>;
1971
m_pRedoStack->setAutoDelete(true);
1974
m_pRedoStack->append(pCommand);
1975
if(m_pRedoStack->count() > KVI_INPUT_MAX_UNDO_SIZE)
1976
m_pRedoStack->removeFirst(); // will delete it
1979
void KviInputEditor::redo()
1981
if(!isRedoAvailable())
1985
return; // this should be ensured by isUndoAvailable() but well...
1989
EditCommand * pCommand = m_pRedoStack->takeLast();
1991
Q_ASSERT(pCommand); // should be true: we delete the empty redo stack
1993
if(m_pRedoStack->isEmpty())
1995
delete m_pRedoStack;
1996
m_pRedoStack = NULL;
1999
switch(pCommand->type())
2001
case EditCommand::InsertText:
2002
m_szTextBuffer.insert(pCommand->startPosition(),pCommand->text());
2003
moveCursorTo(pCommand->startPosition()+pCommand->text().length());
2005
case EditCommand::RemoveText:
2006
m_szTextBuffer.remove(pCommand->startPosition(),pCommand->text().length());
2007
moveCursorTo(pCommand->startPosition());
2010
Q_ASSERT_X(false,"KviInputEditor::redo","Unexpected EditCommand type");
2011
delete pCommand; // argh
2018
m_pUndoStack = new KviPointerList<EditCommand>;
2019
m_pUndoStack->setAutoDelete(true);
2022
m_pUndoStack->append(pCommand);
2023
if(m_pUndoStack->count() > KVI_INPUT_MAX_UNDO_SIZE)
2024
m_pUndoStack->removeFirst(); // will delete it
2027
void KviInputEditor::addUndo(EditCommand * pCommand)
2031
m_pUndoStack = new KviPointerList<EditCommand>;
2032
m_pUndoStack->setAutoDelete(true);
2034
m_pUndoStack->append(pCommand);
2036
if(m_pUndoStack->count() > KVI_INPUT_MAX_UNDO_SIZE)
2037
m_pUndoStack->removeFirst(); // will delete it
2040
void KviInputEditor::openHistory()
2042
if(!KVI_OPTION_BOOL(KviOption_boolEnableInputHistory))
2044
if(m_pInputParent->inherits("KviInput"))
2045
((KviInput*)(m_pInputParent))->historyButtonClicked();
2048
void KviInputEditor::toggleMultiLineEditor()
2050
if(m_pInputParent->inherits("KviInput"))
2052
((KviInput*)(m_pInputParent))->multiLinePaste(m_szTextBuffer);
2058
void KviInputEditor::previousChar()
2060
if(m_iCursorPosition > 0)
2062
internalCursorLeft(false);
2063
repaintWithCursorOn();
2067
void KviInputEditor::nextChar()
2069
if(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
2071
internalCursorRight(false);
2072
repaintWithCursorOn();
2076
void KviInputEditor::previousCharSelection()
2078
if(m_iCursorPosition > 0)
2080
internalCursorLeft(true);
2081
repaintWithCursorOn();
2085
void KviInputEditor::nextCharSelection()
2087
if(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
2089
internalCursorRight(true);
2090
repaintWithCursorOn();
2094
void KviInputEditor::previousWord()
2096
if(m_iCursorPosition > 0)
2099
while(m_iCursorPosition > 0)
2101
if(!m_szTextBuffer.at(m_iCursorPosition - 1).isSpace())
2103
internalCursorLeft(false);
2105
// skip nonwhitespace
2106
while(m_iCursorPosition > 0)
2108
if(m_szTextBuffer.at(m_iCursorPosition - 1).isSpace())
2110
internalCursorLeft(false);
2112
repaintWithCursorOn();
2116
void KviInputEditor::nextWord()
2118
if(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
2121
while(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
2123
if(!m_szTextBuffer.at(m_iCursorPosition).isSpace())
2125
internalCursorRight(false);
2127
// skip nonwhitespace
2128
while(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
2130
if(m_szTextBuffer.at(m_iCursorPosition).isSpace())
2132
internalCursorRight(false);
2134
repaintWithCursorOn();
2138
void KviInputEditor::previousWordSelection()
2140
if(m_iCursorPosition > 0)
2143
while(m_iCursorPosition > 0)
2145
if(!m_szTextBuffer.at(m_iCursorPosition - 1).isSpace())
2147
internalCursorLeft(true);
2149
// skip nonwhitespace
2150
while(m_iCursorPosition > 0)
2152
if(m_szTextBuffer.at(m_iCursorPosition - 1).isSpace())
2154
internalCursorLeft(true);
2156
repaintWithCursorOn();
2160
void KviInputEditor::nextWordSelection()
2162
if(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
2165
while(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
2167
if(!m_szTextBuffer.at(m_iCursorPosition).isSpace())
2169
internalCursorRight(true);
2171
// skip nonwhitespace
2172
while(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
2174
if(m_szTextBuffer.at(m_iCursorPosition).isSpace())
2176
internalCursorRight(true);
2178
repaintWithCursorOn();
2182
void KviInputEditor::insertBold()
2184
if(!m_bReadOnly) insertChar(KviControlCodes::Bold);
2187
void KviInputEditor::insertReset()
2189
if(!m_bReadOnly) insertChar(KviControlCodes::Reset);
2192
void KviInputEditor::insertUnderline()
2194
if(!m_bReadOnly) insertChar(KviControlCodes::Underline);
2197
void KviInputEditor::insertReverse()
2199
if(!m_bReadOnly) insertChar(KviControlCodes::Reverse);
2202
void KviInputEditor::insertPlainText()
2204
if(!m_bReadOnly) insertChar(KviControlCodes::CryptEscape); // DO NOT CRYPT THIS STUFF
2207
void KviInputEditor::insertIcon()
2211
insertChar(KviControlCodes::Icon); // THE NEXT WORD IS AN ICON NAME
2212
int iXPos = xPositionFromCharIndex(m_iCursorPosition);
2215
if(!g_pTextIconWindow)
2216
g_pTextIconWindow = new KviTextIconWindow();
2218
if(iXPos+g_pTextIconWindow->width() > width())
2219
iXPos = width()-(g_pTextIconWindow->width()+2);
2220
g_pTextIconWindow->move(mapToGlobal(QPoint(iXPos,-KVI_TEXTICON_WIN_HEIGHT)));
2221
g_pTextIconWindow->popup(this,false);
2225
void KviInputEditor::insertColor()
2229
insertChar(KviControlCodes::Color);
2230
int xPos = xPositionFromCharIndex(m_iCursorPosition);
2231
if(xPos > 24)xPos-=24;
2232
if(!g_pColorWindow)g_pColorWindow = new KviColorWindow();
2233
if(xPos+g_pColorWindow->width() > width())xPos = width()-(g_pColorWindow->width()+2);
2234
g_pColorWindow->move(mapToGlobal(QPoint(xPos,-35)));
2235
g_pColorWindow->popup(this);
2239
void KviInputEditor::copyInternal()
2244
void KviInputEditor::cutInternal()
2246
if(!m_bReadOnly) cut();
2249
void KviInputEditor::pasteInternal()
2251
if(!m_bReadOnly) pasteClipboardWithConfirmation();
2254
void KviInputEditor::undoInternal()
2260
void KviInputEditor::redoInternal()
2266
void KviInputEditor::selectAllInternal()
2268
m_iSelectionBegin=0;
2269
m_iSelectionEnd=m_szTextBuffer.length()-1;
2270
m_iCursorPosition=m_szTextBuffer.length();
2271
repaintWithCursorOn();
2274
void KviInputEditor::deleteWord()
2276
if(m_iCursorPosition > 0 && !m_bReadOnly && !hasSelection())
2279
while(m_iCursorPosition > 0)
2281
if(!m_szTextBuffer.at(m_iCursorPosition - 1).isSpace())
2283
m_szTextBuffer.remove(m_iCursorPosition-1,1);
2284
m_iCursorPosition--;
2285
if(m_iFirstVisibleChar > m_iCursorPosition)
2286
m_iFirstVisibleChar--;
2288
// skip nonwhitespace
2289
while(m_iCursorPosition > 0)
2291
if(m_szTextBuffer.at(m_iCursorPosition - 1).isSpace())
2293
m_szTextBuffer.remove(m_iCursorPosition-1,1);
2294
m_iCursorPosition--;
2295
if(m_iFirstVisibleChar > m_iCursorPosition)
2296
m_iFirstVisibleChar--;
2298
repaintWithCursorOn();
2302
void KviInputEditor::previousLine()
2305
if(m_pKviWindow->view()) m_pKviWindow->view()->prevLine();
2309
void KviInputEditor::nextLine()
2312
if(m_pKviWindow->view()) m_pKviWindow->view()->nextLine();
2316
void KviInputEditor::previousPage()
2319
if(m_pKviWindow->view()) m_pKviWindow->view()->prevPage();
2322
void KviInputEditor::nextPage()
2325
if(m_pKviWindow->view()) m_pKviWindow->view()->nextPage();
2328
void KviInputEditor::search()
2331
if(m_pKviWindow->view()) m_pKviWindow->view()->toggleToolWidget();
2334
void KviInputEditor::scrollToLastReadLine()
2337
if(m_pKviWindow->view())
2338
if(m_pKviWindow->view()->hasLineMark())
2339
m_pKviWindow->view()->scrollToMarker();
2342
void KviInputEditor::sendPlain()
2344
if(m_pInputParent->inherits("KviInput"))
2346
//ensure the color window is hidden (bug #835)
2348
if(g_pColorWindow->isVisible())
2349
g_pColorWindow->hide();
2351
QString szBuffer(m_szTextBuffer);
2354
m_iCursorPosition = 0;
2355
m_iFirstVisibleChar = 0;
2356
repaintWithCursorOn();
2357
KviUserInput::parseNonCommand(szBuffer,m_pKviWindow);
2358
if (!szBuffer.isEmpty())
2360
KviInputHistory::instance()->add(new QString(szBuffer));
2361
m_pHistory->insert(0,new QString(szBuffer));
2364
KVI_ASSERT(KVI_INPUT_MAX_LOCAL_HISTORY_ENTRIES > 1); //ABSOLUTELY NEEDED, if not, pHist will be destroyed...
2365
if(m_pHistory->count() > KVI_INPUT_MAX_LOCAL_HISTORY_ENTRIES)m_pHistory->removeLast();
2367
m_iCurHistoryIdx = -1;
2371
void KviInputEditor::homeInternal()
2373
if(m_iCursorPosition > 0)
2380
void KviInputEditor::homeInternalSelection()
2382
if(m_iCursorPosition > 0)
2384
if((m_iSelectionBegin == -1) && (m_iSelectionEnd == -1))
2386
// There is no selection
2387
m_iSelectionEnd = m_iCursorPosition - 1;
2389
// There is selection
2390
m_iSelectionEnd = m_iSelectionBegin - 1;
2393
m_iSelectionBegin = 0;
2398
void KviInputEditor::endInternal()
2404
void KviInputEditor::endInternalSelection()
2406
if((m_iSelectionBegin == -1) && (m_iSelectionEnd == -1))
2408
// There is no selection
2409
m_iSelectionBegin = m_iCursorPosition;
2411
// There is selection
2412
m_iSelectionBegin = m_iSelectionEnd+1;
2415
m_iSelectionEnd = m_szTextBuffer.length()-1;
2419
void KviInputEditor::historyPrev()
2423
if(m_pHistory->count() > 0)
2425
if(m_iCurHistoryIdx < 0)
2427
m_szSaveTextBuffer = m_szTextBuffer;
2428
m_szTextBuffer = *(m_pHistory->at(0));
2429
m_iCurHistoryIdx = 0;
2430
} else if(m_iCurHistoryIdx >= (int)(m_pHistory->count()-1))
2432
m_szTextBuffer=m_szSaveTextBuffer;
2433
m_iCurHistoryIdx = -1;
2436
m_szTextBuffer = *(m_pHistory->at(m_iCurHistoryIdx));
2439
if(KVI_OPTION_BOOL(KviOption_boolInputHistoryCursorAtEnd))end();
2445
void KviInputEditor::historyNext()
2449
if(m_pHistory->count() > 0)
2451
if(m_iCurHistoryIdx < 0)
2453
m_szSaveTextBuffer = m_szTextBuffer;
2454
m_szTextBuffer = *(m_pHistory->at(m_pHistory->count()-1));
2455
m_iCurHistoryIdx =m_pHistory->count()-1;
2456
} else if(m_iCurHistoryIdx == 0)
2458
m_szTextBuffer=m_szSaveTextBuffer;
2459
m_iCurHistoryIdx = -1;
2462
m_szTextBuffer = *(m_pHistory->at(m_iCurHistoryIdx));
2465
if(KVI_OPTION_BOOL(KviOption_boolInputHistoryCursorAtEnd))end();
2471
void KviInputEditor::returnHit()
2476
void KviInputEditor::backspaceHit()
2480
if(hasSelection() && (m_iSelectionEnd >= m_iCursorPosition-1) && (m_iSelectionBegin <= m_iCursorPosition))
2482
//remove the selection
2483
addUndo(new EditCommand(EditCommand::RemoveText,m_szTextBuffer.mid(m_iSelectionBegin,(m_iSelectionEnd-m_iSelectionBegin)+1),m_iSelectionBegin));
2484
m_szTextBuffer.remove(m_iSelectionBegin,(m_iSelectionEnd-m_iSelectionBegin)+1);
2485
m_iCursorPosition = m_iSelectionBegin;
2486
if(m_iFirstVisibleChar > m_iCursorPosition)
2487
m_iFirstVisibleChar = m_iCursorPosition;
2488
} else if(m_iCursorPosition > 0)
2490
m_iCursorPosition--;
2491
addUndo(new EditCommand(EditCommand::RemoveText,m_szTextBuffer.mid(m_iCursorPosition,1),m_iCursorPosition));
2492
m_szTextBuffer.remove(m_iCursorPosition,1);
2493
if(m_iFirstVisibleChar > m_iCursorPosition)
2494
m_iFirstVisibleChar--;
2497
repaintWithCursorOn();
2500
void KviInputEditor::deleteHit()
2511
if(m_iCursorPosition < (int)m_szTextBuffer.length())
2513
m_szTextBuffer.remove(m_iCursorPosition,1);
2515
repaintWithCursorOn();
2519
void KviInputEditor::escapeHit()
2521
emit escapePressed();
2525
void KviInputEditor::toggleCommandMode()
2527
if(m_pInputParent->inherits("KviInput"))
2528
((KviInput *)(m_pInputParent))->setUserFriendly(!((KviInput *)(m_pInputParent))->isUserFriendly());
2531
void KviInputEditor::dummy()
2533
// this function does nothing. check the header file for explanation
2536
#ifndef COMPILE_USE_STANDALONE_MOC_SOURCES
2537
#include "KviInputEditor.moc"
2538
#endif //!COMPILE_USE_STANDALONE_MOC_SOURCES