~ubuntu-branches/ubuntu/trusty/kvirc/trusty

« back to all changes in this revision

Viewing changes to src/kvirc/ui/KviInputEditor.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Kai Wasserbäch, Kai Wasserbäch, Raúl Sánchez Siles
  • Date: 2011-02-12 10:40:21 UTC
  • mfrom: (14.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20110212104021-5mh4f75jlku20mnt
The combined "Twisted Experiment" and "Nocturnal Raid" release.

[ Kai Wasserbäch ]
* Synced to upstream's SVN revision 5467.
* debian/rules:
  - Added .PHONY line.
  - Resurrect -DMANUAL_REVISION, got lost somewhere and we build SVN
    revisions again.
  - Replace "-DWITH_NO_EMBEDDED_CODE=YES" with "-DWANT_CRYPTOPP=YES".
  - Change the remaining -DWITH/-DWITHOUT to the new -DWANT syntax.
* debian/control:
  - Removed DMUA, I'm a DD now.
  - Changed my e-mail address.
  - Removed unneeded relationships (no upgrades over two releases are
    supported).
  - Fix Suggests for kvirc-dbg.
  - kvirc-data: Make the "Suggests: kvirc" a Recommends, doesn't make much
    sense to install the -data package without the program.
* debian/source/local-options: Added with "unapply-patches".
* debian/kvirc.lintian-overrides: Updated to work for 4.1.1.
* debian/patches/21_make_shared-mime-info_B-D_superfluous.patch: Updated.
* debian/kvirc-data.install: Added .notifyrc.

[ Raúl Sánchez Siles ]
* Stating the right version where kvirc-data break and replace should happen.
* Fixing link to license file.
* Added French and Portuguese man pages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//============================================================================
 
2
//
 
3
//   File : KviInputEditor.cpp
 
4
//   Creation date : Fri Sep 5 2008 17:26:34 by Elvio Basello
 
5
//
 
6
//   This file is part of the KVIrc irc client distribution
 
7
//   Copyright (C) 2008 Elvio Basello (hellvis69 at netsons dot org)
 
8
//
 
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.
 
13
//
 
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.
 
18
//
 
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.
 
22
//
 
23
//============================================================================
 
24
//   This file was originally part of KviInput.h
 
25
//============================================================================
 
26
 
 
27
#include "KviApplication.h"
 
28
#include "KviColorSelectionWindow.h"
 
29
#include "KviConsoleWindow.h"
 
30
#include "kvi_fileextensions.h"
 
31
#include "KviMainWindow.h"
 
32
#include "KviInput.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"
 
44
#include "kvi_out.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"
 
52
 
 
53
#include <QClipboard>
 
54
#include <QLabel>
 
55
#include <QUrl>
 
56
#include <QStyle>
 
57
#include <QStyleOption>
 
58
#include <QPainter>
 
59
#include <QPixmap>
 
60
#include <QFileDialog>
 
61
#include <QFontMetrics>
 
62
#include <QKeyEvent>
 
63
#include <QDragEnterEvent>
 
64
#include <QInputContext>
 
65
#include <QShortcut>
 
66
 
 
67
// from KviApplication.cpp
 
68
extern KviTalPopupMenu         * g_pInputPopup;
 
69
extern KviTextIconWindow       * g_pTextIconWindow;
 
70
extern KviColorWindow          * g_pColorWindow;
 
71
 
 
72
#ifdef COMPILE_PSEUDO_TRANSPARENCY
 
73
        extern QPixmap       * g_pShadedChildGlobalDesktopBackground;
 
74
#endif
 
75
 
 
76
//static members initialization
 
77
int            KviInputEditor::g_iInputInstances = 0;
 
78
int            KviInputEditor::g_iInputFontCharWidth[256];
 
79
QFontMetrics * KviInputEditor::g_pLastFontMetrics = 0;
 
80
 
 
81
#define KVI_INPUT_MAX_UNDO_SIZE 256
 
82
 
 
83
KviInputEditor::KviInputEditor(QWidget * pPar, KviWindow * pWnd, KviUserListView * pView)
 
84
        : QWidget(pPar)
 
85
{
 
86
        ++KviInputEditor::g_iInputInstances;
 
87
        setObjectName("input_widget");
 
88
        m_pIconMenu            = 0;
 
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.
 
101
 
 
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;
 
109
        m_pKviWindow           = pWnd;
 
110
        m_pUserListView        = pView;
 
111
        m_pHistory             = new KviPointerList<QString>;
 
112
        m_pHistory->setAutoDelete(true);
 
113
        m_bReadOnly            = false;
 
114
 
 
115
        m_pUndoStack = NULL;
 
116
        m_pRedoStack = NULL;
 
117
 
 
118
        setAttribute(Qt::WA_InputMethodEnabled, true);
 
119
 
 
120
        setAutoFillBackground(false);
 
121
 
 
122
        setFocusPolicy(Qt::StrongFocus);
 
123
        setAcceptDrops(true);
 
124
 
 
125
        m_pIconMenu = new KviTalPopupMenu();
 
126
        connect(m_pIconMenu,SIGNAL(activated(int)),this,SLOT(iconPopupActivated(int)));
 
127
 
 
128
        setCursor(Qt::IBeamCursor);
 
129
 
 
130
        setContentsMargins(KVI_INPUT_MARGIN,KVI_INPUT_MARGIN,KVI_INPUT_MARGIN,KVI_INPUT_MARGIN);
 
131
        //set the font and font metrics
 
132
        applyOptions();
 
133
 
 
134
        installShortcuts();
 
135
}
 
136
 
 
137
KviInputEditor::~KviInputEditor()
 
138
{
 
139
        --KviInputEditor::g_iInputInstances;
 
140
        if(KviInputEditor::g_iInputInstances==0 && g_pLastFontMetrics)
 
141
        {
 
142
                //last instance, delete shared resources
 
143
                delete g_pLastFontMetrics;
 
144
                g_pLastFontMetrics = 0;
 
145
        }
 
146
 
 
147
        if(m_pIconMenu)
 
148
                delete m_pIconMenu;
 
149
 
 
150
        delete m_pHistory;
 
151
        
 
152
        if(m_pUndoStack)
 
153
                delete m_pUndoStack;
 
154
        if(m_pRedoStack)
 
155
                delete m_pRedoStack;
 
156
 
 
157
        if(m_iCursorTimer)
 
158
                killTimer(m_iCursorTimer);
 
159
        killDragTimer();
 
160
}
 
161
 
 
162
void KviInputEditor::applyOptions()
 
163
{
 
164
        //set the font
 
165
        QFont newFont(KVI_OPTION_FONT(KviOption_fontInput));
 
166
        newFont.setKerning(false);
 
167
        setFont(newFont);
 
168
 
 
169
        //then, let font metrics be updated in lazy fashion
 
170
        if(g_pLastFontMetrics)
 
171
                delete g_pLastFontMetrics;
 
172
        g_pLastFontMetrics = 0;
 
173
 
 
174
        //not that lazy, since we force an update :)
 
175
        update();
 
176
}
 
177
 
 
178
void KviInputEditor::dragEnterEvent(QDragEnterEvent * e)
 
179
{
 
180
        if(e->mimeData()->hasUrls())
 
181
                e->acceptProposedAction();
 
182
}
 
183
 
 
184
void KviInputEditor::dropEvent(QDropEvent * e)
 
185
{
 
186
        QList<QUrl> list;
 
187
        if(e->mimeData()->hasUrls())
 
188
        {
 
189
                list = e->mimeData()->urls();
 
190
                //qDebug("Local files decoded");
 
191
                if(!list.isEmpty())
 
192
                {
 
193
                        //qDebug("List not empty");
 
194
                        QList<QUrl>::Iterator it = list.begin();
 
195
                        for( ; it != list.end(); ++it )
 
196
                        {
 
197
                                QUrl url = *it;
 
198
                                QString szPath = url.toLocalFile();
 
199
                                if(szPath.endsWith(KVI_FILEEXTENSION_SCRIPT,Qt::CaseInsensitive))
 
200
                                {
 
201
                                        //script, parse it
 
202
                                        KviQString::escapeKvs(&szPath, KviQString::EscapeSpace);
 
203
                                        szPath.prepend("PARSE ");
 
204
                                        if(m_pKviWindow)
 
205
                                                KviKvsScript::run(szPath,m_pKviWindow);
 
206
                                } else {
 
207
                                        //other file, paste link
 
208
                                        szPath.append(" ");
 
209
                                        insertText(szPath);
 
210
                                }
 
211
                        }
 
212
                }
 
213
        }
 
214
}
 
215
 
 
216
int  KviInputEditor::heightHint() const
 
217
{
 
218
        return sizeHint().height();
 
219
}
 
220
 
 
221
QSize KviInputEditor::sizeHint() const
 
222
{
 
223
        ensurePolished();
 
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);
 
227
 
 
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;
 
233
 
 
234
        option.state |= QStyle::State_Sunken;
 
235
        if(isReadOnly())
 
236
                option.state |= QStyle::State_ReadOnly;
 
237
        option.features = QStyleOptionFrameV2::None;
 
238
 
 
239
        return (style()->sizeFromContents(QStyle::CT_LineEdit, &option, QSize(w, h).
 
240
                expandedTo(QApplication::globalStrut()), this));
 
241
}
 
242
 
 
243
void KviInputEditor::paintEvent(QPaintEvent *)
 
244
{
 
245
        QPainter p(this);
 
246
 
 
247
#ifdef COMPILE_PSEUDO_TRANSPARENCY
 
248
        if(KVI_OPTION_BOOL(KviOption_boolUseCompositingForTransparency) && g_pApp->supportsCompositing())
 
249
        {
 
250
                p.save();
 
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);
 
255
                p.restore();
 
256
        } else if(g_pShadedChildGlobalDesktopBackground)
 
257
        {
 
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);
 
260
        } else {
 
261
#endif
 
262
                p.fillRect(contentsRect(),KVI_OPTION_COLOR(KviOption_colorInputBackground));
 
263
 
 
264
                QPixmap * pix = KVI_OPTION_PIXMAP(KviOption_pixmapLabelBackground).pixmap();
 
265
                if(pix)
 
266
                        KviPixmapUtils::drawPixmapWithPainter(&p,pix,KVI_OPTION_UINT(KviOption_uintTreeWindowListPixmapAlign),contentsRect(),contentsRect().width(),contentsRect().height());
 
267
#ifdef COMPILE_PSEUDO_TRANSPARENCY
 
268
        }
 
269
#endif
 
270
 
 
271
        QStyleOptionFrameV2 option;
 
272
 
 
273
        option.initFrom(this);
 
274
        option.rect = rect();
 
275
        option.lineWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, &option, this);
 
276
        option.midLineWidth = 0;
 
277
 
 
278
        option.state |= QStyle::State_Sunken;
 
279
        if(isReadOnly())
 
280
                option.state |= QStyle::State_ReadOnly;
 
281
 
 
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;
 
284
 
 
285
        style()->drawPrimitive(QStyle::PE_FrameLineEdit, &option, &p, this);
 
286
 
 
287
        QRect r = style()->subElementRect(QStyle::SE_LineEditContents, &option, this);
 
288
 
 
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);
 
293
 
 
294
        p.setClipRect(r);
 
295
 
 
296
        p.translate(r.topLeft());
 
297
        drawContents(&p);
 
298
}
 
299
 
 
300
void KviInputEditor::drawContents(QPainter * p)
 
