aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@nokia.com>2011-02-21 16:45:07 +0100
committerFriedemann Kleint <Friedemann.Kleint@nokia.com>2011-02-21 16:51:00 +0100
commitcbafc50acc48d75a1fc993e72bcb6587f8bb9a4e (patch)
treefa639b4e90dfd5e6392d6b7f430e2ac91aece34b
parent6507f5ff835be0e39a235b787cbd62e1943afe89 (diff)
Debugger: Make tooltips use standard text editor tooltips.
Extend text editor tooltips by a 'widget content', making it possible to show any widget utilizing the fact that the QTipLabel actually is a frame (and thus a container). Introduce concept of 'interactive' tooltips and modify the tooltip-closing mechanism such that simple interaction is possible. Emit the base text editor's tooltip signals with the correct position and add API to calculate the tooltip position from the cursor position. Add API for pinning tooltips to the text editor (by removing them from the QTipLabel layout). Modify the Debugger's tooltipmanager not to manage tooltips under TextEditor control and to take over control only once tooltips are pinned. Rubber-stamped-by: Leandro T. C. Melo <leandro.melo@nokia.com>
-rw-r--r--src/plugins/debugger/cdb/cdbengine.cpp2
-rw-r--r--src/plugins/debugger/debuggerplugin.cpp1
-rw-r--r--src/plugins/debugger/debuggertooltipmanager.cpp250
-rw-r--r--src/plugins/debugger/debuggertooltipmanager.h35
-rw-r--r--src/plugins/debugger/gdb/gdbengine.cpp8
-rw-r--r--src/plugins/debugger/watchwindow.cpp6
-rw-r--r--src/plugins/texteditor/basehoverhandler.cpp11
-rw-r--r--src/plugins/texteditor/basetexteditor.cpp23
-rw-r--r--src/plugins/texteditor/basetexteditor.h2
-rw-r--r--src/plugins/texteditor/tooltip/tipcontents.cpp77
-rw-r--r--src/plugins/texteditor/tooltip/tipcontents.h31
-rw-r--r--src/plugins/texteditor/tooltip/tipfactory.cpp16
-rw-r--r--src/plugins/texteditor/tooltip/tips.cpp67
-rw-r--r--src/plugins/texteditor/tooltip/tips.h28
-rw-r--r--src/plugins/texteditor/tooltip/tooltip.cpp37
15 files changed, 421 insertions, 173 deletions
diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp
index 8677a5e293..86a11b6290 100644
--- a/src/plugins/debugger/cdb/cdbengine.cpp
+++ b/src/plugins/debugger/cdb/cdbengine.cpp
@@ -500,7 +500,7 @@ bool CdbEngine::setToolTipExpression(const QPoint &mousePos,
tw->setDebuggerModel(LocalsWatch);
tw->setExpression(exp);
tw->acquireEngine(this);
- DebuggerToolTipManager::instance()->add(mousePos, tw);
+ DebuggerToolTipManager::instance()->showToolTip(mousePos, editor, tw);
return true;
}
diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp
index a7e112bcb3..caaa78a2df 100644
--- a/src/plugins/debugger/debuggerplugin.cpp
+++ b/src/plugins/debugger/debuggerplugin.cpp
@@ -2008,7 +2008,6 @@ void DebuggerPluginPrivate::cleanupViews()
{
m_reverseDirectionAction->setChecked(false);
m_reverseDirectionAction->setEnabled(false);
- m_toolTipManager->closeUnpinnedToolTips();
if (!boolSetting(CloseBuffersOnExit))
return;
diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp
index 30fd434309..1941e0de5d 100644
--- a/src/plugins/debugger/debuggertooltipmanager.cpp
+++ b/src/plugins/debugger/debuggertooltipmanager.cpp
@@ -43,9 +43,12 @@
#include <coreplugin/icore.h>
#include <coreplugin/modemanager.h>
#include <coreplugin/imode.h>
+#include <coreplugin/coreconstants.h>
#include <coreplugin/editormanager/editormanager.h>
#include <texteditor/itexteditor.h>
+#include <texteditor/basetexteditor.h>
#include <texteditor/tooltip/tooltip.h>
+#include <texteditor/tooltip/tipcontents.h>
#include <utils/qtcassert.h>
@@ -66,8 +69,6 @@
#include <QtGui/QTextCursor>
#include <QtGui/QTextDocument>
#include <QtGui/QLabel>
-#include <QtGui/QMenu>
-#include <QtGui/QAction>
#include <QtGui/QClipboard>
#include <QtCore/QVariant>
@@ -76,6 +77,7 @@
#include <QtCore/QTimer>
enum { debugToolTips = 0 };
+enum { debugToolTipPositioning = 0 };
// Expire tooltips after n days on (no longer load them) in order
// to avoid them piling up.
@@ -138,28 +140,29 @@ namespace Internal {
// A convenience struct to pass around all tooltip-relevant editor members
// (TextEditor, Widget, File, etc), constructing from a Core::IEditor.
-struct DebuggerToolTipEditor
+class DebuggerToolTipEditor
{
+public:
explicit DebuggerToolTipEditor(Core::IEditor *ie = 0);
- inline bool isValid() const { return textEditor != 0 && plainTextEdit != 0 && file != 0; }
+ inline bool isValid() const { return textEditor != 0 && baseTextEditor != 0 && file != 0; }
inline operator bool() const { return isValid(); }
QString fileName() const { return file ? file->fileName() : QString(); }
static DebuggerToolTipEditor currentToolTipEditor();
TextEditor::ITextEditor *textEditor;
- QPlainTextEdit *plainTextEdit;
+ TextEditor::BaseTextEditor *baseTextEditor;
Core::IFile *file;
};
DebuggerToolTipEditor::DebuggerToolTipEditor(Core::IEditor *ie) :
- textEditor(0), plainTextEdit(0), file(0)
+ textEditor(0), baseTextEditor(0), file(0)
{
if (ie && ie->file() && isEditorDebuggable(ie)) {
if (TextEditor::ITextEditor *te = qobject_cast<TextEditor::ITextEditor *>(ie)) {
- if (QPlainTextEdit *pe = qobject_cast<QPlainTextEdit *>(ie->widget())) {
+ if (TextEditor::BaseTextEditor *pe = qobject_cast<TextEditor::BaseTextEditor *>(ie->widget())) {
textEditor = te;
- plainTextEdit = pe;
+ baseTextEditor = pe;
file = ie->file();
}
}
@@ -436,12 +439,8 @@ PinnableToolTipWidget::PinnableToolTipWidget(QWidget *parent) :
m_pinState(Unpinned),
m_mainVBoxLayout(new QVBoxLayout),
m_toolBar(new QToolBar),
- m_toolButton(new QToolButton),
- m_menu(new QMenu)
+ m_toolButton(new QToolButton)
{
- setWindowFlags(Qt::ToolTip);
- setAttribute(Qt::WA_DeleteOnClose);
-
m_mainVBoxLayout->setSizeConstraint(QLayout::SetFixedSize);
m_mainVBoxLayout->setContentsMargins(0, 0, 0, 0);
@@ -449,8 +448,6 @@ PinnableToolTipWidget::PinnableToolTipWidget(QWidget *parent) :
const QList<QSize> pinIconSizes = pinIcon.availableSizes();
m_toolButton->setIcon(pinIcon);
- m_toolButton->setMenu(m_menu);
- m_toolButton->setPopupMode(QToolButton::MenuButtonPopup);
connect(m_toolButton, SIGNAL(clicked()), this, SLOT(toolButtonClicked()));
m_toolBar->setProperty("_q_custom_style_disabled", QVariant(true));
@@ -463,16 +460,6 @@ PinnableToolTipWidget::PinnableToolTipWidget(QWidget *parent) :
setLayout(m_mainVBoxLayout);
}
-void PinnableToolTipWidget::addMenuAction(QAction *a)
-{
- m_menu->addAction(a);
-}
-
-void PinnableToolTipWidget::addCloseAllMenuAction()
-{
- m_menu->addAction(tr("Close All"), this, SIGNAL(closeAllRequested()));
-}
-
void PinnableToolTipWidget::addWidget(QWidget *w)
{
w->setFocusPolicy(Qt::NoFocus);
@@ -489,9 +476,15 @@ void PinnableToolTipWidget::pin()
if (m_pinState == Unpinned) {
m_pinState = Pinned;
m_toolButton->setIcon(style()->standardIcon(QStyle::SP_DockWidgetCloseButton));
+ doPin();
+ emit pinned();
}
}
+void PinnableToolTipWidget::doPin()
+{
+}
+
void PinnableToolTipWidget::toolButtonClicked()
{
switch (m_pinState) {
@@ -504,16 +497,6 @@ void PinnableToolTipWidget::toolButtonClicked()
}
}
-void PinnableToolTipWidget::leaveEvent(QEvent *)
-{
- if (!m_menu->isVisible() && m_pinState == Unpinned
- && QApplication::keyboardModifiers() == Qt::NoModifier) {
- if (debugToolTips)
- qDebug("ToolTipWidget::leaveEvent: closing %p", this);
- close();
- }
-}
-
/* A Label that emits a signal when the user drags for moving the parent
* widget around. */
class DraggableLabel : public QLabel
@@ -522,6 +505,9 @@ class DraggableLabel : public QLabel
public:
explicit DraggableLabel(QWidget *parent = 0);
+ bool isActive() const { return m_active; }
+ void setActive(bool v) { m_active = v; }
+
signals:
void dragged(const QPoint &d);
@@ -532,16 +518,17 @@ protected:
private:
QPoint m_moveStartPos;
+ bool m_active;
};
DraggableLabel::DraggableLabel(QWidget *parent) :
- QLabel(parent), m_moveStartPos(-1, -1)
+ QLabel(parent), m_moveStartPos(-1, -1), m_active(false)
{
}
void DraggableLabel::mousePressEvent(QMouseEvent * event)
{
- if (event->button() == Qt::LeftButton) {
+ if (m_active && event->button() == Qt::LeftButton) {
m_moveStartPos = event->globalPos();
event->accept();
}
@@ -550,22 +537,22 @@ void DraggableLabel::mousePressEvent(QMouseEvent * event)
void DraggableLabel::mouseReleaseEvent(QMouseEvent * event)
{
- if (event->button() == Qt::LeftButton)
+ if (m_active && event->button() == Qt::LeftButton)
m_moveStartPos = QPoint(-1, -1);
QLabel::mouseReleaseEvent(event);
}
void DraggableLabel::mouseMoveEvent(QMouseEvent * event)
{
- if (event->buttons() && Qt::LeftButton) {
+ if (m_active && (event->buttons() & Qt::LeftButton)) {
if (m_moveStartPos != QPoint(-1, -1)) {
const QPoint newPos = event->globalPos();
emit dragged(event->globalPos() - m_moveStartPos);
m_moveStartPos = newPos;
}
event->accept();
- QLabel::mouseMoveEvent(event);
}
+ QLabel::mouseMoveEvent(event);
}
/*!
@@ -622,6 +609,13 @@ QDebug operator<<(QDebug d, const DebuggerToolTipContext &c)
In addition, if the stored line number diverges too much from the current line
number in positionShow(), the tooltip is also closed/discarded.
+
+ The widget is that is first shown by the TextEditor's tooltip
+ class and typically closed by it unless the user pins it.
+ In that case, it is removed from the tip's layout, added to the DebuggerToolTipManager's
+ list of pinned tooltips and re-shown as a global tooltip widget.
+ As the debugger stop and continues, it shows the debugger values or a copy
+ of them. On closing or session changes, the contents it saved.
*/
static inline QString msgReleasedText() { return AbstractDebuggerToolTipWidget::tr("Previous"); }
@@ -631,14 +625,15 @@ AbstractDebuggerToolTipWidget::AbstractDebuggerToolTipWidget(QWidget *parent) :
m_titleLabel(new DraggableLabel), m_engineAcquired(false),
m_creationDate(QDate::currentDate())
{
+ QToolButton *copyButton = new QToolButton;
+ copyButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_COPY)));
+ connect(copyButton, SIGNAL(clicked()), this, SLOT(copy()));
+ addToolBarWidget(copyButton);
+
m_titleLabel->setText(msgReleasedText());
m_titleLabel->setMinimumWidth(40); // Ensure a draggable area even if text is empty.
connect(m_titleLabel, SIGNAL(dragged(QPoint)), this, SLOT(slotDragged(QPoint)));
addToolBarWidget(m_titleLabel);
- QAction *copyAction = new QAction(tr("Copy"), this);
- connect(copyAction, SIGNAL(triggered()), this, SLOT(copy()));
- addMenuAction(copyAction);
- addCloseAllMenuAction();
}
bool AbstractDebuggerToolTipWidget::matches(const QString &fileName,
@@ -698,14 +693,15 @@ void AbstractDebuggerToolTipWidget::slotDragged(const QPoint &p)
m_offset += p;
}
-bool AbstractDebuggerToolTipWidget::positionShow(const QPlainTextEdit *pe)
+bool AbstractDebuggerToolTipWidget::positionShow(const DebuggerToolTipEditor &te)
{
// Figure out new position of tooltip using the text edit.
// If the line changed too much, close this tip.
- QTC_ASSERT(pe, return false; )
- QTextCursor cursor(pe->document());
+ QTC_ASSERT(te, return false; )
+ QTextCursor cursor(te.baseTextEditor->document());
cursor.setPosition(m_context.position);
const int line = cursor.blockNumber();
+ const int column = cursor.columnNumber();
if (qAbs(m_context.line - line) > 2) {
if (debugToolTips)
qDebug() << "Closing " << this << " in positionShow() lines "
@@ -713,19 +709,19 @@ bool AbstractDebuggerToolTipWidget::positionShow(const QPlainTextEdit *pe)
close();
return false;
}
- const QRect plainTextToolTipArea = QRect(pe->cursorRect(cursor).topLeft(), QSize(sizeHint()));
- const QRect plainTextArea = QRect(QPoint(0, 0), QPoint(pe->width(), pe->height()));
- const QPoint screenPos = pe->mapToGlobal(plainTextToolTipArea.topLeft() + m_offset);
- const bool visible = plainTextArea.contains(plainTextToolTipArea);
+ if (debugToolTipPositioning)
+ qDebug() << "positionShow" << this << line << column;
+
+ const QPoint screenPos = te.baseTextEditor->toolTipPosition(cursor) + m_offset;
+ const QRect toolTipArea = QRect(screenPos, QSize(sizeHint()));
+ const QRect plainTextArea = QRect(te.baseTextEditor->mapToGlobal(QPoint(0, 0)), te.baseTextEditor->size());
+ const bool visible = plainTextArea.contains(toolTipArea);
if (debugToolTips)
qDebug() << "DebuggerToolTipWidget::positionShow() " << this << m_context
- << " line: " << line << " plainTextPos " << plainTextToolTipArea
+ << " line: " << line << " plainTextPos " << toolTipArea
<< " offset: " << m_offset
<< " Area: " << plainTextArea << " Screen pos: "
- << screenPos << pe << " visible=" << visible
- << " on " << pe->parentWidget()
- << " at " << pe->mapToGlobal(QPoint(0, 0));
-
+ << screenPos << te.baseTextEditor << " visible=" << visible;
if (!visible) {
hide();
@@ -737,6 +733,19 @@ bool AbstractDebuggerToolTipWidget::positionShow(const QPlainTextEdit *pe)
return true;
}
+void AbstractDebuggerToolTipWidget::doPin()
+{
+ if (parentWidget()) {
+ // We are currently within a text editor tooltip:
+ // Rip out of parent widget and re-show as a tooltip
+ TextEditor::WidgetContent::pinToolTip(this);
+ } else {
+ // We have just be restored from session data.
+ setWindowFlags(Qt::ToolTip);
+ }
+ m_titleLabel->setActive(true); // User can now drag
+}
+
// Parse a 'yyyyMMdd' date
static inline QDate dateFromString(const QString &date)
{
@@ -790,6 +799,7 @@ AbstractDebuggerToolTipWidget *AbstractDebuggerToolTipWidget::loadSessionDataI(Q
rc = new DebuggerTreeViewToolTipWidget;
if (rc) {
rc->setContext(context);
+ rc->setAttribute(Qt::WA_DeleteOnClose);
rc->setEngineType(engineType);
rc->doLoadSessionData(r);
rc->setCreationDate(creationDate);
@@ -827,13 +837,15 @@ void AbstractDebuggerToolTipWidget::saveSessionData(QXmlStreamWriter &w) const
}
// Model for tooltips filtering a local variable using the locals model,
-// taking the expression.
+// taking the expression. Suppress the tooltip data.
class DebuggerToolTipExpressionFilterModel : public QSortFilterProxyModel
{
public:
explicit DebuggerToolTipExpressionFilterModel(QAbstractItemModel *model, const QString &exp, QObject *parent = 0);
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
private:
const QString m_expression;
};
@@ -846,6 +858,12 @@ DebuggerToolTipExpressionFilterModel::DebuggerToolTipExpressionFilterModel(QAbst
setSourceModel(model);
}
+QVariant DebuggerToolTipExpressionFilterModel::data(const QModelIndex &index, int role) const
+{
+ return role != Qt::ToolTipRole ?
+ QSortFilterProxyModel::data(index, role) : QVariant();
+}
+
bool DebuggerToolTipExpressionFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
// Match on expression for top level, else pass through.
@@ -1092,23 +1110,22 @@ QString DebuggerTreeViewToolTipWidget::clipboardContents() const
/*!
\class DebuggerToolTipManager
- Manages the tooltip widgets, listens on editor scroll and main window move
+ Manages the pinned tooltip widgets, listens on editor scroll and main window move
events and takes care of repositioning the tooltips.
Listens to editor change and mode change. In debug mode, if there tooltips
for the current editor (by file name), position and show them.
- In addition, listen on state and stack frame change of the engine.
- If a stack frame is activated, have all matching tooltips (by file name)
- acquire the engine, other release.
-
+ In addition, listens on state change and stack frame completed signals
+ of the engine. If a stack frame is completed, have all matching tooltips
+ (by file name and function) acquire the engine, others release.
*/
DebuggerToolTipManager *DebuggerToolTipManager::m_instance = 0;
DebuggerToolTipManager::DebuggerToolTipManager(QObject *parent) :
QObject(parent), m_debugModeActive(false),
- m_lastToolTipPos(-1), m_lastToolTipEditor(0)
+ m_lastToolTipPoint(-1, -1), m_lastToolTipEditor(0)
{
DebuggerToolTipManager::m_instance = this;
}
@@ -1125,33 +1142,49 @@ void DebuggerToolTipManager::registerEngine(DebuggerEngine *engine)
connect(engine, SIGNAL(stackFrameCompleted()), this, SLOT(slotStackFrameCompleted()));
}
-void DebuggerToolTipManager::add(const QPoint &p, AbstractDebuggerToolTipWidget *toolTipWidget)
+void DebuggerToolTipManager::showToolTip(const QPoint &p, Core::IEditor *editor,
+ AbstractDebuggerToolTipWidget *toolTipWidget)
{
- closeUnpinnedToolTips();
- toolTipWidget->move(p);
- toolTipWidget->show();
- add(toolTipWidget);
+ QWidget *widget = editor->widget();
+ if (debugToolTipPositioning)
+ qDebug() << "DebuggerToolTipManager::showToolTip" << p << " Mouse at " << QCursor::pos();
+ const TextEditor::WidgetContent widgetContent(toolTipWidget, true);
+ TextEditor::ToolTip::instance()->show(p, widgetContent, widget);
+ registerToolTip(toolTipWidget);
}
-void DebuggerToolTipManager::add(AbstractDebuggerToolTipWidget *toolTipWidget)
+void DebuggerToolTipManager::registerToolTip(AbstractDebuggerToolTipWidget *toolTipWidget)
{
QTC_ASSERT(toolTipWidget->context().isValid(), return; )
- connect(toolTipWidget, SIGNAL(closeAllRequested()), this, SLOT(closeAllToolTips()));
- m_tooltips.push_back(toolTipWidget);
+ switch (toolTipWidget->pinState()) {
+ case PinnableToolTipWidget::Pinned:
+ m_pinnedTooltips.push_back(toolTipWidget);
+ break;
+ case PinnableToolTipWidget::Unpinned:
+ // Catch the widget once it is pinned.
+ connect(toolTipWidget, SIGNAL(pinned()), this, SLOT(slotPinnedFirstTime()));
+ break;
+ }
+}
+
+void DebuggerToolTipManager::slotPinnedFirstTime()
+{
+ if (AbstractDebuggerToolTipWidget *tw = qobject_cast<AbstractDebuggerToolTipWidget *>(sender()))
+ m_pinnedTooltips.push_back(tw);
}
DebuggerToolTipManager::DebuggerToolTipWidgetList &DebuggerToolTipManager::purgeClosedToolTips()
{
- if (!m_tooltips.isEmpty()) {
- for (DebuggerToolTipWidgetList::iterator it = m_tooltips.begin(); it != m_tooltips.end() ; ) {
+ if (!m_pinnedTooltips.isEmpty()) {
+ for (DebuggerToolTipWidgetList::iterator it = m_pinnedTooltips.begin(); it != m_pinnedTooltips.end() ; ) {
if (it->isNull()) {
- it = m_tooltips.erase(it);
+ it = m_pinnedTooltips.erase(it);
} else {
++it;
}
}
}
- return m_tooltips;
+ return m_pinnedTooltips;
}
void DebuggerToolTipManager::moveToolTipsBy(const QPoint &distance)
@@ -1164,7 +1197,7 @@ void DebuggerToolTipManager::moveToolTipsBy(const QPoint &distance)
bool DebuggerToolTipManager::eventFilter(QObject *, QEvent *e)
{
// Move along with parent (toplevel)
- if (e->type() == QEvent::Move && isActive()) {
+ if (e->type() == QEvent::Move && hasToolTips()) {
const QMoveEvent *me = static_cast<const QMoveEvent *>(e);
moveToolTipsBy(me->pos() - me->oldPos());
}
@@ -1188,10 +1221,10 @@ void DebuggerToolTipManager::loadSessionData()
const double version = r.attributes().value(QLatin1String(sessionVersionAttributeC)).toString().toDouble();
while (!r.atEnd())
if (AbstractDebuggerToolTipWidget *tw = AbstractDebuggerToolTipWidget::loadSessionData(r))
- add(tw);
+ registerToolTip(tw);
if (debugToolTips)
- qDebug() << "DebuggerToolTipManager::loadSessionData version " << version << " restored " << m_tooltips.size();
+ qDebug() << "DebuggerToolTipManager::loadSessionData version " << version << " restored " << m_pinnedTooltips.size();
slotUpdateVisibleToolTips();
}
@@ -1203,12 +1236,12 @@ void DebuggerToolTipManager::saveSessionData()
w.writeStartDocument();
w.writeStartElement(QLatin1String(sessionDocumentC));
w.writeAttribute(QLatin1String(sessionVersionAttributeC), QLatin1String("1.0"));
- foreach (const QPointer<AbstractDebuggerToolTipWidget> &tw, m_tooltips)
+ foreach (const QPointer<AbstractDebuggerToolTipWidget> &tw, m_pinnedTooltips)
tw->saveSessionData(w);
w.writeEndDocument();
}
if (debugToolTips)
- qDebug() << "DebuggerToolTipManager::saveSessionData" << m_tooltips.size() << data ;
+ qDebug() << "DebuggerToolTipManager::saveSessionData" << m_pinnedTooltips.size() << data ;
debuggerCore()->setSessionValue(QLatin1String(sessionSettingsKeyC), QVariant(data));
}
@@ -1219,25 +1252,7 @@ void DebuggerToolTipManager::closeAllToolTips()
foreach (const QPointer<AbstractDebuggerToolTipWidget> &tw, purgeClosedToolTips())
tw->close();
- m_tooltips.clear();
-}
-
-void DebuggerToolTipManager::closeUnpinnedToolTips()
-{
- if (debugToolTips)
- qDebug() << "DebuggerToolTipManager::closeUnpinnedToolTips";
-
- // Filter out unpinned ones, purge null on that occasion
- for (DebuggerToolTipWidgetList::iterator it = m_tooltips.begin(); it != m_tooltips.end() ; ) {
- if (it->isNull()) {
- it = m_tooltips.erase(it);
- } else if ((*it)->pinState() == AbstractDebuggerToolTipWidget::Unpinned) {
- (*it)->close();
- it = m_tooltips.erase(it);
- } else {
- ++it;
- }
- }
+ m_pinnedTooltips.clear();
}
void DebuggerToolTipManager::hide()
@@ -1267,9 +1282,9 @@ void DebuggerToolTipManager::slotUpdateVisibleToolTips()
// Reposition and show all tooltips of that file.
const QString fileName = toolTipEditor.fileName();
- foreach (const QPointer<AbstractDebuggerToolTipWidget> &tw, m_tooltips) {
+ foreach (const QPointer<AbstractDebuggerToolTipWidget> &tw, m_pinnedTooltips) {
if (tw->fileName() == fileName) {
- tw->positionShow(toolTipEditor.plainTextEdit);
+ tw->positionShow(toolTipEditor);
} else {
tw->hide();
}
@@ -1331,7 +1346,7 @@ void DebuggerToolTipManager::slotStackFrameCompleted()
qPrintable(engineName), qPrintable(fileName), lineNumber,
qPrintable(function));
unsigned acquiredCount = 0;
- foreach (const QPointer<AbstractDebuggerToolTipWidget> &tw, m_tooltips) {
+ foreach (const QPointer<AbstractDebuggerToolTipWidget> &tw, m_pinnedTooltips) {
if (tw->matches(fileName, engineName, function)) {
tw->acquireEngine(engine);
acquiredCount++;
@@ -1354,7 +1369,7 @@ void DebuggerToolTipManager::slotEditorOpened(Core::IEditor *e)
{
// Move tooltip along when scrolled.
if (DebuggerToolTipEditor toolTipEditor = DebuggerToolTipEditor(e)) {
- connect(toolTipEditor.plainTextEdit->verticalScrollBar(), SIGNAL(valueChanged(int)),
+ connect(toolTipEditor.baseTextEditor->verticalScrollBar(), SIGNAL(valueChanged(int)),
this, SLOT(slotUpdateVisibleToolTips()));
connect(toolTipEditor.textEditor,
SIGNAL(tooltipOverrideRequested(TextEditor::ITextEditor*,QPoint,int,bool*)),
@@ -1380,7 +1395,7 @@ void DebuggerToolTipManager::debugModeEntered()
foreach (Core::IEditor *e, em->openedEditors())
slotEditorOpened(e);
// Position tooltips delayed once all the editor placeholder layouting is done.
- if (!m_tooltips.isEmpty())
+ if (!m_pinnedTooltips.isEmpty())
QTimer::singleShot(0, this, SLOT(slotUpdateVisibleToolTips()));
}
}
@@ -1399,14 +1414,14 @@ void DebuggerToolTipManager::leavingDebugMode()
if (Core::EditorManager *em = Core::EditorManager::instance()) {
foreach (Core::IEditor *e, em->openedEditors()) {
if (DebuggerToolTipEditor toolTipEditor = DebuggerToolTipEditor(e)) {
- toolTipEditor.plainTextEdit->verticalScrollBar()->disconnect(this);
+ toolTipEditor.baseTextEditor->verticalScrollBar()->disconnect(this);
toolTipEditor.textEditor->disconnect(this);
}
}
em->disconnect(this);
}
m_lastToolTipEditor = 0;
- m_lastToolTipPos = -1;
+ m_lastToolTipPoint = QPoint(-1, -1);
}
}
@@ -1415,12 +1430,18 @@ void DebuggerToolTipManager::slotTooltipOverrideRequested(TextEditor::ITextEdito
int pos, bool *handled)
{
QTC_ASSERT(handled, return);
- if (debugToolTips)
- qDebug() << ">slotTooltipOverrideRequested() " << editor << point << pos << *handled;
+
+ const int movedDistance = (point - m_lastToolTipPoint).manhattanLength();
+ const bool samePosition = m_lastToolTipEditor == editor && movedDistance < 25;
+ if (debugToolTipPositioning)
+ qDebug() << ">slotTooltipOverrideRequested() " << editor << point
+ << "from " << m_lastToolTipPoint << ") pos: "
+ << pos << *handled
+ << " Same position=" << samePosition << " d=" << movedDistance;
DebuggerEngine *currentEngine = 0;
do {
- if (*handled || (m_lastToolTipEditor == editor && pos == m_lastToolTipPos))
+ if (*handled || samePosition)
break; // Avoid flicker.
DebuggerCore *core = debuggerCore();
@@ -1433,11 +1454,9 @@ void DebuggerToolTipManager::slotTooltipOverrideRequested(TextEditor::ITextEdito
const DebuggerToolTipContext context = DebuggerToolTipContext::fromEditor(editor, pos);
if (context.isValid() && currentEngine->setToolTipExpression(point, editor, context)) {
- if (TextEditor::ToolTip::instance()->isVisible())
- TextEditor::ToolTip::instance()->hide();
*handled = true;
m_lastToolTipEditor = editor;
- m_lastToolTipPos = pos;
+ m_lastToolTipPoint = point;
}
} while (false);
@@ -1446,10 +1465,9 @@ void DebuggerToolTipManager::slotTooltipOverrideRequested(TextEditor::ITextEdito
// and no leave was triggered.
if (!*handled) {
m_lastToolTipEditor = 0;
- m_lastToolTipPos = -1;
- closeUnpinnedToolTips();
+ m_lastToolTipPoint = QPoint(-1, -1);
}
- if (debugToolTips)
+ if (debugToolTipPositioning)
qDebug() << "<slotTooltipOverrideRequested() " << currentEngine << *handled;
}
@@ -1458,7 +1476,7 @@ QStringList DebuggerToolTipManager::treeWidgetExpressions(const QString &fileNam
const QString &function) const
{
QStringList rc;
- foreach (const QPointer<AbstractDebuggerToolTipWidget> &tw, m_tooltips)
+ foreach (const QPointer<AbstractDebuggerToolTipWidget> &tw, m_pinnedTooltips)
if (!tw.isNull() && tw->matches(fileName, engineType, function))
if (const DebuggerTreeViewToolTipWidget *ttw = qobject_cast<const DebuggerTreeViewToolTipWidget *>(tw.data()))
rc.push_back(ttw->expression());
diff --git a/src/plugins/debugger/debuggertooltipmanager.h b/src/plugins/debugger/debuggertooltipmanager.h
index 0e59611aa8..2f0a6ad6c1 100644
--- a/src/plugins/debugger/debuggertooltipmanager.h
+++ b/src/plugins/debugger/debuggertooltipmanager.h
@@ -53,9 +53,7 @@ class QStandardItemModel;
class QPlainTextEdit;
class QLabel;
class QToolBar;
-class QMenu;
class QDebug;
-class QAction;
QT_END_NAMESPACE
namespace Core {
@@ -72,6 +70,7 @@ class DebuggerEngine;
namespace Internal {
class DraggableLabel;
+class DebuggerToolTipEditor;
class PinnableToolTipWidget : public QWidget
{
@@ -85,32 +84,28 @@ public:
};
explicit PinnableToolTipWidget(QWidget *parent = 0);
+
PinState pinState() const { return m_pinState; }
void addWidget(QWidget *w);
void addToolBarWidget(QWidget *w);
- void addMenuAction(QAction *a);
- // Add an action to "close all". Call in constructor after populating the tool button menu.
- void addCloseAllMenuAction();
public slots:
void pin();
signals:
- void closeAllRequested();
-
-protected:
- virtual void leaveEvent(QEvent *ev);
+ void pinned();
private slots:
void toolButtonClicked();
private:
+ virtual void doPin();
+
PinState m_pinState;
QVBoxLayout *m_mainVBoxLayout;
QToolBar *m_toolBar;
QToolButton *m_toolButton;
- QMenu *m_menu;
};
class DebuggerToolTipContext
@@ -165,9 +160,10 @@ public slots:
void acquireEngine(Debugger::DebuggerEngine *engine);
void releaseEngine();
void copy();
- bool positionShow(const QPlainTextEdit *pe);
+ bool positionShow(const DebuggerToolTipEditor &pe);
private slots:
+ virtual void doPin();
void slotDragged(const QPoint &p);
protected:
@@ -250,20 +246,19 @@ public:
static DebuggerToolTipManager *instance() { return m_instance; }
void registerEngine(DebuggerEngine *engine);
+ bool hasToolTips() const { return !m_pinnedTooltips.isEmpty(); }
// Collect all expressions of DebuggerTreeViewToolTipWidget
QStringList treeWidgetExpressions(const QString &fileName,
const QString &engineType = QString(),
const QString &function= QString()) const;
- void add(const QPoint &p, AbstractDebuggerToolTipWidget *w);
+ void showToolTip(const QPoint &p, Core::IEditor *editor, AbstractDebuggerToolTipWidget *);
virtual bool eventFilter(QObject *, QEvent *);
static bool debug();
-signals:
-
public slots:
void debugModeEntered();
void leavingDebugMode();
@@ -271,31 +266,31 @@ public slots:
void loadSessionData();
void saveSessionData();
void closeAllToolTips();
- void closeUnpinnedToolTips();
- void hide();
+ void hide()
+;
private slots:
void slotUpdateVisibleToolTips();
void slotDebuggerStateChanged(Debugger::DebuggerState);
void slotStackFrameCompleted();
void slotEditorOpened(Core::IEditor *);
+ void slotPinnedFirstTime();
void slotTooltipOverrideRequested(TextEditor::ITextEditor *editor, const QPoint &point,
int pos, bool *handled);
private:
typedef QList<QPointer<AbstractDebuggerToolTipWidget> > DebuggerToolTipWidgetList;
- inline bool isActive() const { return !m_tooltips.isEmpty(); }
- void add(AbstractDebuggerToolTipWidget *toolTipWidget);
+ void registerToolTip(AbstractDebuggerToolTipWidget *toolTipWidget);
void moveToolTipsBy(const QPoint &distance);
// Purge out closed (null) tooltips and return list for convenience
DebuggerToolTipWidgetList &purgeClosedToolTips();
static DebuggerToolTipManager *m_instance;
- DebuggerToolTipWidgetList m_tooltips;
+ DebuggerToolTipWidgetList m_pinnedTooltips;
bool m_debugModeActive;
- int m_lastToolTipPos;
+ QPoint m_lastToolTipPoint;
Core::IEditor *m_lastToolTipEditor;
};
diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp
index 070f40e39a..dce1d60f1b 100644
--- a/src/plugins/debugger/gdb/gdbengine.cpp
+++ b/src/plugins/debugger/gdb/gdbengine.cpp
@@ -108,10 +108,12 @@ namespace Internal {
class GdbToolTipContext : public DebuggerToolTipContext
{
public:
- GdbToolTipContext(const DebuggerToolTipContext &c) : DebuggerToolTipContext(c) {}
+ GdbToolTipContext(const DebuggerToolTipContext &c) :
+ DebuggerToolTipContext(c), editor(0) {}
QPoint mousePosition;
QString expression;
+ Core::IEditor *editor;
};
static const char winPythonVersionC[] = "python2.5";
@@ -3406,7 +3408,8 @@ bool GdbEngine::showToolTip()
tw->setExpression(expression);
tw->setContext(*m_toolTipContext);
tw->acquireEngine(this);
- DebuggerToolTipManager::instance()->add(m_toolTipContext->mousePosition, tw);
+ DebuggerToolTipManager::instance()->showToolTip(m_toolTipContext->mousePosition,
+ m_toolTipContext->editor, tw);
return true;
}
@@ -3481,6 +3484,7 @@ bool GdbEngine::setToolTipExpression(const QPoint &mousePos,
m_toolTipContext.reset(new GdbToolTipContext(context));
m_toolTipContext->mousePosition = mousePos;
m_toolTipContext->expression = exp;
+ m_toolTipContext->editor = editor;
if (DebuggerToolTipManager::debug())
qDebug() << "GdbEngine::setToolTipExpression2 " << exp << (*m_toolTipContext);
diff --git a/src/plugins/debugger/watchwindow.cpp b/src/plugins/debugger/watchwindow.cpp
index f4c554752a..430fb96eff 100644
--- a/src/plugins/debugger/watchwindow.cpp
+++ b/src/plugins/debugger/watchwindow.cpp
@@ -485,6 +485,10 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
menu.addAction(actShowInEditor);
menu.addAction(debuggerCore()->action(SettingsDialog));
+ QAction *actCloseEditorToolTips = new QAction(tr("Close Editor Tooltips"), &menu);
+ actCloseEditorToolTips->setEnabled(DebuggerToolTipManager::instance()->hasToolTips());
+ menu.addAction(actCloseEditorToolTips);
+
QAction *act = menu.exec(ev->globalPos());
if (act == 0)
return;
@@ -538,6 +542,8 @@ void WatchWindow::contextMenuEvent(QContextMenuEvent *ev)
handler->setUnprintableBase(8);
} else if (act == showUnprintableHexadecimal) {
handler->setUnprintableBase(16);
+ } else if (act == actCloseEditorToolTips) {
+ DebuggerToolTipManager::instance()->closeAllToolTips();
} else {
for (int i = 0; i != typeFormatActions.size(); ++i) {
if (act == typeFormatActions.at(i))
diff --git a/src/plugins/texteditor/basehoverhandler.cpp b/src/plugins/texteditor/basehoverhandler.cpp
index 552dee08ef..9ddb832564 100644
--- a/src/plugins/texteditor/basehoverhandler.cpp
+++ b/src/plugins/texteditor/basehoverhandler.cpp
@@ -82,16 +82,7 @@ void BaseHoverHandler::showToolTip(TextEditor::ITextEditor *editor, const QPoint
editor->setContextHelpId(QString());
process(editor, pos);
-
- const QPoint &actualPoint = point - QPoint(0,
-#ifdef Q_WS_WIN
- 24
-#else
- 16
-#endif
- );
-
- operateTooltip(editor, actualPoint);
+ operateTooltip(editor, point);
}
void BaseHoverHandler::updateContextHelpId(TextEditor::ITextEditor *editor, int pos)
diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp
index d6f10ac401..874aa2b568 100644
--- a/src/plugins/texteditor/basetexteditor.cpp
+++ b/src/plugins/texteditor/basetexteditor.cpp
@@ -2507,6 +2507,19 @@ void BaseTextEditorPrivate::snippetTabOrBacktab(bool forward)
q->setTextCursor(cursor);
}
+// Calculate global position for a tooltip considering the left extra area.
+QPoint BaseTextEditor::toolTipPosition(const QTextCursor &c) const
+{
+ const QPoint cursorPos = mapToGlobal(cursorRect(c).bottomRight() + QPoint(1,1));
+ return cursorPos + QPoint(d->m_extraArea->width(),
+#ifdef Q_WS_WIN
+ -24
+#else
+ -16
+#endif
+ );
+}
+
bool BaseTextEditor::viewportEvent(QEvent *event)
{
d->m_contentsChanged = false;
@@ -2530,15 +2543,13 @@ bool BaseTextEditor::viewportEvent(QEvent *event)
}
// Allow plugins to show tooltips
- const QTextCursor &c = cursorForPosition(pos);
- QPoint cursorPos = mapToGlobal(cursorRect(c).bottomRight() + QPoint(1,1));
- cursorPos.setX(cursorPos.x() + d->m_extraArea->width());
-
+ const QTextCursor c = cursorForPosition(pos);
+ const QPoint toolTipPoint = toolTipPosition(c);
bool handled = false;
BaseTextEditorEditable *editable = editableInterface();
- emit editable->tooltipOverrideRequested(editable, cursorPos, c.position(), &handled);
+ emit editable->tooltipOverrideRequested(editable, toolTipPoint, c.position(), &handled);
if (!handled)
- emit editable->tooltipRequested(editable, cursorPos, c.position());
+ emit editable->tooltipRequested(editable, toolTipPoint, c.position());
return true;
}
return QPlainTextEdit::viewportEvent(event);
diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h
index e2a3bbaf92..385eaa9478 100644
--- a/src/plugins/texteditor/basetexteditor.h
+++ b/src/plugins/texteditor/basetexteditor.h
@@ -235,6 +235,8 @@ public:
void setAutoCompleter(AutoCompleter *autoCompleter);
AutoCompleter *autoCompleter() const;
+ QPoint toolTipPosition(const QTextCursor &c) const;
+
public slots:
void setDisplayName(const QString &title);
diff --git a/src/plugins/texteditor/tooltip/tipcontents.cpp b/src/plugins/texteditor/tooltip/tipcontents.cpp
index 084866bdd0..89351b5f1b 100644
--- a/src/plugins/texteditor/tooltip/tipcontents.cpp
+++ b/src/plugins/texteditor/tooltip/tipcontents.cpp
@@ -32,10 +32,14 @@
**************************************************************************/
#include "tipcontents.h"
+#include "tooltip.h"
+#include "tips.h"
+
+#include <utils/qtcassert.h>
#include <QtCore/QtGlobal>
-using namespace TextEditor;
+namespace TextEditor {
TipContent::TipContent()
{}
@@ -64,6 +68,11 @@ bool ColorContent::isValid() const
return m_color.isValid();
}
+bool ColorContent::isInteractive() const
+{
+ return false;
+}
+
int ColorContent::showTime() const
{
return 4000;
@@ -104,6 +113,11 @@ bool TextContent::isValid() const
return !m_text.isEmpty();
}
+bool TextContent::isInteractive() const
+{
+ return false;
+}
+
int TextContent::showTime() const
{
return 10000 + 40 * qMax(0, m_text.length() - 100);
@@ -122,3 +136,64 @@ const QString &TextContent::text() const
{
return m_text;
}
+
+WidgetContent::WidgetContent(QWidget *w, bool interactive) :
+ m_widget(w), m_interactive(interactive)
+{
+}
+
+TipContent *WidgetContent::clone() const
+{
+ return new WidgetContent(m_widget, m_interactive);
+}
+
+int WidgetContent::typeId() const
+{
+ return WIDGET_CONTENT_ID;
+}
+
+bool WidgetContent::isValid() const
+{
+ return m_widget;
+}
+
+bool WidgetContent::isInteractive() const
+{
+ return m_interactive;
+}
+
+void WidgetContent::setInteractive(bool i)
+{
+ m_interactive = i;
+}
+
+int WidgetContent::showTime() const
+{
+ return 30000;
+}
+
+bool WidgetContent::equals(const TipContent &tipContent) const
+{
+ if (typeId() == tipContent.typeId()) {
+ if (m_widget == static_cast<const WidgetContent &>(tipContent).m_widget)
+ return true;
+ }
+ return false;
+}
+
+bool WidgetContent::pinToolTip(QWidget *w)
+{
+ QTC_ASSERT(w, return false; )
+ // Find the parent WidgetTip, tell it to pin/release the
+ // widget and close.
+ for (QWidget *p = w->parentWidget(); p ; p = p->parentWidget()) {
+ if (Internal::WidgetTip *wt = qobject_cast<Internal::WidgetTip *>(p)) {
+ wt->pinToolTipWidget();
+ ToolTip::instance()->hide();
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/tooltip/tipcontents.h b/src/plugins/texteditor/tooltip/tipcontents.h
index 18dabc7fea..a9b1e9b352 100644
--- a/src/plugins/texteditor/tooltip/tipcontents.h
+++ b/src/plugins/texteditor/tooltip/tipcontents.h
@@ -52,6 +52,7 @@ public:
virtual TipContent *clone() const = 0;
virtual int typeId() const = 0;
virtual bool isValid() const = 0;
+ virtual bool isInteractive() const = 0;
virtual int showTime() const = 0;
virtual bool equals(const TipContent &tipContent) const = 0;
};
@@ -65,6 +66,7 @@ public:
virtual TipContent *clone() const;
virtual int typeId() const;
virtual bool isValid() const;
+ virtual bool isInteractive() const;
virtual int showTime() const;
virtual bool equals(const TipContent &tipContent) const;
@@ -85,6 +87,7 @@ public:
virtual TipContent *clone() const;
virtual int typeId() const;
virtual bool isValid() const;
+ virtual bool isInteractive() const;
virtual int showTime() const;
virtual bool equals(const TipContent &tipContent) const;
@@ -96,6 +99,34 @@ private:
QString m_text;
};
+// A content for displaying any widget (with a layout).
+class TEXTEDITOR_EXPORT WidgetContent : public TipContent
+{
+public:
+ explicit WidgetContent(QWidget *w, bool interactive = false);
+
+ virtual TipContent *clone() const;
+ virtual int typeId() const;
+ virtual bool isValid() const;
+ virtual int showTime() const;
+ virtual bool isInteractive() const;
+ void setInteractive(bool i);
+
+ virtual bool equals(const TipContent &tipContent) const;
+
+ // Helper to 'pin' (show as real window) a tooltip shown
+ // using WidgetContent
+ static bool pinToolTip(QWidget *w);
+
+ static const int WIDGET_CONTENT_ID = 42;
+
+ QWidget *widget() const { return m_widget; }
+
+private:
+ QWidget *m_widget;
+ bool m_interactive;
+};
+
} // namespace TextEditor
#endif // TIPCONTENTS_H
diff --git a/src/plugins/texteditor/tooltip/tipfactory.cpp b/src/plugins/texteditor/tooltip/tipfactory.cpp
index c5ca5ea045..5959134661 100644
--- a/src/plugins/texteditor/tooltip/tipfactory.cpp
+++ b/src/plugins/texteditor/tooltip/tipfactory.cpp
@@ -34,6 +34,9 @@
#include "tipfactory.h"
#include "tipcontents.h"
#include "tips.h"
+#include <utils/qtcassert.h>
+
+#include <QtGui/QVBoxLayout>
using namespace TextEditor;
using namespace Internal;
@@ -46,10 +49,13 @@ TipFactory::~TipFactory()
Internal::QTipLabel *TipFactory::createTip(const TipContent &content, QWidget *w)
{
- QTipLabel *tip = 0;
if (content.typeId() == TextContent::TEXT_CONTENT_ID)
- tip = new TextTip(w);
- else if (content.typeId() == ColorContent::COLOR_CONTENT_ID)
- tip = new ColorTip(w);
- return tip;
+ return new TextTip(w);
+ if (content.typeId() == ColorContent::COLOR_CONTENT_ID)
+ return new ColorTip(w);
+ if (content.typeId() == WidgetContent::WIDGET_CONTENT_ID)
+ return new WidgetTip(w);
+
+ QTC_ASSERT(false, return 0; )
+ return 0;
}
diff --git a/src/plugins/texteditor/tooltip/tips.cpp b/src/plugins/texteditor/tooltip/tips.cpp
index b61bef833e..870298c250 100644
--- a/src/plugins/texteditor/tooltip/tips.cpp
+++ b/src/plugins/texteditor/tooltip/tips.cpp
@@ -35,6 +35,8 @@
#include "tipcontents.h"
#include "reuse.h"
+#include <utils/qtcassert.h>
+
#include <QtCore/QRect>
#include <QtGui/QColor>
#include <QtGui/QPainter>
@@ -47,6 +49,7 @@
#include <QtGui/QStyleOptionFrame>
#include <QtGui/QResizeEvent>
#include <QtGui/QPaintEvent>
+#include <QtGui/QVBoxLayout>
namespace TextEditor {
namespace Internal {
@@ -77,6 +80,11 @@ QTipLabel::~QTipLabel()
delete m_tipContent;
}
+bool QTipLabel::isInteractive() const
+{
+ return m_tipContent && m_tipContent->isInteractive();
+}
+
void QTipLabel::setContent(const TipContent &content)
{
if (m_tipContent)
@@ -104,7 +112,7 @@ void ColorTip::configure(const QPoint &pos, QWidget *w)
update();
}
-bool ColorTip::handleContentReplacement(const TipContent &content) const
+bool ColorTip::canHandleContentReplacement(const TipContent &content) const
{
if (content.typeId() == ColorContent::COLOR_CONTENT_ID)
return true;
@@ -175,7 +183,7 @@ void TextTip::configure(const QPoint &pos, QWidget *w)
resize(tipWidth, heightForWidth(tipWidth) + extraHeight);
}
-bool TextTip::handleContentReplacement(const TipContent &content) const
+bool TextTip::canHandleContentReplacement(const TipContent &content) const
{
if (content.typeId() == TextContent::TEXT_CONTENT_ID)
return true;
@@ -204,6 +212,61 @@ void TextTip::resizeEvent(QResizeEvent *event)
QLabel::resizeEvent(event);
}
+WidgetTip::WidgetTip(QWidget *parent) :
+ QTipLabel(parent), m_layout(new QVBoxLayout)
+{
+ m_layout->setContentsMargins(0, 0, 0, 0);
+ setLayout(m_layout);
+}
+
+QWidget *WidgetTip::takeWidget(Qt::WindowFlags wf)
+{
+ // Remove widget from layout
+ if (!m_layout->count())
+ return 0;
+ QLayoutItem *item = m_layout->takeAt(0);
+ QWidget *widget = item->widget();
+ delete item;
+ if (!widget)
+ return 0;
+ widget->setParent(0, wf);
+ return widget;
+}
+
+void WidgetTip::configure(const QPoint &pos, QWidget *)
+{
+ const WidgetContent &anyContent = static_cast<const WidgetContent &>(content());
+ QWidget *widget = anyContent.widget();
+
+ QTC_ASSERT(widget && m_layout->count() == 0, return; )
+
+ move(pos);
+ m_layout->addWidget(widget);
+ m_layout->setSizeConstraint(QLayout::SetFixedSize);
+ adjustSize();
+}
+
+void WidgetTip::pinToolTipWidget()
+{
+ QTC_ASSERT(m_layout->count(), return; )
+
+ // Pin the content widget: Rip the widget out of the layout
+ // and re-show as a tooltip, with delete on close.
+ const QPoint screenPos = mapToGlobal(QPoint(0, 0));
+ QWidget *widget = takeWidget(Qt::ToolTip);
+ QTC_ASSERT(widget, return; )
+
+ widget->move(screenPos);
+ widget->show();
+ widget->setAttribute(Qt::WA_DeleteOnClose);
+}
+
+bool WidgetTip::canHandleContentReplacement(const TipContent & ) const
+{
+ // Always create a new widget.
+ return false;
+}
+
// need to include it here to force it to be inside the namespaces
#include "moc_tips.cpp"
diff --git a/src/plugins/texteditor/tooltip/tips.h b/src/plugins/texteditor/tooltip/tips.h
index 058209a582..5222a113d1 100644
--- a/src/plugins/texteditor/tooltip/tips.h
+++ b/src/plugins/texteditor/tooltip/tips.h
@@ -38,6 +38,8 @@
#include <QtGui/QLabel>
#include <QtGui/QPixmap>
+QT_FORWARD_DECLARE_CLASS(QVBoxLayout)
+
namespace TextEditor {
class TipContent;
}
@@ -61,7 +63,9 @@ public:
const TextEditor::TipContent &content() const;
virtual void configure(const QPoint &pos, QWidget *w) = 0;
- virtual bool handleContentReplacement(const TextEditor::TipContent &content) const = 0;
+ virtual bool canHandleContentReplacement(const TextEditor::TipContent &content) const = 0;
+
+ bool isInteractive() const;
private:
TextEditor::TipContent *m_tipContent;
@@ -75,7 +79,7 @@ public:
virtual ~ColorTip();
virtual void configure(const QPoint &pos, QWidget *w);
- virtual bool handleContentReplacement(const TipContent &content) const;
+ virtual bool canHandleContentReplacement(const TipContent &content) const;
private:
virtual void paintEvent(QPaintEvent *event);
@@ -91,13 +95,31 @@ public:
virtual ~TextTip();
virtual void configure(const QPoint &pos, QWidget *w);
- virtual bool handleContentReplacement(const TipContent &content) const;
+ virtual bool canHandleContentReplacement(const TipContent &content) const;
private:
virtual void paintEvent(QPaintEvent *event);
virtual void resizeEvent(QResizeEvent *event);
};
+class WidgetTip : public QTipLabel
+{
+ Q_OBJECT
+public:
+ explicit WidgetTip(QWidget *parent = 0);
+
+ virtual void configure(const QPoint &pos, QWidget *w);
+ virtual bool canHandleContentReplacement(const TipContent &content) const;
+
+public slots:
+ void pinToolTipWidget();
+
+private:
+ QWidget *takeWidget(Qt::WindowFlags wf = 0);
+
+ QVBoxLayout *m_layout;
+};
+
#ifndef Q_MOC_RUN
} // namespace Internal
} // namespace TextEditor
diff --git a/src/plugins/texteditor/tooltip/tooltip.cpp b/src/plugins/texteditor/tooltip/tooltip.cpp
index c1dceac23a..20cb215dc4 100644
--- a/src/plugins/texteditor/tooltip/tooltip.cpp
+++ b/src/plugins/texteditor/tooltip/tooltip.cpp
@@ -43,6 +43,9 @@
#include <QtGui/QApplication>
#include <QtGui/QKeyEvent>
#include <QtGui/QMouseEvent>
+#include <QtGui/QMenu>
+
+#include <QtCore/QDebug>
using namespace TextEditor;
using namespace Internal;
@@ -94,7 +97,7 @@ bool ToolTip::acceptShow(const TipContent &content,
return false;
if (isVisible()) {
- if (m_tip->handleContentReplacement(content)) {
+ if (m_tip->canHandleContentReplacement(content)) {
// Reuse current tip.
QPoint localPos = pos;
if (w)
@@ -231,6 +234,9 @@ void ToolTip::placeTip(const QPoint &pos, QWidget *w)
bool ToolTip::eventFilter(QObject *o, QEvent *event)
{
+ if (!o->isWidgetType())
+ return false;
+
switch (event->type()) {
#ifdef Q_WS_MAC
case QEvent::KeyPress:
@@ -245,19 +251,38 @@ bool ToolTip::eventFilter(QObject *o, QEvent *event)
}
#endif
case QEvent::Leave:
- hideTipWithDelay();
+ if (o == m_tip) {
+ hideTipWithDelay();
+ }
+ break;
+ case QEvent::Enter:
+ // User moved cursor into tip and wants to interact.
+ if (m_tip && m_tip->isInteractive() && o == m_tip) {
+ if (m_hideDelayTimer.isActive())
+ m_hideDelayTimer.stop();
+ }
break;
case QEvent::WindowActivate:
case QEvent::WindowDeactivate:
+ case QEvent::FocusOut:
+ case QEvent::FocusIn:
+ if (m_tip && !m_tip->isInteractive()) // Windows: A sequence of those occurs when interacting
+ hideTipImmediately();
+ break;
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
- case QEvent::FocusIn:
- case QEvent::FocusOut:
case QEvent::Wheel:
- hideTipImmediately();
+ if (m_tip) {
+ if (m_tip->isInteractive()) { // Do not close on interaction with the tooltip
+ if (o != m_tip && !m_tip->isAncestorOf(static_cast<QWidget *>(o))) {
+ hideTipImmediately();
+ }
+ } else {
+ hideTipImmediately();
+ }
+ }
break;
-
case QEvent::MouseMove:
if (o == m_widget &&
!m_rect.isNull() &&