1 /* 2 Actiona 3 Copyright (C) 2005 Jonathan Mercier-Ganady 4 5 Actiona is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 3 of the License, or 8 (at your option) any later version. 9 10 Actiona is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 Contact : jmgr@jmgr.info 19 */ 20 21 #include "consolewidget.h" 22 #include "ui_consolewidget.h" 23 24 #include <QStandardItemModel> 25 26 namespace ActionTools 27 { ConsoleWidget(QWidget * parent)28 ConsoleWidget::ConsoleWidget(QWidget *parent) 29 : QWidget(parent), 30 ui(new Ui::ConsoleWidget) 31 32 { 33 ui->setupUi(this); 34 35 ui->console->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); 36 ui->console->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); 37 ui->clearPushButton->setEnabled(false); 38 } 39 ~ConsoleWidget()40 ConsoleWidget::~ConsoleWidget() 41 { 42 delete ui; 43 } 44 setup(QStandardItemModel * model)45 void ConsoleWidget::setup(QStandardItemModel *model) 46 { 47 mModel = (model ? model : new QStandardItemModel(0, 1, this)); 48 49 QItemSelectionModel *oldModel = ui->console->selectionModel(); 50 ui->console->setModel(mModel); 51 delete oldModel; 52 53 // Note: this connection is still string based because it uses a private signal 54 connect(mModel, SIGNAL(rowsInserted(QModelIndex,int,int)), ui->console, SLOT(scrollToBottom())); 55 } 56 addScriptParameterLine(const QString & message,int parameter,int line,int column,Type type)57 void ConsoleWidget::addScriptParameterLine(const QString &message, int parameter, int line, int column, Type type) 58 { 59 auto item = new QStandardItem(); 60 61 item->setData(parameter, ParameterRole); 62 item->setData(line, LineRole); 63 item->setData(column, ColumnRole); 64 65 addLine(message, item, Parameters, type); 66 } 67 addResourceLine(const QString & message,const QString & resourceKey,ConsoleWidget::Type type)68 void ConsoleWidget::addResourceLine(const QString &message, const QString &resourceKey, ConsoleWidget::Type type) 69 { 70 auto item = new QStandardItem(); 71 72 item->setData(resourceKey, ResourceRole); 73 74 addLine(message, item, Resources, type); 75 } 76 addActionLine(const QString & message,qint64 actionRuntimeId,const QString & field,const QString & subField,int line,int column,Type type)77 void ConsoleWidget::addActionLine(const QString &message, qint64 actionRuntimeId, const QString &field, const QString &subField, int line, int column, Type type) 78 { 79 auto item = new QStandardItem(); 80 81 item->setData(actionRuntimeId, ActionRole); 82 item->setData(field, FieldRole); 83 item->setData(subField, SubFieldRole); 84 item->setData(line, LineRole); 85 item->setData(column, ColumnRole); 86 87 addLine(message, item, Action, type); 88 } 89 addUserLine(const QString & message,qint64 actionRuntimeId,const QString & field,const QString & subField,int line,int column,const QStringList & backtrace,Type type)90 void ConsoleWidget::addUserLine(const QString &message, qint64 actionRuntimeId, const QString &field, const QString &subField, int line, int column, const QStringList &backtrace, Type type) 91 { 92 auto item = new QStandardItem(); 93 94 item->setData(actionRuntimeId, ActionRole); 95 item->setData(field, FieldRole); 96 item->setData(subField, SubFieldRole); 97 item->setData(line, LineRole); 98 item->setData(column, ColumnRole); 99 item->setData(backtrace, BacktraceRole); 100 101 addLine(message, item, User, type); 102 } 103 addExceptionLine(const QString & message,qint64 actionRuntimeId,int exception,Type type)104 void ConsoleWidget::addExceptionLine(const QString &message, qint64 actionRuntimeId, int exception, Type type) 105 { 106 auto item = new QStandardItem(); 107 108 item->setData(actionRuntimeId, ActionRole); 109 item->setData(exception, ExceptionRole); 110 111 addLine(message, item, Exception, type); 112 } 113 addDesignErrorLine(const QString & message,Type type)114 void ConsoleWidget::addDesignErrorLine(const QString &message, Type type) 115 { 116 auto item = new QStandardItem(); 117 118 addLine(message, item, DesignError, type); 119 } 120 addStartSeparator()121 void ConsoleWidget::addStartSeparator() 122 { 123 mStartTime = QDateTime::currentDateTime(); 124 QStandardItem *item = new QStandardItem(tr("Execution started at %1").arg(mStartTime.toString(QStringLiteral("dd/MM/yyyy hh:mm:ss:zzz")))); 125 item->setTextAlignment(Qt::AlignCenter); 126 addSeparator(item); 127 } 128 addEndSeparator()129 void ConsoleWidget::addEndSeparator() 130 { 131 const QDateTime ¤tDateTime = QDateTime::currentDateTime(); 132 int days = mStartTime.daysTo(currentDateTime); 133 134 QString durationString; 135 if(days > 0) 136 durationString += tr("%n day(s) ", "", days); 137 mStartTime = mStartTime.addDays(-days); 138 139 int seconds = mStartTime.secsTo(currentDateTime); 140 int hours = seconds / 3600; 141 seconds = seconds % 3600; 142 int minutes = seconds / 60; 143 seconds = seconds % 60; 144 145 if(hours > 0) 146 durationString += tr("%n hour(s) ", "", hours); 147 if(minutes > 0) 148 durationString += tr("%n minute(s) ", "", minutes); 149 if(seconds > 0) 150 durationString += tr("%n second(s) ", "", seconds); 151 int startMSec = mStartTime.toString(QStringLiteral("z")).toInt(); 152 int endMSec = currentDateTime.toString(QStringLiteral("z")).toInt(); 153 int msec = (endMSec > startMSec) ? (endMSec - startMSec) : (1000 - (startMSec - endMSec)); 154 155 durationString += tr("%n millisecond(s)", "", msec); 156 157 QStandardItem *item = new QStandardItem(tr("Execution ended at %1\n(%2)").arg(currentDateTime.toString(QStringLiteral("dd/MM/yyyy hh:mm:ss:zzz"))).arg(durationString)); 158 item->setTextAlignment(Qt::AlignCenter); 159 addSeparator(item); 160 } 161 clear()162 void ConsoleWidget::clear() 163 { 164 mModel->removeRows(0, mModel->rowCount()); 165 166 ui->clearPushButton->setEnabled(false); 167 } 168 clearExceptSeparators()169 void ConsoleWidget::clearExceptSeparators() 170 { 171 int rowCount = mModel->rowCount(); 172 173 for(int index = rowCount - 1; index >= 0; --index) 174 { 175 QStandardItem *item = mModel->item(index); 176 177 Type type = item->data(TypeRole).value<Type>(); 178 179 if(type != Separator) 180 mModel->removeRow(index); 181 } 182 183 if(mModel->rowCount() == 0) 184 ui->clearPushButton->setEnabled(false); 185 } 186 updateClearButton()187 void ConsoleWidget::updateClearButton() 188 { 189 ui->clearPushButton->setEnabled(mModel->rowCount() > 0); 190 } 191 on_clearPushButton_clicked()192 void ConsoleWidget::on_clearPushButton_clicked() 193 { 194 clear(); 195 } 196 on_console_doubleClicked(const QModelIndex & index)197 void ConsoleWidget::on_console_doubleClicked(const QModelIndex &index) 198 { 199 emit itemDoubleClicked(index.row()); 200 } 201 on_console_clicked(const QModelIndex & index)202 void ActionTools::ConsoleWidget::on_console_clicked(const QModelIndex &index) 203 { 204 emit itemClicked(index.row()); 205 } 206 addLine(const QString & message,QStandardItem * item,Source source,Type type)207 void ConsoleWidget::addLine(const QString &message, QStandardItem *item, Source source, Type type) 208 { 209 QIcon icon; 210 211 switch(type) 212 { 213 case Information: 214 icon = QIcon(QStringLiteral(":/images/information.png")); 215 break; 216 case Warning: 217 icon = QIcon(QStringLiteral(":/images/warning.png")); 218 break; 219 case Error: 220 icon = QIcon(QStringLiteral(":/images/error.png")); 221 break; 222 case Separator: 223 Q_ASSERT(false && "Should use addSeparator instead"); 224 break; 225 } 226 227 item->setText(message); 228 if(source == DesignError) 229 item->setToolTip(message); 230 else 231 item->setToolTip(message + tr("\nDouble-click to show")); 232 item->setIcon(icon); 233 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); 234 item->setData(QVariant::fromValue<Source>(source), SourceRole); 235 item->setData(QVariant::fromValue<Type>(type), TypeRole); 236 237 mModel->appendRow(item); 238 239 qApp->processEvents(); // This is needed so that the console output gets displayed before a blocking call (such as sleep) 240 // It would be better not to have any blocking code calls, but then this would cause some bugs when the user cancels the execution during a non-blocking sleep 241 // Pausing the execution and then resuming it after some time seems to be the best way to do this, but would require important changes in the code 242 243 ui->clearPushButton->setEnabled(true); 244 } 245 addSeparator(QStandardItem * item)246 void ConsoleWidget::addSeparator(QStandardItem *item) 247 { 248 item->setFlags(nullptr); 249 item->setBackground(QBrush(Qt::lightGray)); 250 item->setForeground(QBrush(Qt::white)); 251 252 QFont appFont = QApplication::font(); 253 appFont.setPointSize(7); 254 255 item->setFont(appFont); 256 item->setData(QVariant::fromValue<Type>(Separator), TypeRole); 257 258 mModel->appendRow(item); 259 } 260 } 261