301
{
 
302
        QRect rect = p->clipRegion().boundingRect();
 
303
        QFontMetrics * fm = KviInputEditor::getLastFontMetrics(font());
 
304
 
 
305
        int iCurXPos     = 0;
 
306
        int iMaxXPos     = rect.width()-1;
 
307
        m_iCurBack       = KVI_INPUT_DEF_BACK; //transparent
 
308
        m_iCurFore       = KVI_INPUT_DEF_FORE; //normal fore color
 
309
        m_bCurBold       = false;
 
310
        m_bCurUnderline  = false;
 
311
 
 
312
        int iTop          = KVI_INPUT_XTRAPADDING;
 
313
        int iBottom       = rect.height() - KVI_INPUT_XTRAPADDING;
 
314
 
 
315
        int iTextBaseline = iBottom - fm->descent();
 
316
 
 
317
        runUpToTheFirstVisibleChar();
 
318
 
 
319
        int iCharIdx      = m_iFirstVisibleChar;
 
320
 
 
321
        //Control the selection state
 
322
        if((m_iSelectionEnd < m_iSelectionBegin) || (m_iSelectionEnd == -1) || (m_iSelectionBegin == -1))
 
323
        {
 
324
                m_iSelectionEnd = -1;
 
325
                m_iSelectionBegin = -1;
 
326
        }
 
327
 
 
328
        if((m_iSelectionBegin != -1) && (m_iSelectionEnd >= m_iFirstVisibleChar))
 
329
        {
 
330
                int iSelStart = m_iSelectionBegin;
 
331
 
 
332
                if(iSelStart < m_iFirstVisibleChar)
 
333
                        iSelStart = m_iFirstVisibleChar;
 
334
                int iXLeft = xPositionFromCharIndex(iSelStart);
 
335
                int iXRight = xPositionFromCharIndex(m_iSelectionEnd + 1);
 
336
 
 
337
                p->fillRect(iXLeft,0,iXRight - iXLeft,rect.height(),KVI_OPTION_COLOR(KviOption_colorInputSelectionBackground));
 
338
        }
 
339
 
 
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)
 
347
        {
 
348
                int iIMSelectionStart = m_iIMSelectionBegin;
 
349
                if(iIMSelectionStart < m_iFirstVisibleChar)
 
350
                        iIMSelectionStart = m_iFirstVisibleChar;
 
351
 
 
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));
 
355
 
 
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);
 
361
 
 
362
                // underline the IM preedit
 
363
                // Maybe should be put in drawTextBlock, similar to drawing underlined text
 
364
                p->drawLine(xIMLeft, iBottom, xIMRight, iBottom);
 
365
        }
 
366
 
 
367
        while((iCharIdx < ((int)(m_szTextBuffer.length()))) && (iCurXPos < iMaxXPos))
 
368
        {
 
369
                extractNextBlock(iCharIdx,fm,iCurXPos,iMaxXPos);
 
370
 
 
371
                if(m_bControlBlock)
 
372
                {
 
373
                        p->setPen(KVI_OPTION_COLOR(KviOption_colorInputControl));
 
374
 
 
375
                        QChar s = getSubstituteChar(m_szTextBuffer[iCharIdx].unicode());
 
376
 
 
377
                        // the block width is 4 pixels more than the actual character
 
378
 
 
379
                        p->drawText(iCurXPos + 2,iTextBaseline,s);
 
380
 
 
381
                        p->drawRect(iCurXPos,iTop,m_iBlockWidth-1,iBottom-1);
 
382
                } else {
 
383
                        if(m_iSelectionBegin!=-1)
 
384
                        {
 
385
                                int iBlockEnd = iCharIdx + m_iBlockLen;
 
386
                                //block is selected (maybe partially)
 
387
                                if( iBlockEnd > m_iSelectionBegin && iCharIdx <= m_iSelectionEnd )
 
388
                                {
 
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)
 
392
 
 
393
                                        //first part start is always equal to the block start
 
394
                                        iSubStart = iCharIdx;
 
395
                                        iSubLen = m_iSelectionBegin > iCharIdx ? m_iSelectionBegin-iCharIdx : 0;
 
396
 
 
397
                                        if(iSubLen)
 
398
                                        {
 
399
                                                drawTextBlock(p,iTop,iBottom,iCurXPos,iTextBaseline,iSubStart,iSubLen,FALSE);
 
400
                                                iCurXPos += m_iBlockWidth;
 
401
                                                m_iBlockWidth=0;
 
402
                                        }
 
403
 
 
404
                                        //second one
 
405
                                        iSubStart += iSubLen;
 
406
                                        iSubLen = m_iSelectionEnd<iBlockEnd ? m_iSelectionEnd-iSubStart+1 : iBlockEnd-iSubStart;
 
407
 
 
408
                                        if(iSubLen)
 
409
                                        {
 
410
                                                drawTextBlock(p,iTop,iBottom,iCurXPos,iTextBaseline,iSubStart,iSubLen,TRUE);
 
411
                                                iCurXPos += m_iBlockWidth;
 
412
                                                m_iBlockWidth=0;
 
413
                                        }
 
414
 
 
415
                                        if(m_iSelectionEnd<(iBlockEnd-1))
 
416
                                        {
 
417
                                                iSubStart += iSubLen;
 
418
                                                iSubLen = iBlockEnd-iSubStart;
 
419
                                                drawTextBlock(p,iTop,iBottom,iCurXPos,iTextBaseline,iSubStart,iSubLen,FALSE);
 
420
                                        }
 
421
                                } else {
 
422
                                        drawTextBlock(p,iTop,iBottom,iCurXPos,iTextBaseline,iCharIdx,m_iBlockLen);
 
423
                                }
 
424
                        } else {
 
425
                                drawTextBlock(p,iTop,iBottom,iCurXPos,iTextBaseline,iCharIdx,m_iBlockLen);
 
426
                        }
 
427
                }
 
428
 
 
429
                iCurXPos += m_iBlockWidth;
 
430
                iCharIdx += m_iBlockLen;
 
431
        }
 
432
 
 
433
        //Now the cursor
 
434
        m_iLastCursorXPosition = 0;
 
435
        m_iBlockLen = m_iFirstVisibleChar;
 
436
 
 
437
        while(m_iBlockLen < m_iCursorPosition)
 
438
        {
 
439
                QChar c = m_szTextBuffer.at(m_iBlockLen);
 
440
                m_iLastCursorXPosition+= (c.unicode() < 256) ? KviInputEditor::g_iInputFontCharWidth[c.unicode()] : fm->width(c);
 
441
                m_iBlockLen++;
 
442
        }
 
443
 
 
444
        if(m_bCursorOn)
 
445
        {
 
446
                p->setPen(KVI_OPTION_COLOR(KviOption_colorInputCursor));
 
447
                p->drawLine(m_iLastCursorXPosition,iTop,m_iLastCursorXPosition,iBottom);
 
448
        } else {
 
449
                p->setPen(KVI_OPTION_COLOR(KviOption_colorInputForeground));
 
450
        }
 
451
}
 
452
 
 
453
void KviInputEditor::drawTextBlock(QPainter * pa, int iTop, int iBottom, int iCurXPos, int iTextBaseline, int iIdx, int iLen, bool bSelected)
 
454
{
 
455
        QFontMetrics * fm = KviInputEditor::getLastFontMetrics(font());
 
456
        QString szTmp = m_szTextBuffer.mid(iIdx,iLen);
 
457
        m_iBlockWidth = fm->width(szTmp);
 
458
 
 
459
        if(m_iCurFore == KVI_INPUT_DEF_FORE)
 
460
        {
 
461
                pa->setPen( bSelected ? KVI_OPTION_COLOR(KviOption_colorInputSelectionForeground) : KVI_OPTION_COLOR(KviOption_colorInputForeground));
 
462
        } else {
 
463
                if(((unsigned char)m_iCurFore) > 16)
 
464
                {
 
465
                        pa->setPen(KVI_OPTION_COLOR(KviOption_colorInputBackground));
 
466
                } else {
 
467
                        pa->setPen(KVI_OPTION_MIRCCOLOR((unsigned char)m_iCurFore));
 
468
                }
 
469
        }
 
470
 
 
471
        if(m_iCurBack != KVI_INPUT_DEF_BACK)
 
472
        {
 
473
                if(((unsigned char)m_iCurBack) > 16)
 
474
                {
 
475
                        pa->fillRect(iCurXPos,iTop,m_iBlockWidth,iBottom,KVI_OPTION_COLOR(KviOption_colorInputForeground));
 
476
                } else {
 
477
                        pa->fillRect(iCurXPos,iTop,m_iBlockWidth,iBottom,KVI_OPTION_MIRCCOLOR((unsigned char)m_iCurBack));
 
478
                }
 
479
        }
 
480
 
 
481
        pa->drawText(iCurXPos,iTextBaseline,szTmp);
 
482
 
 
483
        if(m_bCurBold)
 
484
                pa->drawText(iCurXPos+1,iTextBaseline,szTmp);
 
485
        if(m_bCurUnderline)
 
486
                pa->drawLine(iCurXPos,iTextBaseline + fm->descent(),iCurXPos+m_iBlockWidth,iTextBaseline + fm->descent());
 
487
}
 
488
 
 
489
QChar KviInputEditor::getSubstituteChar(unsigned short uControlCode)
 
490
{
 
491
        switch(uControlCode)
 
492
        {
 
493
                case KviControlCodes::Color:
 
494
                        return QChar('K');
 
495
                        break;
 
496
                case KviControlCodes::Bold:
 
497
                        return QChar('B');
 
498
                        break;
 
499
                case KviControlCodes::Reset:
 
500
                        return QChar('O');
 
501
                        break;
 
502
                case KviControlCodes::Reverse:
 
503
                        return QChar('R');
 
504
                        break;
 
505
                case KviControlCodes::Underline:
 
506
                        return QChar('U');
 
507
                        break;
 
508
                case KviControlCodes::CryptEscape:
 
509
                        return QChar('P');
 
510
                        break;
 
511
                case KviControlCodes::Icon:
 
512
                        return QChar('I');
 
513
                        break;
 
514
                default:
 
515
                        return QChar(uControlCode);
 
516
                        break;
 
517
        }
 
518
}
 
519
 
 
520
void KviInputEditor::extractNextBlock(int iIdx, QFontMetrics *fm, int iCurXPos, int iMaxXPos)
 
521
{
 
522
        m_iBlockLen = 0;
 
523
        m_iBlockWidth = 0;
 
524
 
 
525
        QChar c = m_szTextBuffer[iIdx];
 
526
 
 
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))))
 
535
        {
 
536
                m_bControlBlock = false;
 
537
                //Not a control code...run..
 
538
                while((iIdx < ((int)(m_szTextBuffer.length()))) && (iCurXPos < iMaxXPos))
 
539
                {
 
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))))
 
549
                        {
 
550
                                m_iBlockLen++;
 
551
                                int iXxx = (c.unicode() < 256) ? KviInputEditor::g_iInputFontCharWidth[c.unicode()] : fm->width(c);
 
552
                                m_iBlockWidth += iXxx;
 
553
                                iCurXPos      += iXxx;
 
554
                                iIdx++;
 
555
                        } else break;
 
556
                }
 
557
                return;
 
558
        } else {
 
559
                m_bControlBlock = true;
 
560
                m_iBlockLen = 1;
 
561
                m_iBlockWidth = KviInputEditor::g_iInputFontCharWidth[c.unicode()];
 
562
                //Control code
 
563
                switch(c.unicode())
 
564
                {
 
565
                        case KviControlCodes::Bold:
 
566
                                m_bCurBold = ! m_bCurBold;
 
567
                                break;
 
568
                        case KviControlCodes::Underline:
 
569
                                m_bCurUnderline = ! m_bCurUnderline;
 
570
                                break;
 
571
                        case KviControlCodes::Reset:
 
572
                                m_iCurFore = KVI_INPUT_DEF_FORE;
 
573
                                m_iCurBack = KVI_INPUT_DEF_BACK;
 
574
                                m_bCurBold = false;
 
575
                                m_bCurUnderline = false;
 
576
                                break;
 
577
                        case KviControlCodes::Reverse:
 
578
                        {
 
579
                                char cAuxClr = m_iCurFore;
 
580
                                m_iCurFore  = m_iCurBack;
 
581
                                m_iCurBack  = cAuxClr;
 
582
                        }
 
583
                        break;
 
584
                        case KviControlCodes::CryptEscape:
 
585
                        case KviControlCodes::Icon:
 
586
                                // makes a single block
 
587
                                break;
 
588
                        case KviControlCodes::Color:
 
589
                        {
 
590
                                iIdx++;
 
591
                                if(iIdx >= ((int)(m_szTextBuffer.length())))
 
592
                                        return;
 
593
 
 
594
                                unsigned char uFore;
 
595
                                unsigned char uBack;
 
596
                                iIdx = KviControlCodes::getUnicodeColorBytes(m_szTextBuffer,iIdx,&uFore,&uBack);
 
597
                                if(uFore != KviControlCodes::NoChange)
 
598
                                {
 
599
                                        m_iCurFore = uFore;
 
600
                                        if(uBack != KviControlCodes::NoChange)
 
601
                                                m_iCurBack = uBack;
 
602
                                } else {
 
603
                                        // ONLY a CTRL+K
 
604
                                        m_iCurBack = KVI_INPUT_DEF_BACK;
 
605
                                        m_iCurFore = KVI_INPUT_DEF_FORE;
 
606
                                }
 
607
                        }
 
608
                        break;
 
609
                        default:
 
610
                                qDebug("Ops..");
 
611
                                exit(0);
 
612
                        break;
 
613
                }
 
614
        }
 
