View difference between Paste ID: D9UCPsVE and 0vLk2uWi
SHOW: | | - or go back to the newest paste.
1
#include "qpconsole.h"
2
3
#include <QApplication>
4
#include <QTextBlock>
5
#include <QTextDocument>
6
#include <QTextCursor>
7
#include <QClipboard>
8-
#include "global.h"
8+
9
QPConsole::QPConsole(QWidget *parent) :
10
  QPlainTextEdit(parent),
11
  mHistoryPos(-1),
12
  mCommandLineReady(false)
13
{
14
  QPalette p = palette();
15
  p.setColor(QPalette::Active, QPalette::Base, Qt::black);
16
  p.setColor(QPalette::Inactive, QPalette::Base, Qt::black);
17
  p.setColor(QPalette::Active, QPalette::Text, Qt::white);
18
  p.setColor(QPalette::Inactive, QPalette::Text, Qt::white);
19
  setPalette(p);
20
  
21
  QFont f;
22
#ifdef Q_OS_LINUX
23
  f.setFamily("Monospace");
24
  f.setPointSize(10);
25
#else
26
  f.setFamily("Lucida Console");
27
  f.setPointSize(10);
28
#endif
29
  f.setFixedPitch(true);
30
  setFont(f);
31
  
32
  setCursorWidth(QFontMetrics(font()).width(QChar('x')));
33
  setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
34
  setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
35
  setUndoRedoEnabled(false);
36
  setLineWrapMode(QPlainTextEdit::NoWrap);
37
  setWordWrapMode(QTextOption::NoWrap);
38
  setBackgroundVisible(false);
39
  setFrameStyle(QFrame::NoFrame);
40
  setTabStopWidth(40);
41
  setAcceptDrops(false);
42
  setPrefix("terminal> ");
43
  setPrefixColor(QColor(140, 255, 50));
44
  f.setBold(true);
45
  setPrefixFont(f);
46
  
47
  prepareCommandLine();
48
}
49
50
void QPConsole::setPrefix(const QString &prefix)
51
{
52
  mPrefix = prefix;
53
}
54
55
void QPConsole::setPrefixColor(const QColor &color)
56
{
57
  mPrefixColor = color;
58
}
59
60
void QPConsole::setPrefixFont(const QFont &font)
61
{
62
  mPrefixFont = font;
63
}
64
65
bool QPConsole::inCommandLine() const
66
{
67
  return mCommandLineReady && document()->blockCount()-1 == textCursor().blockNumber() && textCursor().positionInBlock() >= mPrefix.length();
68
}
69
70
void QPConsole::processCommand()
71
{
72
  QString inputString = document()->lastBlock().text();
73
  if (inputString.startsWith(mPrefix))
74
    inputString.remove(0, mPrefix.length());
75
  if (!inputString.trimmed().isEmpty())
76
    mHistory.append(inputString);
77
  mHistoryPos = -1;
78
  inputString = inputString.trimmed();
79
  
80
  QStringList params;
81
  QString cmd;
82
  int p = inputString.indexOf(' ');
83
  if (p > -1)
84
  {
85
    cmd = inputString.mid(0, p);
86
    params = getParams(inputString.mid(p+1));
87
  } else
88
    cmd = inputString;
89
  
90
  QTextCursor cur(document()->lastBlock());
91
  cur.movePosition(QTextCursor::EndOfBlock);
92
  cur.insertBlock();
93
  setTextCursor(cur);
94
  mCommandLineReady = false;
95
  emit command(cmd, params);
96
}
97
98
QStringList QPConsole::getParams(QString str)
99
{
100
  QStringList result;
101
  str = str.trimmed();
102
  if (str.isEmpty())
103
    return result;
104
  
105
  bool escaped = false;
106
  bool quoted = false;
107
  QString param;
108
  int i = 0;
109
  while (i < str.size())
110
  {
111
    if (escaped)
112
    {
113
      escaped = false;
114
      param += str[i];
115
    } else if (str[i] == '\\')
116
    {
117
      escaped = true;
118
    } else if (str[i] == '"')
119
    {
120
      quoted = !quoted;
121
      if (!param.isEmpty() && !(i+1>=str.size() || str[i+1]==' ')) // only add quote if not first and last, embracing a parameter
122
        param += str[i];
123
    } else if (str[i] == ' ')
124
    {
125
      if (quoted)
126
      {
127
        param += str[i];
128
      } else if (!param.isEmpty())
129
      {
130
        result.append(param);
131
        param.clear();
132
      }
133
    } else
134
    {
135
      param += str[i];
136
    }
137
    ++i;
138
  }
139
  if (!param.isEmpty())
140
  {
141
    result.append(param);
142
    param.clear();
143
  }
144
  return result;
145
}
146
147
void QPConsole::keyPressEvent(QKeyEvent *event)
148
{
149
  if (inCommandLine())
150
  {
151
    // clear selection that spans multiple blocks (or prefix characters) (would overwrite previous command lines):
152
    QTextCursor cur = textCursor();
153
    if (cur.hasSelection())
154
    {
155
      if (document()->findBlock(cur.selectionStart()) != document()->findBlock(cur.selectionEnd()) || // spans multiple blocks (including command line)
156
          cur.selectionStart()-cur.block().position() < mPrefix.length() || // spans prefix
157
          cur.selectionEnd()-cur.block().position() < mPrefix.length() ) // spans prefix
158
      {
159
        cur.clearSelection();
160
        if (cur.positionInBlock() < mPrefix.length())
161
          cur.setPosition(cur.block().position()+mPrefix.length());
162
        setTextCursor(cur);
163
      }
164
    }
165
    if (cur.positionInBlock() == mPrefix.length())
166
    {
167
      cur.setCharFormat(QTextCharFormat()); // make sure we don't pick up format from prefix
168
      setTextCursor(cur);
169
    }
170
    // react to keystroke:
171
    if (event->matches(QKeySequence::MoveToPreviousLine)) // history up
172
    {
173
      if (mHistory.isEmpty() || mHistoryPos >= mHistory.size()-1)
174
        return;
175
      ++mHistoryPos;
176
      int index = mHistory.size()-mHistoryPos-1;
177
      QTextCursor cur(document()->lastBlock());
178
      cur.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, mPrefix.length());
179
      cur.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
180
      cur.removeSelectedText();
181
      cur.setCharFormat(QTextCharFormat());
182
      cur.insertText(mHistory.at(index));
183
      setTextCursor(cur);
184
    } else if (event->matches(QKeySequence::MoveToNextLine)) // history down
185
    {
186
      if (mHistory.isEmpty() || mHistoryPos <= 0)
187
        return;
188
      --mHistoryPos;
189
      int index = mHistory.size()-mHistoryPos-1;
190
      QTextCursor cur(document()->lastBlock());
191
      cur.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, mPrefix.length());
192
      cur.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
193
      cur.removeSelectedText();
194
      cur.setCharFormat(QTextCharFormat());
195
      cur.insertText(mHistory.at(index));
196
      setTextCursor(cur);
197
    } else if (event->matches(QKeySequence::Paste)) // paste text, do it manually to remove text char formatting and newlines
