1 | /* |
---|
2 | * This file Copyright (C) 2009-2015 Mnemosyne LLC |
---|
3 | * |
---|
4 | * It may be used under the GNU GPL versions 2 or 3 |
---|
5 | * or any future license endorsed by Mnemosyne LLC. |
---|
6 | * |
---|
7 | * $Id: MakeDialog.cc 14561 2015-09-01 20:19:26Z mikedld $ |
---|
8 | */ |
---|
9 | |
---|
10 | #include <QDir> |
---|
11 | #include <QFileInfo> |
---|
12 | #include <QMimeData> |
---|
13 | #include <QPushButton> |
---|
14 | #include <QTimer> |
---|
15 | |
---|
16 | #include <libtransmission/transmission.h> |
---|
17 | #include <libtransmission/makemeta.h> |
---|
18 | #include <libtransmission/utils.h> |
---|
19 | |
---|
20 | #include "ColumnResizer.h" |
---|
21 | #include "Formatter.h" |
---|
22 | #include "MakeDialog.h" |
---|
23 | #include "Session.h" |
---|
24 | #include "Utils.h" |
---|
25 | |
---|
26 | #include "ui_MakeProgressDialog.h" |
---|
27 | |
---|
28 | namespace |
---|
29 | { |
---|
30 | class MakeProgressDialog: public BaseDialog |
---|
31 | { |
---|
32 | Q_OBJECT |
---|
33 | |
---|
34 | public: |
---|
35 | MakeProgressDialog (Session& session, tr_metainfo_builder& builder, QWidget * parent = nullptr); |
---|
36 | |
---|
37 | private slots: |
---|
38 | void onButtonBoxClicked (QAbstractButton *); |
---|
39 | void onProgress (); |
---|
40 | |
---|
41 | private: |
---|
42 | Session& mySession; |
---|
43 | tr_metainfo_builder& myBuilder; |
---|
44 | Ui::MakeProgressDialog ui; |
---|
45 | QTimer myTimer; |
---|
46 | }; |
---|
47 | } |
---|
48 | |
---|
49 | MakeProgressDialog::MakeProgressDialog (Session& session, tr_metainfo_builder& builder, QWidget * parent): |
---|
50 | BaseDialog (parent), |
---|
51 | mySession (session), |
---|
52 | myBuilder (builder) |
---|
53 | { |
---|
54 | ui.setupUi (this); |
---|
55 | |
---|
56 | connect (ui.dialogButtons, SIGNAL (clicked (QAbstractButton *)), |
---|
57 | this, SLOT (onButtonBoxClicked (QAbstractButton *))); |
---|
58 | |
---|
59 | connect (&myTimer, SIGNAL (timeout ()), this, SLOT (onProgress ())); |
---|
60 | myTimer.start (100); |
---|
61 | |
---|
62 | onProgress (); |
---|
63 | } |
---|
64 | |
---|
65 | void |
---|
66 | MakeProgressDialog::onButtonBoxClicked (QAbstractButton * button) |
---|
67 | { |
---|
68 | switch (ui.dialogButtons->standardButton (button)) |
---|
69 | { |
---|
70 | case QDialogButtonBox::Open: |
---|
71 | mySession.addNewlyCreatedTorrent (QString::fromUtf8 (myBuilder.outputFile), |
---|
72 | QFileInfo (QString::fromUtf8 (myBuilder.top)).dir ().path ()); |
---|
73 | break; |
---|
74 | |
---|
75 | case QDialogButtonBox::Abort: |
---|
76 | myBuilder.abortFlag = true; |
---|
77 | break; |
---|
78 | |
---|
79 | default: // QDialogButtonBox::Ok: |
---|
80 | break; |
---|
81 | } |
---|
82 | |
---|
83 | close (); |
---|
84 | } |
---|
85 | |
---|
86 | void |
---|
87 | MakeProgressDialog::onProgress () |
---|
88 | { |
---|
89 | // progress bar |
---|
90 | const tr_metainfo_builder& b = myBuilder; |
---|
91 | const double denom = b.pieceCount ? b.pieceCount : 1; |
---|
92 | ui.progressBar->setValue (static_cast<int> ((100.0 * b.pieceIndex) / denom)); |
---|
93 | |
---|
94 | // progress label |
---|
95 | const QString top = QString::fromUtf8 (b.top); |
---|
96 | const QString base (QFileInfo (top).completeBaseName ()); |
---|
97 | QString str; |
---|
98 | if (!b.isDone) |
---|
99 | str = tr ("Creating \"%1\"").arg (base); |
---|
100 | else if (b.result == TR_MAKEMETA_OK) |
---|
101 | str = tr ("Created \"%1\"!").arg (base); |
---|
102 | else if (b.result == TR_MAKEMETA_URL) |
---|
103 | str = tr ("Error: invalid announce URL \"%1\"").arg (QString::fromUtf8 (b.errfile)); |
---|
104 | else if (b.result == TR_MAKEMETA_CANCELLED) |
---|
105 | str = tr ("Cancelled"); |
---|
106 | else if (b.result == TR_MAKEMETA_IO_READ) |
---|
107 | str = tr ("Error reading \"%1\": %2").arg (QString::fromUtf8 (b.errfile)). |
---|
108 | arg (QString::fromLocal8Bit (tr_strerror (b.my_errno))); |
---|
109 | else if (b.result == TR_MAKEMETA_IO_WRITE) |
---|
110 | str = tr ("Error writing \"%1\": %2").arg (QString::fromUtf8 (b.errfile)). |
---|
111 | arg (QString::fromLocal8Bit (tr_strerror (b.my_errno))); |
---|
112 | ui.progressLabel->setText (str); |
---|
113 | |
---|
114 | // buttons |
---|
115 | ui.dialogButtons->button (QDialogButtonBox::Abort)->setEnabled (!b.isDone); |
---|
116 | ui.dialogButtons->button (QDialogButtonBox::Ok)->setEnabled (b.isDone); |
---|
117 | ui.dialogButtons->button (QDialogButtonBox::Open)->setEnabled (b.isDone && b.result == TR_MAKEMETA_OK); |
---|
118 | } |
---|
119 | |
---|
120 | #include "MakeDialog.moc" |
---|
121 | |
---|
122 | /*** |
---|
123 | **** |
---|
124 | ***/ |
---|
125 | |
---|
126 | void |
---|
127 | MakeDialog::makeTorrent () |
---|
128 | { |
---|
129 | if (myBuilder == nullptr) |
---|
130 | return; |
---|
131 | |
---|
132 | // get the tiers |
---|
133 | int tier = 0; |
---|
134 | QVector<tr_tracker_info> trackers; |
---|
135 | for (const QString& line: ui.trackersEdit->toPlainText ().split (QLatin1Char ('\n'))) |
---|
136 | { |
---|
137 | const QString announceUrl = line.trimmed (); |
---|
138 | if (announceUrl.isEmpty ()) |
---|
139 | { |
---|
140 | ++tier; |
---|
141 | } |
---|
142 | else |
---|
143 | { |
---|
144 | tr_tracker_info tmp; |
---|
145 | tmp.announce = tr_strdup (announceUrl.toUtf8 ().constData ()); |
---|
146 | tmp.tier = tier; |
---|
147 | trackers.append (tmp); |
---|
148 | } |
---|
149 | } |
---|
150 | |
---|
151 | // the file to create |
---|
152 | const QString path = QString::fromUtf8 (myBuilder->top); |
---|
153 | const QString torrentName = QFileInfo (path).completeBaseName () + QLatin1String (".torrent"); |
---|
154 | const QString target = QDir (ui.destinationButton->path ()).filePath (torrentName); |
---|
155 | |
---|
156 | // comment |
---|
157 | QString comment; |
---|
158 | if (ui.commentCheck->isChecked ()) |
---|
159 | comment = ui.commentEdit->text (); |
---|
160 | |
---|
161 | // start making the torrent |
---|
162 | tr_makeMetaInfo (myBuilder.get (), |
---|
163 | target.toUtf8 ().constData (), |
---|
164 | trackers.isEmpty () ? NULL : trackers.data (), |
---|
165 | trackers.size (), |
---|
166 | comment.isEmpty () ? NULL : comment.toUtf8 ().constData (), |
---|
167 | ui.privateCheck->isChecked ()); |
---|
168 | |
---|
169 | // pop up the dialog |
---|
170 | MakeProgressDialog * dialog = new MakeProgressDialog (mySession, *myBuilder, this); |
---|
171 | dialog->setAttribute (Qt::WA_DeleteOnClose); |
---|
172 | dialog->open (); |
---|
173 | } |
---|
174 | |
---|
175 | /*** |
---|
176 | **** |
---|
177 | ***/ |
---|
178 | |
---|
179 | QString |
---|
180 | MakeDialog::getSource () const |
---|
181 | { |
---|
182 | return (ui.sourceFileRadio->isChecked () ? ui.sourceFileButton : ui.sourceFolderButton)->path (); |
---|
183 | } |
---|
184 | |
---|
185 | /*** |
---|
186 | **** |
---|
187 | ***/ |
---|
188 | |
---|
189 | void |
---|
190 | MakeDialog::onSourceChanged () |
---|
191 | { |
---|
192 | myBuilder.reset (); |
---|
193 | |
---|
194 | const QString filename = getSource (); |
---|
195 | if (!filename.isEmpty ()) |
---|
196 | myBuilder.reset (tr_metaInfoBuilderCreate (filename.toUtf8 ().constData ())); |
---|
197 | |
---|
198 | QString text; |
---|
199 | if (myBuilder == nullptr) |
---|
200 | { |
---|
201 | text = tr ("<i>No source selected<i>"); |
---|
202 | } |
---|
203 | else |
---|
204 | { |
---|
205 | QString files = tr ("%Ln File(s)", 0, myBuilder->fileCount); |
---|
206 | QString pieces = tr ("%Ln Piece(s)", 0, myBuilder->pieceCount); |
---|
207 | text = tr ("%1 in %2; %3 @ %4") |
---|
208 | .arg (Formatter::sizeToString (myBuilder->totalSize)) |
---|
209 | .arg (files) |
---|
210 | .arg (pieces) |
---|
211 | .arg (Formatter::sizeToString (myBuilder->pieceSize)); |
---|
212 | } |
---|
213 | |
---|
214 | ui.sourceSizeLabel->setText (text); |
---|
215 | } |
---|
216 | |
---|
217 | MakeDialog::MakeDialog (Session& session, QWidget * parent): |
---|
218 | BaseDialog (parent), |
---|
219 | mySession (session), |
---|
220 | myBuilder (nullptr, &tr_metaInfoBuilderFree) |
---|
221 | { |
---|
222 | ui.setupUi (this); |
---|
223 | |
---|
224 | ui.destinationButton->setMode (PathButton::DirectoryMode); |
---|
225 | ui.destinationButton->setPath (QDir::homePath ()); |
---|
226 | |
---|
227 | ui.sourceFolderButton->setMode (PathButton::DirectoryMode); |
---|
228 | ui.sourceFileButton->setMode (PathButton::FileMode); |
---|
229 | |
---|
230 | ColumnResizer * cr (new ColumnResizer (this)); |
---|
231 | cr->addLayout (ui.filesSectionLayout); |
---|
232 | cr->addLayout (ui.propertiesSectionLayout); |
---|
233 | cr->update (); |
---|
234 | |
---|
235 | resize (minimumSizeHint ()); |
---|
236 | |
---|
237 | connect (ui.sourceFolderRadio, SIGNAL (toggled (bool)), this, SLOT (onSourceChanged ())); |
---|
238 | connect (ui.sourceFolderButton, SIGNAL (pathChanged (QString)), this, SLOT (onSourceChanged ())); |
---|
239 | connect (ui.sourceFileRadio, SIGNAL (toggled (bool)), this, SLOT (onSourceChanged ())); |
---|
240 | connect (ui.sourceFileButton, SIGNAL (pathChanged (QString)), this, SLOT (onSourceChanged ())); |
---|
241 | |
---|
242 | connect (ui.dialogButtons, SIGNAL (accepted ()), this, SLOT (makeTorrent ())); |
---|
243 | connect (ui.dialogButtons, SIGNAL (rejected ()), this, SLOT (close ())); |
---|
244 | |
---|
245 | onSourceChanged (); |
---|
246 | } |
---|
247 | |
---|
248 | MakeDialog::~MakeDialog () |
---|
249 | { |
---|
250 | } |
---|
251 | |
---|
252 | /*** |
---|
253 | **** |
---|
254 | ***/ |
---|
255 | |
---|
256 | void |
---|
257 | MakeDialog::dragEnterEvent (QDragEnterEvent * event) |
---|
258 | { |
---|
259 | const QMimeData * mime = event->mimeData (); |
---|
260 | |
---|
261 | if (!mime->urls ().isEmpty () && QFileInfo (mime->urls ().front ().path ()).exists ()) |
---|
262 | event->acceptProposedAction (); |
---|
263 | } |
---|
264 | |
---|
265 | void |
---|
266 | MakeDialog::dropEvent (QDropEvent * event) |
---|
267 | { |
---|
268 | const QString filename = event->mimeData ()->urls ().front ().path (); |
---|
269 | const QFileInfo fileInfo (filename); |
---|
270 | |
---|
271 | if (fileInfo.exists ()) |
---|
272 | { |
---|
273 | if (fileInfo.isDir ()) |
---|
274 | { |
---|
275 | ui.sourceFolderRadio->setChecked (true); |
---|
276 | ui.sourceFolderButton->setPath (filename); |
---|
277 | } |
---|
278 | else // it's a file |
---|
279 | { |
---|
280 | ui.sourceFileRadio->setChecked (true); |
---|
281 | ui.sourceFileButton->setPath (filename); |
---|
282 | } |
---|
283 | } |
---|
284 | } |
---|