PageRenderTime 67ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/app/qgsappbrowserproviders.cpp

http://github.com/qgis/Quantum-GIS
C++ | 1295 lines | 1058 code | 154 blank | 83 comment | 128 complexity | 34d89f627fdee69d2d112e68c6f2a8d9 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-3.0, GPL-2.0, CC-BY-SA-3.0, MIT, 0BSD, BSD-3-Clause
  1. /***************************************************************************
  2. qgsappbrowserproviders.cpp
  3. ---------------------------
  4. begin : September 2017
  5. copyright : (C) 2017 by Nyall Dawson
  6. email : nyall dot dawson at gmail dot com
  7. ***************************************************************************
  8. * *
  9. * This program is free software; you can redistribute it and/or modify *
  10. * it under the terms of the GNU General Public License as published by *
  11. * the Free Software Foundation; either version 2 of the License, or *
  12. * (at your option) any later version. *
  13. * *
  14. ***************************************************************************/
  15. #include "qgisapp.h"
  16. #include "qgsapplication.h"
  17. #include "qgsappbrowserproviders.h"
  18. #include "qgsbookmarkeditordialog.h"
  19. #include "qgsmapcanvas.h"
  20. #include "qgsmessagebar.h"
  21. #include "qgsproject.h"
  22. #include "qgsstyleexportimportdialog.h"
  23. #include "qgsstyle.h"
  24. #include "qgslayertreenode.h"
  25. #include "qgslayertree.h"
  26. #include "qgsstylemanagerdialog.h"
  27. #include "qgsguiutils.h"
  28. #include "qgsfileutils.h"
  29. #include <QDesktopServices>
  30. #include <QMessageBox>
  31. #include <QFileDialog>
  32. QIcon QgsBookmarksItem::iconBookmarks()
  33. {
  34. return QgsApplication::getThemeIcon( QStringLiteral( "/mActionShowBookmarks.svg" ) );
  35. }
  36. QVariant QgsBookmarksItem::sortKey() const
  37. {
  38. return QStringLiteral( " 1" );
  39. }
  40. QIcon QgsBookmarkManagerItem::iconBookmarkManager()
  41. {
  42. return QgsApplication::getThemeIcon( QStringLiteral( "/mIconFolder.svg" ) );
  43. }
  44. QIcon QgsBookmarkGroupItem::iconBookmarkGroup()
  45. {
  46. return QgsApplication::getThemeIcon( QStringLiteral( "/mIconFolder.svg" ) );
  47. }
  48. QIcon QgsBookmarkItem::iconBookmark()
  49. {
  50. return QgsApplication::getThemeIcon( QStringLiteral( "/mItemBookmark.svg" ) );
  51. }
  52. bool QgsBookmarkItem::hasDragEnabled() const
  53. {
  54. return true;
  55. }
  56. QgsMimeDataUtils::Uri QgsBookmarkItem::mimeUri() const
  57. {
  58. QgsMimeDataUtils::Uri u;
  59. u.layerType = QStringLiteral( "custom" );
  60. u.providerKey = QStringLiteral( "bookmark" );
  61. u.name = name();
  62. QDomDocument doc;
  63. doc.appendChild( mBookmark.writeXml( doc ) );
  64. u.uri = doc.toString();
  65. return u;
  66. }
  67. //
  68. // QgsQlrDataItem
  69. //
  70. QgsQlrDataItem::QgsQlrDataItem( QgsDataItem *parent, const QString &name, const QString &path )
  71. : QgsLayerItem( parent, name, path, path, QgsLayerItem::NoType, QStringLiteral( "qlr" ) )
  72. {
  73. setState( QgsDataItem::Populated ); // no children
  74. setIconName( QStringLiteral( ":/images/icons/qgis-icon-16x16.png" ) );
  75. setToolTip( QDir::toNativeSeparators( path ) );
  76. }
  77. bool QgsQlrDataItem::hasDragEnabled() const
  78. {
  79. return true;
  80. }
  81. QgsMimeDataUtils::Uri QgsQlrDataItem::mimeUri() const
  82. {
  83. QgsMimeDataUtils::Uri u;
  84. u.layerType = QStringLiteral( "custom" );
  85. u.providerKey = QStringLiteral( "qlr" );
  86. u.name = name();
  87. u.uri = path();
  88. return u;
  89. }
  90. //
  91. // QgsQlrDataItemProvider
  92. //
  93. QString QgsQlrDataItemProvider::name()
  94. {
  95. return QStringLiteral( "QLR" );
  96. }
  97. int QgsQlrDataItemProvider::capabilities() const
  98. {
  99. return QgsDataProvider::File;
  100. }
  101. QgsDataItem *QgsQlrDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
  102. {
  103. QFileInfo fileInfo( path );
  104. if ( fileInfo.suffix().compare( QLatin1String( "qlr" ), Qt::CaseInsensitive ) == 0 )
  105. {
  106. return new QgsQlrDataItem( parentItem, fileInfo.fileName(), path );
  107. }
  108. return nullptr;
  109. }
  110. QString QgsQlrDropHandler::customUriProviderKey() const
  111. {
  112. return QStringLiteral( "qlr" );
  113. }
  114. void QgsQlrDropHandler::handleCustomUriDrop( const QgsMimeDataUtils::Uri &uri ) const
  115. {
  116. QString path = uri.uri;
  117. QgisApp::instance()->openLayerDefinition( path );
  118. }
  119. //
  120. // QgsQptDataItemProvider
  121. //
  122. QString QgsQptDataItemProvider::name()
  123. {
  124. return QStringLiteral( "QPT" );
  125. }
  126. int QgsQptDataItemProvider::capabilities() const
  127. {
  128. return QgsDataProvider::File;
  129. }
  130. QgsDataItem *QgsQptDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
  131. {
  132. QFileInfo fileInfo( path );
  133. if ( fileInfo.suffix().compare( QLatin1String( "qpt" ), Qt::CaseInsensitive ) == 0 )
  134. {
  135. return new QgsQptDataItem( parentItem, fileInfo.baseName(), path );
  136. }
  137. return nullptr;
  138. }
  139. //
  140. // QgsQptDropHandler
  141. //
  142. QString QgsQptDropHandler::customUriProviderKey() const
  143. {
  144. return QStringLiteral( "qpt" );
  145. }
  146. void QgsQptDropHandler::handleCustomUriDrop( const QgsMimeDataUtils::Uri &uri ) const
  147. {
  148. QString path = uri.uri;
  149. QgisApp::instance()->openTemplate( path );
  150. }
  151. bool QgsQptDropHandler::handleFileDrop( const QString &file )
  152. {
  153. QFileInfo fi( file );
  154. if ( fi.completeSuffix().compare( QLatin1String( "qpt" ), Qt::CaseInsensitive ) == 0 )
  155. {
  156. QgisApp::instance()->openTemplate( file );
  157. return true;
  158. }
  159. return false;
  160. }
  161. //
  162. // QgsQptDataItem
  163. //
  164. QgsQptDataItem::QgsQptDataItem( QgsDataItem *parent, const QString &name, const QString &path )
  165. : QgsDataItem( QgsDataItem::Custom, parent, name, path )
  166. {
  167. setState( QgsDataItem::Populated ); // no children
  168. setIconName( QStringLiteral( "/mIconQptFile.svg" ) );
  169. setToolTip( QDir::toNativeSeparators( path ) );
  170. }
  171. bool QgsQptDataItem::hasDragEnabled() const
  172. {
  173. return true;
  174. }
  175. QgsMimeDataUtils::Uri QgsQptDataItem::mimeUri() const
  176. {
  177. QgsMimeDataUtils::Uri u;
  178. u.layerType = QStringLiteral( "custom" );
  179. u.providerKey = QStringLiteral( "qpt" );
  180. u.name = name();
  181. u.uri = path();
  182. return u;
  183. }
  184. bool QgsQptDataItem::handleDoubleClick()
  185. {
  186. QgisApp::instance()->openTemplate( path() );
  187. return true;
  188. }
  189. QList<QAction *> QgsQptDataItem::actions( QWidget *parent )
  190. {
  191. QAction *newLayout = new QAction( tr( "New Layout from Template" ), parent );
  192. connect( newLayout, &QAction::triggered, this, [ = ]
  193. {
  194. QgisApp::instance()->openTemplate( path() );
  195. } );
  196. return QList<QAction *>() << newLayout;
  197. }
  198. //
  199. // QgsPyDataItem
  200. //
  201. QgsPyDataItem::QgsPyDataItem( QgsDataItem *parent, const QString &name, const QString &path )
  202. : QgsDataItem( QgsDataItem::Custom, parent, name, path )
  203. {
  204. setState( QgsDataItem::Populated ); // no children
  205. setIconName( QStringLiteral( "/mIconPythonFile.svg" ) );
  206. setToolTip( QDir::toNativeSeparators( path ) );
  207. }
  208. bool QgsPyDataItem::hasDragEnabled() const
  209. {
  210. return true;
  211. }
  212. QgsMimeDataUtils::Uri QgsPyDataItem::mimeUri() const
  213. {
  214. QgsMimeDataUtils::Uri u;
  215. u.layerType = QStringLiteral( "custom" );
  216. u.providerKey = QStringLiteral( "py" );
  217. u.name = name();
  218. u.uri = path();
  219. return u;
  220. }
  221. bool QgsPyDataItem::handleDoubleClick()
  222. {
  223. QgisApp::instance()->runScript( path() );
  224. return true;
  225. }
  226. QList<QAction *> QgsPyDataItem::actions( QWidget *parent )
  227. {
  228. QAction *runScript = new QAction( tr( "&Run Script" ), parent );
  229. connect( runScript, &QAction::triggered, this, [ = ]
  230. {
  231. QgisApp::instance()->runScript( path() );
  232. } );
  233. QAction *editScript = new QAction( tr( "Open in External &Editor" ), this );
  234. connect( editScript, &QAction::triggered, this, [ = ]
  235. {
  236. QDesktopServices::openUrl( QUrl::fromLocalFile( path() ) );
  237. } );
  238. return QList<QAction *>() << runScript << editScript;
  239. }
  240. //
  241. // QgsPyDataItemProvider
  242. //
  243. QString QgsPyDataItemProvider::name()
  244. {
  245. return QStringLiteral( "py" );
  246. }
  247. int QgsPyDataItemProvider::capabilities() const
  248. {
  249. return QgsDataProvider::File;
  250. }
  251. QgsDataItem *QgsPyDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
  252. {
  253. QFileInfo fileInfo( path );
  254. if ( fileInfo.suffix().compare( QLatin1String( "py" ), Qt::CaseInsensitive ) == 0 )
  255. {
  256. return new QgsPyDataItem( parentItem, fileInfo.baseName(), path );
  257. }
  258. return nullptr;
  259. }
  260. //
  261. // QgsPyDropHandler
  262. //
  263. QString QgsPyDropHandler::customUriProviderKey() const
  264. {
  265. return QStringLiteral( "py" );
  266. }
  267. void QgsPyDropHandler::handleCustomUriDrop( const QgsMimeDataUtils::Uri &uri ) const
  268. {
  269. QString path = uri.uri;
  270. QgisApp::instance()->runScript( path );
  271. }
  272. bool QgsPyDropHandler::handleFileDrop( const QString &file )
  273. {
  274. QFileInfo fi( file );
  275. if ( fi.completeSuffix().compare( QLatin1String( "py" ), Qt::CaseInsensitive ) == 0 )
  276. {
  277. QgisApp::instance()->runScript( file );
  278. return true;
  279. }
  280. return false;
  281. }
  282. //
  283. // QgsStyleXmlDataItem
  284. //
  285. QgsStyleXmlDataItem::QgsStyleXmlDataItem( QgsDataItem *parent, const QString &name, const QString &path )
  286. : QgsDataItem( QgsDataItem::Custom, parent, name, path )
  287. {
  288. setState( QgsDataItem::Populated ); // no children
  289. setIconName( QStringLiteral( "/mActionStyleManager.svg" ) );
  290. setToolTip( QStringLiteral( "<b>%1</b><br>%2" ).arg( tr( "QGIS style library" ), QDir::toNativeSeparators( path ) ) );
  291. }
  292. bool QgsStyleXmlDataItem::hasDragEnabled() const
  293. {
  294. return true;
  295. }
  296. QgsMimeDataUtils::Uri QgsStyleXmlDataItem::mimeUri() const
  297. {
  298. QgsMimeDataUtils::Uri u;
  299. u.layerType = QStringLiteral( "custom" );
  300. u.providerKey = QStringLiteral( "style_xml" );
  301. u.name = name();
  302. u.uri = path();
  303. return u;
  304. }
  305. bool QgsStyleXmlDataItem::handleDoubleClick()
  306. {
  307. browseStyle( mPath );
  308. return true;
  309. }
  310. QList<QAction *> QgsStyleXmlDataItem::actions( QWidget *parent )
  311. {
  312. QAction *browseAction = new QAction( tr( "&Open Style…" ), parent );
  313. const QString path = mPath;
  314. connect( browseAction, &QAction::triggered, this, [path]
  315. {
  316. browseStyle( path );
  317. } );
  318. QAction *importAction = new QAction( tr( "&Import Style…" ), parent );
  319. connect( importAction, &QAction::triggered, this, [path]
  320. {
  321. QgsStyleExportImportDialog dlg( QgsStyle::defaultStyle(), QgisApp::instance(), QgsStyleExportImportDialog::Import );
  322. dlg.setImportFilePath( path );
  323. dlg.exec();
  324. } );
  325. return QList<QAction *>() << browseAction << importAction;
  326. }
  327. void QgsStyleXmlDataItem::browseStyle( const QString &xmlPath )
  328. {
  329. QgsStyle s;
  330. s.createMemoryDatabase();
  331. auto cursorOverride = qgis::make_unique< QgsTemporaryCursorOverride >( Qt::WaitCursor );
  332. if ( s.importXml( xmlPath ) )
  333. {
  334. cursorOverride.reset();
  335. QFileInfo fi( xmlPath );
  336. QgsStyleManagerDialog dlg( &s, QgisApp::instance(), Qt::WindowFlags(), true );
  337. dlg.setSmartGroupsVisible( false );
  338. dlg.setFavoritesGroupVisible( false );
  339. dlg.setBaseStyleName( fi.baseName() );
  340. dlg.exec();
  341. }
  342. }
  343. //
  344. // QgsStyleXmlDataItemProvider
  345. //
  346. QString QgsStyleXmlDataItemProvider::name()
  347. {
  348. return QStringLiteral( "style_xml" );
  349. }
  350. int QgsStyleXmlDataItemProvider::capabilities() const
  351. {
  352. return QgsDataProvider::File;
  353. }
  354. QgsDataItem *QgsStyleXmlDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
  355. {
  356. if ( QgsStyle::isXmlStyleFile( path ) )
  357. {
  358. return new QgsStyleXmlDataItem( parentItem, QFileInfo( path ).fileName(), path );
  359. }
  360. return nullptr;
  361. }
  362. //
  363. // QgsStyleXmlDropHandler
  364. //
  365. QString QgsStyleXmlDropHandler::customUriProviderKey() const
  366. {
  367. return QStringLiteral( "style_xml" );
  368. }
  369. void QgsStyleXmlDropHandler::handleCustomUriDrop( const QgsMimeDataUtils::Uri &uri ) const
  370. {
  371. QgsStyleExportImportDialog dlg( QgsStyle::defaultStyle(), QgisApp::instance(), QgsStyleExportImportDialog::Import );
  372. dlg.setImportFilePath( uri.uri );
  373. dlg.exec();
  374. }
  375. bool QgsStyleXmlDropHandler::handleFileDrop( const QString &file )
  376. {
  377. if ( QgsStyle::isXmlStyleFile( file ) )
  378. {
  379. QgsStyleExportImportDialog dlg( QgsStyle::defaultStyle(), QgisApp::instance(), QgsStyleExportImportDialog::Import );
  380. dlg.setImportFilePath( file );
  381. dlg.exec();
  382. return true;
  383. }
  384. return false;
  385. }
  386. //
  387. // QgsProjectRootDataItem
  388. //
  389. QgsProjectRootDataItem::QgsProjectRootDataItem( QgsDataItem *parent, const QString &path )
  390. : QgsProjectItem( parent, QFileInfo( path ).completeBaseName(), path )
  391. {
  392. mCapabilities = Collapse | Fertile; // collapse by default to avoid costly population on startup
  393. setState( NotPopulated );
  394. }
  395. QVector<QgsDataItem *> QgsProjectRootDataItem::createChildren()
  396. {
  397. QVector<QgsDataItem *> childItems;
  398. QgsProject p;
  399. if ( !p.read( mPath, QgsProject::ReadFlag::FlagDontResolveLayers | QgsProject::ReadFlag::FlagDontLoadLayouts ) )
  400. {
  401. childItems.append( new QgsErrorItem( nullptr, p.error(), mPath + "/error" ) );
  402. return childItems;
  403. }
  404. // recursively create groups and layer items for project's layer tree
  405. std::function<void( QgsDataItem *parentItem, QgsLayerTreeGroup *group )> addNodes;
  406. addNodes = [this, &addNodes, &childItems]( QgsDataItem * parentItem, QgsLayerTreeGroup * group )
  407. {
  408. const QList< QgsLayerTreeNode * > children = group->children();
  409. for ( QgsLayerTreeNode *child : children )
  410. {
  411. switch ( child->nodeType() )
  412. {
  413. case QgsLayerTreeNode::NodeLayer:
  414. {
  415. if ( QgsLayerTreeLayer *layerNode = qobject_cast< QgsLayerTreeLayer * >( child ) )
  416. {
  417. QgsMapLayer *layer = layerNode->layer();
  418. #if 0 // TODO
  419. QString style;
  420. if ( layer )
  421. {
  422. QString errorMsg;
  423. QDomDocument doc( QStringLiteral( "qgis" ) );
  424. QgsReadWriteContext context;
  425. context.setPathResolver( p.pathResolver() );
  426. layer->exportNamedStyle( doc, errorMsg, context );
  427. style = doc.toString();
  428. }
  429. #endif
  430. QgsLayerItem *layerItem = new QgsLayerItem( nullptr, layerNode->name(),
  431. layer ? layer->source() : QString(),
  432. layer ? layer->source() : QString(),
  433. layer ? QgsLayerItem::typeFromMapLayer( layer ) : QgsLayerItem::NoType,
  434. layer ? layer->providerType() : QString() );
  435. layerItem->setState( Populated ); // children are not expected
  436. layerItem->setToolTip( layer ? layer->source() : QString() );
  437. if ( parentItem == this )
  438. childItems << layerItem;
  439. else
  440. parentItem->addChildItem( layerItem, true );
  441. }
  442. break;
  443. }
  444. case QgsLayerTreeNode::NodeGroup:
  445. {
  446. if ( QgsLayerTreeGroup *groupNode = qobject_cast< QgsLayerTreeGroup * >( child ) )
  447. {
  448. QgsProjectLayerTreeGroupItem *groupItem = new QgsProjectLayerTreeGroupItem( nullptr, groupNode->name() );
  449. addNodes( groupItem, groupNode );
  450. groupItem->setState( Populated );
  451. if ( parentItem == this )
  452. childItems << groupItem;
  453. else
  454. parentItem->addChildItem( groupItem, true );
  455. }
  456. }
  457. break;
  458. }
  459. }
  460. };
  461. addNodes( this, p.layerTreeRoot() );
  462. return childItems;
  463. }
  464. //
  465. // QgsProjectLayerTreeGroupItem
  466. //
  467. QgsProjectLayerTreeGroupItem::QgsProjectLayerTreeGroupItem( QgsDataItem *parent, const QString &name )
  468. : QgsDataCollectionItem( parent, name )
  469. {
  470. mIconName = QStringLiteral( "mActionFolder.svg" );
  471. mCapabilities = NoCapabilities;
  472. setToolTip( name );
  473. }
  474. //
  475. // QgsProjectDataItemProvider
  476. //
  477. QString QgsProjectDataItemProvider::name()
  478. {
  479. return QStringLiteral( "project_item" );
  480. }
  481. int QgsProjectDataItemProvider::capabilities() const
  482. {
  483. return QgsDataProvider::File;
  484. }
  485. QgsDataItem *QgsProjectDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
  486. {
  487. QFileInfo fileInfo( path );
  488. if ( fileInfo.suffix().compare( QLatin1String( "qgs" ), Qt::CaseInsensitive ) == 0 || fileInfo.suffix().compare( QLatin1String( "qgz" ), Qt::CaseInsensitive ) == 0 )
  489. {
  490. return new QgsProjectRootDataItem( parentItem, path );
  491. }
  492. return nullptr;
  493. }
  494. //
  495. // QgsBookmarksDataItemProvider
  496. //
  497. QString QgsBookmarksDataItemProvider::name()
  498. {
  499. return QStringLiteral( "bookmarks_item" );
  500. }
  501. int QgsBookmarksDataItemProvider::capabilities() const
  502. {
  503. return QgsDataProvider::Database;
  504. }
  505. QgsDataItem *QgsBookmarksDataItemProvider::createDataItem( const QString &, QgsDataItem *parentItem )
  506. {
  507. return new QgsBookmarksItem( parentItem, QObject::tr( "Spatial Bookmarks" ), QgsApplication::bookmarkManager(), QgsProject::instance()->bookmarkManager() );
  508. }
  509. QgsBookmarksItem::QgsBookmarksItem( QgsDataItem *parent, const QString &name, QgsBookmarkManager *applicationManager, QgsBookmarkManager *projectManager )
  510. : QgsDataCollectionItem( parent, name, QStringLiteral( "bookmarks:" ) )
  511. {
  512. mType = Custom;
  513. mCapabilities = Fast;
  514. mApplicationManager = applicationManager;
  515. mProjectManager = projectManager;
  516. mIconName = QStringLiteral( "/mActionShowBookmarks.svg" );
  517. populate();
  518. }
  519. QVector<QgsDataItem *> QgsBookmarksItem::createChildren()
  520. {
  521. QVector<QgsDataItem *> children;
  522. if ( mApplicationManager )
  523. children << new QgsBookmarkManagerItem( this, tr( "User Bookmarks" ), mApplicationManager );
  524. if ( mProjectManager )
  525. children << new QgsBookmarkManagerItem( this, tr( "Project Bookmarks" ), mProjectManager );
  526. return children;
  527. }
  528. QgsBookmarkManagerItem::QgsBookmarkManagerItem( QgsDataItem *parent, const QString &name, QgsBookmarkManager *manager )
  529. : QgsDataCollectionItem( parent, name, QStringLiteral( "bookmarks:%1" ).arg( name.toLower() ) )
  530. {
  531. mType = Custom;
  532. mCapabilities = Fast;
  533. mManager = manager;
  534. mIconName = QStringLiteral( "/mIconFolder.svg" );
  535. connect( mManager, &QgsBookmarkManager::bookmarkAdded, this, [ = ]( const QString & id )
  536. {
  537. QgsBookmark newDetails = mManager->bookmarkById( id );
  538. if ( newDetails.group().isEmpty() )
  539. addChildItem( new QgsBookmarkItem( this, newDetails.name(), newDetails, mManager ), true );
  540. else
  541. {
  542. if ( QgsBookmarkGroupItem *newGroup = groupItem( newDetails.group() ) )
  543. {
  544. // existing group, add this bookmark to it
  545. newGroup->addBookmark( newDetails );
  546. }
  547. else
  548. {
  549. // need to create a new group for this (will automatically add the new bookmark)
  550. addChildItem( new QgsBookmarkGroupItem( this, newDetails.group(), mManager ), true );
  551. }
  552. }
  553. } );
  554. connect( mManager, &QgsBookmarkManager::bookmarkChanged, this, [ = ]( const QString & id )
  555. {
  556. QgsBookmark newDetails = mManager->bookmarkById( id );
  557. // have to do a deep dive to find the old item...!
  558. const QVector<QgsDataItem *> c = children();
  559. for ( QgsDataItem *i : c )
  560. {
  561. if ( QgsBookmarkItem *bookmarkItem = qobject_cast< QgsBookmarkItem * >( i ) )
  562. {
  563. if ( bookmarkItem->bookmark().id() == id )
  564. {
  565. // found the target! now, what's changed?
  566. if ( bookmarkItem->bookmark().group() == newDetails.group() )
  567. {
  568. // good, not the group. Just update the existing bookmark then.
  569. bookmarkItem->setBookmark( newDetails );
  570. return;
  571. }
  572. else
  573. {
  574. // group has changed, ouch!
  575. // first remove from existing group
  576. deleteChildItem( bookmarkItem );
  577. // and add a child to the new group
  578. if ( QgsBookmarkGroupItem *newGroup = groupItem( newDetails.group() ) )
  579. {
  580. newGroup->addBookmark( newDetails );
  581. }
  582. else
  583. {
  584. // need to create a new group for this (will automatically add the new bookmark)
  585. addChildItem( new QgsBookmarkGroupItem( this, newDetails.group(), mManager ), true );
  586. }
  587. }
  588. break;
  589. }
  590. }
  591. else if ( QgsBookmarkGroupItem *group = qobject_cast< QgsBookmarkGroupItem * >( i ) )
  592. {
  593. if ( QgsBookmarkItem *bookmarkItem = group->childItemById( id ) )
  594. {
  595. // ok, found old group, now compare
  596. if ( bookmarkItem->bookmark().group() == newDetails.group() )
  597. {
  598. // good, not the group. Just update the existing bookmark then.
  599. bookmarkItem->setBookmark( newDetails );
  600. }
  601. else
  602. {
  603. // group has changed!
  604. // first remove from existing group
  605. group->deleteChildItem( bookmarkItem );
  606. if ( group->children().empty() )
  607. deleteChildItem( group );
  608. // and add a child to the new group
  609. if ( !newDetails.group().isEmpty() )
  610. {
  611. if ( QgsBookmarkGroupItem *newGroup = groupItem( newDetails.group() ) )
  612. {
  613. newGroup->addBookmark( newDetails );
  614. }
  615. else
  616. {
  617. // need to create a new group for this (will automatically add the new bookmark)
  618. addChildItem( new QgsBookmarkGroupItem( this, newDetails.group(), mManager ), true );
  619. }
  620. }
  621. else
  622. {
  623. addChildItem( new QgsBookmarkItem( this, newDetails.name(), newDetails, mManager ), true );
  624. }
  625. }
  626. break;
  627. }
  628. }
  629. }
  630. } );
  631. connect( mManager, &QgsBookmarkManager::bookmarkAboutToBeRemoved, this, [ = ]( const QString & id )
  632. {
  633. QgsBookmark b = mManager->bookmarkById( id );
  634. if ( !b.group().isEmpty() )
  635. {
  636. if ( QgsBookmarkGroupItem *group = groupItem( b.group() ) )
  637. {
  638. group->removeBookmarkChildById( id );
  639. if ( group->children().empty() )
  640. deleteChildItem( group );
  641. }
  642. }
  643. else if ( QgsBookmarkItem *bookmarkItem = childItemById( id ) )
  644. {
  645. deleteChildItem( bookmarkItem );
  646. }
  647. } );
  648. populate();
  649. }
  650. QVector<QgsDataItem *> QgsBookmarkManagerItem::createChildren()
  651. {
  652. QVector<QgsDataItem *> children;
  653. const QStringList groupNames = mManager->groups();
  654. for ( const QString &group : groupNames )
  655. {
  656. if ( group.isEmpty() )
  657. {
  658. const QList<QgsBookmark> matching = mManager->bookmarksByGroup( QString() );
  659. for ( const QgsBookmark &bookmark : matching )
  660. {
  661. children << new QgsBookmarkItem( this, bookmark.name(), bookmark, mManager );
  662. }
  663. }
  664. else
  665. {
  666. QgsBookmarkGroupItem *item = new QgsBookmarkGroupItem( this, group, mManager );
  667. children << item;
  668. }
  669. }
  670. return children;
  671. }
  672. QgsBookmarkGroupItem *QgsBookmarkManagerItem::groupItem( const QString &group )
  673. {
  674. const QVector<QgsDataItem *> c = children();
  675. for ( QgsDataItem *i : c )
  676. {
  677. if ( QgsBookmarkGroupItem *groupItem = qobject_cast< QgsBookmarkGroupItem * >( i ) )
  678. {
  679. if ( groupItem->group() == group )
  680. {
  681. return groupItem;
  682. }
  683. }
  684. }
  685. return nullptr;
  686. }
  687. QgsBookmarkItem *QgsBookmarkManagerItem::childItemById( const QString &id )
  688. {
  689. const QVector<QgsDataItem *> c = children();
  690. for ( QgsDataItem *i : c )
  691. {
  692. if ( QgsBookmarkItem *bookmarkItem = qobject_cast< QgsBookmarkItem * >( i ) )
  693. {
  694. if ( bookmarkItem->bookmark().id() == id )
  695. {
  696. return bookmarkItem;
  697. }
  698. }
  699. }
  700. return nullptr;
  701. }
  702. QgsBookmarkGroupItem::QgsBookmarkGroupItem( QgsDataItem *parent, const QString &name, QgsBookmarkManager *manager )
  703. : QgsDataCollectionItem( parent, name, QStringLiteral( "bookmarks:%1" ).arg( name.toLower() ) )
  704. , mGroup( name )
  705. {
  706. mType = Custom;
  707. mCapabilities = Fast | Rename;
  708. mManager = manager;
  709. mIconName = QStringLiteral( "/mIconFolder.svg" );
  710. setToolTip( name );
  711. setSortKey( QStringLiteral( " %1" ).arg( name ) );
  712. populate();
  713. }
  714. QVector<QgsDataItem *> QgsBookmarkGroupItem::createChildren()
  715. {
  716. QVector<QgsDataItem *> children;
  717. const QList< QgsBookmark > bookmarks = mManager->bookmarksByGroup( mName );
  718. children.reserve( bookmarks.size() );
  719. for ( const QgsBookmark &bookmark : bookmarks )
  720. {
  721. children << new QgsBookmarkItem( this, bookmark.name(), bookmark, mManager );
  722. }
  723. return children;
  724. }
  725. void QgsBookmarkGroupItem::addBookmark( const QgsBookmark &bookmark )
  726. {
  727. addChildItem( new QgsBookmarkItem( this, bookmark.name(), bookmark, mManager ), true );
  728. }
  729. QgsBookmarkItem *QgsBookmarkGroupItem::childItemById( const QString &id )
  730. {
  731. const QVector<QgsDataItem *> c = children();
  732. for ( QgsDataItem *i : c )
  733. {
  734. if ( QgsBookmarkItem *bookmarkItem = qobject_cast< QgsBookmarkItem * >( i ) )
  735. {
  736. if ( bookmarkItem->bookmark().id() == id )
  737. {
  738. return bookmarkItem;
  739. }
  740. }
  741. }
  742. return nullptr;
  743. }
  744. void QgsBookmarkGroupItem::removeBookmarkChildById( const QString &id )
  745. {
  746. if ( QgsBookmarkItem *bookmarkItem = childItemById( id ) )
  747. deleteChildItem( bookmarkItem );
  748. }
  749. QgsBookmarkItem::QgsBookmarkItem( QgsDataItem *parent, const QString &name, const QgsBookmark &bookmark, QgsBookmarkManager *manager )
  750. : QgsDataItem( Custom, parent, name, QStringLiteral( "bookmarks:%1/%2" ).arg( bookmark.group().toLower(), bookmark.id() ) )
  751. , mManager( manager )
  752. , mBookmark( bookmark )
  753. {
  754. mType = Custom;
  755. mCapabilities = Rename;
  756. mIconName = QStringLiteral( "/mItemBookmark.svg" );
  757. setToolTip( name );
  758. setState( Populated ); // no more children
  759. }
  760. void QgsBookmarkItem::setBookmark( const QgsBookmark &bookmark )
  761. {
  762. setName( bookmark.name() );
  763. setToolTip( bookmark.name() );
  764. mBookmark = bookmark;
  765. }
  766. QString QgsBookmarkDropHandler::customUriProviderKey() const
  767. {
  768. return QStringLiteral( "bookmark" );
  769. }
  770. bool QgsBookmarkDropHandler::canHandleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &uri, QgsMapCanvas * )
  771. {
  772. return uri.providerKey == customUriProviderKey();
  773. }
  774. bool QgsBookmarkDropHandler::handleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &uri, QgsMapCanvas *canvas ) const
  775. {
  776. QDomDocument doc;
  777. doc.setContent( uri.uri );
  778. QDomElement elem = doc.documentElement();
  779. QgsBookmark b = QgsBookmark::fromXml( elem, doc );
  780. try
  781. {
  782. if ( ! canvas->setReferencedExtent( b.extent() ) )
  783. {
  784. QgisApp::instance()->messageBar()->pushWarning( tr( "Zoom to Bookmark" ), tr( "Bookmark extent is empty" ) );
  785. }
  786. else
  787. {
  788. canvas->refresh();
  789. }
  790. }
  791. catch ( QgsCsException & )
  792. {
  793. QgisApp::instance()->messageBar()->pushWarning( tr( "Zoom to Bookmark" ), tr( "Could not reproject bookmark extent to canvas CRS." ) );
  794. }
  795. return true;
  796. }
  797. QString QgsBookmarksItemGuiProvider::name()
  798. {
  799. return QStringLiteral( "bookmark_item" );
  800. }
  801. bool QgsBookmarksItemGuiProvider::acceptDrop( QgsDataItem *item, QgsDataItemGuiContext )
  802. {
  803. if ( qobject_cast< QgsBookmarkManagerItem * >( item ) )
  804. return true;
  805. if ( qobject_cast< QgsBookmarkGroupItem * >( item ) )
  806. return true;
  807. return false;
  808. }
  809. bool QgsBookmarksItemGuiProvider::handleDrop( QgsDataItem *item, QgsDataItemGuiContext, const QMimeData *data, Qt::DropAction )
  810. {
  811. QgsBookmarkManagerItem *managerItem = qobject_cast< QgsBookmarkManagerItem * >( item );
  812. QgsBookmarkGroupItem *groupItem = qobject_cast< QgsBookmarkGroupItem * >( item );
  813. if ( managerItem || groupItem )
  814. {
  815. QgsBookmarkManager *target = managerItem ? managerItem->manager() : groupItem->manager();
  816. if ( QgsMimeDataUtils::isUriList( data ) )
  817. {
  818. const QgsMimeDataUtils::UriList list = QgsMimeDataUtils::decodeUriList( data );
  819. for ( const QgsMimeDataUtils::Uri &uri : list )
  820. {
  821. QDomDocument doc;
  822. doc.setContent( uri.uri );
  823. QDomElement elem = doc.documentElement();
  824. QgsBookmark b = QgsBookmark::fromXml( elem, doc );
  825. if ( !groupItem )
  826. b.setGroup( QString() );
  827. else
  828. b.setGroup( groupItem->group() );
  829. // if bookmark doesn't already exist in manager, we add it. Otherwise we update it.
  830. if ( target->bookmarkById( b.id() ).id().isEmpty() )
  831. target->addBookmark( b );
  832. else
  833. target->updateBookmark( b );
  834. }
  835. return true;
  836. }
  837. }
  838. return false;
  839. }
  840. void QgsBookmarksItemGuiProvider::populateContextMenu( QgsDataItem *item, QMenu *menu, const QList<QgsDataItem *> &selectedItems, QgsDataItemGuiContext context )
  841. {
  842. if ( qobject_cast< QgsBookmarksItem * >( item ) )
  843. {
  844. QAction *addBookmark = new QAction( tr( "New Spatial Bookmark…" ), menu );
  845. connect( addBookmark, &QAction::triggered, this, [ = ]
  846. {
  847. QgisApp::instance()->newBookmark();
  848. } );
  849. menu->addAction( addBookmark );
  850. QAction *showBookmarksPanel = new QAction( tr( "Show Spatial Bookmarks Manager" ), menu );
  851. connect( showBookmarksPanel, &QAction::triggered, this, [ = ]
  852. {
  853. QgisApp::instance()->showBookmarkManager( true );
  854. } );
  855. menu->addAction( showBookmarksPanel );
  856. menu->addSeparator();
  857. QAction *importBookmarks = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionSharingImport.svg" ) ), tr( "Import Spatial Bookmarks…" ), menu );
  858. connect( importBookmarks, &QAction::triggered, this, [ = ]
  859. {
  860. importBookmarksToManager( QgsApplication::bookmarkManager(), context.messageBar() );
  861. } );
  862. menu->addAction( importBookmarks );
  863. QAction *exportBookmarks = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionSharingExport.svg" ) ), tr( "Export Spatial Bookmarks…" ), menu );
  864. connect( exportBookmarks, &QAction::triggered, this, [ = ]
  865. {
  866. exportBookmarksFromManagers( QList< const QgsBookmarkManager * >() << QgsApplication::bookmarkManager() << QgsProject::instance()->bookmarkManager(), context.messageBar() );
  867. } );
  868. menu->addAction( exportBookmarks );
  869. }
  870. else if ( QgsBookmarkManagerItem *managerItem = qobject_cast< QgsBookmarkManagerItem * >( item ) )
  871. {
  872. QAction *addBookmark = new QAction( tr( "New Spatial Bookmark…" ), menu );
  873. const bool inProject = managerItem->manager() != QgsApplication::bookmarkManager();
  874. connect( addBookmark, &QAction::triggered, this, [ = ]
  875. {
  876. QgisApp::instance()->newBookmark( inProject );
  877. } );
  878. menu->addAction( addBookmark );
  879. menu->addSeparator();
  880. QAction *importBookmarks = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionSharingImport.svg" ) ), tr( "Import Spatial Bookmarks…" ), menu );
  881. connect( importBookmarks, &QAction::triggered, this, [ = ]
  882. {
  883. importBookmarksToManager( managerItem->manager(), context.messageBar() );
  884. } );
  885. menu->addAction( importBookmarks );
  886. QAction *exportBookmarks = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionSharingExport.svg" ) ), tr( "Export Spatial Bookmarks…" ), menu );
  887. connect( exportBookmarks, &QAction::triggered, this, [ = ]
  888. {
  889. exportBookmarksFromManagers( QList< const QgsBookmarkManager * >() << managerItem->manager(), context.messageBar() );
  890. } );
  891. menu->addAction( exportBookmarks );
  892. }
  893. else if ( QgsBookmarkItem *bookmarkItem = qobject_cast< QgsBookmarkItem * >( item ) )
  894. {
  895. QAction *actionZoom = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionZoomToLayer.svg" ) ), tr( "Zoom to Bookmark" ), menu );
  896. connect( actionZoom, &QAction::triggered, this, [bookmarkItem, context]
  897. {
  898. try
  899. {
  900. if ( !QgisApp::instance()->mapCanvas()->setReferencedExtent( bookmarkItem->bookmark().extent() ) )
  901. {
  902. context.messageBar()->pushWarning( tr( "Zoom to Bookmark" ), tr( "Bookmark extent is empty" ) );
  903. }
  904. else
  905. {
  906. QgisApp::instance()->mapCanvas()->refresh();
  907. }
  908. }
  909. catch ( QgsCsException & )
  910. {
  911. context.messageBar()->pushWarning( tr( "Zoom to Bookmark" ), tr( "Could not reproject bookmark extent to project CRS." ) );
  912. }
  913. } );
  914. menu->addAction( actionZoom );
  915. menu->addSeparator();
  916. QAction *actionEdit = new QAction( tr( "Edit Spatial Bookmark…" ), menu );
  917. connect( actionEdit, &QAction::triggered, this, [bookmarkItem]
  918. {
  919. QgsBookmarkEditorDialog *dlg = new QgsBookmarkEditorDialog( bookmarkItem->bookmark(), bookmarkItem->manager() == QgsProject::instance()->bookmarkManager(), QgisApp::instance(), QgisApp::instance()->mapCanvas() );
  920. dlg->setAttribute( Qt::WA_DeleteOnClose );
  921. dlg->show();
  922. } );
  923. menu->addAction( actionEdit );
  924. QStringList ids;
  925. for ( QgsDataItem *i : selectedItems )
  926. {
  927. if ( QgsBookmarkItem *b = qobject_cast< QgsBookmarkItem * >( i ) )
  928. {
  929. if ( b->manager() == bookmarkItem->manager() )
  930. ids << b->bookmark().id();
  931. }
  932. }
  933. QAction *actionDelete = new QAction( selectedItems.count() == 1 ? tr( "Delete Spatial Bookmark" ) : tr( "Delete Spatial Bookmarks" ), menu );
  934. connect( actionDelete, &QAction::triggered, this, [bookmarkItem, ids]
  935. {
  936. if ( ids.count() == 1 )
  937. {
  938. if ( QMessageBox::question( nullptr, QObject::tr( "Delete Spatial Bookmark" ),
  939. QObject::tr( "Are you sure you want to delete the %1 bookmark?" ).arg( bookmarkItem->name() ),
  940. QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
  941. return;
  942. bookmarkItem->manager()->removeBookmark( bookmarkItem->bookmark().id() );
  943. }
  944. else
  945. {
  946. if ( QMessageBox::question( nullptr, QObject::tr( "Delete Spatial Bookmarks" ),
  947. QObject::tr( "Are you sure you want to delete the %1 selected bookmarks?" ).arg( ids.count() ),
  948. QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
  949. return;
  950. for ( const QString &id : ids )
  951. bookmarkItem->manager()->removeBookmark( id );
  952. }
  953. } );
  954. menu->addAction( actionDelete );
  955. }
  956. else if ( QgsBookmarkGroupItem *groupItem = qobject_cast< QgsBookmarkGroupItem * >( item ) )
  957. {
  958. QStringList groups;
  959. QgsBookmarkManager *manager = groupItem->manager();
  960. for ( QgsDataItem *i : selectedItems )
  961. {
  962. if ( QgsBookmarkGroupItem *g = qobject_cast< QgsBookmarkGroupItem * >( i ) )
  963. {
  964. if ( g->manager() == manager )
  965. groups << g->group();
  966. }
  967. }
  968. QAction *exportBookmarks = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "/mActionSharingExport.svg" ) ), tr( "Export Spatial Bookmarks…" ), menu );
  969. connect( exportBookmarks, &QAction::triggered, this, [ = ]
  970. {
  971. exportBookmarksFromManagers( QList< const QgsBookmarkManager * >() << groupItem->manager(), context.messageBar(), groupItem->group() );
  972. } );
  973. menu->addAction( exportBookmarks );
  974. menu->addSeparator();
  975. QAction *actionDelete = new QAction( selectedItems.count() == 1 ? tr( "Delete Bookmark Group" ) : tr( "Delete Bookmark Groups" ), menu );
  976. connect( actionDelete, &QAction::triggered, this, [selectedItems, groups, manager]
  977. {
  978. if ( groups.count() == 1 )
  979. {
  980. if ( QMessageBox::question( nullptr, QObject::tr( "Delete Bookmark Group" ),
  981. QObject::tr( "Are you sure you want to delete the %1 bookmark group? This will delete all bookmarks in this group." ).arg( groups.at( 0 ) ),
  982. QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
  983. return;
  984. const QList<QgsBookmark> matching = manager->bookmarksByGroup( groups.at( 0 ) );
  985. for ( const QgsBookmark &bookmark : matching )
  986. {
  987. manager->removeBookmark( bookmark.id() );
  988. }
  989. }
  990. else
  991. {
  992. if ( QMessageBox::question( nullptr, QObject::tr( "Delete Bookmark Groups" ),
  993. QObject::tr( "Are you sure you want to delete the %1 selected bookmark groups? This will delete all bookmarks in these groups." ).arg( groups.count() ),
  994. QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
  995. return;
  996. int i = 0;
  997. for ( const QString &g : groups )
  998. {
  999. const QList<QgsBookmark> matching = manager->bookmarksByGroup( g );
  1000. for ( const QgsBookmark &bookmark : matching )
  1001. {
  1002. manager->removeBookmark( bookmark.id() );
  1003. }
  1004. i++;
  1005. }
  1006. }
  1007. } );
  1008. menu->addAction( actionDelete );
  1009. }
  1010. }
  1011. bool QgsBookmarksItemGuiProvider::handleDoubleClick( QgsDataItem *item, QgsDataItemGuiContext context )
  1012. {
  1013. if ( QgsBookmarkItem *bookmarkItem = qobject_cast< QgsBookmarkItem * >( item ) )
  1014. {
  1015. try
  1016. {
  1017. if ( !QgisApp::instance()->mapCanvas()->setReferencedExtent( bookmarkItem->bookmark().extent() ) )
  1018. {
  1019. context.messageBar()->pushWarning( tr( "Zoom to Bookmark" ), tr( "Bookmark extent is empty" ) );
  1020. }
  1021. else
  1022. {
  1023. QgisApp::instance()->mapCanvas()->refresh();
  1024. }
  1025. }
  1026. catch ( QgsCsException & )
  1027. {
  1028. context.messageBar()->pushWarning( tr( "Zoom to Bookmark" ), tr( "Could not reproject bookmark extent to project CRS." ) );
  1029. }
  1030. return true;
  1031. }
  1032. return false;
  1033. }
  1034. bool QgsBookmarksItemGuiProvider::rename( QgsDataItem *item, const QString &name, QgsDataItemGuiContext context )
  1035. {
  1036. if ( QgsBookmarkItem *bookmarkItem = qobject_cast< QgsBookmarkItem * >( item ) )
  1037. {
  1038. QgsBookmark bookmark = bookmarkItem->bookmark();
  1039. bookmark.setName( name );
  1040. if ( !bookmarkItem->manager()->updateBookmark( bookmark ) )
  1041. {
  1042. context.messageBar()->pushWarning( tr( "Rename Bookmark" ), tr( "Could not rename bookmark" ) );
  1043. return true;
  1044. }
  1045. return true;
  1046. }
  1047. else if ( QgsBookmarkGroupItem *groupItem = qobject_cast< QgsBookmarkGroupItem * >( item ) )
  1048. {
  1049. groupItem->manager()->renameGroup( groupItem->group(), name );
  1050. return true;
  1051. }
  1052. return false;
  1053. }
  1054. void QgsBookmarksItemGuiProvider::exportBookmarksFromManagers( const QList<const QgsBookmarkManager *> &managers, QgsMessageBar *messageBar, const QString &group )
  1055. {
  1056. QgsSettings settings;
  1057. QString lastUsedDir = settings.value( QStringLiteral( "Windows/Bookmarks/LastUsedDirectory" ), QDir::homePath() ).toString();
  1058. QString fileName = QFileDialog::getSaveFileName( QgisApp::instance(), tr( "Export Bookmarks" ), lastUsedDir,
  1059. tr( "XML files (*.xml *.XML)" ) );
  1060. if ( fileName.isEmpty() )
  1061. {
  1062. return;
  1063. }
  1064. // ensure the user never omitted the extension from the file name
  1065. fileName = QgsFileUtils::ensureFileNameHasExtension( fileName, QStringList() << QStringLiteral( "xml" ) );
  1066. if ( !QgsBookmarkManager::exportToFile( fileName, managers, group ) )
  1067. {
  1068. messageBar->pushWarning( tr( "Export Bookmarks" ), tr( "Error exporting bookmark file" ) );
  1069. }
  1070. else
  1071. {
  1072. messageBar->pushSuccess( tr( "Export Bookmarks" ), tr( "Successfully exported bookmarks to <a href=\"%1\">%2</a>" )
  1073. .arg( QUrl::fromLocalFile( fileName ).toString(), QDir::toNativeSeparators( fileName ) ) );
  1074. }
  1075. settings.setValue( QStringLiteral( "Windows/Bookmarks/LastUsedDirectory" ), QFileInfo( fileName ).path() );
  1076. }
  1077. void QgsBookmarksItemGuiProvider::importBookmarksToManager( QgsBookmarkManager *manager, QgsMessageBar *messageBar )
  1078. {
  1079. QgsSettings settings;
  1080. QString lastUsedDir = settings.value( QStringLiteral( "Windows/Bookmarks/LastUsedDirectory" ), QDir::homePath() ).toString();
  1081. QString fileName = QFileDialog::getOpenFileName( QgisApp::instance(), tr( "Import Bookmarks" ), lastUsedDir,
  1082. tr( "XML files (*.xml *.XML)" ) );
  1083. if ( fileName.isEmpty() )
  1084. {
  1085. return;
  1086. }
  1087. if ( !manager->importFromFile( fileName ) )
  1088. {
  1089. messageBar->pushWarning( tr( "Import Bookmarks" ), tr( "Error importing bookmark file" ) );
  1090. }
  1091. else
  1092. {
  1093. messageBar->pushSuccess( tr( "Import Bookmarks" ), tr( "Bookmarks imported successfully" ) );
  1094. }
  1095. settings.setValue( QStringLiteral( "Windows/Bookmarks/LastUsedDirectory" ), QFileInfo( fileName ).path() );
  1096. }
  1097. //
  1098. // QgsHtmlDataItemProvider
  1099. //
  1100. QString QgsHtmlDataItemProvider::name()
  1101. {
  1102. return QStringLiteral( "html" );
  1103. }
  1104. int QgsHtmlDataItemProvider::capabilities() const
  1105. {
  1106. return QgsDataProvider::File;
  1107. }
  1108. QgsDataItem *QgsHtmlDataItemProvider::createDataItem( const QString &path, QgsDataItem *parentItem )
  1109. {
  1110. QFileInfo fileInfo( path );
  1111. if ( fileInfo.suffix().compare( QLatin1String( "htm" ), Qt::CaseInsensitive ) == 0
  1112. || fileInfo.suffix().compare( QLatin1String( "html" ), Qt::CaseInsensitive ) == 0 )
  1113. {
  1114. return new QgsHtmlDataItem( parentItem, fileInfo.fileName(), path );
  1115. }
  1116. return nullptr;
  1117. }
  1118. //
  1119. // QgsHtmlDataItemProvider
  1120. //
  1121. QgsHtmlDataItem::QgsHtmlDataItem( QgsDataItem *parent, const QString &name, const QString &path )
  1122. : QgsDataItem( QgsDataItem::Custom, parent, name, path )
  1123. {
  1124. setState( QgsDataItem::Populated ); // no children
  1125. setIconName( QStringLiteral( "/mIconHtml.svg" ) );
  1126. setToolTip( QDir::toNativeSeparators( path ) );
  1127. }
  1128. bool QgsHtmlDataItem::handleDoubleClick()
  1129. {
  1130. QDesktopServices::openUrl( QUrl::fromLocalFile( path() ) );
  1131. return true;
  1132. }
  1133. QList<QAction *> QgsHtmlDataItem::actions( QWidget *parent )
  1134. {
  1135. QAction *openAction = new QAction( tr( "&Open File…" ), parent );
  1136. connect( openAction, &QAction::triggered, this, [ = ]
  1137. {
  1138. QDesktopServices::openUrl( QUrl::fromLocalFile( path() ) );
  1139. } );
  1140. return QList<QAction *>() << openAction;
  1141. }