198
    {
199
      QString pasteText = QApplication::clipboard()->text();
200
      pasteText.replace("\n", "").replace("\r", "");
201
      cur.setCharFormat(QTextCharFormat());
202
      cur.insertText(pasteText);
203
      setTextCursor(cur);
204
    } else if (event->key() == Qt::Key_Return) // process command
205
    {
206
      processCommand();
207
    } else if (event->key() == Qt::Key_Backspace) // only allow backspace if we wouldn't delete last char of prefix
208
    {
209
      if (cur.positionInBlock() > mPrefix.length()) 
210
        QPlainTextEdit::keyPressEvent(event);
211
    } else if (!event->matches(QKeySequence::Close) &&
212
               !event->matches(QKeySequence::New) &&
213
               !event->matches(QKeySequence::Open) &&
214
               !event->matches(QKeySequence::Preferences) &&
215
               !event->matches(QKeySequence::Bold) &&
216
               !event->matches(QKeySequence::Italic) &&
217
               !event->matches(QKeySequence::InsertLineSeparator) &&
218
               !event->matches(QKeySequence::InsertParagraphSeparator) &&
219
               !event->matches(QKeySequence::Redo) &&
220
               !event->matches(QKeySequence::Undo) &&
221
               !event->matches(QKeySequence::DeleteStartOfWord))