615
}
 
616
 
 
617
void KviInputEditor::runUpToTheFirstVisibleChar()
 
618
{
 
619
        register int iIdx = 0;
 
620
        while(iIdx < m_iFirstVisibleChar)
 
621
        {
 
622
                unsigned short uChar = m_szTextBuffer[iIdx].unicode();
 
623
                if(uChar < 32)
 
624
                {
 
625
                        switch(uChar)
 
626
                        {
 
627
                                case KviControlCodes::Bold:
 
628
                                        m_bCurBold = ! m_bCurBold;
 
629
                                        break;
 
630
                                case KviControlCodes::Underline:
 
631
                                        m_bCurUnderline = ! m_bCurUnderline;
 
632
                                        break;
 
633
                                case KviControlCodes::Reset:
 
634
                                        m_iCurFore = KVI_INPUT_DEF_FORE;
 
635
                                        m_iCurBack = KVI_INPUT_DEF_BACK;
 
636
                                        m_bCurBold = false;
 
637
                                        m_bCurUnderline = false;
 
638
                                        break;
 
639
                                case KviControlCodes::Reverse:
 
640
                                {
 
641
                                        char cAuxClr = m_iCurFore;
 
642
                                        m_iCurFore = m_iCurBack;
 
643
                                        m_iCurBack = cAuxClr;
 
644
                                }
 
645
                                break;
 
646
                                case KviControlCodes::Color:
 
647
                                {
 
648
                                        iIdx++;
 
649
                                        if(iIdx >= ((int)(m_szTextBuffer.length())))return;
 
650
                                        unsigned char uFore;
 
651
                                        unsigned char uBack;
 
652
                                        iIdx = KviControlCodes::getUnicodeColorBytes(m_szTextBuffer,iIdx,&uFore,&uBack);
 
653
                                        iIdx--;
 
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;
 
658
                                }
 
659
                                break;
 
660
                                case 0:
 
661
                                        qDebug("KviInputEditor::Encountered invisible end of the string!");
 
662
                                        exit(0);
 
663
                                break;
 
664
                        }
 
665
                }
 
666
                iIdx++;
 
667
        }
 
668
}
 
669
 
 
670
void KviInputEditor::mouseDoubleClickEvent(QMouseEvent * e)
 
671
{
 
672
        //select clicked word
 
673
        if(e->button() & Qt::LeftButton)
 
674
        {
 
675
                if(m_szTextBuffer.length()<1)
 
676
                        return;
 
677
                int iCursor = charIndexFromXPosition(e->pos().x());
 
678
                int iLen=m_szTextBuffer.length()-1;
 
679
                if(iCursor>iLen)
 
680
                        iCursor=iLen;
 
681
                if(!m_szTextBuffer.at(iCursor).isLetterOrNumber())
 
682
                        return;
 
683
                //search word init
 
684
                m_iSelectionBegin = iCursor;
 
685
                while(m_iSelectionBegin > 0)
 
686
                {
 
687
                        if(!m_szTextBuffer.at(m_iSelectionBegin-1).isLetterOrNumber())
 
688
                                        break;
 
689
                        m_iSelectionBegin--;
 
690
                }
 
691
                //ensure that the begin of the selection is visible
 
692
                if(m_iFirstVisibleChar>m_iSelectionBegin)
 
693
                        m_iFirstVisibleChar=m_iSelectionBegin;
 
694
 
 
695
                //search word end
 
696
                m_iSelectionEnd = iCursor;
 
697
                while(m_iSelectionEnd < iLen)
 
698
                {
 
699
                        if(!m_szTextBuffer.at(m_iSelectionEnd+1).isLetterOrNumber())
 
700
                                        break;
 
701
                        m_iSelectionEnd++;
 
702
                }
 
703
                if(m_iSelectionEnd==((int)(m_szTextBuffer.length())))
 
704
                        m_iSelectionEnd--;
 
705
                //all-in-one: move cursor at the end of the selection, ensure it's visible and repaint
 
706
                moveCursorTo(m_iSelectionEnd, true);
 
707
                m_iCursorPosition++;
 
708
                killDragTimer();
 
709
        }
 
710
}
 
711
 
 
712
void KviInputEditor::mousePressEvent(QMouseEvent * e)
 
713
{
 
714
        if(e->button() & Qt::LeftButton)
 
715
        {
 
716
                m_iCursorPosition = charIndexFromXPosition(e->pos().x());
 
717
                //move the cursor to
 
718
                int iAnchorX = xPositionFromCharIndex(m_iCursorPosition);
 
719
                if(iAnchorX > width()) m_iFirstVisibleChar++;
 
720
                m_iSelectionAnchorChar = m_iCursorPosition;
 
721
                selectOneChar(-1);
 
722
                //grabMouse(QCursor(crossCursor));
 
723
                repaintWithCursorOn();
 
724
                killDragTimer();
 
725
                m_iDragTimer = startTimer(KVI_INPUT_DRAG_TIMEOUT);
 
726
 
 
727
        } else if(e->button() & Qt::RightButton)
 
728
        {
 
729
                int iType = g_pActiveWindow->type();
 
730
 
 
731
                //Popup menu
 
732
                g_pInputPopup->clear();
 
733
 
 
734
                QString szClip;
 
735
 
 
736
                QClipboard * pClip = QApplication::clipboard();
 
737
                if(pClip)
 
738
                {
 
739
                        szClip = pClip->text(QClipboard::Clipboard);
 
740
 
 
741
                        int iOcc = szClip.count(QChar('\n'));
 
742
 
 
743
                        if(!szClip.isEmpty())
 
744
                        {
 
745
                                if(szClip.length() > 60)
 
746
                                {
 
747
                                        szClip.truncate(60);
 
748
                                        szClip.append("...");
 
749
                                }
 
750
                                szClip.replace(QChar('&'),"&amp;");
 
751
                                szClip.replace(QChar('<'),"&lt;");
 
752
                                szClip.replace(QChar('>'),"&gt;");
 
753
                                szClip.replace(QChar('\n'),"<br>");
 
754
 
 
755
                                QString szLabel = "<center><b>";
 
756
                                szLabel += __tr2qs("Clipboard");
 
757
                                szLabel += ":</b><br>";
 
758
                                szLabel += szClip;
 
759
                                szLabel += "<br><b>";
 
760
 
 
761
                                QString szNum;
 
762
                                szNum.setNum(iOcc);
 
763
 
 
764
                                szLabel += szNum;
 
765
                                szLabel += QChar(' ');
 
766
                                szLabel += (iOcc == 1) ? __tr2qs("line break") : __tr2qs("line breaks");
 
767
                                szLabel += "</b></center>";
 
768
 
 
769
                                QLabel * pLabel = new QLabel(szLabel,g_pInputPopup);
 
770
                                pLabel->setFrameStyle(QFrame::Raised | QFrame::StyledPanel);
 
771
                                pLabel->setMargin(5);
 
772
 
 
773
                                delete pLabel;
 
774
                        }
 
775
                }
 
776
 
 
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);
 
790
                else
 
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);
 
795
                else
 
796
                        g_pInputPopup->setItemEnabled(iId,!m_bReadOnly);
 
797
                if(m_bSpSlowFlag ==true)
 
798
                {
 
799
                        iId = g_pInputPopup->insertItem(__tr2qs("Stop Paste"),this,SLOT(stopPasteSlow())); /*G&N 2005*/
 
800
                }
 
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()));
 
806
 
 
807
                g_pInputPopup->insertSeparator();
 
808
                m_pIconMenu->clear();
 
809
 
 
810
                KviPointerHashTable<QString,KviTextIcon> * d = g_pTextIconManager->textIconDict();
 
811
                KviPointerHashTableIterator<QString,KviTextIcon> it(*d);
 
812
                QStringList szList;
 
813
 
 
814
                while(it.current())
 
815
                {
 
816
                        szList.append(it.currentKey());
 
817
                        ++it;
 
818
                }
 
819
                szList.sort();
 
820
 
 
821
                KviTextIcon * pIcon;
 
822
                QPixmap * pPix;
 
823
 
 
824
                for(QStringList::Iterator iter = szList.begin(); iter != szList.end(); ++iter)
 
825
                {
 
826
                        pIcon = g_pTextIconManager->lookupTextIcon(*iter);
 
827
                        if(pIcon)
 
828
                        {
 
829
                                pPix = pIcon->pixmap();
 
830
                                if(pPix) m_pIconMenu->insertItem(*pPix,*iter);
 
831
                        }
 
832
                }
 
833
 
 
834
                g_pInputPopup->insertItem(*(g_pIconManager->getSmallIcon(KviIconManager::BigGrin)),__tr2qs("Insert Icon"),m_pIconMenu);
 
835
 
 
836
                QInputContext *qic = g_pApp->inputContext();
 
837
                if (qic) {
 
838
                        QList<QAction *> imActions = qic->actions();
 
839
                        for (int i = 0; i < imActions.size(); ++i)
 
840
                                g_pInputPopup->addAction(imActions.at(i));
 
841
                }
 
842
 
 
843
                g_pInputPopup->popup(mapToGlobal(e->pos()));
 
844
        } else {
 
845
                pasteSelectionWithConfirmation();
 
846
        }
 
847
}
 
848
 
 
849
void KviInputEditor::iconPopupActivated(int iId)
 
850
{
 
851
        if(!m_bReadOnly)
 
852
        {
 
853
                QString szText = m_pIconMenu->text(iId);
 
854
                if(!szText.isEmpty())
 
855
                {
 
856
                        szText.prepend(KviControlCodes::Icon);
 
857
                        szText.append(' ');
 
858
                        insertText(szText);
 
859
                }
 
860
        }
 
861
}
 
862
 
 
863
bool KviInputEditor::hasSelection()
 
864
{
 
865
        return ((m_iSelectionBegin != -1) && (m_iSelectionEnd != -1));
 
866
}
 
867
 
 
868
void KviInputEditor::copyToClipboard()
 
869
{
 
870
        if(!hasSelection()) return;
 
871
        QClipboard * pClip = QApplication::clipboard();
 
872
        if(!pClip) return;
 
873
        QString szTxt = m_szTextBuffer.mid(m_iSelectionBegin,(m_iSelectionEnd-m_iSelectionBegin)+1);
 
874
        pClip->setText(szTxt,QClipboard::Clipboard);
 
875
        repaintWithCursorOn();
 
876
}
 
877
 
 
878
void KviInputEditor::copyToSelection(bool bDonNotCopyToClipboard)
 
879
{
 
880
        if(!hasSelection()) return;
 
881
        QClipboard * pClip = QApplication::clipboard();
 
882
        if(!pClip) return;
 
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();
 
889
}
 
890
 
 
891
void KviInputEditor::moveCursorTo(int iIdx, bool bRepaint)
 
892
{
 
893
        if(iIdx < 0) iIdx = 0;
 
894
        if(iIdx > ((int)(m_szTextBuffer.length()))) iIdx = m_szTextBuffer.length();
 
895
        if(iIdx > m_iCursorPosition)
 
896
        {
 
897
                while(m_iCursorPosition < iIdx)
 
898
                {
 
899
                        moveRightFirstVisibleCharToShowCursor();
 
900
                        m_iCursorPosition++;
 
901
                }
 
902
        } else {
 
903
                m_iCursorPosition = iIdx;
 
904
                if(m_iFirstVisibleChar > m_iCursorPosition)m_iFirstVisibleChar = m_iCursorPosition;
 
905
        }
 
906
        if(bRepaint)
 
907
                repaintWithCursorOn();
 
908
}
 
