Guest User

Dolphin+ 11.95 / tooltipmanager.cpp

a guest
Nov 28th, 2013
128
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*******************************************************************************
  2. * Copyright (C) 2008 by Konstantin Heil <konst.heil@stud.uni-heidelberg.de> *
  3. * *
  4. * This program is free software; you can redistribute it and/or modify *
  5. * it under the terms of the GNU General Public License as published by *
  6. * the Free Software Foundation; either version 2 of the License, or *
  7. * (at your option) any later version. *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
  18. *******************************************************************************/
  19.  
  20. #include "tooltipmanager.h"
  21.  
  22. #include "filemetadatatooltip.h"
  23. #include <KIcon>
  24. #include <KIO/JobUiDelegate>
  25. #include <KIO/PreviewJob>
  26.  
  27. #include <QApplication>
  28. #include <QDesktopWidget>
  29. #include <QLayout>
  30. #include <QScrollArea>
  31. #include <QScrollBar>
  32. #include <QStyle>
  33. #include <QTimer>
  34.  
  35. #include <QProcess>
  36.  
  37. ToolTipManager::ToolTipManager(QWidget* parent) :
  38. QObject(parent),
  39. m_showToolTipTimer(0),
  40. m_contentRetrievalTimer(0),
  41. m_fileMetaDataToolTip(0),
  42. m_toolTipRequested(false),
  43. m_metaDataRequested(false),
  44. m_appliedWaitCursor(false),
  45. m_margin(4),
  46. m_item(),
  47. m_itemRect()
  48. {
  49. if (parent) {
  50. m_margin = qMax(m_margin, parent->style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth));
  51. }
  52.  
  53. m_showToolTipTimer = new QTimer(this);
  54. m_showToolTipTimer->setSingleShot(true);
  55. m_showToolTipTimer->setInterval(500);
  56. connect(m_showToolTipTimer, SIGNAL(timeout()), this, SLOT(showToolTip()));
  57.  
  58. m_contentRetrievalTimer = new QTimer(this);
  59. m_contentRetrievalTimer->setSingleShot(true);
  60. m_contentRetrievalTimer->setInterval(200);
  61. connect(m_contentRetrievalTimer, SIGNAL(timeout()), this, SLOT(startContentRetrieval()));
  62.  
  63. Q_ASSERT(m_contentRetrievalTimer->interval() < m_showToolTipTimer->interval());
  64. }
  65.  
  66. ToolTipManager::~ToolTipManager()
  67. {
  68. delete m_fileMetaDataToolTip;
  69. m_fileMetaDataToolTip = 0;
  70. }
  71.  
  72. void ToolTipManager::showToolTip(const KFileItem& item, const QRectF& itemRect)
  73. {
  74. hideToolTip();
  75.  
  76. m_itemRect = itemRect.toRect();
  77.  
  78. m_itemRect.adjust(-m_margin, -m_margin, m_margin, m_margin);
  79. m_item = item;
  80.  
  81. // Only start the retrieving of the content, when the mouse has been over this
  82. // item for 200 milliseconds. This prevents a lot of useless preview jobs and
  83. // meta data retrieval, when passing rapidly over a lot of items.
  84. Q_ASSERT(!m_fileMetaDataToolTip);
  85. m_fileMetaDataToolTip = new FileMetaDataToolTip();
  86. connect(m_fileMetaDataToolTip, SIGNAL(metaDataRequestFinished(KFileItemList)),
  87. this, SLOT(slotMetaDataRequestFinished()));
  88.  
  89. m_contentRetrievalTimer->start();
  90. m_showToolTipTimer->start();
  91. m_toolTipRequested = true;
  92. Q_ASSERT(!m_metaDataRequested);
  93. }
  94.  
  95. void ToolTipManager::hideToolTip()
  96. {
  97. if (m_appliedWaitCursor) {
  98. QApplication::restoreOverrideCursor();
  99. m_appliedWaitCursor = false;
  100. }
  101.  
  102. m_toolTipRequested = false;
  103. m_metaDataRequested = false;
  104. m_showToolTipTimer->stop();
  105. m_contentRetrievalTimer->stop();
  106.  
  107. if (m_fileMetaDataToolTip) {
  108. m_fileMetaDataToolTip->hide();
  109. // Do not delete the tool tip immediately to prevent crashes when
  110. // QCoreApplication tries to deliver an 'Enter' event to it, see bug 310579.
  111. m_fileMetaDataToolTip->deleteLater();
  112. m_fileMetaDataToolTip = 0;
  113.  
  114. // Kill mouse over action
  115. QObject *parent;
  116. QString program = "/usr/bin/pkill";
  117. QStringList arguments;
  118. arguments << "-f" << "/usr/local/bin/MouseOverAction.sh";
  119. QProcess *killAction = new QProcess(parent);
  120. killAction->start(program, arguments);
  121. }
  122. }
  123.  
  124. void ToolTipManager::startContentRetrieval()
  125. {
  126. if (!m_toolTipRequested) {
  127. return;
  128. }
  129.  
  130. m_fileMetaDataToolTip->setName(m_item.text());
  131.  
  132. // Request the retrieval of meta-data. The slot
  133. // slotMetaDataRequestFinished() is invoked after the
  134. // meta-data have been received.
  135. m_metaDataRequested = true;
  136. m_fileMetaDataToolTip->setItems(KFileItemList() << m_item);
  137. m_fileMetaDataToolTip->adjustSize();
  138.  
  139. // Request a preview of the item
  140. m_fileMetaDataToolTip->setPreview(QPixmap());
  141.  
  142. KIO::PreviewJob* job = new KIO::PreviewJob(KFileItemList() << m_item, QSize(256, 256));
  143. job->setIgnoreMaximumSize(m_item.isLocalFile());
  144. if (job->ui()) {
  145. job->ui()->setWindow(qApp->activeWindow());
  146. }
  147.  
  148. connect(job, SIGNAL(gotPreview(KFileItem,QPixmap)),
  149. this, SLOT(setPreviewPix(KFileItem,QPixmap)));
  150. connect(job, SIGNAL(failed(KFileItem)),
  151. this, SLOT(previewFailed()));
  152. }
  153.  
  154.  
  155. void ToolTipManager::setPreviewPix(const KFileItem& item,
  156. const QPixmap& pixmap)
  157. {
  158. if (!m_toolTipRequested || (m_item.url() != item.url())) {
  159. // No tooltip is requested anymore or an old preview has been received
  160. return;
  161. }
  162.  
  163. if (pixmap.isNull()) {
  164. previewFailed();
  165. } else {
  166. m_fileMetaDataToolTip->setPreview(pixmap);
  167. if (!m_showToolTipTimer->isActive()) {
  168. showToolTip();
  169. }
  170. }
  171. }
  172.  
  173. void ToolTipManager::previewFailed()
  174. {
  175. if (!m_toolTipRequested) {
  176. return;
  177. }
  178.  
  179. const QPixmap pixmap = KIcon(m_item.iconName()).pixmap(128, 128);
  180. m_fileMetaDataToolTip->setPreview(pixmap);
  181. if (!m_showToolTipTimer->isActive()) {
  182. showToolTip();
  183. }
  184. }
  185.  
  186. void ToolTipManager::slotMetaDataRequestFinished()
  187. {
  188. if (!m_toolTipRequested) {
  189. return;
  190. }
  191.  
  192. m_metaDataRequested = false;
  193.  
  194. if (!m_showToolTipTimer->isActive()) {
  195. showToolTip();
  196. }
  197. }
  198.  
  199. void ToolTipManager::showToolTip()
  200. {
  201. Q_ASSERT(m_toolTipRequested);
  202. if (m_appliedWaitCursor) {
  203. QApplication::restoreOverrideCursor();
  204. m_appliedWaitCursor = false;
  205. }
  206.  
  207. if (m_fileMetaDataToolTip->preview().isNull() || m_metaDataRequested) {
  208. Q_ASSERT(!m_appliedWaitCursor);
  209. QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
  210. m_appliedWaitCursor = true;
  211. return;
  212. }
  213.  
  214. const QRect screen = QApplication::desktop()->screenGeometry(QCursor::pos());
  215.  
  216. // Restrict tooltip size to current screen size when needed.
  217. // Because layout controlling widget doesn't respect widget's maximumSize property
  218. // (correct me if I'm wrong), we need to let layout do its work, then manually change
  219. // geometry if resulting widget doesn't fit the screen.
  220.  
  221. // Step #1 - make sizeHint return calculated tooltip size
  222. m_fileMetaDataToolTip->layout()->setSizeConstraint(QLayout::SetFixedSize);
  223. m_fileMetaDataToolTip->adjustSize();
  224. QSize size = m_fileMetaDataToolTip->sizeHint();
  225.  
  226. // Step #2 - correct tooltip size when needed
  227. if (size.width() > screen.width()) {
  228. size.setWidth(screen.width());
  229. }
  230. if (size.height() > screen.height()) {
  231. size.setHeight(screen.height());
  232. }
  233.  
  234. // m_itemRect defines the area of the item, where the tooltip should be
  235. // shown. Per default the tooltip is shown centered at the bottom.
  236. // It must be assured that:
  237. // - the content is fully visible
  238. // - the content is not drawn inside m_itemRect
  239. const bool hasRoomToLeft = (m_itemRect.left() - size.width() - m_margin >= screen.left());
  240. const bool hasRoomToRight = (m_itemRect.right() + size.width() + m_margin <= screen.right());
  241. const bool hasRoomAbove = (m_itemRect.top() - size.height() - m_margin >= screen.top());
  242. const bool hasRoomBelow = (m_itemRect.bottom() + size.height() + m_margin <= screen.bottom());
  243. if (!hasRoomAbove && !hasRoomBelow && !hasRoomToLeft && !hasRoomToRight) {
  244. return;
  245. }
  246.  
  247. int x, y;
  248. if (hasRoomBelow || hasRoomAbove) {
  249. x = qMax(screen.left(), m_itemRect.center().x() - size.width() / 2);
  250. if (x + size.width() >= screen.right()) {
  251. x = screen.right() - size.width() + 1;
  252. }
  253. if (hasRoomBelow) {
  254. y = m_itemRect.bottom() + m_margin;
  255. } else {
  256. y = m_itemRect.top() - size.height() - m_margin;
  257. }
  258. } else {
  259. Q_ASSERT(hasRoomToLeft || hasRoomToRight);
  260. if (hasRoomToRight) {
  261. x = m_itemRect.right() + m_margin;
  262. } else {
  263. x = m_itemRect.left() - size.width() - m_margin;
  264. }
  265. // Put the tooltip at the bottom of the screen. The x-coordinate has already
  266. // been adjusted, so that no overlapping with m_itemRect occurs.
  267. y = screen.bottom() - size.height() + 1;
  268. }
  269.  
  270. // Step #3 - Alter tooltip geometry
  271. m_fileMetaDataToolTip->setFixedSize(size);
  272. m_fileMetaDataToolTip->layout()->setSizeConstraint(QLayout::SetNoConstraint);
  273. m_fileMetaDataToolTip->move(QPoint(x, y));
  274. m_fileMetaDataToolTip->show();
  275.  
  276. m_toolTipRequested = false;
  277.  
  278. // Start mouse over action
  279. // http://api.kde.org/4.x-api/kdelibs-apidocs/kio/html/classKFileItem.html
  280. // mimetype() and localPath()
  281. QObject *parent;
  282. QString program = "/usr/local/bin/MouseOverAction.sh";
  283. QStringList arguments;
  284. arguments << m_item.mimetype() << m_item.localPath();
  285. QProcess *startAction = new QProcess(parent);
  286. startAction->start(program, arguments);
  287. }
  288.  
  289. #include "tooltipmanager.moc"
RAW Paste Data