ScriptOutputDisplay.cpp 7.99 KB
Newer Older
1
2
3
#include "ScriptOutputDisplay.h"
#include "TextFileIO.h"

Roman Tolchenov's avatar
Roman Tolchenov committed
4
#include <MantidQtWidgets/Common/pixmaps.h>
5
6

#include <QDateTime>
7
#include <QKeyEvent>
8
#include <QMenu>
9
#include <QPrintDialog>
10
#include <QPrinter>
11
#include <QWheelEvent>
12

13
14
using namespace MantidQt::API;

15
16
17
18
19
20
/**
 * Constructor
 * @param title :: The title
 * @param parent :: The parent widget
 * @param flags :: Window flags
 */
21
22
23
ScriptOutputDisplay::ScriptOutputDisplay(QWidget *parent)
    : QTextEdit(parent), m_copy(NULL), m_clear(NULL), m_save(NULL),
      m_origFontSize(8), m_zoomLevel(0) {
24
#ifdef __APPLE__
25
  // Make all fonts 4 points bigger on the Mac because otherwise they're tiny!
26
27
28
  m_zoomLevel += 4;
#endif

29
30
31
32
33
34
35
  // the control is readonly, but if you set it read only then ctrl+c for
  // copying does not work
  // this approach allows ctrl+c and disables user editing through the use of
  // the KeyPress handler
  // and disabling drag and drop
  // also the mouseMoveEventHandler prevents dragging out of the control
  // affecting the text.
36
37
  setReadOnly(false);
  this->setAcceptDrops(false);
38

39
  setLineWrapMode(QTextEdit::WidgetWidth);
40
41
42
43
  setLineWrapColumnOrWidth(105);
  setAutoFormatting(QTextEdit::AutoNone);
  // Change to fix width font so that table formatting isn't screwed up
  resetFont();
44

45
  setContextMenuPolicy(Qt::CustomContextMenu);
46
47
  connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this,
          SLOT(showContextMenu(const QPoint &)));
48
49
50
51

  initActions();
}

52
53
54
55
/** Mouse move event handler - overridden to prevent dragging out of the control
 * affecting the text
 * it does this by temporarily setting the control to read only while the base
 * event handler operates
56
57
 * @param e the mouse move event
 */
58
void ScriptOutputDisplay::mouseMoveEvent(QMouseEvent *e) {
59
60
61
62
63
  this->setReadOnly(true);
  QTextEdit::mouseMoveEvent(e);
  this->setReadOnly(false);
}

64
65
/** Mouse move release handler - overridden to prevent middle mouse button
* clicks from pasting on linux
66
67
* @param e the mouse move event
*/
68
void ScriptOutputDisplay::mouseReleaseEvent(QMouseEvent *e) {
69
70
71
72
73
  this->setReadOnly(true);
  QTextEdit::mousePressEvent(e);
  this->setReadOnly(false);
}

74
void ScriptOutputDisplay::wheelEvent(QWheelEvent *e) {
75
76
77
78
79
80
81
82
  if (e->modifiers() & Qt::ControlModifier) {
    const int delta = e->delta();
    if (delta < 0) {
      zoom(-1);
      emit textZoomedOut(); // allows tracking
    } else if (delta > 0) {
      zoom(1);
      emit textZoomedIn(); // allows tracking
83
    }
84
85
86
87
    return;
  } else {
    QTextEdit::wheelEvent(e);
  }
88
89
}

90
void ScriptOutputDisplay::zoom(int range) {
91
  if ((range == 0) && (!isEmpty()))
92
    return;
93
94

  m_zoomLevel += range;
95
  // boundary protection
96
  if (m_zoomLevel < -10)
97
    m_zoomLevel = -10;
98
  if (m_zoomLevel > 20)
99
    m_zoomLevel = 20;
100

101
  QFont f = this->currentFont();
102
  int newSize = m_origFontSize + m_zoomLevel;
103
104

  if (newSize <= 0)
105
    newSize = 1;
106

107
108
  f.setPointSize(newSize);
  this->setCurrentFont(f);
109
110
  this->setFontPointSize(newSize);

111
112
113
  QTextCursor cursor = this->textCursor();
  this->selectAll();
  this->setFontPointSize(newSize);
114
  this->setTextCursor(cursor);
115
116
}

117
int ScriptOutputDisplay::zoomLevel() { return m_zoomLevel; }
118

119
void ScriptOutputDisplay::zoomUp() { zoom(1); }
120

121
void ScriptOutputDisplay::zoomDown() { zoom(-1); }
122

123
void ScriptOutputDisplay::setZoom(int value) {
124
125
  // 8 is the default font size
  QFont f = this->currentFont();
126
  zoom(value - m_zoomLevel);
127
}
128

129
130
131
/**
 * Is there anything here
 */
132
bool ScriptOutputDisplay::isEmpty() const { return document()->isEmpty(); }
133
134
135
136
137

/**
 * Populate a menu with editing actions
 * @param editMenu A new menu
 */
138
void ScriptOutputDisplay::populateEditMenu(QMenu &editMenu) {
139
140
141
  editMenu.addAction(m_clear);
}

142
143
/**
 * Capture key presses.
144
145
 * @param event A pointer to the QKeyPressEvent object
 */
146
147
148
void ScriptOutputDisplay::keyPressEvent(QKeyEvent *event) {
  if ((event->key() == Qt::Key_C) &&
      (event->modifiers() == Qt::KeyboardModifier::ControlModifier)) {
149
150
    this->copy();
  }
151
  // accept all key presses to prevent keyboard interaction
152
153
154
  event->accept();
}