909
 
 
910
void KviInputEditor::removeSelected()
 
911
{
 
912
        if(!hasSelection())
 
913
                return;
 
914
 
 
915
        addUndo(new EditCommand(EditCommand::RemoveText,m_szTextBuffer.mid(m_iSelectionBegin, m_iSelectionEnd-m_iSelectionBegin+1),m_iSelectionBegin));
 
916
 
 
917
        m_szTextBuffer.remove(m_iSelectionBegin,(m_iSelectionEnd-m_iSelectionBegin)+1);
 
918
        moveCursorTo(m_iSelectionBegin,false);
 
919
        selectOneChar(-1);
 
920
        repaintWithCursorOn();
 
921
}
 
922
 
 
923
void KviInputEditor::cut()
 
924
{
 
925
        if(!hasSelection())
 
926
                return;
 
927
        QClipboard * pClip = QApplication::clipboard();
 
928
        if(!pClip)
 
929
                return;
 
930
        pClip->setText(m_szTextBuffer.mid(m_iSelectionBegin,(m_iSelectionEnd-m_iSelectionBegin)+1),QClipboard::Clipboard);
 
931
 
 
932
        addUndo(new EditCommand(EditCommand::RemoveText,m_szTextBuffer.mid(m_iSelectionBegin, m_iSelectionEnd-m_iSelectionBegin+1),m_iSelectionBegin));
 
933
 
 
934
        m_szTextBuffer.remove(m_iSelectionBegin,(m_iSelectionEnd-m_iSelectionBegin)+1);
 
935
        moveCursorTo(m_iSelectionBegin,false);
 
936
        selectOneChar(-1);
 
937
        repaintWithCursorOn();
 
938
}
 
939
 
 
940
void KviInputEditor::insertText(const QString & szTxt)
 
941
{
 
942
        QString szText = szTxt; // crop away constness
 
943
        if(szText.isEmpty())return;
 
944
 
 
945
        szText.replace('\t',QString(KVI_OPTION_UINT(KviOption_uintSpacesToExpandTabulationInput),' ')); //expand tabs to spaces
 
946
 
 
947
        m_bUpdatesEnabled = false;
 
948
        removeSelected();
 
949
        m_bUpdatesEnabled = true;
 
950
 
 
951
        if(szText.indexOf('\n') == -1)
 
952
        {
 
953
                addUndo(new EditCommand(EditCommand::InsertText,szText,m_iCursorPosition));
 
954
 
 
955
                m_szTextBuffer.insert(m_iCursorPosition,szText);
 
956
                m_szTextBuffer.truncate(m_iMaxBufferSize);
 
957
                moveCursorTo(m_iCursorPosition + szText.length());
 
958
        } else {
 
959
                //Multiline paste...do not execute commands here
 
960
                QString szBlock;
 
961
                while(!szText.isEmpty())
 
962
                {
 
963
                        int iIdx = szText.indexOf('\n');
 
964
                        if(iIdx != -1)
 
965
                        {
 
966
                                szBlock = szText.left(iIdx);
 
967
                                //else szBlock = QChar(KviControlCodes::Reset);
 
968
                                szText.remove(0,iIdx+1);
 
969
                        } else {
 
970
                                szBlock = szText;
 
971
                                szText  = "";
 
972
                        }
 
973
 
 
974
                        m_szTextBuffer.insert(m_iCursorPosition,szBlock);
 
975
                        m_szTextBuffer.truncate(m_iMaxBufferSize);
 
976
 
 
977
                        int iPos = 0;
 
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,"\\");
 
980
 
 
981
                        returnPressed(iIdx != -1);
 
982
                }
 
983
        }
 
984
}
 
985
 
 
986
int KviInputEditor::replaceSegment(int iStart, int iLength, const QString & szText)
 
987
{
 
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();
 
994
 
 
995
        int iInsertedLength = szText.length();
 
996
        int iMaxInsertedLength = m_iMaxBufferSize - iStart;
 
997
        if(iInsertedLength > iMaxInsertedLength) return iMaxInsertedLength;
 
998
        return iInsertedLength;
 
999
}
 
1000
 
 
1001
void KviInputEditor::pasteClipboardWithConfirmation()
 
1002
{
 
1003
        QClipboard * pClip = QApplication::clipboard();
 
1004
        if(!pClip) return;
 
1005
        QString szText = pClip->text(QClipboard::Clipboard);
 
1006
 
 
1007
        if(KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnInputBarPaste,m_pKviWindow,m_pKviWindow->id(),szText))
 
1008
                return;
 
1009
 
 
1010
        if(szText.contains(QChar('\n')) > 0)
 
1011
        {
 
1012
                if(m_pInputParent->inherits("KviInput"))
 
1013
                        ((KviInput*)(m_pInputParent))->multiLinePaste(szText);
 
1014
        } else {
 
1015
                insertText(szText);
 
1016
        }
 
1017
}
 
1018
 
 
1019
void KviInputEditor::pasteSelectionWithConfirmation()
 
1020
{
 
1021
        QClipboard * pClip = QApplication::clipboard();
 
1022
        if(!pClip) return;
 
1023
        QString szText = pClip->text(pClip->supportsSelection() ? QClipboard::Selection : QClipboard::Clipboard);
 
1024
 
 
1025
        if(KVS_TRIGGER_EVENT_2_HALTED(KviEvent_OnInputBarPaste,m_pKviWindow,m_pKviWindow->id(),szText))
 
1026
                return;
 
1027
 
 
1028
        if(szText.contains(QChar('\n')) > 0)
 
1029
        {
 
1030
                if(m_pInputParent->inherits("KviInput"))
 
1031
                        ((KviInput*)(m_pInputParent))->multiLinePaste(szText);
 
1032
        } else {
 
1033
                insertText(szText);
 
1034
        }
 
1035
}
 
1036
 
 
1037
void KviInputEditor::pasteSlow()
 
1038
{
 
1039
        KviKvsScript::run("spaste.clipboard",g_pActiveWindow);
 
1040
        m_bSpSlowFlag = true;
 
1041
}
 
1042
 
 
1043
void KviInputEditor::stopPasteSlow()
 
1044
{
 
1045
        KviKvsScript::run("spaste.stop",g_pActiveWindow);
 
1046
        m_bSpSlowFlag = false;
 
1047
}
 
1048
 
 
1049
void KviInputEditor::pasteFile()
 
1050
{
 
1051
        QString szTmp = QFileDialog::getOpenFileName(this,"Choose a file","","");
 
1052
        if(!szTmp.isEmpty())
 
1053
        {
 
1054
                KviQString::escapeKvs(&szTmp, KviQString::EscapeSpace);
 
1055
                szTmp.prepend("spaste.file ");
 
1056
                KviKvsScript::run(szTmp, g_pActiveWindow);
 
1057
                m_bSpSlowFlag = true;
 
1058
        }
 
1059
}
 
1060
 
 
1061
void KviInputEditor::selectAll()
 
1062
{
 
1063
        if(m_szTextBuffer.length() > 0)
 
1064
        {
 
1065
                m_iSelectionBegin = 0;
 
1066
                m_iSelectionEnd = m_szTextBuffer.length()-1;
 
1067
        }
 
1068
        end();
 
1069
}
 
1070
 
 
1071
void KviInputEditor::clear()
 
1072
{
 
1073
        addUndo(new EditCommand(EditCommand::RemoveText,m_szTextBuffer,0));
 
1074
        m_szTextBuffer = "";
 
1075
        selectOneChar(-1);
 
1076
        home();
 
1077
}
 
1078
 
 
1079
void KviInputEditor::setText(const QString szText)
 
1080
{
 
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);
 
1085
        selectOneChar(-1);
 
1086
        end();
 
1087
}
 
1088
 
 
1089
void KviInputEditor::mouseReleaseEvent(QMouseEvent *)
 
1090
{
 
1091
        if(m_iDragTimer)
 
1092
        {
 
1093
                m_iSelectionAnchorChar =-1;
 
1094
                //releaseMouse();
 
1095
                killDragTimer();
 
1096
        }
 
1097
        if(hasSelection()) copyToSelection();
 
1098
}
 
1099
 
 
1100
void KviInputEditor::killDragTimer()
 
1101
{
 
1102
        if(m_iDragTimer)
 
1103
        {
 
1104
                killTimer(m_iDragTimer);
 
1105
                m_iDragTimer = 0;
 
1106
        }
 
1107
}
 
1108
 
 
1109
void KviInputEditor::timerEvent(QTimerEvent * e)
 
1110
{
 
1111
        if(e->timerId() == m_iCursorTimer)
 
1112
        {
 
1113
                if(!hasFocus() || !isVisible())
 
1114
                {
 
1115
                        killTimer(m_iCursorTimer);
 
1116
                        m_iCursorTimer = 0;
 
1117
                        m_bCursorOn = false;
 
1118
                } else m_bCursorOn = ! m_bCursorOn;
 
1119
                update();
 
1120
        } else {
 
1121
                //Drag timer
 
1122
                handleDragSelection();
 
1123
        }
 
1124
}
 
1125
 
 
1126
void KviInputEditor::handleDragSelection()
 
1127
{
 
1128
        if(m_iSelectionAnchorChar == -1)
 
1129
                return;
 
1130
 
 
1131
        if(m_iSelectionAnchorChar > m_szTextBuffer.length()) // may happen if hitting backspace or del while dragging
 
1132
                m_iSelectionAnchorChar = m_szTextBuffer.length();
 
1133
 
 
1134
        QPoint pnt = mapFromGlobal(QCursor::pos());
 
1135
 
 
1136
        if(pnt.x() <= 0)
 
1137
        {
 
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())))
 
1145
                {
 
1146
                        moveRightFirstVisibleCharToShowCursor();
 
1147
                        m_iCursorPosition++;
 
1148
                } //else at the end of the selection...don't move anything
 
1149
        } else {
 
1150
                //Inside the window...
 
1151
                m_iCursorPosition = charIndexFromXPosition(pnt.x());
 
1152
        }
 
1153
 
 
1154
        if(m_iCursorPosition == m_iSelectionAnchorChar) selectOneChar(-1);
 
1155
        else {
 
1156
                if(m_iCursorPosition > m_iSelectionAnchorChar)
 
1157
                {
 
1158
                        m_iSelectionBegin = m_iSelectionAnchorChar;
 
1159
                        m_iSelectionEnd   = m_iCursorPosition-1;
 
1160
                } else {
 
1161
                        m_iSelectionBegin = m_iCursorPosition;
 
1162
                        m_iSelectionEnd   = m_iSelectionAnchorChar-1;
 
1163
                }
 
1164
        }
 
1165
        repaintWithCursorOn();
 
1166
}
 
1167
 
 
1168
void KviInputEditor::returnPressed(bool)
 
1169
{
 
1170
        if (!m_szTextBuffer.isEmpty() /* && (!m_pHistory->current() || m_szTextBuffer.compare(*(m_pHistory->current())))*/)
 
1171
        {
 
1172
                if(m_pInputParent->inherits("KviInput"))
 
1173
                        KviInputHistory::instance()->add(new QString(m_szTextBuffer));
 
1174
 
 
1175
                m_pHistory->insert(0,new QString(m_szTextBuffer));
 
1176
        }
 
1177
 
 
1178
        //ensure the color window is hidden (bug #835)
 
1179
        if(g_pColorWindow)
 
1180
                if(g_pColorWindow->isVisible())
 
1181
                        g_pColorWindow->hide();
 
1182
 
 
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();
 
1186
 
 
1187
        m_iCurHistoryIdx = -1;
 
1188
 
 
1189
        emit enterPressed();
 
1190
}
 
1191
 
 
1192
void KviInputEditor::clearUndoStack()
 
1193
{
 
1194
        if(m_pUndoStack)
 
1195
        {
 
1196
                delete m_pUndoStack;
 
1197
                m_pUndoStack = NULL;
 
1198
        }
 
1199
        
 
1200
        if(m_pRedoStack)
 
1201
        {
 
1202
                delete m_pRedoStack;
 
1203
                m_pRedoStack = NULL;
 
1204
        }
 
1205
}
 
1206
 
 
1207
void KviInputEditor::focusInEvent(QFocusEvent *)
 
