1 | #include"filetransdlg.h"
|
---|
2 |
|
---|
3 | #include<qlabel.h>
|
---|
4 | #include<qlineedit.h>
|
---|
5 | #include<qpushbutton.h>
|
---|
6 | #include<qtimer.h>
|
---|
7 | #include<qfiledialog.h>
|
---|
8 | #include<qfile.h>
|
---|
9 | #include<qprogressbar.h>
|
---|
10 | #include<qdir.h>
|
---|
11 | #include<qlistview.h>
|
---|
12 | #include<qlayout.h>
|
---|
13 | #include<qhbox.h>
|
---|
14 | #include<qdatetime.h>
|
---|
15 | #include<qpainter.h>
|
---|
16 | #include<qheader.h>
|
---|
17 | #include<qtooltip.h>
|
---|
18 | #include<qpopupmenu.h>
|
---|
19 | #include<qtextedit.h>
|
---|
20 | #include"psicon.h"
|
---|
21 | #include"psiaccount.h"
|
---|
22 | #include"userlist.h"
|
---|
23 | #include"common.h"
|
---|
24 | #include"iconwidget.h"
|
---|
25 | #include"busywidget.h"
|
---|
26 | #include"filetransfer.h"
|
---|
27 | #include"profiles.h"
|
---|
28 | #include"psiiconset.h"
|
---|
29 | #include"msgmle.h"
|
---|
30 |
|
---|
31 | #if QT_VERSION >= 0x030200
|
---|
32 | typedef Q_UINT64 LARGE_TYPE;
|
---|
33 | #else
|
---|
34 | typedef Q_UINT32 LARGE_TYPE;
|
---|
35 | #endif
|
---|
36 |
|
---|
37 | #define CSMAX (sizeof(LARGE_TYPE)*8)
|
---|
38 | #define CSMIN 16
|
---|
39 | static int calcShift(Q_LLONG big)
|
---|
40 | {
|
---|
41 | LARGE_TYPE val = 1;
|
---|
42 | val <<= CSMAX - 1;
|
---|
43 | for(int n = CSMAX - CSMIN; n > 0; --n) {
|
---|
44 | if(big & val)
|
---|
45 | return n;
|
---|
46 | val >>= 1;
|
---|
47 | }
|
---|
48 | return 0;
|
---|
49 | }
|
---|
50 |
|
---|
51 | static int calcComplement(Q_LLONG big, int shift)
|
---|
52 | {
|
---|
53 | int block = 1 << shift;
|
---|
54 | Q_LLONG rem = big % block;
|
---|
55 | if(rem == 0)
|
---|
56 | return 0;
|
---|
57 | else
|
---|
58 | return (block - (int)rem);
|
---|
59 | }
|
---|
60 |
|
---|
61 | static int calcTotalSteps(Q_LLONG big, int shift)
|
---|
62 | {
|
---|
63 | if(big < 1)
|
---|
64 | return 0;
|
---|
65 | return ((big - 1) >> shift) + 1;
|
---|
66 | }
|
---|
67 |
|
---|
68 | static int calcProgressStep(Q_LLONG big, int complement, int shift)
|
---|
69 | {
|
---|
70 | return ((big + complement) >> shift);
|
---|
71 | }
|
---|
72 |
|
---|
73 | static QStringList *activeFiles = 0;
|
---|
74 |
|
---|
75 | static void active_file_add(const QString &s)
|
---|
76 | {
|
---|
77 | if(!activeFiles)
|
---|
78 | activeFiles = new QStringList;
|
---|
79 | activeFiles->append(s);
|
---|
80 | //printf("added: [%s]\n", s.latin1());
|
---|
81 | }
|
---|
82 |
|
---|
83 | static void active_file_remove(const QString &s)
|
---|
84 | {
|
---|
85 | if(!activeFiles)
|
---|
86 | return;
|
---|
87 | activeFiles->remove(s);
|
---|
88 | //printf("removed: [%s]\n", s.latin1());
|
---|
89 | }
|
---|
90 |
|
---|
91 | static bool active_file_check(const QString &s)
|
---|
92 | {
|
---|
93 | if(!activeFiles)
|
---|
94 | return false;
|
---|
95 | return activeFiles->contains(s);
|
---|
96 | }
|
---|
97 |
|
---|
98 | static QString clean_filename(const QString &s)
|
---|
99 | {
|
---|
100 | //#ifdef Q_OS_WIN
|
---|
101 | QString badchars = "\\/|?*:\"<>";
|
---|
102 | QString str;
|
---|
103 | for(uint n = 0; n < s.length(); ++n) {
|
---|
104 | bool found = false;
|
---|
105 | for(uint b = 0; b < badchars.length(); ++b) {
|
---|
106 | if(s.at(n) == badchars.at(b)) {
|
---|
107 | found = true;
|
---|
108 | break;
|
---|
109 | }
|
---|
110 | }
|
---|
111 | if(!found)
|
---|
112 | str += s;
|
---|
113 | }
|
---|
114 | if(str.isEmpty())
|
---|
115 | str = "unnamed";
|
---|
116 | return str;
|
---|
117 | //#else
|
---|
118 | // return s;
|
---|
119 | //#endif
|
---|
120 | }
|
---|
121 |
|
---|
122 | //----------------------------------------------------------------------------
|
---|
123 | // FileTransferHandler
|
---|
124 | //----------------------------------------------------------------------------
|
---|
125 | class FileTransferHandler::Private
|
---|
126 | {
|
---|
127 | public:
|
---|
128 | PsiAccount *pa;
|
---|
129 | FileTransfer *ft;
|
---|
130 | S5BConnection *c;
|
---|
131 | Jid peer;
|
---|
132 | QString fileName, saveName;
|
---|
133 | Q_LLONG fileSize, sent, offset, length;
|
---|
134 | QString desc;
|
---|
135 | bool sending;
|
---|
136 | QFile f;
|
---|
137 | int shift;
|
---|
138 | int complement;
|
---|
139 | QString activeFile;
|
---|
140 | };
|
---|
141 |
|
---|
142 | FileTransferHandler::FileTransferHandler(PsiAccount *pa, FileTransfer *ft)
|
---|
143 | {
|
---|
144 | d = new Private;
|
---|
145 | d->pa = pa;
|
---|
146 | d->c = 0;
|
---|
147 |
|
---|
148 | if(ft) {
|
---|
149 | d->sending = false;
|
---|
150 | d->peer = ft->peer();
|
---|
151 | d->fileName = clean_filename(ft->fileName());
|
---|
152 | d->fileSize = ft->fileSize();
|
---|
153 | d->desc = ft->description();
|
---|
154 | d->shift = calcShift(d->fileSize);
|
---|
155 | d->complement = calcComplement(d->fileSize, d->shift);
|
---|
156 | d->ft = ft;
|
---|
157 | Jid proxy = d->pa->userAccount().dtProxy;
|
---|
158 | if(proxy.isValid())
|
---|
159 | d->ft->setProxy(proxy);
|
---|
160 | mapSignals();
|
---|
161 | }
|
---|
162 | else {
|
---|
163 | d->sending = true;
|
---|
164 | d->ft = 0;
|
---|
165 | }
|
---|
166 | }
|
---|
167 |
|
---|
168 | FileTransferHandler::~FileTransferHandler()
|
---|
169 | {
|
---|
170 | if(!d->activeFile.isEmpty())
|
---|
171 | active_file_remove(d->activeFile);
|
---|
172 |
|
---|
173 | if(d->ft) {
|
---|
174 | d->ft->close();
|
---|
175 | delete d->ft;
|
---|
176 | }
|
---|
177 | delete d;
|
---|
178 | }
|
---|
179 |
|
---|
180 | void FileTransferHandler::send(const XMPP::Jid &to, const QString &fname, const QString &desc)
|
---|
181 | {
|
---|
182 | if(!d->sending)
|
---|
183 | return;
|
---|
184 |
|
---|
185 | d->peer = to;
|
---|
186 | QFileInfo fi(fname);
|
---|
187 | d->fileName = fi.fileName();
|
---|
188 | d->fileSize = fi.size(); // TODO: large file support
|
---|
189 | d->desc = desc;
|
---|
190 | d->shift = calcShift(d->fileSize);
|
---|
191 | d->complement = calcComplement(d->fileSize, d->shift);
|
---|
192 |
|
---|
193 | d->ft = d->pa->client()->fileTransferManager()->createTransfer();
|
---|
194 | Jid proxy = d->pa->userAccount().dtProxy;
|
---|
195 | if(proxy.isValid())
|
---|
196 | d->ft->setProxy(proxy);
|
---|
197 | mapSignals();
|
---|
198 |
|
---|
199 | d->f.setName(fname);
|
---|
200 | d->ft->sendFile(d->peer, d->fileName, d->fileSize, desc);
|
---|
201 | }
|
---|
202 |
|
---|
203 | PsiAccount *FileTransferHandler::account() const
|
---|
204 | {
|
---|
205 | return d->pa;
|
---|
206 | }
|
---|
207 |
|
---|
208 | int FileTransferHandler::mode() const
|
---|
209 | {
|
---|
210 | return (d->sending ? Sending : Receiving);
|
---|
211 | }
|
---|
212 |
|
---|
213 | Jid FileTransferHandler::peer() const
|
---|
214 | {
|
---|
215 | return d->peer;
|
---|
216 | }
|
---|
217 |
|
---|
218 | QString FileTransferHandler::fileName() const
|
---|
219 | {
|
---|
220 | return d->fileName;
|
---|
221 | }
|
---|
222 |
|
---|
223 | Q_LLONG FileTransferHandler::fileSize() const
|
---|
224 | {
|
---|
225 | return d->fileSize;
|
---|
226 | }
|
---|
227 |
|
---|
228 | QString FileTransferHandler::description() const
|
---|
229 | {
|
---|
230 | return d->desc;
|
---|
231 | }
|
---|
232 |
|
---|
233 | Q_LLONG FileTransferHandler::offset() const
|
---|
234 | {
|
---|
235 | return d->offset;
|
---|
236 | }
|
---|
237 |
|
---|
238 | int FileTransferHandler::totalSteps() const
|
---|
239 | {
|
---|
240 | return calcTotalSteps(d->fileSize, d->shift);
|
---|
241 | }
|
---|
242 |
|
---|
243 | bool FileTransferHandler::resumeSupported() const
|
---|
244 | {
|
---|
245 | if(d->ft)
|
---|
246 | return d->ft->rangeSupported();
|
---|
247 | else
|
---|
248 | return false;
|
---|
249 | }
|
---|
250 |
|
---|
251 | QString FileTransferHandler::saveName() const
|
---|
252 | {
|
---|
253 | return d->saveName;
|
---|
254 | }
|
---|
255 |
|
---|
256 | void FileTransferHandler::accept(const QString &saveName, const QString &fileName, Q_LLONG offset)
|
---|
257 | {
|
---|
258 | if(d->sending)
|
---|
259 | return;
|
---|
260 | d->fileName = fileName;
|
---|
261 | d->saveName = saveName;
|
---|
262 | d->offset = offset;
|
---|
263 | d->length = d->fileSize;
|
---|
264 | d->f.setName(saveName);
|
---|
265 | d->ft->accept(offset);
|
---|
266 | }
|
---|
267 |
|
---|
268 | void FileTransferHandler::s5b_proxyQuery()
|
---|
269 | {
|
---|
270 | statusMessage(tr("Quering proxy..."));
|
---|
271 | }
|
---|
272 |
|
---|
273 | void FileTransferHandler::s5b_proxyResult(bool b)
|
---|
274 | {
|
---|
275 | if(b)
|
---|
276 | statusMessage(tr("Proxy query successful."));
|
---|
277 | else
|
---|
278 | statusMessage(tr("Proxy query failed!"));
|
---|
279 | }
|
---|
280 |
|
---|
281 | void FileTransferHandler::s5b_requesting()
|
---|
282 | {
|
---|
283 | statusMessage(tr("Requesting data transfer channel..."));
|
---|
284 | }
|
---|
285 |
|
---|
286 | void FileTransferHandler::s5b_accepted()
|
---|
287 | {
|
---|
288 | statusMessage(tr("Peer accepted request."));
|
---|
289 | }
|
---|
290 |
|
---|
291 | void FileTransferHandler::s5b_tryingHosts(const StreamHostList &)
|
---|
292 | {
|
---|
293 | statusMessage(tr("Connecting to peer..."));
|
---|
294 | }
|
---|
295 |
|
---|
296 | void FileTransferHandler::s5b_proxyConnect()
|
---|
297 | {
|
---|
298 | statusMessage(tr("Connecting to proxy..."));
|
---|
299 | }
|
---|
300 |
|
---|
301 | void FileTransferHandler::s5b_waitingForActivation()
|
---|
302 | {
|
---|
303 | statusMessage(tr("Waiting for peer activation..."));
|
---|
304 | }
|
---|
305 |
|
---|
306 | void FileTransferHandler::ft_accepted()
|
---|
307 | {
|
---|
308 | d->offset = d->ft->offset();
|
---|
309 | d->length = d->ft->length();
|
---|
310 |
|
---|
311 | d->c = d->ft->s5bConnection();
|
---|
312 | connect(d->c, SIGNAL(proxyQuery()), SLOT(s5b_proxyQuery()));
|
---|
313 | connect(d->c, SIGNAL(proxyResult(bool)), SLOT(s5b_proxyResult(bool)));
|
---|
314 | connect(d->c, SIGNAL(requesting()), SLOT(s5b_requesting()));
|
---|
315 | connect(d->c, SIGNAL(accepted()), SLOT(s5b_accepted()));
|
---|
316 | connect(d->c, SIGNAL(tryingHosts(const StreamHostList &)), SLOT(s5b_tryingHosts(const StreamHostList &)));
|
---|
317 | connect(d->c, SIGNAL(proxyConnect()), SLOT(s5b_proxyConnect()));
|
---|
318 | connect(d->c, SIGNAL(waitingForActivation()), SLOT(s5b_waitingForActivation()));
|
---|
319 |
|
---|
320 | if(d->sending)
|
---|
321 | accepted();
|
---|
322 | }
|
---|
323 |
|
---|
324 | void FileTransferHandler::ft_connected()
|
---|
325 | {
|
---|
326 | d->sent = d->offset;
|
---|
327 |
|
---|
328 | if(d->sending) {
|
---|
329 | // open the file, and set the correct offset
|
---|
330 | bool ok = false;
|
---|
331 | if(d->f.open(IO_ReadOnly)) {
|
---|
332 | if(d->offset == 0) {
|
---|
333 | ok = true;
|
---|
334 | }
|
---|
335 | else {
|
---|
336 | if(d->f.at(d->offset))
|
---|
337 | ok = true;
|
---|
338 | }
|
---|
339 | }
|
---|
340 | if(!ok) {
|
---|
341 | delete d->ft;
|
---|
342 | d->ft = 0;
|
---|
343 | error(ErrFile, 0, "");
|
---|
344 | return;
|
---|
345 | }
|
---|
346 |
|
---|
347 | if(d->sent == d->fileSize)
|
---|
348 | QTimer::singleShot(0, this, SLOT(doFinish()));
|
---|
349 | else
|
---|
350 | QTimer::singleShot(0, this, SLOT(trySend()));
|
---|
351 | }
|
---|
352 | else {
|
---|
353 | // open the file, truncating if offset is zero, otherwise set the correct offset
|
---|
354 | int m = IO_ReadWrite;
|
---|
355 | if(d->offset == 0)
|
---|
356 | m |= IO_Truncate;
|
---|
357 | bool ok = false;
|
---|
358 | if(d->f.open(m)) {
|
---|
359 | if(d->offset == 0) {
|
---|
360 | ok = true;
|
---|
361 | }
|
---|
362 | else {
|
---|
363 | if(d->f.at(d->offset))
|
---|
364 | ok = true;
|
---|
365 | }
|
---|
366 | }
|
---|
367 | if(!ok) {
|
---|
368 | delete d->ft;
|
---|
369 | d->ft = 0;
|
---|
370 | error(ErrFile, 0, "");
|
---|
371 | return;
|
---|
372 | }
|
---|
373 |
|
---|
374 | d->activeFile = d->f.name();
|
---|
375 | active_file_add(d->activeFile);
|
---|
376 |
|
---|
377 | // done already? this means a file size of zero
|
---|
378 | if(d->sent == d->fileSize)
|
---|
379 | QTimer::singleShot(0, this, SLOT(doFinish()));
|
---|
380 | }
|
---|
381 |
|
---|
382 | connected();
|
---|
383 | }
|
---|
384 |
|
---|
385 | void FileTransferHandler::ft_readyRead(const QByteArray &a)
|
---|
386 | {
|
---|
387 | if(!d->sending) {
|
---|
388 | //printf("%d bytes read\n", a.size());
|
---|
389 | int r = d->f.writeBlock(a.data(), a.size());
|
---|
390 | if(r < 0) {
|
---|
391 | d->f.close();
|
---|
392 | delete d->ft;
|
---|
393 | d->ft = 0;
|
---|
394 | error(ErrFile, 0, "");
|
---|
395 | return;
|
---|
396 | }
|
---|
397 | d->sent += a.size();
|
---|
398 | doFinish();
|
---|
399 | }
|
---|
400 | }
|
---|
401 |
|
---|
402 | void FileTransferHandler::ft_bytesWritten(int x)
|
---|
403 | {
|
---|
404 | if(d->sending) {
|
---|
405 | //printf("%d bytes written\n", x);
|
---|
406 | d->sent += x;
|
---|
407 | if(d->sent == d->fileSize) {
|
---|
408 | d->f.close();
|
---|
409 | delete d->ft;
|
---|
410 | d->ft = 0;
|
---|
411 | }
|
---|
412 | else
|
---|
413 | QTimer::singleShot(0, this, SLOT(trySend()));
|
---|
414 | progress(calcProgressStep(d->sent, d->complement, d->shift), d->sent);
|
---|
415 | }
|
---|
416 | }
|
---|
417 |
|
---|
418 | void FileTransferHandler::ft_error(int x)
|
---|
419 | {
|
---|
420 | if(d->f.isOpen())
|
---|
421 | d->f.close();
|
---|
422 | delete d->ft;
|
---|
423 | d->ft = 0;
|
---|
424 |
|
---|
425 | if(x == FileTransfer::ErrReject)
|
---|
426 | error(ErrReject, x, "");
|
---|
427 | else if(x == FileTransfer::ErrNeg)
|
---|
428 | error(ErrTransfer, x, tr("Unable to negotiate transfer."));
|
---|
429 | else if(x == FileTransfer::ErrConnect)
|
---|
430 | error(ErrTransfer, x, tr("Unable to connect to peer for data transfer."));
|
---|
431 | else if(x == FileTransfer::ErrProxy)
|
---|
432 | error(ErrTransfer, x, tr("Unable to connect to proxy for data transfer."));
|
---|
433 | else if(x == FileTransfer::ErrStream)
|
---|
434 | error(ErrTransfer, x, tr("Lost connection / Cancelled."));
|
---|
435 | }
|
---|
436 |
|
---|
437 | void FileTransferHandler::trySend()
|
---|
438 | {
|
---|
439 | int blockSize = d->ft->dataSizeNeeded();
|
---|
440 | QByteArray a(blockSize);
|
---|
441 | int r = d->f.readBlock(a.data(), a.size());
|
---|
442 | if(r < 0) {
|
---|
443 | d->f.close();
|
---|
444 | delete d->ft;
|
---|
445 | d->ft = 0;
|
---|
446 | error(ErrFile, 0, "");
|
---|
447 | return;
|
---|
448 | }
|
---|
449 | if(r < (int)a.size())
|
---|
450 | a.resize(r);
|
---|
451 | d->ft->writeFileData(a);
|
---|
452 | }
|
---|
453 |
|
---|
454 | void FileTransferHandler::doFinish()
|
---|
455 | {
|
---|
456 | if(d->sent == d->fileSize) {
|
---|
457 | d->f.close();
|
---|
458 | delete d->ft;
|
---|
459 | d->ft = 0;
|
---|
460 | }
|
---|
461 | progress(calcProgressStep(d->sent, d->complement, d->shift), d->sent);
|
---|
462 | }
|
---|
463 |
|
---|
464 | void FileTransferHandler::mapSignals()
|
---|
465 | {
|
---|
466 | connect(d->ft, SIGNAL(accepted()), SLOT(ft_accepted()));
|
---|
467 | connect(d->ft, SIGNAL(connected()), SLOT(ft_connected()));
|
---|
468 | connect(d->ft, SIGNAL(readyRead(const QByteArray &)), SLOT(ft_readyRead(const QByteArray &)));
|
---|
469 | connect(d->ft, SIGNAL(bytesWritten(int)), SLOT(ft_bytesWritten(int)));
|
---|
470 | connect(d->ft, SIGNAL(error(int)), SLOT(ft_error(int)));
|
---|
471 | }
|
---|
472 |
|
---|
473 | //----------------------------------------------------------------------------
|
---|
474 | // FileRequestDlg
|
---|
475 | //----------------------------------------------------------------------------
|
---|
476 |
|
---|
477 | class FileRequestDlg::Private
|
---|
478 | {
|
---|
479 | public:
|
---|
480 | PsiCon *psi;
|
---|
481 | PsiAccount *pa;
|
---|
482 | AccountsComboBox *cb_ident;
|
---|
483 | QLabel *lb_ident, *lb_time;
|
---|
484 | ChatView *te;
|
---|
485 | Jid jid;
|
---|
486 | FileTransferHandler *ft;
|
---|
487 | QString fileName;
|
---|
488 | Q_LLONG fileSize;
|
---|
489 | bool sending;
|
---|
490 | QTimer t;
|
---|
491 | };
|
---|
492 |
|
---|
493 |
|
---|
494 | FileRequestDlg::FileRequestDlg(const Jid &j, PsiCon *psi, PsiAccount *pa)
|
---|
495 | :FileTransUI(0, 0, false, psi_dialog_flags | WDestructiveClose)
|
---|
496 | {
|
---|
497 | QStringList l;
|
---|
498 | FileRequestDlg(j, psi, pa, l);
|
---|
499 | }
|
---|
500 |
|
---|
501 |
|
---|
502 | FileRequestDlg::FileRequestDlg(const Jid &jid, PsiCon *psi, PsiAccount *pa, const QStringList& files)
|
---|
503 | :FileTransUI(0, 0, false, psi_dialog_flags | WDestructiveClose)
|
---|
504 | {
|
---|
505 | d = new Private;
|
---|
506 | d->psi = psi;
|
---|
507 | d->pa = 0;
|
---|
508 | d->jid = jid;
|
---|
509 | d->ft = 0;
|
---|
510 | d->sending = true;
|
---|
511 | updateIdentity(pa);
|
---|
512 |
|
---|
513 | QHBox *hb = new QHBox(this);
|
---|
514 | new QLabel(tr("Identity: "), hb);
|
---|
515 | d->cb_ident = d->psi->accountsComboBox(hb);
|
---|
516 | connect(d->cb_ident, SIGNAL(activated(PsiAccount *)), SLOT(updateIdentity(PsiAccount *)));
|
---|
517 | d->cb_ident->setAccount(pa);
|
---|
518 | replaceWidget(lb_accountlabel, hb);
|
---|
519 | setTabOrder(d->cb_ident, le_to);
|
---|
520 |
|
---|
521 | d->te = new ChatView(this);
|
---|
522 | d->te->setReadOnly(false);
|
---|
523 | d->te->setTextFormat(PlainText);
|
---|
524 | replaceWidget(te_desc, d->te);
|
---|
525 | setTabOrder(le_fname, d->te);
|
---|
526 | setTabOrder(d->te, pb_stop);
|
---|
527 |
|
---|
528 | setCaption(tr("Send File"));
|
---|
529 | #ifndef Q_WS_MAC
|
---|
530 | setIcon(IconsetFactory::icon("psi/upload"));
|
---|
531 | #endif
|
---|
532 |
|
---|
533 | le_to->setText(d->jid.full());
|
---|
534 | le_to->setReadOnly(false);
|
---|
535 | pb_start->setText(tr("&Send"));
|
---|
536 | pb_stop->setText(tr("&Close"));
|
---|
537 |
|
---|
538 | connect(tb_browse, SIGNAL(clicked()), SLOT(chooseFile()));
|
---|
539 | connect(pb_start, SIGNAL(clicked()), SLOT(doStart()));
|
---|
540 | connect(pb_stop, SIGNAL(clicked()), SLOT(close()));
|
---|
541 |
|
---|
542 | lb_status->setText(tr("Ready"));
|
---|
543 |
|
---|
544 | d->te->setFocus();
|
---|
545 | d->psi->dialogRegister(this);
|
---|
546 |
|
---|
547 | if (files.isEmpty()) {
|
---|
548 | QTimer::singleShot(0, this, SLOT(chooseFile()));
|
---|
549 | }
|
---|
550 | else {
|
---|
551 | // TODO: Once sending of multiple files is supported, change this
|
---|
552 | QFileInfo fi(files.first());
|
---|
553 |
|
---|
554 | // Check if the file is legal
|
---|
555 | if(!fi.exists()) {
|
---|
556 | QMessageBox::critical(this, tr("Error"), QString("The file '%1' does not exist.").arg(files.first()));
|
---|
557 | QTimer::singleShot(0, this, SLOT(reject()));
|
---|
558 | return;
|
---|
559 | }
|
---|
560 | if(fi.isDir()) {
|
---|
561 | QMessageBox::critical(this, tr("Error"), tr("Sending folders is not supported."));
|
---|
562 | QTimer::singleShot(0, this, SLOT(reject()));
|
---|
563 | return;
|
---|
564 | }
|
---|
565 |
|
---|
566 | option.lastPath = fi.dirPath();
|
---|
567 | le_fname->setText(QDir::convertSeparators(fi.filePath()));
|
---|
568 | lb_size->setText(tr("%1 byte(s)").arg(fi.size())); // TODO: large file support
|
---|
569 | }
|
---|
570 | }
|
---|
571 |
|
---|
572 | FileRequestDlg::FileRequestDlg(const QDateTime &ts, FileTransfer *ft, PsiAccount *pa)
|
---|
573 | :FileTransUI(0, 0, false, psi_dialog_flags | WDestructiveClose)
|
---|
574 | {
|
---|
575 | d = new Private;
|
---|
576 | d->psi = 0;
|
---|
577 | d->pa = 0;
|
---|
578 | d->jid = ft->peer();
|
---|
579 | d->ft = new FileTransferHandler(pa, ft);
|
---|
580 | d->sending = false;
|
---|
581 | updateIdentity(pa);
|
---|
582 |
|
---|
583 | d->fileName = ft->fileName();
|
---|
584 | d->fileSize = ft->fileSize();
|
---|
585 |
|
---|
586 | d->cb_ident = 0;
|
---|
587 | QHBox *hb = new QHBox(this);
|
---|
588 | new QLabel(tr("Identity: "), hb);
|
---|
589 | d->lb_ident = d->pa->accountLabel(hb);
|
---|
590 | d->lb_ident->setSizePolicy(QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ));
|
---|
591 | new QLabel(tr("Time:"), hb);
|
---|
592 | d->lb_time = new QLabel(ts.time().toString(LocalDate), hb);
|
---|
593 | d->lb_time->setFrameStyle( QFrame::Panel | QFrame::Sunken );
|
---|
594 |
|
---|
595 | replaceWidget(lb_accountlabel, hb);
|
---|
596 |
|
---|
597 | d->te = new ChatView(this);
|
---|
598 | d->te->setTextFormat(PlainText);
|
---|
599 | replaceWidget(te_desc, d->te);
|
---|
600 | setTabOrder(le_fname, d->te);
|
---|
601 | setTabOrder(d->te, pb_stop);
|
---|
602 |
|
---|
603 | lb_to->setText(tr("From:"));
|
---|
604 | setCaption(tr("Receive File"));
|
---|
605 | #ifndef Q_WS_MAC
|
---|
606 | setIcon(IconsetFactory::icon("psi/download"));
|
---|
607 | #endif
|
---|
608 |
|
---|
609 | le_to->setText(d->jid.full());
|
---|
610 | le_fname->setText(d->fileName);
|
---|
611 | lb_size->setText(tr("%1 byte(s)").arg(d->fileSize));
|
---|
612 | d->te->setReadOnly(true);
|
---|
613 | d->te->setText(ft->description());
|
---|
614 | pb_start->setText(tr("&Accept"));
|
---|
615 | pb_stop->setText(tr("&Reject"));
|
---|
616 |
|
---|
617 | tb_browse->hide();
|
---|
618 |
|
---|
619 | connect(pb_start, SIGNAL(clicked()), SLOT(doStart()));
|
---|
620 | connect(pb_stop, SIGNAL(clicked()), SLOT(close()));
|
---|
621 |
|
---|
622 | connect(&d->t, SIGNAL(timeout()), SLOT(t_timeout()));
|
---|
623 |
|
---|
624 | lb_status->setText(tr("Ready"));
|
---|
625 |
|
---|
626 | pb_start->setFocus();
|
---|
627 | d->pa->dialogRegister(this);
|
---|
628 | }
|
---|
629 |
|
---|
630 | FileRequestDlg::~FileRequestDlg()
|
---|
631 | {
|
---|
632 | delete d->ft;
|
---|
633 | if(d->psi)
|
---|
634 | d->psi->dialogUnregister(this);
|
---|
635 | else
|
---|
636 | d->pa->dialogUnregister(this);
|
---|
637 | delete d;
|
---|
638 | }
|
---|
639 |
|
---|
640 | void FileRequestDlg::done(int r)
|
---|
641 | {
|
---|
642 | if(busy->isActive()) {
|
---|
643 | int n = QMessageBox::information(this, tr("Warning"), tr("Are you sure you want to cancel the transfer?"), tr("&Yes"), tr("&No"));
|
---|
644 | if(n != 0)
|
---|
645 | return;
|
---|
646 |
|
---|
647 | // close/reject FT if there is one
|
---|
648 | if(d->ft) {
|
---|
649 | delete d->ft;
|
---|
650 | d->ft = 0;
|
---|
651 | }
|
---|
652 | }
|
---|
653 |
|
---|
654 | QDialog::done(r);
|
---|
655 | }
|
---|
656 |
|
---|
657 | void FileRequestDlg::keyPressEvent(QKeyEvent *e)
|
---|
658 | {
|
---|
659 | if(e->key() == Key_Return && ((e->state() & ControlButton) || (e->state() & AltButton)) ) {
|
---|
660 | if(pb_start->isEnabled())
|
---|
661 | doStart();
|
---|
662 | }
|
---|
663 | else
|
---|
664 | QDialog::keyPressEvent(e);
|
---|
665 | }
|
---|
666 |
|
---|
667 | void FileRequestDlg::updateIdentity(PsiAccount *pa)
|
---|
668 | {
|
---|
669 | if(d->pa)
|
---|
670 | disconnect(d->pa, SIGNAL(disconnected()), this, SLOT(pa_disconnected()));
|
---|
671 |
|
---|
672 | if(!pa) {
|
---|
673 | close();
|
---|
674 | return;
|
---|
675 | }
|
---|
676 |
|
---|
677 | d->pa = pa;
|
---|
678 | connect(d->pa, SIGNAL(disconnected()), this, SLOT(pa_disconnected()));
|
---|
679 | }
|
---|
680 |
|
---|
681 | void FileRequestDlg::pa_disconnected()
|
---|
682 | {
|
---|
683 | //if(busy->isActive()) {
|
---|
684 | // busy->stop();
|
---|
685 | // close();
|
---|
686 | //}
|
---|
687 | }
|
---|
688 |
|
---|
689 | void FileRequestDlg::blockWidgets()
|
---|
690 | {
|
---|
691 | if(d->cb_ident)
|
---|
692 | d->cb_ident->setEnabled(false);
|
---|
693 | le_to->setEnabled(false);
|
---|
694 | le_fname->setEnabled(false);
|
---|
695 | tb_browse->setEnabled(false);
|
---|
696 | d->te->setEnabled(false);
|
---|
697 | pb_start->setEnabled(false);
|
---|
698 | }
|
---|
699 |
|
---|
700 | void FileRequestDlg::unblockWidgets()
|
---|
701 | {
|
---|
702 | if(d->cb_ident)
|
---|
703 | d->cb_ident->setEnabled(true);
|
---|
704 | le_to->setEnabled(true);
|
---|
705 | le_fname->setEnabled(true);
|
---|
706 | tb_browse->setEnabled(true);
|
---|
707 | d->te->setEnabled(true);
|
---|
708 | pb_start->setEnabled(true);
|
---|
709 | }
|
---|
710 |
|
---|
711 | void FileRequestDlg::chooseFile()
|
---|
712 | {
|
---|
713 | while(1) {
|
---|
714 | if(option.lastPath.isEmpty())
|
---|
715 | option.lastPath = QDir::homeDirPath();
|
---|
716 | QString str = QFileDialog::getOpenFileName(option.lastPath, tr("All files (*)"), this, 0, tr("Choose a file"));
|
---|
717 | if(!str.isEmpty()) {
|
---|
718 | QFileInfo fi(str);
|
---|
719 | if(!fi.exists()) {
|
---|
720 | QMessageBox::information(this, tr("Error"), tr("The file specified does not exist."));
|
---|
721 | continue;
|
---|
722 | }
|
---|
723 | option.lastPath = fi.dirPath();
|
---|
724 | le_fname->setText(QDir::convertSeparators(fi.filePath()));
|
---|
725 | lb_size->setText(tr("%1 byte(s)").arg(fi.size())); // TODO: large file support
|
---|
726 | }
|
---|
727 | break;
|
---|
728 | }
|
---|
729 | }
|
---|
730 |
|
---|
731 | void FileRequestDlg::doStart()
|
---|
732 | {
|
---|
733 | if(!d->pa->checkConnected(this))
|
---|
734 | return;
|
---|
735 |
|
---|
736 | if(d->sending) {
|
---|
737 | Jid to = le_to->text();
|
---|
738 | if(!to.isValid()) {
|
---|
739 | QMessageBox::information(this, tr("Error"), tr("The Jabber ID specified is not valid. Correct this and try again."));
|
---|
740 | return;
|
---|
741 | }
|
---|
742 |
|
---|
743 | QFileInfo fi(le_fname->text());
|
---|
744 | if(!fi.exists()) {
|
---|
745 | QMessageBox::information(this, tr("Error"), tr("The file specified does not exist. Choose a correct file name before sending."));
|
---|
746 | return;
|
---|
747 | }
|
---|
748 |
|
---|
749 | blockWidgets();
|
---|
750 |
|
---|
751 | pb_stop->setText(tr("&Cancel"));
|
---|
752 | pb_stop->setFocus();
|
---|
753 | busy->start();
|
---|
754 | lb_status->setText(tr("Requesting..."));
|
---|
755 |
|
---|
756 | d->fileName = fi.fileName();
|
---|
757 | d->fileSize = fi.size(); // TODO: large file support
|
---|
758 |
|
---|
759 | d->ft = new FileTransferHandler(d->pa);
|
---|
760 | connect(d->ft, SIGNAL(accepted()), SLOT(ft_accepted()));
|
---|
761 | connect(d->ft, SIGNAL(statusMessage(const QString &)), SLOT(ft_statusMessage(const QString &)));
|
---|
762 | connect(d->ft, SIGNAL(connected()), SLOT(ft_connected()));
|
---|
763 | connect(d->ft, SIGNAL(error(int, int, const QString &)), SLOT(ft_error(int, int, const QString &)));
|
---|
764 | d->ft->send(le_to->text(), le_fname->text(), d->te->text());
|
---|
765 | }
|
---|
766 | else {
|
---|
767 | QString fname, savename;
|
---|
768 | bool overwrite = false;
|
---|
769 | while(1) {
|
---|
770 | if(option.lastSavePath.isEmpty())
|
---|
771 | option.lastSavePath = QDir::homeDirPath();
|
---|
772 | fname = QFileDialog::getSaveFileName(QDir(option.lastSavePath).filePath(d->fileName), tr("All files (*)"), this, 0, tr("Save As"));
|
---|
773 | if(!fname.isEmpty()) {
|
---|
774 | QFileInfo fi(fname);
|
---|
775 | if(fi.exists()) {
|
---|
776 | int x = QMessageBox::information(this, tr("Error"), tr("File already exists. Overwrite?"), tr("&Yes"), tr("&No"));
|
---|
777 | if(x != 0)
|
---|
778 | continue;
|
---|
779 | overwrite = true;
|
---|
780 | }
|
---|
781 | option.lastSavePath = fi.dirPath();
|
---|
782 | savename = fname + ".part";
|
---|
783 | fname = fi.fileName();
|
---|
784 | }
|
---|
785 | else
|
---|
786 | return;
|
---|
787 |
|
---|
788 | break;
|
---|
789 | }
|
---|
790 |
|
---|
791 | if(active_file_check(savename)) {
|
---|
792 | QMessageBox::information(this, tr("Error"), tr("This file is being transferred already!"));
|
---|
793 | return;
|
---|
794 | }
|
---|
795 |
|
---|
796 | Q_LLONG resume_offset = 0;
|
---|
797 | if(!overwrite) {
|
---|
798 | // supports resume? check for a .part
|
---|
799 | if(d->ft->resumeSupported()) {
|
---|
800 | QFileInfo fi(savename);
|
---|
801 | if(fi.exists())
|
---|
802 | resume_offset = fi.size();
|
---|
803 | }
|
---|
804 | }
|
---|
805 |
|
---|
806 | pb_start->setEnabled(false);
|
---|
807 |
|
---|
808 | le_fname->setText(fname);
|
---|
809 | pb_stop->setText(tr("&Cancel"));
|
---|
810 | pb_stop->setFocus();
|
---|
811 | busy->start();
|
---|
812 | lb_status->setText(tr("Accepting..."));
|
---|
813 |
|
---|
814 | d->t.start(30000, true);
|
---|
815 |
|
---|
816 | connect(d->ft, SIGNAL(accepted()), SLOT(ft_accepted()));
|
---|
817 | connect(d->ft, SIGNAL(statusMessage(const QString &)), SLOT(ft_statusMessage(const QString &)));
|
---|
818 | connect(d->ft, SIGNAL(connected()), SLOT(ft_connected()));
|
---|
819 | connect(d->ft, SIGNAL(error(int, int, const QString &)), SLOT(ft_error(int, int, const QString &)));
|
---|
820 | d->ft->accept(savename, fname, resume_offset);
|
---|
821 | }
|
---|
822 | }
|
---|
823 |
|
---|
824 | void FileRequestDlg::ft_accepted()
|
---|
825 | {
|
---|
826 | lb_status->setText(tr("Accepted!"));
|
---|
827 | }
|
---|
828 |
|
---|
829 | void FileRequestDlg::ft_statusMessage(const QString &s)
|
---|
830 | {
|
---|
831 | lb_status->setText(s);
|
---|
832 |
|
---|
833 | // stop the timer at first activity
|
---|
834 | if(d->t.isActive())
|
---|
835 | d->t.stop();
|
---|
836 | }
|
---|
837 |
|
---|
838 | void FileRequestDlg::ft_connected()
|
---|
839 | {
|
---|
840 | d->t.stop();
|
---|
841 | busy->stop();
|
---|
842 | FileTransDlg *w = d->pa->psi()->ftdlg();
|
---|
843 | FileTransferHandler *h = d->ft;
|
---|
844 | d->ft = 0;
|
---|
845 | closeDialogs(this);
|
---|
846 | close();
|
---|
847 | bringToFront(w);
|
---|
848 |
|
---|
849 | w->takeTransfer(h, 0, 0);
|
---|
850 | }
|
---|
851 |
|
---|
852 | void FileRequestDlg::ft_error(int x, int fx, const QString &)
|
---|
853 | {
|
---|
854 | d->t.stop();
|
---|
855 | busy->stop();
|
---|
856 |
|
---|
857 | delete d->ft;
|
---|
858 | d->ft = 0;
|
---|
859 |
|
---|
860 | closeDialogs(this);
|
---|
861 |
|
---|
862 | if(d->sending) {
|
---|
863 | unblockWidgets();
|
---|
864 | pb_stop->setText(tr("&Close"));
|
---|
865 | lb_status->setText(tr("Ready"));
|
---|
866 | }
|
---|
867 |
|
---|
868 | QString str;
|
---|
869 | if(x == FileTransferHandler::ErrReject)
|
---|
870 | str = tr("File was rejected by remote user.");
|
---|
871 | else if(x == FileTransferHandler::ErrTransfer) {
|
---|
872 | if(fx == FileTransfer::ErrNeg)
|
---|
873 | str = tr(
|
---|
874 | "Unable to negotiate transfer.\n\n"
|
---|
875 | "This can happen if the contact did not understand our request, or if the\n"
|
---|
876 | "contact is offline."
|
---|
877 | );
|
---|
878 | else if(fx == FileTransfer::ErrConnect)
|
---|
879 | str = tr(
|
---|
880 | "Unable to connect to peer for data transfer.\n\n"
|
---|
881 | "Ensure that your Data Transfer settings are proper. If you are behind\n"
|
---|
882 | "a NAT router or firewall then you'll need to open the proper TCP port\n"
|
---|
883 | "or specify a Data Transfer Proxy in your account settings."
|
---|
884 | );
|
---|
885 | else if(fx == FileTransfer::ErrProxy)
|
---|
886 | str = tr(
|
---|
887 | "Failure to either connect to, or activate, the Data Transfer Proxy.\n\n"
|
---|
888 | "This means that the Proxy service is either not functioning or it is\n"
|
---|
889 | "unreachable. If you are behind a firewall, then you'll need to ensure\n"
|
---|
890 | "that outgoing TCP connections are allowed."
|
---|
891 | );
|
---|
892 | }
|
---|
893 | else
|
---|
894 | str = tr("File I/O error");
|
---|
895 | QMessageBox::information(this, tr("Error"), str);
|
---|
896 |
|
---|
897 | if(!d->sending || x == FileTransferHandler::ErrReject)
|
---|
898 | close();
|
---|
899 | }
|
---|
900 |
|
---|
901 | void FileRequestDlg::t_timeout()
|
---|
902 | {
|
---|
903 | delete d->ft;
|
---|
904 | d->ft = 0;
|
---|
905 |
|
---|
906 | busy->stop();
|
---|
907 | closeDialogs(this);
|
---|
908 |
|
---|
909 | QString str = tr("Unable to accept the file. Perhaps the sender has cancelled the request.");
|
---|
910 | QMessageBox::information(this, tr("Error"), str);
|
---|
911 | close();
|
---|
912 | }
|
---|
913 |
|
---|
914 | //----------------------------------------------------------------------------
|
---|
915 | // FileTransDlg
|
---|
916 | //----------------------------------------------------------------------------
|
---|
917 | class FileTransItem : public QListViewItem
|
---|
918 | {
|
---|
919 | public:
|
---|
920 | QPixmap icon;
|
---|
921 | bool sending;
|
---|
922 | QString name;
|
---|
923 | Q_LLONG size;
|
---|
924 | QString peer;
|
---|
925 | QString rate;
|
---|
926 | int progress;
|
---|
927 | Q_LLONG sent;
|
---|
928 | int bps;
|
---|
929 | int timeRemaining;
|
---|
930 | int id;
|
---|
931 | int dist;
|
---|
932 | bool done;
|
---|
933 | QString error;
|
---|
934 |
|
---|
935 | FileTransItem(QListView *parent, const QString &_name, Q_LLONG _size, const QString &_peer, bool _sending)
|
---|
936 | :QListViewItem(parent)
|
---|
937 | {
|
---|
938 | done = false;
|
---|
939 | sending = _sending;
|
---|
940 | name = _name;
|
---|
941 | size = _size;
|
---|
942 | peer = _peer;
|
---|
943 | rate = FileTransDlg::tr("N/A");
|
---|
944 | sent = 0;
|
---|
945 | progress = 0;
|
---|
946 | dist = -1;
|
---|
947 | }
|
---|
948 |
|
---|
949 | void niceUnit(Q_LLONG n, Q_LLONG *div, QString *unit)
|
---|
950 | {
|
---|
951 | Q_LLONG gb = 1024 * 1024 * 1024;
|
---|
952 | Q_LLONG mb = 1024 * 1024;
|
---|
953 | Q_LLONG kb = 1024;
|
---|
954 | if(n >= gb) {
|
---|
955 | *div = gb;
|
---|
956 | *unit = QString("GB");
|
---|
957 | }
|
---|
958 | else if(n >= mb) {
|
---|
959 | *div = mb;
|
---|
960 | *unit = QString("MB");
|
---|
961 | }
|
---|
962 | else if(n >= kb) {
|
---|
963 | *div = kb;
|
---|
964 | *unit = QString("KB");
|
---|
965 | }
|
---|
966 | else {
|
---|
967 | *div = 1;
|
---|
968 | *unit = QString("B");
|
---|
969 | }
|
---|
970 | }
|
---|
971 |
|
---|
972 | QString roundedNumber(Q_LLONG n, Q_LLONG div)
|
---|
973 | {
|
---|
974 | bool decimal = false;
|
---|
975 | if(div >= 1024) {
|
---|
976 | div /= 10;
|
---|
977 | decimal = true;
|
---|
978 | }
|
---|
979 | Q_LLONG x_long = n / div;
|
---|
980 | int x = (int)x_long;
|
---|
981 | if(decimal) {
|
---|
982 | double f = (double)x;
|
---|
983 | f /= 10;
|
---|
984 | return QString::number(f, 'f', 1);
|
---|
985 | }
|
---|
986 | else
|
---|
987 | return QString::number(x);
|
---|
988 | }
|
---|
989 |
|
---|
990 | bool setProgress(int _progress, Q_LLONG _sent, int _bps)
|
---|
991 | {
|
---|
992 | progress = _progress;
|
---|
993 | sent = _sent;
|
---|
994 | bps = _bps;
|
---|
995 |
|
---|
996 | if(bps > 0) {
|
---|
997 | Q_LLONG rest_long = size - sent;
|
---|
998 | rest_long /= bps;
|
---|
999 | int maxtime = (23 * 60 * 60) + (59 * 60) + (59); // 23h59m59s
|
---|
1000 | if(rest_long > maxtime)
|
---|
1001 | rest_long = maxtime;
|
---|
1002 | timeRemaining = (int)rest_long;
|
---|
1003 | }
|
---|
1004 |
|
---|
1005 | int lastDist = dist;
|
---|
1006 | dist = progressBarDist(progressBarWidth());
|
---|
1007 | if(dist != lastDist)
|
---|
1008 | return true;
|
---|
1009 | else
|
---|
1010 | return false;
|
---|
1011 | }
|
---|
1012 |
|
---|
1013 | void updateRate()
|
---|
1014 | {
|
---|
1015 | QString s;
|
---|
1016 | {
|
---|
1017 | Q_LLONG div;
|
---|
1018 | QString unit;
|
---|
1019 | niceUnit(size, &div, &unit);
|
---|
1020 |
|
---|
1021 | s = roundedNumber(sent, div) + '/' + roundedNumber(size, div) + unit;
|
---|
1022 |
|
---|
1023 | if(done) {
|
---|
1024 | if(error.isEmpty())
|
---|
1025 | s += QString(" ") + FileTransDlg::tr("[Done]");
|
---|
1026 | else
|
---|
1027 | s += QString(" ") + FileTransDlg::tr("[Error: %1]").arg(error);
|
---|
1028 | }
|
---|
1029 | else if(bps == -1)
|
---|
1030 | s += "";
|
---|
1031 | else if(bps == 0)
|
---|
1032 | s += QString(" ") + FileTransDlg::tr("[Stalled]");
|
---|
1033 | else {
|
---|
1034 | niceUnit(bps, &div, &unit);
|
---|
1035 | s += QString(" @ ") + FileTransDlg::tr("%1%2/s").arg(roundedNumber(bps, div)).arg(unit);
|
---|
1036 |
|
---|
1037 | s += ", ";
|
---|
1038 | QTime t = QTime().addSecs(timeRemaining);
|
---|
1039 | s += FileTransDlg::tr("%1h%2m%3s remaining").arg(t.hour()).arg(t.minute()).arg(t.second());
|
---|
1040 | }
|
---|
1041 | }
|
---|
1042 | rate = s;
|
---|
1043 | }
|
---|
1044 |
|
---|
1045 | int progressBarWidth() const
|
---|
1046 | {
|
---|
1047 | int m = 4;
|
---|
1048 | int w = listView()->columnWidth(0);
|
---|
1049 | //int pw = (w - (3 * m)) / 2;
|
---|
1050 | int pw = (w - (3 * m)) * 2 / 3;
|
---|
1051 | return pw;
|
---|
1052 | }
|
---|
1053 |
|
---|
1054 | int progressBarDist(int width) const
|
---|
1055 | {
|
---|
1056 | int xsize = width - 2;
|
---|
1057 | return (progress * xsize / 8192);
|
---|
1058 | }
|
---|
1059 |
|
---|
1060 | void drawProgressBar(QPainter *p, const QColorGroup &cg, int x, int y, int width, int height) const
|
---|
1061 | {
|
---|
1062 | p->save();
|
---|
1063 | if(isSelected())
|
---|
1064 | p->setPen(cg.highlightedText());
|
---|
1065 | else
|
---|
1066 | p->setPen(cg.text());
|
---|
1067 | p->drawRect(x, y, width, height);
|
---|
1068 | int xoff = x + 1;
|
---|
1069 | int yoff = y + 1;
|
---|
1070 | int xsize = width - 2;
|
---|
1071 | int ysize = height - 2;
|
---|
1072 |
|
---|
1073 | int dist = progressBarDist(width);
|
---|
1074 | p->fillRect(xoff, yoff, dist, ysize, cg.brush(QColorGroup::Highlight));
|
---|
1075 | p->fillRect(xoff + dist, yoff, width - 2 - dist, ysize, cg.brush(QColorGroup::Base));
|
---|
1076 |
|
---|
1077 | int percent = progress * 100 / 8192;
|
---|
1078 | QString s = QString::number(percent) + '%';
|
---|
1079 |
|
---|
1080 | QFontMetrics fm(p->font());
|
---|
1081 | int ty = ((height - fm.height()) / 2) + fm.ascent() + y;
|
---|
1082 | int textwidth = fm.width(s);
|
---|
1083 | int center = xoff + (xsize / 2);
|
---|
1084 |
|
---|
1085 | p->save();
|
---|
1086 | p->setPen(cg.highlightedText());
|
---|
1087 | p->setClipRect(xoff, yoff, dist, ysize, QPainter::CoordPainter);
|
---|
1088 | p->drawText(center - (textwidth / 2), ty, s);
|
---|
1089 | p->restore();
|
---|
1090 |
|
---|
1091 | p->save();
|
---|
1092 | p->setPen(cg.text());
|
---|
1093 | p->setClipRect(xoff + dist, yoff, width - 2 - dist, ysize, QPainter::CoordPainter);
|
---|
1094 | p->drawText(center - (textwidth / 2), ty, s);
|
---|
1095 | p->restore();
|
---|
1096 | p->restore();
|
---|
1097 | }
|
---|
1098 |
|
---|
1099 | void setup()
|
---|
1100 | {
|
---|
1101 | widthChanged();
|
---|
1102 | QListView *lv = listView();
|
---|
1103 |
|
---|
1104 | QFontMetrics fm = lv->fontMetrics();
|
---|
1105 | int m = 4;
|
---|
1106 | int pm = 2;
|
---|
1107 | int ph = fm.height() + 2 + (pm * 2);
|
---|
1108 | int h = (ph * 2) + (m * 3);
|
---|
1109 |
|
---|
1110 | h += lv->itemMargin() * 2;
|
---|
1111 |
|
---|
1112 | // ensure an even number
|
---|
1113 | if(h & 1)
|
---|
1114 | ++h;
|
---|
1115 |
|
---|
1116 | setHeight(h);
|
---|
1117 | }
|
---|
1118 |
|
---|
1119 | QString chopString(const QString &s, const QFontMetrics &fm, int len) const
|
---|
1120 | {
|
---|
1121 | if(fm.width(s) <= len)
|
---|
1122 | return s;
|
---|
1123 |
|
---|
1124 | QString str;
|
---|
1125 | uint n = s.length();
|
---|
1126 | do {
|
---|
1127 | str = s.mid(0, --n) + "...";
|
---|
1128 | } while(n > 0 && fm.width(str) > len);
|
---|
1129 | return str;
|
---|
1130 | }
|
---|
1131 |
|
---|
1132 | void paintCell(QPainter *mp, const QColorGroup &_cg, int, int width, int)
|
---|
1133 | {
|
---|
1134 | QColorGroup cg = _cg;
|
---|
1135 | int w = width;
|
---|
1136 | int h = height();
|
---|
1137 |
|
---|
1138 | // tint the background
|
---|
1139 | /*//QColor base = Qt::black; //cg.base();
|
---|
1140 | QColor base = Qt::white;
|
---|
1141 | int red = base.red();
|
---|
1142 | int green = base.green();
|
---|
1143 | int blue = base.blue();
|
---|
1144 | bool light = false;//true;
|
---|
1145 | if(sending) {
|
---|
1146 | if(light) {
|
---|
1147 | green = green * 15 / 16;
|
---|
1148 | blue = blue * 15 / 16;
|
---|
1149 | }
|
---|
1150 | else {
|
---|
1151 | red = 255 - red;
|
---|
1152 | red = red * 15 / 16;
|
---|
1153 | red = 255 - red;
|
---|
1154 | }
|
---|
1155 | }
|
---|
1156 | else {
|
---|
1157 | if(light) {
|
---|
1158 | red = red * 15 / 16;
|
---|
1159 | blue = blue * 15 / 16;
|
---|
1160 | }
|
---|
1161 | else {
|
---|
1162 | green = 255 - green;
|
---|
1163 | green = green * 15 / 16;
|
---|
1164 | green = 255 - green;
|
---|
1165 | }
|
---|
1166 | }
|
---|
1167 | base.setRgb(red, green, blue);
|
---|
1168 | cg.setColor(QColorGroup::Base, base);*/
|
---|
1169 |
|
---|
1170 | QPixmap pix(w, h);
|
---|
1171 | QPainter *p = new QPainter(&pix);
|
---|
1172 | QFont font = mp->font();
|
---|
1173 | QFont boldFont = font;
|
---|
1174 | boldFont.setBold(true);
|
---|
1175 | QFontMetrics fm(font);
|
---|
1176 | QFontMetrics fmbold(boldFont);
|
---|
1177 | QBrush br;
|
---|
1178 |
|
---|
1179 | // m = margin, pm = progress margin, ph = progress height, yoff = text y offset,
|
---|
1180 | // tt = text top, tb = text bottom, pw = progress width, px = progress x coord
|
---|
1181 | int m = 4;
|
---|
1182 | int pm = 2;
|
---|
1183 | int ph = fm.height() + 2 + (pm * 2);
|
---|
1184 | int yoff = 1 + pm;
|
---|
1185 | int tt = m + yoff + fm.ascent();
|
---|
1186 | int tb = (m * 2) + ph + yoff + fm.ascent();
|
---|
1187 | //int pw = (w - (3 * m)) / 2;
|
---|
1188 | int pw = (w - (3 * m)) * 2 / 3;
|
---|
1189 | int tw = (w - (3 * m)) - pw;
|
---|
1190 | int px = (m * 2) + tw;
|
---|
1191 |
|
---|
1192 | // clear out the background
|
---|
1193 | if(isSelected())
|
---|
1194 | br = cg.brush(QColorGroup::Highlight);
|
---|
1195 | else
|
---|
1196 | br = cg.brush(QColorGroup::Base);
|
---|
1197 | p->fillRect(0, 0, width, h, br);
|
---|
1198 |
|
---|
1199 | // icon
|
---|
1200 | p->drawPixmap(m, m + yoff, icon);
|
---|
1201 | int tm = m + icon.width() + 4;
|
---|
1202 | tw = tw - (icon.width() + 4);
|
---|
1203 |
|
---|
1204 | // filename / peer
|
---|
1205 | if(isSelected())
|
---|
1206 | p->setPen(cg.highlightedText());
|
---|
1207 | else
|
---|
1208 | p->setPen(cg.text());
|
---|
1209 | p->setFont(boldFont);
|
---|
1210 | QString s1 = FileTransDlg::tr("File") + ": ";
|
---|
1211 | QString s2 = FileTransDlg::tr("To") + ": ";
|
---|
1212 | QString s3 = FileTransDlg::tr("From") + ": ";
|
---|
1213 |
|
---|
1214 | int lw = QMAX(QMAX(fmbold.width(s1), fmbold.width(s2)), fmbold.width(s3));
|
---|
1215 | int left = tw - lw;
|
---|
1216 | p->drawText(tm, tt, s1);
|
---|
1217 | p->drawText(tm, tb, sending ? s2 : s3);
|
---|
1218 | p->setFont(font);
|
---|
1219 | p->drawText(tm + lw, tt, chopString(name, fm, left));
|
---|
1220 | p->drawText(tm + lw, tb, chopString(peer, fm, left));
|
---|
1221 |
|
---|
1222 | // rate
|
---|
1223 | p->setFont(boldFont);
|
---|
1224 | s1 = FileTransDlg::tr("Status") + ": ";
|
---|
1225 | lw = fmbold.width(s1);
|
---|
1226 | left = pw - lw;
|
---|
1227 | p->drawText(px, tb, s1);
|
---|
1228 | p->setFont(font);
|
---|
1229 | p->drawText(px + lw, tb, chopString(rate, fm, left));
|
---|
1230 |
|
---|
1231 | // progress bar
|
---|
1232 | drawProgressBar(p, cg, px, m, pw, ph);
|
---|
1233 |
|
---|
1234 | delete p;
|
---|
1235 | mp->drawPixmap(0, 0, pix);
|
---|
1236 | }
|
---|
1237 |
|
---|
1238 | QString makeTip() const
|
---|
1239 | {
|
---|
1240 | QTime t = QTime().addSecs(timeRemaining);
|
---|
1241 | QString rem = FileTransDlg::tr("%1h%2m%3s").arg(t.hour()).arg(t.minute()).arg(t.second());
|
---|
1242 |
|
---|
1243 | QString s;
|
---|
1244 | s += FileTransDlg::tr("Filename") + QString(": %1").arg(name);
|
---|
1245 | s += QString("\n") + FileTransDlg::tr("Type") + QString(": %1").arg(sending ? FileTransDlg::tr("Upload") : FileTransDlg::tr("Download"));
|
---|
1246 | s += QString("\n") + FileTransDlg::tr("Peer") + QString(": %1").arg(peer);
|
---|
1247 | s += QString("\n") + FileTransDlg::tr("Size") + QString(": %1").arg(size);
|
---|
1248 | if(done) {
|
---|
1249 | s += QString("\n") + FileTransDlg::tr("[Done]");
|
---|
1250 | }
|
---|
1251 | else {
|
---|
1252 | s += QString("\n") + FileTransDlg::tr("Transferred") + QString(": %1").arg(sent);
|
---|
1253 | if(bps > 0)
|
---|
1254 | s += QString("\n") + FileTransDlg::tr("Time remaining") + QString(": %1").arg(rem);
|
---|
1255 | }
|
---|
1256 |
|
---|
1257 | return s;
|
---|
1258 | }
|
---|
1259 | };
|
---|
1260 |
|
---|
1261 | class FileTransView : public QListView, public QToolTip
|
---|
1262 | {
|
---|
1263 | Q_OBJECT
|
---|
1264 | public:
|
---|
1265 | FileTransView(QWidget *parent=0, const char *name=0)
|
---|
1266 | :QListView(parent, name), QToolTip(viewport())
|
---|
1267 | {
|
---|
1268 | connect(this, SIGNAL(contextMenuRequested(QListViewItem *, const QPoint &, int)), this, SLOT(qlv_contextMenuRequested(QListViewItem *, const QPoint &, int)));
|
---|
1269 | }
|
---|
1270 |
|
---|
1271 | void maybeTip(const QPoint &pos)
|
---|
1272 | {
|
---|
1273 | FileTransItem *i = static_cast<FileTransItem*>(itemAt(pos));
|
---|
1274 | if(!i)
|
---|
1275 | return;
|
---|
1276 | QRect r(itemRect(i));
|
---|
1277 | tip(r, i->makeTip());
|
---|
1278 | }
|
---|
1279 |
|
---|
1280 | void resizeEvent(QResizeEvent *e)
|
---|
1281 | {
|
---|
1282 | QListView::resizeEvent(e);
|
---|
1283 |
|
---|
1284 | if(e->oldSize().width() != e->size().width())
|
---|
1285 | doResize();
|
---|
1286 | }
|
---|
1287 |
|
---|
1288 | signals:
|
---|
1289 | void itemCancel(int id);
|
---|
1290 | void itemOpenDest(int id);
|
---|
1291 | void itemClear(int id);
|
---|
1292 |
|
---|
1293 | private slots:
|
---|
1294 | void qlv_contextMenuRequested(QListViewItem *item, const QPoint &pos, int)
|
---|
1295 | {
|
---|
1296 | if(!item)
|
---|
1297 | return;
|
---|
1298 |
|
---|
1299 | FileTransItem *i = static_cast<FileTransItem*>(item);
|
---|
1300 |
|
---|
1301 | QPopupMenu p;
|
---|
1302 | p.insertItem(tr("&Cancel"), 0);
|
---|
1303 | p.insertSeparator();
|
---|
1304 | //p.insertItem(tr("&Open Destination Folder"), 1);
|
---|
1305 | p.insertItem(tr("Cl&ear"), 2);
|
---|
1306 |
|
---|
1307 | if(i->done) {
|
---|
1308 | p.setItemEnabled(0, false);
|
---|
1309 | }
|
---|
1310 | else {
|
---|
1311 | //p.setItemEnabled(1, false);
|
---|
1312 | p.setItemEnabled(2, false);
|
---|
1313 | }
|
---|
1314 |
|
---|
1315 | int x = p.exec(pos);
|
---|
1316 |
|
---|
1317 | // TODO: what if item is deleted during exec?
|
---|
1318 |
|
---|
1319 | if(x == 0) {
|
---|
1320 | if(!i->done)
|
---|
1321 | itemCancel(i->id);
|
---|
1322 | }
|
---|
1323 | else if(x == 1)
|
---|
1324 | itemOpenDest(i->id);
|
---|
1325 | else if(x == 2)
|
---|
1326 | itemClear(i->id);
|
---|
1327 | }
|
---|
1328 |
|
---|
1329 | private:
|
---|
1330 | void doResize()
|
---|
1331 | {
|
---|
1332 | QListViewItemIterator it(this);
|
---|
1333 | for(QListViewItem *i; (i = it.current()); ++it)
|
---|
1334 | i->setup();
|
---|
1335 | }
|
---|
1336 | };
|
---|
1337 |
|
---|
1338 | class TransferMapping
|
---|
1339 | {
|
---|
1340 | public:
|
---|
1341 | FileTransferHandler *h;
|
---|
1342 | int id;
|
---|
1343 | int p;
|
---|
1344 | Q_LLONG sent;
|
---|
1345 |
|
---|
1346 | int at;
|
---|
1347 | Q_LLONG last[10];
|
---|
1348 |
|
---|
1349 | TransferMapping()
|
---|
1350 | {
|
---|
1351 | h = 0;
|
---|
1352 | at = 0;
|
---|
1353 | }
|
---|
1354 |
|
---|
1355 | ~TransferMapping()
|
---|
1356 | {
|
---|
1357 | delete h;
|
---|
1358 | }
|
---|
1359 |
|
---|
1360 | void logSent()
|
---|
1361 | {
|
---|
1362 | // if we're at the end, shift down to make room
|
---|
1363 | if(at == 10) {
|
---|
1364 | for(int n = 0; n < at - 1; ++n)
|
---|
1365 | last[n] = last[n + 1];
|
---|
1366 | --at;
|
---|
1367 | }
|
---|
1368 | last[at++] = sent;
|
---|
1369 | }
|
---|
1370 | };
|
---|
1371 |
|
---|
1372 | class FileTransDlg::Private
|
---|
1373 | {
|
---|
1374 | public:
|
---|
1375 | FileTransDlg *parent;
|
---|
1376 | PsiCon *psi;
|
---|
1377 | FileTransView *lv;
|
---|
1378 | QPtrList<TransferMapping> transferList;
|
---|
1379 | QTimer t;
|
---|
1380 |
|
---|
1381 | Private(FileTransDlg *_parent)
|
---|
1382 | {
|
---|
1383 | parent = _parent;
|
---|
1384 | transferList.setAutoDelete(true);
|
---|
1385 | }
|
---|
1386 |
|
---|
1387 | int findFreeId()
|
---|
1388 | {
|
---|
1389 | int n = 0;
|
---|
1390 | while(1) {
|
---|
1391 | bool found = false;
|
---|
1392 | QListViewItemIterator it(lv);
|
---|
1393 | for(QListViewItem *i; (i = it.current()); ++it) {
|
---|
1394 | FileTransItem *fi = static_cast<FileTransItem*>(i);
|
---|
1395 | if(fi->id == n) {
|
---|
1396 | found = true;
|
---|
1397 | break;
|
---|
1398 | }
|
---|
1399 | }
|
---|
1400 | if(!found)
|
---|
1401 | break;
|
---|
1402 | ++n;
|
---|
1403 | }
|
---|
1404 | return n;
|
---|
1405 | }
|
---|
1406 |
|
---|
1407 | FileTransItem *findItem(int id)
|
---|
1408 | {
|
---|
1409 | QListViewItemIterator it(lv);
|
---|
1410 | for(QListViewItem *i; (i = it.current()); ++it) {
|
---|
1411 | FileTransItem *fi = static_cast<FileTransItem*>(i);
|
---|
1412 | if(fi->id == id)
|
---|
1413 | return fi;
|
---|
1414 | }
|
---|
1415 | return 0;
|
---|
1416 | }
|
---|
1417 |
|
---|
1418 | QPtrList<FileTransItem> getFinished()
|
---|
1419 | {
|
---|
1420 | QPtrList<FileTransItem> list;
|
---|
1421 | QListViewItemIterator it(lv);
|
---|
1422 | for(QListViewItem *i; (i = it.current()); ++it) {
|
---|
1423 | FileTransItem *fi = static_cast<FileTransItem*>(i);
|
---|
1424 | if(fi->done)
|
---|
1425 | list.append(fi);
|
---|
1426 | }
|
---|
1427 | return list;
|
---|
1428 | }
|
---|
1429 |
|
---|
1430 | TransferMapping *findMapping(FileTransferHandler *h)
|
---|
1431 | {
|
---|
1432 | QPtrListIterator<TransferMapping> it(transferList);
|
---|
1433 | for(TransferMapping *i; (i = it.current()); ++it) {
|
---|
1434 | if(i->h == h)
|
---|
1435 | return i;
|
---|
1436 | }
|
---|
1437 | return 0;
|
---|
1438 | }
|
---|
1439 |
|
---|
1440 | TransferMapping *findMapping(int id)
|
---|
1441 | {
|
---|
1442 | QPtrListIterator<TransferMapping> it(transferList);
|
---|
1443 | for(TransferMapping *i; (i = it.current()); ++it) {
|
---|
1444 | if(i->id == id)
|
---|
1445 | return i;
|
---|
1446 | }
|
---|
1447 | return 0;
|
---|
1448 | }
|
---|
1449 |
|
---|
1450 | void updateProgress(TransferMapping *i, bool updateAll=true)
|
---|
1451 | {
|
---|
1452 | bool done = (i->p == i->h->totalSteps());
|
---|
1453 |
|
---|
1454 | // calculate bps
|
---|
1455 | int bps = -1;
|
---|
1456 | if(!done && i->at >= 2) {
|
---|
1457 | int seconds = i->at - 1;
|
---|
1458 | Q_LLONG average = i->last[i->at-1] - i->last[0];
|
---|
1459 | bps = ((int)average) / seconds;
|
---|
1460 | }
|
---|
1461 |
|
---|
1462 | if(done) {
|
---|
1463 | FileTransItem *fi = findItem(i->id);
|
---|
1464 | fi->done = true;
|
---|
1465 | }
|
---|
1466 |
|
---|
1467 | parent->setProgress(i->id, i->p, i->h->totalSteps(), i->sent, bps, updateAll);
|
---|
1468 |
|
---|
1469 | if(done) {
|
---|
1470 | bool recv = (i->h->mode() == FileTransferHandler::Receiving);
|
---|
1471 | QString fname, savename;
|
---|
1472 | if(recv) {
|
---|
1473 | fname = i->h->fileName();
|
---|
1474 | savename = i->h->saveName();
|
---|
1475 | }
|
---|
1476 |
|
---|
1477 | PsiAccount *pa = i->h->account();
|
---|
1478 | transferList.removeRef(i);
|
---|
1479 |
|
---|
1480 | if(recv) {
|
---|
1481 | //printf("fname: [%s], savename: [%s]\n", fname.latin1(), savename.latin1());
|
---|
1482 |
|
---|
1483 | // rename .part to original filename
|
---|
1484 | QFileInfo fi(savename);
|
---|
1485 | QDir dir = fi.dir();
|
---|
1486 | if(dir.exists(fname))
|
---|
1487 | dir.remove(fname);
|
---|
1488 | if(!dir.rename(fi.fileName(), fname)) {
|
---|
1489 | // TODO: display some error about renaming
|
---|
1490 | }
|
---|
1491 | }
|
---|
1492 |
|
---|
1493 | pa->playSound(option.onevent[eFTComplete]);
|
---|
1494 | }
|
---|
1495 | }
|
---|
1496 | };
|
---|
1497 |
|
---|
1498 | FileTransDlg::FileTransDlg(PsiCon *psi)
|
---|
1499 | :QDialog(0, 0, false, psi_dialog_flags)
|
---|
1500 | {
|
---|
1501 | d = new Private(this);
|
---|
1502 | d->psi = psi;
|
---|
1503 | //d->psi->dialogRegister(this);
|
---|
1504 |
|
---|
1505 | connect(&d->t, SIGNAL(timeout()), SLOT(updateItems()));
|
---|
1506 |
|
---|
1507 | setCaption(tr("Transfer Manager"));
|
---|
1508 | #ifndef Q_WS_MAC
|
---|
1509 | setIcon(IconsetFactory::icon("psi/filemanager"));
|
---|
1510 | #endif
|
---|
1511 |
|
---|
1512 | QVBoxLayout *vb = new QVBoxLayout(this, 11, 6);
|
---|
1513 | d->lv = new FileTransView(this);
|
---|
1514 | connect(d->lv, SIGNAL(itemCancel(int)), SLOT(itemCancel(int)));
|
---|
1515 | connect(d->lv, SIGNAL(itemOpenDest(int)), SLOT(itemOpenDest(int)));
|
---|
1516 | connect(d->lv, SIGNAL(itemClear(int)), SLOT(itemClear(int)));
|
---|
1517 | vb->addWidget(d->lv);
|
---|
1518 | QHBoxLayout *hb = new QHBoxLayout(vb);
|
---|
1519 | hb->addStretch(1);
|
---|
1520 | QPushButton *pb_clear = new QPushButton(tr("Clear &Finished"), this);
|
---|
1521 | connect(pb_clear, SIGNAL(clicked()), SLOT(clearFinished()));
|
---|
1522 | hb->addWidget(pb_clear);
|
---|
1523 | QPushButton *pb_close = new QPushButton(tr("&Hide"), this);
|
---|
1524 | connect(pb_close, SIGNAL(clicked()), SLOT(close()));
|
---|
1525 | hb->addWidget(pb_close);
|
---|
1526 |
|
---|
1527 | pb_close->setDefault(true);
|
---|
1528 | pb_close->setFocus();
|
---|
1529 |
|
---|
1530 | d->lv->addColumn("");
|
---|
1531 | d->lv->header()->hide();
|
---|
1532 |
|
---|
1533 | d->lv->setResizeMode(QListView::LastColumn);
|
---|
1534 | d->lv->setAllColumnsShowFocus(true);
|
---|
1535 | d->lv->setSorting(-1);
|
---|
1536 |
|
---|
1537 | resize(560, 240);
|
---|
1538 | }
|
---|
1539 |
|
---|
1540 | FileTransDlg::~FileTransDlg()
|
---|
1541 | {
|
---|
1542 | //d->psi->dialogUnregister(this);
|
---|
1543 | delete d;
|
---|
1544 | }
|
---|
1545 |
|
---|
1546 | int FileTransDlg::addItem(const QString &filename, Q_LLONG size, const QString &peer, bool sending)
|
---|
1547 | {
|
---|
1548 | int id = d->findFreeId();
|
---|
1549 | FileTransItem *i = new FileTransItem(d->lv, filename, size, peer, sending);
|
---|
1550 | if(sending)
|
---|
1551 | i->icon = IconsetFactory::icon("psi/upload").impix().pixmap();
|
---|
1552 | else
|
---|
1553 | i->icon = IconsetFactory::icon("psi/download").impix().pixmap();
|
---|
1554 | i->id = id;
|
---|
1555 | d->t.start(1000);
|
---|
1556 | return id;
|
---|
1557 | }
|
---|
1558 |
|
---|
1559 | void FileTransDlg::setProgress(int id, int step, int total, Q_LLONG sent, int bytesPerSecond, bool updateAll)
|
---|
1560 | {
|
---|
1561 | FileTransItem *i = d->findItem(id);
|
---|
1562 | if(i) {
|
---|
1563 | // convert steps/total into a word
|
---|
1564 | int progress;
|
---|
1565 | if(total > 0)
|
---|
1566 | progress = step * 8192 / total;
|
---|
1567 | else
|
---|
1568 | progress = 8192;
|
---|
1569 |
|
---|
1570 | bool do_repaint = i->setProgress(progress, sent, bytesPerSecond);
|
---|
1571 | if(updateAll) {
|
---|
1572 | i->updateRate();
|
---|
1573 | do_repaint = true;
|
---|
1574 | }
|
---|
1575 | if(do_repaint)
|
---|
1576 | i->repaint();
|
---|
1577 | }
|
---|
1578 | }
|
---|
1579 |
|
---|
1580 | void FileTransDlg::removeItem(int id)
|
---|
1581 | {
|
---|
1582 | FileTransItem *i = d->findItem(id);
|
---|
1583 | if(i)
|
---|
1584 | delete i;
|
---|
1585 | if(d->lv->childCount() == 0)
|
---|
1586 | d->t.stop();
|
---|
1587 | }
|
---|
1588 |
|
---|
1589 | void FileTransDlg::setError(int id, const QString &reason)
|
---|
1590 | {
|
---|
1591 | FileTransItem *i = d->findItem(id);
|
---|
1592 | if(i) {
|
---|
1593 | i->done = true;
|
---|
1594 | i->error = reason;
|
---|
1595 | i->updateRate();
|
---|
1596 | i->repaint();
|
---|
1597 | show();
|
---|
1598 | d->lv->ensureItemVisible(i);
|
---|
1599 | QMessageBox::information(this, tr("Transfer Error"), tr("Transfer of %1 with %2 failed.\nReason: %3").arg(i->name).arg(i->peer).arg(reason));
|
---|
1600 | }
|
---|
1601 | }
|
---|
1602 |
|
---|
1603 | void FileTransDlg::takeTransfer(FileTransferHandler *h, int p, Q_LLONG sent)
|
---|
1604 | {
|
---|
1605 | QString peer;
|
---|
1606 | UserListItem *u = h->account()->findFirstRelavent(h->peer());
|
---|
1607 | if(u)
|
---|
1608 | peer = jidnick(u->jid().full(), u->name());
|
---|
1609 | else
|
---|
1610 | peer = h->peer().full();
|
---|
1611 |
|
---|
1612 | TransferMapping *i = new TransferMapping;
|
---|
1613 | i->h = h;
|
---|
1614 | i->id = addItem(h->fileName(), h->fileSize(), peer, (h->mode() == FileTransferHandler::Sending));
|
---|
1615 | i->p = p;
|
---|
1616 | i->sent = sent;
|
---|
1617 | d->transferList.append(i);
|
---|
1618 |
|
---|
1619 | FileTransItem *fi = d->findItem(i->id);
|
---|
1620 | d->lv->ensureItemVisible(fi);
|
---|
1621 |
|
---|
1622 | if(p == i->h->totalSteps()) {
|
---|
1623 | d->updateProgress(i, true);
|
---|
1624 | }
|
---|
1625 | else {
|
---|
1626 | connect(h, SIGNAL(progress(int, Q_LLONG)), SLOT(ft_progress(int, Q_LLONG)));
|
---|
1627 | connect(h, SIGNAL(error(int, int, const QString &)), SLOT(ft_error(int, int, const QString &)));
|
---|
1628 | }
|
---|
1629 | }
|
---|
1630 |
|
---|
1631 | void FileTransDlg::clearFinished()
|
---|
1632 | {
|
---|
1633 | QPtrList<FileTransItem> list = d->getFinished();
|
---|
1634 | {
|
---|
1635 | // remove related transfer mappings
|
---|
1636 | QPtrListIterator<FileTransItem> it(list);
|
---|
1637 | for(FileTransItem *fi; (fi = it.current()); ++it) {
|
---|
1638 | TransferMapping *i = d->findMapping(fi->id);
|
---|
1639 | d->transferList.removeRef(i);
|
---|
1640 | }
|
---|
1641 | }
|
---|
1642 | list.setAutoDelete(true);
|
---|
1643 | list.clear();
|
---|
1644 | }
|
---|
1645 |
|
---|
1646 | void FileTransDlg::ft_progress(int p, Q_LLONG sent)
|
---|
1647 | {
|
---|
1648 | TransferMapping *i = d->findMapping((FileTransferHandler *)sender());
|
---|
1649 | i->p = p;
|
---|
1650 | i->sent = sent;
|
---|
1651 | if(p == i->h->totalSteps())
|
---|
1652 | d->updateProgress(i, true);
|
---|
1653 | else
|
---|
1654 | d->updateProgress(i, false);
|
---|
1655 | }
|
---|
1656 |
|
---|
1657 | void FileTransDlg::ft_error(int x, int, const QString &s)
|
---|
1658 | {
|
---|
1659 | TransferMapping *i = d->findMapping((FileTransferHandler *)sender());
|
---|
1660 | int id = i->id;
|
---|
1661 | d->transferList.removeRef(i);
|
---|
1662 |
|
---|
1663 | QString str;
|
---|
1664 | //if(x == FileTransferHandler::ErrReject)
|
---|
1665 | // str = tr("File was rejected by remote user.");
|
---|
1666 | if(x == FileTransferHandler::ErrTransfer)
|
---|
1667 | str = s;
|
---|
1668 | else
|
---|
1669 | str = tr("File I/O error");
|
---|
1670 | setError(id, str);
|
---|
1671 | }
|
---|
1672 |
|
---|
1673 | void FileTransDlg::updateItems()
|
---|
1674 | {
|
---|
1675 | // operate on a copy so that we can delete items in updateProgress
|
---|
1676 | QPtrList<TransferMapping> list = d->transferList;
|
---|
1677 | QPtrListIterator<TransferMapping> it(list);
|
---|
1678 | for(TransferMapping *i; (i = it.current()); ++it) {
|
---|
1679 | if(i->h) {
|
---|
1680 | i->logSent();
|
---|
1681 | d->updateProgress(i);
|
---|
1682 | }
|
---|
1683 | }
|
---|
1684 | }
|
---|
1685 |
|
---|
1686 | void FileTransDlg::itemCancel(int id)
|
---|
1687 | {
|
---|
1688 | FileTransItem *fi = d->findItem(id);
|
---|
1689 | TransferMapping *i = d->findMapping(id);
|
---|
1690 | d->transferList.removeRef(i);
|
---|
1691 | delete fi;
|
---|
1692 | }
|
---|
1693 |
|
---|
1694 | void FileTransDlg::itemOpenDest(int id)
|
---|
1695 | {
|
---|
1696 | TransferMapping *i = d->findMapping(id);
|
---|
1697 |
|
---|
1698 | QString path;
|
---|
1699 | bool recv = (i->h->mode() == FileTransferHandler::Receiving);
|
---|
1700 | if(recv)
|
---|
1701 | path = QFileInfo(i->h->saveName()).dirPath();
|
---|
1702 | else
|
---|
1703 | path = QFileInfo(i->h->fileName()).dirPath();
|
---|
1704 |
|
---|
1705 | //printf("item open dest: [%s]\n", path.latin1());
|
---|
1706 | }
|
---|
1707 |
|
---|
1708 | void FileTransDlg::itemClear(int id)
|
---|
1709 | {
|
---|
1710 | FileTransItem *fi = d->findItem(id);
|
---|
1711 | TransferMapping *i = d->findMapping(id);
|
---|
1712 | d->transferList.removeRef(i);
|
---|
1713 | delete fi;
|
---|
1714 | }
|
---|
1715 |
|
---|
1716 | void FileTransDlg::killTransfers(PsiAccount *pa)
|
---|
1717 | {
|
---|
1718 | QPtrList<TransferMapping> list = d->transferList;
|
---|
1719 | QPtrListIterator<TransferMapping> it(list);
|
---|
1720 | for(TransferMapping *i; (i = it.current()); ++it) {
|
---|
1721 | // this account?
|
---|
1722 | if(i->h->account() == pa) {
|
---|
1723 | FileTransItem *fi = d->findItem(i->id);
|
---|
1724 | d->transferList.removeRef(i);
|
---|
1725 | delete fi;
|
---|
1726 | }
|
---|
1727 | }
|
---|
1728 | }
|
---|
1729 |
|
---|
1730 | #include"filetransdlg.moc"
|
---|