KHtml

consoledock.cpp
1 /*
2  * This file is part of the KDE libraries
3  * Copyright (C) 2006 Matt Broadstone ([email protected])
4  * Copyright (C) 2007 Maks Orlovich ([email protected])
5  * Copyright © 2007 Fredrik Höglund <[email protected]>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "consoledock.h"
23 
24 #include <QVBoxLayout>
25 #include <QPushButton>
26 #include <QModelIndex>
27 #include <QTextLayout>
28 #include <QPainter>
29 #include <QLineEdit>
30 #include <QListWidget>
31 #include "khtml_debug.h"
32 #include <QAbstractItemDelegate>
33 #include <QTextLayout>
34 
35 #include <khistorycombobox.h>
36 #include <klocalizedstring.h>
37 
38 namespace KJSDebugger
39 {
40 
41 class ConsoleItemDelegate : public QAbstractItemDelegate
42 {
43 public:
44  enum ItemRole { ResultRole = 0x106EE9CA };
45 
46  ConsoleItemDelegate(QObject *parent = 0);
47  ~ConsoleItemDelegate();
48  QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
49  void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
50 
51 private:
52  void setLayoutOption(QTextLayout &layout, const QStyleOptionViewItemV3 &option, Qt::Alignment alignment) const;
53  QSize layoutText(QTextLayout &layout, const QString &text, const QSize &constraints) const;
54  void drawTextLayout(QPainter *painter, const QTextLayout &layout, const QRect &rect) const;
55 };
56 
57 ConsoleItemDelegate::ConsoleItemDelegate(QObject *parent)
58  : QAbstractItemDelegate(parent)
59 {
60 }
61 
62 ConsoleItemDelegate::~ConsoleItemDelegate()
63 {
64 }
65 
66 void ConsoleItemDelegate::setLayoutOption(QTextLayout &layout, const QStyleOptionViewItemV3 &option, Qt::Alignment alignment) const
67 {
68  QTextOption textoption;
69  textoption.setTextDirection(option.direction);
70  textoption.setAlignment(QStyle::visualAlignment(option.direction, alignment));
71  textoption.setWrapMode(option.features & QStyleOptionViewItemV2::WrapText ? QTextOption::WordWrap
73 
74  layout.setTextOption(textoption);
75 }
76 
77 QSize ConsoleItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
78 {
79  if (!index.isValid()) {
80  return QSize();
81  }
82 
83  QFont normalFont = option.font;
84  QFont boldFont = normalFont;
85  boldFont.setBold(true);
86 
87  // Extract the items we want to measure
88  QString input = index.data(Qt::DisplayRole).toString();
89  QString result = index.data(ResultRole).toString();
90 
91  QStyleOptionViewItemV3 opt(option);
92  int maxWidth = static_cast<const QListView *>(opt.widget)->viewport()->width();
93 
94  QTextLayout inputLayout, resultLayout;
95  setLayoutOption(inputLayout, opt, Qt::AlignLeft);
96  setLayoutOption(resultLayout, opt, Qt::AlignRight);
97 
98  inputLayout.setFont(normalFont);
99  resultLayout.setFont(boldFont);
100 
101  QSize constraints(maxWidth - 4, 65536);
102 
103  QSize inputSize = layoutText(inputLayout, input, constraints);
104  QSize resultSize = layoutText(resultLayout, result, constraints);
105 
106  int width = qBound(0, qMax(inputSize.width(), resultSize.width()) + 4, maxWidth);
107  int height = inputSize.height() + option.fontMetrics.leading() + resultSize.height();
108 
109  return QSize(width, height + 8);
110 }
111 
112 QSize ConsoleItemDelegate::layoutText(QTextLayout &layout, const QString &text, const QSize &constraints) const
113 {
114  QFontMetrics metrics(layout.font());
115  int leading = metrics.leading();
116  int height = 0;
117  int maxWidth = constraints.width();
118  int widthUsed = 0;
119  QTextLine line;
120 
121  layout.setText(text);
122 
123  layout.beginLayout();
124  while ((line = layout.createLine()).isValid()) {
125  height += leading;
126 
127  line.setLineWidth(maxWidth);
128 
129  // Make the last line that will fit infinitely long.
130  // drawTextLayout() will handle this by fading the line out
131  // if it won't fit in the contraints.
132  if (height + metrics.height() * 2 + leading >= constraints.height()) {
133  line.setLineWidth(INT_MAX);
134  line.setLineWidth(line.naturalTextWidth());
135  } else {
136  line.setLineWidth(maxWidth);
137  }
138 
139  line.setPosition(QPoint(0, height));
140 
141  height += int(line.height());
142  widthUsed = int(qMax(qreal(widthUsed), line.naturalTextWidth()));
143  }
144  layout.endLayout();
145 
146  return QSize(widthUsed, height);
147 }
148 
149 void ConsoleItemDelegate::drawTextLayout(QPainter *painter, const QTextLayout &layout, const QRect &rect) const
150 {
151  if (rect.width() < 1 || rect.height() < 1) {
152  return;
153  }
154 
155  QFontMetrics fm(layout.font());
156  bool leftAligned = layout.textOption().alignment() & Qt::AlignLeft;
157 
158  // Draw each line in the layout
159  for (int i = 0; i < layout.lineCount(); i++) {
160  QTextLine line = layout.lineAt(i);
161 
162  int width = line.naturalTextWidth();
163  int x = width > rect.width() && !leftAligned ? rect.width() - width : 0;
164  line.draw(painter, QPoint(x + rect.x(), rect.y()));
165  }
166 }
167 
168 void ConsoleItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
169 {
170  if (!index.isValid()) {
171  return;
172  }
173 
174  painter->save();
175 
176  QFont normalFont = option.font;
177  QFont boldFont = normalFont;
178  boldFont.setBold(true);
179 
180  QString input = index.data(Qt::DisplayRole).toString();
181  QString result = index.data(ResultRole).toString();
182 
183  // Draw the background
184  bool selected = option.state & QStyle::State_Selected;
185 
186  QStyleOptionViewItemV4 opt(option);
187 
188  QStyle *style = opt.widget->style();
189  style->drawPrimitive(QStyle::PE_PanelItemViewRow, &opt, painter, opt.widget);
190  if (selected) {
191  painter->setPen(option.palette.color(QPalette::HighlightedText));
192  }
193 
194  // Draw the text
195  QTextLayout inputLayout, resultLayout;
196  setLayoutOption(inputLayout, opt, Qt::AlignLeft);
197  setLayoutOption(resultLayout, opt, Qt::AlignRight);
198 
199  inputLayout.setFont(normalFont);
200  resultLayout.setFont(boldFont);
201 
202  QRect contentRect = option.rect.adjusted(2, 4, -2, -4);
203 
204  QSize inputSize = layoutText(inputLayout, input, contentRect.size());
205  QSize resultSize = layoutText(resultLayout, result, QSize(contentRect.width(),
206  contentRect.height() - inputSize.height() - option.fontMetrics.leading()));
207 
208  QRect inputRect = QStyle::alignedRect(option.direction, Qt::AlignLeft | Qt::AlignTop, inputSize, contentRect);
209  QRect resultRect = QStyle::alignedRect(option.direction, Qt::AlignRight | Qt::AlignBottom, resultSize, contentRect);
210 
211  drawTextLayout(painter, inputLayout, inputRect & option.rect);
212  drawTextLayout(painter, resultLayout, resultRect & option.rect);
213 
214  painter->restore();
215 }
216 
217 //------------------------------------------------------------------------
218 
219 ConsoleDock::ConsoleDock(QWidget *parent)
220  : QDockWidget(i18n("Console"), parent)
221 {
222  setFeatures(DockWidgetMovable | DockWidgetFloatable);
223 
224  QWidget *mainFrame = new QWidget(this);
225 
226  consoleView = new QListWidget(mainFrame);
227  consoleView->setWordWrap(true);
228  consoleView->setItemDelegate(new ConsoleItemDelegate(consoleView));
229  consoleView->setAlternatingRowColors(true);
230 
231  connect(consoleView, SIGNAL(itemClicked(QListWidgetItem*)),
232  this, SLOT(slotPasteItem(QListWidgetItem*)));
233  connect(consoleView, SIGNAL(itemDoubleClicked(QListWidgetItem*)),
234  this, SLOT(slotPasteItem(QListWidgetItem*)));
235 
236  consoleInput = new KHistoryComboBox(mainFrame);
237  consoleInput->setSizePolicy(QSizePolicy::MinimumExpanding,
239 
240  connect(consoleInput, SIGNAL(returnPressed()),
241  this, SLOT(slotUserRequestedEval()));
242 
243  consoleInputButton = new QPushButton(i18n("Enter"), mainFrame);
244  connect(consoleInputButton, SIGNAL(clicked(bool)),
245  this, SLOT(slotUserRequestedEval()));
246 
247  QHBoxLayout *bottomLayout = new QHBoxLayout;
248  bottomLayout->setSpacing(0);
249  bottomLayout->setContentsMargins(0, 0, 0, 0);
250  bottomLayout->addWidget(consoleInput);
251  bottomLayout->addWidget(consoleInputButton);
252 
253  QVBoxLayout *mainLayout = new QVBoxLayout;
254  mainLayout->setSpacing(0);
255  mainLayout->setContentsMargins(0, 0, 0, 0);
256  mainLayout->addWidget(consoleView);
257  mainLayout->addLayout(bottomLayout);
258  mainFrame->setLayout(mainLayout);
259 
260  setWidget(mainFrame);
261 }
262 
263 ConsoleDock::~ConsoleDock()
264 {
265 }
266 
267 void ConsoleDock::reportResult(const QString &src, const QString &msg)
268 {
269  QListWidgetItem *item = new QListWidgetItem(src, consoleView);
270  item->setData(ConsoleItemDelegate::ResultRole, msg);
271  consoleView->scrollToItem(item);
272 }
273 
274 void ConsoleDock::slotPasteItem(QListWidgetItem *item)
275 {
276  consoleInput->lineEdit()->setText(item->data(Qt::DisplayRole).toString());
277 }
278 
279 void ConsoleDock::slotUserRequestedEval()
280 {
281  QString src = consoleInput->lineEdit()->text();
282  consoleInput->addToHistory(src);
283  consoleInput->lineEdit()->clear();
284 
285  emit requestEval(src);
286 }
287 
288 }
const QTextOption & textOption() const const
QSize size() const const
void setContentsMargins(int left, int top, int right, int bottom)
int width() const const
void setFont(const QFont &font)
qreal height() const const
qreal naturalTextWidth() const const
void save()
int height() const const
Qt::Alignment alignment() const const
int x() const const
int y() const const
typedef Alignment
void beginLayout()
QRect alignedRect(Qt::LayoutDirection direction, Qt::Alignment alignment, const QSize &size, const QRect &rectangle)
void setLineWidth(qreal width)
void clear()
void setBold(bool enable)
void setWrapMode(QTextOption::WrapMode mode)
bool isValid() const const
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
void setLayout(QLayout *layout)
void setPosition(const QPointF &pos)
void setPen(const QColor &color)
QTextLine createLine()
DisplayRole
virtual QVariant data(int role) const const
PE_PanelItemViewRow
virtual void setData(int role, const QVariant &value)
int leading() const const
void restore()
QString i18n(const char *text, const TYPE &arg...)
int width() const const
QVariant data(int role) const const
QTextLine lineAt(int i) const const
QFont font() const const
bool isValid(QStringView ifopt)
void setTextDirection(Qt::LayoutDirection direction)
int height() const const
virtual void drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const const =0
void setTextOption(const QTextOption &option)
Qt::Alignment visualAlignment(Qt::LayoutDirection direction, Qt::Alignment alignment)
void setText(const QString &string)
void setAlignment(Qt::Alignment alignment)
QString toString() const const
void setSpacing(int spacing)
void endLayout()
void draw(QPainter *painter, const QPointF &position, const QTextLayout::FormatRange *selection) const const
void addLayout(QLayout *layout, int stretch)
int lineCount() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Oct 26 2021 22:47:58 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.