1208
{
 
1209
        if(m_iCursorTimer==0)
 
1210
        {
 
1211
                m_iCursorTimer = startTimer(KVI_INPUT_BLINK_TIME);
 
1212
                m_bCursorOn = true;
 
1213
                update();
 
1214
        }
 
1215
}
 
1216
 
 
1217
void KviInputEditor::focusOutEvent(QFocusEvent *)
 
1218
{
 
1219
        if(m_iCursorTimer) killTimer(m_iCursorTimer);
 
1220
        m_iCursorTimer = 0;
 
1221
        m_bCursorOn = false;
 
1222
        update();
 
1223
}
 
1224
 
 
1225
void KviInputEditor::internalCursorRight(bool bShift)
 
1226
{
 
1227
        if(m_iCursorPosition >= ((int)(m_szTextBuffer.length()))) return;
 
1228
        moveRightFirstVisibleCharToShowCursor();
 
1229
        //Grow the selection if needed
 
1230
        if(bShift)
 
1231
        {
 
1232
                if((m_iSelectionBegin > -1)&&(m_iSelectionEnd > -1))
 
1233
                {
 
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++;
 
1240
}
 
1241
 
 
1242
void KviInputEditor::internalCursorLeft(bool bShift)
 
1243
{
 
1244
        if(m_iCursorPosition <= 0) return;
 
1245
 
 
1246
        if(bShift)
 
1247
        {
 
1248
                if((m_iSelectionBegin > -1) && (m_iSelectionEnd > -1))
 
1249
                {
 
1250
                        if(m_iSelectionBegin == m_iCursorPosition)
 
1251
                                m_iSelectionBegin--;
 
1252
                        else if(m_iSelectionEnd == m_iCursorPosition-1)
 
1253
                                m_iSelectionEnd--;
 
1254
                        else selectOneChar(m_iCursorPosition - 1);
 
1255
                } else selectOneChar(m_iCursorPosition - 1);
 
1256
        } else selectOneChar(-1);
 
1257
 
 
1258
        m_iCursorPosition--;
 
1259
        if(m_iFirstVisibleChar > m_iCursorPosition) m_iFirstVisibleChar--;
 
1260
}
 
1261
 
 
1262
void KviInputEditor::inputMethodEvent(QInputMethodEvent * e)
 
1263
{
 
1264
        if (m_bReadOnly) {
 
1265
                e->ignore();
 
1266
                return;
 
1267
        }
 
1268
 
 
1269
        if(!m_bIMComposing)
 
1270
        {
 
1271
                removeSelected();
 
1272
                m_iIMStart = m_iIMSelectionBegin = m_iCursorPosition;
 
1273
                m_iIMLength = 0;
 
1274
                m_bIMComposing = true;
 
1275
        }
 
1276
 
 
1277
        m_bUpdatesEnabled = false;
 
1278
 
 
1279
        m_iIMLength = replaceSegment(m_iIMStart, m_iIMLength, e->commitString());
 
1280
 
 
1281
        // update selection inside the pre-edit
 
1282
        m_iIMSelectionBegin = m_iIMStart + e->replacementStart();
 
1283
        m_iIMSelectionLength = e->replacementLength();
 
1284
        moveCursorTo(m_iIMSelectionBegin);
 
1285
 
 
1286
        if (e->commitString().isEmpty())
 
1287
        {
 
1288
                if(e->preeditString().isEmpty())
 
1289
                {
 
1290
                        m_bIMComposing = false;
 
1291
                        m_iIMStart = 0;
 
1292
                        m_iIMLength = 0;
 
1293
                } else {
 
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);
 
1298
                }
 
1299
        } else {
 
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);
 
1304
                // reset data
 
1305
                m_bIMComposing = false;
 
1306
                m_iIMStart = 0;
 
1307
                m_iIMLength = 0;
 
1308
        }
 
1309
 
 
1310
        // repaint
 
1311
        m_bUpdatesEnabled = true;
 
1312
 
 
1313
        repaintWithCursorOn();
 
1314
}
 
1315
 
 
1316
void KviInputEditor::installShortcuts()
 
1317
{
 
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);
 
1371
}
 
1372
 
 
1373
void KviInputEditor::zoomIn()
 
1374
{
 
1375
        if(m_pKviWindow)
 
1376
                if(m_pKviWindow->view())
 
1377
                        m_pKviWindow->view()->increaseFontSize();
 
1378
}
 
1379
 
 
1380
void KviInputEditor::zoomOut()
 
1381
{
 
1382
        if(m_pKviWindow)
 
1383
                if(m_pKviWindow->view())
 
1384
                        m_pKviWindow->view()->decreaseFontSize();
 
1385
}
 
1386
 
 
1387
void KviInputEditor::zoomDefault()
 
1388
{
 
1389
        if(m_pKviWindow)
 
1390
                if(m_pKviWindow->view())
 
1391
                        m_pKviWindow->view()->resetDefaultFont();
 
1392
}
 
1393
 
 
1394
void KviInputEditor::keyPressEvent(QKeyEvent * e)
 
1395
{
 
1396
 
 
1397
        // disable the keyPress handling when IM is in composition.
 
1398
        if(m_bIMComposing)
 
1399
        {
 
1400
                e->ignore();
 
1401
                return;
 
1402
        }
 
1403
        // completion thingies
 
1404
 
 
1405
        if(!m_bReadOnly)
 
1406
        {
 
1407
                if((e->key() == Qt::Key_Tab) || (e->key() == Qt::Key_Backtab))
 
1408
                {
 
1409
                        completion(e->modifiers() & Qt::ShiftModifier);
 
1410
                        return;
 
1411
                } else {
 
1412
                        m_bLastCompletionFinished=1;
 
1413
                }
 
1414
        }
 
1415
 
 
1416
        if(e->modifiers() & Qt::ControlModifier)
 
1417
        {
 
1418
                switch(e->key())
 
1419
                {
 
1420
                        case Qt::Key_J:
 
1421
                        {
 
1422
                                //avoid Ctrl+J from inserting a linefeed
 
1423
                                break;
 
1424
                        }
 
1425
                        default:
 
1426
                                if(!m_bReadOnly) insertText(e->text());
 
1427
                        break;
 
1428
                }
 
1429
                return;
 
1430
        }
 
1431
#if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
 
1432
        if((e->modifiers() & Qt::AltModifier) && (e->modifiers() & Qt::KeypadModifier))
 
1433
        {
 
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))
 
1436
                {
 
1437
                        m_szAltKeyCode = "";
 
1438
                        return;
 
1439
                } else if((e->text().unicode()->toLatin1() >= '0') && (e->text().unicode()->toLatin1() <= '9')) {
 
1440
                        m_szAltKeyCode += e->text().unicode()->toLatin1();
 
1441
                        return;
 
1442
                } else if((e->key() >= Qt::Key_0) && (e->key() <= Qt::Key_9)) {
 
1443
                        m_szAltKeyCode += e->key();
 
1444
                        return;
 
1445
                }
 
1446
 
 
1447
                if(!m_bReadOnly)
 
1448
                        insertText(e->text());
 
1449
 
 
1450
                return;
 
1451
        }
 
1452
#endif
 
1453
        if(!e->text().isEmpty() && !m_bReadOnly)
 
1454
                insertText(e->text());
 
1455
}
 
1456
 
 
1457
void KviInputEditor::keyReleaseEvent(QKeyEvent * e)
 
1458
{
 
1459
#if !defined(COMPILE_ON_WINDOWS) && !defined(COMPILE_ON_MINGW)
 
1460
        if((e->key() == Qt::Key_Alt) || (e->key() == Qt::Key_Meta))
 
1461
        {
 
1462
                if(m_szAltKeyCode.hasData())
 
1463
                {
 
1464
                        bool bOk;
 
1465
                        unsigned short uCh = m_szAltKeyCode.toUShort(&bOk);
 
1466
                        if(bOk && uCh != 0)
 
1467
                        {
 
1468
                                //qDebug("INSERTING CHAR %c",uCh);
 
1469
                                insertChar(QChar(uCh));
 
1470
                                e->accept();
 
1471
                        }
 
1472
                }
 
1473
                m_szAltKeyCode = "";
 
1474
        }
 
1475
#endif
 
1476
        e->ignore();
 
1477
}
 
1478
 
 
1479
 
 
1480
void KviInputEditor::getWordBeforeCursor(QString & szBuffer, bool * bIsFirstWordInLine)
 
1481
{
 
1482
        if(m_szTextBuffer.isEmpty() || m_iCursorPosition <= 0)
 
1483
        {
 
1484
                szBuffer = "";
 
1485
                return;
 
1486
        }
 
1487
 
 
1488
        szBuffer = m_szTextBuffer.left(m_iCursorPosition);
 
1489
 
 
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;
 
1500
}
 
1501
 
 
1502
void KviInputEditor::completionEscapeUnsafeToken(QString &szToken)
 
1503
{
 
1504
        if(!((KviInput *)(m_pInputParent))->isUserFriendly())
 
1505
                KviQString::escapeKvs(&szToken, KviQString::EscapeSpace);
 
1506
}
 
1507
 
 
1508
void KviInputEditor::completion(bool bShift)
 
