ctkPathListWidget.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. /*=========================================================================
  2. Library: CTK
  3. Copyright (c) Kitware Inc.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0.txt
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. This file was originally developed by Jean-Christophe Fillion-Robin, Kitware Inc.
  14. and was partially funded by NIH grant 3P41RR013218-12S1
  15. =========================================================================*/
  16. // Qt includes
  17. #include <QFileInfo>
  18. #include <QHBoxLayout>
  19. #include <QListView>
  20. #include <QStandardItemModel>
  21. #include <QApplication>
  22. // QtGUI includes
  23. #include "ctkPathListWidget.h"
  24. // --------------------------------------------------------------------------
  25. // ctkPathListWidgetPrivate
  26. //-----------------------------------------------------------------------------
  27. class ctkPathListWidgetPrivate
  28. {
  29. Q_DECLARE_PUBLIC(ctkPathListWidget)
  30. protected:
  31. ctkPathListWidget* const q_ptr;
  32. public:
  33. enum PathType {
  34. Unknown,
  35. File,
  36. Directory
  37. };
  38. ctkPathListWidgetPrivate(ctkPathListWidget& object);
  39. void _q_emitPathClicked(const QModelIndex &index);
  40. void _q_emitPathDoubleClicked(const QModelIndex &index);
  41. void _q_emitPathActivated(const QModelIndex &index);
  42. void _q_emitCurrentPathChanged(const QModelIndex &current, const QModelIndex &previous);
  43. bool addPath(const QString& path);
  44. bool removePath(const QString& path);
  45. void fileOptionsChanged();
  46. void directoryOptionsChanged();
  47. PathType pathType(const QString& absolutePath) const;
  48. bool isValidPath(const QString& absoluteFilePath, PathType pathType) const;
  49. bool isValidFile(const QString& absoluteFilePath) const;
  50. bool isValidDir(const QString& absoluteDirPath) const;
  51. QStandardItemModel PathListModel;
  52. ctkPathListWidget::Mode Mode;
  53. ctkPathListWidget::PathOptions FileOptions;
  54. ctkPathListWidget::PathOptions DirectoryOptions;
  55. QIcon FileIcon;
  56. QIcon DirectoryIcon;
  57. };
  58. // --------------------------------------------------------------------------
  59. // ctkPathListWidgetPrivate methods
  60. #include "moc_ctkPathListWidget.cpp"
  61. // --------------------------------------------------------------------------
  62. ctkPathListWidgetPrivate::ctkPathListWidgetPrivate(ctkPathListWidget& object)
  63. : q_ptr(&object)
  64. , Mode(ctkPathListWidget::Any)
  65. , FileOptions(ctkPathListWidget::Exists | ctkPathListWidget::Readable)
  66. , DirectoryOptions(ctkPathListWidget::Exists | ctkPathListWidget::Readable)
  67. {
  68. }
  69. // --------------------------------------------------------------------------
  70. void ctkPathListWidgetPrivate::_q_emitPathClicked(const QModelIndex &index)
  71. {
  72. Q_Q(ctkPathListWidget);
  73. emit q->pathClicked(this->PathListModel.data(index, ctkPathListWidget::AbsolutePathRole).toString());
  74. }
  75. // --------------------------------------------------------------------------
  76. void ctkPathListWidgetPrivate::_q_emitPathDoubleClicked(const QModelIndex &index)
  77. {
  78. Q_Q(ctkPathListWidget);
  79. emit q->pathDoubleClicked(this->PathListModel.data(index, ctkPathListWidget::AbsolutePathRole).toString());
  80. }
  81. // --------------------------------------------------------------------------
  82. void ctkPathListWidgetPrivate::_q_emitPathActivated(const QModelIndex &index)
  83. {
  84. Q_Q(ctkPathListWidget);
  85. emit q->pathActivated(this->PathListModel.data(index, ctkPathListWidget::AbsolutePathRole).toString());
  86. }
  87. // --------------------------------------------------------------------------
  88. void ctkPathListWidgetPrivate::_q_emitCurrentPathChanged(const QModelIndex &current, const QModelIndex &previous)
  89. {
  90. Q_Q(ctkPathListWidget);
  91. QString currentPath = this->PathListModel.data(current, ctkPathListWidget::AbsolutePathRole).toString();
  92. QString previousPath = this->PathListModel.data(previous, ctkPathListWidget::AbsolutePathRole).toString();
  93. emit q->currentPathChanged(currentPath, previousPath);
  94. }
  95. // --------------------------------------------------------------------------
  96. bool ctkPathListWidgetPrivate::addPath(const QString& path)
  97. {
  98. Q_Q(ctkPathListWidget);
  99. QString absolutePath = QFileInfo(path).absoluteFilePath();
  100. if (q->contains(absolutePath))
  101. {
  102. return false;
  103. }
  104. PathType pathType = this->pathType(absolutePath);
  105. if (!this->isValidPath(absolutePath, pathType))
  106. {
  107. return false;
  108. }
  109. QStandardItem * item = new QStandardItem(path);
  110. item->setData(QVariant(absolutePath), Qt::ToolTipRole);
  111. item->setData(QVariant(absolutePath), ctkPathListWidget::AbsolutePathRole);
  112. if (pathType == File && !this->FileIcon.isNull())
  113. {
  114. item->setData(this->FileIcon, Qt::DecorationRole);
  115. }
  116. else if (pathType == Directory && !this->DirectoryIcon.isNull())
  117. {
  118. item->setData(this->DirectoryIcon, Qt::DecorationRole);
  119. }
  120. this->PathListModel.appendRow(item);
  121. return true;
  122. }
  123. // --------------------------------------------------------------------------
  124. bool ctkPathListWidgetPrivate::removePath(const QString& path)
  125. {
  126. QString absolutePath = QFileInfo(path).absoluteFilePath();
  127. QModelIndexList foundIndices = this->PathListModel.match(this->PathListModel.index(0, 0),
  128. ctkPathListWidget::AbsolutePathRole,
  129. absolutePath);
  130. Q_ASSERT(foundIndices.count() < 2);
  131. if (!foundIndices.isEmpty())
  132. {
  133. this->PathListModel.removeRow(foundIndices.front().row());
  134. return true;
  135. }
  136. return false;
  137. }
  138. // --------------------------------------------------------------------------
  139. void ctkPathListWidgetPrivate::fileOptionsChanged()
  140. {
  141. QStringList removedPaths;
  142. for(int i = 0; i < this->PathListModel.rowCount();)
  143. {
  144. QModelIndex index = this->PathListModel.index(i, 0);
  145. QString filePath = this->PathListModel.data(index, ctkPathListWidget::AbsolutePathRole).toString();
  146. if (!this->isValidFile(filePath))
  147. {
  148. this->PathListModel.removeRow(i);
  149. removedPaths << filePath;
  150. }
  151. else
  152. {
  153. ++i;
  154. }
  155. }
  156. if (!removedPaths.empty())
  157. {
  158. Q_Q(ctkPathListWidget);
  159. emit q->pathsChanged(QStringList(), removedPaths);
  160. }
  161. }
  162. // --------------------------------------------------------------------------
  163. void ctkPathListWidgetPrivate::directoryOptionsChanged()
  164. {
  165. QStringList removedPaths;
  166. for(int i = 0; i < this->PathListModel.rowCount();)
  167. {
  168. QModelIndex index = this->PathListModel.index(i, 0);
  169. QString dirPath = this->PathListModel.data(index, ctkPathListWidget::AbsolutePathRole).toString();
  170. if (!this->isValidDir(dirPath))
  171. {
  172. this->PathListModel.removeRow(i);
  173. removedPaths << dirPath;
  174. }
  175. else
  176. {
  177. ++i;
  178. }
  179. }
  180. if (!removedPaths.empty())
  181. {
  182. Q_Q(ctkPathListWidget);
  183. emit q->pathsChanged(QStringList(), removedPaths);
  184. }
  185. }
  186. // --------------------------------------------------------------------------
  187. ctkPathListWidgetPrivate::PathType ctkPathListWidgetPrivate::pathType(const QString& absolutePath) const
  188. {
  189. QFileInfo fileInfo(absolutePath);
  190. if (fileInfo.exists())
  191. {
  192. if (fileInfo.isFile())
  193. {
  194. return File;
  195. }
  196. else if (fileInfo.isDir())
  197. {
  198. return Directory;
  199. }
  200. return Unknown;
  201. }
  202. // Check if path is a file or directory by looking for a trailing slash
  203. else if (absolutePath.endsWith('/'))
  204. {
  205. return Directory;
  206. }
  207. else
  208. {
  209. return File;
  210. }
  211. }
  212. // --------------------------------------------------------------------------
  213. bool ctkPathListWidgetPrivate::isValidPath(const QString& absoluteFilePath, PathType pathType) const
  214. {
  215. switch (pathType)
  216. {
  217. case Unknown:
  218. if (this->Mode == ctkPathListWidget::Any)
  219. {
  220. return true;
  221. }
  222. return false;
  223. case File:
  224. return this->isValidFile(absoluteFilePath);
  225. case Directory:
  226. return this->isValidDir(absoluteFilePath);
  227. default:
  228. return false;
  229. }
  230. }
  231. // --------------------------------------------------------------------------
  232. bool ctkPathListWidgetPrivate::isValidFile(const QString& absoluteFilePath) const
  233. {
  234. if (this->Mode == ctkPathListWidget::DirectoriesOnly)
  235. {
  236. return false;
  237. }
  238. if (this->FileOptions.testFlag(ctkPathListWidget::None))
  239. {
  240. return true;
  241. }
  242. else
  243. {
  244. QFileInfo fileInfo(absoluteFilePath);
  245. if (fileInfo.exists())
  246. {
  247. if (!fileInfo.isFile())
  248. {
  249. return false;
  250. }
  251. if (this->FileOptions.testFlag(ctkPathListWidget::Readable) &&
  252. !fileInfo.isReadable())
  253. {
  254. return false;
  255. }
  256. if (this->FileOptions.testFlag(ctkPathListWidget::Writable) &&
  257. !fileInfo.isWritable())
  258. {
  259. return false;
  260. }
  261. if (this->FileOptions.testFlag(ctkPathListWidget::Executable) &&
  262. !fileInfo.isExecutable())
  263. {
  264. return false;
  265. }
  266. return true;
  267. }
  268. else
  269. {
  270. return !this->FileOptions.testFlag(ctkPathListWidget::Exists);
  271. }
  272. }
  273. }
  274. // --------------------------------------------------------------------------
  275. bool ctkPathListWidgetPrivate::isValidDir(const QString& absoluteDirPath) const
  276. {
  277. if (this->Mode == ctkPathListWidget::FilesOnly)
  278. {
  279. return false;
  280. }
  281. if (this->DirectoryOptions.testFlag(ctkPathListWidget::None))
  282. {
  283. return true;
  284. }
  285. else
  286. {
  287. QFileInfo fileInfo(absoluteDirPath);
  288. if (fileInfo.exists())
  289. {
  290. if (!fileInfo.isDir())
  291. {
  292. return false;
  293. }
  294. if (this->DirectoryOptions.testFlag(ctkPathListWidget::Readable) &&
  295. !fileInfo.isReadable())
  296. {
  297. return false;
  298. }
  299. if (this->DirectoryOptions.testFlag(ctkPathListWidget::Writable) &&
  300. !fileInfo.isWritable())
  301. {
  302. return false;
  303. }
  304. if (this->DirectoryOptions.testFlag(ctkPathListWidget::Executable) &&
  305. !fileInfo.isExecutable())
  306. {
  307. return false;
  308. }
  309. return true;
  310. }
  311. else
  312. {
  313. return !this->FileOptions.testFlag(ctkPathListWidget::Exists);
  314. }
  315. }
  316. }
  317. // --------------------------------------------------------------------------
  318. // ctkPathListWidget methods
  319. // --------------------------------------------------------------------------
  320. ctkPathListWidget::ctkPathListWidget(QWidget* _parent)
  321. : Superclass(_parent)
  322. , d_ptr(new ctkPathListWidgetPrivate(*this))
  323. {
  324. Q_D(ctkPathListWidget);
  325. this->setSelectionBehavior(QAbstractItemView::SelectRows);
  326. this->setSelectionMode(QAbstractItemView::ExtendedSelection);
  327. this->setEditTriggers(QAbstractItemView::NoEditTriggers);
  328. this->unsetFileIcon();
  329. this->unsetDirectoryIcon();
  330. QListView::setModel(&d->PathListModel);
  331. // signals
  332. this->connect(this, SIGNAL(clicked(QModelIndex)), SLOT(_q_emitPathClicked(QModelIndex)));
  333. this->connect(this, SIGNAL(doubleClicked(QModelIndex)), SLOT(_q_emitPathDoubleClicked(QModelIndex)));
  334. this->connect(this, SIGNAL(activated(QModelIndex)), SLOT(_q_emitPathActivated(QModelIndex)));
  335. this->connect(this->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
  336. SLOT(_q_emitCurrentPathChanged(QModelIndex,QModelIndex)));
  337. }
  338. // --------------------------------------------------------------------------
  339. ctkPathListWidget::~ctkPathListWidget()
  340. {
  341. }
  342. // --------------------------------------------------------------------------
  343. ctkPathListWidget::Mode ctkPathListWidget::mode() const
  344. {
  345. Q_D(const ctkPathListWidget);
  346. return d->Mode;
  347. }
  348. // --------------------------------------------------------------------------
  349. QIcon ctkPathListWidget::fileIcon() const
  350. {
  351. Q_D(const ctkPathListWidget);
  352. return d->FileIcon;
  353. }
  354. // --------------------------------------------------------------------------
  355. void ctkPathListWidget::setFileIcon(const QIcon& icon)
  356. {
  357. Q_D(ctkPathListWidget);
  358. d->FileIcon = icon;
  359. }
  360. // --------------------------------------------------------------------------
  361. void ctkPathListWidget::unsetFileIcon()
  362. {
  363. Q_D(ctkPathListWidget);
  364. d->FileIcon = QApplication::style()->standardIcon(QStyle::SP_FileIcon);
  365. }
  366. // --------------------------------------------------------------------------
  367. QIcon ctkPathListWidget::directoryIcon() const
  368. {
  369. Q_D(const ctkPathListWidget);
  370. return d->DirectoryIcon;
  371. }
  372. // --------------------------------------------------------------------------
  373. void ctkPathListWidget::setDirectoryIcon(const QIcon& icon)
  374. {
  375. Q_D(ctkPathListWidget);
  376. d->DirectoryIcon = icon;
  377. }
  378. // --------------------------------------------------------------------------
  379. void ctkPathListWidget::unsetDirectoryIcon()
  380. {
  381. Q_D(ctkPathListWidget);
  382. d->DirectoryIcon = QApplication::style()->standardIcon(QStyle::SP_DirIcon);
  383. }
  384. // --------------------------------------------------------------------------
  385. ctkPathListWidget::PathOptions ctkPathListWidget::fileOptions() const
  386. {
  387. Q_D(const ctkPathListWidget);
  388. return d->FileOptions;
  389. }
  390. // --------------------------------------------------------------------------
  391. void ctkPathListWidget::setFileOptions(PathOptions fileOptions)
  392. {
  393. Q_D(ctkPathListWidget);
  394. if (d->FileOptions != fileOptions)
  395. {
  396. d->FileOptions = fileOptions;
  397. d->fileOptionsChanged();
  398. }
  399. }
  400. // --------------------------------------------------------------------------
  401. ctkPathListWidget::PathOptions ctkPathListWidget::directoryOptions() const
  402. {
  403. Q_D(const ctkPathListWidget);
  404. return d->DirectoryOptions;
  405. }
  406. // --------------------------------------------------------------------------
  407. void ctkPathListWidget::setDirectoryOptions(PathOptions directoryOptions)
  408. {
  409. Q_D(ctkPathListWidget);
  410. if (d->DirectoryOptions != directoryOptions)
  411. {
  412. d->DirectoryOptions = directoryOptions;
  413. d->directoryOptionsChanged();
  414. }
  415. }
  416. // --------------------------------------------------------------------------
  417. QStringList ctkPathListWidget::files(bool absolutePath) const
  418. {
  419. Q_D(const ctkPathListWidget);
  420. QStringList fileList;
  421. int role = Qt::DisplayRole;
  422. if (absolutePath)
  423. {
  424. role = ctkPathListWidget::AbsolutePathRole;
  425. }
  426. for(int i = 0; i < d->PathListModel.rowCount(); ++i)
  427. {
  428. QString filePath = d->PathListModel.data(d->PathListModel.index(i, 0), role).toString();
  429. if (d->pathType(filePath) == ctkPathListWidgetPrivate::File)
  430. {
  431. fileList << filePath;
  432. }
  433. }
  434. return fileList;
  435. }
  436. // --------------------------------------------------------------------------
  437. QStringList ctkPathListWidget::directories(bool absolutePath) const
  438. {
  439. Q_D(const ctkPathListWidget);
  440. QStringList pathList;
  441. int role = Qt::DisplayRole;
  442. if (absolutePath)
  443. {
  444. role = ctkPathListWidget::AbsolutePathRole;
  445. }
  446. for(int i = 0; i < d->PathListModel.rowCount(); ++i)
  447. {
  448. QString dirPath = d->PathListModel.data(d->PathListModel.index(i, 0), role).toString();
  449. if (d->pathType(dirPath) == ctkPathListWidgetPrivate::Directory)
  450. {
  451. pathList << dirPath;
  452. }
  453. }
  454. return pathList;
  455. }
  456. // --------------------------------------------------------------------------
  457. QStringList ctkPathListWidget::paths(bool absolutePath)const
  458. {
  459. Q_D(const ctkPathListWidget);
  460. QStringList pathList;
  461. int role = Qt::DisplayRole;
  462. if (absolutePath)
  463. {
  464. role = ctkPathListWidget::AbsolutePathRole;
  465. }
  466. for(int i = 0; i < d->PathListModel.rowCount(); ++i)
  467. {
  468. pathList << d->PathListModel.data(d->PathListModel.index(i, 0), role).toString();
  469. }
  470. return pathList;
  471. }
  472. // --------------------------------------------------------------------------
  473. QStringList ctkPathListWidget::selectedPaths(bool absolutePath)const
  474. {
  475. Q_D(const ctkPathListWidget);
  476. QStringList pathList;
  477. int role = Qt::DisplayRole;
  478. if (absolutePath)
  479. {
  480. role = ctkPathListWidget::AbsolutePathRole;
  481. }
  482. QModelIndexList selectedIndexes = this->selectionModel()->selectedRows();
  483. foreach(const QModelIndex& index, selectedIndexes)
  484. {
  485. pathList << d->PathListModel.data(index, role).toString();
  486. }
  487. return pathList;
  488. }
  489. // --------------------------------------------------------------------------
  490. QString ctkPathListWidget::currentPath(bool absolutePath) const
  491. {
  492. Q_D(const ctkPathListWidget);
  493. QModelIndex currentIndex = this->currentIndex();
  494. if (!currentIndex.isValid())
  495. {
  496. return QString();
  497. }
  498. int role = absolutePath ? static_cast<int>(AbsolutePathRole)
  499. : static_cast<int>(Qt::DisplayRole);
  500. return d->PathListModel.data(currentIndex, role).toString();
  501. }
  502. // --------------------------------------------------------------------------
  503. int ctkPathListWidget::count() const
  504. {
  505. return this->model()->rowCount();
  506. }
  507. // --------------------------------------------------------------------------
  508. QString ctkPathListWidget::path(int row) const
  509. {
  510. Q_D(const ctkPathListWidget);
  511. if (row < 0 || row >= count())
  512. {
  513. return QString();
  514. }
  515. return d->PathListModel.data(d->PathListModel.index(row, 0), AbsolutePathRole).toString();
  516. }
  517. // --------------------------------------------------------------------------
  518. QStandardItem* ctkPathListWidget::item(int row) const
  519. {
  520. Q_D(const ctkPathListWidget);
  521. return d->PathListModel.item(row);
  522. }
  523. // --------------------------------------------------------------------------
  524. QStandardItem *ctkPathListWidget::item(const QString &absolutePath) const
  525. {
  526. Q_D(const ctkPathListWidget);
  527. QModelIndexList result = d->PathListModel.match(d->PathListModel.index(0,0), AbsolutePathRole,
  528. absolutePath, 1, Qt::MatchExactly);
  529. Q_ASSERT(result.count() < 2);
  530. if (result.isEmpty())
  531. {
  532. return NULL;
  533. }
  534. else
  535. {
  536. return d->PathListModel.item(result.front().row());
  537. }
  538. }
  539. // --------------------------------------------------------------------------
  540. QString ctkPathListWidget::pathAt(const QPoint& point) const
  541. {
  542. Q_D(const ctkPathListWidget);
  543. return d->PathListModel.data(indexAt(point), AbsolutePathRole).toString();
  544. }
  545. // --------------------------------------------------------------------------
  546. QStandardItem* ctkPathListWidget::itemAt(const QPoint &point) const
  547. {
  548. Q_D(const ctkPathListWidget);
  549. QModelIndex index = this->indexAt(point);
  550. if (index.isValid())
  551. {
  552. return d->PathListModel.item(index.row());
  553. }
  554. return NULL;
  555. }
  556. // --------------------------------------------------------------------------
  557. int ctkPathListWidget::row(const QString& path) const
  558. {
  559. Q_D(const ctkPathListWidget);
  560. QModelIndexList result = d->PathListModel.match(d->PathListModel.index(0,0), AbsolutePathRole,
  561. QFileInfo(path).absoluteFilePath(), 1, Qt::MatchExactly);
  562. Q_ASSERT(result.count() < 2);
  563. if (!result.isEmpty())
  564. {
  565. return result.front().row();
  566. }
  567. return -1;
  568. }
  569. // --------------------------------------------------------------------------
  570. bool ctkPathListWidget::editPath(const QString &oldPath, const QString &newPath)
  571. {
  572. Q_D(ctkPathListWidget);
  573. QString oldAbsolutePath = QFileInfo(oldPath).absoluteFilePath();
  574. QModelIndexList matched = d->PathListModel.match(d->PathListModel.index(0,0), AbsolutePathRole,
  575. oldAbsolutePath, 1, Qt::MatchExactly);
  576. Q_ASSERT(matched.size() < 2);
  577. if (matched.isEmpty())
  578. {
  579. return false;
  580. }
  581. return this->editPath(matched.front(), newPath);
  582. }
  583. // --------------------------------------------------------------------------
  584. bool ctkPathListWidget::editPath(const QModelIndex &index, const QString &newPath)
  585. {
  586. Q_D(ctkPathListWidget);
  587. if (!index.isValid())
  588. {
  589. return false;
  590. }
  591. QString oldAbsolutePath = d->PathListModel.data(index, AbsolutePathRole).toString();
  592. ctkPathListWidgetPrivate::PathType oldPathType = d->pathType(oldAbsolutePath);
  593. ctkPathListWidgetPrivate::PathType newPathType = d->pathType(newPath);
  594. if (oldPathType != newPathType)
  595. {
  596. return false;
  597. }
  598. if (!d->isValidPath(newPath, newPathType))
  599. {
  600. return false;
  601. }
  602. QString newAbsolutePath = QFileInfo(newPath).absoluteFilePath();
  603. d->PathListModel.setData(index, newPath, Qt::DisplayRole);
  604. d->PathListModel.setData(index, newAbsolutePath, AbsolutePathRole);
  605. emit this->pathsChanged(QStringList(newAbsolutePath), QStringList(oldAbsolutePath));
  606. return true;
  607. }
  608. // --------------------------------------------------------------------------
  609. bool ctkPathListWidget::isFile(const QString &path) const
  610. {
  611. Q_D(const ctkPathListWidget);
  612. return d->pathType(path) == ctkPathListWidgetPrivate::File;
  613. }
  614. // --------------------------------------------------------------------------
  615. bool ctkPathListWidget::isDirectory(const QString &path) const
  616. {
  617. Q_D(const ctkPathListWidget);
  618. return d->pathType(path) == ctkPathListWidgetPrivate::Directory;
  619. }
  620. // --------------------------------------------------------------------------
  621. void ctkPathListWidget::setMode(ctkPathListWidget::Mode mode)
  622. {
  623. Q_D(ctkPathListWidget);
  624. d->Mode = mode;
  625. }
  626. // --------------------------------------------------------------------------
  627. bool ctkPathListWidget::contains(const QString& path)const
  628. {
  629. Q_D(const ctkPathListWidget);
  630. QString absolutePath = QFileInfo(path).absoluteFilePath();
  631. QModelIndexList foundIndexes = d->PathListModel.match(
  632. d->PathListModel.index(0, 0), ctkPathListWidget::AbsolutePathRole,
  633. QVariant(absolutePath), 1, Qt::MatchExactly);
  634. Q_ASSERT(foundIndexes.size() < 2);
  635. return (foundIndexes.size() != 0);
  636. }
  637. // --------------------------------------------------------------------------
  638. bool ctkPathListWidget::addPath(const QString& path)
  639. {
  640. return !this->addPaths(QStringList() << path).empty();
  641. }
  642. // --------------------------------------------------------------------------
  643. QStringList ctkPathListWidget::addPaths(const QStringList &paths)
  644. {
  645. Q_D(ctkPathListWidget);
  646. QStringList addedPaths;
  647. foreach(const QString& path, paths)
  648. {
  649. if (d->addPath(path))
  650. {
  651. addedPaths << QFileInfo(path).absoluteFilePath();
  652. }
  653. }
  654. if (!addedPaths.empty())
  655. {
  656. emit this->pathsChanged(addedPaths, QStringList());
  657. }
  658. return addedPaths;
  659. }
  660. // --------------------------------------------------------------------------
  661. bool ctkPathListWidget::removePath(const QString& path)
  662. {
  663. return !this->removePaths(QStringList() << path).empty();
  664. }
  665. // --------------------------------------------------------------------------
  666. QStringList ctkPathListWidget::removePaths(const QStringList &paths)
  667. {
  668. Q_D(ctkPathListWidget);
  669. QStringList removedPaths;
  670. foreach(const QString& path, paths)
  671. {
  672. if (d->removePath(path))
  673. {
  674. removedPaths << QFileInfo(path).absoluteFilePath();
  675. }
  676. }
  677. if (!removedPaths.empty())
  678. {
  679. emit this->pathsChanged(QStringList(), removedPaths);
  680. }
  681. return removedPaths;
  682. }
  683. // --------------------------------------------------------------------------
  684. void ctkPathListWidget::removeSelectedPaths()
  685. {
  686. Q_D(ctkPathListWidget);
  687. QModelIndexList selectedIndexes = this->selectionModel()->selectedRows();
  688. if (selectedIndexes.empty()) return;
  689. QStringList removedPaths;
  690. while(selectedIndexes.count() > 0)
  691. {
  692. removedPaths << d->PathListModel.data(selectedIndexes.front(), AbsolutePathRole).toString();
  693. d->PathListModel.removeRow(selectedIndexes.front().row());
  694. selectedIndexes = this->selectionModel()->selectedRows();
  695. }
  696. emit this->pathsChanged(QStringList(), removedPaths);
  697. }
  698. // --------------------------------------------------------------------------
  699. void ctkPathListWidget::clear()
  700. {
  701. Q_D(ctkPathListWidget);
  702. if (d->PathListModel.rowCount() == 0) return;
  703. QStringList removedPaths = this->paths(true);
  704. d->PathListModel.clear();
  705. emit this->pathsChanged(QStringList(), removedPaths);
  706. }
  707. // --------------------------------------------------------------------------
  708. void ctkPathListWidget::setPaths(const QStringList& paths)
  709. {
  710. Q_D(ctkPathListWidget);
  711. QStringList addedPaths;
  712. QStringList removedPaths;
  713. QStringList absolutePaths;
  714. foreach(const QString& path, paths)
  715. {
  716. absolutePaths << QFileInfo(path).absoluteFilePath();
  717. }
  718. foreach(const QString& path, this->paths(true))
  719. {
  720. if (!absolutePaths.contains(path) && d->removePath(path))
  721. {
  722. removedPaths << path;
  723. }
  724. }
  725. for(int i = 0; i < paths.count(); ++i)
  726. {
  727. if (!this->contains(paths[i]) && d->addPath(paths[i]))
  728. {
  729. addedPaths << absolutePaths[i];
  730. }
  731. }
  732. if (addedPaths.isEmpty() && removedPaths.empty())
  733. {
  734. return;
  735. }
  736. emit this->pathsChanged(addedPaths, removedPaths);
  737. }
  738. // --------------------------------------------------------------------------
  739. void ctkPathListWidget::setModel(QAbstractItemModel*)
  740. {
  741. Q_ASSERT(!"ctkPathListWidget::setModel() - Changing the model of the ctkPathListWidget is not allowed.");
  742. }