/**************************************************************************** ** ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ****************************************************************************/ #include "qtmessagelogview.h" #include "qtmessagelogitemdelegate.h" #include "qtmessageloghandler.h" #include "debuggerstringutils.h" #include "debuggercore.h" #include "debuggerengine.h" #include #include #include #include #include #include #include #include #include #include namespace Debugger { namespace Internal { class QtMessageLogViewViewStyle : public QProxyStyle { public: void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = 0) const { if (element != QStyle::PE_PanelItemViewRow) QProxyStyle::drawPrimitive(element, option, painter, widget); } int styleHint(StyleHint hint, const QStyleOption *option = 0, const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const { if (hint == SH_ItemView_ShowDecorationSelected) return 0; else return QProxyStyle::styleHint(hint, option, widget, returnData); } }; /////////////////////////////////////////////////////////////////////// // // QtMessageLogView // /////////////////////////////////////////////////////////////////////// QtMessageLogView::QtMessageLogView(QWidget *parent) : QTreeView(parent) { setFrameStyle(QFrame::NoFrame); setHeaderHidden(true); setRootIsDecorated(false); setEditTriggers(QAbstractItemView::AllEditTriggers); setStyleSheet(QLatin1String("QTreeView::branch:has-siblings:!adjoins-item {" "border-image: none;" "image: none; }" "QTreeView::branch:has-siblings:adjoins-item {" "border-image: none;" "image: none; }" "QTreeView::branch:!has-children:!has-siblings:adjoins-item {" "border-image: none;" "image: none; }" "QTreeView::branch:has-children:!has-siblings:closed," "QTreeView::branch:closed:has-children:has-siblings {" "border-image: none;" "image: none; }" "QTreeView::branch:open:has-children:!has-siblings," "QTreeView::branch:open:has-children:has-siblings {" "border-image: none;" "image: none; }")); QtMessageLogViewViewStyle *style = new QtMessageLogViewViewStyle; setStyle(style); style->setParent(this); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); connect(this, SIGNAL(activated(QModelIndex)), SLOT(onRowActivated(QModelIndex))); } void QtMessageLogView::onScrollToBottom() { //Keep scrolling to bottom if scroll bar is at maximum() if (verticalScrollBar()->value() == verticalScrollBar()->maximum()) scrollToBottom(); } void QtMessageLogView::mousePressEvent(QMouseEvent *event) { QPoint pos = event->pos(); QModelIndex index = indexAt(pos); if (index.isValid()) { QtMessageLogHandler::ItemType type = (QtMessageLogHandler::ItemType)index.data( QtMessageLogHandler::TypeRole).toInt(); bool handled = false; if (type == QtMessageLogHandler::UndefinedType) { bool showTypeIcon = index.parent() == QModelIndex(); ConsoleItemPositions positions(visualRect(index), viewOptions().font, showTypeIcon, true); if (positions.expandCollapseIcon().contains(pos)) { if (isExpanded(index)) setExpanded(index, false); else setExpanded(index, true); handled = true; } } if (!handled) QTreeView::mousePressEvent(event); } else { selectionModel()->setCurrentIndex(model()->index( model()->rowCount() - 1, 0), QItemSelectionModel::ClearAndSelect); } } void QtMessageLogView::keyPressEvent(QKeyEvent *e) { if (!e->modifiers() && e->key() == Qt::Key_Return) { emit activated(currentIndex()); e->accept(); return; } QTreeView::keyPressEvent(e); } void QtMessageLogView::resizeEvent(QResizeEvent *e) { static_cast(itemDelegate())->emitSizeHintChanged( selectionModel()->currentIndex()); QTreeView::resizeEvent(e); } void QtMessageLogView::drawBranches(QPainter *painter, const QRect &rect, const QModelIndex &index) const { static_cast(itemDelegate())->drawBackground( painter, rect, index, false); QTreeView::drawBranches(painter, rect, index); } void QtMessageLogView::contextMenuEvent(QContextMenuEvent *event) { QModelIndex itemIndex = indexAt(event->pos()); QMenu menu; QAction *copy = new QAction(tr("&Copy"), this); copy->setEnabled(itemIndex.isValid()); menu.addAction(copy); QAction *show = new QAction(tr("&Show in Editor"), this); show->setEnabled(canShowItemInTextEditor(itemIndex)); menu.addAction(show); menu.addSeparator(); QAction *clear = new QAction(tr("C&lear"), this); menu.addAction(clear); QAction *a = menu.exec(event->globalPos()); if (a == 0) return; if (a == copy) copyToClipboard(itemIndex); else if (a == show) onRowActivated(itemIndex); else if (a == clear) { QAbstractProxyModel *proxyModel = qobject_cast(model()); QtMessageLogHandler *handler = qobject_cast(proxyModel->sourceModel()); handler->clear(); } } void QtMessageLogView::onRowActivated(const QModelIndex &index) { if (!index.isValid()) return; //See if we have file and line Info QString filePath = model()->data(index, QtMessageLogHandler::FileRole).toString(); if (!filePath.isEmpty()) { filePath = debuggerCore()->currentEngine()->toFileInProject( QUrl(filePath)); QFileInfo fi(filePath); if (fi.exists() && fi.isFile() && fi.isReadable()) { int line = model()->data(index, QtMessageLogHandler::LineRole).toInt(); TextEditor::BaseTextEditorWidget::openEditorAt( fi.canonicalFilePath(), line); } } } void QtMessageLogView::copyToClipboard(const QModelIndex &index) { if (!index.isValid()) return; QString contents = model()->data(index).toString(); //See if we have file and line Info QString filePath = model()->data(index, QtMessageLogHandler::FileRole).toString(); if (!filePath.isEmpty()) { contents = QString(_("%1 %2: %3")).arg(contents).arg(filePath).arg( model()->data(index, QtMessageLogHandler::LineRole).toString()); } QClipboard *cb = QApplication::clipboard(); cb->setText(contents); } bool QtMessageLogView::canShowItemInTextEditor(const QModelIndex &index) { if (!index.isValid()) return false; //See if we have file and line Info QString filePath = model()->data(index, QtMessageLogHandler::FileRole).toString(); if (!filePath.isEmpty()) { filePath = debuggerCore()->currentEngine()->toFileInProject( QUrl(filePath)); QFileInfo fi(filePath); if (fi.exists() && fi.isFile() && fi.isReadable()) { return true; } } return false; } } //Internal } //Debugger