1509
{
 
1510
        // FIXME: Spaces in directory completion can mess everything completely
 
1511
        //        On windows the characters are breaking everything...
 
1512
        //        Well.... :D
 
1513
 
 
1514
        QString szWord;
 
1515
        QString szMatch;
 
1516
        bool bFirstWordInLine;
 
1517
 
 
1518
        bool bInCommand = m_szTextBuffer.trimmed().indexOf('/') == 0;
 
1519
 
 
1520
        getWordBeforeCursor(szWord,&bFirstWordInLine);
 
1521
        if(szWord.isEmpty())
 
1522
        {
 
1523
                if(m_szLastCompletedNick.isEmpty())
 
1524
                        return; // nothing to complete
 
1525
 
 
1526
                // this is standard nick completion continued
 
1527
                standardNickCompletion(bShift,szWord,bFirstWordInLine,bInCommand);
 
1528
                repaintWithCursorOn();
 
1529
                return;
 
1530
        }
 
1531
        int iOffset;
 
1532
        if(KviQString::equalCI(m_szTextBuffer.left(5),"/help") || KviQString::equalCI(m_szTextBuffer.left(5),"/help.open")) iOffset=1;
 
1533
        else iOffset=0;
 
1534
 
 
1535
        KviPointerList<QString> tmp;
 
1536
        tmp.setAutoDelete(true);
 
1537
 
 
1538
        bool bIsCommand = false;
 
1539
        bool bIsFunction = false;
 
1540
        bool bIsDir = false;
 
1541
        bool bIsNick = false;
 
1542
 
 
1543
        unsigned short uc = szWord[0].unicode();
 
1544
 
 
1545
 
 
1546
        if(uc == '/' || iOffset)
 
1547
        {
 
1548
                if(szWord[1-iOffset].unicode()=='$')
 
1549
                {
 
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
 
1555
                        bIsFunction = true;
 
1556
                }
 
1557
                else if(bFirstWordInLine || iOffset)
 
1558
                {
 
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
 
1564
                        bIsCommand = true;
 
1565
                } else {
 
1566
                        // directory completion attempt
 
1567
                        g_pApp->completeDirectory(szWord,&tmp);
 
1568
                        bIsDir = true;
 
1569
                }
 
1570
        } else if(uc == '$')
 
1571
        {
 
1572
                // function/identifer completion
 
1573
                szWord.remove(0,1);
 
1574
                if(szWord.isEmpty()) return;
 
1575
                KviKvsKernel::instance()->completeFunction(szWord,&tmp);
 
1576
                bIsFunction = true;
 
1577
        } else if(uc == '#' || uc == '&' || uc == '!')
 
1578
        {
 
1579
                if(m_pKviWindow)
 
1580
                {
 
1581
                        if( (szWord.length()==1) && (m_pKviWindow->windowName()[0].unicode()==uc))
 
1582
                        {
 
1583
                                szMatch=m_pKviWindow->windowName();
 
1584
                                completionEscapeUnsafeToken(szMatch);
 
1585
                                szMatch.append(" ");
 
1586
                                replaceWordBeforeCursor(szWord,szMatch,false);
 
1587
                                repaintWithCursorOn();
 
1588
                                return;
 
1589
                        }
 
1590
                        if(m_pKviWindow->console())
 
1591
                                m_pKviWindow->console()->completeChannel(szWord,&tmp);
 
1592
                }
 
1593
 
 
1594
        //FIXME: Complete also on irc:// starting strings, not only irc.?
 
1595
        } else if(KviQString::equalCIN(szWord,"irc.",4))
 
1596
        {
 
1597
                // irc server name
 
1598
                if(m_pKviWindow)
 
1599
                        if(m_pKviWindow->console())
 
1600
                                m_pKviWindow->console()->completeServer(szWord,&tmp);
 
1601
        } else {
 
1602
                // empty word will end up here
 
1603
                if(m_pUserListView)
 
1604
                {
 
1605
                        if(KVI_OPTION_BOOL(KviOption_boolZshLikeNickCompletion))
 
1606
                        {
 
1607
                                if(m_szLastCompletedNick.isEmpty())
 
1608
                                {
 
1609
                                        //first round of zsh completion
 
1610
                                        m_pUserListView->completeNickBashLike(szWord,&tmp,bShift);
 
1611
                                        bIsNick = true;
 
1612
                                        m_szLastCompletedNick=szWord;
 
1613
                                } else {
 
1614
                                        standardNickCompletion(bShift,szWord,bFirstWordInLine,bInCommand);
 
1615
                                        repaintWithCursorOn();
 
1616
                                        return;
 
1617
                                }
 
1618
                        } else if(KVI_OPTION_BOOL(KviOption_boolBashLikeNickCompletion))
 
1619
                        {
 
1620
                                m_pUserListView->completeNickBashLike(szWord,&tmp,bShift);
 
1621
                                bIsNick = true;
 
1622
                        } else {
 
1623
                                standardNickCompletion(bShift,szWord,bFirstWordInLine,bInCommand);
 
1624
                                repaintWithCursorOn();
 
1625
                                return;
 
1626
                        }
 
1627
                }
 
1628
        }
 
1629
 
 
1630
        // Lookup the longest exact match
 
1631
        if(tmp.count() > 0)
 
1632
        {
 
1633
                if(tmp.count() == 1)
 
1634
                {
 
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('(');
 
1639
                        else if(bIsNick)
 
1640
                        {
 
1641
                                if(!KVI_OPTION_STRING(KviOption_stringNickCompletionPostfix).isEmpty())
 
1642
                                {
 
1643
                                        if(bFirstWordInLine || (!KVI_OPTION_BOOL(KviOption_boolUseNickCompletionPostfixForFirstWordOnly)))
 
1644
                                                szMatch.append(KVI_OPTION_STRING(KviOption_stringNickCompletionPostfix));
 
1645
                                }
 
1646
                        }
 
1647
 
 
1648
                        if(bInCommand && !bIsCommand)
 
1649
                        {
 
1650
                                // escape crazy things like Nick\nquit
 
1651
                                completionEscapeUnsafeToken(szMatch);
 
1652
                        }
 
1653
                } else {
 
1654
                        QString szAll;
 
1655
                        QString * szTmp = tmp.first();
 
1656
                        szMatch = *szTmp;
 
1657
                        int iWLen = szWord.length();
 
1658
                        if (szMatch.left(1)=='$')szMatch.remove(0,1);
 
1659
                        for(; szTmp; szTmp = tmp.next())
 
1660
                        {
 
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);
 
1674
                        }
 
1675
                        if(m_pKviWindow)
 
1676
                                m_pKviWindow->output(KVI_OUT_SYSTEMMESSAGE,__tr2qs("%d matches: %Q"),tmp.count(),&szAll);
 
1677
                }
 
1678
        } else
 
1679
                if(m_pKviWindow)
 
1680
                        m_pKviWindow->outputNoFmt(KVI_OUT_SYSTEMMESSAGE,__tr2qs("No matches"));
 
1681
 
 
1682
        if(!szMatch.isEmpty())
 
1683
        {
 
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);
 
1688
        }
 
1689
 
 
1690
        repaintWithCursorOn();
 
1691
}
 
1692
 
 
1693
void KviInputEditor::replaceWordBeforeCursor(const QString & szWord, const QString & szReplacement, bool bRepaint)
 
1694
{
 
1695
        selectOneChar(-1);
 
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());
 
1701
        if(bRepaint)
 
1702
                repaintWithCursorOn();
 
1703
}
 
1704
 
 
1705
void KviInputEditor::standardNickCompletionInsertCompletedText(const QString & szReplacedWord, const QString & szCompletedText, bool bFirstWordInLine, bool bInCommand)
 
1706
{
 
1707
        QString szBuffer = szCompletedText;
 
1708
 
 
1709
        if(!KVI_OPTION_STRING(KviOption_stringNickCompletionPostfix).isEmpty())
 
1710
        {
 
1711
                if(bFirstWordInLine || (!KVI_OPTION_BOOL(KviOption_boolUseNickCompletionPostfixForFirstWordOnly)))
 
1712
                        szBuffer.append(KVI_OPTION_STRING(KviOption_stringNickCompletionPostfix));
 
1713
        }
 
1714
        if(bInCommand)
 
1715
        {
 
1716
                // escape crazy things like Nick\nquit
 
1717
                completionEscapeUnsafeToken(szBuffer);
 
1718
        }
 
1719
        replaceWordBeforeCursor(szReplacedWord,szBuffer,false);
 
1720
}
 
1721
 
 
1722
void KviInputEditor::standardNickCompletion(bool bAddMask,QString & szWord,bool bFirstWordInLine,bool bInCommand)
 