222
    {
223
      QPlainTextEdit::keyPressEvent(event);
224
    }
225
  } else // cursor position not in command line
226
  {
227
    if (event->matches(QKeySequence::MoveToEndOfDocument) ||
228
        event->matches(QKeySequence::MoveToEndOfBlock) ||
229
        event->matches(QKeySequence::MoveToEndOfLine) ||
230
        event->matches(QKeySequence::MoveToStartOfDocument) ||
231
        event->matches(QKeySequence::MoveToStartOfBlock) ||
232
        event->matches(QKeySequence::MoveToStartOfLine) ||
233
        event->matches(QKeySequence::MoveToNextLine) ||
234
        event->matches(QKeySequence::MoveToNextWord) ||
235
        event->matches(QKeySequence::MoveToNextChar) ||
236
        event->matches(QKeySequence::MoveToPreviousLine) ||
237
        event->matches(QKeySequence::MoveToPreviousWord) ||
238
        event->matches(QKeySequence::MoveToPreviousChar) ||
239
        event->matches(QKeySequence::SelectAll) ||
240
        event->matches(QKeySequence::SelectEndOfDocument) ||
241
        event->matches(QKeySequence::SelectEndOfBlock) ||
242
        event->matches(QKeySequence::SelectEndOfLine) ||
243
        event->matches(QKeySequence::SelectStartOfDocument) ||
244
        event->matches(QKeySequence::SelectStartOfBlock) ||
245
        event->matches(QKeySequence::SelectStartOfLine) ||
246
        event->matches(QKeySequence::SelectNextLine) ||
247
        event->matches(QKeySequence::SelectNextWord) ||
248
        event->matches(QKeySequence::SelectNextChar) ||
249
        event->matches(QKeySequence::SelectPreviousLine) ||
250
        event->matches(QKeySequence::SelectPreviousWord) ||
251
        event->matches(QKeySequence::SelectPreviousChar) ||
252
        event->matches(QKeySequence::Copy) )
253
      QPlainTextEdit::keyPressEvent(event);
254
  }
255
}
256
257
void QPConsole::print(QString str)
258
{
259
  QTextCursor cur(document()->lastBlock());
260
  cur.setCharFormat(QTextCharFormat());
261
  cur.insertText(str);
262
  cur.movePosition(QTextCursor::EndOfBlock);
263
  cur.insertBlock();
264
  setTextCursor(cur);
265
  mCommandLineReady = false;
266
}
267
268
void QPConsole::prepareCommandLine()
269
{
270
  QTextCursor cur(document()->lastBlock());
271
  if (!document()->lastBlock().text().isEmpty())
272
  {
273
    cur.movePosition(QTextCursor::EndOfBlock);
274
    cur.insertBlock();
275
  }
276
  QTextCharFormat fmt;
277
  fmt.setForeground(QBrush(mPrefixColor));
278
  fmt.setFont(mPrefixFont);
279
  cur.setCharFormat(fmt);
280
  cur.insertText(mPrefix);
281
  cur.setCharFormat(QTextCharFormat());
282
  setTextCursor(cur);
283
  mCommandLineReady = true;
284
}