PageRenderTime 78ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/guitone-1.0rc5/src/model/InventoryItem.cpp

#
C++ | 557 lines | 460 code | 69 blank | 28 comment | 158 complexity | ca3eab2e97be174e2772674761dc5610 MD5 | raw file
Possible License(s): GPL-3.0
  1. /***************************************************************************
  2. * Copyright (C) 2006 by Thomas Keller *
  3. * me@thomaskeller.biz *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation, either version 3 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  10. * This program is distributed in the hope that it will be useful, *
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13. * GNU General Public License for more details. *
  14. * *
  15. * You should have received a copy of the GNU General Public License *
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>. *
  17. ***************************************************************************/
  18. #include "InventoryItem.h"
  19. #include <QStringList>
  20. #include <QFont>
  21. ModelItem::ModelItem(const QString & l) : parentItem(0), label(l)
  22. {}
  23. ModelItem::ModelItem(const ModelItem * other)
  24. {
  25. parentItem = other->parent();
  26. children = other->getChildren();
  27. label = other->getLabel();
  28. }
  29. ModelItem::~ModelItem()
  30. {
  31. deleteAllChildren();
  32. }
  33. void ModelItem::setLabel(const QString & l)
  34. {
  35. label = l;
  36. }
  37. QString ModelItem::getLabel() const
  38. {
  39. return label;
  40. }
  41. void ModelItem::deleteAllChildren()
  42. {
  43. qDeleteAll(children);
  44. children.clear();
  45. }
  46. void ModelItem::appendChild(ModelItem * child)
  47. {
  48. child->setParent(this);
  49. children.append(child);
  50. }
  51. void ModelItem::removeChild(ModelItem * child)
  52. {
  53. int idx = children.indexOf(child);
  54. if (idx == -1) return;
  55. children.removeAt(idx);
  56. }
  57. void ModelItem::setChildren(QList<ModelItem *> items)
  58. {
  59. deleteAllChildren();
  60. foreach (ModelItem * item, items)
  61. {
  62. appendChild(item);
  63. }
  64. }
  65. QList<ModelItem *> ModelItem::getChildren() const
  66. {
  67. return children;
  68. }
  69. void ModelItem::setParent(ModelItem * p)
  70. {
  71. parentItem = p;
  72. }
  73. ModelItem * ModelItem::parent() const
  74. {
  75. return parentItem;
  76. }
  77. ModelItem * ModelItem::child(int row) const
  78. {
  79. if (row < children.size())
  80. {
  81. return children.value(row);
  82. }
  83. return 0;
  84. }
  85. int ModelItem::childCount() const
  86. {
  87. return children.count();
  88. }
  89. int ModelItem::row() const
  90. {
  91. if (parentItem)
  92. {
  93. return parentItem->children.indexOf(const_cast<ModelItem *>(this));
  94. }
  95. return 0;
  96. }
  97. QVariant ModelItem::data(int column, int role) const
  98. {
  99. if (role == Qt::DisplayRole)
  100. {
  101. // return column headers for root item
  102. if (parentItem == this)
  103. {
  104. switch (column)
  105. {
  106. case 0: return QVariant(QString(tr("File")));
  107. case 1: return QVariant(QString(tr("Status")));
  108. default: return QVariant();
  109. }
  110. }
  111. switch (column)
  112. {
  113. case 0: return QVariant(label);
  114. default: return QVariant();
  115. }
  116. }
  117. if (role == Qt::DecorationRole && column == 0)
  118. {
  119. IconProvider * provider = IconProvider::singleton();
  120. return provider->getIcon(this);
  121. }
  122. return QVariant();
  123. }
  124. bool ModelItem::isRoot() const
  125. {
  126. return this == parentItem;
  127. }
  128. const int InventoryItem::RenameSource = 1;
  129. const int InventoryItem::RenameTarget = 2;
  130. const int InventoryItem::Added = 4;
  131. const int InventoryItem::Dropped = 8;
  132. const int InventoryItem::Missing = 16;
  133. const int InventoryItem::Known = 32;
  134. const int InventoryItem::Unknown = 64;
  135. const int InventoryItem::Ignored = 128;
  136. const int InventoryItem::Invalid = 256;
  137. const int InventoryItem::ContentsChanged = 512;
  138. const int InventoryItem::AttributesChanged = 1024;
  139. QString InventoryItem::translateFileType(const FileType & t)
  140. {
  141. switch (t)
  142. {
  143. case File: return tr("File");
  144. case Directory: return tr("Directory");
  145. case None: return tr("None");
  146. default: return "-";
  147. }
  148. }
  149. InventoryItem::InventoryItem(const Stanza & stanza)
  150. : ModelItem(), fs_type(Undefined), old_type(Undefined), new_type(Undefined),
  151. status(0), aboutToBeExpanded(false)
  152. {
  153. foreach (const StanzaEntry & en, stanza)
  154. {
  155. if (en.sym == "path")
  156. {
  157. I(en.vals.size() == 1);
  158. path = en.vals.at(0);
  159. continue;
  160. }
  161. if (en.sym == "old_path")
  162. {
  163. I(en.vals.size() == 1);
  164. old_path = en.vals.at(0);
  165. continue;
  166. }
  167. if (en.sym == "new_path")
  168. {
  169. I(en.vals.size() == 1);
  170. new_path = en.vals.at(0);
  171. continue;
  172. }
  173. if (en.sym == "old_type")
  174. {
  175. I(en.vals.size() == 1);
  176. if (en.vals.at(0) == "file")
  177. old_type = File;
  178. else if (en.vals.at(0) == "directory")
  179. old_type = Directory;
  180. else
  181. I(false);
  182. continue;
  183. }
  184. if (en.sym == "new_type")
  185. {
  186. I(en.vals.size() == 1);
  187. if (en.vals.at(0) == "file")
  188. new_type = File;
  189. else if (en.vals.at(0) == "directory")
  190. new_type = Directory;
  191. else
  192. I(false);
  193. continue;
  194. }
  195. if (en.sym == "fs_type")
  196. {
  197. I(en.vals.size() == 1);
  198. if (en.vals.at(0) == "file")
  199. fs_type = File;
  200. else if (en.vals.at(0) == "directory")
  201. fs_type = Directory;
  202. else if (en.vals.at(0) == "none")
  203. fs_type = None;
  204. else
  205. I(false);
  206. continue;
  207. }
  208. if (en.sym == "status")
  209. {
  210. I(en.vals.size() > 0);
  211. foreach (const QString & val, en.vals)
  212. {
  213. if (val == "rename_source")
  214. status |= RenameSource;
  215. else if (val == "rename_target")
  216. status |= RenameTarget;
  217. else if (val == "added")
  218. status |= Added;
  219. else if (val == "dropped")
  220. status |= Dropped;
  221. else if (val == "known")
  222. status |= Known;
  223. else if (val == "unknown")
  224. status |= Unknown;
  225. else if (val == "ignored")
  226. status |= Ignored;
  227. else if (val == "missing")
  228. status |= Missing;
  229. else if (val == "invalid")
  230. status |= Invalid;
  231. else
  232. I(false);
  233. }
  234. continue;
  235. }
  236. if (en.sym == "changes")
  237. {
  238. I(en.vals.size() > 0 && en.vals.size() < 3);
  239. foreach (const QString & val, en.vals)
  240. {
  241. if (val == "content")
  242. status |= ContentsChanged;
  243. else if (val == "attrs")
  244. status |= AttributesChanged;
  245. else
  246. I(false);
  247. }
  248. continue;
  249. }
  250. if (en.sym == "birth")
  251. {
  252. I(en.vals.size() == 1);
  253. birthRev = en.vals.at(0);
  254. }
  255. }
  256. // we should have received at least a path, status and fs_type entry
  257. I(!path.isNull());
  258. I(status > 0);
  259. I(fs_type > 0);
  260. }
  261. InventoryItem::InventoryItem(const InventoryItem * other) : ModelItem(other)
  262. {
  263. path = other->getPath();
  264. old_path = other->getRenameSource();
  265. new_path = other->getRenameTarget();
  266. fs_type = other->getFSType();
  267. old_type = other->getOldType();
  268. new_type = other->getNewType();
  269. birthRev = other->getBirthRevision();
  270. status = other->getStatus();
  271. }
  272. QVariant InventoryItem::data(int column, int role) const
  273. {
  274. if (role == Qt::DisplayRole && parentItem != this)
  275. {
  276. switch (column)
  277. {
  278. case 0: return QVariant(getLabel());
  279. case 1: return QVariant(getStatusString());
  280. default: return QVariant();
  281. }
  282. }
  283. else if (role == Qt::FontRole && column == 0)
  284. {
  285. QFont font;
  286. font.setBold(false);
  287. if (hasChangedRecursive())
  288. {
  289. font.setBold(true);
  290. }
  291. return QVariant(font);
  292. }
  293. else if (role == Qt::ForegroundRole)
  294. {
  295. if (hasStatus(Invalid))
  296. {
  297. return QVariant(Qt::red);
  298. }
  299. return QVariant();
  300. }
  301. else if (role == Qt::EditRole && column == 0)
  302. {
  303. return QVariant(getFilename());
  304. }
  305. return ModelItem::data(column, role);
  306. }
  307. QString InventoryItem::getLabel() const
  308. {
  309. if (!label.isEmpty()) return label;
  310. return getFilename();
  311. }
  312. QString InventoryItem::getFilename() const
  313. {
  314. int pos = path.lastIndexOf('/');
  315. return pos == -1 ? path : path.right(path.length() - pos - 1);
  316. }
  317. QString InventoryItem::getRelativePath(const QString & part) const
  318. {
  319. int partLen = part.length();
  320. I(path.left(partLen).compare(part) == 0);
  321. return path.right(path.length() - partLen);
  322. }
  323. QString InventoryItem::getBaseDirectory() const
  324. {
  325. int pos = path.lastIndexOf('/');
  326. return pos == -1 ? QString("") : path.left(pos);
  327. }
  328. bool InventoryItem::hasStatus(int statusBits) const
  329. {
  330. return (status & statusBits) == statusBits;
  331. }
  332. bool InventoryItem::hasNotStatus(int statusBits) const
  333. {
  334. return (status & statusBits) == 0;
  335. }
  336. void InventoryItem::setStatusRecursive(int statusBits)
  337. {
  338. status = statusBits;
  339. if (!isDirectory())
  340. {
  341. return;
  342. }
  343. for (int i=0,s=children.size(); i<s; i++)
  344. {
  345. InventoryItem * item = qobject_cast<InventoryItem *>(children.at(i));
  346. // skip everything other than InventoryItems
  347. if (!item) continue;
  348. item->setStatusRecursive(statusBits);
  349. }
  350. }
  351. int InventoryItem::getStatusRecursive() const
  352. {
  353. int overallStatus = status;
  354. if (!isDirectory())
  355. {
  356. return overallStatus;
  357. }
  358. for (int i=0,s=children.size(); i<s; i++)
  359. {
  360. InventoryItem * item = qobject_cast<InventoryItem *>(children.at(i));
  361. // skip everything other than InventoryItems
  362. if (!item) continue;
  363. overallStatus |= item->getStatusRecursive();
  364. }
  365. return overallStatus;
  366. }
  367. bool InventoryItem::isNewNode() const
  368. {
  369. return hasStatus(Known) || hasStatus(Missing)
  370. || hasStatus(Added) || hasStatus(RenameTarget);
  371. }
  372. bool InventoryItem::isOldNode() const
  373. {
  374. return hasStatus(Dropped) || hasStatus(RenameSource);
  375. }
  376. bool InventoryItem::isTracked() const
  377. {
  378. return hasNotStatus(Ignored | Unknown);
  379. }
  380. bool InventoryItem::hasChanged() const
  381. {
  382. return hasStatus(Added) || hasStatus(Dropped)
  383. || hasStatus(RenameSource) || hasStatus(RenameTarget)
  384. || hasStatus(Invalid) || hasStatus(AttributesChanged)
  385. || hasStatus(ContentsChanged);
  386. }
  387. bool InventoryItem::hasChangedRecursive() const
  388. {
  389. int state = getStatusRecursive();
  390. return
  391. (state & Added) == Added ||
  392. (state & Dropped) == Dropped ||
  393. (state & RenameSource) == RenameSource ||
  394. (state & RenameTarget) == RenameTarget ||
  395. (state & Invalid) == Invalid ||
  396. (state & AttributesChanged) == AttributesChanged ||
  397. (state & ContentsChanged) == ContentsChanged;
  398. }
  399. QString InventoryItem::getStatusString() const
  400. {
  401. QStringList list;
  402. // the patch states
  403. if (this->hasStatus(InventoryItem::ContentsChanged))
  404. {
  405. list.append(tr("Contents modified"));
  406. }
  407. if (this->hasStatus(InventoryItem::AttributesChanged))
  408. {
  409. list.append(tr("Attributes modified"));
  410. }
  411. // the possible old node states
  412. if (this->hasStatus(InventoryItem::RenameSource))
  413. {
  414. list.append(tr("Rename Source"));
  415. }
  416. if (this->hasStatus(InventoryItem::Dropped))
  417. {
  418. list.append(tr("Dropped"));
  419. }
  420. // the possible new states
  421. if (this->hasStatus(InventoryItem::RenameTarget))
  422. {
  423. list.append(tr("Rename Target"));
  424. }
  425. if (this->hasStatus(InventoryItem::Added))
  426. {
  427. list.append(tr("Added"));
  428. }
  429. // the file states
  430. if (this->hasStatus(InventoryItem::Missing))
  431. {
  432. list.append(tr("Missing"));
  433. }
  434. if (this->hasStatus(InventoryItem::Known))
  435. {
  436. list.append(tr("Known"));
  437. }
  438. if (this->hasStatus(InventoryItem::Unknown))
  439. {
  440. list.append(tr("Unknown"));
  441. }
  442. if (this->hasStatus(InventoryItem::Ignored))
  443. {
  444. list.append(tr("Ignored"));
  445. }
  446. // a state which occurs if the node's file type has been
  447. // mangled (f.e. node is recorded as file, but exists in fs as directory)
  448. if (this->hasStatus(InventoryItem::Invalid))
  449. {
  450. list.append(tr("Invalid"));
  451. }
  452. return list.join(", ");
  453. }
  454. bool InventoryItem::isExpanded(int level) const
  455. {
  456. I(level >= 0);
  457. if (!isDirectory())
  458. return true;
  459. if (childCount() == 0)
  460. return false;
  461. if (level > 0)
  462. {
  463. foreach (ModelItem * child, children)
  464. {
  465. InventoryItem * invitem = dynamic_cast<InventoryItem *>(child);
  466. if (!invitem)
  467. continue;
  468. if (!invitem->isExpanded(level - 1))
  469. return false;
  470. }
  471. }
  472. return true;
  473. }
  474. bool InventoryItem::isAboutToBeExpanded() const
  475. {
  476. return aboutToBeExpanded;
  477. }
  478. void InventoryItem::setAboutToBeExpanded()
  479. {
  480. aboutToBeExpanded = true;
  481. // set the dirty status for all current descendants as well
  482. foreach (ModelItem * child, children)
  483. {
  484. InventoryItem * invitem = dynamic_cast<InventoryItem *>(child);
  485. if (!invitem) continue;
  486. invitem->setAboutToBeExpanded();
  487. }
  488. }