1723
{
 
1724
        // FIXME: this could be really simplified...
 
1725
        if(!m_pUserListView)
 
1726
                return;
 
1727
 
 
1728
        selectOneChar(-1);
 
1729
 
 
1730
        QString szBuffer;
 
1731
        if(m_szLastCompletedNick.isEmpty())
 
1732
        {
 
1733
                // New completion session: we NEED sth to complete
 
1734
                if(szWord.isEmpty())
 
1735
                        return;
 
1736
 
 
1737
                if(m_pUserListView->completeNickStandard(szWord,m_szLastCompletedNick,szBuffer,bAddMask))
 
1738
                {
 
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
 
1749
 
 
1750
                return;
 
1751
        }
 
1752
 
 
1753
        if(!m_bLastCompletionFinished)
 
1754
        {
 
1755
                // Old session
 
1756
                // swap the buffers
 
1757
                m_szTextBuffer                        = m_szLastCompletionBuffer;
 
1758
                m_iCursorPosition                     = m_iLastCompletionCursorPosition;
 
1759
                m_iLastCursorXPosition                = m_iLastCompletionCursorXPosition;
 
1760
                m_iFirstVisibleChar                   = m_iLastCompletionFirstVisibleChar;
 
1761
                // re-extract
 
1762
                //word = m_szTextBuffer.left(m_iCursorPosition);
 
1763
 
 
1764
                getWordBeforeCursor(szWord,&bFirstWordInLine);
 
1765
                if(szWord.isEmpty())return;
 
1766
                if(m_pUserListView->completeNickStandard(szWord,m_szLastCompletedNick,szBuffer,bAddMask))
 
1767
                {
 
1768
                        // completed
 
1769
                        m_szLastCompletedNick             = szBuffer;
 
1770
                        standardNickCompletionInsertCompletedText(szWord,szBuffer,bFirstWordInLine,bInCommand);
 
1771
                        m_bLastCompletionFinished=0;
 
1772
                        // REPAINT CALLED FROM OUTSIDE!
 
1773
                } else {
 
1774
                        m_bLastCompletionFinished=1;
 
1775
                        m_szLastCompletedNick = "";
 
1776
                }
 
1777
 
 
1778
                return;
 
1779
        }
 
1780
 
 
1781
        // Old session finished
 
1782
        // re-extract
 
1783
        //word = m_szTextBuffer.left(m_iCursorPosition);
 
1784
        //getWordBeforeCursor(word,&bFirstWordInLine);
 
1785
        if(szWord.isEmpty())return;
 
1786
        if(m_pUserListView->completeNickStandard(szWord,"",szBuffer,bAddMask))
 
1787
        {
 
1788
                // completed
 
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!
 
1797
        } else {
 
1798
                m_bLastCompletionFinished=1;
 
1799
                m_szLastCompletedNick = "";
 
1800
        }
 
1801
}
 
1802
 
 
1803
//Funky helpers
 
1804
void KviInputEditor::end()
 
1805
{
 
1806
        m_iLastCursorXPosition = 0;
 
1807
        m_iCursorPosition = 0;
 
1808
        m_iFirstVisibleChar = 0;
 
1809
        while(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
 
1810
        {
 
1811
                moveRightFirstVisibleCharToShowCursor();
 
1812
                m_iCursorPosition++;
 
1813
        }
 
1814
        repaintWithCursorOn();
 
1815
}
 
1816
 
 
1817
void KviInputEditor::home()
 
1818
{
 
1819
        m_iFirstVisibleChar = 0;
 
1820
        m_iCursorPosition   = 0;
 
1821
        repaintWithCursorOn();
 
1822
}
 
1823
 
 
1824
void KviInputEditor::insertChar(QChar c)
 
1825
{
 
1826
        if(m_szTextBuffer.length() >= m_iMaxBufferSize)
 
1827
                return;
 
1828
 
 
1829
        // Kill the selection
 
1830
        if((m_iSelectionBegin > -1) || (m_iSelectionEnd > -1))
 
1831
        {
 
1832
                if((m_iCursorPosition >= m_iSelectionBegin) && (m_iCursorPosition <= m_iSelectionEnd))
 
1833
                {
 
1834
                        m_bUpdatesEnabled = false;
 
1835
                        removeSelected();
 
1836
                        m_bUpdatesEnabled = true;
 
1837
                }
 
1838
        }
 
1839
        selectOneChar(-1);
 
1840
        m_szTextBuffer.insert(m_iCursorPosition,c);
 
1841
 
 
1842
        addUndo(new EditCommand(EditCommand::InsertText,c,m_iCursorPosition));
 
1843
 
 
1844
        moveRightFirstVisibleCharToShowCursor();
 
1845
        m_iCursorPosition++;
 
1846
        repaintWithCursorOn();
 
1847
}
 
1848
 
 
1849
void KviInputEditor::moveRightFirstVisibleCharToShowCursor()
 
1850
{
 
1851
        // :)
 
1852
        QFontMetrics * fm = KviInputEditor::getLastFontMetrics(font());
 
1853
 
 
1854
        QChar c = m_szTextBuffer.at(m_iCursorPosition);
 
1855
 
 
1856
        m_iLastCursorXPosition += (c.unicode() < 256) ? KviInputEditor::g_iInputFontCharWidth[c.unicode()] : fm->width(c);
 
1857
 
 
1858
        while(m_iLastCursorXPosition >= contentsRect().width()-2*KVI_INPUT_MARGIN)
 
1859
        {
 
1860
                c = m_szTextBuffer.at(m_iFirstVisibleChar);
 
1861
 
 
1862
                m_iLastCursorXPosition -= (c.unicode() < 256) ? KviInputEditor::g_iInputFontCharWidth[c.unicode()] : fm->width(c);
 
1863
 
 
1864
                m_iFirstVisibleChar++;
 
1865
        }
 
1866
}
 
1867
 
 
1868
void KviInputEditor::repaintWithCursorOn()
 
1869
{
 
1870
        // :)
 
1871
        if(m_bUpdatesEnabled)
 
1872
        {
 
1873
                m_bCursorOn = true;
 
1874
                update();
 
1875
        }
 
1876
}
 
1877
 
 
1878
void KviInputEditor::selectOneChar(int iPos)
 
1879
{
 
1880
        m_iSelectionBegin = iPos;
 
1881
        m_iSelectionEnd   = iPos;
 
1882
}
 
1883
 
 
1884
int KviInputEditor::charIndexFromXPosition(int iXPos)
 
1885
{
 
1886
        int iCurXPos = KVI_INPUT_MARGIN;
 
1887
        int iCurChar = m_iFirstVisibleChar;
 
1888
        int iBufLen  = m_szTextBuffer.length();
 
1889
 
 
1890
        QFontMetrics *fm = KviInputEditor::getLastFontMetrics(font());
 
1891
        while(iCurChar < iBufLen)
 
1892
        {
 
1893
                QChar c = m_szTextBuffer.at(iCurChar);
 
1894
                int iWidthCh = (c.unicode() < 256) ? KviInputEditor::g_iInputFontCharWidth[c.unicode()] : fm->width(c);
 
1895
 
 
1896
                if(iXPos < (iCurXPos+(iWidthCh/2)))
 
1897
                {
 
1898
                        return iCurChar;
 
1899
                } else {
 
1900
                        if(iXPos < (iCurXPos+iWidthCh))
 
1901
                        {
 
1902
                                return (iCurChar+1);
 
1903
                        }
 
1904
                }
 
1905
 
 
1906
                iCurXPos += iWidthCh;
 
1907
                iCurChar++;
 
1908
        }
 
1909
        return iCurChar;
 
1910
}
 
1911
 
 
1912
int KviInputEditor::xPositionFromCharIndex(int iChIdx)
 
1913
{
 
1914
        QFontMetrics *fm = KviInputEditor::getLastFontMetrics(font());
 
1915
        int iCurXPos = 0;
 
1916
        int iCurChar = m_iFirstVisibleChar;
 
1917
 
 
1918
        if(m_szTextBuffer.isEmpty())
 
1919
                return iCurXPos;
 
1920
 
 
1921
        while(iCurChar < iChIdx)
 
1922
        {
 
1923
                QChar c = m_szTextBuffer.at(iCurChar);
 
1924
                iCurXPos += (c.unicode() < 256) ? KviInputEditor::g_iInputFontCharWidth[c.unicode()] : fm->width(c);
 
1925
                iCurChar++;
 
1926
        }
 
1927
 
 
1928
        return iCurXPos;
 
1929
}
 
1930
 
 
1931
void KviInputEditor::undo()
 
1932
{
 
1933
        if(!isUndoAvailable())
 
1934
                return;
 
1935
 
 
1936
        if(!m_pUndoStack)
 
1937
                return; // this should be ensured by isUndoAvailable() but well...
 
1938
 
 
1939
        selectOneChar(-1);
 
1940
 
 
1941
        EditCommand * pCommand = m_pUndoStack->takeLast();
 
1942
 
 
1943
        Q_ASSERT(pCommand); // should be true: we delete the empty undo stack
 
1944
 
 
1945
        if(m_pUndoStack->isEmpty())
 
1946
        {
 
1947
                delete m_pUndoStack;
 
1948
                m_pUndoStack = NULL;
 
1949
        }
 
1950
 
 
1951
        switch(pCommand->type())
 
1952
        {
 
1953
                case EditCommand::InsertText:
 
1954
                        m_szTextBuffer.remove(pCommand->startPosition(),pCommand->text().length());
 
1955
                        moveCursorTo(pCommand->startPosition());
 
1956
                break;
 
1957
                case EditCommand::RemoveText:
 
1958
                        m_szTextBuffer.insert(pCommand->startPosition(),pCommand->text());
 
1959
                        moveCursorTo(pCommand->startPosition()+pCommand->text().length());
 
1960
                break;
 
1961
                default:
 
1962
                        Q_ASSERT_X(false,"KviInputEditor::undo","Unexpected EditCommand type");
 
1963
                        delete pCommand; // argh
 
1964
                        return;
 
1965
                break;
 
1966
        }
 
1967
        
 
1968
        if(!m_pRedoStack)
 
1969
        {
 
1970
                m_pRedoStack = new KviPointerList<EditCommand>;
 
1971
                m_pRedoStack->setAutoDelete(true);
 
1972
        }
 
1973
        
 
1974
        m_pRedoStack->append(pCommand);
 
1975
        if(m_pRedoStack->count() > KVI_INPUT_MAX_UNDO_SIZE)
 
1976
                m_pRedoStack->removeFirst(); // will delete it
 
1977
}
 
1978
 
 
1979
void KviInputEditor::redo()
 
1980
{
 
1981
        if(!isRedoAvailable())
 
1982
                return;
 
1983
 
 
1984
        if(!m_pRedoStack)
 
1985
                return; // this should be ensured by isUndoAvailable() but well...
 
1986
 
 
1987
        selectOneChar(-1);
 
1988
 
 
1989
        EditCommand * pCommand = m_pRedoStack->takeLast();
 
1990
 
 
1991
        Q_ASSERT(pCommand); // should be true: we delete the empty redo stack
 
1992
 
 
1993
        if(m_pRedoStack->isEmpty())
 
1994
        {
 
1995
                delete m_pRedoStack;
 
1996
                m_pRedoStack = NULL;
 
1997
        }
 
1998
 
 
1999
        switch(pCommand->type())
 
2000
        {
 
2001
                case EditCommand::InsertText:
 
2002
                        m_szTextBuffer.insert(pCommand->startPosition(),pCommand->text());
 
2003
                        moveCursorTo(pCommand->startPosition()+pCommand->text().length());
 
2004
                break;
 
2005
                case EditCommand::RemoveText:
 
2006
                        m_szTextBuffer.remove(pCommand->startPosition(),pCommand->text().length());
 
2007
                        moveCursorTo(pCommand->startPosition());
 
2008
                break;
 
2009
                default:
 
2010
                        Q_ASSERT_X(false,"KviInputEditor::redo","Unexpected EditCommand type");
 
2011
                        delete pCommand; // argh
 
2012
                        return;
 
2013
                break;
 
2014
        }
 
2015
        
 
2016
        if(!m_pUndoStack)
 
2017
        {
 
2018
                m_pUndoStack = new KviPointerList<EditCommand>;
 
2019
                m_pUndoStack->setAutoDelete(true);
 
2020
        }
 
2021
        
 
2022
        m_pUndoStack->append(pCommand);
 
2023
        if(m_pUndoStack->count() > KVI_INPUT_MAX_UNDO_SIZE)
 
2024
                m_pUndoStack->removeFirst(); // will delete it
 
2025
}
 
2026
 
 
2027
void KviInputEditor::addUndo(EditCommand * pCommand)
 
2028
{
 
2029
        if(!m_pUndoStack)
 
2030
        {
 
2031
                m_pUndoStack = new KviPointerList<EditCommand>;
 
2032
                m_pUndoStack->setAutoDelete(true);
 
2033
        }
 
2034
        m_pUndoStack->append(pCommand);
 
2035
 
 
2036
        if(m_pUndoStack->count() > KVI_INPUT_MAX_UNDO_SIZE)
 
2037
                m_pUndoStack->removeFirst(); // will delete it
 
2038
}
 
2039
 
 
2040
void KviInputEditor::openHistory()
 
2041
{
 
2042
        if(!KVI_OPTION_BOOL(KviOption_boolEnableInputHistory))
 
2043
                return;
 
2044
        if(m_pInputParent->inherits("KviInput"))
 
2045
                ((KviInput*)(m_pInputParent))->historyButtonClicked();
 
2046
}
 
2047
 
 
2048
void KviInputEditor::toggleMultiLineEditor()
 
2049
{
 
2050
        if(m_pInputParent->inherits("KviInput"))
 
2051
        {
 
2052
                ((KviInput*)(m_pInputParent))->multiLinePaste(m_szTextBuffer);
 
2053
                clear();
 
2054
                return;
 
2055
        }
 
2056
}
 
2057
 
 
2058
void KviInputEditor::previousChar()
 
2059
{
 
2060
        if(m_iCursorPosition > 0)
 
2061
        {
 
2062
                internalCursorLeft(false);
 
2063
                repaintWithCursorOn();
 
2064
        }
 
2065
}
 
2066
 
 
2067
void KviInputEditor::nextChar()
 
2068
{
 
2069
        if(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
 
2070
        {
 
2071
                internalCursorRight(false);
 
2072
                repaintWithCursorOn();
 
2073
        }
 
2074
}
 
2075
 
 
2076
void KviInputEditor::previousCharSelection()
 
2077
{
 
2078
        if(m_iCursorPosition > 0)
 
2079
        {
 
2080
                internalCursorLeft(true);
 
2081
                repaintWithCursorOn();
 
2082
        }
 
2083
}
 
2084
 
 
2085
void KviInputEditor::nextCharSelection()
 
2086
{
 
2087
        if(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
 
2088
        {
 
2089
                internalCursorRight(true);
 
2090
                repaintWithCursorOn();
 
2091
        }
 
2092
}
 
2093
 
 
2094
void KviInputEditor::previousWord()
 
2095
{
 
2096
        if(m_iCursorPosition > 0)
 
2097
        {
 
2098
                // skip whitespace
 
2099
                while(m_iCursorPosition > 0)
 
2100
                {
 
2101
                        if(!m_szTextBuffer.at(m_iCursorPosition - 1).isSpace())
 
2102
                                break;
 
2103
                        internalCursorLeft(false);
 
2104
                }
 
2105
                // skip nonwhitespace
 
2106
                while(m_iCursorPosition > 0)
 
2107
                {
 
2108
                        if(m_szTextBuffer.at(m_iCursorPosition - 1).isSpace())
 
2109
                                break;
 
2110
                        internalCursorLeft(false);
 
2111
                }
 
2112
                repaintWithCursorOn();
 
2113
        }
 
2114
}
 
2115
 
 
2116
void KviInputEditor::nextWord()
 
2117
{
 
2118
        if(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
 
2119
        {
 
2120
                // skip whitespace
 
2121
                while(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
 
2122
                {
 
2123
                        if(!m_szTextBuffer.at(m_iCursorPosition).isSpace())
 
2124
                                break;
 
2125
                        internalCursorRight(false);
 
2126
                }
 
2127
                // skip nonwhitespace
 
2128
                while(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
 
2129
                {
 
2130
                        if(m_szTextBuffer.at(m_iCursorPosition).isSpace())
 
2131
                                break;
 
2132
                        internalCursorRight(false);
 
2133
                }
 
2134
                repaintWithCursorOn();
 
2135
        }
 
2136
}
 
2137
 
 
2138
void KviInputEditor::previousWordSelection()
 
2139
{
 
2140
        if(m_iCursorPosition > 0)
 
2141
        {
 
2142
                // skip whitespace
 
2143
                while(m_iCursorPosition > 0)
 
2144
                {
 
2145
                        if(!m_szTextBuffer.at(m_iCursorPosition - 1).isSpace())
 
2146
                                break;
 
2147
                        internalCursorLeft(true);
 
2148
                }
 
2149
                // skip nonwhitespace
 
2150
                while(m_iCursorPosition > 0)
 
2151
                {
 
2152
                        if(m_szTextBuffer.at(m_iCursorPosition - 1).isSpace())
 
2153
                                break;
 
2154
                        internalCursorLeft(true);
 
2155
                }
 
2156
                repaintWithCursorOn();
 
2157
        }
 
2158
}
 
2159
 
 
2160
void KviInputEditor::nextWordSelection()
 
2161
{
 
2162
        if(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
 
2163
        {
 
2164
                // skip whitespace
 
2165
                while(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
 
2166
                {
 
2167
                        if(!m_szTextBuffer.at(m_iCursorPosition).isSpace())
 
2168
                                break;
 
2169
                        internalCursorRight(true);
 
2170
                }
 
2171
                // skip nonwhitespace
 
2172
                while(m_iCursorPosition < ((int)(m_szTextBuffer.length())))
 
2173
                {
 
2174
                        if(m_szTextBuffer.at(m_iCursorPosition).isSpace())
 
2175
                                break;
 
2176
                        internalCursorRight(true);
 
2177
                }
 
2178
                repaintWithCursorOn();
 
2179
        }
 
2180
}
 
2181
 
 
2182
void KviInputEditor::insertBold()
 
2183
{
 
2184
        if(!m_bReadOnly) insertChar(KviControlCodes::Bold);
 
2185
}
 
2186
 
 
2187
void KviInputEditor::insertReset()
 
2188
{
 
2189
        if(!m_bReadOnly) insertChar(KviControlCodes::Reset);
 
2190
}
 
2191
 
 
2192
void KviInputEditor::insertUnderline()
 
2193
{
 
2194
        if(!m_bReadOnly) insertChar(KviControlCodes::Underline);
 
2195
}
 
2196
 
 
2197
void KviInputEditor::insertReverse()
 
2198
{
 
2199
        if(!m_bReadOnly) insertChar(KviControlCodes::Reverse);
 
2200
}
 
2201
 
 
2202
void KviInputEditor::insertPlainText()
 
2203
{
 
2204
        if(!m_bReadOnly) insertChar(KviControlCodes::CryptEscape); // DO NOT CRYPT THIS STUFF
 
2205
}
 
2206
 
 
2207
void KviInputEditor::insertIcon()
 
2208
{
 
2209
        if(!m_bReadOnly)
 
2210
        {
 
2211
                insertChar(KviControlCodes::Icon); // THE NEXT WORD IS AN ICON NAME
 
2212
                int iXPos = xPositionFromCharIndex(m_iCursorPosition);
 
2213
                if(iXPos > 24)
 
2214
                        iXPos-=24;
 
2215
                if(!g_pTextIconWindow)
 
2216
                        g_pTextIconWindow = new KviTextIconWindow();
 
2217
 
 
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);
 
2222
        }
 
2223
}
 
2224
 
 
2225
void KviInputEditor::insertColor()
 
2226
{
 
2227
        if(!m_bReadOnly)
 
2228
        {
 
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);
 
2236
        }
 
2237
}
 
2238
 
 
2239
void KviInputEditor::copyInternal()
 
2240
{
 
2241
        copyToClipboard();
 
2242
}
 
2243
 
 
2244
void KviInputEditor::cutInternal()
 
2245
{
 
2246
        if(!m_bReadOnly) cut();
 
2247
}
 
2248
 
 
2249
void KviInputEditor::pasteInternal()
 
2250
{
 
2251
        if(!m_bReadOnly) pasteClipboardWithConfirmation();
 
2252
}
 
2253
 
 
2254
void KviInputEditor::undoInternal()
 
2255
{
 
2256
        if(!m_bReadOnly)
 
2257
                undo();
 
2258
}
 
2259
 
 
2260
void KviInputEditor::redoInternal()
 
2261
{
 
2262
        if(!m_bReadOnly)
 
2263
                redo();
 
2264
}
 
2265
 
 
2266
void KviInputEditor::selectAllInternal()
 
2267
{
 
2268
        m_iSelectionBegin=0;
 
2269
        m_iSelectionEnd=m_szTextBuffer.length()-1;
 
2270
        m_iCursorPosition=m_szTextBuffer.length();
 
2271
        repaintWithCursorOn();
 
2272
}
 
2273
 
 
2274
void KviInputEditor::deleteWord()
 
2275
{
 
2276
        if(m_iCursorPosition > 0 && !m_bReadOnly && !hasSelection())
 
2277
        {
 
2278
                // skip whitespace
 
2279
                while(m_iCursorPosition > 0)
 
2280
                {
 
2281
                        if(!m_szTextBuffer.at(m_iCursorPosition - 1).isSpace())
 
2282
                                break;
 
2283
                        m_szTextBuffer.remove(m_iCursorPosition-1,1);
 
2284
                        m_iCursorPosition--;
 
2285
                        if(m_iFirstVisibleChar > m_iCursorPosition)
 
2286
                                m_iFirstVisibleChar--;
 
2287
                }
 
2288
                // skip nonwhitespace
 
2289
                while(m_iCursorPosition > 0)
 
2290
                {
 
2291
                        if(m_szTextBuffer.at(m_iCursorPosition - 1).isSpace())
 
2292
                                break;
 
2293
                        m_szTextBuffer.remove(m_iCursorPosition-1,1);
 
2294
                        m_iCursorPosition--;
 
2295
                        if(m_iFirstVisibleChar > m_iCursorPosition)
 
2296
                                m_iFirstVisibleChar--;
 
2297
                }
 
2298
                repaintWithCursorOn();
 
2299
        }
 
2300
}
 
2301
 
 
2302
void KviInputEditor::previousLine()
 
2303
{
 
2304
        if(m_pKviWindow)
 
2305
                if(m_pKviWindow->view()) m_pKviWindow->view()->prevLine();
 
2306
        return;
 
2307
}
 
2308
 
 
2309
void KviInputEditor::nextLine()
 
2310
{
 
2311
        if(m_pKviWindow)
 
2312
                if(m_pKviWindow->view()) m_pKviWindow->view()->nextLine();
 
2313
        return;
 
2314
}
 
2315
 
 
2316
void KviInputEditor::previousPage()
 
2317
{
 
2318
        if(m_pKviWindow)
 
2319
                if(m_pKviWindow->view()) m_pKviWindow->view()->prevPage();
 
2320
}
 
2321
 
 
2322
void KviInputEditor::nextPage()
 
2323
{
 
2324
        if(m_pKviWindow)
 
2325
                if(m_pKviWindow->view()) m_pKviWindow->view()->nextPage();
 
2326
}
 
2327
 
 
2328
void KviInputEditor::search()
 
2329
{
 
2330
        if(m_pKviWindow)
 
2331
                if(m_pKviWindow->view()) m_pKviWindow->view()->toggleToolWidget();
 
2332
}
 
2333
 
 
2334
void KviInputEditor::scrollToLastReadLine()
 
2335
{
 
2336
        if(m_pKviWindow)
 
2337
                if(m_pKviWindow->view())
 
2338
                        if(m_pKviWindow->view()->hasLineMark())
 
2339
                                m_pKviWindow->view()->scrollToMarker();
 
2340
}
 
2341
 
 
2342
void KviInputEditor::sendPlain()
 
2343
{
 
2344
        if(m_pInputParent->inherits("KviInput"))
 
2345
        {
 
2346
                //ensure the color window is hidden (bug #835)
 
2347
                if(g_pColorWindow)
 
2348
                        if(g_pColorWindow->isVisible())
 
2349
                                g_pColorWindow->hide();
 
2350
 
 
2351
                QString szBuffer(m_szTextBuffer);
 
2352
                m_szTextBuffer="";
 
2353
                selectOneChar(-1);
 
2354
                m_iCursorPosition = 0;
 
2355
                m_iFirstVisibleChar = 0;
 
2356
                repaintWithCursorOn();
 
2357
                KviUserInput::parseNonCommand(szBuffer,m_pKviWindow);
 
2358
                if (!szBuffer.isEmpty())
 
2359
                {
 
2360
                        KviInputHistory::instance()->add(new QString(szBuffer));
 
2361
                        m_pHistory->insert(0,new QString(szBuffer));
 
2362
                }
 
2363
 
 
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();
 
2366
 
 
2367
                m_iCurHistoryIdx = -1;
 
2368
        }
 
2369
}
 
2370
 
 
2371
void KviInputEditor::homeInternal()
 
2372
{
 
2373
        if(m_iCursorPosition > 0)
 
2374
        {
 
2375
                selectOneChar(-1);
 
2376
                home();
 
2377
        }
 
2378
}
 
2379
 
 
2380
void KviInputEditor::homeInternalSelection()
 
2381
{
 
2382
        if(m_iCursorPosition > 0)
 
2383
        {
 
2384
                if((m_iSelectionBegin == -1) && (m_iSelectionEnd == -1))
 
2385
                {
 
2386
                        // There is no selection
 
2387
                        m_iSelectionEnd = m_iCursorPosition - 1;
 
2388
                } else {
 
2389
                        // There is selection
 
2390
                        m_iSelectionEnd = m_iSelectionBegin - 1;
 
2391
                }
 
2392
 
 
2393
                m_iSelectionBegin = 0;
 
2394
                home();
 
2395
        }
 
2396
}
 
2397
 
 
2398
void KviInputEditor::endInternal()
 
2399
{
 
2400
        selectOneChar(-1);
 
2401
        end();
 
2402
}
 
2403
 
 
2404
void KviInputEditor::endInternalSelection()
 
2405
{
 
2406
        if((m_iSelectionBegin == -1) && (m_iSelectionEnd == -1))
 
2407
        {
 
2408
                // There is no selection
 
2409
                m_iSelectionBegin = m_iCursorPosition;
 
2410
        } else {
 
2411
                // There is selection
 
2412
                m_iSelectionBegin = m_iSelectionEnd+1;
 
2413
        }
 
2414
 
 
2415
        m_iSelectionEnd = m_szTextBuffer.length()-1;
 
2416
        end();
 
2417
}
 
2418
 
 
2419
void KviInputEditor::historyPrev()
 
2420
{
 
2421
        if(!m_bReadOnly)
 
2422
        {
 
2423
                if(m_pHistory->count() > 0)
 
2424
                {
 
2425
                        if(m_iCurHistoryIdx < 0)
 
2426
                        {
 
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))
 
2431
                        {
 
2432
                                m_szTextBuffer=m_szSaveTextBuffer;
 
2433
                                m_iCurHistoryIdx = -1;
 
2434
                        } else {
 
2435
                                m_iCurHistoryIdx++;
 
2436
                                m_szTextBuffer = *(m_pHistory->at(m_iCurHistoryIdx));
 
2437
                        }
 
2438
                        selectOneChar(-1);
 
2439
                        if(KVI_OPTION_BOOL(KviOption_boolInputHistoryCursorAtEnd))end();
 
2440
                        else home();
 
2441
                }
 
2442
        }
 
2443
}
 
2444
 
 
2445
void KviInputEditor::historyNext()
 
2446
{
 
2447
        if(!m_bReadOnly)
 
2448
        {
 
2449
                if(m_pHistory->count() > 0)
 
2450
                {
 
2451
                        if(m_iCurHistoryIdx < 0)
 
2452
                        {
 
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)
 
2457
                        {
 
2458
                                m_szTextBuffer=m_szSaveTextBuffer;
 
2459
                                m_iCurHistoryIdx = -1;
 
2460
                        } else {
 
2461
                                m_iCurHistoryIdx--;
 
2462
                                m_szTextBuffer = *(m_pHistory->at(m_iCurHistoryIdx));
 
2463
                        }
 
2464
                        selectOneChar(-1);
 
2465
                        if(KVI_OPTION_BOOL(KviOption_boolInputHistoryCursorAtEnd))end();
 
2466
                        else home();
 
2467
                }
 
2468
        }
 
2469
}
 
2470
 
 
2471
void KviInputEditor::returnHit()
 
2472
{
 
2473
        returnPressed();
 
2474
}
 
2475
 
 
2476
void KviInputEditor::backspaceHit()
 
2477
{
 
2478
        if(m_bReadOnly)
 
2479
                return;
 
2480
        if(hasSelection() && (m_iSelectionEnd >= m_iCursorPosition-1) && (m_iSelectionBegin <= m_iCursorPosition))
 
2481
        {
 
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)
 
2489
        {
 
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--;
 
2495
        }
 
2496
        selectOneChar(-1);
 
2497
        repaintWithCursorOn();
 
2498
}
 
2499
 
 
2500
void KviInputEditor::deleteHit()
 
2501
{
 
2502
        if(m_bReadOnly)
 
2503
                return;
 
2504
 
 
2505
        if(hasSelection())
 
2506
        {
 
2507
                removeSelected();
 
2508
                return;
 
2509
        }
 
2510
 
 
2511
        if(m_iCursorPosition < (int)m_szTextBuffer.length())
 
2512
        {
 
2513
                m_szTextBuffer.remove(m_iCursorPosition,1);
 
2514
                selectOneChar(-1);
 
2515
                repaintWithCursorOn();
 
2516
        }
 
2517
}
 
2518
 
 
2519
void KviInputEditor::escapeHit()
 
2520
{
 
2521
        emit escapePressed();
 
2522
        return;
 
2523
}
 
2524
 
 
2525
void KviInputEditor::toggleCommandMode()
 
2526
{
 
2527
        if(m_pInputParent->inherits("KviInput"))
 
2528
                ((KviInput *)(m_pInputParent))->setUserFriendly(!((KviInput *)(m_pInputParent))->isUserFriendly());
 
2529
}
 
2530
 
 
2531
void KviInputEditor::dummy()
 
2532
{
 
2533
        // this function does nothing. check the header file for explanation
 
2534
}
 
2535
 
 
2536
#ifndef COMPILE_USE_STANDALONE_MOC_SOURCES
 
2537
#include "KviInputEditor.moc"
 
2538
#endif //!COMPILE_USE_STANDALONE_MOC_SOURCES