PageRenderTime 27ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/release/src/router/transmission/qt/make-dialog.cc

https://gitlab.com/envieidoc/advancedtomato2
C++ | 460 lines | 371 code | 59 blank | 30 comment | 34 complexity | 7071b717a85caed9c673893c7f421c29 MD5 | raw file
  1. /*
  2. * This file Copyright (C) 2009-2014 Mnemosyne LLC
  3. *
  4. * It may be used under the GNU Public License v2 or v3 licenses,
  5. * or any future license endorsed by Mnemosyne LLC.
  6. *
  7. * $Id: make-dialog.cc 14225 2014-01-19 01:09:44Z jordan $
  8. */
  9. #include <cassert>
  10. #include <iostream>
  11. #include <QCheckBox>
  12. #include <QDialogButtonBox>
  13. #include <QFileDialog>
  14. #include <QFileIconProvider>
  15. #include <QHBoxLayout>
  16. #include <QLabel>
  17. #include <QLineEdit>
  18. #include <QList>
  19. #include <QMimeData>
  20. #include <QPlainTextEdit>
  21. #include <QProgressBar>
  22. #include <QPushButton>
  23. #include <QRadioButton>
  24. #include <QSize>
  25. #include <QStyle>
  26. #include <QTimer>
  27. #include <QVBoxLayout>
  28. #include <libtransmission/transmission.h>
  29. #include <libtransmission/makemeta.h>
  30. #include <libtransmission/utils.h>
  31. #include "formatter.h"
  32. #include "hig.h"
  33. #include "make-dialog.h"
  34. #include "session.h"
  35. #include "utils.h"
  36. /***
  37. ****
  38. ***/
  39. void
  40. MakeDialog :: onNewDialogDestroyed (QObject * o)
  41. {
  42. Q_UNUSED (o);
  43. myTimer.stop ();
  44. }
  45. void
  46. MakeDialog :: onNewButtonBoxClicked (QAbstractButton * button)
  47. {
  48. switch (myNewButtonBox->standardButton (button))
  49. {
  50. case QDialogButtonBox::Open:
  51. mySession.addNewlyCreatedTorrent (myTarget, QFileInfo(QString::fromUtf8(myBuilder->top)).dir().path());
  52. break;
  53. case QDialogButtonBox::Abort:
  54. myBuilder->abortFlag = true;
  55. break;
  56. default: // QDialogButtonBox::Ok:
  57. break;
  58. }
  59. myNewDialog->deleteLater ();
  60. }
  61. void
  62. MakeDialog :: onProgress ()
  63. {
  64. // progress bar
  65. const tr_metainfo_builder * b = myBuilder;
  66. const double denom = b->pieceCount ? b->pieceCount : 1;
  67. myNewProgress->setValue ((int) ((100.0 * b->pieceIndex) / denom));
  68. // progress label
  69. const QString top = QString::fromLocal8Bit (myBuilder->top);
  70. const QString base (QFileInfo(top).completeBaseName());
  71. QString str;
  72. if (!b->isDone)
  73. str = tr ("Creating \"%1\"").arg (base);
  74. else if (b->result == TR_MAKEMETA_OK)
  75. str = tr ("Created \"%1\"!").arg (base);
  76. else if (b->result == TR_MAKEMETA_URL)
  77. str = tr ("Error: invalid announce URL \"%1\"").arg (QString::fromLocal8Bit (b->errfile));
  78. else if (b->result == TR_MAKEMETA_CANCELLED)
  79. str = tr ("Cancelled");
  80. else if (b->result == TR_MAKEMETA_IO_READ)
  81. str = tr ("Error reading \"%1\": %2").arg (QString::fromLocal8Bit(b->errfile)).arg (QString::fromLocal8Bit(strerror(b->my_errno)));
  82. else if (b->result == TR_MAKEMETA_IO_WRITE)
  83. str = tr ("Error writing \"%1\": %2").arg (QString::fromLocal8Bit(b->errfile)).arg (QString::fromLocal8Bit(strerror(b->my_errno)));
  84. myNewLabel->setText (str);
  85. // buttons
  86. (myNewButtonBox->button(QDialogButtonBox::Abort))->setEnabled (!b->isDone);
  87. (myNewButtonBox->button(QDialogButtonBox::Ok))->setEnabled (b->isDone);
  88. (myNewButtonBox->button(QDialogButtonBox::Open))->setEnabled (b->isDone && !b->result);
  89. }
  90. void
  91. MakeDialog :: makeTorrent ()
  92. {
  93. if (!myBuilder)
  94. return;
  95. // get the tiers
  96. int tier = 0;
  97. QVector<tr_tracker_info> trackers;
  98. foreach (QString line, myTrackerEdit->toPlainText().split("\n"))
  99. {
  100. line = line.trimmed ();
  101. if (line.isEmpty ())
  102. {
  103. ++tier;
  104. }
  105. else
  106. {
  107. tr_tracker_info tmp;
  108. tmp.announce = tr_strdup (line.toUtf8().constData ());
  109. tmp.tier = tier;
  110. trackers.append (tmp);
  111. }
  112. }
  113. // pop up the dialog
  114. QDialog * dialog = new QDialog (this);
  115. dialog->setWindowTitle (tr ("New Torrent"));
  116. myNewDialog = dialog;
  117. QVBoxLayout * top = new QVBoxLayout (dialog);
  118. top->addWidget( (myNewLabel = new QLabel));
  119. top->addWidget( (myNewProgress = new QProgressBar));
  120. QDialogButtonBox * buttons = new QDialogButtonBox (QDialogButtonBox::Ok
  121. | QDialogButtonBox::Open
  122. | QDialogButtonBox::Abort);
  123. myNewButtonBox = buttons;
  124. connect (buttons, SIGNAL(clicked(QAbstractButton*)),
  125. this, SLOT(onNewButtonBoxClicked(QAbstractButton*)));
  126. top->addWidget (buttons);
  127. onProgress ();
  128. dialog->show ();
  129. connect (dialog, SIGNAL(destroyed(QObject*)),
  130. this, SLOT(onNewDialogDestroyed(QObject*)));
  131. myTimer.start (100);
  132. // the file to create
  133. const QString path = QString::fromUtf8 (myBuilder->top);
  134. const QString torrentName = QFileInfo(path).completeBaseName() + ".torrent";
  135. myTarget = QDir (myDestination).filePath (torrentName);
  136. // comment
  137. QString comment;
  138. if (myCommentCheck->isChecked())
  139. comment = myCommentEdit->text();
  140. // start making the torrent
  141. tr_makeMetaInfo (myBuilder,
  142. myTarget.toUtf8().constData(),
  143. (trackers.isEmpty() ? NULL : trackers.data()),
  144. trackers.size(),
  145. (comment.isEmpty() ? NULL : comment.toUtf8().constData()),
  146. myPrivateCheck->isChecked());
  147. }
  148. /***
  149. ****
  150. ***/
  151. void
  152. MakeDialog :: onFileClicked ()
  153. {
  154. QFileDialog * d = new QFileDialog (this, tr ("Select File"));
  155. d->setFileMode (QFileDialog::ExistingFile);
  156. d->setAttribute (Qt::WA_DeleteOnClose);
  157. connect (d, SIGNAL(filesSelected(const QStringList&)),
  158. this, SLOT(onFileSelected(const QStringList&)));
  159. d->show ();
  160. }
  161. void
  162. MakeDialog :: onFileSelected (const QStringList& list)
  163. {
  164. if (!list.empty ())
  165. onFileSelected (list.front ());
  166. }
  167. void
  168. MakeDialog :: onFileSelected (const QString& filename)
  169. {
  170. myFile = Utils::removeTrailingDirSeparator (filename);
  171. myFileButton->setText (QFileInfo(myFile).fileName());
  172. onSourceChanged ();
  173. }
  174. void
  175. MakeDialog :: onFolderClicked ()
  176. {
  177. QFileDialog * d = new QFileDialog (this, tr ("Select Folder"));
  178. d->setFileMode (QFileDialog::Directory);
  179. d->setOption (QFileDialog::ShowDirsOnly);
  180. d->setAttribute (Qt::WA_DeleteOnClose);
  181. connect (d, SIGNAL(filesSelected(const QStringList&)),
  182. this, SLOT(onFolderSelected(const QStringList&)));
  183. d->show ();
  184. }
  185. void
  186. MakeDialog :: onFolderSelected (const QStringList& list)
  187. {
  188. if (!list.empty ())
  189. onFolderSelected (list.front ());
  190. }
  191. void
  192. MakeDialog :: onFolderSelected (const QString& filename)
  193. {
  194. myFolder = Utils::removeTrailingDirSeparator (filename);
  195. myFolderButton->setText (QFileInfo(myFolder).fileName());
  196. onSourceChanged ();
  197. }
  198. void
  199. MakeDialog :: onDestinationClicked ()
  200. {
  201. QFileDialog * d = new QFileDialog (this, tr ("Select Folder"));
  202. d->setFileMode (QFileDialog::Directory);
  203. d->setOption (QFileDialog::ShowDirsOnly);
  204. d->setAttribute (Qt::WA_DeleteOnClose);
  205. connect (d, SIGNAL(filesSelected(const QStringList&)),
  206. this, SLOT(onDestinationSelected(const QStringList&)));
  207. d->show ();
  208. }
  209. void
  210. MakeDialog :: onDestinationSelected (const QStringList& list)
  211. {
  212. if (!list.empty ())
  213. onDestinationSelected (list.front());
  214. }
  215. void
  216. MakeDialog :: onDestinationSelected (const QString& filename)
  217. {
  218. myDestination = Utils::removeTrailingDirSeparator (filename);
  219. myDestinationButton->setText (QFileInfo(myDestination).fileName());
  220. }
  221. void
  222. MakeDialog :: enableBuddyWhenChecked (QRadioButton * box, QWidget * buddy)
  223. {
  224. connect (box, SIGNAL(toggled(bool)), buddy, SLOT(setEnabled(bool)));
  225. buddy->setEnabled (box->isChecked ());
  226. }
  227. void
  228. MakeDialog :: enableBuddyWhenChecked (QCheckBox * box, QWidget * buddy)
  229. {
  230. connect (box, SIGNAL(toggled(bool)), buddy, SLOT(setEnabled(bool)));
  231. buddy->setEnabled (box->isChecked ());
  232. }
  233. QString
  234. MakeDialog :: getSource () const
  235. {
  236. return myFileRadio->isChecked () ? myFile : myFolder;
  237. }
  238. void
  239. MakeDialog :: onButtonBoxClicked (QAbstractButton * button)
  240. {
  241. switch (myButtonBox->standardButton (button))
  242. {
  243. case QDialogButtonBox::Ok:
  244. makeTorrent ();
  245. break;
  246. default: // QDialogButtonBox::Close:
  247. deleteLater ();
  248. break;
  249. }
  250. }
  251. /***
  252. ****
  253. ***/
  254. void
  255. MakeDialog :: onSourceChanged ()
  256. {
  257. if (myBuilder)
  258. {
  259. tr_metaInfoBuilderFree (myBuilder);
  260. myBuilder = 0;
  261. }
  262. const QString filename = getSource ();
  263. if (!filename.isEmpty ())
  264. myBuilder = tr_metaInfoBuilderCreate (filename.toUtf8().constData());
  265. QString text;
  266. if (!myBuilder)
  267. {
  268. text = tr ("<i>No source selected<i>");
  269. }
  270. else
  271. {
  272. QString files = tr ("%Ln File(s)", 0, myBuilder->fileCount);
  273. QString pieces = tr ("%Ln Piece(s)", 0, myBuilder->pieceCount);
  274. text = tr ("%1 in %2; %3 @ %4")
  275. .arg (Formatter::sizeToString (myBuilder->totalSize))
  276. .arg (files)
  277. .arg (pieces)
  278. .arg (Formatter::sizeToString (myBuilder->pieceSize));
  279. }
  280. mySourceLabel->setText (text);
  281. }
  282. // bah, there doesn't seem to be any cleaner way to override
  283. // QPlainTextEdit's default desire to be 12 lines tall
  284. class ShortPlainTextEdit: public QPlainTextEdit
  285. {
  286. public:
  287. virtual ~ShortPlainTextEdit () {}
  288. ShortPlainTextEdit (QWidget * parent = 0): QPlainTextEdit(parent) {}
  289. virtual QSize sizeHint () const { return QSize (256, 50); }
  290. };
  291. MakeDialog :: MakeDialog (Session & session, QWidget * parent):
  292. QDialog (parent, Qt::Dialog),
  293. mySession (session),
  294. myBuilder (0)
  295. {
  296. setAcceptDrops (true);
  297. connect (&myTimer, SIGNAL(timeout()), this, SLOT(onProgress()));
  298. setWindowTitle (tr ("New Torrent"));
  299. QVBoxLayout * top = new QVBoxLayout (this);
  300. top->setSpacing (HIG :: PAD);
  301. HIG * hig = new HIG;
  302. hig->setContentsMargins (0, 0, 0, 0);
  303. hig->addSectionTitle (tr ("Files"));
  304. QFileIconProvider iconProvider;
  305. const int iconSize (style()->pixelMetric (QStyle::PM_SmallIconSize));
  306. const QIcon folderIcon = iconProvider.icon (QFileIconProvider::Folder);
  307. const QPixmap folderPixmap = folderIcon.pixmap (iconSize);
  308. QPushButton * b = new QPushButton;
  309. b->setIcon (folderPixmap);
  310. b->setStyleSheet (QString::fromUtf8 ("text-align: left; padding-left: 5; padding-right: 5"));
  311. myDestination = QDir::homePath();
  312. b->setText (myDestination);
  313. connect (b, SIGNAL(clicked(bool)),
  314. this, SLOT(onDestinationClicked(void)));
  315. myDestinationButton = b;
  316. hig->addRow (tr ("Sa&ve to:"), b);
  317. myFolderRadio = new QRadioButton (tr ("Source F&older:"));
  318. connect (myFolderRadio, SIGNAL(toggled(bool)),
  319. this, SLOT(onSourceChanged()));
  320. myFolderButton = new QPushButton;
  321. myFolderButton->setIcon (folderPixmap);
  322. myFolderButton->setText (tr ("(None)"));
  323. myFolderButton->setStyleSheet (QString::fromUtf8 ("text-align: left; padding-left: 5; padding-right: 5"));
  324. connect (myFolderButton, SIGNAL(clicked(bool)),
  325. this, SLOT(onFolderClicked(void)));
  326. hig->addRow (myFolderRadio, myFolderButton);
  327. enableBuddyWhenChecked (myFolderRadio, myFolderButton);
  328. const QIcon fileIcon = iconProvider.icon (QFileIconProvider::File);
  329. const QPixmap filePixmap = fileIcon.pixmap (iconSize);
  330. myFileRadio = new QRadioButton (tr ("Source &File:"));
  331. myFileRadio->setChecked (true);
  332. connect (myFileRadio, SIGNAL(toggled(bool)),
  333. this, SLOT(onSourceChanged()));
  334. myFileButton = new QPushButton;
  335. myFileButton->setText (tr ("(None)"));
  336. myFileButton->setIcon (filePixmap);
  337. myFileButton->setStyleSheet (QString::fromUtf8 ("text-align: left; padding-left: 5; padding-right: 5"));
  338. connect (myFileButton, SIGNAL(clicked(bool)),
  339. this, SLOT(onFileClicked(void)));
  340. hig->addRow (myFileRadio, myFileButton);
  341. enableBuddyWhenChecked (myFileRadio, myFileButton);
  342. mySourceLabel = new QLabel (this);
  343. hig->addRow (tr (""), mySourceLabel);
  344. hig->addSectionDivider ();
  345. hig->addSectionTitle (tr ("Properties"));
  346. hig->addWideControl (myTrackerEdit = new ShortPlainTextEdit);
  347. const int height = fontMetrics().size (0, QString::fromUtf8("\n\n\n\n")).height ();
  348. myTrackerEdit->setMinimumHeight (height);
  349. hig->addTallRow (tr ("&Trackers:"), myTrackerEdit);
  350. QLabel * l = new QLabel (tr ("To add a backup URL, add it on the line after the primary URL.\nTo add another primary URL, add it after a blank line."));
  351. l->setAlignment (Qt::AlignLeft);
  352. hig->addRow (tr (""), l);
  353. myTrackerEdit->resize (500, height);
  354. myCommentCheck = new QCheckBox (tr ("Co&mment"));
  355. myCommentEdit = new QLineEdit ();
  356. hig->addRow (myCommentCheck, myCommentEdit);
  357. enableBuddyWhenChecked (myCommentCheck, myCommentEdit);
  358. myPrivateCheck = hig->addWideCheckBox (tr ("&Private torrent"), false);
  359. hig->finish ();
  360. top->addWidget (hig, 1);
  361. myButtonBox = new QDialogButtonBox (QDialogButtonBox::Ok
  362. | QDialogButtonBox::Close);
  363. connect (myButtonBox, SIGNAL(clicked(QAbstractButton*)),
  364. this, SLOT(onButtonBoxClicked(QAbstractButton*)));
  365. top->addWidget (myButtonBox);
  366. onSourceChanged ();
  367. }
  368. MakeDialog :: ~MakeDialog ()
  369. {
  370. if (myBuilder)
  371. tr_metaInfoBuilderFree (myBuilder);
  372. }
  373. /***
  374. ****
  375. ***/
  376. void
  377. MakeDialog :: dragEnterEvent (QDragEnterEvent * event)
  378. {
  379. const QMimeData * mime = event->mimeData ();
  380. if (mime->urls().size() && QFile(mime->urls().front().path()).exists ())
  381. event->acceptProposedAction();
  382. }
  383. void
  384. MakeDialog :: dropEvent (QDropEvent * event)
  385. {
  386. const QString filename = event->mimeData()->urls().front().path();
  387. const QFileInfo fileInfo (filename);
  388. if (fileInfo.exists ())
  389. {
  390. if (fileInfo.isDir ())
  391. {
  392. myFolderRadio->setChecked (true);
  393. onFolderSelected (filename );
  394. }
  395. else // it's a file
  396. {
  397. myFileRadio->setChecked (true);
  398. onFileSelected (filename);
  399. }
  400. }
  401. }