folderwizard.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. * Copyright (C) by Duncan Mac-Vicar P. <duncan@kde.org>
  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, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  12. * for more details.
  13. */
  14. #include "mirall/folderwizard.h"
  15. #include "mirall/folderman.h"
  16. #include "mirall/mirallconfigfile.h"
  17. #include "mirall/theme.h"
  18. #include "mirall/networkjobs.h"
  19. #include "mirall/account.h"
  20. #include <QDebug>
  21. #include <QDesktopServices>
  22. #include <QDir>
  23. #include <QFileDialog>
  24. #include <QFileInfo>
  25. #include <QFileIconProvider>
  26. #include <QInputDialog>
  27. #include <QUrl>
  28. #include <QValidator>
  29. #include <QWizardPage>
  30. #include <QTreeWidget>
  31. #include <stdlib.h>
  32. namespace Mirall
  33. {
  34. FolderWizardSourcePage::FolderWizardSourcePage()
  35. : QWizardPage()
  36. {
  37. _ui.setupUi(this);
  38. registerField(QLatin1String("sourceFolder*"), _ui.localFolderLineEdit);
  39. QString defaultPath = QString::fromLatin1( "%1/%2").arg( QDir::homePath() ).arg(Theme::instance()->appName() );
  40. _ui.localFolderLineEdit->setText( QDir::toNativeSeparators( defaultPath ) );
  41. registerField(QLatin1String("alias*"), _ui.aliasLineEdit);
  42. _ui.aliasLineEdit->setText( Theme::instance()->appNameGUI() );
  43. _ui.warnLabel->hide();
  44. }
  45. FolderWizardSourcePage::~FolderWizardSourcePage()
  46. {
  47. }
  48. void FolderWizardSourcePage::initializePage()
  49. {
  50. _ui.warnLabel->hide();
  51. }
  52. void FolderWizardSourcePage::cleanupPage()
  53. {
  54. _ui.warnLabel->hide();
  55. }
  56. bool FolderWizardSourcePage::isComplete() const
  57. {
  58. QFileInfo selFile( QDir::fromNativeSeparators(_ui.localFolderLineEdit->text()) );
  59. QString userInput = selFile.canonicalFilePath();
  60. QString warnString;
  61. bool isOk = selFile.isDir();
  62. if( !isOk ) {
  63. warnString = tr("No local folder selected!");
  64. }
  65. if (isOk && !selFile.isWritable()) {
  66. isOk = false;
  67. warnString += tr("You have no permission to write to the selected folder!");
  68. }
  69. // check if the local directory isn't used yet in another ownCloud sync
  70. Folder::Map map = _folderMap;
  71. if( isOk ) {
  72. Folder::Map::const_iterator i = map.constBegin();
  73. while( isOk && i != map.constEnd() ) {
  74. Folder *f = static_cast<Folder*>(i.value());
  75. QString folderDir = QDir( f->path() ).canonicalPath();
  76. if( folderDir.isEmpty() )
  77. {
  78. isOk = true;
  79. qDebug() << "Absolute path for folder: " << f->path() << " doesn't exist. Skipping.";
  80. i++;
  81. continue;
  82. }
  83. if( ! folderDir.endsWith(QLatin1Char('/')) ) folderDir.append(QLatin1Char('/'));
  84. qDebug() << "Checking local path: " << folderDir << " <-> " << userInput;
  85. if( QFileInfo( f->path() ) == userInput ) {
  86. isOk = false;
  87. warnString.append( tr("The local path %1 is already an upload folder.<br/>Please pick another one!")
  88. .arg(QDir::toNativeSeparators(userInput)) );
  89. }
  90. if( isOk && folderDir.startsWith( userInput )) {
  91. qDebug() << "A already configured folder is child of the current selected";
  92. warnString.append( tr("An already configured folder is contained in the current entry."));
  93. isOk = false;
  94. }
  95. if( isOk && userInput.startsWith( folderDir ) ) {
  96. qDebug() << "An already configured folder is parent of the current selected";
  97. warnString.append( tr("An already configured folder contains the currently entered directory."));
  98. isOk = false;
  99. }
  100. i++;
  101. }
  102. }
  103. // check if the alias is unique.
  104. QString alias = _ui.aliasLineEdit->text();
  105. if( alias.isEmpty() ) {
  106. warnString.append( tr("The alias can not be empty. Please provide a descriptive alias word.") );
  107. isOk = false;
  108. }
  109. Folder::Map::const_iterator i = map.constBegin();
  110. bool goon = true;
  111. while( goon && i != map.constEnd() ) {
  112. Folder *f = i.value();
  113. qDebug() << "Checking local alias: " << f->alias();
  114. if( f ) {
  115. if( f->alias() == alias ) {
  116. warnString.append( tr("<br/>The alias <i>%1</i> is already in use. Please pick another alias.").arg(alias) );
  117. isOk = false;
  118. goon = false;
  119. }
  120. }
  121. i++;
  122. }
  123. if( isOk ) {
  124. _ui.warnLabel->hide();
  125. _ui.warnLabel->setText( QString::null );
  126. } else {
  127. _ui.warnLabel->show();
  128. _ui.warnLabel->setText( warnString );
  129. }
  130. return isOk;
  131. }
  132. void FolderWizardSourcePage::on_localFolderChooseBtn_clicked()
  133. {
  134. QString dir = QFileDialog::getExistingDirectory(this,
  135. tr("Select the source folder"),
  136. QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
  137. if (!dir.isEmpty()) {
  138. _ui.localFolderLineEdit->setText(QDir::toNativeSeparators(dir));
  139. }
  140. }
  141. void FolderWizardSourcePage::on_localFolderLineEdit_textChanged()
  142. {
  143. emit completeChanged();
  144. }
  145. // =================================================================================
  146. FolderWizardTargetPage::FolderWizardTargetPage()
  147. : _warnWasVisible(false)
  148. {
  149. _ui.setupUi(this);
  150. _ui.warnFrame->hide();
  151. connect(_ui.addFolderButton, SIGNAL(clicked()), SLOT(slotAddRemoteFolder()));
  152. connect(_ui.refreshButton, SIGNAL(clicked()), SLOT(slotRefreshFolders()));
  153. connect(_ui.folderTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), SIGNAL(completeChanged()));
  154. connect(_ui.folderTreeWidget, SIGNAL(itemActivated(QTreeWidgetItem*,int)), SIGNAL(completeChanged()));
  155. connect(_ui.folderTreeWidget, SIGNAL(itemExpanded(QTreeWidgetItem*)), SLOT(slotItemExpanded(QTreeWidgetItem*)));
  156. }
  157. void FolderWizardTargetPage::slotAddRemoteFolder()
  158. {
  159. QTreeWidgetItem *current = _ui.folderTreeWidget->currentItem();
  160. QString parent('/');
  161. if (current) {
  162. parent = current->data(0, Qt::UserRole).toString();
  163. }
  164. QInputDialog *dlg = new QInputDialog(this);
  165. dlg->setWindowTitle(tr("Add Remote Folder"));
  166. dlg->setLabelText(tr("Enter the name of the new folder:"));
  167. dlg->setTextValue(parent);
  168. dlg->open(this, SLOT(slotCreateRemoteFolder(QString)));
  169. dlg->setAttribute(Qt::WA_DeleteOnClose);
  170. }
  171. void FolderWizardTargetPage::slotCreateRemoteFolder(const QString &folder)
  172. {
  173. if( folder.isEmpty() ) return;
  174. MkColJob *job = new MkColJob(AccountManager::instance()->account(), folder, this);
  175. /* check the owncloud configuration file and query the ownCloud */
  176. connect(job, SIGNAL(finished(QNetworkReply::NetworkError)),
  177. SLOT(slotCreateRemoteFolderFinished(QNetworkReply::NetworkError)));
  178. connect(job, SIGNAL(networkError(QNetworkReply*)), SLOT(slotHandleNetworkError(QNetworkReply*)));
  179. }
  180. void FolderWizardTargetPage::slotCreateRemoteFolderFinished(QNetworkReply::NetworkError error)
  181. {
  182. if (error == QNetworkReply::NoError) {
  183. qDebug() << "** webdav mkdir request finished";
  184. showWarn(tr("Folder was successfully created on %1.").arg(Theme::instance()->appNameGUI()));
  185. slotRefreshFolders();
  186. }
  187. }
  188. void FolderWizardTargetPage::slotHandleNetworkError(QNetworkReply *reply)
  189. {
  190. qDebug() << "** webdav mkdir request failed:" << reply->error();
  191. showWarn(tr("Failed to create the folder on %1.<br/>Please check manually.")
  192. .arg(Theme::instance()->appNameGUI()));
  193. }
  194. static QTreeWidgetItem* findFirstChild(QTreeWidgetItem *parent, const QString& text)
  195. {
  196. for (int i = 0; i < parent->childCount(); ++i) {
  197. QTreeWidgetItem *child = parent->child(i);
  198. if (child->text(0) == text) {
  199. return child;
  200. }
  201. }
  202. return 0;
  203. }
  204. void FolderWizardTargetPage::recursiveInsert(QTreeWidgetItem *parent, QStringList pathTrail, QString path)
  205. {
  206. QFileIconProvider prov;
  207. QIcon folderIcon = prov.icon(QFileIconProvider::Folder);
  208. if (pathTrail.size() == 0) {
  209. if (path.endsWith('/')) {
  210. path.chop(1);
  211. }
  212. parent->setToolTip(0, path);
  213. parent->setData(0, Qt::UserRole, path);
  214. } else {
  215. QTreeWidgetItem *item = findFirstChild(parent, pathTrail.first());
  216. if (!item) {
  217. item = new QTreeWidgetItem(parent);
  218. item->setIcon(0, folderIcon);
  219. item->setText(0, pathTrail.first());
  220. item->setData(0, Qt::UserRole, pathTrail.first());
  221. item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator);
  222. }
  223. pathTrail.removeFirst();
  224. recursiveInsert(item, pathTrail, path);
  225. }
  226. }
  227. void FolderWizardTargetPage::slotUpdateDirectories(const QStringList &list)
  228. {
  229. QString webdavFolder = QUrl(AccountManager::instance()->account()->davUrl()).path();
  230. QTreeWidgetItem *root = _ui.folderTreeWidget->topLevelItem(0);
  231. if (!root) {
  232. root = new QTreeWidgetItem(_ui.folderTreeWidget);
  233. root->setText(0, Theme::instance()->appNameGUI());
  234. root->setIcon(0, Theme::instance()->applicationIcon());
  235. root->setToolTip(0, tr("Choose this to sync the entire account"));
  236. root->setData(0, Qt::UserRole, "/");
  237. }
  238. foreach (QString path, list) {
  239. path.remove(webdavFolder);
  240. QStringList paths = path.split('/');
  241. if (paths.last().isEmpty()) paths.removeLast();
  242. recursiveInsert(root, paths, path);
  243. }
  244. root->setExpanded(true);
  245. }
  246. void FolderWizardTargetPage::slotRefreshFolders()
  247. {
  248. LsColJob *job = new LsColJob(AccountManager::instance()->account(), "/", this);
  249. connect(job, SIGNAL(directoryListing(QStringList)),
  250. SLOT(slotUpdateDirectories(QStringList)));
  251. _ui.folderTreeWidget->clear();
  252. }
  253. void FolderWizardTargetPage::slotItemExpanded(QTreeWidgetItem *item)
  254. {
  255. QString dir = item->data(0, Qt::UserRole).toString();
  256. LsColJob *job = new LsColJob(AccountManager::instance()->account(), dir, this);
  257. connect(job, SIGNAL(directoryListing(QStringList)),
  258. SLOT(slotUpdateDirectories(QStringList)));
  259. }
  260. FolderWizardTargetPage::~FolderWizardTargetPage()
  261. {
  262. }
  263. bool FolderWizardTargetPage::isComplete() const
  264. {
  265. if (!_ui.folderTreeWidget->currentItem())
  266. return false;
  267. QString dir = _ui.folderTreeWidget->currentItem()->data(0, Qt::UserRole).toString();
  268. wizard()->setProperty("targetPath", dir);
  269. Folder::Map map = _folderMap;
  270. Folder::Map::const_iterator i = map.constBegin();
  271. for(i = map.constBegin();i != map.constEnd(); i++ ) {
  272. Folder *f = static_cast<Folder*>(i.value());
  273. QString curDir = f->remotePath();
  274. if (dir == curDir) {
  275. showWarn( tr("This directory is already being synced.") );
  276. return false;
  277. } else if (dir.startsWith(curDir + QLatin1Char('/'))) {
  278. if (dir.isEmpty()) dir = QLatin1Char('/');
  279. if (curDir.isEmpty()) curDir = QLatin1Char('/');
  280. showWarn( tr("You are already syncing <i>%1</i>, which is a parent folder of <i>%2</i>.").arg(curDir).arg(dir) );
  281. return false;
  282. }
  283. }
  284. if( dir == QLatin1String("/") ) {
  285. showWarn( tr("If you sync the root folder, you can <b>not</b> configure another sync directory."));
  286. return true;
  287. } else {
  288. showWarn();
  289. return true;
  290. }
  291. }
  292. void FolderWizardTargetPage::cleanupPage()
  293. {
  294. showWarn();
  295. }
  296. void FolderWizardTargetPage::initializePage()
  297. {
  298. showWarn();
  299. slotRefreshFolders();
  300. }
  301. void FolderWizardTargetPage::showWarn( const QString& msg ) const
  302. {
  303. if( msg.isEmpty() ) {
  304. _ui.warnFrame->hide();
  305. } else {
  306. _ui.warnFrame->show();
  307. _ui.warnLabel->setText( msg );
  308. }
  309. }
  310. // ====================================================================================
  311. /**
  312. * Folder wizard itself
  313. */
  314. FolderWizard::FolderWizard( QWidget *parent )
  315. : QWizard(parent),
  316. _folderWizardSourcePage(new FolderWizardSourcePage),
  317. _folderWizardTargetPage(0)
  318. {
  319. setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
  320. setPage(Page_Source, _folderWizardSourcePage );
  321. if (!Theme::instance()->singleSyncFolder()) {
  322. _folderWizardTargetPage = new FolderWizardTargetPage();
  323. setPage(Page_Target, _folderWizardTargetPage );
  324. }
  325. setWindowTitle( tr("Add Folder") );
  326. setOptions(QWizard::CancelButtonOnLeft);
  327. setButtonText(QWizard::FinishButton, tr("Add Folder"));
  328. }
  329. FolderWizard::~FolderWizard()
  330. {
  331. }
  332. void FolderWizard::setFolderMap( const Folder::Map& fm)
  333. {
  334. _folderWizardSourcePage->setFolderMap( fm );
  335. _folderWizardTargetPage->setFolderMap( fm );
  336. }
  337. } // end namespace