155
156
157
158
/**
 *  Display an output message that is not an error
 *  @param msg :: The string message
 */
159
void ScriptOutputDisplay::displayMessage(const QString &msg) {
160
161
162
163
164
165
166
167
  prepareForNewMessage(ScriptOutputDisplay::Standard);
  appendText(msg);
}

/**
 *  Display an output message with a timestamp & border
 *  @param msg :: The string message
 */
168
void ScriptOutputDisplay::displayMessageWithTimestamp(const QString &msg) {
169
170
171
172
173
174
175
176
177
  prepareForNewMessage(ScriptOutputDisplay::Standard);
  QString timestamped = addTimestamp(msg);
  appendText(timestamped);
}

/**
 *  Display an error message
 *  @param msg :: The string message
 */
178
void ScriptOutputDisplay::displayError(const QString &msg) {
179
180
181
182
183
184
185
186
187
188
  prepareForNewMessage(ScriptOutputDisplay::Error);
  appendText(msg);
}

//-------------------------------------------
// Private slot member functions
//-------------------------------------------
/**
 * Display a context menu
 */
189
void ScriptOutputDisplay::showContextMenu(const QPoint &pos) {
190
191
192
193
194
  QMenu menu(this);
  menu.addAction(m_clear);
  menu.addAction(m_copy);
  menu.addAction(m_save);

195
196
  if (!isEmpty()) {
    QAction *print = new QAction(getQPixmap("fileprint_xpm"), "&Print", this);
197
    connect(print, SIGNAL(triggered()), this, SLOT(print()));
198
199
200
201
202
203
204
205
206
    menu.addAction(print);
  }

  menu.exec(mapToGlobal(pos));
}

/**
 * Print the window output
 */
207
void ScriptOutputDisplay::print() {
208
209
210
211
212
  QPrinter printer;
  QPrintDialog *print_dlg = new QPrintDialog(&printer, this);
  print_dlg->setWindowTitle(tr("Print Output"));
  if (print_dlg->exec() != QDialog::Accepted)
    return;
Nick Draper's avatar
Nick Draper committed
213
  QTextDocument document(toPlainText());
214
215
216
217
218
  document.print(&printer);
}

/**
 * Save script output to a file
219
220
 * @param filename :: The file name to save the output, if empty (default) then
 * a dialog is raised
221
 */
222
void ScriptOutputDisplay::saveToFile(const QString &filename) {
223
224
225
226
227
228
229
230
231
232
233
234
235
236
  QStringList filters;
  filters.append(tr("Text") + " (*.txt *.TXT)");
  filters.append(tr("All Files") + " (*)");
  TextFileIO fileIO(filters);
  fileIO.save(this->toPlainText(), filename);
}

//-------------------------------------------
// Private non-slot member functions
//-------------------------------------------
/**
 * Prepares the display for the next message
 * @param msgType :: One of the predefined message types
 */
237
238
239
void ScriptOutputDisplay::prepareForNewMessage(const MessageType msgType) {
  // Ensure the cursor is in the correct position. This affects the font
  // unfortunately
240
241
  moveCursor(QTextCursor::End);
  resetFont();
242
243
  // zoom(0);
  if (msgType == ScriptOutputDisplay::Error) {
244
    setTextColor(Qt::red);
245
  } else {
246
247
248
249
250
251
252
253
254
    setTextColor(Qt::black);
  }
}

/**
 * Adds a border & timestamp to the message
 * @param msg
 * @return A new string with the required formatting
 */
255
QString ScriptOutputDisplay::addTimestamp(const QString &msg) {
256
  QString separator(75, '-');
257
258
259
260
261
262
  QString timestamped = "%1\n"
                        "%2: %3\n"
                        "%4\n";
  timestamped =
      timestamped.arg(separator, QDateTime::currentDateTime().toString(),
                      msg.trimmed(), separator);
263
264
265
266
267
268
269
  return timestamped;
}

/**
 * Append new text
 * @param txt :: The text to append
 */
270
void ScriptOutputDisplay::appendText(const QString &txt) {
271
272
273
274
275
276
277
  textCursor().insertText(txt);
  moveCursor(QTextCursor::End);
}

/**
 * Create the actions associated with this widget
 */
278
void ScriptOutputDisplay::initActions() {
279
280
281
  // Copy action
  m_copy = new QAction(getQPixmap("copy_xpm"), "Copy", this);
  m_copy->setShortcut(tr("Ctrl+C"));
282
  connect(m_copy, SIGNAL(triggered()), this, SLOT(copy()));
283
284
285

  // Clear action
  m_clear = new QAction("Clear Output", this);
286
  connect(m_clear, SIGNAL(triggered()), this, SLOT(clear()));
287
288
289

  // Save  action
  m_save = new QAction("Save Output", this);
290
  connect(m_save, SIGNAL(triggered()), this, SLOT(saveToFile()));
291
292
293
294
295
}

/**
 * Rest the font to default
 */
296
void ScriptOutputDisplay::resetFont() {
297
298
  QFont f("Andale Mono");
  f.setFixedPitch(true);
299
300
301
302
  int fontSize = m_origFontSize + m_zoomLevel;
  if (fontSize < 1)
    fontSize = 1;
  f.setPointSize(fontSize);
303
304
305
306
  setCurrentFont(f);
  setMinimumWidth(5);
  setMinimumHeight(5);
}