Compare commits

..

819 Commits

Author SHA1 Message Date
Christophe Dumez
429ff34e46 - Tagged beta2 release 2008-06-22 17:41:47 +00:00
Christophe Dumez
54bf7e61f7 - libmagick configure improvement 2008-04-11 16:47:55 +00:00
Christophe Dumez
8422cb395a - Fixed unlimited download limit problem (trayicon) 2008-03-14 20:54:02 +00:00
Christophe Dumez
313b9b9bc0 - Fixed mistake in french translation 2008-03-14 20:46:07 +00:00
Christophe Dumez
9d3fcb10d5 - Updated language files 2008-03-14 20:27:40 +00:00
Christophe Dumez
34725dc26b - Fixed index problem in preview selection (closes #192495) 2008-02-17 13:33:43 +00:00
Christophe Dumez
8b576fcc50 - Attempt to fix compilation on vc++ 2008-02-03 10:43:12 +00:00
Christophe Dumez
1b7449ef4e - Fixed torrent names in mininova search engine 2008-01-28 12:26:44 +00:00
Christophe Dumez
596ec6ae4c - Updated slovak translation 2008-01-11 23:35:09 +00:00
Christophe Dumez
569b69689a - updated translation files 2008-01-04 20:53:56 +00:00
Christophe Dumez
07c195f475 - Catch more exceptions when adding a torrent 2008-01-04 20:43:28 +00:00
Christophe Dumez
5e86c8a14d - Fixed systray integration when qbittorrent is launched on system startup 2008-01-04 20:09:37 +00:00
Christophe Dumez
85796d9c2c - Use 16px tray icon on windows 2008-01-04 19:48:26 +00:00
Christophe Dumez
f4120088c6 Updated language files 2008-01-03 16:18:37 +00:00
Christophe Dumez
8d1f1512b0 - Fixed UPnP messages 2008-01-03 16:17:01 +00:00
Christophe Dumez
c6abdacadd - Threadified torrent creation
- Added a progress bar in torrent creation
- Display if UPnP/NAT-PMP was successful or not
2007-12-31 16:57:35 +00:00
Christophe Dumez
fa00d745b2 - Sharemonkey filename fix (Thanks Keiron Waites) 2007-12-30 21:03:05 +00:00
Christophe Dumez
1e1313dffc - Fixed torrent creation from a folder
- Fixed start seeding directly after torrent creation
2007-12-30 18:06:51 +00:00
Christophe Dumez
00b3677867 - Fixed btjunkie search engine 2007-12-28 09:57:05 +00:00
Ishan Arora
8a9a23866f Corrections in RealProgressBarThread
- Fixed a bug related to the size of the array
- Removed the much hated goto statements with loops :)
2007-12-26 16:40:20 +00:00
Christophe Dumez
91328de30f - Disabled libcurl verbosity 2007-12-12 22:20:36 +00:00
Christophe Dumez
204d9ff496 - Fixed eol problems on Windows 2007-12-12 22:00:41 +00:00
Christophe Dumez
5d64373798 should fix eol problems on windows 2007-12-12 21:45:44 +00:00
Christophe Dumez
699d4b1161 - Forgot to call a python script with python executable 2007-12-12 18:17:09 +00:00
Christophe Dumez
0fe9d68be1 - Forgot to call one script with python 2007-12-12 17:55:16 +00:00
Christophe Dumez
b2f9394d6e - Call python scripts using python executable (fix for windows) 2007-12-12 17:14:15 +00:00
Christophe Dumez
56965d444a - Attempt to fix search engine on Windows 2007-12-12 16:56:32 +00:00
Christophe Dumez
07d7a44731 - DownloadThread now write in binary mode (should fix problems on Windows) 2007-12-12 12:23:38 +00:00
Christophe Dumez
f85aa72c72 - Disable libcurl debug 2007-12-11 20:33:57 +00:00
Christophe Dumez
2f5b4a190e - downloads from urls now follow redirections 2007-12-11 20:20:43 +00:00
Christophe Dumez
aada4f3c03 - Forgot to remove temporary download file when addition failed 2007-12-11 20:00:43 +00:00
Christophe Dumez
9540d45c1d - Fixed torrentreactor search engine 2007-12-11 19:32:09 +00:00
Christophe Dumez
cfd7a1bf0b Updated Japanese translation 2007-12-11 17:11:27 +00:00
Arnaud Demaiziere
3e13bd1381 BUGFIX : when shutting down the system, qbt simply quits 2007-12-09 16:35:51 +00:00
Christophe Dumez
3af23ae8a9 - Fixed compilation warning 2007-12-09 15:51:09 +00:00
Christophe Dumez
f1aa1f993d - Fixed preview when path contain spaces 2007-12-09 09:30:06 +00:00
Christophe Dumez
82b1b29906 - Fixed space problem for "open destination folder" action 2007-12-09 09:28:11 +00:00
Christophe Dumez
14882fe38f - Added our sharemonkey campaign id
- Updated hungarian translation
2007-12-08 22:17:01 +00:00
Christophe Dumez
82f60f1b89 - Updated version in menu entry 2007-12-07 22:59:12 +00:00
Christophe Dumez
dab617458a - Added comment for sharemonkey campaign id 2007-12-07 22:56:36 +00:00
Christophe Dumez
1832d518d6 - Updated splash screen for v1.1.0
- Version Bump to v1.1.0alpha2
2007-12-07 22:51:25 +00:00
Christophe Dumez
5ed8517cde - Added an icon for the new "Buy it" action
- Updated language files
2007-12-07 22:48:51 +00:00
Christophe Dumez
b2950afd5c - FEATURE: Allow to buy downloads using ShareMonkey 2007-12-07 22:33:19 +00:00
Christophe Dumez
a84c686090 - Fixed a problem when closing to systray, then closing the app and cancel 2007-12-04 12:04:53 +00:00
Christophe Dumez
efb8315a38 - Fixed nbResult != 0 when clearing results while a search is running 2007-12-03 19:29:57 +00:00
Christophe Dumez
56b018fb95 - Attempt to fix downloadFromUrl on Windows 2007-11-30 16:05:20 +00:00
Christophe Dumez
731438a19a - Updated search engine plugins in order to limit to 10 pages 2007-11-30 11:54:05 +00:00
Christophe Dumez
fd4ce53eb1 - Added a 3 minutes search timeout 2007-11-30 10:48:00 +00:00
Christophe Dumez
b4f0fbdbc4 Updated polish translation 2007-11-29 18:16:45 +00:00
Christophe Dumez
26ae2af198 - Fixed proxy host max length in preferences 2007-11-28 12:50:08 +00:00
Christophe Dumez
bdb625a615 - Fixed compilation on windows (closes #172391) 2007-11-27 19:37:45 +00:00
Christophe Dumez
f68c5114b2 Updated japanese translation 2007-11-25 19:55:19 +00:00
Christophe Dumez
83282bf835 - Updated polish translation 2007-11-25 14:55:16 +00:00
Christophe Dumez
054351e3a4 - Updated translation files 2007-11-25 13:38:21 +00:00
Christophe Dumez
a5dac03956 - Same as last commit but for gnome looks 2007-11-24 23:47:44 +00:00
Christophe Dumez
a760913482 - Same as last commit but for infoBar this time 2007-11-24 23:43:57 +00:00
Christophe Dumez
f3c8889865 - Should fixed text color for stalled torrents when using a dark theme 2007-11-24 23:39:44 +00:00
Christophe Dumez
b24a1e9123 - COSMETIC: Do not display progress bar in seeding list (always 100%) 2007-11-24 22:24:01 +00:00
Christophe Dumez
c4b7622a17 - Do not compute data for hidden columns in order to save CPU 2007-11-24 22:16:00 +00:00
Christophe Dumez
f7fa66c65d - Improved a lot ETA calculation algorithm 2007-11-24 21:55:19 +00:00
Christophe Dumez
a91d2028d8 - Rewrote part of Arnaud's code for column hiding to debug and optimize it 2007-11-24 19:04:28 +00:00
Christophe Dumez
adea644c04 - Removed "Resize all columns" action 2007-11-24 18:33:17 +00:00
Christophe Dumez
31679f0d6d Tagged rc9 release 2007-11-24 12:11:12 +00:00
Arnaud Demaiziere
0d90ad8f7c bufixes on hidden columns in transfert lists 2007-11-24 00:14:19 +00:00
Christophe Dumez
8ab6aeafcc - Fixed compilation warning in Ishan's code 2007-11-23 23:48:05 +00:00
Christophe Dumez
a56baf5b58 - Added some errors code for libcurl
- Added HTTPS download support
2007-11-23 23:06:38 +00:00
Christophe Dumez
61eb921e44 - Moved from libcommoncpp to libcurl for downloads from urls
- Added SOCKS5 proxy support when downloading from urls
2007-11-23 22:57:49 +00:00
Christophe Dumez
8ecf79e91c - Do not use SOCKS5 proxies in downloadThread.cpp (does not work) 2007-11-23 20:48:47 +00:00
Christophe Dumez
349e58fa22 - Fixed minor version number 2007-11-23 17:22:48 +00:00
Christophe Dumez
436f5bbd7e - Fixed HTTP proxy support in downloadThread 2007-11-23 15:54:18 +00:00
Christophe Dumez
64bfdf930c - Fixed not destructing libtorrent session bug 2007-11-23 15:20:26 +00:00
Christophe Dumez
8858518a14 - fixed proxy layout in preferences 2007-11-23 00:23:55 +00:00
Christophe Dumez
def19ef88b - Added h.is_valid check 2007-11-22 21:53:42 +00:00
Christophe Dumez
4f989b674f - Do not save fastresume data for paused torrents anymore 2007-11-22 21:50:22 +00:00
Christophe Dumez
f0ef21e409 - Fixed proxy auth disable problem when disabling proxy 2007-11-22 21:32:30 +00:00
Christophe Dumez
6b0ae4f575 - Some bug fixes (Proxy) 2007-11-22 10:49:10 +00:00
Christophe Dumez
3926b0d787 - Fixed compilation warning 2007-11-21 22:46:13 +00:00
Christophe Dumez
a721e6d943 - Improved proxy support (search, rss, downloadFromUrl...) 2007-11-21 22:30:33 +00:00
Ishan Arora
9c05148a24 few more corrections on RealProgressBar
- removed counting incomplete pieces
- replaced few Q_ASSERT with corrective statements
2007-11-21 21:12:03 +00:00
Christophe Dumez
725ef52cfe - Fixed compilation warning 2007-11-21 20:35:31 +00:00
Christophe Dumez
7982011d0b - Do not save fastresume data regularly for seeding torrents 2007-11-21 20:33:30 +00:00
Christophe Dumez
0a3bb0cfcd - BUGFIX: title bar is now reset when "Display speed in title" is disabled 2007-11-21 20:17:01 +00:00
Christophe Dumez
f75501f781 - Fixed overflow handling in ETA calculation 2007-11-21 18:59:49 +00:00
Christophe Dumez
70f8a00c20 - Save fastresume data every minute instead of every 10 sec 2007-11-21 16:50:26 +00:00
Christophe Dumez
2691677650 - Fixed segfault that would happen when unfiltering files in torrent addition dialog (closes #163379) 2007-11-19 21:42:58 +00:00
Christophe Dumez
be34bed61a - Fixed compilation warning 2007-11-19 21:33:07 +00:00
Christophe Dumez
721ef1d236 - Fixed useless variable in properties 2007-11-19 21:31:48 +00:00
Christophe Dumez
c8b944508b - Saving trackers file only when necessary
- Avoid code duplication for showProperties()
2007-11-19 21:10:57 +00:00
Christophe Dumez
f3f3f2822b - Do not save fastresume data for checking torrents anymore 2007-11-19 20:43:54 +00:00
Christophe Dumez
3ef0c82a8c - Do no pause torrents before saving fastresume data anymore (no longer needed)
- Save fast resume data regularly (every 10 seconds) to avoid downloading from s
cratch when qBittorrent restart
2007-11-19 20:33:31 +00:00
Arnaud Demaiziere
b8200fd7b2 feature : allow to hide/show columns 2007-11-19 00:58:14 +00:00
Ishan Arora
9e62780a6d Added files missing in last revision 2007-11-18 19:40:49 +00:00
Christophe Dumez
58c78fa6f6 - FEATURE: Real progress bar in torrent properties that displays downloaded pieces (contribution by
Ishan Arora)
2007-11-18 18:06:44 +00:00
Christophe Dumez
5484ec923d - Improved proxy support in search engine 2007-11-16 19:59:36 +00:00
Christophe Dumez
54225cd42f - Made properties window a bit larger
- Remember properties window size and position on startup
2007-11-16 19:33:38 +00:00
Christophe Dumez
dc651ffed3 - Updated TODO List 2007-11-16 19:21:24 +00:00
Christophe Dumez
476a7d7be0 Updated language files 2007-11-16 18:54:52 +00:00
Christophe Dumez
c580285fe8 - Allow to open destination folder on right click on a torrent 2007-11-16 18:53:21 +00:00
Christophe Dumez
5b6166ee15 - Simplified file preview using QDesktopServices 2007-11-16 18:36:57 +00:00
Christophe Dumez
18ee43225e - Allow to open destination folder on double-click 2007-11-16 18:26:00 +00:00
Christophe Dumez
b47073901f - Removed a fedora 7 workaround 2007-11-13 10:32:42 +00:00
Christophe Dumez
d45c44868e - Removed Fedora workaround because Fedora 8 is working propery now 2007-11-10 09:25:51 +00:00
Christophe Dumez
4401b60d51 - cleaned up arnaud's code for double-click action 2007-11-08 18:31:41 +00:00
Christophe Dumez
0ce114a7f8 - Fixed double-click default action 2007-11-08 18:22:34 +00:00
Christophe Dumez
38ca306499 - Fixed start minimized 2007-11-07 12:30:20 +00:00
Christophe Dumez
6cb636f85d - Fixed Changelog 2007-11-07 12:19:12 +00:00
Christophe Dumez
7563b09ead - Updated TODO/Changelog 2007-11-07 11:20:28 +00:00
Arnaud Demaiziere
76783c819c clear the results of a search stops it 2007-11-07 08:41:34 +00:00
Arnaud Demaiziere
42312b982b i forgot the changelog ... oups 2007-11-06 21:16:49 +00:00
Arnaud Demaiziere
a329a59719 - Start minimized option in program preferences
*** - In finished list, replace "Seeds/Leechs" column by "Leechers" 
because Seeds are always 0.
- Allow to change action on double-click
  -> in download list
  -> in seeding list
2007-11-06 21:11:09 +00:00
Christophe Dumez
82e548a2fd - Fixed a bug in torrent files filtering (closes #158846) 2007-11-06 20:55:23 +00:00
Christophe Dumez
5bbdb9e119 - Renabled debug
- Bumped to v1.1.0alpha1
2007-11-06 17:40:44 +00:00
Christophe Dumez
68cbcaeab9 - Fixed a little problem with 16x16px icon install 2007-11-04 09:18:31 +00:00
Christophe Dumez
3c88657e0f rc7 release 2007-11-03 11:57:00 +00:00
Christophe Dumez
f836be6736 - BUGFIX: Don't reload seeding torrents anymore (no point) 2007-11-03 00:19:24 +00:00
Christophe Dumez
85fe900afe - Disable debug mode 2007-11-02 22:56:33 +00:00
Christophe Dumez
052ccf2302 - BUGFIX: Don't reload all torrents everytime settings are saved 2007-11-02 22:56:07 +00:00
Christophe Dumez
ae384da609 - Updated TODO 2007-11-02 13:32:24 +00:00
Christophe Dumez
0fc2d289eb - BUGFIX: Pause/Start All now affect all tabs, not only the current one 2007-11-02 13:12:31 +00:00
Christophe Dumez
9ca02aad88 - BUGFIX: Fixed a bug in children update when changing files priorities 2007-10-30 21:29:15 +00:00
Christophe Dumez
8ea34135e4 - BUGFIX: Catching DHT exception in case there is a problem 2007-10-27 20:53:09 +00:00
Christophe Dumez
b66be5b64b - Removed build dependency on Python 2007-10-27 20:24:17 +00:00
Christophe Dumez
ebc738e3a5 - Updated Turkish translation 2007-10-19 22:27:00 +00:00
Christophe Dumez
713474bc43 - Bump to rc6 2007-10-19 21:25:17 +00:00
Christophe Dumez
265a8cada8 - Fixed ETA display 2007-10-19 20:38:00 +00:00
Christophe Dumez
138af31ef9 - BUGFIX: Remember scan directory in program preferences now 2007-10-19 16:08:05 +00:00
Christophe Dumez
a5f6663e65 - BUGFIX: Fixed deletion of subfolders when deleting torrents from hard drive 2007-10-19 16:00:42 +00:00
Christophe Dumez
1519bca46d - Fixed folder progress calculation in torrent properties (closes #154387) 2007-10-19 15:51:13 +00:00
Christophe Dumez
03719cbb87 - Simplified code 2007-10-18 18:30:04 +00:00
Christophe Dumez
98825613fa - Fixed spanish translation 2007-10-17 16:18:40 +00:00
Christophe Dumez
47abadfc67 - Fixed a typo in french translation 2007-10-17 15:47:49 +00:00
Christophe Dumez
a220e01e2e - FEATURE: Added a button to clear search pattern
- I18N: Fixed swedish translation
2007-10-14 12:21:51 +00:00
Christophe Dumez
dea9237aa0 - BUGFIX: Fixed minimize to tray feature 2007-10-14 09:23:29 +00:00
Christophe Dumez
6099544da5 - BUGFIX: configure doesn't require paths with a terminal "/" anymore 2007-10-14 09:15:02 +00:00
Christophe Dumez
902116cbc8 - BUGFIX: configure looks for libraries in lib64 folders too 2007-10-14 09:09:19 +00:00
Christophe Dumez
96a6f450d0 - Make use of this: added option to delete files from disk as a torrent is removed (libtorrent) 2007-10-13 08:54:46 +00:00
Christophe Dumez
6ed565a06b - COSMETIC: Improved progress bar text rendering 2007-10-13 08:32:31 +00:00
Christophe Dumez
1fbbee794c - BUGFIX: Fixed "Automatically start seeding" feature in torrent creation tool 2007-10-12 18:28:30 +00:00
Christophe Dumez
bfab6389b5 - Commented fast resume rejected alert until #182 is fixed in libtorrent 2007-10-12 11:54:29 +00:00
Christophe Dumez
26a4040003 - BUGFIX: Fixed "Missing Input path" error when creating a torrent
- BUGFIX: Fixed some notification messages for torrent addition dialog
2007-10-12 11:50:02 +00:00
Christophe Dumez
e7ac721b3c - Updated TODO 2007-10-11 18:34:14 +00:00
Christophe Dumez
48f5436f6f - Improved ETA calculation code a little and fixed a little typo in the code
- Updated TODO (waiting for a bug fix in libtorrent)
2007-10-10 20:29:07 +00:00
Christophe Dumez
f754e34e35 - BUGFIX: Fixed possible overflow in ETA calculation 2007-10-10 19:57:24 +00:00
Christophe Dumez
9bb18e1a07 - reverted src.pro 2007-10-10 19:17:25 +00:00
Christophe Dumez
0245bbf5ab - BUGFIX: Fixed an ETA calculation problem when the torrent has filtered files 2007-10-10 19:10:34 +00:00
Christophe Dumez
0a0c1f3529 - BUGFIX: AddInPause setting doesn't pause downloads on startup anymore (real fix this time...) 2007-10-10 17:54:09 +00:00
Christophe Dumez
be94c86350 - Revert a change in src.pro I didn't mean to commit 2007-10-10 17:36:02 +00:00
Christophe Dumez
a26333bc65 - BUGFIX: Now filtered don't appear on hard drive anymore (libtorrent >= r1659 REQUIRED)
- BUGFIX: AddInPause setting doesn't pause downloads on startup anymore
2007-10-10 17:34:52 +00:00
Christophe Dumez
4c862597ae - Updated Japanese translation
- rc4 release
2007-10-06 20:00:13 +00:00
Christophe Dumez
937d45d850 - Use system's default style as a default instead of Plastique style 2007-10-03 19:18:55 +00:00
Christophe Dumez
20b6579392 - BUGFIX: Updated INSTALL file
- BUGFIX: Optimized torrent real size calculation
2007-10-01 19:43:24 +00:00
Christophe Dumez
4f25e6c769 - Another attempt to fix compilation on FreeBSD
- Fixed IP Filter preferences (closes #147532)
2007-10-01 09:47:00 +00:00
Christophe Dumez
ce3b8733d1 BUGFIX: Fixed a proxy problem causing connections to be rejected by trackers 2007-09-30 17:46:47 +00:00
Christophe Dumez
b0140fbdbe - We have an optimized way to get the torrent actual size using libtorrent but this is buggy. Hence we don't use it yet. 2007-09-29 08:32:22 +00:00
Christophe Dumez
abcd2b7600 - Ok, Now I'm pretty sure I fixed the compilation problem on FreeBSD 2007-09-29 08:13:20 +00:00
Christophe Dumez
f9998957cd - attempt to fix compilation on FreeBSD 2007-09-29 08:00:14 +00:00
Christophe Dumez
acb8d5679f - rc2 release 2007-09-27 19:15:41 +00:00
Christophe Dumez
c3d3156ec7 - BUGFIX: Fixed search engine plugins update 2007-09-27 19:09:32 +00:00
Christophe Dumez
09abd303bd - Updated plugin version in text file 2007-09-27 18:51:06 +00:00
Christophe Dumez
0678e2e2bd - Fixed mininova search engie plugin 2007-09-27 18:47:26 +00:00
Christophe Dumez
00dbf7ba38 - Updated italian and korean translations
- Fixed infoBar text when adding a torrent
2007-09-27 18:25:37 +00:00
Christophe Dumez
42cacabccd - BUGFIX: Fixed a unsupported character in man page 2007-09-26 18:32:17 +00:00
Christophe Dumez
3d04a944b6 - rc1 release
- disabled debug mode
2007-09-25 17:50:04 +00:00
Christophe Dumez
b02e2c2f9b Updated Hungarian translation 2007-09-24 21:01:46 +00:00
Christophe Dumez
5c0f17bf31 - Fixed a problem in log text color (introduced very recently) 2007-09-24 18:56:14 +00:00
Christophe Dumez
ac9a81985f - Fixed error in last commit 2007-09-24 18:35:35 +00:00
Christophe Dumez
a46c63d883 - Updated spanish translation
- Log text default color uses skin foreground color instead of black now
2007-09-24 18:08:38 +00:00
Christophe Dumez
09a696fc27 updated translations 2007-09-22 13:32:31 +00:00
Christophe Dumez
dedc54d26f - Updated TODO 2007-09-21 20:06:04 +00:00
Christophe Dumez
c0ffb8fa5c - BUGFIX: Fixed overflow in ratio 2007-09-21 07:45:28 +00:00
Christophe Dumez
3e350c5935 - Updated some translation
- Added -NDEBUG to src.pro to fix compilation problem with libtorrent svn
2007-09-20 20:57:41 +00:00
Christophe Dumez
da244d7ef2 - Added more debug when we get a file_error 2007-09-18 22:41:23 +00:00
Christophe Dumez
2fc7039cc7 - COSMETIC: Progress bar text now uses style foreground color 2007-09-18 22:09:06 +00:00
Christophe Dumez
654497cd4a - Disable debug in libtorrent when qBittorrent is in release mode 2007-09-18 20:01:31 +00:00
Christophe Dumez
bdf50483df - Attempt to make progress bar text color dynamic 2007-09-18 19:08:09 +00:00
Christophe Dumez
8a0681744e - Improved tracker deletion code slightly 2007-09-18 17:27:01 +00:00
Christophe Dumez
2699c76afd Updated japanese 2007-09-18 06:52:41 +00:00
Christophe Dumez
773064a081 - beta7 release 2007-09-17 19:50:47 +00:00
Christophe Dumez
7718403419 - Perfected chinese translation 2007-09-17 19:42:31 +00:00
Christophe Dumez
26b4d31810 - Updated a lot of translations 2007-09-17 19:16:12 +00:00
Christophe Dumez
f8dfda0893 - Updated resource files 2007-09-16 19:59:54 +00:00
Christophe Dumez
e8897ae159 - Fixed configure 2007-09-16 19:58:07 +00:00
Christophe Dumez
2f71f9f51a - Updated russian translation 2007-09-16 18:37:24 +00:00
Christophe Dumez
fc595f49d8 - Updated slovak translation 2007-09-16 16:51:56 +00:00
Christophe Dumez
92444fccf4 - Updated swedish translation 2007-09-16 15:15:44 +00:00
Christophe Dumez
6d0aebe9cb - Edit a bit of code in torrent permanent deletion to make sure all files are actually deleted 2007-09-16 15:13:32 +00:00
Christophe Dumez
ef7af6bad6 - Fixed torrent permanent deletion from hd
- Updated Romanian translation
2007-09-16 15:10:25 +00:00
Christophe Dumez
c1a8a58080 - Updated TODO 2007-09-16 14:27:13 +00:00
Christophe Dumez
76047f4ef2 - Fixed transfers list interval setting 2007-09-16 14:25:24 +00:00
Christophe Dumez
9062266a84 - Fixed a ratio assert in libtorrent because we sent it -1 for unlimited instead of 0 2007-09-16 14:16:42 +00:00
Christophe Dumez
9cdcd53234 - Completed french translation 2007-09-16 14:02:06 +00:00
Christophe Dumez
419b94f042 - A lot of improvement and bug fixes in new torrent content selection 2007-09-16 13:33:41 +00:00
Christophe Dumez
3cb34ed7ee - Fixed an overflow that could cause ETA to become negative sometimes (hitted an assert) 2007-09-16 12:30:41 +00:00
Christophe Dumez
925ecb3464 - Fixed search engines plugins saving 2007-09-16 12:08:26 +00:00
Christophe Dumez
488bd90303 - Fixed a bug in torrent content selection when there is only one file in the torrent 2007-09-16 09:41:05 +00:00
Christophe Dumez
c478ba59ac - new torrent content selection (as a tree). Merge from the new-torrent-selection branch 2007-09-16 09:19:22 +00:00
Christophe Dumez
fe7c0db425 - remove ratio should be applied to finished torrent only (and disabled as a default!) - FIXED 2007-09-13 19:50:14 +00:00
Christophe Dumez
b2bf7047d9 - Fixed search resource file 2007-09-13 19:34:21 +00:00
Christophe Dumez
e943449b42 - Updated TODO, spotted a bug 2007-09-13 18:48:52 +00:00
Christophe Dumez
69e2355ff4 Update language files 2007-09-11 19:32:37 +00:00
Christophe Dumez
b7ea2fb51a - Allow to download plugins from their url 2007-09-11 19:31:21 +00:00
Christophe Dumez
4c880fea09 - Improved tooltip title style 2007-09-11 18:49:24 +00:00
Christophe Dumez
a0e895641c - Improved systray tooltip a little 2007-09-11 11:55:58 +00:00
Christophe Dumez
484f1c36c9 - Improved systray style 2007-09-10 20:25:31 +00:00
Christophe Dumez
982ce5c0ad - Updated TODO 2007-09-09 20:12:54 +00:00
Christophe Dumez
7ac5da0acc - Updated TODO 2007-09-09 20:10:49 +00:00
Christophe Dumez
9733716136 - Updated language files 2007-09-09 20:08:53 +00:00
Christophe Dumez
eebdc26e5a - FEATURE: Articles in a RSS feed are now ordered by date (newer at the top)
- FEATURE: Read articles in a feed are not resetted when the feed is refreshed anymore
2007-09-09 20:02:49 +00:00
Christophe Dumez
1f8b9378a3 - FEATURE: Display RSS article date and author if available 2007-09-09 19:19:33 +00:00
Christophe Dumez
b99b838827 - Fix in rss refresh and mark all as read 2007-09-09 17:02:12 +00:00
Christophe Dumez
c4d143c2c0 - Added some RSS preferences 2007-09-09 15:46:23 +00:00
Christophe Dumez
db1bd53f44 - Fixed a typo in RSS 2007-09-09 12:23:29 +00:00
Christophe Dumez
07dc182053 - FEATURE: Added 'Mark all as read' function for RSS feeds 2007-09-09 11:31:51 +00:00
Christophe Dumez
563055e891 Updated language files 2007-09-09 09:47:59 +00:00
Christophe Dumez
b3de2ccc72 - Small fix for proxy options 2007-09-09 09:42:30 +00:00
Christophe Dumez
f4d5ceb3c4 - Fixed a unit problem in last commit 2007-09-09 09:36:10 +00:00
Christophe Dumez
70beef9f94 - FEATURE: Added an option to display current transfer speeds in title bar 2007-09-09 09:35:30 +00:00
Christophe Dumez
47c1908519 - Added some more debug 2007-09-09 09:20:01 +00:00
Christophe Dumez
e1ead940be - Added some more debug 2007-09-09 09:15:29 +00:00
Christophe Dumez
862d24ac48 - FEATURE: Added an option to automatically delete torrents when they reach a given ratio (>= 1.0) 2007-09-09 09:09:24 +00:00
Christophe Dumez
078c80c81d - FEATURE: Added an option to set the max number of connections per torrent
- FEATURE: Added an option to set the max number of uploads per torrent
2007-09-09 07:44:22 +00:00
Christophe Dumez
6ba4588e62 Updated language files 2007-09-08 17:11:08 +00:00
Christophe Dumez
cd70843ee9 - Totally redesigned program preferences
- Added some options, the following are already implemented:
  * Start/Stop LSD/NAT-PMP/UPnP
	* Force preallocation of all files
	* Force new torrents status to pause
- Other new features are going to be implemented soon
2007-09-08 17:07:29 +00:00
Christophe Dumez
cb8ecb74bf - Fixed a bug introduced recently in torrent addition dialog 2007-09-04 04:27:52 +00:00
Christophe Dumez
9f36d521a4 - BUGFIX: Fixed deprecation warning with latest libtorrent svn
- FEATURE: Redesigned torrent creation dialog
- FEATURE: Allow to set piece size when creating a torrent
- improved new options dialog a little
2007-09-04 04:18:51 +00:00
Christophe Dumez
2c2c1093c3 - Reworked options UI file. Now I need to rewrite the code 2007-09-04 02:20:28 +00:00
Christophe Dumez
0e81f3731f - Dropped Qt4.2 support, it becomes too difficult to maintain for me and Trolltech broke backward compatibility for UI files... 2007-09-03 22:59:46 +00:00
Christophe Dumez
f1114387ae - Updated TODO 2007-09-03 22:54:19 +00:00
Christophe Dumez
54516ac231 - In torrent content selection, check if all files are filtered before saving and display an error if it is the case. I removed this checking on right click menu in case people want to filter all torrents, then add one, then save. 2007-09-03 22:52:58 +00:00
Christophe Dumez
913f93ba82 - Updated language files
- Fixed a typo in french translation
- Updated Hungarian translation
2007-09-03 22:38:37 +00:00
Christophe Dumez
11c7255da6 - Added a lot of stuff to TODO list 2007-09-03 22:33:37 +00:00
Christophe Dumez
69fa916e26 - FEATURE: Added zip support in search plugins manager (can put .py & .png inside) 2007-09-03 22:05:40 +00:00
Christophe Dumez
d86335a58e - Rename fake zip files to pyqBT because we will add real zip support soon 2007-09-03 17:58:23 +00:00
Christophe Dumez
24dced2411 - BUGFIX: the function that set the rows color doesn't handle hidden columns anymore
- BUGFIX: improved search engine plugin manager code and fixed bugs
2007-09-03 17:45:16 +00:00
Christophe Dumez
1b71a4a4a4 - Updated TODO 2007-09-03 17:18:31 +00:00
Christophe Dumez
ffedffcead - Updated Itralian, greek and bolgarian translations 2007-09-03 11:14:11 +00:00
Christophe Dumez
1f64e14195 updated french translation 2007-09-02 17:08:55 +00:00
Christophe Dumez
d6a5b1d321 updated language files 2007-09-02 17:05:26 +00:00
Christophe Dumez
792101731f - BUGFIX: Fixed torrent create (can only one file or one folder) 2007-09-02 17:03:33 +00:00
Christophe Dumez
3e783873ec - BUGFIX: Made pause/resume all function affect both (dl/up) tabs when window is hidden 2007-09-02 14:57:07 +00:00
Christophe Dumez
ffb262f0a1 - Fixed log context menu position
- Updated Changelog
2007-09-02 14:42:09 +00:00
Christophe Dumez
4727c1bdca - Updated remove icon 2007-09-02 14:29:43 +00:00
Christophe Dumez
1f1e37ce76 - Updated bug report icon 2007-09-02 14:14:22 +00:00
Christophe Dumez
f40337d2e3 - Updated cryptographie icon 2007-09-02 13:53:34 +00:00
Christophe Dumez
ecc5106f07 - Updated TODO 2007-09-02 13:32:14 +00:00
Christophe Dumez
1b93f4eaf1 - Fixed a little bug in last commit 2007-09-02 13:23:02 +00:00
Christophe Dumez
685ceafc5b - second attempt for drag n drop 2007-09-02 13:19:30 +00:00
Christophe Dumez
cf6128a222 - Fixed drag'ndrop on non-KDE systems 2007-09-02 13:06:42 +00:00
Christophe Dumez
f78c74c1b5 - Updated checking icon 2007-09-02 12:50:38 +00:00
Christophe Dumez
faeee49517 - Use RSS (un)subscribe icons 2007-09-02 12:44:09 +00:00
Christophe Dumez
1918969e28 - Updated RSS icon with one from Oxygen (KDE4 icons) 2007-09-02 12:12:51 +00:00
Christophe Dumez
fa9e3bf564 Updated french translation 2007-09-02 09:37:18 +00:00
Christophe Dumez
8eac154c05 Updated language files 2007-09-02 09:32:59 +00:00
Christophe Dumez
ff12c76a62 - Updated TODO 2007-09-02 09:12:26 +00:00
Christophe Dumez
2c27f952e2 - FEATURE: Allow to drag'n drop plugin to list for install/update
- Added some debug
2007-09-02 09:01:22 +00:00
Christophe Dumez
e3214a9b6a - Updated TODO 2007-09-02 08:23:59 +00:00
Christophe Dumez
4a02d171b4 - BUGFIX: 'Unknown' is now displayed in search results columns where value is -1
- BUGFIX: Improved search engine core a little
- BUGFIX: Forgot to remove *.pyc files when uninstalling a search plugin
2007-09-02 07:58:25 +00:00
Christophe Dumez
7a16a1d8f1 - updated language files 2007-09-02 06:53:55 +00:00
Christophe Dumez
ecc41fbc60 - Display "Unknown" in search engine result columns where value is -1 2007-09-02 06:39:55 +00:00
Christophe Dumez
0125a2b521 - Updated polish translation 2007-09-01 23:05:56 +00:00
Christophe Dumez
d328b93c1a - Updated swedish and German translations 2007-09-01 23:01:15 +00:00
Christophe Dumez
ab588b741e Paused torrents could be displayed as connected for a sec after checking 2007-09-01 22:57:50 +00:00
Christophe Dumez
1588cd5d3d - Updated Ukrainian translation 2007-09-01 12:24:40 +00:00
Christophe Dumez
a597f067e2 - Updated french and dutch translations
- Fixed some typos in engineSelect
- Made search engine plugin install more reliable
- Added some comments
2007-09-01 10:23:39 +00:00
Christophe Dumez
0778f2a19e - Updated Russian translation 2007-08-31 21:32:30 +00:00
Christophe Dumez
6c0d4b9439 - Dropped Hong Kong flag 2007-08-31 17:39:41 +00:00
Christophe Dumez
98d91f7697 - beta6 release 2007-08-31 17:15:38 +00:00
Christophe Dumez
f7ac4ec652 - Updated Italian translation 2007-08-31 16:56:21 +00:00
Christophe Dumez
43b96ea4f2 - Updated slovak translation 2007-08-31 16:55:00 +00:00
Christophe Dumez
91bd5f1d8e - Updated Changelog 2007-08-31 16:51:02 +00:00
Christophe Dumez
f0edd7dcf7 - Added multipage support for mininova 2007-08-31 16:39:29 +00:00
Christophe Dumez
e3f2480fe5 - Added multipage support to btjunkie plugin 2007-08-31 16:15:39 +00:00
Christophe Dumez
26e5785754 - Fixed plugin update && fixed btjunkie search plugin 2007-08-31 16:02:01 +00:00
Christophe Dumez
db12fb292a - Updated French translation 2007-08-31 14:25:07 +00:00
Christophe Dumez
798ee52de1 - Added some more debug 2007-08-31 14:08:47 +00:00
Christophe Dumez
b1f562d7c0 - Fixed a bug in previous commit
- Added some debug
2007-08-31 13:39:27 +00:00
Christophe Dumez
41daeb4c19 - Added a messagebox when plugin are already up to date 2007-08-31 13:35:55 +00:00
Christophe Dumez
d66b788e5f - Update translation files 2007-08-31 12:11:38 +00:00
Christophe Dumez
ff4ab915a2 - Merged custom-search branch. New search plugins management system 2007-08-31 12:06:31 +00:00
Christophe Dumez
b7fd7d9837 - Fixed memory leak in GUI 2007-08-30 22:42:02 +00:00
Christophe Dumez
89670af7c9 - Updated Romanian translation 2007-08-30 18:51:05 +00:00
Christophe Dumez
10a13195b3 - Updated dutch translation 2007-08-30 13:46:42 +00:00
Christophe Dumez
0f34a98350 - Updated dutch translator 2007-08-30 13:36:47 +00:00
Christophe Dumez
59279aa43a - Ok. Jarek confirmed that Qt4.2 compatibility is back :) 2007-08-30 11:04:51 +00:00
Christophe Dumez
11198208eb - Updated TODO 2007-08-30 10:36:46 +00:00
Christophe Dumez
4a2c7efb27 FEATURE: Replaced Meganova search engine by TorrentReactor 2007-08-30 10:25:27 +00:00
Christophe Dumez
3ea344cb2e attempt to fix toolbar with Qt4.2 2007-08-30 06:48:47 +00:00
Christophe Dumez
dff33dbfb1 - Should fix a layout problem with the infoBar and Qt4.2 (need confirmation) 2007-08-29 19:03:53 +00:00
Christophe Dumez
ed6cad6d1b - Updated TODO 2007-08-29 16:24:47 +00:00
Christophe Dumez
b582ec9480 - BUGFIX: Do not store and calculate ETA values for paused torrents 2007-08-29 16:23:37 +00:00
Christophe Dumez
b5ccf05541 - BUGFIX: Do not store and calculate ETA values for finished torrents 2007-08-29 16:15:11 +00:00
Christophe Dumez
b3c5e6cfa2 - Store less ETA values for each torrent in order to save memory 2007-08-29 16:11:24 +00:00
Christophe Dumez
229927bbe9 - BUGFIX: Fixed file preview and improved previewable files detection 2007-08-29 16:07:37 +00:00
Christophe Dumez
495d6f2bab - Save less trackers errors to save memory 2007-08-29 15:13:20 +00:00
Christophe Dumez
a9f1bd4f74 - Refresh list every 1500ms instead of 2000ms 2007-08-29 15:05:57 +00:00
Christophe Dumez
73c247fe10 BUGFIX: Fixed pause state toggle for paused and checking torrents 2007-08-29 15:04:30 +00:00
Christophe Dumez
bd84cb197f - little optimization for torrentstopauseafterchecking 2007-08-29 15:00:31 +00:00
Christophe Dumez
57309c7d82 - Do not save paused torrents in a list anymore to save some memory 2007-08-29 14:54:03 +00:00
Christophe Dumez
27e76962d1 - Found a way not to use FullAllocationMode list in order to save memory in cpu 2007-08-29 14:30:30 +00:00
Christophe Dumez
db6180b737 - Little hint for windows 2007-08-29 14:05:59 +00:00
Christophe Dumez
6918aba90c - Use "Magick++-config --libs" to get linking libs instead of pkg-config because some distros (like Mandriva) do not provide ImageMagick++.pc 2007-08-29 14:04:45 +00:00
Christophe Dumez
17b8f76dda - UpdateRatio only when it is displayed
- Resample favicon to 16x16 before displaying it for better quality
- Updated TODO
2007-08-29 13:45:51 +00:00
Christophe Dumez
ea3a635d49 - Updated Greek translation 2007-08-29 12:57:00 +00:00
Christophe Dumez
2ddcaf008b - Improved ImageMagick detection and it should be able to build without it too now 2007-08-29 10:20:39 +00:00
Christophe Dumez
99268bfc06 - Added .ico support, which is really useful for RSS favicons. We use libMagick++ in order to convert ICO icons to PNG. If this library is not installed, qBittorrent will still compile but this feature will be disabled. 2007-08-29 09:22:21 +00:00
Christophe Dumez
19c606e067 - Removed outdated define 2007-08-29 06:35:47 +00:00
Christophe Dumez
057029787a - Added some asserts to check for overflows
- Removed a useless functions (was used for debug)
- Fixed 2 warnings in createTorrent.ui
- Improved CXX_FLAGS in src.pro
2007-08-29 06:33:27 +00:00
Christophe Dumez
06cb5ff4c6 - Second attempt to fix Qt4.2 COMPATIBILITY 2007-08-29 03:58:01 +00:00
Christophe Dumez
f67eb47f8c - Updated TODO 2007-08-28 19:37:30 +00:00
Christophe Dumez
7921adbcf9 - Cleaned torrent progress asserts 2007-08-28 19:22:05 +00:00
Christophe Dumez
63334ea6fb - Optimized a lot torrent real size calculation 2007-08-28 19:10:35 +00:00
Christophe Dumez
cdfaed4fb4 BUGFIX: ETA was wrong for torrents with filtered files 2007-08-28 18:49:45 +00:00
Christophe Dumez
21908e0a03 - Optimized function that transform a number of seconds to a duration(days, hours, minutes, secs)
- Improved ETA calculation to avoid overflows (Added asserts to make sure it doesn't happen)
2007-08-28 18:44:54 +00:00
Christophe Dumez
105563ac5a - Fixed a bug in last commit in qBittorrentPath()
- Optimized float to string conversions
2007-08-28 18:05:20 +00:00
Christophe Dumez
c064e5877c - Optimised GUI class a little 2007-08-28 17:33:00 +00:00
Christophe Dumez
29a290264e - updated resources files 2007-08-28 17:05:12 +00:00
Christophe Dumez
08a57d267b - some optimizations 2007-08-28 17:03:55 +00:00
Christophe Dumez
01df4d3c81 - Use int instead of short where possible 2007-08-28 16:55:14 +00:00
Christophe Dumez
6ecb45d661 - Code optimization using initialization lists
- Removed Traditional Chinese translation because we lost our translator and translation is outdated
2007-08-28 16:17:32 +00:00
Christophe Dumez
c6b25e5f79 - Should fix compatibility with Qt4.2 2007-08-28 14:49:57 +00:00
Christophe Dumez
39feb335a4 BUGFIX: Display the torrent that are being checked as 'checking' in seeding list 2007-08-28 14:30:24 +00:00
Christophe Dumez
b90012e431 - Updated TODO 2007-08-28 14:18:31 +00:00
Christophe Dumez
71599c0f9f - Made finished list menu more similar to the download list one
- Fixed Start/Pause actions in lists context menus
2007-08-28 14:18:09 +00:00
Christophe Dumez
20a8b3f418 - Updated language files 2007-08-27 18:28:13 +00:00
Christophe Dumez
3b03b385f3 - removed some useless includes 2007-08-27 13:34:41 +00:00
Christophe Dumez
c7592a6dc8 - prevent downloadFromUrl flooding 2007-08-27 10:06:13 +00:00
Christophe Dumez
8f7de730cc - Added some more torrent_handle checking to be sure we don't use invalid ones 2007-08-27 09:24:22 +00:00
Christophe Dumez
e4795cd64b - removed bad assert 2007-08-27 08:39:04 +00:00
Christophe Dumez
fd2ee35e92 - Do not save torrent related info in class destruction, this is too dangerous 2007-08-26 19:58:41 +00:00
Christophe Dumez
8404eec301 - Force progress update in download list before calling sort function to make it more reliable 2007-08-26 19:52:10 +00:00
Christophe Dumez
cc252fc70a - Fix progress column delayed sorting 2007-08-26 19:33:08 +00:00
Christophe Dumez
89ecdca5e7 Compile with -O2 in release mode and -O1 in debug mode 2007-08-26 19:30:27 +00:00
Christophe Dumez
1bfc181cb2 - Better handing of .finished files (bittorrent class level instead of GUI level) 2007-08-26 19:17:50 +00:00
Christophe Dumez
124fa3c8ed BUGFIX: Showing checking progress for paused torrents too 2007-08-26 18:59:27 +00:00
Christophe Dumez
28294efadf - Check if the hash read from the filename and from the torrent are the same and don't add it if it is different. Safer 2007-08-26 18:50:51 +00:00
Christophe Dumez
829c358f10 - fixed some bugs introduced recently
- improved debug output
2007-08-26 18:41:45 +00:00
Christophe Dumez
35a9fab3b4 - Check if priorities file exists before trying to read it to avoid a warning message 2007-08-26 17:48:38 +00:00
Christophe Dumez
4e2ebe5a69 - Fixed torrent switching to finished tab 2007-08-26 17:25:37 +00:00
Christophe Dumez
366d5108c4 - I thought there was a memory leak here but it crashes when I delete it so.. 2007-08-26 16:30:52 +00:00
Christophe Dumez
7dc7cea31b - Updated TODO. GUI splitting was planned for v1.1.0 but it is already in v1.0.0beta6 after all :) 2007-08-26 16:29:06 +00:00
Christophe Dumez
32c330092a - Merged splitGUI branch, GUI and download tab are now splitted. Code is a lot cleaner and easier to understand. I also fixed some bugs I found on the way :) 2007-08-26 16:25:22 +00:00
Christophe Dumez
36e2cb6f68 - Updated TODO 2007-08-26 16:21:16 +00:00
Christophe Dumez
cebb5fc1fe - dropped Threaded branch
- Added a function to torrent_handle wrapper for debug use
2007-08-24 12:25:52 +00:00
Christophe Dumez
1ad2495896 - Updated polish translation 2007-08-23 15:49:39 +00:00
Christophe Dumez
e82cb2188e - Made torrent deletion from hard-drive safer 2007-08-23 14:04:53 +00:00
Christophe Dumez
680f6409d8 - beta5 release 2007-08-23 04:01:17 +00:00
Christophe Dumez
cfacac7dbf - Add torrents in pause before applying settings to avoid race conditions
- Started to work on a new function to delete torrents permanently that is safer. Not used yet because it is buggy : it works only for simple cases and I'm not sure I can do better right now with the info libtorrent is providing.
2007-08-22 18:26:00 +00:00
Christophe Dumez
8ce1a4c3df - Updated Korean translation 2007-08-22 03:58:05 +00:00
Christophe Dumez
6ee9152b21 - Handling progress bar text painting ourselves because some styles really don't handle it well (cleanlooks...) 2007-08-21 17:33:06 +00:00
Christophe Dumez
d8dd509a7b - Updated Russian translation 2007-08-21 07:17:13 +00:00
Christophe Dumez
4c5c1d49c2 - Updated german translation 2007-08-20 11:47:26 +00:00
Christophe Dumez
8ba1cb329d - Improved unicode support a bit 2007-08-20 07:03:41 +00:00
Christophe Dumez
a28160bcaa - Fixed a bug when deleting a torrent from finished list (just introduced) 2007-08-20 06:41:36 +00:00
Christophe Dumez
c9925eddb6 - Big code cleanup
- Added a Qwrapper for torrent_handle to make code more readable
2007-08-20 06:29:18 +00:00
Christophe Dumez
5946f20783 - Updated beta5 changelog 2007-08-19 16:51:23 +00:00
Christophe Dumez
a4a98e3ada - Added some checking before adding torrents to finished/download lists to avoid duplicate in some circumstances 2007-08-19 16:50:05 +00:00
Christophe Dumez
a01c7e2c60 - Improved finished torrents code a little 2007-08-19 16:45:05 +00:00
Christophe Dumez
2bf0aba48a - improved some asserts for progress checking 2007-08-19 16:33:37 +00:00
Christophe Dumez
7030f85826 - Added an assert to check that progress value is < 100%
- Modified a test due to a bug in libtorrent for #133480
2007-08-19 14:48:16 +00:00
Christophe Dumez
5066819c58 - Added some more assert to be sure progress value is under 100% 2007-08-19 14:39:40 +00:00
Christophe Dumez
5231f5a22b - Rewrote a lot of code concerning finishedTorrents code. It was optimized and should be safer too 2007-08-19 14:20:54 +00:00
Christophe Dumez
de8c3158fe - Make use of qDeleteAll() function from Qt4 2007-08-19 13:00:51 +00:00
Christophe Dumez
04352cce3c - Fixed bad assert
- Little checking before saving url seeds list
- Little optimization to make fastresume data saving faster
2007-08-19 08:45:24 +00:00
Christophe Dumez
5315ba7894 - Fixed french translation 2007-08-18 12:50:48 +00:00
Christophe Dumez
2ce097ec77 - Fixed keyboard shortcuts for third tab (closes #127942) 2007-08-18 12:43:21 +00:00
Christophe Dumez
d025a2ea36 - Updated TODO (preview is working in seeding list now) 2007-08-18 06:00:18 +00:00
Christophe Dumez
a4d24fd4a7 - Updated TODO
- Last commit allows to remove url seeds now too (forgot)
2007-08-18 05:56:59 +00:00
Christophe Dumez
b2867e97bf - Updated spanish translation 2007-08-18 05:55:09 +00:00
Christophe Dumez
98159eaa1b - Updated TODO 2007-08-17 04:10:23 +00:00
Christophe Dumez
b4fbaaa47c BUGFIX: Improved incremental download 2007-08-17 02:22:04 +00:00
Christophe Dumez
df8c591edd - Updated todo 2007-08-17 02:14:37 +00:00
Christophe Dumez
13f21ef6cd - Make use of new torrent_checked_alert that was just included in libtorrent. This allowed to improve torrent that just finished checking handling and progress column sorting. Also allowed to optimize cpu/memory usage a little. 2007-08-17 02:03:13 +00:00
Christophe Dumez
55834ba5db - Fixed session ratio value: was either 10. or 1. (closes #133026) 2007-08-16 23:46:45 +00:00
Christophe Dumez
417d8a777b - Updated portuguese and brazilian translations 2007-08-16 08:59:31 +00:00
Christophe Dumez
38b008a2ac - Updated slovak translation 2007-08-16 08:54:49 +00:00
Christophe Dumez
38283882e9 - Updated Japanese translation 2007-08-16 04:09:39 +00:00
Christophe Dumez
85055c1ef9 - Updated ToDO 2007-08-15 19:59:17 +00:00
Christophe Dumez
36e87952fa - BUGFIX: Wait for torrent_paused_alert before reloading a torrent for full allocation mode 2007-08-15 19:41:12 +00:00
Christophe Dumez
d5fa6cefe4 - Removed some debug
- Updated Changelog (now libtorrent supports Bittorrent FAST extension)
2007-08-15 19:17:17 +00:00
Christophe Dumez
12fd87ab85 - Removed some debug (didn't mean to commit that) 2007-08-11 14:54:24 +00:00
Christophe Dumez
47b42c1c90 - Updated TODO (changelog beta5) 2007-08-11 14:50:29 +00:00
Christophe Dumez
31abae33a1 - Improved the way menu icons are installed to avoid problems on some systems (Thanks JanCR for reporting this)
- Fixed version in desktop file
2007-08-11 14:47:52 +00:00
Christophe Dumez
7b8722df34 - Updated TODO 2007-08-09 06:59:21 +00:00
Christophe Dumez
eda115249a - Updated Italian translator 2007-08-09 06:43:42 +00:00
Christophe Dumez
aa4c53ec43 - Fixed assert so that it doesn't crash when we toggle paused state of a torrent several times and quickly 2007-08-09 05:10:39 +00:00
Christophe Dumez
44d61e0b9d - Fixed overflow that caused ratio to become negative
- Added some more asserts so that it doesn't happen again
- Fixed waiting for paused_alert on exit in the case where a torrent was paused then resumed before we received torrent_paused_alert
2007-08-09 05:03:06 +00:00
Christophe Dumez
c51abd9096 - Updated TODO 2007-08-08 12:43:58 +00:00
Christophe Dumez
320c125d17 - Added some more debug 2007-08-08 07:35:57 +00:00
Christophe Dumez
8b26b7fd48 - BUGFIX: Fixed progress column delayed sorting (after torrent finished checking) 2007-08-07 23:15:46 +00:00
Christophe Dumez
f9c357b52d - Wait for torrent_paused_alert before saving fast resume data 2007-08-07 23:00:51 +00:00
Christophe Dumez
3494702437 - Fixed include again 2007-08-07 22:29:46 +00:00
Christophe Dumez
3100c4afc9 - Added missing include 2007-08-07 22:26:58 +00:00
Christophe Dumez
60923e81c6 - Updated TODO
- Removed useless include in downloadThread
2007-08-07 22:14:23 +00:00
Christophe Dumez
06a2f2ad1f - Updated polish translation 2007-08-07 10:25:36 +00:00
Christophe Dumez
d02edebb58 - Fixed italian trannslation 2007-08-05 17:36:26 +00:00
Christophe Dumez
a9692dbe60 - Changed the way progress bars are rendered 2007-08-04 22:14:17 +00:00
Christophe Dumez
bee1dbeea4 BUGFIX: Finished torrents were still displayed as checking when paused by libtorrent on full disk (hit an assert) 2007-08-04 18:26:42 +00:00
Christophe Dumez
9ba0c7ebba - Updated Italian translation 2007-08-04 11:32:19 +00:00
Christophe Dumez
b702bea806 - beta4 release 2007-08-04 06:23:44 +00:00
Christophe Dumez
ff756a2b1f - Some fixes in bandwidth allocation per torrent dialog 2007-08-04 05:29:35 +00:00
Christophe Dumez
8e6b1be322 - updated TODO 2007-08-03 18:24:36 +00:00
Christophe Dumez
d74a095186 - Updated TODO with beta3->beta4 changelog 2007-08-03 18:20:01 +00:00
Christophe Dumez
037fc69c34 - Updated language files 2007-08-03 15:37:42 +00:00
Christophe Dumez
969d9d5f69 - Fixed debug output 2007-08-03 15:17:34 +00:00
Christophe Dumez
db9bc24b5f - rss feeds are now updated automatically every 10 minutes 2007-08-03 15:16:42 +00:00
Christophe Dumez
86d38efcb2 - Allow to delete rss streams using "Del" key 2007-08-03 15:02:16 +00:00
Christophe Dumez
533aeb3f8b - Allow to select multiple rss feeds at once
- Fixed an icon problem when a feed refreshing fails
2007-08-03 14:51:32 +00:00
Christophe Dumez
dcb6642394 - Mostly rewritten RSS part
* Fixed a lot of bugs
	* Improved CPU & memory usage
	* Improved usability
Please report any bug you may experience.
2007-08-03 14:37:56 +00:00
Christophe Dumez
2589d4e682 - Fixed layout again for about 2007-08-02 18:20:13 +00:00
Christophe Dumez
b2eec9a765 - Fied layout a little (broken by arnaud) 2007-08-02 18:10:31 +00:00
Christophe Dumez
e569fdd2c0 - Added arnaud to thanks page 2007-08-02 18:03:47 +00:00
Arnaud Demaiziere
fff4ad529c port properties.ui to qt 4.2 2007-08-02 17:51:45 +00:00
Christophe Dumez
ab63fa62ea - Fixed ambiguous keyboard shortcut for options 2007-08-02 16:47:29 +00:00
Christophe Dumez
30fef7d1fc - A fix for the thanks page 2007-08-02 15:34:35 +00:00
Christophe Dumez
6d7c15aa33 - Improved about dialog a lot. (broke compatibility with Qt4.2, arnaud will fix this soon)
- Added a missing file for brazilian translation
2007-08-02 15:24:52 +00:00
Christophe Dumez
be11acb31b - Fixed scrolling problem in about window 2007-08-02 14:52:38 +00:00
Christophe Dumez
a9cd4fd3f4 - Fixed a utf8 problem in our dear graphist's name 2007-08-02 14:23:15 +00:00
Christophe Dumez
1c0e890252 - Fixed columns width in transfers list (problem was caused by the hidden "hash" column that didn't have a null size) 2007-08-02 14:12:22 +00:00
Christophe Dumez
190dc793ac - Should fix building with boost 1.33.1 2007-08-01 20:01:06 +00:00
Christophe Dumez
0c18f44a34 - Updated TODO 2007-08-01 19:43:21 +00:00
Christophe Dumez
0280158138 - Updated hungarian translation 2007-08-01 19:40:49 +00:00
Christophe Dumez
265458ae98 - deleteThread: check if a path exists before trying to delete it 2007-08-01 19:25:11 +00:00
Christophe Dumez
a98a21196f - Updated Chinese (Simplified) translation 2007-08-01 18:15:24 +00:00
Christophe Dumez
66c8a21a66 - refresh list was refreshed even though the main window was hidden or minimized. This hitted an assert 2007-08-01 18:08:49 +00:00
Christophe Dumez
4ce1a7eda2 - Fixed deleteThread connect slot 2007-08-01 18:03:58 +00:00
Christophe Dumez
83b0cd5706 - Updated TODO 2007-08-01 10:10:20 +00:00
Christophe Dumez
1a1219448a - Beta 3 release 2007-08-01 10:09:43 +00:00
Christophe Dumez
f4465dcea2 - Updated unkrainian translation 2007-08-01 09:11:38 +00:00
Christophe Dumez
fc0a41e7f8 - Partially updated italian translation 2007-08-01 09:08:42 +00:00
Christophe Dumez
7469f97953 - Really enable UPnP/LSD/NAT-PMP (recently disabled as a default in libtorrent) 2007-08-01 08:47:58 +00:00
Christophe Dumez
80fa44f8bb - It is not possible to pause torrents in finished tab (closes #129498) 2007-08-01 08:43:00 +00:00
Christophe Dumez
6eae7bd201 - Forgot this one 2007-08-01 07:22:27 +00:00
Christophe Dumez
5879df7d5f - Should fix compiling errors with Qt 4.2 2007-08-01 07:19:44 +00:00
Christophe Dumez
57b4a7150a - Prevent users from filtering all the files in a torrent using right-click menu (combobox was ok) 2007-07-31 15:37:14 +00:00
Christophe Dumez
58dc75fbcf - Fixed some slots connects in new deleteThread
- Added some debug when pausing torrents
2007-07-31 14:28:17 +00:00
Christophe Dumez
d04b9a7f02 - Fixed color when filtering files using right-click menu in torrent properties and torrent addition dialog 2007-07-31 13:59:03 +00:00
Christophe Dumez
c2450cd41e - updated TODO 2007-07-31 11:22:05 +00:00
Christophe Dumez
4922eb3dc5 - Improved preview list delegate
- All delegates are now good :)
2007-07-31 11:12:41 +00:00
Christophe Dumez
34d94cd2bb - Improved search list delegate 2007-07-31 11:06:54 +00:00
Christophe Dumez
9bd3647f36 - Improved property list delegate 2007-07-31 11:02:53 +00:00
Christophe Dumez
79e2d253d4 - Improved finishedList delegate 2007-07-31 10:48:17 +00:00
Christophe Dumez
9b08b0ff8c - little improvement in download list delegate
- Disabled editor in finished list
2007-07-31 10:42:45 +00:00
Christophe Dumez
b0f3cdad5d - Improved a lot the download list delegate
- Replaced Qt::TextColorRole by Qt::ForegroundRole because it is deprecated
2007-07-31 10:39:03 +00:00
Christophe Dumez
0561206d91 - Started to improve download & finished list rendering (filename column) 2007-07-31 09:41:47 +00:00
Christophe Dumez
99530728c5 Update torrent progress when its content changed (filtered files) 2007-07-31 09:25:54 +00:00
Christophe Dumez
99a58b9208 - Removed a useless function
- Stop resfreshing trackers errors in torrent properties because this is annoying when you're trying to read them
2007-07-31 09:17:59 +00:00
Christophe Dumez
816a3c8784 - Paused torrents are displayed as paused, even if they are checking (to display their progress). This is less confusing. 2007-07-31 08:56:24 +00:00
Christophe Dumez
570296c29e - Multithreaded deletionThread (harmonized with deleteThread) 2007-07-31 08:52:04 +00:00
Christophe Dumez
5518144b26 - Improved resumeUnfinishedTorrents using a "*.torrent" filter 2007-07-31 08:21:51 +00:00
Christophe Dumez
e66af5b271 - Improved files deletion in BT_backup (no more hard-coded extensions that are annoying when adding new ones)
- Improved directory scanning for torrents using a "*.torrent" filter
2007-07-31 08:13:38 +00:00
Christophe Dumez
7b9da8d941 - Fixed [Bug 129286] Priority is not saved while using the context menu 2007-07-30 18:43:00 +00:00
Christophe Dumez
05a7ba4e38 - Fixed some bugs in italian translation 2007-07-30 16:57:28 +00:00
Christophe Dumez
f07b0eed61 - Removed useless function 2007-07-30 14:01:14 +00:00
Christophe Dumez
8fdc59c37c - Optimized Bittorrent class for faster compilation 2007-07-30 13:56:31 +00:00
Christophe Dumez
58b5d4378d - finished GUI class cleanup 2007-07-30 13:47:16 +00:00
Christophe Dumez
bd8ec01add - Removed bad assert
- Improved updateDlList function a little
2007-07-30 10:37:13 +00:00
Christophe Dumez
c0e4b0bbff removed a function that is not used anymore 2007-07-30 10:30:43 +00:00
Christophe Dumez
b0bbbf0305 - removed useless function (not used anymore) 2007-07-30 10:29:19 +00:00
Christophe Dumez
6dd78d33ab - Improved download list popup menu code
- Added some asserts
- bit of code improvement/clean up
2007-07-30 10:27:56 +00:00
Christophe Dumez
d2983fa5aa - Updated Slovak translation 2007-07-30 10:06:46 +00:00
Christophe Dumez
d680be3626 FEATURE: Allow to drag 'n drop urls on the main window 2007-07-30 09:30:07 +00:00
Christophe Dumez
0043edc85f - Updated changelog 2007-07-29 15:40:56 +00:00
Christophe Dumez
a00ea9af99 - Added a different icon for torrents being checking so that we can differenciate them from finished torrents 2007-07-29 15:40:11 +00:00
Christophe Dumez
57376ae875 - Fixed deletion message when deleting from finished list
- Added some more asserts (let's kill all those bugs time)
2007-07-29 15:32:27 +00:00
Christophe Dumez
7f89b30190 - Fixed a compiling error 2007-07-29 15:20:05 +00:00
Christophe Dumez
6951619c04 - Improved updateDlList code
- Added some ASSERTS
2007-07-29 15:17:50 +00:00
Christophe Dumez
c19937cf98 - removed some useless debug 2007-07-29 14:58:18 +00:00
Christophe Dumez
dbc084dd66 - Improved debug output
- code clean up
- Moved some bittorrent code from GUI class to Bittorrent one
2007-07-29 14:54:39 +00:00
Christophe Dumez
3cb0612cc6 - Added some ASSERTS
- Improved session ratio calculation in main window
2007-07-29 14:41:47 +00:00
Christophe Dumez
c6285d8f67 - Improved start/Pause & start_all/pause_all functions 2007-07-29 14:14:57 +00:00
Christophe Dumez
0a144708d8 - Updated swedish translation 2007-07-29 08:59:23 +00:00
Christophe Dumez
410bbcf003 - Updated Japanese translation 2007-07-29 04:32:01 +00:00
Christophe Dumez
c4a1f30b70 - Prepare for brazilian translation by Nick Manrinho 2007-07-29 03:51:42 +00:00
Christophe Dumez
269b59f8a2 - Updated french translation 2007-07-29 03:23:03 +00:00
Christophe Dumez
ffc1479b1f - Added a little more debug (tested progress column sorting : it works fine now) 2007-07-29 02:03:16 +00:00
Christophe Dumez
9683916d88 - Should fix progress column sorting 2007-07-29 01:55:59 +00:00
Christophe Dumez
74b2b955c9 - Added some more debug in pause function 2007-07-29 01:46:31 +00:00
Christophe Dumez
620deb3b6a - Fixed a problem that happened sometimes with torrents to pause after checking 2007-07-29 01:44:49 +00:00
Arnaud Demaiziere
e4fbf2107d port properties.ui to qt 4.2 2007-07-27 18:43:57 +00:00
Christophe Dumez
1db4af50dd - Reverted changes to MainWindow.ui (broke compatibility with Qt4.2) 2007-07-27 16:17:21 +00:00
Christophe Dumez
a5ac742c1f - Fixed (workaround, maybe Qt's bug?) for transfers list background painting problem. 2007-07-27 16:10:50 +00:00
Christophe Dumez
183544b959 - Updated language files 2007-07-27 15:39:03 +00:00
Christophe Dumez
897ab4d782 - Updated TODO (url seeds are documented on wiki) 2007-07-27 15:04:08 +00:00
Christophe Dumez
3e36cd3c46 - Update trackers edition code
- current tracker is now updated regularly when properties are displayed
2007-07-27 14:43:42 +00:00
Christophe Dumez
f839d6fe41 - Improved trackers errors code a lot and moved it to Bittorrent class
- When using startAll() command and when only some torrents are paused : already started torrents are not displayed as connecting untill next refresh anymore (they keep their current state).
2007-07-27 13:58:12 +00:00
Christophe Dumez
ff9b9d7148 - Updated language files 2007-07-27 10:07:05 +00:00
Christophe Dumez
b4537c52c1 - Fixed typo in changelog 2007-07-27 10:04:43 +00:00
Christophe Dumez
9cbab8d63e -FEATURE: Url seeds are now displayed in torrent properties and are editable
- Broke compatibility with Qt4.2. Will fix this a bit later (in the meantime, edit properties.ui)
2007-07-27 09:53:55 +00:00
Christophe Dumez
676f30d9a1 - Fixed ipv4 compilation warning with latest g++
- Paused torrents that are checking are now displayed as paused (not checking) -> less confusing
- Updated TODO (libtorrent fixed ipfilter bug)
2007-07-26 15:43:27 +00:00
Christophe Dumez
d3f917b408 - Fixed delete functions for finished list 2007-07-26 12:25:46 +00:00
Christophe Dumez
faf6f155ca - Improved a lot delete functions 2007-07-25 14:32:09 +00:00
Christophe Dumez
4e4b0ed9ff - Reverted a previous commit. Transfer lists refreshers aren't in separate threads anymore: too buggy 2007-07-25 14:14:38 +00:00
Christophe Dumez
95fc9e3a72 Fix last commit 2007-07-25 14:03:04 +00:00
Christophe Dumez
3ba3e12f93 - Fixed removing from finished list 2007-07-25 14:01:48 +00:00
Christophe Dumez
2ab7f6f923 - Transfer lists refreshers were moved to separate threads to improve GUI responsiveness. Please report any problem (like mutex deadlocks in console output) or crashes. 2007-07-25 09:03:22 +00:00
Christophe Dumez
d43d68122b BUGFIX: The number of search results was not reset when clicking on 'Clear' button 2007-07-25 07:22:32 +00:00
Christophe Dumez
03fae3953f - Made error message clearer when libcommoncpp2 is not installed. 2007-07-25 07:00:14 +00:00
Christophe Dumez
102c5ee81e - Updated polish translation 2007-07-25 06:46:37 +00:00
Christophe Dumez
f27e913f67 - updated changelog 2007-07-24 08:33:00 +00:00
Christophe Dumez
4ef72c6c8f - Fixed new lines in search engine update changelog 2007-07-24 08:32:17 +00:00
Christophe Dumez
a370503eb3 search plugin update - do not display only last version changelog 2007-07-24 08:22:12 +00:00
Christophe Dumez
e9126aedc3 - Improved mininova search engine support 2007-07-24 07:58:31 +00:00
Christophe Dumez
e493776a73 - User is now warned when fast resume data was rejected 2007-07-24 07:30:33 +00:00
Christophe Dumez
a0e32fefd7 - Fixed compilation warnings
- Started work on fastresume reject alerts
2007-07-24 07:13:40 +00:00
Christophe Dumez
e606d04098 - added doc url in INSTALL file 2007-07-24 06:20:32 +00:00
Christophe Dumez
5713af7375 - Workaround to build on fedora system (pkg-config problem) 2007-07-24 05:08:02 +00:00
Christophe Dumez
1e64d0a3e4 - Added a lot of supported media extensions for preview (tried to be exhaustive but the best way would probably be to use mime types) 2007-07-23 15:55:12 +00:00
Christophe Dumez
e4ab5ceb43 - Compile with -O2 optimization
- Added some media extensions supported
2007-07-23 15:31:30 +00:00
Christophe Dumez
ce5baa93b7 - Ok, includes look fine now 2007-07-23 12:56:57 +00:00
Christophe Dumez
042323a1a8 - Improved rss includes a little and fix a memory leak I just introduced 2007-07-23 12:52:25 +00:00
Christophe Dumez
93938d8597 - still optimizing includes 2007-07-23 12:46:36 +00:00
Christophe Dumez
0db60065c0 - Removed useless mutex in GUI
- started to optimize headers includes for compilation speed
2007-07-23 12:12:55 +00:00
Christophe Dumez
c8c53e2812 - Use pkgconfig for GNU common c++ 2007-07-23 09:48:51 +00:00
Christophe Dumez
737bdadbd0 - Updated TODO 2007-07-23 08:41:23 +00:00
Christophe Dumez
53d2bc34fc - fixed minor code error in finishedList 2007-07-23 08:32:06 +00:00
Christophe Dumez
5cc6e6e8f4 - sometimes, rss feeds had a red cross icon although their download succeeded : fixed 2007-07-23 07:55:06 +00:00
Christophe Dumez
a27e7e1b9e - Lightened finished list code
- Fixed properties slots connects in finished list
- Fixed columns width in finished list
2007-07-23 07:44:58 +00:00
Christophe Dumez
2ba45ef9ad - Updated french translation 2007-07-23 05:11:11 +00:00
Christophe Dumez
59d35b9f8a - beta2 release 2007-07-23 04:57:28 +00:00
Christophe Dumez
cf6a91e850 - BUGFIX: DHT settings were not saved correctly 2007-07-23 04:51:29 +00:00
Christophe Dumez
4e0ed1ec4c - Optimized downloadThread memory usage 2007-07-22 15:48:34 +00:00
Christophe Dumez
2ad1c56933 - Create urlstream for subdownloadthreads only 2007-07-22 15:18:09 +00:00
Christophe Dumez
4f17339820 - URLStream is now constructed in downloadThread constructor 2007-07-22 15:13:11 +00:00
Christophe Dumez
c019b0d72c - Added some debug in rss 2007-07-22 15:02:19 +00:00
Christophe Dumez
0fb78727d5 - Added more debug in rss 2007-07-22 14:14:05 +00:00
Christophe Dumez
2c48968a31 - a search request can now be terminated by another 2007-07-22 13:42:09 +00:00
Christophe Dumez
f4adf173a2 - Multithreaded downloadThread for performance 2007-07-22 13:21:04 +00:00
Christophe Dumez
c086558597 - Updated TODO
- Load torrents before loading rss and sreach engine on startup
2007-07-22 12:46:03 +00:00
Christophe Dumez
7c48afd6eb - Improved downloadThread aborting support 2007-07-22 12:08:16 +00:00
Christophe Dumez
e6554db498 - Updated language files 2007-07-22 12:00:14 +00:00
Christophe Dumez
d25776ddda - Quite a few improvements in rss interface 2007-07-22 11:53:43 +00:00
Christophe Dumez
325a588526 - Fixed some signals/slots (safer)
- Forgot to remove temp file when the file was downloaded from an url (rare occasions)
2007-07-22 09:47:27 +00:00
Christophe Dumez
8c05caba3a - Improved rss favicon handling a little 2007-07-22 09:12:50 +00:00
Christophe Dumez
d3793d180c - Removed some useless debug in downloadThread and added a little more interesting one
- Updated TODO
2007-07-22 04:14:44 +00:00
Christophe Dumez
e1e28fa9ff - Updated TODO 2007-07-22 03:41:53 +00:00
Christophe Dumez
e3e559d857 - Fixed typo in last commit 2007-07-22 03:21:41 +00:00
Christophe Dumez
708e802570 - trying to fix gtsould's work... 2007-07-22 03:07:59 +00:00
Christophe Dumez
a74dc5ee35 - GTSOUL, wtf you're doing??? Committing back the new downloadThread.h 2007-07-22 03:04:47 +00:00
Arnaud Demaiziere
7edc89638f rss : show the number of NONREAD news (local test succeeded, need tests)
rss : clean the file rss.h
rss : display the site favicon (local test succeeded, need tests)

bug that i've noticed but not fixed :
_ something create qt_temp files without delete them
_ in dl list, columns disappear
2007-07-21 19:37:10 +00:00
Christophe Dumez
e4915260e7 - Updated language files 2007-07-20 21:39:21 +00:00
Christophe Dumez
92ae8de58e - Updated TODO list 2007-07-20 21:23:35 +00:00
Christophe Dumez
f81e431032 - Added rss download failure handling (display red cross next to the stream name) 2007-07-20 21:06:50 +00:00
Christophe Dumez
2789316e38 - Fixed a connect in last commit 2007-07-20 20:58:20 +00:00
Christophe Dumez
f4250d812f - Added search plugin download error handling (Fallback on secondary server and then warn the user if both failed) 2007-07-20 20:30:33 +00:00
Christophe Dumez
1fb848e9ed - Added download from url handling in GUI (still missing: search plugin update and rss) 2007-07-20 20:18:18 +00:00
Christophe Dumez
2fd0de082c - Updated configure file to check for libcommoncpp2 instead of libcurl
- Used downloadThread in search plugin update instead of libcurl (no more gui freeze by the same occasion)
- Still need to handle download from urls errors and use fallback url in search plugin update (before beta2)
2007-07-20 17:11:02 +00:00
Christophe Dumez
7c8677d787 - Improved a lot downloading from url using libcommoncpp2 instead of libcurl
- TODO soon:
  - Updated configure file
	- Add url download error handling
2007-07-20 15:55:50 +00:00
Christophe Dumez
347b03d699 - Updated TODO 2007-07-20 14:05:39 +00:00
Christophe Dumez
4c9d1db9d5 - Fixed popup menu position in last commit 2007-07-20 13:30:30 +00:00
Christophe Dumez
8fdd614673 - Added popup menu for file priorities in torrent addition dialog too 2007-07-20 13:21:46 +00:00
Christophe Dumez
0bdb10cdbe - Prepare this dialog for popup menu 2007-07-20 13:10:06 +00:00
Christophe Dumez
60c0049bef - Added a popup menu to set priority for multiple files at once 2007-07-20 13:07:34 +00:00
Christophe Dumez
a40c2bfc8f - Fixed an ambiguous shortcut in french translation 2007-07-20 12:48:06 +00:00
Christophe Dumez
a6b037d663 - Fixed last commit 2007-07-20 12:39:20 +00:00
Christophe Dumez
e079c87f5c - Simplified keyboard shortcuts code 2007-07-20 12:22:28 +00:00
Christophe Dumez
22a80fe1c3 - Updated french translation 2007-07-19 14:44:08 +00:00
Christophe Dumez
d762f094f2 - Updated TODO: Keyboard shortcuts are now documented 2007-07-19 13:36:27 +00:00
Christophe Dumez
e916300a6e - Improved keyboard shortcuts 2007-07-19 13:07:52 +00:00
Christophe Dumez
99959b1aa3 - Added keyboard shortcuts for main actions (thanks Alexander Kuzmenkov) 2007-07-19 12:58:45 +00:00
Christophe Dumez
38c6c63924 - Improved debug output 2007-07-18 08:05:15 +00:00
Christophe Dumez
3d7540dafe - Updated translation files 2007-07-18 07:46:06 +00:00
Christophe Dumez
86a0e68f46 - Added ratio column 2007-07-18 07:44:52 +00:00
Christophe Dumez
eb3db365e7 - Can't set a limit for a torrent superior to the global limit in program preferences 2007-07-17 11:45:36 +00:00
Christophe Dumez
2dea5f2ff8 - Fixed a bug in speed allocation per torrent. Libtorrent works better too but I'm still hitting an assert. 2007-07-17 11:26:49 +00:00
Christophe Dumez
766be4b381 - Fixed hungarian translation 2007-07-17 01:08:44 +00:00
Arnaud Demaiziere
d0bf8b5b04 save mainwindows to qt 4.2 2007-07-14 20:24:45 +00:00
Christophe Dumez
8df61db644 - Rollback to GNU GPLv2 because Qt4 is not compatible with GPLv3 :( 2007-07-14 14:31:59 +00:00
Christophe Dumez
f0353e50b2 - Upload/download limits per torrent are now saved on restart. I can't test this feature yet though because libtorrent is crashing when I try to use it :) 2007-07-14 13:38:29 +00:00
Christophe Dumez
28ea505088 - qBittorrent is not exiting anymore when Main window is hidden and a dialog is closed (nasty long-standing bug...) 2007-07-14 12:35:04 +00:00
Christophe Dumez
8c5d38400a - Allow to set global upload/download bandwidth limit from tray icon menu
- Fixed a bug in bandwidth limitation per torrent (confused bytes with kbytes)
- Fixed a bug with paused torrents still displayed as checking
2007-07-14 10:50:38 +00:00
Christophe Dumez
eed49c10ce - Peer blocked are now added in the right box (not log) 2007-07-14 04:22:57 +00:00
Christophe Dumez
0a2ab16e4c - little translation for hungarian 2007-07-14 04:18:26 +00:00
Christophe Dumez
dda4ffed08 - Added hungarian translation 2007-07-13 12:28:18 +00:00
Christophe Dumez
54f9375b32 - Update to GNU GPL v3 2007-07-13 06:55:51 +00:00
Christophe Dumez
8d667310e3 - Fixed signal connect 2007-07-13 01:28:08 +00:00
Christophe Dumez
a4371e7f55 - Removed some debug
- Updated TODO
2007-07-12 13:38:40 +00:00
Arnaud Demaiziere
a5b8d3c730 bug fix in ipfilter 2007-07-10 18:16:07 +00:00
Arnaud Demaiziere
09c97decb6 ipfilter : ipv6 support 2007-07-09 22:09:21 +00:00
Christophe Dumez
c2fc03b0d7 - Updated french translation 2007-07-07 01:29:32 +00:00
Christophe Dumez
5622fd0991 - Updated French translation 2007-07-05 13:02:04 +00:00
Arnaud Demaiziere
1712a7c776 * port interfaces to qt 4.2
* fix size bug
2007-07-05 11:31:33 +00:00
Christophe Dumez
9f3b9da24a - fixed a bug with full allocation mode, introduced yesterday 2007-07-05 00:07:45 +00:00
Christophe Dumez
18ec98c3fb - Reloading a torrent only when necessary (properties, when files are filtered but full allocation mode is disabled) 2007-07-04 10:06:22 +00:00
Christophe Dumez
c8e4894d85 - Fixed size update when filtering files in a torrent (broken in svn) 2007-07-04 08:10:44 +00:00
Christophe Dumez
4657ee9087 Fixed a crash when filtering all the files in a torrent 2007-07-04 07:28:51 +00:00
Christophe Dumez
97aed61fc8 ** first beta ** 2007-07-04 06:48:38 +00:00
Christophe Dumez
c11e5e8b12 - Blocked users (by ipfilter) are now logged in GUI 2007-07-04 06:42:36 +00:00
Christophe Dumez
3a727dea28 - improved tabs at the bottom 2007-07-03 22:53:10 +00:00
Christophe Dumez
107d2c8e7b Fixed file filtering in a torrent 2007-07-03 22:39:49 +00:00
Christophe Dumez
b1ed521d6b Fixed downloadFromUrl 2007-07-03 09:04:04 +00:00
Christophe Dumez
e2427a4ce2 - Delete torrent permanently from hard drive used to delete parent folder if empty (fixed) 2007-06-30 19:19:09 +00:00
Christophe Dumez
d12e510fad Improved start_All and resume_All functions to detect if a torrent's state changed or not. This way, it doesn't flood the GUI if the user keeps on clicking on those buttons 2007-06-30 18:56:49 +00:00
Christophe Dumez
9bde00b7de Improved ETA calculation 2007-06-29 16:49:45 +00:00
Christophe Dumez
611b9424ee updated version 2007-06-29 15:50:55 +00:00
Christophe Dumez
0ec6af03c0 Fixed possible division by 0 2007-06-29 15:37:59 +00:00
Christophe Dumez
80f61880b7 made ETA calculation more reliable 2007-06-29 15:23:15 +00:00
Arnaud Demaiziere
92541b779c fixed sort bug (made by chris) 2007-06-29 14:23:15 +00:00
Christophe Dumez
f5a4190e4b attempt to fix progress column sorting 2007-06-29 14:13:50 +00:00
Christophe Dumez
6ae1564136 fixed a deadlock 2007-06-29 14:11:31 +00:00
Christophe Dumez
e361ef5543 Oops forgot a mutex locker in progress column sorting 2007-06-29 14:06:34 +00:00
Christophe Dumez
dfa9965ed3 use a mutex for download list access (should fix sorting) 2007-06-29 14:00:17 +00:00
Arnaud Demaiziere
dcc54a7f35 fixed addtorrent signal, add bool onstartup to connect methods 2007-06-29 13:42:10 +00:00
Christophe Dumez
478a275bb5 - Updated german translation 2007-06-29 12:42:05 +00:00
Christophe Dumez
8c30ee3403 - Updated changelog in search engine 2007-06-29 12:24:50 +00:00
Christophe Dumez
cf002e5ab2 fixed mininova search engine 2007-06-29 12:22:55 +00:00
Christophe Dumez
09ca6e97b8 Fixed addTorrent slot 2007-06-29 10:34:10 +00:00
Christophe Dumez
dfa58f909b Fixed addtorrent slot 2007-06-29 10:30:00 +00:00
Arnaud Demaiziere
d925efb928 save options.ui with qt 4.2 2007-06-29 10:18:27 +00:00
Christophe Dumez
1910ee20dd Real time sorting of progress column was broken by ealier patch -> Fixed 2007-06-29 08:14:43 +00:00
Christophe Dumez
faaa700270 Updated polish translator 2007-06-28 23:10:57 +00:00
Christophe Dumez
d0e2e9c85f - Updating polish translation (Thanks Jarek) 2007-06-28 23:07:16 +00:00
Christophe Dumez
55538934e0 A better fix for progress column sorting on restart (still untested, gtsoul please check) 2007-06-28 22:58:43 +00:00
Christophe Dumez
ee4a4c81bf Attempt to fix the sorting of the progress column on restart (anyone can confirm? my Qt4.3 is buggy and columns won't sort) 2007-06-28 22:13:01 +00:00
Christophe Dumez
568b2ddf75 Progress of paused torrents is now correct on restart 2007-06-28 21:54:07 +00:00
Christophe Dumez
8755ebba01 Added an icon for the new encryption option 2007-06-28 21:03:52 +00:00
Christophe Dumez
18b41d07bd - Updated TODO 2007-06-19 15:58:53 +00:00
Arnaud Demaiziere
614606e3be update main menu items'order 2007-06-19 15:19:23 +00:00
Christophe Dumez
0aa4651657 - added documentation icon 2007-06-19 15:11:02 +00:00
Arnaud Demaiziere
841e6549c0 interface ported to qt 4.2, resize of the log windows 2007-06-19 14:53:58 +00:00
Christophe Dumez
3ec647cfda -legal notice in red 2007-06-17 18:36:04 +00:00
Christophe Dumez
e6fca96d0d - Added Documentation entry in Help menu 2007-06-17 15:09:00 +00:00
Christophe Dumez
5e73539393 - fixed delete permanently in finished list 2007-06-17 12:15:04 +00:00
Christophe Dumez
68b867e480 - Fixed a few other bugs in translatable strings
- French translation is up to date!
2007-06-15 23:51:10 +00:00
Christophe Dumez
4a671dba9e - Fixed a lot of bugs in translatable strings
- Started to update french translation
2007-06-15 23:40:33 +00:00
Christophe Dumez
ef1f030076 - Added some debug in bittorrent.cpp
- Added Legal Notice on qBittorrent startup "Be careful, sharing copyrighted material without permission is against the law." because of new DADVSI law.
2007-06-15 23:02:35 +00:00
Christophe Dumez
341225aff4 - Updated TODO 2007-06-15 22:47:55 +00:00
Christophe Dumez
2d9f688d56 Updated TODO 2007-06-15 22:29:11 +00:00
Christophe Dumez
3b63d34f34 Allow only rc4 for encryption, no plaintext 2007-06-15 20:43:31 +00:00
Christophe Dumez
c39da36cca - Added Encryption support!
- Removed old UPnP code
- Removed UPnP in options since libtorrent doesn't allow to disable it. Thus, UPnP is always enabled
- Made options window a bit larger
- Added Arnaud Demaiziere to developpers list
- Updated TODO & Changelog
2007-06-15 20:35:07 +00:00
Christophe Dumez
c4b49a6d96 Added a way to build statically against libtorrent (see ./configure --help) 2007-06-15 11:29:00 +00:00
Christophe Dumez
68e78a7d24 Updated TODO 2007-06-15 09:04:39 +00:00
Christophe Dumez
8b9a15d4f2 Updated TODO 2007-06-14 22:10:48 +00:00
Christophe Dumez
71dd59f5bc Added Kdevelop project file 2007-06-14 20:14:06 +00:00
Christophe Dumez
4b03220064 Updated TODO 2007-06-14 19:57:34 +00:00
Christophe Dumez
7fad742e99 - Fixed compiling with latest libtorrent svn 2007-06-13 14:04:29 +00:00
Christophe Dumez
fe70d5ecaa - Oops was in v0.9.3 already 2007-06-12 18:30:59 +00:00
Christophe Dumez
89022a5065 - Updated Changelog (forgot this one) 2007-06-12 18:28:27 +00:00
Christophe Dumez
a0d107a0e8 - Updated changelog 2007-06-12 18:24:15 +00:00
Christophe Dumez
e71252306a - Fixed a bug in polish translation 2007-06-12 18:19:16 +00:00
Christophe Dumez
f86037865d - Updated TODO 2007-06-12 12:40:10 +00:00
Christophe Dumez
1cff97f65d - Bugfix: User can't empty the trackers list 2007-05-16 18:55:34 +00:00
Christophe Dumez
e3228a9699 - Updated Japanese translation (Thanks Nardog) 2007-05-14 07:58:18 +00:00
Christophe Dumez
407ae8d01b - Updated translation files 2007-05-13 20:08:42 +00:00
Christophe Dumez
b3b1bcc60c - Updated TODO 2007-05-13 20:05:30 +00:00
Christophe Dumez
2196fcc911 - Supports SOCKS5 proxies as well as HTTP ones
- Allow to use Proxy for Trackers / Peers / Web seeds / DHT connections
- Redesigned Proxy options a little (for new features)
2007-05-13 20:02:30 +00:00
Christophe Dumez
2985fa921a remember sorted columns in download list 2007-05-07 21:20:35 +00:00
Christophe Dumez
9808e5a37a - Fixes in Slovak translation 2007-05-07 20:10:23 +00:00
Christophe Dumez
ff70dc7c83 - Updated changelog 2007-05-02 14:04:11 +00:00
Christophe Dumez
9093f8e44a - Proxy is now used for tracker / web seeds / peers connections
- Fixed the compiling errors with latest libtorrent svn
2007-05-02 13:52:29 +00:00
Christophe Dumez
f8eea3b779 - Updated TODO (search plugin update improvement to come) 2007-04-16 07:10:54 +00:00
Arnaud Demaiziere
85fa92ca12 rss : bug fixes 2007-04-15 21:43:58 +00:00
Christophe Dumez
44bfb1e376 - Fixed a small error in the german translation 2007-04-15 21:37:22 +00:00
Arnaud Demaiziere
06378e09be rss : improvements of the qtreeview 2007-04-15 21:31:32 +00:00
Arnaud Demaiziere
2c6b66a834 rss : from qlistwidget to qtreewidget 2007-04-15 19:06:19 +00:00
Christophe Dumez
9a4466e74f - Improved right click menu in RSS streams list 2007-04-15 18:53:53 +00:00
Christophe Dumez
f482496a61 - Updated smileys 2007-04-15 18:38:32 +00:00
Christophe Dumez
6802e22f7e - Improved a lot switching between tabs 2007-04-15 18:15:22 +00:00
Christophe Dumez
79253c76f1 - Now finished torrents are moved correctly to download tab if for some reason the files disapear from the hard-drive :) 2007-04-15 17:42:43 +00:00
Christophe Dumez
5fc754520a - small fix in finished list 2007-04-15 17:00:16 +00:00
Christophe Dumez
43bced2e04 - Improved refresh icon
- Added tooltips on rss buttons
- Fixed a compiling warning
2007-04-15 14:53:38 +00:00
Christophe Dumez
65468d7826 - Improved add/remove icons 2007-04-15 14:43:12 +00:00
Arnaud Demaiziere
1a553b00b0 rss : download icon fix, don't work so i commented it 2007-04-15 12:05:14 +00:00
Christophe Dumez
79a3d2e81b - Updated splash screen 2007-04-15 09:56:50 +00:00
Christophe Dumez
4ed6f12374 - Added a text to help using the rss 2007-04-14 21:08:33 +00:00
Christophe Dumez
4d6afaacfd - Should fix the problem of finished torrents in download list (Thx heavyjoos) 2007-04-14 21:06:00 +00:00
Arnaud Demaiziere
7d8d4e7ee5 rss : try to download streams' favicon 2007-04-14 18:04:47 +00:00
Arnaud Demaiziere
3fa88436c3 rss : try to use dynamic icon before streams names 2007-04-14 12:41:42 +00:00
Arnaud Demaiziere
191ac5eeac rss : another improvements 2007-04-13 12:13:27 +00:00
Arnaud Demaiziere
2ce51400aa rss : work to improve algorithm & memory
implements some color
2007-04-13 12:07:14 +00:00
Arnaud Demaiziere
d5aea98f80 rss : color try 2007-04-12 23:53:15 +00:00
Christophe Dumez
85fd33a619 - Updated to v1.0.0alpha8 (not a v0.10 after all)
- Added a new splash screen by our graphist but still unfinished
2007-04-12 22:17:33 +00:00
Christophe Dumez
ada614a956 - Updated Changelog 2007-04-12 21:43:33 +00:00
Christophe Dumez
45d51e1d44 - The torrent size displayed now takes filtered files into consideration 2007-04-12 21:28:15 +00:00
Christophe Dumez
9c83c195e3 - Fixed some slots bindings in finished list 2007-04-12 21:10:44 +00:00
Christophe Dumez
ec3f878372 - Updated alpha version 2007-04-12 20:36:27 +00:00
Christophe Dumez
9885169baf - Updated translation files
- Fixed column width in torrent addition dialog
2007-04-12 20:28:10 +00:00
Christophe Dumez
00afd6b635 - Implemented files prioritizing in torrent addition dialog 2007-04-12 20:22:42 +00:00
Christophe Dumez
ff3575c7ac - Implemented files prioritizing in a torrent (Part I: Torrent Properties), still need to work on torrent addition dialog 2007-04-12 19:51:39 +00:00
Arnaud Demaiziere
66201a2853 rss : bugs fixes, better refresh 2007-04-12 19:24:05 +00:00
Christophe Dumez
eb85389c0a - UPnP is on as a default, display the display message 2007-04-12 17:25:47 +00:00
Christophe Dumez
f7c4411c9a - UPnP is enabled as a default and there is no way to disable it at the moment (libtorrent API) 2007-04-12 17:21:30 +00:00
Christophe Dumez
36d073d597 - Removing our UPnP code because libtorrent svn does it 2007-04-12 17:19:12 +00:00
Christophe Dumez
658771612a - Upgraded to libtorrent svn (0.13) 2007-04-12 17:17:04 +00:00
Christophe Dumez
7f7fb2354f - Added some scripts that might be useful in the future 2007-04-12 13:26:06 +00:00
Christophe Dumez
c146f6d0d9 - Added experimental windows build url to TODO 2007-04-12 09:27:05 +00:00
Christophe Dumez
923bba95b4 - Updated TODO 2007-04-11 21:13:34 +00:00
Christophe Dumez
ee594400dc - Fixed togglepausedstate() on double click in download list 2007-04-11 20:50:41 +00:00
Arnaud Demaiziere
77b998c438 rss : bug fixes and refresh algorithm improved and better use of
signals&memory
2007-04-11 20:24:41 +00:00
Christophe Dumez
cf2bc1e980 - removed ETA & DL speed columns in finished torrents list 2007-04-11 18:31:21 +00:00
Christophe Dumez
ab4ad0b114 - Use a standard QDialogButtonBox in options for better systems integration 2007-04-11 18:19:20 +00:00
Christophe Dumez
dc4acc83a5 - Allow multiple selection in finished list 2007-04-11 18:06:54 +00:00
Christophe Dumez
7263867f14 - Display torrent properties on double click in finished torrents list (togglepausedstate() was useless here)
- Fixed default tab selected in torrent properties
- Updated TODO
2007-04-11 13:23:17 +00:00
Christophe Dumez
cfe979c8dd - Updated changelog
- Made sorting work in the finished torrents list
2007-04-11 13:19:58 +00:00
Christophe Dumez
762df4b914 - Columns width are now remembered on restart for the finished torrent list 2007-04-11 13:10:13 +00:00
Christophe Dumez
4a57037c47 - Fixed typo and redesigned rss code a little 2007-04-11 12:59:55 +00:00
Christophe Dumez
bfe7010350 - Fixed right click menu disposition in RSS
- Improved some sentences in dialogs
2007-04-11 12:33:41 +00:00
Christophe Dumez
76708c96df - Updated TODO 2007-04-11 10:41:33 +00:00
Arnaud Demaiziere
e0261295db rss : bug fix 2007-04-11 09:45:00 +00:00
Christophe Dumez
953a99ee90 - Updated turkish translation 2007-04-10 20:57:35 +00:00
Christophe Dumez
e3f3293461 - Updated TODO 2007-04-10 15:26:44 +00:00
Christophe Dumez
8e8ffae57a - Disabled MainWindow context menu, more annoying than useful 2007-04-10 10:54:22 +00:00
Christophe Dumez
30d328774f - Fixed compiling error in finishedTorrents.cpp
- Added icons for bandwidth allocation actions
2007-04-10 10:50:34 +00:00
Christophe Dumez
e1660e592b - Added Upload limit per torrent in finished list 2007-04-10 10:11:36 +00:00
Christophe Dumez
6428fd4ae0 - Added bandwidth allocation to the right click menu on torrents 2007-04-10 10:05:04 +00:00
Christophe Dumez
b08d08512f - Bandwidth allocation per torrent class should be almost ready now 2007-04-10 09:43:26 +00:00
Christophe Dumez
a25cc14af4 - Fixed a crash when stopping a search (introduced when splitting search engine from GUI recently) 2007-04-10 09:35:34 +00:00
Christophe Dumez
30aa59f582 - Kept on working on bandwidth allocation per torrent
- Fixed a crash in search engine when systray integration was disabled
2007-04-10 09:31:25 +00:00
Christophe Dumez
3933d78da2 - Started to work on bandwidth allocation per torrent 2007-04-10 09:07:33 +00:00
Christophe Dumez
a9ed013ca3 - Code optimization in for loops tests 2007-04-10 08:05:27 +00:00
Christophe Dumez
b198494900 - Code cleanup using autoconnect slots 2007-04-10 07:54:06 +00:00
Christophe Dumez
216e9a9785 - Updated TODO 2007-04-10 07:21:56 +00:00
Christophe Dumez
c627c9b540 - Fixed the name of the protuguese translator 2007-04-09 19:01:56 +00:00
Christophe Dumez
359dcd3b99 - Added Japanese translator 2007-04-09 17:12:36 +00:00
Christophe Dumez
0eaa592086 - Disabled context menu in toolbar 2007-04-08 18:21:26 +00:00
Christophe Dumez
62b61750d1 - Translated "Japanese" into japanese in options 2007-04-07 13:58:23 +00:00
Christophe Dumez
3e1f7d2193 - Improved icons in torrent creation dialog for add_older and add_file 2007-04-07 13:54:59 +00:00
Christophe Dumez
8980905c24 - Fixed a typo 2007-04-07 07:48:06 +00:00
Christophe Dumez
f3f71e5d14 - Added Japanese translation 2007-04-07 07:43:57 +00:00
Arnaud Demaiziere
2a9d2a4910 about rss : new streams are aliased by their title 2007-04-06 12:57:41 +00:00
Christophe Dumez
59c6f469a0 - use PKGCONFIG again for libtorrent in configure 2007-04-05 22:58:12 +00:00
Christophe Dumez
4473b7917b - Fixed some bugs in rss 2007-04-05 22:38:46 +00:00
Christophe Dumez
3dbb958bde - Doesn't display that a torrent has finished on start when it finished during last session 2007-04-05 22:29:09 +00:00
Christophe Dumez
f81481c50f - Still cleaning up rss 2007-04-05 22:10:55 +00:00
Christophe Dumez
485c6b80af - Added a TODO in rss.h 2007-04-05 22:02:04 +00:00
Christophe Dumez
b8d5793ab7 - cleaned up rss.h 2007-04-05 20:29:30 +00:00
Christophe Dumez
933957282b - gtsoul commited some files he shouldn't have ;) 2007-04-05 19:43:11 +00:00
Christophe Dumez
381ae195b9 - Fixed a bug in the number of finished torrents initial display
- Started to clean up rss.h
2007-04-05 19:42:39 +00:00
Arnaud Demaiziere
d323dcd4e0 add svn_imp 2007-04-05 19:26:30 +00:00
Arnaud Demaiziere
1ae635a8b5 work on rss, right-click menu, refresh functions, and anticrash methods 2007-04-05 18:30:20 +00:00
Christophe Dumez
d3eda2e8be - Added Comboboxes in torrent properties. No usable yet but it will be very useful when we will support pieces prioritization 2007-04-05 15:55:05 +00:00
Arnaud Demaiziere
adf91c95d3 some work on rss, direct open & add stream function 2007-04-05 13:07:46 +00:00
Arnaud Demaiziere
eddee2a0d5 some work on rss, refresh & autoopenbrowser 2007-04-05 12:39:42 +00:00
Christophe Dumez
ff0dd88ee1 - Improved a lot the torrent creation module 2007-04-04 18:55:38 +00:00
Christophe Dumez
81d05a67b3 - Window can now stay maximized on exit 2007-04-04 14:53:00 +00:00
Christophe Dumez
a0743c0713 - Preview from finished list should now be working 2007-04-04 14:36:47 +00:00
Christophe Dumez
8c9ce5dd45 - Improved popup menu in finished list 2007-04-04 14:29:59 +00:00
Christophe Dumez
4727cd57ed - Removed pause/start in finished list (useless) 2007-04-04 14:25:56 +00:00
Christophe Dumez
775afd6ac2 - Implemented Start/Pause in finished list 2007-04-04 13:58:38 +00:00
Christophe Dumez
a615038498 - Added a popu menu in finished list 2007-04-04 13:12:11 +00:00
Christophe Dumez
cd70dcc3ba - Allow the user to display torrent properties in finished list 2007-04-04 12:52:50 +00:00
Christophe Dumez
5c53c457e5 - Implemented delete from finished list 2007-04-04 12:41:47 +00:00
Christophe Dumez
6d0b550f5d - Implemented DeleteFromHardDrive & finishedList 2007-04-04 12:33:53 +00:00
Christophe Dumez
37027c0480 - A lot of work on "Finished torrents are moved to a new tab". It still needs improvements but most of it is working
- Fixed pressing return in search field to launch search
2007-04-04 12:01:32 +00:00
Christophe Dumez
13aa2cfa6e - Added a new tab for finished torrents (WIP, not used yet) 2007-04-04 01:36:55 +00:00
Christophe Dumez
c832d91f79 - Ask for exit confirmation only if the download list is not empty 2007-04-04 00:47:26 +00:00
Christophe Dumez
c6c4bc1277 - FEATURE: Search engine is now using one thread per website for faster results 2007-04-03 23:55:21 +00:00
Christophe Dumez
2ab2e5a40f - Fixed configure files 2007-04-03 21:51:26 +00:00
Christophe Dumez
732cc41be4 - qConf is buggy and the configure file was not working properly. I had to rewrite most of the configure code to get it working. 2007-04-03 21:49:52 +00:00
Christophe Dumez
2f0bee3b19 - Updated splash screen to v0.10.0 2007-04-03 12:24:12 +00:00
Christophe Dumez
ab1d664f07 - Updated Changelog / Todo
- Fixed a title boldness in torrent properties
2007-04-02 13:22:48 +00:00
Christophe Dumez
95bc8e513a - Optimized friendlyUnit() function a little 2007-03-30 12:47:57 +00:00
Christophe Dumez
da2602a632 - Updated INSTALL file 2007-03-29 20:43:35 +00:00
Christophe Dumez
178a2046dc - Updated TODO
- Updated dependencies
2007-03-29 20:40:39 +00:00
Christophe Dumez
d90e4286e3 - Bring the window to foreround on exit when it was minimized 2007-03-29 20:21:17 +00:00
Christophe Dumez
5d0e466d6d - Allow the user to disable systray integration 2007-03-29 19:54:45 +00:00
Christophe Dumez
622fb85f60 - Updated TODO 2007-03-29 18:49:58 +00:00
Christophe Dumez
0ebdd34df3 Bring mainWindow to foreground when asking for exit confirmation 2007-03-29 18:46:50 +00:00
Christophe Dumez
81eee7bba2 - Style is now applied instantly, no need to restart qBT
- Fixed a typo in WIndowsXP Style
2007-03-29 18:43:04 +00:00
Christophe Dumez
5ddc3467f8 - Added some more debug in upnp code 2007-03-29 18:14:45 +00:00
Christophe Dumez
76d9a230c0 - Added all missing icons in RSS tab 2007-03-29 16:09:21 +00:00
Christophe Dumez
b3e6f341ff - Added RSS icon on its tab 2007-03-29 16:02:34 +00:00
Arnaud Demaiziere
6c8f0bff13 - Added a rss tab (still not functional) 2007-03-29 15:43:08 +00:00
Arnaud Demaiziere
456f57e32f - Added RSS support header 2007-03-29 15:27:40 +00:00
Christophe Dumez
4ca852c2b3 - Added a message log when an UPnP WAN service is detected 2007-03-29 14:49:01 +00:00
Christophe Dumez
3ff075c048 - Display more log messages 2007-03-29 14:31:43 +00:00
Christophe Dumez
ebc9d62f69 - Added a signal in upnp to display an error on GUI when no wan service is detected (still unused) 2007-03-29 14:12:26 +00:00
Christophe Dumez
fd3e60bce1 - Updated dutch translation 2007-03-29 13:55:38 +00:00
Christophe Dumez
3f01be8d6e - Fixed an error when disabling upnp
- upnp is now disabled as a default
2007-03-29 13:51:15 +00:00
Christophe Dumez
3ea7685405 - cleaning up upnp code 2007-03-29 13:31:10 +00:00
Christophe Dumez
fa2815df49 - Started to clean up upnp code 2007-03-29 13:28:11 +00:00
Christophe Dumez
01dd57a5fb - Reworked UPnP code a little 2007-03-29 12:52:14 +00:00
Christophe Dumez
a5ebc85bdb - Added some more debug in UPnP 2007-03-29 10:10:28 +00:00
Christophe Dumez
04a716ac91 - Fixed a mutex lock in UPnP code 2007-03-29 10:06:55 +00:00
Christophe Dumez
fc10f3c4cd - Forgot to remove this include 2007-03-29 09:55:53 +00:00
Christophe Dumez
682196543f - Move our own UPnP to a branch because it is taking too long 2007-03-29 09:55:17 +00:00
Christophe Dumez
2772a41917 - Added some missing functions body :) **WIP** but I need to sleep now. Will resume tomorrow :) 2007-03-28 22:29:23 +00:00
Christophe Dumez
0dc4bdd646 - some fixes in new UPnP (still unfinished) 2007-03-28 22:14:38 +00:00
Christophe Dumez
78916bba41 - Added debug in UPnP
- Started to rewrite qBT's own UPnP support instead of using aMule CVS code : (not usable yet)
2007-03-28 21:59:21 +00:00
Arnaud Demaiziere
e8e40c7bcf - Fixed compiling errors when upnp is disabled (chris) 2007-03-28 11:45:32 +00:00
Christophe Dumez
47db3386aa - Updated Italian translation 2007-03-28 11:19:30 +00:00
Christophe Dumez
92f840519c - Allow to change UPnP port while it is enabled
- Allow to change qBT style! (GTK people should like Cleanlooks style)
2007-03-28 08:05:37 +00:00
Christophe Dumez
e0a0a0beb1 - fix for UPnP option 2007-03-27 21:12:33 +00:00
Christophe Dumez
d778766e29 - UPnP option should now be working 2007-03-27 21:08:07 +00:00
Christophe Dumez
371dcb0a45 - Disable UPnP in options if qBT isn't compiled with UPnP support 2007-03-27 20:33:00 +00:00
Christophe Dumez
9408e8006d - Redesigned options
- Updated TODO
- Added UPnP option entry (but still not taken into consideration nor saved)
2007-03-27 20:26:07 +00:00
Christophe Dumez
2e4b7b375b - Removed option 'Automatically clear finished torrents' <- Decided it wasn't good for the network :) 2007-03-27 19:27:42 +00:00
Christophe Dumez
868d7cee4a - Removed some unused headers 2007-03-27 19:22:53 +00:00
Christophe Dumez
e8cc751f22 - Splitted search engine code from MainWindow part because GUI.cpp was getting too big and we are going to add a RSS tab soon
- Removed some unnecessary includes
2007-03-27 18:49:29 +00:00
Christophe Dumez
26e0c5d4ea - Updated TODO 2007-03-26 14:51:01 +00:00
Christophe Dumez
ef71b122df - Made ipfilter.dat parser less sensitive to errors 2007-03-26 14:48:01 +00:00
Christophe Dumez
98ecb97790 - Made ipfilter.dat parser less sensitive to errors 2007-03-26 14:45:09 +00:00
Christophe Dumez
86cfe82b89 - Updated version in desktop file 2007-03-26 07:49:34 +00:00
Christophe Dumez
1502bcb5d4 - Updated TODO
- Added a message box to display errors for torrent creation
2007-03-25 23:22:10 +00:00
Christophe Dumez
d2d3968b8b - Finished trackers edition 2007-03-25 18:39:27 +00:00
Christophe Dumez
1256da9bd5 - Remember edited trackers on restart 2007-03-25 16:18:57 +00:00
Christophe Dumez
1f6948d260 - Keep on working on trackers edition 2007-03-25 13:45:20 +00:00
Christophe Dumez
ab18594e00 - Updated Portuguese translation 2007-03-25 10:51:43 +00:00
Christophe Dumez
3467d68020 - Keep on working on trackers edition 2007-03-24 21:36:22 +00:00
Christophe Dumez
db7c7bd21a - Added missing icons in trackers tab (torrent properties) -> still unfinished 2007-03-24 20:55:15 +00:00
Christophe Dumez
f785888213 - Updated Changelog 2007-03-24 17:52:51 +00:00
Christophe Dumez
a346d49b60 - Displaying more infos about the torrent in its properties (hash, creator, comment)
- Preparing GUI to allow trackers list edition (Unfinished)
2007-03-24 17:50:53 +00:00
Christophe Dumez
5dacf4755e - Updated Ukrainian translation 2007-03-24 15:30:52 +00:00
Christophe Dumez
3e5f36dc97 - changed Danish to Dansk 2007-03-23 17:59:44 +00:00
Christophe Dumez
db55b72d87 - Updated TODO 2007-03-23 14:35:45 +00:00
Christophe Dumez
95844ce045 - Added option entry to select new Danish translation 2007-03-23 14:24:36 +00:00
Christophe Dumez
4bf4ed0f00 - Added Danish translation 2007-03-23 14:11:15 +00:00
Christophe Dumez
1d2d91d091 - Added a message saying if upnp is enabled or not 2007-03-23 14:10:16 +00:00
Christophe Dumez
40239f5cb2 - Updated spanish translation 2007-03-22 08:35:56 +00:00
Christophe Dumez
488e9d77b8 - Updated Bulgarian & greek translations 2007-03-19 21:54:33 +00:00
Christophe Dumez
85a5041a35 - Updated simplified chinese translation & translator 2007-03-19 21:21:01 +00:00
Christophe Dumez
fd2d2ddc0b - Added UPnP support (experimental) - taken from aMule CVS 2007-03-19 21:15:29 +00:00
Christophe Dumez
f8e7687551 - Added CONFIG += thread 2007-03-19 15:51:31 +00:00
Christophe Dumez
5140f42cb1 Update application style according to the system (WindowsXP, MacOS, X11) 2007-03-19 14:45:17 +00:00
Christophe Dumez
59e1e0bbf0 - Fixed a memory leak in options
- Removed unneeded QTranslator object in options.
2007-03-19 14:31:08 +00:00
Christophe Dumez
d53e85a232 - Updated TODO 2007-03-19 14:30:26 +00:00
Christophe Dumez
cf36db16ba - Updated korean translation 2007-03-17 13:56:59 +00:00
Christophe Dumez
5adf3f023d - Removing empty doc folders (moved) 2007-03-15 16:28:40 +00:00
Christophe Dumez
a0e49f8162 - bump version to v0.10.0alpha1 because now there is a branch for v0.9.x 2007-03-15 15:59:05 +00:00
Christophe Dumez
92eed29ded - Updated slovak translation 2007-03-15 15:54:06 +00:00
228 changed files with 99106 additions and 26609 deletions

View File

@@ -1 +1,6 @@
Christophe Dumez <chris@qbittorrent.org>
Author:
* Christophe Dumez <chris@qbittorrent.org>
Contributors:
* Arnaud Demaizière <arnaud@qbittorrent.org>
* Ishan Arora <ishanarora@gmail.com>

109
Changelog
View File

@@ -1,3 +1,112 @@
* Unknown - Christophe Dumez <chris@qbittorrent.org> - v1.1.0
- FEATURE: Web interface to control qbittorrent (Ishan Arora)
- FEATURE: Can spoof Azureus peer id to avoid ban
- FEATURE: Allow to hide/show some columns in download and seeding lists
- FEATURE: Option to start qBittorrent minimized in systray
- FEATURE: Allow to define double-click actions in torrents lists
- FEATURE: Allow to open torrent destination folder
- FEATURE: Real progress bar in torrent properties that displays downloaded pieces
- FEATURE: Allow to buy downloads using ShareMonkey
- FEATURE: Display if UPnP/NAT-PMP was successful or not
- FEATURE: Threadified torrent creation
- FEATURE: Improved eMule DAT ip filter parser
- FEATURE: Added support for PeerGuardian p2p filters (text)
- FEATURE: Added support for PeerGuardian p2b filters (binary)
- FEATURE: Allow to customize folder scan interval
- FEATURE: Allow to add several trackers at once
- BUGFIX: Do not display seeds number in seeding list (always 0)
- BUGFIX: Threadified IP filter file parser to avoid GUI freeze
- COSMETIC: Do not display progress bar in seeding list (always 100%)
- COSMETIC: Added a progress bar for torrent creation
- COSMETIC: Display tracker errors in a cleaner way
- COSMETIC: Display "unpaused/total_torrent" in download/upload tabs
- COSMETIC: Allow to resize RSS column
- COSMETIC: Global UP/DL speeds and ratio are displayed above tabs
* Fri Apr 11 2008 - Christophe Dumez <chris@qbittorrent.org> - v1.0.0
- FEATURE: Based on new libtorrent v0.13
- FEATURE: Added UPnP / NAT-PMP port forwarding support
- FEATURE: Added encryption support (compatible with Azureus)
- FEATURE: Bittorrent FAST extension support
- FEATURE: Added RSS support
- FEATURE: Support files prioritizing in a torrent
- FEATURE: Brand new search engine plugins system
- FEATURE: Filtered files don't appear on hard disk anymore
- FEATURE: Finished torrents are now moved to another tab for seeding
- FEATURE: Display more infos about the torrent in its properties
- FEATURE: Allow the user to edit torrents' trackers
- FEATURE: Allow user to change qBT's style (Plastique, Cleanlooks, Motif, CDE, MacOSX, WinXP)
- FEATURE: Allow the user to disable system tray integration
- FEATURE: Search engine is now using one thread per website for faster results
- FEATURE: Improved a lot the torrent creation module
- FEATURE: Allow to set upload/download limit per torrent (right click)
- FEATURE: Ask for exit confirmation only if download list is not empty
- FEATURE: Allow to use a proxy for trackers / web seeds / peers / DHT connections
- FEATURE: Supports SOCKS5 proxies as well as HTTP ones
- FEATURE: Better systems integration (buttons, dialogs...)
- FEATURE: Filtered files are not allocated on the hard-drive anymore (sparse file support)
- FEATURE: IPs blocked by filter are now logged in GUI
- FEATURE: Added a way to link against static libtorrent (useful for deb packages)
- FEATURE: Allow to set global upload/download limits from tray icon menu
- FEATURE: IPv6 is now fully supported
- FEATURE: Real torrent share ratio is now displayed in transfer list
- FEATURE: Added keyboard shortcuts for main actions (see wiki)
- FEATURE: Added a popup menu to set priority for multiple files at once
- FEATURE: Improved a lot downloading from urls (using libcommoncpp2 instead of libcurl)
- FEATURE: A search request can now be terminated by another
- FEATURE: User is now warned when fast resume data was rejected
- FEATURE: Url seeds are now displayed in torrent properties and are editable
- FEATURE: Allow to drag 'n drop urls on the main window
- FEATURE: Improved search engine (multipage support in all plugins)
- FEATURE: Added BTJunkie search engine plugin
- FEATURE: Added an option to force full disk allocation for all torrents
- FEATURE: Added an option to add torrents in paused state
- FEATURE: Added an option to set the max number of connections per torrent
- FEATURE: Added an option to set the max number of uploads per torrent
- FEATURE: Added an option to automatically delete torrents when they reach a given ratio (>= 1.0)
- FEATURE: Added an option to display current transfer speeds in title bar
- FEATURE: Torrent content is now displayed as a tree
- I18N: Added Hungarian translation
- I18N: Added Brazilian translation
- BUGFIX: Progress of paused torrents is now correct on restart
- BUGFIX: Progress column gets sorted on restart it is was during last execution
- BUGFIX: Made ETA more reliable using stats instead of instant values
- BUGFIX: Remove torrent from hard drive used to delete parent folder if empty
- BUGFIX: Fixed a crash when filtering all the files in a torrent
- BUGFIX: Reload torrent only when necessary (properties)
- BUGFIX: qBittorrent is not exiting anymore when a dialog is closed and main window is hidden
- BUGFIX: Search plugin update is not making the GUI freeze anymore (moved to a thread)
- BUGFIX: DHT settings were not saved correctly
- BUGFIX: Workaround to build on Fedora system (pkg-config problem)
- BUGFIX: search plugin update - do not display only last version changelog
- BUGFIX: Search plugin update - fixed missing new lines in changelog
- BUGFIX: The number of search results was not reset when clicking on 'Clear' button
- BUGFIX: Update torrent progress when its content changed (filtered files)
- BUGFIX: Improved the way menu icons are installed to avoid problems on some systems
- BUGFIX: Improved incremental download
- BUGFIX: Improved unicode support
- BUGFIX: Made torrent deletion from hard-drive safer
- BUGFIX: Prevent downloadFromUrl flooding
- BUGFIX: ETA was wrong for torrents with filtered files
- BUGFIX: Fixed drag'n drop on non-KDE systems
- BUGFIX: Removed build dependency on Python
- BUGFIX: Catching DHT exception in case there is a problem
- COSMETIC: Redesigned torrent properties a little
- COSMETIC: Totally redesigned program preferences
- COSMETIC: Display more logs messages concerning features
- COSMETIC: Improved lists renderers
- COSMETIC: Use a different icon for torrents being checked and for connecting ones
- COSMETIC: Improved some icons
- COSMETIC: Improved systray tooltip style
* Mon May 07 2007 - Christophe Dumez <chris@qbittorrent.org> - v0.9.3
- BUGFIX: Fixed pause toggle on double-click in download list
- BUGFIX: The torrent size displayed now only takes unfiltered files into account
- BUGFIX: Fixed compiling errors with libtorrent svn (future v0.13 with UPnP enabled)
- BUGFIX: Remember sorted column in download list on restart
- BUGFIX: Small fix in the german translation
- BUGFIX: Some fixes in slovak translation
* Tue Apr 10 2007 - Christophe Dumez <chris@qbittorrent.org> - v0.9.2
- BUGFIX: Window can now stay maximized on exit
- BUGFIX: Use PKGCONFIG again for configuring libtorrent

26
INSTALL
View File

@@ -1,4 +1,4 @@
qBittorrent - A BitTorrent client in C++ / Qt4.2
qBittorrent - A BitTorrent client in C++ / Qt4
------------------------------------------
*** Necessary if qt3 is default on your system ***
@@ -14,11 +14,12 @@ qbittorrent
will install and execute qBittorrent hopefully without any problems.
Dependencies:
- Qt >= 4.2 (libqt-devel, libqtgui, libqtcore, libqtnetwork)
- Qt >= 4.3.0 (libqt-devel, libqtgui, libqtcore, libqtnetwork, libqtxml)
- libtorrent by Arvid Norberg (>= v0.11 REQUIRED, >= 0.12 ADVISED)
-> http://libtorrent.sf.net
Be carefull: another library (the one used by rtorrent) use the same name.
- rblibtorrent by Arvid Norberg (>= v0.13 REQUIRED)
-> http://www.qbittorrent.org/download.php (advised)
-> http://www.libtorrent.net
Be careful: another library (the one used by rTorrent) use the same name.
These are TWO different libraries and qBittorrent will only work with the one provided
on sourceforge (created by Arvid Norberg). The two libraries conflicts with each other.
@@ -26,11 +27,20 @@ Dependencies:
- libcurl
- python >= 2.3 (previous might work - not tested): needed by search engine.
- python >= 2.3 (needed by search engine)
NOTE FOR GNOME USERS:
- qt4-qtconfig package is advised or qBittorrent interface will be ugly
- libmagick++ (advised, not required)
* Needed for favicons support (RSS / Search plugins)
- libzzip (advised, not required)
* Needed for zip support (Search plugins)
NOTE FOR NON-KDE USERS:
- qt4-qtconfig package is advised when using other systems than KDE.
You can also change qBittorrent style to Cleanlooks (GNOME like)
DOCUMENTATION:
Please note that there is a documentation with a "compiling howto" at http://wiki.qbittorrent.org.
------------------------------------------
Christophe Dumez <chris@qbittorrent.org>

16
README
View File

@@ -1,32 +1,32 @@
qBittorrent - A BitTorrent client in Qt4.2
qBittorrent - A BitTorrent client in Qt4
------------------------------------------
Description:
********************************
qBittorrent is a bittorrent client programmed in C++ / Qt4.2 that use
libtorrent (sometimes called rb_libtorrent) by Arvid Norberg.
qBittorrent is a bittorrent client programmed in C++ / Qt4 that uses
libtorrent (sometimes called rblibtorrent) by Arvid Norberg.
It aims to be a good alternative to all other bittorrent clients
out there. qBittorrent is fast, stable and provides unicode
support.
support as well as many features.
Installation:
********************************
For installation follow the instructions from INSTALL file, but simple
For installation, follow the instructions from INSTALL file, but simple:
./configure
make && make install
qbittorrent
will install and execute qBittorrent hopefully without any problems.
will install and execute qBittorrent hopefully without any problem.
For more information please visit:
http://www.qbittorrent.org
Please report any bug (or feature requests) to:
Please report any bug (or feature request) to:
http://bugs.qbittorrent.org
You can also meet me on IRC:
You can also meet me (chris-qBT) on IRC:
#qbittorrent on irc.freenode.net
------------------------------------------

50
TODO
View File

@@ -1,41 +1,37 @@
// Easy
- Write documentation
- Translations into as many languages as possible
- Improve man page
- Add more keyboard shortcuts
- Use Launchpad/Rosetta for translations once it supports TS files
// Intermediate
- Port on MacOS, Windows (and create an installer for Windows) - Progressing
- Add some transparency (menus,...)
- Add upnp port forwarding support
- Port on MacOS, Windows (and create an installer for Windows) - Slow progress
- Add some transparency (menus,...), improve look / usabilty
- Skins support? (contact Mateusz)
// Harder
- Allow user to organize the downloads into categories/folders
- Display new searches in new tabs
- Display a progress bar that really displays the pieces we have (like in eMule)
- Torrent scheduler ala µtorrent/Bitcomet
// Waiting for libtorrent
- Encryption support (v0.13?)
- File selection in a torrent in compact mode
- Allow to prioritize files within a torrent
- Allow to prioritize torrents
- Allow to prioritize torrents (may code this in qBittorrent?)
// Unsure
- Display the peers we are connected to for each torrent with infos (like flag, dl/up speeds, ...)
- Azureus spoofing to prevent ban from trackers?
- Web interface?
- Use downloader class to download search plugin updates
- Allow to set upload limit for each torrent
- Option to shutdown computer when downloads are finished
- Add a torrent scheduler
- NAT checker/Tester
- Display hard drive space left?
- Make use of dbus on Linux for the single instance instead of socket communication?
(http://techbase.kde.org/Development/Tutorials/D-Bus/Accessing_Interfaces)
- When favicon can't be downloaded, try to parse the webpage for:
<link rel="icon" href="http://example.com/favicon.ico" type="image/vnd.microsoft.icon">
* Be careful, the link can be relative
- Improve search plugin install (choose in a list taken from plugins.qbittorrent.org)
- support zipped torrents? (useful?)
- Allow to limit the number of downloading torrents simultaneously (other are paused until a download finishes)
// in v1.0.0 (partial)
- Download from RSS feeds (WIP by gtsoul)
- Move finished torrent to another tab and keep on seeding them even after restart
- Allow to edit the trackers for a torrent
- Improve torrent creation dialog (look & features)
- Add IPv6 support (at least start working on it)
- UPnP support?
// in v1.2.0
- Allow user to organize the downloads into categories/folders?
// in v1.1.0
- Stop calculating ETAs when ETA column is hidden
-> See https://blueprints.launchpad.net/qbittorrent
// In v0.9.0
- Update translations (FR, SV, NB, PL, RU, DE, SK, KO, ZH_CN, EL, BG, ES, DA, UK, PT, IT, NL done)
- Wait for libtorrent v0.12 official release

369
configure vendored
View File

@@ -1,6 +1,6 @@
#!/bin/sh
#
# Generated by qconf 1.3 ( http://delta.affinix.com/qconf/ )
# Generated by qconf 1.4 ( http://delta.affinix.com/qconf/ )
#
show_usage() {
@@ -20,9 +20,16 @@ Main options:
Dependency options:
--with-libtorrent-inc=[path] Path to libtorrent include files
--with-libtorrent-lib=[path] Path to libtorrent library files
--with-libtorrent-static-lib=[path] Path to libtorrent .a file
--with-libboost-inc=[path] Path to libboost include files
--with-libcurl-inc=[path] Path to libcurl include files
--with-libcurl-lib=[path] Path to libcurl library files
--disable-libmagick Disable use of libmagick
--with-libmagick-inc=[path] Path to libmagick++ include files
--with-libmagick-lib=[path] Path to libmagick++ library files
--disable-libzzip Disable use of libzzip
--with-libzzip-inc=[path] Path to libzzip++ include files
--with-libzzip-lib=[path] Path to libzzip++ library files
EOT
}
@@ -149,6 +156,11 @@ while [ $# -gt 0 ]; do
shift
;;
--with-libtorrent-static-lib=*)
QC_WITH_LIBTORRENT_STATIC_LIB=$optarg
shift
;;
--with-libboost-inc=*)
QC_WITH_LIBBOOST_INC=$optarg
shift
@@ -164,8 +176,38 @@ while [ $# -gt 0 ]; do
shift
;;
--disable-libmagick)
QC_DISABLE_libmagick="Y"
shift
;;
--with-libmagick-inc=*)
QC_WITH_LIBMAGICK_INC=$optarg
shift
;;
--with-libmagick-lib=*)
QC_WITH_LIBMAGICK_LIB=$optarg
shift
;;
--disable-libzzip)
QC_DISABLE_libzzip="Y"
shift
;;
--with-libzzip-inc=*)
QC_WITH_LIBZZIP_INC=$optarg
shift
;;
--with-libzzip-lib=*)
QC_WITH_LIBZZIP_LIB=$optarg
shift
;;
--verbose)
QC_DEBUG="Y"
QC_VERBOSE="Y"
shift
;;
--help) show_usage; exit ;;
@@ -179,7 +221,7 @@ DATADIR=${DATADIR:-$PREFIX/share}
echo "Configuring qbittorrent ..."
if [ "$QC_DEBUG" = "Y" ]; then
if [ "$QC_VERBOSE" = "Y" ]; then
echo
echo PREFIX=$PREFIX
echo BINDIR=$BINDIR
@@ -187,39 +229,65 @@ echo DATADIR=$DATADIR
echo EX_QTDIR=$EX_QTDIR
echo QC_WITH_LIBTORRENT_INC=$QC_WITH_LIBTORRENT_INC
echo QC_WITH_LIBTORRENT_LIB=$QC_WITH_LIBTORRENT_LIB
echo QC_WITH_LIBTORRENT_STATIC_LIB=$QC_WITH_LIBTORRENT_STATIC_LIB
echo QC_WITH_LIBBOOST_INC=$QC_WITH_LIBBOOST_INC
echo QC_WITH_LIBCURL_INC=$QC_WITH_LIBCURL_INC
echo QC_WITH_LIBCURL_LIB=$QC_WITH_LIBCURL_LIB
echo QC_DISABLE_libmagick=$QC_DISABLE_libmagick
echo QC_WITH_LIBMAGICK_INC=$QC_WITH_LIBMAGICK_INC
echo QC_WITH_LIBMAGICK_LIB=$QC_WITH_LIBMAGICK_LIB
echo QC_DISABLE_libzzip=$QC_DISABLE_libzzip
echo QC_WITH_LIBZZIP_INC=$QC_WITH_LIBZZIP_INC
echo QC_WITH_LIBZZIP_LIB=$QC_WITH_LIBZZIP_LIB
echo
fi
printf "Verifying Qt 4 build environment ... "
if [ "$QC_DEBUG" = "Y" ]; then
# run qmake -v and check version
qmake_check_v4() {
if [ -x "$1" ]; then
if echo `$1 -v 2>&1` | grep "Qt version 4\." >/dev/null 2>&1; then
return 0
elif [ "$QC_VERBOSE" = "Y" ]; then
echo "Warning: $1 not for Qt 4"
fi
fi
return 1
}
if [ "$QC_VERBOSE" = "Y" ]; then
echo
fi
qm=""
names="qmake-qt4 qmake4 qmake"
# qt4 check: --qtdir
if [ -z "$qm" ]; then
qstr=$EX_QTDIR/bin/qmake
if [ -x "$qstr" ]; then
if [ -z "$qm" ] && [ ! -z "$EX_QTDIR" ]; then
for n in $names; do
qstr=$EX_QTDIR/bin/$n
if qmake_check_v4 "$qstr"; then
qm=$qstr
break;
fi
done
fi
if [ -z "$qm" ] && [ "$QC_DEBUG" = "Y" ]; then
if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then
echo "Warning: qmake not found via --qtdir"
fi
# qt4 check: QTDIR
if [ -z "$qm" ]; then
qstr=$QTDIR/bin/qmake
if [ -x "$qstr" ]; then
if [ -z "$qm" ] && [ ! -z "$QTDIR" ]; then
for n in $names; do
qstr=$QTDIR/bin/$n
if qmake_check_v4 "$qstr"; then
qm=$qstr
break;
fi
done
fi
if [ -z "$qm" ] && [ "$QC_DEBUG" = "Y" ]; then
if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then
echo "Warning: qmake not found via \$QTDIR"
fi
@@ -227,60 +295,66 @@ fi
if [ -z "$qm" ]; then
str=`pkg-config QtCore --variable=exec_prefix 2>/dev/null`
if [ ! -z "$str" ]; then
qstr=$str/bin/qmake
if [ -x "$qstr" ]; then
for n in $names; do
qstr=$str/bin/$n
if qmake_check_v4 "$qstr"; then
qm=$qstr
break;
fi
done
fi
fi
fi
if [ -z "$qm" ] && [ "$QC_DEBUG" = "Y" ]; then
if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then
echo "Warning: qmake not found via pkg-config"
fi
# qt4 check: PATH
if [ -z "$qm" ]; then
qstr=`$WHICH qmake 2>/dev/null`
if [ -x "$qstr" ]; then
for n in $names; do
qstr=`$WHICH $n 2>/dev/null`
if qmake_check_v4 "$qstr"; then
qm=$qstr
break;
fi
done
fi
if [ -z "$qm" ] && [ "$QC_DEBUG" = "Y" ]; then
if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then
echo "Warning: qmake not found via \$PATH"
fi
if [ -z "$qm" ]; then
if [ "$QC_DEBUG" = "Y" ]; then
if [ "$QC_VERBOSE" = "Y" ]; then
echo " -> fail"
else
echo "fail"
fi
printf "\n"
printf "Reason: Unable to find the 'qmake' tool.\n"
printf "Reason: Unable to find the 'qmake' tool for Qt 4.\n"
printf "\n"
show_qt_info
exit 1;
fi
if [ "$QC_DEBUG" = "Y" ]; then
if [ "$QC_VERBOSE" = "Y" ]; then
echo qmake found in $qm
fi
gen_files() {
cat >$1/modules.cpp <<EOT
#line 1 "qt42.qcm"
#line 1 "qt4.qcm"
/*
-----BEGIN QCMOD-----
name: Qt >= 4.2
name: Qt >= 4.3
-----END QCMOD-----
*/
class qc_qt42 : public ConfObj
class qc_qt4 : public ConfObj
{
public:
qc_qt42(Conf *c) : ConfObj(c) {}
QString name() const { return "Qt >= 4.2"; }
QString shortname() const { return "qt42"; }
qc_qt4(Conf *c) : ConfObj(c) {}
QString name() const { return "Qt >= 4.3"; }
QString shortname() const { return "Qt 4.3"; }
bool exec()
{
return(QT_VERSION >= 0x040200);
return(QT_VERSION >= 0x040300);
}
};
#line 1 "libtorrent.qcm"
@@ -289,45 +363,46 @@ public:
name: libtorrent
arg: with-libtorrent-inc=[path], Path to libtorrent include files
arg: with-libtorrent-lib=[path], Path to libtorrent library files
arg: with-libtorrent-static-lib=[path], Path to libtorrent .a file
-----END QCMOD-----
*/
class qc_libtorrent : public ConfObj
{
public:
qc_libtorrent(Conf *c) : ConfObj(c) {}
QString name() const { return "libtorrent >= 0.11 (>= 0.12 ADVISED)"; }
QString name() const { return "libtorrent >= 0.13"; }
QString shortname() const { return "libtorrent"; }
bool exec(){
QString s;
s = conf->getenv("QC_WITH_LIBTORRENT_INC");
if(!s.isEmpty()) {
if(!conf->checkHeader(s, "libtorrent/kademlia/node.hpp")){
if(!conf->checkHeader(s, "libtorrent/lsd.hpp")) {
return false;
}
if(!conf->checkHeader(s, "libtorrent/extensions/ut_pex.hpp")) {
qWarning("Libtorrent >= v0.12 was not detected, PeX will be disabled.");
conf->addDefine("NO_PEX");
}
}else{
QStringList sl;
sl << "/usr/include";
sl << "/usr/local/include";
bool found = false;
foreach(s, sl){
if(conf->checkHeader(s, "libtorrent/kademlia/node.hpp")){
if(conf->checkHeader(s, "libtorrent/lsd.hpp")){
found = true;
break;
}
}
if(!found) return false;
if(!conf->checkHeader(s, "libtorrent/extensions/ut_pex.hpp")){
qWarning("Libtorrent >= v0.12 was not detected, PeX will be disabled.");
conf->addDefine("NO_PEX");
if(!found) {
return false;
}
}
conf->addIncludePath(s);
conf->addIncludePath(s+QDir::separator()+"libtorrent");
s = conf->getenv("QC_WITH_LIBTORRENT_STATIC_LIB");
if(!s.isEmpty() && QFile::exists(s) && s.endsWith(".a")){
conf->addLib(s);
return true;
}
s = conf->getenv("QC_WITH_LIBTORRENT_LIB");
if(!s.isEmpty()) {
if(!conf->checkLibrary(s, "torrent")) {
@@ -337,7 +412,9 @@ public:
}else{
QStringList sl;
sl << "/usr/lib/";
sl << "/usr/lib64/";
sl << "/usr/local/lib/";
sl << "/usr/local/lib64/";
bool found = false;
foreach(s, sl){
if(conf->checkLibrary(s, "torrent")){
@@ -348,7 +425,6 @@ public:
if(!found) return false;
conf->addLib(QString("-L") + s);
}
//conf->addLib("-ltorrent");
return true;
}
};
@@ -412,7 +488,7 @@ public:
#line 1 "libcurl.qcm"
/*
-----BEGIN QCMOD-----
name: libcurl
name: libcommoncpp2
arg: with-libcurl-inc=[path], Path to libcurl include files
arg: with-libcurl-lib=[path], Path to libcurl library files
-----END QCMOD-----
@@ -449,17 +525,18 @@ public:
s = conf->getenv("QC_WITH_LIBCURL_LIB");
if(!s.isEmpty()) {
if(!conf->checkLibrary(s, "curl")) {
if(!QFile::exists(s+QString("/libcurl.so")))
return false;
}
conf->addLib(QString("-L") + s);
}else{
QStringList sl;
sl << "/usr/lib/";
sl << "/usr/lib64/";
sl << "/usr/local/lib/";
sl << "/usr/local/lib64/";
bool found = false;
foreach(s, sl){
if(conf->checkLibrary(s, "curl")){
if(QFile::exists(s+QString("libcurl.so"))){
found = true;
break;
}
@@ -467,34 +544,165 @@ public:
if(!found) return false;
conf->addLib(QString("-L") + s);
}
conf->addLib("-lcurl");
return true;
}
};
#line 1 "python.qcm"
#line 1 "libmagick.qcm"
/*
-----BEGIN QCMOD-----
name: python
name: libmagick
arg: with-libmagick-inc=[path], Path to libmagick++ include files
arg: with-libmagick-lib=[path], Path to libmagick++ library files
-----END QCMOD-----
*/
class qc_python : public ConfObj
#include <QProcess>
class qc_libmagick : public ConfObj
{
public:
qc_python(Conf *c) : ConfObj(c) {}
QString name() const { return "python >= 2.3"; }
QString shortname() const { return "python"; }
qc_libmagick(Conf *c) : ConfObj(c) {}
QString name() const { return "ImageMagick library (libmagick++)"; }
QString shortname() const { return "libmagick++"; }
QString checkString() const {
if(!conf->getenv("QC_DISABLE_libmagick").isEmpty())
return "";
return ConfObj::checkString();
}
bool exec(){
int r = conf->doCommand("python testpython.py");
if(r == 0)
return true;
else
if(!conf->getenv("QC_DISABLE_libmagick").isEmpty())
return false;
QString s;
s = conf->getenv("QC_WITH_LIBMAGICK_INC");
if(!s.isEmpty()) {
if(!conf->checkHeader(s, "Magick++.h")) {
return false;
}
}else{
QStringList sl;
sl << "/usr/include";
sl << "/usr/local/include";
bool found = false;
foreach(s, sl){
if(conf->checkHeader(s, "Magick++.h")){
found = true;
break;
}
}
if(!found)
return false;
}
conf->addIncludePath(s);
s = conf->getenv("QC_WITH_LIBMAGICK_LIB");
if(!s.isEmpty()) {
if(!conf->checkLibrary(s, "Magick++")) {
return false;
}
}else{
QStringList sl;
sl << "/usr/lib/";
sl << "/usr/lib64/";
sl << "/usr/local/lib/";
sl << "/usr/local/lib64/";
bool found = false;
foreach(s, sl){
if(conf->checkLibrary(s, "Magick++")) {
found = true;
break;
}
}
if(!found)
return false;
}
conf->addLib(QString("-L") + s);
QProcess magickConfig;
QStringList params;
params << "--libs";
magickConfig.start("Magick++-config", params, QIODevice::ReadOnly);
magickConfig.waitForStarted();
magickConfig.waitForFinished();
QByteArray result = magickConfig.readAll();
result = result.replace("\n", "");
conf->addLib(result.data());
conf->addDefine("HAVE_MAGICK");
return true;
}
};
#line 1 "libzzip.qcm"
/*
-----BEGIN QCMOD-----
name: libzzip
arg: with-libzzip-inc=[path], Path to libzzip++ include files
arg: with-libzzip-lib=[path], Path to libzzip++ library files
-----END QCMOD-----
*/
#include <QProcess>
class qc_libzzip : public ConfObj
{
public:
qc_libzzip(Conf *c) : ConfObj(c) {}
QString name() const { return "Zzip library (libzzip)"; }
QString shortname() const { return "libzzip"; }
QString checkString() const {
if(!conf->getenv("QC_DISABLE_LIBZZIP").isEmpty())
return "";
return ConfObj::checkString();
}
bool exec(){
if(!conf->getenv("QC_DISABLE_LIBZZIP").isEmpty())
return false;
QString s;
s = conf->getenv("QC_WITH_LIBZZIP_INC");
if(!s.isEmpty()) {
if(!conf->checkHeader(s, "zzip/zzip.h")) {
return false;
}
}else{
QStringList sl;
sl << "/usr/include";
sl << "/usr/local/include";
bool found = false;
foreach(s, sl){
if(conf->checkHeader(s, "zzip/zzip.h")){
found = true;
break;
}
}
if(!found)
return false;
}
conf->addIncludePath(s);
s = conf->getenv("QC_WITH_LIBZZIP_LIB");
if(!s.isEmpty()) {
if(!QFile::exists(s+QString("/libzzip.so"))){
return false;
}
}else{
QStringList sl;
sl << "/usr/lib/";
sl << "/usr/lib64/";
sl << "/usr/local/lib/";
sl << "/usr/local/lib64/";
bool found = false;
foreach(s, sl){
if(QFile::exists(s+QString("libzzip.so"))){
found = true;
break;
}
}
if(!found)
return false;
}
conf->addLib(QString("-L") + s);
conf->addLib("-lzzip");
conf->addDefine("HAVE_ZZIP");
return true;
}
};
EOT
cat >$1/modules_new.cpp <<EOT
o = new qc_qt42(conf);
o = new qc_qt4(conf);
o->required = true;
o->disabled = false;
o = new qc_libtorrent(conf);
@@ -506,12 +714,17 @@ cat >$1/modules_new.cpp <<EOT
o = new qc_libcurl(conf);
o->required = true;
o->disabled = false;
o = new qc_python(conf);
o->required = true;
o = new qc_libmagick(conf);
o->required = false;
o->disabled = false;
o = new qc_libzzip(conf);
o->required = false;
o->disabled = false;
EOT
cat >$1/conf4.h <<EOT
// For license information, see the COPYING file in the qconf base directory.
#ifndef QC_CONF4_H
#define QC_CONF4_H
@@ -616,6 +829,8 @@ private:
EOT
cat >$1/conf4.cpp <<EOT
// For license information, see the COPYING file in the qconf base directory.
#include "conf4.h"
#include <stdio.h>
@@ -766,6 +981,18 @@ void qc_splitcflags(const QString &cflags, QStringList *incs, QStringList *other
}
}
QString qc_escapeArg(const QString &str)
{
QString out;
for(int n = 0; n < (int)str.length(); ++n) {
if(str[n] == '-')
out += '_';
else
out += str[n];
}
return out;
}
//----------------------------------------------------------------------------
// ConfObj
//----------------------------------------------------------------------------
@@ -882,14 +1109,14 @@ bool Conf::exec()
// if this was a disabled-by-default option, check if it was enabled
if(o->disabled)
{
QString v = QString("QC_ENABLE_") + o->shortname();
QString v = QString("QC_ENABLE_") + qc_escapeArg(o->shortname());
if(getenv(v) != "Y")
continue;
}
// and the opposite?
else
{
QString v = QString("QC_DISABLE_") + o->shortname();
QString v = QString("QC_DISABLE_") + qc_escapeArg(o->shortname());
if(getenv(v) == "Y")
continue;
}
@@ -1316,7 +1543,7 @@ int main()
# include"modules_new.cpp"
#endif
conf->debug_enabled = (qc_getenv("QC_DEBUG") == "Y") ? true: false;
conf->debug_enabled = (qc_getenv("QC_VERBOSE") == "Y") ? true: false;
if(conf->debug_enabled)
printf(" -> ok\n");
else
@@ -1372,6 +1599,9 @@ int main()
var = qc_getenv("BINDIR");
if(!var.isEmpty())
str += QString("BINDIR = %1\n").arg(var);
var = qc_getenv("INCDIR");
if(!var.isEmpty())
str += QString("INCDIR = %1\n").arg(var);
var = qc_getenv("LIBDIR");
if(!var.isEmpty())
str += QString("LIBDIR = %1\n").arg(var);
@@ -1437,10 +1667,17 @@ export DATADIR
export EX_QTDIR
export QC_WITH_LIBTORRENT_INC
export QC_WITH_LIBTORRENT_LIB
export QC_WITH_LIBTORRENT_STATIC_LIB
export QC_WITH_LIBBOOST_INC
export QC_WITH_LIBCURL_INC
export QC_WITH_LIBCURL_LIB
export QC_DEBUG
export QC_DISABLE_libmagick
export QC_WITH_LIBMAGICK_INC
export QC_WITH_LIBMAGICK_LIB
export QC_DISABLE_libzzip
export QC_WITH_LIBZZIP_INC
export QC_WITH_LIBZZIP_LIB
export QC_VERBOSE
rm -rf .qconftemp
(
mkdir .qconftemp
@@ -1453,7 +1690,7 @@ rm -rf .qconftemp
if [ "$?" != "0" ]; then
rm -rf .qconftemp
if [ "$QC_DEBUG" = "Y" ]; then
if [ "$QC_VERBOSE" = "Y" ]; then
echo " -> fail"
else
echo "fail"
@@ -1462,7 +1699,7 @@ if [ "$?" != "0" ]; then
printf "Reason: There was an error compiling 'conf'. See conf.log for details.\n"
printf "\n"
show_qt_info
if [ "$QC_DEBUG" = "Y" ]; then
if [ "$QC_VERBOSE" = "Y" ]; then
echo "conf.log:"
cat conf.log
fi
@@ -1486,7 +1723,7 @@ if [ "$ret" = "1" ]; then
else
if [ "$ret" != "0" ]; then
rm -rf .qconftemp
if [ "$QC_DEBUG" = "Y" ]; then
if [ "$QC_VERBOSE" = "Y" ]; then
echo " -> fail"
else
echo "fail"

28
doc/qbittorrent.1 Normal file
View File

@@ -0,0 +1,28 @@
.\" This manpage has been automatically generated by docbook2man
.\" from a DocBook document. This tool can be found at:
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>.
.TH "QBITTORRENT" "1" "September 1st 2007" "Bittorrent client written in C++ / Qt4" ""
.SH NAME
qBittorrent \- a Bittorrent client written in C++ / Qt4
.SH SYNOPSIS
\fBqbittorrent\fR [FILE | URL] [FILE | URL...]
\fBqbittorrent\fR \-\-help
\fBqbittorrent\fR \-\-version
.PP
.SH "DESCRIPTION"
\fBqBittorrent\fR is an advanced Bittorrent client written in C++ / Qt4,
using the \fBrblibtorrent\fR library by Arvid Norberg. qBittorrent aims
to be a good alternative to all other bittorrent clients out there. qBittorrent
is fast, stable, light, it supports unicode and it provides a good integrated search engine.
It also comes with UPnP port forwarding / NAT-PMP, encryption (Azureus compatible), FAST extension (mainline) and PeX support (utorrent compatible).
Please report any problem to http://bugs.qbittorrent.org
.PP
.SH "AUTHOR"
Christophe Dumez <chris@qbittorrent.org>

Binary file not shown.

199
qBittorrent.kdevelop Normal file
View File

@@ -0,0 +1,199 @@
<?xml version = '1.0'?>
<kdevelop>
<general>
<author>Christophe Dumez</author>
<email>chris@qbittorrent.org</email>
<version>1.0.0</version>
<projectmanagement>KDevTrollProject</projectmanagement>
<primarylanguage>C++</primarylanguage>
<keywords>
<keyword>Qt</keyword>
</keywords>
<projectname>qBittorrent</projectname>
<ignoreparts/>
<projectdirectory>.</projectdirectory>
<absoluteprojectpath>false</absoluteprojectpath>
<description/>
<defaultencoding/>
<versioncontrol>kdevsubversion</versioncontrol>
</general>
<kdevfileview>
<groups>
<group pattern="*.cpp;*.cxx;*.h" name="Sources" />
<group pattern="*.ui" name="User Interface" />
<group pattern="*.png" name="Icons" />
<group pattern="*" name="Others" />
<hidenonprojectfiles>false</hidenonprojectfiles>
<hidenonlocation>false</hidenonlocation>
</groups>
<tree>
<hidepatterns>*.o,*.lo,CVS</hidepatterns>
<hidenonprojectfiles>false</hidenonprojectfiles>
<showvcsfields>false</showvcsfields>
</tree>
</kdevfileview>
<kdevdoctreeview>
<ignoretocs>
<toc>bash</toc>
<toc>bash_bugs</toc>
<toc>clanlib</toc>
<toc>w3c-dom-level2-html</toc>
<toc>fortran_bugs_gcc</toc>
<toc>gnome1</toc>
<toc>gnustep</toc>
<toc>gtk</toc>
<toc>gtk_bugs</toc>
<toc>haskell</toc>
<toc>haskell_bugs_ghc</toc>
<toc>java_bugs_gcc</toc>
<toc>java_bugs_sun</toc>
<toc>kde2book</toc>
<toc>opengl</toc>
<toc>pascal_bugs_fp</toc>
<toc>php</toc>
<toc>php_bugs</toc>
<toc>perl</toc>
<toc>perl_bugs</toc>
<toc>python</toc>
<toc>python_bugs</toc>
<toc>qt-kdev3</toc>
<toc>ruby</toc>
<toc>ruby_bugs</toc>
<toc>sdl</toc>
<toc>stl</toc>
<toc>w3c-svg</toc>
<toc>sw</toc>
<toc>w3c-uaag10</toc>
<toc>wxwidgets_bugs</toc>
</ignoretocs>
<ignoredoxygen>
<toc>KDE Libraries (Doxygen)</toc>
</ignoredoxygen>
</kdevdoctreeview>
<kdevdebugger>
<general>
<dbgshell/>
<gdbpath/>
<configGdbScript/>
<runShellScript/>
<runGdbScript/>
<breakonloadinglibs>true</breakonloadinglibs>
<separatetty>false</separatetty>
<floatingtoolbar>false</floatingtoolbar>
</general>
<display>
<staticmembers>false</staticmembers>
<demanglenames>true</demanglenames>
<outputradix>10</outputradix>
</display>
</kdevdebugger>
<kdevcppsupport>
<qt>
<version>4</version>
<used>true</used>
<includestyle>4</includestyle>
<designerintegration>ExternalDesigner</designerintegration>
<root>/usr/lib/qt4</root>
<qmake>/usr/bin/qmake</qmake>
<designer>/usr/bin/designer</designer>
<designerpluginpaths/>
</qt>
<references>
<pcs>automatic_%2Fhome%2Fishanarora%2Fprojects%2Fqbittorrent</pcs>
</references>
<codecompletion>
<automaticCodeCompletion>true</automaticCodeCompletion>
<automaticArgumentsHint>true</automaticArgumentsHint>
<automaticHeaderCompletion>true</automaticHeaderCompletion>
<codeCompletionDelay>250</codeCompletionDelay>
<argumentsHintDelay>400</argumentsHintDelay>
<headerCompletionDelay>250</headerCompletionDelay>
<showOnlyAccessibleItems>false</showOnlyAccessibleItems>
<completionBoxItemOrder>0</completionBoxItemOrder>
<howEvaluationContextMenu>true</howEvaluationContextMenu>
<showCommentWithArgumentHint>true</showCommentWithArgumentHint>
<statusBarTypeEvaluation>false</statusBarTypeEvaluation>
<namespaceAliases>std=_GLIBCXX_STD;__gnu_cxx=std</namespaceAliases>
<processPrimaryTypes>true</processPrimaryTypes>
<processFunctionArguments>true</processFunctionArguments>
<preProcessAllHeaders>true</preProcessAllHeaders>
<parseMissingHeadersExperimental>true</parseMissingHeadersExperimental>
<resolveIncludePathsUsingMakeExperimental>true</resolveIncludePathsUsingMakeExperimental>
<alwaysParseInBackground>true</alwaysParseInBackground>
<usePermanentCaching>true</usePermanentCaching>
<alwaysIncludeNamespaces>false</alwaysIncludeNamespaces>
<includePaths>.;</includePaths>
</codecompletion>
<creategettersetter>
<prefixGet>get</prefixGet>
<prefixSet>set</prefixSet>
<prefixVariable>m_,_</prefixVariable>
<parameterName>theValue</parameterName>
<inlineGet>true</inlineGet>
<inlineSet>true</inlineSet>
</creategettersetter>
<splitheadersource>
<enabled>false</enabled>
<synchronize>true</synchronize>
<orientation>Vertical</orientation>
</splitheadersource>
</kdevcppsupport>
<kdevfilecreate>
<filetypes/>
<useglobaltypes>
<type ext="ui" />
<type ext="cpp" />
<type ext="h" />
</useglobaltypes>
</kdevfilecreate>
<kdevtrollproject>
<general>
<activedir>src</activedir>
</general>
<run>
<directoryradio>executable</directoryradio>
<mainprogram>/home/ishanarora/projects/qbittorrent/src/qbittorrent</mainprogram>
<programargs/>
<globaldebugarguments/>
<globalcwd>/home/ishanarora/projects/qbittorrent</globalcwd>
<useglobalprogram>true</useglobalprogram>
<terminal>false</terminal>
<autocompile>true</autocompile>
<autoinstall>false</autoinstall>
<autokdesu>false</autokdesu>
<envvars/>
</run>
<make>
<abortonerror>true</abortonerror>
<runmultiplejobs>false</runmultiplejobs>
<numberofjobs>1</numberofjobs>
<dontact>false</dontact>
<makebin/>
<prio>0</prio>
<envvars/>
</make>
<qmake>
<savebehaviour>2</savebehaviour>
<replacePaths>false</replacePaths>
<disableDefaultOpts>true</disableDefaultOpts>
</qmake>
</kdevtrollproject>
<cppsupportpart>
<filetemplates>
<interfacesuffix>.h</interfacesuffix>
<implementationsuffix>.cpp</implementationsuffix>
</filetemplates>
</cppsupportpart>
<ctagspart>
<customArguments/>
<customTagfilePath>/home/ishanarora/projects/qbittorrent/tags</customTagfilePath>
<activeTagsFiles/>
</ctagspart>
<kdevdocumentation>
<projectdoc>
<docsystem/>
<docurl/>
<usermanualurl/>
</projectdoc>
</kdevdocumentation>
</kdevelop>

View File

@@ -2,7 +2,8 @@
<name>qbittorrent</name>
<profile>qbittorrent.pro</profile>
<moddir>qcm</moddir>
<dep type='qt42'>
<datadir/>
<dep type='qt4'>
<required/>
</dep>
<dep type='libtorrent'>
@@ -14,7 +15,6 @@
<dep type='libcurl'>
<required/>
</dep>
<dep type='python'>
<required/>
</dep>
<dep type='libmagick'/>
<dep type='libzzip'/>
</qconf>

65
qcm/libcommoncpp2.qcm Normal file
View File

@@ -0,0 +1,65 @@
/*
-----BEGIN QCMOD-----
name: libcommoncpp2
arg: with-libcommoncpp2-inc=[path], Path to libcommoncpp2 include files
arg: with-libcommoncpp2-lib=[path], Path to libcommoncpp2 library files
-----END QCMOD-----
*/
class qc_libcommoncpp2 : public ConfObj
{
public:
qc_libcommoncpp2(Conf *c) : ConfObj(c) {}
QString name() const { return "GNU Common C++ library (libcommoncpp2)"; }
QString shortname() const { return "libcommoncpp2"; }
bool exec(){
QString s;
s = conf->getenv("QC_WITH_LIBCOMMONCPP2_INC");
if(!s.isEmpty()) {
if(!conf->checkHeader(s, "cc++/url.h")) {
return false;
}
}else{
QStringList sl;
sl << "/usr/include";
sl << "/usr/local/include";
bool found = false;
foreach(s, sl){
if(conf->checkHeader(s, "cc++/url.h")){
found = true;
break;
}
}
if(!found) {
return false;
}
}
conf->addIncludePath(s);
s = conf->getenv("QC_WITH_LIBCOMMONCPP2_LIB");
if(!s.isEmpty()) {
if(!QFile::exists(s+QString("/libccext2.so")))
return false;
if(!QFile::exists(s+QString("/libccgnu2.so")))
return false;
conf->addLib(QString("-L") + s);
}else{
QStringList sl;
sl << "/usr/lib/";
sl << "/usr/lib64/";
sl << "/usr/local/lib/";
sl << "/usr/local/lib64/";
bool found = false;
foreach(s, sl){
if(QFile::exists(s+QString("libccext2.so"))){
if(QFile::exists(s+QString("libccgnu2.so"))){
found = true;
break;
}
}
}
if(!found) return false;
conf->addLib(QString("-L") + s);
}
return true;
}
};

View File

@@ -1,6 +1,6 @@
/*
-----BEGIN QCMOD-----
name: libcurl
name: libcommoncpp2
arg: with-libcurl-inc=[path], Path to libcurl include files
arg: with-libcurl-lib=[path], Path to libcurl library files
-----END QCMOD-----
@@ -37,17 +37,18 @@ public:
s = conf->getenv("QC_WITH_LIBCURL_LIB");
if(!s.isEmpty()) {
if(!conf->checkLibrary(s, "curl")) {
if(!QFile::exists(s+QString("/libcurl.so")))
return false;
}
conf->addLib(QString("-L") + s);
}else{
QStringList sl;
sl << "/usr/lib/";
sl << "/usr/lib64/";
sl << "/usr/local/lib/";
sl << "/usr/local/lib64/";
bool found = false;
foreach(s, sl){
if(conf->checkLibrary(s, "curl")){
if(QFile::exists(s+QString("libcurl.so"))){
found = true;
break;
}
@@ -55,7 +56,6 @@ public:
if(!found) return false;
conf->addLib(QString("-L") + s);
}
conf->addLib("-lcurl");
return true;
}
};

79
qcm/libmagick.qcm Normal file
View File

@@ -0,0 +1,79 @@
/*
-----BEGIN QCMOD-----
name: libmagick
arg: with-libmagick-inc=[path], Path to libmagick++ include files
arg: with-libmagick-lib=[path], Path to libmagick++ library files
-----END QCMOD-----
*/
#include <QProcess>
class qc_libmagick : public ConfObj
{
public:
qc_libmagick(Conf *c) : ConfObj(c) {}
QString name() const { return "ImageMagick library (libmagick++)"; }
QString shortname() const { return "libmagick++"; }
QString checkString() const {
if(!conf->getenv("QC_DISABLE_libmagick").isEmpty())
return "";
return ConfObj::checkString();
}
bool exec(){
if(!conf->getenv("QC_DISABLE_libmagick").isEmpty())
return false;
QString s;
s = conf->getenv("QC_WITH_LIBMAGICK_INC");
if(!s.isEmpty()) {
if(!conf->checkHeader(s, "Magick++.h")) {
return false;
}
}else{
QStringList sl;
sl << "/usr/include";
sl << "/usr/local/include";
bool found = false;
foreach(s, sl){
if(conf->checkHeader(s, "Magick++.h")){
found = true;
break;
}
}
if(!found)
return false;
}
conf->addIncludePath(s);
s = conf->getenv("QC_WITH_LIBMAGICK_LIB");
if(!s.isEmpty()) {
if(!conf->checkLibrary(s, "Magick++")) {
return false;
}
}else{
QStringList sl;
sl << "/usr/lib/";
sl << "/usr/lib64/";
sl << "/usr/local/lib/";
sl << "/usr/local/lib64/";
bool found = false;
foreach(s, sl){
if(conf->checkLibrary(s, "Magick++")) {
found = true;
break;
}
}
if(!found)
return false;
}
conf->addLib(QString("-L") + s);
QProcess magickConfig;
QStringList params;
params << "--libs";
magickConfig.start("Magick++-config", params, QIODevice::ReadOnly);
magickConfig.waitForStarted();
magickConfig.waitForFinished();
QByteArray result = magickConfig.readAll();
result = result.replace("\n", "");
conf->addLib(result.data());
conf->addDefine("HAVE_MAGICK");
return true;
}
};

View File

@@ -3,45 +3,46 @@
name: libtorrent
arg: with-libtorrent-inc=[path], Path to libtorrent include files
arg: with-libtorrent-lib=[path], Path to libtorrent library files
arg: with-libtorrent-static-lib=[path], Path to libtorrent .a file
-----END QCMOD-----
*/
class qc_libtorrent : public ConfObj
{
public:
qc_libtorrent(Conf *c) : ConfObj(c) {}
QString name() const { return "libtorrent >= 0.11 (>= 0.12 ADVISED)"; }
QString name() const { return "libtorrent >= 0.13"; }
QString shortname() const { return "libtorrent"; }
bool exec(){
QString s;
s = conf->getenv("QC_WITH_LIBTORRENT_INC");
if(!s.isEmpty()) {
if(!conf->checkHeader(s, "libtorrent/kademlia/node.hpp")){
if(!conf->checkHeader(s, "libtorrent/lsd.hpp")) {
return false;
}
if(!conf->checkHeader(s, "libtorrent/extensions/ut_pex.hpp")) {
qWarning("Libtorrent >= v0.12 was not detected, PeX will be disabled.");
conf->addDefine("NO_PEX");
}
}else{
QStringList sl;
sl << "/usr/include";
sl << "/usr/local/include";
bool found = false;
foreach(s, sl){
if(conf->checkHeader(s, "libtorrent/kademlia/node.hpp")){
if(conf->checkHeader(s, "libtorrent/lsd.hpp")){
found = true;
break;
}
}
if(!found) return false;
if(!conf->checkHeader(s, "libtorrent/extensions/ut_pex.hpp")){
qWarning("Libtorrent >= v0.12 was not detected, PeX will be disabled.");
conf->addDefine("NO_PEX");
if(!found) {
return false;
}
}
conf->addIncludePath(s);
conf->addIncludePath(s+QDir::separator()+"libtorrent");
s = conf->getenv("QC_WITH_LIBTORRENT_STATIC_LIB");
if(!s.isEmpty() && QFile::exists(s) && s.endsWith(".a")){
conf->addLib(s);
return true;
}
s = conf->getenv("QC_WITH_LIBTORRENT_LIB");
if(!s.isEmpty()) {
if(!conf->checkLibrary(s, "torrent")) {
@@ -51,7 +52,9 @@ public:
}else{
QStringList sl;
sl << "/usr/lib/";
sl << "/usr/lib64/";
sl << "/usr/local/lib/";
sl << "/usr/local/lib64/";
bool found = false;
foreach(s, sl){
if(conf->checkLibrary(s, "torrent")){
@@ -62,7 +65,6 @@ public:
if(!found) return false;
conf->addLib(QString("-L") + s);
}
//conf->addLib("-ltorrent");
return true;
}
};

71
qcm/libzzip.qcm Normal file
View File

@@ -0,0 +1,71 @@
/*
-----BEGIN QCMOD-----
name: libzzip
arg: with-libzzip-inc=[path], Path to libzzip++ include files
arg: with-libzzip-lib=[path], Path to libzzip++ library files
-----END QCMOD-----
*/
#include <QProcess>
class qc_libzzip : public ConfObj
{
public:
qc_libzzip(Conf *c) : ConfObj(c) {}
QString name() const { return "Zzip library (libzzip)"; }
QString shortname() const { return "libzzip"; }
QString checkString() const {
if(!conf->getenv("QC_DISABLE_LIBZZIP").isEmpty())
return "";
return ConfObj::checkString();
}
bool exec(){
if(!conf->getenv("QC_DISABLE_LIBZZIP").isEmpty())
return false;
QString s;
s = conf->getenv("QC_WITH_LIBZZIP_INC");
if(!s.isEmpty()) {
if(!conf->checkHeader(s, "zzip/zzip.h")) {
return false;
}
}else{
QStringList sl;
sl << "/usr/include";
sl << "/usr/local/include";
bool found = false;
foreach(s, sl){
if(conf->checkHeader(s, "zzip/zzip.h")){
found = true;
break;
}
}
if(!found)
return false;
}
conf->addIncludePath(s);
s = conf->getenv("QC_WITH_LIBZZIP_LIB");
if(!s.isEmpty()) {
if(!QFile::exists(s+QString("/libzzip.so"))){
return false;
}
}else{
QStringList sl;
sl << "/usr/lib/";
sl << "/usr/lib64/";
sl << "/usr/local/lib/";
sl << "/usr/local/lib64/";
bool found = false;
foreach(s, sl){
if(QFile::exists(s+QString("libzzip.so"))){
found = true;
break;
}
}
if(!found)
return false;
}
conf->addLib(QString("-L") + s);
conf->addLib("-lzzip");
conf->addDefine("HAVE_ZZIP");
return true;
}
};

View File

@@ -1,19 +0,0 @@
/*
-----BEGIN QCMOD-----
name: python
-----END QCMOD-----
*/
class qc_python : public ConfObj
{
public:
qc_python(Conf *c) : ConfObj(c) {}
QString name() const { return "python >= 2.3"; }
QString shortname() const { return "python"; }
bool exec(){
int r = conf->doCommand("python testpython.py");
if(r == 0)
return true;
else
return false;
}
};

16
qcm/qt4.qcm Normal file
View File

@@ -0,0 +1,16 @@
/*
-----BEGIN QCMOD-----
name: Qt >= 4.3
-----END QCMOD-----
*/
class qc_qt4 : public ConfObj
{
public:
qc_qt4(Conf *c) : ConfObj(c) {}
QString name() const { return "Qt >= 4.3"; }
QString shortname() const { return "Qt 4.3"; }
bool exec()
{
return(QT_VERSION >= 0x040300);
}
};

View File

@@ -1,16 +0,0 @@
/*
-----BEGIN QCMOD-----
name: Qt >= 4.2
-----END QCMOD-----
*/
class qc_qt42 : public ConfObj
{
public:
qc_qt42(Conf *c) : ConfObj(c) {}
QString name() const { return "Qt >= 4.2"; }
QString shortname() const { return "qt42"; }
bool exec()
{
return(QT_VERSION >= 0x040200);
}
};

View File

@@ -22,10 +22,11 @@
#ifndef DLLISTDELEGATE_H
#define DLLISTDELEGATE_H
#include <QAbstractItemDelegate>
#include <QItemDelegate>
#include <QModelIndex>
#include <QPainter>
#include <QStyleOptionProgressBarV2>
#include <QStyleOptionViewItemV2>
#include <QProgressBar>
#include <QApplication>
#include "misc.h"
@@ -37,128 +38,66 @@
#define DLSPEED 3
#define UPSPEED 4
#define SEEDSLEECH 5
#define STATUS 6
#define RATIO 6
#define ETA 7
#define HASH 8
class DLListDelegate: public QAbstractItemDelegate {
class DLListDelegate: public QItemDelegate {
Q_OBJECT
public:
DLListDelegate(QObject *parent=0) : QAbstractItemDelegate(parent){}
DLListDelegate(QObject *parent) : QItemDelegate(parent){}
~DLListDelegate(){}
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const{
QStyleOptionViewItem opt = option;
char tmp[MAX_CHAR_TMP];
// set text color
QVariant value = index.data(Qt::TextColorRole);
if (value.isValid() && qvariant_cast<QColor>(value).isValid()){
opt.palette.setColor(QPalette::Text, qvariant_cast<QColor>(value));
}
QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
? QPalette::Normal : QPalette::Disabled;
if (option.state & QStyle::State_Selected){
painter->setPen(opt.palette.color(cg, QPalette::HighlightedText));
}else{
painter->setPen(opt.palette.color(cg, QPalette::Text));
}
// draw the background color
if(index.column() != PROGRESS){
if (option.showDecorationSelected && (option.state & QStyle::State_Selected)){
if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)){
cg = QPalette::Inactive;
}
painter->fillRect(option.rect, option.palette.brush(cg, QPalette::Highlight));
}else{
value = index.data(Qt::BackgroundColorRole);
if (value.isValid() && qvariant_cast<QColor>(value).isValid()){
painter->fillRect(option.rect, qvariant_cast<QColor>(value));
}
}
}
QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option);
switch(index.column()){
case SIZE:
painter->drawText(option.rect, Qt::AlignCenter, misc::friendlyUnit(index.data().toLongLong()));
QItemDelegate::drawBackground(painter, opt, index);
QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong()));
break;
case ETA:
painter->drawText(option.rect, Qt::AlignCenter, misc::userFriendlyDuration(index.data().toLongLong()));
QItemDelegate::drawBackground(painter, opt, index);
QItemDelegate::drawDisplay(painter, opt, option.rect, misc::userFriendlyDuration(index.data().toLongLong()));
break;
case UPSPEED:
case DLSPEED:{
float speed = index.data().toDouble();
snprintf(tmp, MAX_CHAR_TMP, "%.1f", speed/1024.);
painter->drawText(option.rect, Qt::AlignCenter, QString(tmp)+" "+tr("KiB/s"));
QItemDelegate::drawBackground(painter, opt, index);
double speed = index.data().toDouble();
QItemDelegate::drawDisplay(painter, opt, opt.rect, QString(QByteArray::number(speed/1024., 'f', 1))+QString::fromUtf8(" ")+tr("KiB/s"));
break;
}
case RATIO:{
QItemDelegate::drawBackground(painter, opt, index);
double ratio = index.data().toDouble();
QItemDelegate::drawDisplay(painter, opt, opt.rect, QString(QByteArray::number(ratio, 'f', 1)));
break;
}
case PROGRESS:{
QStyleOptionProgressBarV2 newopt;
float progress;
progress = index.data().toDouble()*100.;
snprintf(tmp, MAX_CHAR_TMP, "%.1f", progress);
double progress = index.data().toDouble()*100.;
newopt.rect = opt.rect;
newopt.text = QString(tmp)+"%";
newopt.text = QString(QByteArray::number(progress, 'f', 1))+QString::fromUtf8("%");
newopt.progress = (int)progress;
newopt.maximum = 100;
newopt.minimum = 0;
newopt.state |= QStyle::State_Enabled;
newopt.textVisible = false;
newopt.textVisible = true;
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt,
painter);
//We prefer to display text manually to control color/font/boldness
if (option.state & QStyle::State_Selected){
opt.palette.setColor(QPalette::Text, QColor("grey"));
painter->setPen(opt.palette.color(cg, QPalette::Text));
}
painter->drawText(option.rect, Qt::AlignCenter, newopt.text);
break;
}
case NAME:{
// decoration
value = index.data(Qt::DecorationRole);
QPixmap pixmap = qvariant_cast<QIcon>(value).pixmap(option.decorationSize, option.state & QStyle::State_Enabled ? QIcon::Normal : QIcon::Disabled, option.state & QStyle::State_Open ? QIcon::On : QIcon::Off);
QRect pixmapRect = (pixmap.isNull() ? QRect(0, 0, 0, 0): QRect(QPoint(0, 0), option.decorationSize));
if (pixmapRect.isValid()){
QPoint p = QStyle::alignedRect(option.direction, Qt::AlignLeft, pixmap.size(), option.rect).topLeft();
painter->drawPixmap(p, pixmap);
}
painter->drawText(option.rect.translated(pixmap.size().width(), 0), Qt::AlignLeft, index.data().toString());
break;
}
default:
painter->drawText(option.rect, Qt::AlignCenter, index.data().toString());
QItemDelegate::paint(painter, option, index);
}
}
QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const{
QVariant value = index.data(Qt::FontRole);
QFont fnt = value.isValid() ? qvariant_cast<QFont>(value) : option.font;
QFontMetrics fontMetrics(fnt);
const QString text = index.data(Qt::DisplayRole).toString();
QRect textRect = QRect(0, 0, 0, fontMetrics.lineSpacing() * (text.count(QLatin1Char('\n')) + 1));
return textRect.size();
QWidget* createEditor(QWidget*, const QStyleOptionViewItem &, const QModelIndex &) const {
// No editor here
return 0;
}
// QWidget* createEditor(QWidget * parent, const QStyleOptionViewItem& /*option*/, const QModelIndex & index) const{
// if(index.column() == PROGRESS){
// QProgressBar *progressBar = new QProgressBar(parent);
// progressBar->setRange(0,100);
// progressBar->installEventFilter(const_cast<DLListDelegate*>(this));
// return progressBar;
// }
// return 0;
// }
// void setEditorData(QWidget *editor, const QModelIndex &index) const{
// QProgressBar *progressBar = static_cast<QProgressBar*>(editor);
// float progress = index.data().toDouble();
// progressBar->setValue((int)(progress*100.));
// }
// void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex & index) const{
// if(index.column() == PROGRESS){
// editor->setGeometry(option.rect);
// }
// }
};
#endif

View File

@@ -0,0 +1,81 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contact : chris@qbittorrent.org
*/
#ifndef FINISHEDLISTDELEGATE_H
#define FINISHEDLISTDELEGATE_H
#include <QItemDelegate>
#include <QModelIndex>
#include <QPainter>
#include <QStyleOptionProgressBarV2>
#include <QStyleOptionViewItemV2>
#include <QProgressBar>
#include <QApplication>
#include "misc.h"
// Defines for download list list columns
#define F_NAME 0
#define F_SIZE 1
#define F_UPSPEED 2
#define F_LEECH 3
#define F_RATIO 4
#define F_HASH 5
class FinishedListDelegate: public QItemDelegate {
Q_OBJECT
public:
FinishedListDelegate(QObject *parent) : QItemDelegate(parent){}
~FinishedListDelegate(){}
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const{
QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option);
switch(index.column()){
case F_SIZE:
QItemDelegate::drawBackground(painter, opt, index);
QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong()));
break;
case F_UPSPEED:{
QItemDelegate::drawBackground(painter, opt, index);
double speed = index.data().toDouble();
QItemDelegate::drawDisplay(painter, opt, opt.rect, QString(QByteArray::number(speed/1024., 'f', 1))+QString::fromUtf8(" ")+tr("KiB/s"));
break;
}
case F_RATIO:{
QItemDelegate::drawBackground(painter, opt, index);
double ratio = index.data().toDouble();
QItemDelegate::drawDisplay(painter, opt, opt.rect, QString(QByteArray::number(ratio, 'f', 1)));
break;
}
default:
QItemDelegate::paint(painter, option, index);
}
}
QWidget* createEditor(QWidget*, const QStyleOptionViewItem &, const QModelIndex &) const {
// No editor here
return 0;
}
};
#endif

594
src/FinishedTorrents.cpp Normal file
View File

@@ -0,0 +1,594 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contact : chris@qbittorrent.org
*/
#include "FinishedTorrents.h"
#include "misc.h"
#include "properties_imp.h"
#include "bittorrent.h"
#include "allocationDlg.h"
#include "FinishedListDelegate.h"
#include "GUI.h"
#include <QFile>
#include <QSettings>
#include <QStandardItemModel>
#include <QHeaderView>
#include <QMenu>
FinishedTorrents::FinishedTorrents(QObject *parent, bittorrent *BTSession) : parent(parent), BTSession(BTSession), nbFinished(0){
setupUi(this);
actionStart->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/play.png")));
actionPause->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/pause.png")));
connect(BTSession, SIGNAL(addedTorrent(QString, QTorrentHandle&, bool)), this, SLOT(torrentAdded(QString, QTorrentHandle&, bool)));
finishedListModel = new QStandardItemModel(0,6);
finishedListModel->setHeaderData(F_NAME, Qt::Horizontal, tr("Name", "i.e: file name"));
finishedListModel->setHeaderData(F_SIZE, Qt::Horizontal, tr("Size", "i.e: file size"));
finishedListModel->setHeaderData(F_UPSPEED, Qt::Horizontal, tr("UP Speed", "i.e: Upload speed"));
finishedListModel->setHeaderData(F_LEECH, Qt::Horizontal, tr("Leechers", "i.e: full/partial sources"));
finishedListModel->setHeaderData(F_RATIO, Qt::Horizontal, tr("Ratio"));
finishedList->setModel(finishedListModel);
loadHiddenColumns();
// Hide hash column
finishedList->hideColumn(F_HASH);
// Load last columns width for download list
if(!loadColWidthFinishedList()){
finishedList->header()->resizeSection(0, 200);
}
// Make download list header clickable for sorting
finishedList->header()->setClickable(true);
finishedList->header()->setSortIndicatorShown(true);
connect(finishedList->header(), SIGNAL(sectionPressed(int)), this, SLOT(sortFinishedList(int)));
finishedListDelegate = new FinishedListDelegate(finishedList);
finishedList->setItemDelegate(finishedListDelegate);
connect(finishedList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayFinishedListMenu(const QPoint&)));
finishedList->header()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(finishedList->header(), SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayFinishedHoSMenu(const QPoint&)));
connect(finishedList, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(notifyTorrentDoubleClicked(const QModelIndex&)));
actionDelete->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete.png")));
actionPreview_file->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/preview.png")));
actionDelete_Permanently->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png")));
actionTorrent_Properties->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/properties.png")));
actionSet_upload_limit->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png")));
connect(actionPause, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionPause_triggered()));
connect(actionStart, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionStart_triggered()));
connect(actionDelete, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionDelete_triggered()));
connect(actionPreview_file, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionPreview_file_triggered()));
connect(actionDelete_Permanently, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionDelete_Permanently_triggered()));
connect(actionOpen_destination_folder, SIGNAL(triggered()), (GUI*)parent, SLOT(openDestinationFolder()));
connect(actionBuy_it, SIGNAL(triggered()), (GUI*)parent, SLOT(goBuyPage()));
connect(actionTorrent_Properties, SIGNAL(triggered()), this, SLOT(propertiesSelection()));
connect(actionHOSColName, SIGNAL(triggered()), this, SLOT(hideOrShowColumnName()));
connect(actionHOSColSize, SIGNAL(triggered()), this, SLOT(hideOrShowColumnSize()));
connect(actionHOSColUpSpeed, SIGNAL(triggered()), this, SLOT(hideOrShowColumnUpSpeed()));
connect(actionHOSColLeechers, SIGNAL(triggered()), this, SLOT(hideOrShowColumnLeechers()));
connect(actionHOSColRatio, SIGNAL(triggered()), this, SLOT(hideOrShowColumnRatio()));
}
FinishedTorrents::~FinishedTorrents(){
saveColWidthFinishedList();
saveHiddenColumns();
delete finishedListDelegate;
delete finishedListModel;
}
void FinishedTorrents::notifyTorrentDoubleClicked(const QModelIndex& index) {
unsigned int row = index.row();
QString hash = getHashFromRow(row);
emit torrentDoubleClicked(hash, true);
}
void FinishedTorrents::addTorrent(QString hash){
if(!BTSession->isFinished(hash)){
BTSession->setFinishedTorrent(hash);
}
int row = getRowFromHash(hash);
if(row != -1) return;
row = finishedListModel->rowCount();
QTorrentHandle h = BTSession->getTorrentHandle(hash);
// Adding torrent to download list
finishedListModel->insertRow(row);
finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(h.name()));
finishedListModel->setData(finishedListModel->index(row, F_SIZE), QVariant((qlonglong)h.actual_size()));
finishedListModel->setData(finishedListModel->index(row, F_UPSPEED), QVariant((double)0.));
finishedListModel->setData(finishedListModel->index(row, F_LEECH), QVariant("0"));
finishedListModel->setData(finishedListModel->index(row, F_RATIO), QVariant(QString::fromUtf8(misc::toString(BTSession->getRealRatio(hash)).c_str())));
finishedListModel->setData(finishedListModel->index(row, F_HASH), QVariant(hash));
if(h.is_paused()) {
finishedListModel->setData(finishedListModel->index(row, F_NAME), QIcon(":/Icons/skin/paused.png"), Qt::DecorationRole);
setRowColor(row, "red");
}else{
finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(QIcon(":/Icons/skin/seeding.png")), Qt::DecorationRole);
setRowColor(row, "orange");
}
// Update the number of finished torrents
++nbFinished;
emit finishedTorrentsNumberChanged(nbFinished);
}
void FinishedTorrents::torrentAdded(QString, QTorrentHandle& h, bool) {
QString hash = h.hash();
if(BTSession->isFinished(hash)) {
addTorrent(hash);
}
}
// Set the color of a row in data model
void FinishedTorrents::setRowColor(int row, QString color){
unsigned int nbColumns = finishedListModel->columnCount()-1;
for(unsigned int i=0; i<nbColumns; ++i){
finishedListModel->setData(finishedListModel->index(row, i), QVariant(QColor(color)), Qt::ForegroundRole);
}
}
QStringList FinishedTorrents::getSelectedTorrents(bool only_one) const{
QStringList res;
QModelIndex index;
QModelIndexList selectedIndexes = finishedList->selectionModel()->selectedIndexes();
foreach(index, selectedIndexes) {
if(index.column() == F_NAME) {
// Get the file hash
QString hash = finishedListModel->data(finishedListModel->index(index.row(), F_HASH)).toString();
res << hash;
if(only_one) break;
}
}
return res;
}
unsigned int FinishedTorrents::getNbTorrentsInList() const {
return nbFinished;
}
// Load columns width in a file that were saved previously
// (finished list)
bool FinishedTorrents::loadColWidthFinishedList(){
qDebug("Loading columns width for finished list");
QSettings settings("qBittorrent", "qBittorrent");
QString line = settings.value("FinishedListColsWidth", QString()).toString();
if(line.isEmpty())
return false;
QStringList width_list = line.split(' ');
if(width_list.size() < finishedListModel->columnCount()-1)
return false;
unsigned int listSize = width_list.size();
for(unsigned int i=0; i<listSize; ++i){
finishedList->header()->resizeSection(i, width_list.at(i).toInt());
}
qDebug("Finished list columns width loaded");
return true;
}
// Save columns width in a file to remember them
// (finished list)
void FinishedTorrents::saveColWidthFinishedList() const{
qDebug("Saving columns width in finished list");
QSettings settings("qBittorrent", "qBittorrent");
QStringList width_list;
QStringList new_width_list;
short nbColumns = finishedListModel->columnCount()-1;
QString line = settings.value("FinishedListColsWidth", QString()).toString();
if(!line.isEmpty()) {
width_list = line.split(' ');
}
for(short i=0; i<nbColumns; ++i){
if(finishedList->columnWidth(i)<1 && width_list.size() == finishedListModel->columnCount()-1 && width_list.at(i).toInt()>=1) {
// load the former width
new_width_list << width_list.at(i);
} else if(finishedList->columnWidth(i)>=1) {
// usual case, save the current width
new_width_list << QString::fromUtf8(misc::toString(finishedList->columnWidth(i)).c_str());
} else {
// default width
finishedList->resizeColumnToContents(i);
new_width_list << QString::fromUtf8(misc::toString(finishedList->columnWidth(i)).c_str());
}
}
settings.setValue("FinishedListColsWidth", new_width_list.join(" "));
qDebug("Finished list columns width saved");
}
void FinishedTorrents::on_actionSet_upload_limit_triggered(){
QModelIndexList selectedIndexes = finishedList->selectionModel()->selectedIndexes();
QModelIndex index;
QStringList hashes;
foreach(index, selectedIndexes){
if(index.column() == F_NAME){
// Get the file hash
hashes << finishedListModel->data(finishedListModel->index(index.row(), F_HASH)).toString();
}
}
new BandwidthAllocationDialog(this, true, BTSession, hashes);
}
void FinishedTorrents::updateFinishedList(){
QString hash;
QStringList finishedSHAs = BTSession->getFinishedTorrents();
foreach(hash, finishedSHAs){
QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(!h.is_valid()){
qDebug("Problem: This torrent is not valid in finished list");
continue;
}
int row = getRowFromHash(hash);
if(row == -1){
qDebug("Cannot find torrent in finished list, adding it");
addTorrent(hash);
row = getRowFromHash(hash);
}
Q_ASSERT(row != -1);
if(h.is_paused()) continue;
if(BTSession->getTorrentsToPauseAfterChecking().indexOf(hash) != -1) {
continue;
}
if(h.state() == torrent_status::downloading || (h.state() != torrent_status::checking_files && h.state() != torrent_status::queued_for_checking && h.progress() < 1.)) {
// What are you doing here? go back to download tab!
qDebug("Info: a torrent was moved from finished to download tab");
deleteTorrent(hash);
BTSession->setFinishedTorrent(hash);
emit torrentMovedFromFinishedList(hash);
continue;
}
if(h.state() == torrent_status::checking_files){
finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/time.png"))), Qt::DecorationRole);
setRowColor(row, QString::fromUtf8("grey"));
continue;
}
setRowColor(row, QString::fromUtf8("orange"));
finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png"))), Qt::DecorationRole);
if(!finishedList->isColumnHidden(F_UPSPEED)) {
finishedListModel->setData(finishedListModel->index(row, F_UPSPEED), QVariant((double)h.upload_payload_rate()));
}
if(!finishedList->isColumnHidden(F_LEECH)) {
finishedListModel->setData(finishedListModel->index(row, F_LEECH), misc::toQString(h.num_peers() - h.num_seeds(), true));
}
if(!finishedList->isColumnHidden(F_RATIO)) {
finishedListModel->setData(finishedListModel->index(row, F_RATIO), QVariant(misc::toQString(BTSession->getRealRatio(hash))));
}
}
}
int FinishedTorrents::getRowFromHash(QString hash) const{
unsigned int nbRows = finishedListModel->rowCount();
for(unsigned int i=0; i<nbRows; ++i){
if(finishedListModel->data(finishedListModel->index(i, F_HASH)) == hash){
return i;
}
}
return -1;
}
// Note: does not actually pause the torrent in BT Session
void FinishedTorrents::pauseTorrent(QString hash) {
int row = getRowFromHash(hash);
if(row == -1)
return;
finishedListModel->setData(finishedListModel->index(row, F_UPSPEED), QVariant((double)0.0));
finishedListModel->setData(finishedListModel->index(row, F_NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole);
finishedListModel->setData(finishedListModel->index(row, F_LEECH), QVariant(QString::fromUtf8("0")));
setRowColor(row, QString::fromUtf8("red"));
}
void FinishedTorrents::resumeTorrent(QString hash) {
int row = getRowFromHash(hash);
Q_ASSERT(row != -1);
finishedListModel->setData(finishedListModel->index(row, F_NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png"))), Qt::DecorationRole);
setRowColor(row, QString::fromUtf8("orange"));
}
QString FinishedTorrents::getHashFromRow(unsigned int row) const {
Q_ASSERT(row < (unsigned int)finishedListModel->rowCount());
return finishedListModel->data(finishedListModel->index(row, F_HASH)).toString();
}
// Will move it to download tab
void FinishedTorrents::deleteTorrent(QString hash){
int row = getRowFromHash(hash);
if(row == -1){
qDebug("Torrent is not in finished list, nothing to delete");
return;
}
finishedListModel->removeRow(row);
--nbFinished;
emit finishedTorrentsNumberChanged(nbFinished);
}
// Show torrent properties dialog
void FinishedTorrents::showProperties(const QModelIndex &index){
showPropertiesFromHash(finishedListModel->data(finishedListModel->index(index.row(), F_HASH)).toString());
}
void FinishedTorrents::showPropertiesFromHash(QString hash){
QTorrentHandle h = BTSession->getTorrentHandle(hash);
properties *prop = new properties(this, BTSession, h);
connect(prop, SIGNAL(filteredFilesChanged(QString)), this, SLOT(updateFileSize(QString)));
connect(prop, SIGNAL(trackersChanged(QString)), BTSession, SLOT(saveTrackerFile(QString)));
prop->show();
}
void FinishedTorrents::updateFileSize(QString hash){
int row = getRowFromHash(hash);
QTorrentHandle h = BTSession->getTorrentHandle(hash);
finishedListModel->setData(finishedListModel->index(row, F_SIZE), QVariant((qlonglong)h.actual_size()));
}
// display properties of selected items
void FinishedTorrents::propertiesSelection(){
QModelIndexList selectedIndexes = finishedList->selectionModel()->selectedIndexes();
QModelIndex index;
foreach(index, selectedIndexes){
if(index.column() == F_NAME){
showProperties(index);
}
}
}
void FinishedTorrents::displayFinishedListMenu(const QPoint& pos){
QMenu myFinishedListMenu(this);
QModelIndex index;
// Enable/disable pause/start action given the DL state
QModelIndexList selectedIndexes = finishedList->selectionModel()->selectedIndexes();
bool has_pause = false, has_start = false, has_preview = false;
foreach(index, selectedIndexes) {
if(index.column() == F_NAME) {
// Get the file name
QString hash = finishedListModel->data(finishedListModel->index(index.row(), F_HASH)).toString();
// Get handle and pause the torrent
QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(!h.is_valid()) continue;
if(h.is_paused()) {
if(!has_start) {
myFinishedListMenu.addAction(actionStart);
has_start = true;
}
}else{
if(!has_pause) {
myFinishedListMenu.addAction(actionPause);
has_pause = true;
}
}
if(BTSession->isFilePreviewPossible(hash) && !has_preview) {
myFinishedListMenu.addAction(actionPreview_file);
has_preview = true;
}
if(has_pause && has_start && has_preview) break;
}
}
myFinishedListMenu.addSeparator();
myFinishedListMenu.addAction(actionDelete);
myFinishedListMenu.addAction(actionDelete_Permanently);
myFinishedListMenu.addSeparator();
myFinishedListMenu.addAction(actionSet_upload_limit);
myFinishedListMenu.addSeparator();
myFinishedListMenu.addAction(actionOpen_destination_folder);
myFinishedListMenu.addAction(actionTorrent_Properties);
myFinishedListMenu.addSeparator();
myFinishedListMenu.addAction(actionBuy_it);
// Call menu
// XXX: why mapToGlobal() is not enough?
myFinishedListMenu.exec(mapToGlobal(pos)+QPoint(10,55));
}
/*
* Hiding Columns functions
*/
// hide/show columns menu
void FinishedTorrents::displayFinishedHoSMenu(const QPoint& pos){
QMenu hideshowColumn(this);
hideshowColumn.setTitle(tr("Hide or Show Column"));
for(int i=0; i<=F_RATIO; i++) {
hideshowColumn.addAction(getActionHoSCol(i));
}
// Call menu
hideshowColumn.exec(mapToGlobal(pos)+QPoint(10,55));
}
// toggle hide/show a column
void FinishedTorrents::hideOrShowColumn(int index) {
unsigned int nbVisibleColumns = 0;
unsigned int nbCols = finishedListModel->columnCount();
// Count visible columns
for(unsigned int i=0; i<nbCols; ++i) {
if(!finishedList->isColumnHidden(i))
++nbVisibleColumns;
}
if(!finishedList->isColumnHidden(index)) {
// User wants to hide the column
// Is there at least one other visible column?
if(nbVisibleColumns <= 1) return;
// User can hide the column, do it.
finishedList->setColumnHidden(index, true);
getActionHoSCol(index)->setIcon(QIcon(QString::fromUtf8(":/Icons/button_cancel.png")));
--nbVisibleColumns;
} else {
// User want to display the column
finishedList->setColumnHidden(index, false);
getActionHoSCol(index)->setIcon(QIcon(QString::fromUtf8(":/Icons/button_ok.png")));
++nbVisibleColumns;
}
//resize all others non-hidden columns
for(unsigned int i=0; i<nbCols; ++i) {
if(!finishedList->isColumnHidden(i)) {
finishedList->setColumnWidth(i, (int)ceil(finishedList->columnWidth(i)+(finishedList->columnWidth(index)/nbVisibleColumns)));
}
}
}
void FinishedTorrents::hideOrShowColumnName() {
hideOrShowColumn(F_NAME);
}
void FinishedTorrents::hideOrShowColumnSize() {
hideOrShowColumn(F_SIZE);
}
void FinishedTorrents::hideOrShowColumnUpSpeed() {
hideOrShowColumn(F_UPSPEED);
}
void FinishedTorrents::hideOrShowColumnLeechers() {
hideOrShowColumn(F_LEECH);
}
void FinishedTorrents::hideOrShowColumnRatio() {
hideOrShowColumn(F_RATIO);
}
// load the previous settings, and hide the columns
bool FinishedTorrents::loadHiddenColumns() {
bool loaded = false;
QSettings settings("qBittorrent", "qBittorrent");
QString line = settings.value("FinishedListColsHoS", QString()).toString();
QStringList ishidden_list;
if(!line.isEmpty()) {
ishidden_list = line.split(' ');
if(ishidden_list.size() == finishedListModel->columnCount()-1) {
unsigned int listSize = ishidden_list.size();
for(unsigned int i=0; i<listSize; ++i){
finishedList->header()->resizeSection(i, ishidden_list.at(i).toInt());
}
loaded = true;
}
}
for(int i=0; i<finishedListModel->columnCount()-1; i++) {
if(loaded && ishidden_list.at(i) == "0") {
finishedList->setColumnHidden(i, true);
getActionHoSCol(i)->setIcon(QIcon(QString::fromUtf8(":/Icons/button_cancel.png")));
} else {
getActionHoSCol(i)->setIcon(QIcon(QString::fromUtf8(":/Icons/button_ok.png")));
}
}
return loaded;
}
// save the hidden columns in settings
void FinishedTorrents::saveHiddenColumns() {
QSettings settings("qBittorrent", "qBittorrent");
QStringList ishidden_list;
short nbColumns = finishedListModel->columnCount()-1;
for(short i=0; i<nbColumns; ++i){
if(finishedList->isColumnHidden(i)) {
ishidden_list << QString::fromUtf8(misc::toString(0).c_str());
} else {
ishidden_list << QString::fromUtf8(misc::toString(1).c_str());
}
}
settings.setValue("FinishedListColsHoS", ishidden_list.join(" "));
}
// getter, return the action hide or show whose id is index
QAction* FinishedTorrents::getActionHoSCol(int index) {
switch(index) {
case F_NAME :
return actionHOSColName;
break;
case F_SIZE :
return actionHOSColSize;
break;
case F_UPSPEED :
return actionHOSColUpSpeed;
break;
case F_LEECH :
return actionHOSColLeechers;
break;
case F_RATIO :
return actionHOSColRatio;
break;
default :
return NULL;
}
}
/*
* Sorting functions
*/
void FinishedTorrents::sortFinishedList(int index){
static Qt::SortOrder sortOrder = Qt::AscendingOrder;
if(finishedList->header()->sortIndicatorSection() == index){
if(sortOrder == Qt::AscendingOrder){
sortOrder = Qt::DescendingOrder;
}else{
sortOrder = Qt::AscendingOrder;
}
}
finishedList->header()->setSortIndicator(index, sortOrder);
switch(index){
case F_SIZE:
case F_UPSPEED:
sortFinishedListFloat(index, sortOrder);
break;
default:
sortFinishedListString(index, sortOrder);
}
}
void FinishedTorrents::sortFinishedListFloat(int index, Qt::SortOrder sortOrder){
QList<QPair<int, double> > lines;
// insertion sorting
unsigned int nbRows = finishedListModel->rowCount();
for(unsigned int i=0; i<nbRows; ++i){
misc::insertSort(lines, QPair<int,double>(i, finishedListModel->data(finishedListModel->index(i, index)).toDouble()), sortOrder);
}
// Insert items in new model, in correct order
unsigned int nbRows_old = lines.size();
for(unsigned int row=0; row<nbRows_old; ++row){
finishedListModel->insertRow(finishedListModel->rowCount());
unsigned int sourceRow = lines[row].first;
unsigned int nbColumns = finishedListModel->columnCount();
for(unsigned int col=0; col<nbColumns; ++col){
finishedListModel->setData(finishedListModel->index(nbRows_old+row, col), finishedListModel->data(finishedListModel->index(sourceRow, col)));
finishedListModel->setData(finishedListModel->index(nbRows_old+row, col), finishedListModel->data(finishedListModel->index(sourceRow, col), Qt::DecorationRole), Qt::DecorationRole);
finishedListModel->setData(finishedListModel->index(nbRows_old+row, col), finishedListModel->data(finishedListModel->index(sourceRow, col), Qt::ForegroundRole), Qt::ForegroundRole);
}
}
// Remove old rows
finishedListModel->removeRows(0, nbRows_old);
}
void FinishedTorrents::sortFinishedListString(int index, Qt::SortOrder sortOrder){
QList<QPair<int, QString> > lines;
// Insertion sorting
unsigned int nbRows = finishedListModel->rowCount();
for(unsigned int i=0; i<nbRows; ++i){
misc::insertSortString(lines, QPair<int, QString>(i, finishedListModel->data(finishedListModel->index(i, index)).toString()), sortOrder);
}
// Insert items in new model, in correct order
unsigned int nbRows_old = lines.size();
for(unsigned int row=0; row<nbRows_old; ++row){
finishedListModel->insertRow(finishedListModel->rowCount());
unsigned int sourceRow = lines[row].first;
unsigned int nbColumns = finishedListModel->columnCount();
for(unsigned int col=0; col<nbColumns; ++col){
finishedListModel->setData(finishedListModel->index(nbRows_old+row, col), finishedListModel->data(finishedListModel->index(sourceRow, col)));
finishedListModel->setData(finishedListModel->index(nbRows_old+row, col), finishedListModel->data(finishedListModel->index(sourceRow, col), Qt::DecorationRole), Qt::DecorationRole);
finishedListModel->setData(finishedListModel->index(nbRows_old+row, col), finishedListModel->data(finishedListModel->index(sourceRow, col), Qt::ForegroundRole), Qt::ForegroundRole);
}
}
// Remove old rows
finishedListModel->removeRows(0, nbRows_old);
}

92
src/FinishedTorrents.h Normal file
View File

@@ -0,0 +1,92 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contact : chris@qbittorrent.org
*/
#ifndef SEEDING_H
#define SEEDING_H
#include "ui_seeding.h"
#include "qtorrenthandle.h"
class QStandardItemModel;
class bittorrent;
class FinishedListDelegate;
using namespace libtorrent;
class FinishedTorrents : public QWidget, public Ui::seeding {
Q_OBJECT
private:
QObject *parent;
bittorrent *BTSession;
FinishedListDelegate *finishedListDelegate;
QStandardItemModel *finishedListModel;
unsigned int nbFinished;
void hideOrShowColumn(int index);
bool loadHiddenColumns();
void saveHiddenColumns();
QAction* getActionHoSCol(int index);
public:
FinishedTorrents(QObject *parent, bittorrent *BTSession);
~FinishedTorrents();
// Methods
bool loadColWidthFinishedList();
int getRowFromHash(QString hash) const;
QStringList getSelectedTorrents(bool only_one=false) const;
unsigned int getNbTorrentsInList() const;
QString getHashFromRow(unsigned int row) const;
protected slots:
void showProperties(const QModelIndex &index);
void displayFinishedListMenu(const QPoint&);
void displayFinishedHoSMenu(const QPoint&);
void setRowColor(int row, QString color);
void saveColWidthFinishedList() const;
void sortFinishedList(int index);
void sortFinishedListFloat(int index, Qt::SortOrder sortOrder);
void sortFinishedListString(int index, Qt::SortOrder sortOrder);
void updateFileSize(QString hash);
void torrentAdded(QString path, QTorrentHandle& h, bool fastResume);
void on_actionSet_upload_limit_triggered();
void notifyTorrentDoubleClicked(const QModelIndex& index);
void hideOrShowColumnName();
void hideOrShowColumnSize();
void hideOrShowColumnUpSpeed();
void hideOrShowColumnLeechers();
void hideOrShowColumnRatio();
public slots:
void addTorrent(QString hash);
void updateFinishedList();
void pauseTorrent(QString hash);
void resumeTorrent(QString hash);
void propertiesSelection();
void deleteTorrent(QString hash);
void showPropertiesFromHash(QString hash);
signals:
void torrentMovedFromFinishedList(QString);
void torrentDoubleClicked(QString hash, bool finished);
void finishedTorrentsNumberChanged(unsigned int);
};
#endif

File diff suppressed because it is too large Load Diff

213
src/GUI.h
View File

@@ -22,167 +22,141 @@
#ifndef GUI_H
#define GUI_H
#include <QMainWindow>
#include <QProcess>
#include <QTcpServer>
#include <QSystemTrayIcon>
#include <libtorrent/entry.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/session.hpp>
#include <libtorrent/fingerprint.hpp>
#include <libtorrent/session_settings.hpp>
#include <libtorrent/identify_client.hpp>
#include <libtorrent/alert_types.hpp>
#include "ui_MainWindow.h"
#include "options_imp.h"
#include "about_imp.h"
#include "previewSelect.h"
#include "trackerLogin.h"
#include "bittorrent.h"
#define TIME_TRAY_BALLOON 5000
#include "qtorrenthandle.h"
class bittorrent;
class createtorrent;
class QTimer;
class QCompleter;
class DLListDelegate;
class SearchListDelegate;
class downloadThread;
class DownloadingTorrents;
class FinishedTorrents;
class downloadFromURL;
class SearchEngine;
class QTcpServer;
class QTcpSocket;
class QCloseEvent;
using namespace libtorrent;
namespace fs = boost::filesystem;
class RSSImp;
class QShortcut;
class about;
class previewSelect;
class options_imp;
class QTabWidget;
class QLabel;
class QModelIndex;
class HttpServer;
class GUI : public QMainWindow, private Ui::MainWindow{
Q_OBJECT
private:
// Bittorrent
bittorrent BTSession;
bittorrent *BTSession;
QTimer *checkConnect;
QHash<QString, QStringList> trackerErrors;
QList<QPair<torrent_handle,std::string> > unauthenticated_trackers;
downloadFromURL *downloadFromURLDialog;
QList<QPair<QTorrentHandle,QString> > unauthenticated_trackers;
// GUI related
QTabWidget *tabs;
options_imp *options;
createtorrent *createWindow;
QTimer *refresher;
QSystemTrayIcon *myTrayIcon;
QTimer *systrayCreator;
QMenu *myTrayIconMenu;
about *aboutdlg;
QStandardItemModel *DLListModel;
DLListDelegate *DLDelegate;
QStandardItemModel *SearchListModel;
SearchListDelegate *SearchDelegate;
unsigned int nbTorrents;
DownloadingTorrents *downloadingTorrentTab;
FinishedTorrents *finishedTorrentTab;
QLabel *connecStatusLblIcon;
bool systrayIntegration;
bool displaySpeedInTitle;
bool force_exit;
// Preview
previewSelect *previewSelection;
QProcess *previewProcess;
// Search related
QHash<QString, QString> searchResultsUrls;
QProcess *searchProcess;
bool search_stopped;
bool no_search_results;
QByteArray search_result_line_truncated;
unsigned long nb_search_results;
QTcpServer tcpServer;
unsigned int refreshInterval;
QTimer *refresher;
// Keyboard shortcuts
QShortcut *switchSearchShortcut;
QShortcut *switchSearchShortcut2;
QShortcut *switchDownShortcut;
QShortcut *switchUpShortcut;
QShortcut *switchRSSShortcut;
// Search
SearchEngine *searchEngine;
// RSS
RSSImp *rssWidget;
// Web UI
HttpServer *httpServer;
// Misc
QTcpServer *tcpServer;
QTcpSocket *clientConnection;
QCompleter *searchCompleter;
QStringList searchHistory;
protected slots:
// GUI related slots
void dropEvent(QDropEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void toggleVisibility(QSystemTrayIcon::ActivationReason e);
void showAbout();
void setInfoBar(const QString& info, const QString& color="black");
void updateDlList(bool force=false);
void showCreateWindow();
void clearLog();
void openqBTHomepage();
void openqBTBugTracker();
void on_actionAbout_triggered();
void on_actionCreate_torrent_triggered();
void on_actionWebsite_triggered() const;
void on_actionBugReport_triggered() const;
void readParamsOnSocket();
void acceptConnection();
void saveCheckedSearchEngines(int) const;
void saveColWidthDLList() const;
void saveColWidthSearchList() const;
void loadCheckedSearchEngines();
bool loadColWidthDLList();
bool loadColWidthSearchList();
void sortDownloadList(int index);
void sortDownloadListFloat(int index, Qt::SortOrder sortOrder);
void sortDownloadListString(int index, Qt::SortOrder sortOrder);
void sortSearchList(int index);
void sortSearchListInt(int index, Qt::SortOrder sortOrder);
void sortSearchListString(int index, Qt::SortOrder sortOrder);
void displayDLListMenu(const QPoint& pos);
void selectGivenRow(const QModelIndex& index);
void togglePausedState(const QModelIndex& index);
void displayInfoBarMenu(const QPoint& pos);
void displayGUIMenu(const QPoint& pos);
void previewFileSelection();
void previewFile(const QString& filePath);
void cleanTempPreviewFile(int, QProcess::ExitStatus);
void togglePausedState(QString hash);
void torrentDoubleClicked(QString hash, bool finished);
void on_actionPreview_file_triggered();
void previewFile(QString filePath);
void balloonClicked();
void writeSettings();
void readSettings();
void forceExit();
void on_actionExit_triggered();
void createTrayIcon();
void updateUnfinishedTorrentNumber(unsigned int nb);
void updateFinishedTorrentNumber(unsigned int nb);
void fullDiskError(QTorrentHandle& h) const;
void handleDownloadFromUrlFailure(QString, QString) const;
void createSystrayDelayed();
// Keyboard shortcuts
void createKeyboardShortcuts();
void displayDownTab() const;
void displayUpTab() const;
void displaySearchTab() const;
void displayRSSTab() const;
// Torrent actions
void showProperties(const QModelIndex &index);
void propertiesSelection();
void pauseSelection();
void pauseAll();
void startSelection();
void resumeAll();
void askForTorrents();
void deletePermanently();
void deleteSelection();
void on_actionTorrent_Properties_triggered();
void on_actionPause_triggered();
void on_actionPause_All_triggered();
void on_actionStart_triggered();
void on_actionStart_All_triggered();
void on_actionOpen_triggered();
void on_actionDelete_Permanently_triggered();
void on_actionDelete_triggered();
void on_actionSet_global_upload_limit_triggered();
void on_actionSet_global_download_limit_triggered();
void on_actionDocumentation_triggered() const;
void checkConnectionStatus();
void configureSession(bool deleteOptions);
void processParams(const QStringList& params);
void addUnauthenticatedTracker(QPair<torrent_handle,std::string> tracker);
void addTorrent(QString path);
void addUnauthenticatedTracker(QPair<QTorrentHandle,QString> tracker);
void processScannedFiles(const QStringList& params);
void processDownloadedFiles(const QString& path, const QString& url);
void processDownloadedFiles(QString path, QString url);
void downloadFromURLList(const QStringList& urls);
void displayDownloadingUrlInfos(const QString& url);
// Search slots
void on_search_button_clicked();
void on_stop_search_button_clicked();
void on_clear_button_clicked();
void on_download_button_clicked();
void on_update_nova_button_clicked();
void appendSearchResult(const QString& line);
void searchFinished(int exitcode,QProcess::ExitStatus);
void readSearchOutput();
void searchStarted();
void downloadSelectedItem(const QModelIndex& index);
void startSearchHistory();
void saveSearchHistory();
// Utils slots
void setRowColor(int row, const QString& color, bool inDLList=true);
void deleteTorrent(QString hash);
void deleteRatioTorrent(QString fileName);
void finishedTorrent(QTorrentHandle& h) const;
void torrentChecked(QString hash) const;
void updateLists();
bool initWebUi(QString username, QString password, int port);
void pauseTorrent(QString hash);
// Options slots
void showOptions();
void OptionsSaved(const QString& info, bool deleteOptions);
void on_actionOptions_triggered();
void OptionsSaved(QString info, bool deleteOptions);
// HTTP slots
void askForTorrentUrl();
void on_actionDownload_from_URL_triggered();
public slots:
void torrentAdded(const QString& path, torrent_handle& h, bool fastResume);
void torrentDuplicate(const QString& path);
void torrentCorrupted(const QString& path);
void finishedTorrent(torrent_handle& h);
void fullDiskError(torrent_handle& h);
void portListeningFailure();
void trackerError(const QString& hash, const QString& time, const QString& msg);
void trackerAuthenticationRequired(torrent_handle& h);
void trackerAuthenticationRequired(QTorrentHandle& h);
void setTabText(int index, QString text) const;
void openDestinationFolder() const;
void goBuyPage() const;
void updateRatio();
protected:
void closeEvent(QCloseEvent *);
@@ -193,11 +167,8 @@ class GUI : public QMainWindow, private Ui::MainWindow{
GUI(QWidget *parent=0, QStringList torrentCmdLine=QStringList());
~GUI();
// Methods
int getRowFromHash(const QString& name) const;
float getNovaVersion(const QString& novaPath) const;
QByteArray getNovaChangelog(const QString& novaPath) const;
void updateNova() const;
QPoint screenCenter();
int getCurrentTabIndex() const;
QPoint screenCenter() const;
};
#endif

BIN
src/Icons/add_file.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

BIN
src/Icons/add_folder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/Icons/bt_settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
src/Icons/configure.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
src/Icons/connection.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

BIN
src/Icons/description.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

BIN
src/Icons/downarrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 722 B

BIN
src/Icons/download.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
src/Icons/edit_clear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

BIN
src/Icons/file.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 704 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 998 B

BIN
src/Icons/flags/brazil.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 799 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 558 B

BIN
src/Icons/flags/hungary.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 B

BIN
src/Icons/folder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 449 B

BIN
src/Icons/gear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/Icons/loading.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

BIN
src/Icons/mascot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
src/Icons/money.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 813 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 532 B

BIN
src/Icons/password.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -1,22 +1,23 @@
[Desktop Entry]
Categories=Qt;Application;Network;P2P
Comment=V0.9.2
Encoding=UTF-8
Comment=V1.1.0
Exec=qbittorrent
GenericName=Bittorrent client
GenericName[fr]=Client Bittorrent
GenericName[nl]=Bittorrent client
GenericName[bg]=Торент клиент
GenericName[de]=Bittorren Client
GenericName[el]=Τορεντ πελάτης
GenericName[es]=Cliente Bittorrent
GenericName[fr]=Client Bittorrent
GenericName[it]=Client Bittorrent
GenericName[ja]=Bittorrent クライアント
GenericName[ko]=비토렌트 클라이언트
GenericName[nl]=Bittorrent client
GenericName[pl]=Klient Bittorrent
GenericName[ru]=клиент Bittorrent
GenericName[sv]=Bittorrent-klient
GenericName[tr]=Bittorrent istemcisi
GenericName[de]=Bittorren Client
GenericName[pl]=Klient Bittorrent
GenericName[zh]=Bittorrent之用户
GenericName[ko]=비토렌트 클라이언트
GenericName[el]=Τορεντ πελάτης
GenericName[bg]=Торент клиент
GenericName[uk]=Bittorrent-клієнт
GenericName[ru]=клиент Bittorrent
GenericName[zh]=Bittorrent之用户
Icon=qbittorrent
MimeType=application/x-bittorrent
Name=qBittorrent

BIN
src/Icons/refresh.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 948 B

BIN
src/Icons/rss16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 607 B

BIN
src/Icons/rss32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 496 B

After

Width:  |  Height:  |  Size: 842 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 770 B

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/Icons/sphere.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

BIN
src/Icons/sphere2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

BIN
src/Icons/splash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
src/Icons/star.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 766 B

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
src/Icons/subscribe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
src/Icons/subscribe16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 B

BIN
src/Icons/time.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 856 B

BIN
src/Icons/unavailable.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 888 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 825 B

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
src/Icons/unsubscribe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
src/Icons/unsubscribe16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 765 B

BIN
src/Icons/uparrow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

BIN
src/Icons/url.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 B

View File

@@ -6,7 +6,7 @@
<x>0</x>
<y>0</y>
<width>849</width>
<height>576</height>
<height>563</height>
</rect>
</property>
<property name="contextMenuPolicy" >
@@ -16,54 +16,29 @@
<string/>
</property>
<widget class="QWidget" name="centralwidget" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
<property name="geometry" >
<rect>
<x>0</x>
<y>58</y>
<width>849</width>
<height>505</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
<layout class="QHBoxLayout" name="_3" >
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QTabWidget" name="tabs" >
<property name="tabPosition" >
<enum>QTabWidget::North</enum>
</property>
<property name="currentIndex" >
<number>0</number>
</property>
<widget class="QWidget" name="tab" >
<attribute name="title" >
<string>Transfers</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0" >
<size>
<width>40</width>
<height>20</height>
@@ -72,7 +47,7 @@
</spacer>
</item>
<item>
<widget class="QLabel" name="lbl_DLSpeed" >
<widget class="QLabel" name="lbl_DLSpeed_2" >
<property name="text" >
<string>Total DL Speed:</string>
</property>
@@ -107,7 +82,7 @@
</widget>
</item>
<item>
<widget class="QLabel" name="unitDL" >
<widget class="QLabel" name="unitDL_2" >
<property name="text" >
<string>KiB/s</string>
</property>
@@ -121,7 +96,7 @@
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0" >
<size>
<width>40</width>
<height>20</height>
@@ -130,7 +105,7 @@
</spacer>
</item>
<item>
<widget class="QLabel" name="label" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Session ratio: </string>
</property>
@@ -167,7 +142,7 @@
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0" >
<size>
<width>40</width>
<height>20</height>
@@ -176,7 +151,7 @@
</spacer>
</item>
<item>
<widget class="QLabel" name="lbl_UPSpeed" >
<widget class="QLabel" name="lbl_UPSpeed_2" >
<property name="text" >
<string>Total UP Speed:</string>
</property>
@@ -205,7 +180,7 @@
</widget>
</item>
<item>
<widget class="QLabel" name="unitUP" >
<widget class="QLabel" name="unitUP_2" >
<property name="text" >
<string>KiB/s</string>
</property>
@@ -219,7 +194,7 @@
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0" >
<size>
<width>40</width>
<height>20</height>
@@ -229,501 +204,6 @@
</item>
</layout>
</item>
<item>
<widget class="QTreeView" name="downloadList" >
<property name="contextMenuPolicy" >
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="autoScroll" >
<bool>true</bool>
</property>
<property name="selectionMode" >
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="indentation" >
<number>1</number>
</property>
<property name="itemsExpandable" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="info_icon" >
<property name="minimumSize" >
<size>
<width>20</width>
<height>20</height>
</size>
</property>
<property name="text" >
<string/>
</property>
<property name="alignment" >
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbl_info" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="font" >
<font>
<family>Sans Serif</family>
<pointsize>9</pointsize>
<weight>75</weight>
<italic>false</italic>
<bold>true</bold>
<underline>true</underline>
<strikeout>false</strikeout>
</font>
</property>
<property name="text" >
<string>Log:</string>
</property>
<property name="alignment" >
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>661</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QTextBrowser" name="infoBar" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>0</vsizetype>
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>123</height>
</size>
</property>
<property name="contextMenuPolicy" >
<enum>Qt::CustomContextMenu</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2" >
<attribute name="title" >
<string>Search</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="groupEngines" >
<property name="minimumSize" >
<size>
<width>131</width>
<height>132</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>125</width>
<height>132</height>
</size>
</property>
<property name="title" >
<string>Search Engines</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QCheckBox" name="mininova" >
<property name="text" >
<string/>
</property>
<property name="checked" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="piratebay" >
<property name="text" >
<string/>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="isohunt" >
<property name="text" >
<string/>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="meganova" >
<property name="text" >
<string/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="search_lbl" >
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>35</height>
</size>
</property>
<property name="font" >
<font>
<family>Sans Serif</family>
<pointsize>9</pointsize>
<weight>75</weight>
<italic>false</italic>
<bold>true</bold>
<underline>false</underline>
<strikeout>false</strikeout>
</font>
</property>
<property name="text" >
<string>Search Pattern:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="search_pattern" >
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>22</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="search_button" >
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>29</height>
</size>
</property>
<property name="text" >
<string>Search</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="stop_search_button" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>29</height>
</size>
</property>
<property name="text" >
<string>Stop</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="status_lbl" >
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>35</height>
</size>
</property>
<property name="font" >
<font>
<family>Sans Serif</family>
<pointsize>9</pointsize>
<weight>75</weight>
<italic>false</italic>
<bold>true</bold>
<underline>false</underline>
<strikeout>false</strikeout>
</font>
</property>
<property name="text" >
<string>Status:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="search_status" >
<property name="minimumSize" >
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>35</height>
</size>
</property>
<property name="font" >
<font>
<family>Sans Serif</family>
<pointsize>9</pointsize>
<weight>50</weight>
<italic>true</italic>
<bold>false</bold>
<underline>false</underline>
<strikeout>false</strikeout>
</font>
</property>
<property name="text" >
<string>Stopped</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="results_lbl" >
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>20</height>
</size>
</property>
<property name="font" >
<font>
<family>Sans Serif</family>
<pointsize>9</pointsize>
<weight>75</weight>
<italic>false</italic>
<bold>true</bold>
<underline>false</underline>
<strikeout>false</strikeout>
</font>
</property>
<property name="text" >
<string>Results:</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>721</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QTreeView" name="resultsBrowser" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>200</height>
</size>
</property>
<property name="contextMenuPolicy" >
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="autoScroll" >
<bool>true</bool>
</property>
<property name="selectionMode" >
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="indentation" >
<number>1</number>
</property>
<property name="itemsExpandable" >
<bool>false</bool>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QPushButton" name="download_button" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="text" >
<string>Download</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="clear_button" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="text" >
<string>Clear</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>601</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="update_nova_button" >
<property name="text" >
<string>Update search plugin</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar" >
@@ -732,15 +212,9 @@
<x>0</x>
<y>0</y>
<width>849</width>
<height>29</height>
<height>26</height>
</rect>
</property>
<widget class="QMenu" name="menu_Options" >
<property name="title" >
<string>&amp;Options</string>
</property>
<addaction name="actionOptions" />
</widget>
<widget class="QMenu" name="menu_Edit" >
<property name="title" >
<string>&amp;Edit</string>
@@ -760,9 +234,16 @@
<property name="title" >
<string>&amp;Help</string>
</property>
<addaction name="actionAbout" />
<addaction name="actionBugReport" />
<addaction name="actionWebsite" />
<addaction name="actionDocumentation" />
<addaction name="actionAbout" />
</widget>
<widget class="QMenu" name="menu_Options" >
<property name="title" >
<string>Options</string>
</property>
<addaction name="actionOptions" />
</widget>
<widget class="QMenu" name="menu_File" >
<property name="title" >
@@ -782,6 +263,14 @@
<property name="enabled" >
<bool>true</bool>
</property>
<property name="geometry" >
<rect>
<x>0</x>
<y>26</y>
<width>849</width>
<height>32</height>
</rect>
</property>
<property name="contextMenuPolicy" >
<enum>Qt::NoContextMenu</enum>
</property>
@@ -798,7 +287,10 @@
</size>
</property>
<attribute name="toolBarArea" >
<number>4</number>
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak" >
<bool>false</bool>
</attribute>
<addaction name="actionOpen" />
<addaction name="actionDownload_from_URL" />
@@ -903,24 +395,32 @@
<string>Report a bug</string>
</property>
</action>
<action name="actionSet_upload_limit" >
<property name="text" >
<string>Set upload limit</string>
</property>
</action>
<action name="actionSet_download_limit" >
<property name="text" >
<string>Set download limit</string>
</property>
</action>
<action name="actionDocumentation" >
<property name="text" >
<string>Documentation</string>
</property>
</action>
<action name="actionSet_global_download_limit" >
<property name="text" >
<string>Set global download limit</string>
</property>
</action>
<action name="actionSet_global_upload_limit" >
<property name="text" >
<string>Set global upload limit</string>
</property>
</action>
</widget>
<resources/>
<connections>
<connection>
<sender>search_pattern</sender>
<signal>returnPressed()</signal>
<receiver>search_button</receiver>
<slot>click()</slot>
<hints>
<hint type="sourcelabel" >
<x>405</x>
<y>125</y>
</hint>
<hint type="destinationlabel" >
<x>543</x>
<y>123</y>
</hint>
</hints>
</connection>
</connections>
<connections/>
</ui>

View File

@@ -24,6 +24,7 @@
#include <QItemDelegate>
#include <QStyleOptionProgressBarV2>
#include <QStyleOptionViewItemV2>
#include <QModelIndex>
#include <QPainter>
#include <QProgressBar>
@@ -35,80 +36,43 @@
#define SIZE 1
#define PROGRESS 2
class PreviewListDelegate: public QAbstractItemDelegate {
class PreviewListDelegate: public QItemDelegate {
Q_OBJECT
public:
PreviewListDelegate(QObject *parent=0) : QAbstractItemDelegate(parent){}
PreviewListDelegate(QObject *parent=0) : QItemDelegate(parent){}
~PreviewListDelegate(){}
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const{
QItemDelegate delegate;
QStyleOptionViewItem opt = option;
QStyleOptionProgressBarV2 newopt;
char tmp[MAX_CHAR_TMP];
float progress;
// set text color
QVariant value = index.data(Qt::TextColorRole);
if (value.isValid() && qvariant_cast<QColor>(value).isValid()){
opt.palette.setColor(QPalette::Text, qvariant_cast<QColor>(value));
}
QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
? QPalette::Normal : QPalette::Disabled;
if (option.state & QStyle::State_Selected){
painter->setPen(opt.palette.color(cg, QPalette::HighlightedText));
}else{
painter->setPen(opt.palette.color(cg, QPalette::Text));
}
// draw the background color
if(index.column() != PROGRESS){
if (option.showDecorationSelected && (option.state & QStyle::State_Selected)){
if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)){
cg = QPalette::Inactive;
}
painter->fillRect(option.rect, option.palette.brush(cg, QPalette::Highlight));
}else{
value = index.data(Qt::BackgroundColorRole);
if (value.isValid() && qvariant_cast<QColor>(value).isValid()){
painter->fillRect(option.rect, qvariant_cast<QColor>(value));
}
}
}
QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option);
switch(index.column()){
case SIZE:
painter->drawText(option.rect, Qt::AlignCenter, misc::friendlyUnit(index.data().toLongLong()));
QItemDelegate::drawBackground(painter, opt, index);
QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong()));
break;
case NAME:
painter->drawText(option.rect, Qt::AlignLeft, index.data().toString());
break;
case PROGRESS:
progress = index.data().toDouble()*100.;
snprintf(tmp, MAX_CHAR_TMP, "%.1f", progress);
case PROGRESS:{
float progress = index.data().toDouble()*100.;
QStyleOptionProgressBarV2 newopt;
newopt.rect = opt.rect;
newopt.text = QString(tmp)+"%";
newopt.text = QString(QByteArray::number(progress, 'f', 1))+QString::fromUtf8("%");
newopt.progress = (int)progress;
newopt.maximum = 100;
newopt.minimum = 0;
newopt.state |= QStyle::State_Enabled;
newopt.textVisible = false;
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt,
painter);
//We prefer to display text manually to control color/font/boldness
if (option.state & QStyle::State_Selected){
opt.palette.setColor(QPalette::Text, QColor("grey"));
painter->setPen(opt.palette.color(cg, QPalette::Text));
}
painter->drawText(option.rect, Qt::AlignCenter, newopt.text);
newopt.textVisible = true;
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt, painter);
break;
}
default:
painter->drawText(option.rect, Qt::AlignCenter, index.data().toString());
QItemDelegate::paint(painter, option, index);
}
}
QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const{
QItemDelegate delegate;
return delegate.sizeHint(option, index);
QWidget* createEditor(QWidget*, const QStyleOptionViewItem &, const QModelIndex &) const {
// No editor here
return 0;
}
};

View File

@@ -22,8 +22,11 @@
#ifndef PROPLISTDELEGATE_H
#define PROPLISTDELEGATE_H
#include <QAbstractItemDelegate>
#include <QItemDelegate>
#include <QStyleOptionProgressBarV2>
#include <QStyleOptionViewItemV2>
#include <QStyleOptionComboBox>
#include <QComboBox>
#include <QModelIndex>
#include <QPainter>
#include <QProgressBar>
@@ -34,82 +37,112 @@
#define NAME 0
#define SIZE 1
#define PROGRESS 2
#define SELECTED 3
#define PRIORITY 3
#define INDEX 4
class PropListDelegate: public QAbstractItemDelegate {
#define IGNORED 0
#define NORMAL 1
#define HIGH 2
#define MAXIMUM 7
class PropListDelegate: public QItemDelegate {
Q_OBJECT
private:
bool* filteredFilesChanged;
public:
PropListDelegate(QObject *parent=0) : QAbstractItemDelegate(parent){}
PropListDelegate(QObject *parent=0, bool* filteredFilesChanged=0) : QItemDelegate(parent){
this->filteredFilesChanged = filteredFilesChanged;
}
~PropListDelegate(){}
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const{
QStyleOptionViewItem opt = option;
char tmp[MAX_CHAR_TMP];
// set text color
QVariant value = index.data(Qt::TextColorRole);
if (value.isValid() && qvariant_cast<QColor>(value).isValid()){
opt.palette.setColor(QPalette::Text, qvariant_cast<QColor>(value));
}
QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
? QPalette::Normal : QPalette::Disabled;
if (option.state & QStyle::State_Selected){
painter->setPen(opt.palette.color(cg, QPalette::HighlightedText));
}else{
painter->setPen(opt.palette.color(cg, QPalette::Text));
}
// draw the background color
if(index.column() != PROGRESS){
if (option.showDecorationSelected && (option.state & QStyle::State_Selected)){
if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)){
cg = QPalette::Inactive;
}
painter->fillRect(option.rect, option.palette.brush(cg, QPalette::Highlight));
}else{
value = index.data(Qt::BackgroundColorRole);
if (value.isValid() && qvariant_cast<QColor>(value).isValid()){
painter->fillRect(option.rect, qvariant_cast<QColor>(value));
}
}
}
QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option);
QPalette::ColorGroup cg = option.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
switch(index.column()){
case SIZE:
painter->drawText(option.rect, Qt::AlignCenter, misc::friendlyUnit(index.data().toLongLong()));
break;
case NAME:
painter->drawText(option.rect, Qt::AlignLeft, index.data().toString());
QItemDelegate::drawBackground(painter, opt, index);
QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong()));
break;
case PROGRESS:{
QStyleOptionProgressBarV2 newopt;
float progress = index.data().toDouble()*100.;
snprintf(tmp, MAX_CHAR_TMP, "%.1f", progress);
newopt.rect = opt.rect;
newopt.text = QString(tmp)+"%";
newopt.text = QString(QByteArray::number(progress, 'f', 1))+QString::fromUtf8("%");
newopt.progress = (int)progress;
newopt.maximum = 100;
newopt.minimum = 0;
newopt.state |= QStyle::State_Enabled;
newopt.textVisible = false;
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt,
painter);
//We prefer to display text manually to control color/font/boldness
if (option.state & QStyle::State_Selected){
opt.palette.setColor(QPalette::Text, QColor("grey"));
painter->setPen(opt.palette.color(cg, QPalette::Text));
}
painter->drawText(option.rect, Qt::AlignCenter, newopt.text);
newopt.textVisible = true;
QApplication::style()->drawControl(QStyle::CE_ProgressBar, &newopt, painter);
break;
}
case SELECTED:
if(index.data().toBool()){
painter->drawText(option.rect, Qt::AlignCenter, tr("True"));
}else{
painter->drawText(option.rect, Qt::AlignCenter, tr("False"));
}
case PRIORITY:{
QStyleOptionComboBox newopt;
newopt.rect = opt.rect;
switch(index.data().toInt()){
case IGNORED:
newopt.currentText = tr("Ignored");
break;
case NORMAL:
newopt.currentText = tr("Normal", "Normal (priority)");
break;
case HIGH:
newopt.currentText = tr("High", "High (priority)");
break;
case MAXIMUM:
newopt.currentText = tr("Maximum", "Maximum (priority)");
break;
default:
painter->drawText(option.rect, Qt::AlignCenter, index.data().toString());
qDebug("Unhandled priority, setting NORMAL");
newopt.currentText = tr("Normal", "Normal (priority)");
}
newopt.state |= QStyle::State_Enabled;
QApplication::style()->drawComplexControl(QStyle::CC_ComboBox, &newopt,
painter);
opt.palette.setColor(QPalette::Text, QColor("black"));
painter->setPen(opt.palette.color(cg, QPalette::Text));
painter->drawText(option.rect, Qt::AlignLeft, QString::fromUtf8(" ")+newopt.currentText);
break;
}
default:
QItemDelegate::paint(painter, option, index);
}
}
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex & index) const {
if(index.column() != PRIORITY) return 0;
QComboBox* editor = new QComboBox(parent);
editor->setFocusPolicy(Qt::StrongFocus);
editor->addItem(tr("Ignored"));
editor->addItem(tr("Normal", "Normal (priority)"));
editor->addItem(tr("High", "High (priority)"));
editor->addItem(tr("Maximum", "Maximum (priority)"));
return editor;
}
void setEditorData(QWidget *editor, const QModelIndex &index) const {
unsigned short val = index.model()->data(index, Qt::DisplayRole).toInt();
QComboBox *combobox = static_cast<QComboBox*>(editor);
qDebug("Set Editor data: Prio is %d", val);
switch(val){
case IGNORED:
combobox->setCurrentIndex(0);
break;
case NORMAL:
combobox->setCurrentIndex(1);
break;
case HIGH:
combobox->setCurrentIndex(2);
break;
case MAXIMUM:
combobox->setCurrentIndex(3);
break;
default:
qDebug("Unhandled priority, setting to NORMAL");
combobox->setCurrentIndex(1);
}
}
@@ -121,6 +154,73 @@ class PropListDelegate: public QAbstractItemDelegate {
QRect textRect = QRect(0, 0, 0, fontMetrics.lineSpacing() * (text.count(QLatin1Char('\n')) + 1));
return textRect.size();
}
public slots:
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const {
QComboBox *combobox = static_cast<QComboBox*>(editor);
int value = combobox->currentIndex();
qDebug("Setting combobox value in index: %d", value);
unsigned short old_val = index.model()->data(index, Qt::DisplayRole).toInt();
switch(value){
case 0:
if(old_val != IGNORED){
model->setData(index, QVariant(IGNORED));
if(filteredFilesChanged != 0)
*filteredFilesChanged = true;
} else {
// XXX: hack to force the model to send the itemChanged() signal
model->setData(index, QVariant(NORMAL));
model->setData(index, QVariant(IGNORED));
}
break;
case 1:
// if(old_val != NORMAL){
// model->setData(index, QVariant(NORMAL));
// if(filteredFilesChanged != 0)
// *filteredFilesChanged = true;
// } else {
model->setData(index, QVariant(HIGH));
model->setData(index, QVariant(NORMAL));
if(filteredFilesChanged != 0)
*filteredFilesChanged = true;
// }
break;
case 2:
if(old_val != HIGH){
model->setData(index, QVariant(HIGH));
if(filteredFilesChanged != 0)
*filteredFilesChanged = true;
} else {
model->setData(index, QVariant(NORMAL));
model->setData(index, QVariant(HIGH));
}
break;
case 3:
if(old_val != MAXIMUM){
model->setData(index, QVariant(MAXIMUM));
if(filteredFilesChanged != 0)
*filteredFilesChanged = true;
} else {
model->setData(index, QVariant(HIGH));
model->setData(index, QVariant(MAXIMUM));
}
break;
default:
if(old_val != NORMAL){
model->setData(index, QVariant(NORMAL));
if(filteredFilesChanged != 0)
*filteredFilesChanged = true;
} else {
model->setData(index, QVariant(HIGH));
model->setData(index, QVariant(NORMAL));
}
}
}
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const {
editor->setGeometry(option.rect);
}
};
#endif

View File

@@ -22,8 +22,9 @@
#ifndef SEARCHLISTDELEGATE_H
#define SEARCHLISTDELEGATE_H
#include <QAbstractItemDelegate>
#include <QItemDelegate>
#include <QStyleOptionProgressBarV2>
#include <QStyleOptionViewItemV2>
#include <QModelIndex>
#include <QPainter>
#include <QProgressBar>
@@ -36,59 +37,29 @@
#define LEECHERS 3
#define ENGINE 4
class SearchListDelegate: public QAbstractItemDelegate {
class SearchListDelegate: public QItemDelegate {
Q_OBJECT
public:
SearchListDelegate(QObject *parent=0) : QAbstractItemDelegate(parent){}
SearchListDelegate(QObject *parent=0) : QItemDelegate(parent){}
~SearchListDelegate(){}
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const{
QStyleOptionViewItem opt = option;
// set text color
QVariant value = index.data(Qt::TextColorRole);
if (value.isValid() && qvariant_cast<QColor>(value).isValid()){
opt.palette.setColor(QPalette::Text, qvariant_cast<QColor>(value));
}
QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
? QPalette::Normal : QPalette::Disabled;
if (option.state & QStyle::State_Selected){
painter->setPen(opt.palette.color(cg, QPalette::HighlightedText));
}else{
painter->setPen(opt.palette.color(cg, QPalette::Text));
}
// draw the background color
if (option.showDecorationSelected && (option.state & QStyle::State_Selected)){
if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)){
cg = QPalette::Inactive;
}
painter->fillRect(option.rect, option.palette.brush(cg, QPalette::Highlight));
}else{
value = index.data(Qt::BackgroundColorRole);
if (value.isValid() && qvariant_cast<QColor>(value).isValid()){
painter->fillRect(option.rect, qvariant_cast<QColor>(value));
}
}
QStyleOptionViewItemV2 opt = QItemDelegate::setOptions(index, option);
switch(index.column()){
case SIZE:
painter->drawText(option.rect, Qt::AlignCenter, misc::friendlyUnit(index.data().toLongLong()));
break;
case NAME:
painter->drawText(option.rect, Qt::AlignLeft, index.data().toString());
QItemDelegate::drawBackground(painter, opt, index);
QItemDelegate::drawDisplay(painter, opt, option.rect, misc::friendlyUnit(index.data().toLongLong()));
break;
default:
painter->drawText(option.rect, Qt::AlignCenter, index.data().toString());
QItemDelegate::paint(painter, option, index);
}
}
QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const{
QVariant value = index.data(Qt::FontRole);
QFont fnt = value.isValid() ? qvariant_cast<QFont>(value) : option.font;
QFontMetrics fontMetrics(fnt);
const QString text = index.data(Qt::DisplayRole).toString();
QRect textRect = QRect(0, 0, 0, fontMetrics.lineSpacing() * (text.count(QLatin1Char('\n')) + 1));
return textRect.size();
QWidget* createEditor(QWidget*, const QStyleOptionViewItem &, const QModelIndex &) const {
// No editor here
return 0;
}
};

53
src/TrackersAdditionDlg.h Normal file
View File

@@ -0,0 +1,53 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contact : chris@qbittorrent.org
*/
#ifndef TRACKERSADDITION_H
#define TRACKERSADDITION_H
#include <QDialog>
#include <QStringList>
#include "ui_trackersAdd.h"
class TrackersAddDlg : public QDialog, private Ui::TrackersAdditionDlg{
Q_OBJECT
public:
TrackersAddDlg(QWidget *parent): QDialog(parent){
setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
show();
}
~TrackersAddDlg(){}
signals:
void TrackersToAdd(QStringList trackers);
public slots:
void on_buttonBox_accepted() {
QStringList trackers = trackers_list->toPlainText().trimmed().split("\n");
if(trackers.size()) {
emit TrackersToAdd(trackers);
}
}
};
#endif

View File

@@ -1,7 +1,5 @@
<ui version="4.0" >
<author>Christophe Dumez</author>
<comment></comment>
<exportmacro></exportmacro>
<class>AboutDlg</class>
<widget class="QDialog" name="AboutDlg" >
<property name="geometry" >
@@ -12,26 +10,38 @@
<height>320</height>
</rect>
</property>
<property name="minimumSize" >
<size>
<width>504</width>
<height>320</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>504</width>
<height>320</height>
</size>
</property>
<property name="windowTitle" >
<string>About qBittorrent</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="logo" >
<property name="minimumSize" >
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text" >
<string/>
</property>
@@ -40,9 +50,7 @@
<item>
<widget class="QLabel" name="lb_name" >
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>5</vsizetype>
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -55,6 +63,19 @@
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
@@ -66,44 +87,30 @@
<attribute name="title" >
<string>About</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
<widget class="QLabel" name="mascot_lbl" >
<property name="geometry" >
<rect>
<x>380</x>
<y>50</y>
<width>94</width>
<height>162</height>
</rect>
</property>
<property name="spacing" >
<number>6</number>
<property name="text" >
<string/>
</property>
<item>
<widget class="QWidget" name="widget1" >
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
</widget>
<widget class="QLabel" name="lb_about" >
<property name="geometry" >
<rect>
<x>0</x>
<y>40</y>
<width>481</width>
<height>102</height>
</rect>
</property>
<property name="sizePolicy" >
<sizepolicy>
<hsizetype>7</hsizetype>
<vsizetype>7</vsizetype>
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@@ -121,66 +128,39 @@ Copyright © 2006 by Christophe Dumez&lt;br>
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab3" >
<attribute name="title" >
<string>Author</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QFrame" name="te_authors" >
<layout class="QHBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QSplitter" name="splitter" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="widget" >
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
<property name="sizeType" >
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="spacing" >
<number>6</number>
<property name="sizeHint" >
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
@@ -295,10 +275,23 @@ Copyright © 2006 by Christophe Dumez&lt;br>
</layout>
</item>
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
@@ -346,10 +339,6 @@ Copyright © 2006 by Christophe Dumez&lt;br>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
@@ -370,12 +359,9 @@ Copyright © 2006 by Christophe Dumez&lt;br>
</widget>
<widget class="QWidget" name="tab4" >
<attribute name="title" >
<string>Thanks To</string>
<string>Thanks to</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
@@ -389,9 +375,6 @@ Copyright © 2006 by Christophe Dumez&lt;br>
<string>Translation</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
@@ -409,9 +392,6 @@ Copyright © 2006 by Christophe Dumez&lt;br>
<string>License</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
@@ -425,7 +405,6 @@ Copyright © 2006 by Christophe Dumez&lt;br>
</layout>
</widget>
<layoutdefault spacing="6" margin="11" />
<pixmapfunction></pixmapfunction>
<resources/>
<connections/>
</ui>

View File

@@ -23,40 +23,51 @@
#define ABOUT_H
#include "ui_about.h"
#include <QScrollBar>
class about : public QDialog, private Ui::AboutDlg{
Q_OBJECT
public:
about(QWidget *parent = 0): QDialog(parent){
~about() {
qDebug("Deleting about dlg");
}
about(QWidget *parent): QDialog(parent){
setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
// Set icons
logo->setPixmap(QPixmap(QString::fromUtf8(":/Icons/qbittorrent32.png")));
logo->setPixmap(QPixmap(QString::fromUtf8(":/Icons/qbittorrent22.png")));
mascot_lbl->setPixmap(QPixmap(QString::fromUtf8(":/Icons/mascot.png")));
//Title
lb_name->setText("<b><h1>"+tr("qBittorrent")+" "VERSION"</h1></b>");
lb_name->setText(QString::fromUtf8("<b><h1>")+tr("qBittorrent")+QString::fromUtf8(" "VERSION"</h1></b>"));
// Thanks
te_thanks->append("<ul><li>I would like to thank sourceforge.net for hosting qBittorrent project.</li>");
te_thanks->append("<li>I also want to thank Jeffery Fernandez (jeffery@qbittorrent.org), project consultant, webdevelopper and RPM packager, for his help.</li>");
te_thanks->append("<li>I am gratefull to Peter Koeleman (peter@qbittorrent.org) and Johnny Mast (rave@qbittorrent.org) who helped me port qBittorrent to Windows.</li>");
te_thanks->append("<li>Thanks a lot to our graphist Mateusz Toboła (tobejodok@qbittorrent.org) for his great work.</li></ul>");
te_thanks->append(QString::fromUtf8("<a name='top'></a>"));
te_thanks->append(QString::fromUtf8("<ul><li>I would like to thank sourceforge.net for hosting qBittorrent project.</li>"));
te_thanks->append(QString::fromUtf8("<li>I am happy that Arnaud Demaizière is contributing to the project as a developer. His help is greatly appreciated</li>"));
te_thanks->append(QString::fromUtf8("<li>I also want to thank Jeffery Fernandez (jeffery@qbittorrent.org), project consultant, RPM packager, for his help and support.</li>"));
te_thanks->append(QString::fromUtf8("<li>I am grateful to Peter Koeleman (peter@qbittorrent.org) who is helping port qBittorrent to Windows.</li>"));
te_thanks->append(QString::fromUtf8("<li>Thanks a lot to our graphist Mateusz Toboła (tobejodok@qbittorrent.org) for his great work.</li></ul><br><br>"));
te_thanks->scrollToAnchor(QString::fromUtf8("top"));
// Translation
te_translation->append(tr("I would like to thank the following people who volunteered to translate qBittorrent:")+"<br>");
te_translation->append(QString::fromUtf8("<a name='top'></a>"));
te_translation->append(tr("I would like to thank the following people who volunteered to translate qBittorrent:")+QString::fromUtf8("<br>"));
te_translation->append(QString::fromUtf8(
"<i>- <u>Bulgarian:</u> Tsvetan & Boiko Bankov (emerge_life@users.sourceforge.net)<br>\
"<i>- <u>Brazilian:</u> Nick Marinho (nickmarinho@gmail.com)<br>\
- <u>Bulgarian:</u> Tsvetan & Boiko Bankov (emerge_life@users.sourceforge.net)<br>\
- <u>Catalan:</u> Gekko Dam Beer (gekko04@users.sourceforge.net)<br>\
- <u>Chinese (Simplified):</u> Guo Yue (guoyue0418@hotmail.com)<br>\
- <u>Chinese (Traditional):</u> Jeff Chen (jeff.cn.chen@gmail.com)<br>\
- <u>Danish:</u> Mathias Nielsen (comoneo@gmail.com)<br>\
- <u>Dutch:</u> Luke Niesink (luke@lukeniesink.net)<br>\
- <u>Dutch:</u> Joost Schipper (heavyjoost@users.sourceforge.net)<br>\
- <u>Finnish:</u> Niklas Laxström (nikerabbit@users.sourceforge.net)<br>\
- <u>German:</u> Niels Hoffmann (zentralmaschine@users.sourceforge.net)<br>\
- <u>Greek:</u> Tsvetan Bankov (emerge_life@users.sourceforge.net)<br>\
- <u>Italian:</u> Ferraro Luciano (luciano.ferraro@gmail.com)<br>\
- <u>Hungarian:</u> Majoros Péter (majoros.j.p@t-online.hu)<br>\
- <u>Italian:</u> Mirko Ferrari (mirkoferrari@gmail.com) and Ferraro Luciano (luciano.ferraro@gmail.com)<br>\
- <u>Japanese:</u> Nardog (nardog@e2umail.com)<br>\
- <u>Korean:</u> Jin Woo Sin (jin828sin@users.sourceforge.net)<br>\
- <u>Norwegian:</u> Lars-Erik Labori (hamil@users.sourceforge.net)<br>\
- <u>Polish:</u> Adam Babol (a-b@users.sourceforge.net)<br>\
- <u>Polish:</u> Jarek Smieja (ajep9691@wp.pl)<br>\
- <u>Portuguese:</u> Nick Marinho (nickmarinho@gmail.com)<br>\
- <u>Romanian:</u> Obada Denis (obadadenis@users.sourceforge.net)<br>\
- <u>Russian:</u> Nick Khazov (m2k3d0n at users.sourceforge.net)<br>\
@@ -66,8 +77,10 @@ class about : public QDialog, private Ui::AboutDlg{
- <u>Turkish:</u> Erdem Bingöl (erdem84@gmail.com)<br>\
- <u>Ukrainian:</u> Andrey Shpachenko (masterfix@users.sourceforge.net)<br><br>"));
te_translation->append(tr("Please contact me if you would like to translate qBittorrent into your own language."));
te_translation->scrollToAnchor(QString::fromUtf8("top"));
// License
te_license->append("<center><b>GNU GENERAL PUBLIC LICENSE</b></center><br>\
te_license->append(QString::fromUtf8("<a name='top'></a>"));
te_license->append(QString::fromUtf8("<center><b>GNU GENERAL PUBLIC LICENSE</b></center><br>\
<center>Version 2, June 1991</center><br>\
Copyright (C) 1989, 1991 Free Software Foundation, Inc.<br>\
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA<br>\
@@ -400,7 +413,8 @@ class about : public QDialog, private Ui::AboutDlg{
proprietary programs. If your program is a subroutine library, you may<br>\
consider it more useful to permit linking proprietary applications with the<br>\
library. If this is what you want to do, use the GNU Library General<br>\
Public License instead of this License.<br>");
Public License instead of this License.<br>"));
te_license->scrollToAnchor(QString::fromUtf8("top"));
show();
}
};

View File

@@ -5,20 +5,29 @@
<rect>
<x>0</x>
<y>0</y>
<width>440</width>
<height>389</height>
<width>511</width>
<height>441</height>
</rect>
</property>
<property name="windowTitle" >
<string>Torrent addition dialog</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>9</number>
</property>
<property name="topMargin" >
<number>9</number>
</property>
<property name="rightMargin" >
<number>9</number>
</property>
<property name="bottomMargin" >
<number>9</number>
</property>
<item>
<widget class="QLabel" name="fileNameLbl" >
<property name="text" >
@@ -48,12 +57,21 @@
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="savePathTxt" />
</item>
@@ -80,31 +98,16 @@
</widget>
</item>
<item>
<widget class="QTreeWidget" name="torrentContentList" >
<widget class="QTreeView" name="torrentContentList" >
<property name="contextMenuPolicy" >
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="editTriggers" >
<set>QAbstractItemView::AllEditTriggers</set>
</property>
<property name="selectionMode" >
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="indentation" >
<number>2</number>
</property>
<column>
<property name="text" >
<string>File name</string>
</property>
</column>
<column>
<property name="text" >
<string>File size</string>
</property>
</column>
<column>
<property name="text" >
<string>Selected</string>
</property>
</column>
</widget>
</item>
<item>
@@ -123,12 +126,21 @@
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<spacer>
<property name="orientation" >
@@ -172,20 +184,24 @@
</layout>
</item>
</layout>
<action name="actionSelect" >
<action name="actionIgnored" >
<property name="text" >
<string>Select</string>
</property>
<property name="iconText" >
<string>Select</string>
</property>
<property name="toolTip" >
<string>Select</string>
<string>Ignored</string>
</property>
</action>
<action name="actionUnselect" >
<action name="actionNormal" >
<property name="text" >
<string>Unselect</string>
<string>Normal</string>
</property>
</action>
<action name="actionHigh" >
<property name="text" >
<string>High</string>
</property>
</action>
<action name="actionMaximum" >
<property name="text" >
<string>Maximum</string>
</property>
</action>
</widget>

179
src/allocationDlg.h Normal file
View File

@@ -0,0 +1,179 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contact : chris@qbittorrent.org
*/
#ifndef BANDWIDTH_ALLOCATION_H
#define BANDWIDTH_ALLOCATION_H
#include <QDialog>
#include <QList>
#include <QSettings>
#include "ui_bandwidth_limit.h"
#include "misc.h"
#include "bittorrent.h"
using namespace libtorrent;
class BandwidthAllocationDialog : public QDialog, private Ui_bandwidth_dlg {
Q_OBJECT
public:
BandwidthAllocationDialog(QWidget *parent, bool uploadMode, bittorrent *BTSession, QStringList hashes): QDialog(parent), uploadMode(uploadMode), hashes(hashes){
setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
qDebug("Bandwidth allocation dialog creation");
this->BTSession = BTSession;
if(hashes.size() == 0)
global = true;
else
global = false;
if(uploadMode)
lblTitle->setText(tr("Upload limit:"));
else
lblTitle->setText(tr("Download limit:"));
connect(bandwidthSlider, SIGNAL(valueChanged(int)), this, SLOT(updateBandwidthLabel(int)));
if(!global){
unsigned int nbTorrents = hashes.size();
if(!nbTorrents) close();
int val = 0;
int max = -1;
if(nbTorrents == 1){
QTorrentHandle h = BTSession->getTorrentHandle(hashes.at(0));
if(uploadMode){
if(h.upload_limit() > 0)
val = (int)(h.upload_limit() / 1024.);
if(BTSession->getSession()->upload_rate_limit() > 0)
max = (int)(BTSession->getSession()->upload_rate_limit() / 1024.);
}else{
if(h.download_limit() > 0)
val = (int)(h.download_limit() / 1024.);
if(BTSession->getSession()->download_rate_limit() > 0){
qDebug("there is a global download rate limit at: %d kb/s", (int)(BTSession->getSession()->download_rate_limit() / 1024.));
max = (int)(BTSession->getSession()->download_rate_limit() / 1024.);
}
}
if(max != -1)
bandwidthSlider->setMaximum(max);
qDebug("Bandwidth limit: %d", val);
if(val > bandwidthSlider->maximum())
val = bandwidthSlider->maximum();
else if(val < bandwidthSlider->minimum())
val = 0;
bandwidthSlider->setValue(val);
if(val == 0) {
limit_lbl->setText(tr("Unlimited", "Unlimited (bandwidth)"));
kb_lbl->setText(QString::fromUtf8(""));
} else {
limit_lbl->setText(misc::toQString(val));
}
}else{
qDebug("More than one torrent selected, no initilization");
bandwidthSlider->setValue(0);
limit_lbl->setText(tr("Unlimited", "Unlimited (bandwidth)"));
kb_lbl->setText(QString::fromUtf8(""));
}
}else{
// Global limit
int val = 0;
session *s = BTSession->getSession();
if(uploadMode){
if(s->upload_rate_limit() > 0)
val = (int)(s->upload_rate_limit()/1024.);
}else{
if(s->download_rate_limit() > 0)
val = (int)(s->download_rate_limit()/1024.);
}
if(val == 0){
bandwidthSlider->setValue(0);
limit_lbl->setText(tr("Unlimited", "Unlimited (bandwidth)"));
kb_lbl->setText(QString::fromUtf8(""));
}else{
bandwidthSlider->setValue(val);
}
}
connect(buttonBox, SIGNAL(accepted()), this, SLOT(setBandwidth()));
show();
}
~BandwidthAllocationDialog(){
qDebug("Deleting bandwidth allocation dialog");
}
protected slots:
void updateBandwidthLabel(int val){
if(val == 0){
limit_lbl->setText(tr("Unlimited", "Unlimited (bandwidth)"));
kb_lbl->setText(QString::fromUtf8(""));
}else{
limit_lbl->setText(misc::toQString(val));
kb_lbl->setText(tr("KiB/s"));
}
}
void setBandwidth(){
qDebug("setBandwidth called");
int val = bandwidthSlider->value();
if(!global){
QString hash;
if(uploadMode) {
foreach(hash, hashes) {
if(!val)
BTSession->setUploadLimit(hash, -1);
else
BTSession->setUploadLimit(hash, val*1024);
qDebug("Setting upload limit");
}
} else {
foreach(hash, hashes) {
if(!val)
BTSession->setDownloadLimit(hash, -1);
else
BTSession->setDownloadLimit(hash, val*1024);
qDebug("Setting download limit");
}
}
}else{
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
session *s = BTSession->getSession();
if(uploadMode){
if(!val)
s->set_upload_rate_limit(-1);
else
s->set_upload_rate_limit(val*1024);
settings.setValue(QString::fromUtf8("Preferences/Connection/GlobalUPLimit"), val);
}else{
if(!val)
s->set_download_rate_limit(-1);
else
s->set_download_rate_limit(val*1024);
settings.setValue(QString::fromUtf8("Preferences/Connection/GlobalDLLimit"), val);
}
}
close();
}
private:
bool uploadMode;
bool global;
bittorrent *BTSession;
QStringList hashes;
};
#endif

264
src/arborescence.h Normal file
View File

@@ -0,0 +1,264 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contact : chris@qbittorrent.org
*/
#ifndef ARBORESCENCE_H
#define ARBORESCENCE_H
#include <QFileInfo>
#include <QStringList>
#include <QDir>
#include "misc.h"
class torrent_file {
private:
torrent_file *parent;
bool is_dir;
QString rel_path;
QList<torrent_file*> children;
size_type size;
float progress;
int priority;
int index; // Index in torrent_info
public:
torrent_file(torrent_file *parent, QString path, bool dir, size_type size=0, int index=-1, float progress=0., int priority=1): parent(parent), is_dir(dir), size(size), progress(progress), priority(priority), index(index){
qDebug("created a file with index %d", index);
rel_path = QDir::cleanPath(path);
if(parent) {
parent->updateProgress();
parent->updatePriority(priority);
}
}
~torrent_file() {
qDeleteAll(children);
}
QString path() const {
return rel_path;
}
QString name() const {
return rel_path.split(QDir::separator()).last();
}
void updateProgress() {
Q_ASSERT(is_dir);
if(children.isEmpty()) {
progress = 0.;
return;
}
float wanted = 0.;
float done = 0.;
torrent_file *child;
foreach(child, children) {
wanted += child->getSize();
done += child->getSize()*child->getProgress();
}
progress = done / wanted;
Q_ASSERT(progress >= 0.);
Q_ASSERT(progress <= 1.);
}
void updatePriority(int prio) {
Q_ASSERT(is_dir);
torrent_file *child;
foreach(child, children) {
if(child->getPriority() != prio) return;
}
priority = prio;
}
int getPriority() const {
return priority;
}
size_type getSize() const {
return size;
}
float getProgress() const {
return progress;
}
int getIndex() const {
return index;
}
bool isDir() const {
return is_dir;
}
bool hasChildren() const {
return (!children.isEmpty());
}
QList<torrent_file*> getChildren() const {
return children;
}
torrent_file* getChild(QString fileName) const {
Q_ASSERT(is_dir);
torrent_file* f;
foreach(f, children) {
if(f->name() == fileName) return f;
}
return 0;
}
void addBytes(size_type b) {
size += b;
if(parent)
parent->addBytes(b);
}
torrent_file* addChild(QString fileName, bool dir, size_type size=0, int index = -1, float progress=0., int priority=1) {
Q_ASSERT(is_dir);
qDebug("Adding a new child of size: %ld", (long)size);
torrent_file *f = new torrent_file(this, QDir::cleanPath(rel_path+QDir::separator()+fileName), dir, size, index, progress, priority);
children << f;
if(size) {
addBytes(size);
}
return f;
}
bool removeFromFS(QString saveDir) {
QString full_path = saveDir + QDir::separator() + rel_path;
if(!QFile::exists(full_path)) {
qDebug("%s does not exist, no need to remove it", full_path.toUtf8().data());
return true;
}
bool success = true;
torrent_file *f;
qDebug("We have %d children", children.size());
foreach(f, children) {
bool s = f->removeFromFS(saveDir);
success = s && success;
}
if(is_dir) {
qDebug("trying to remove directory: %s", full_path.toUtf8().data());
QDir dir(full_path);
dir.rmdir(full_path);
} else {
qDebug("trying to remove file: %s", full_path.toUtf8().data());
bool s = QFile::remove(full_path);
success = s && success;
}
return success;
}
};
class arborescence {
private:
torrent_file *root;
public:
arborescence(torrent_info t) {
torrent_info::file_iterator fi = t.begin_files();
if(t.num_files() > 1) {
root = new torrent_file(0, misc::toQString(t.name()), true);
} else {
// XXX: Will crash if there is no file in torrent
root = new torrent_file(0, misc::toQString(t.name()), false, fi->size, 0);
return;
}
int i = 0;
while(fi != t.end_files()) {
QString path = QDir::cleanPath(misc::toQString(fi->path.string()));
addFile(path, fi->size, i);
fi++;
++i;
}
qDebug("real size: %ld, tree size: %ld", (long)t.total_size(), (long)root->getSize());
Q_ASSERT(root->getSize() == t.total_size());
}
arborescence(torrent_info t, std::vector<float> fp, int *prioritiesTab) {
torrent_info::file_iterator fi = t.begin_files();
if(t.num_files() > 1) {
qDebug("More than one file in the torrent, setting a folder as root");
root = new torrent_file(0, misc::toQString(t.name()), true);
} else {
// XXX: Will crash if there is no file in torrent
qDebug("one file in the torrent, setting it as root with index 0");
root = new torrent_file(0, misc::toQString(t.name()), false, fi->size, 0, fp[0], prioritiesTab[0]);
return;
}
int i = 0;
while(fi != t.end_files()) {
QString path = QDir::cleanPath(misc::toQString(fi->path.string()));
addFile(path, fi->size, i, fp[i], prioritiesTab[i]);
fi++;
++i;
}
qDebug("real size: %ld, tree size: %ld", (long)t.total_size(), (long)root->getSize());
Q_ASSERT(root->getSize() == t.total_size());
}
~arborescence() {
delete root;
}
torrent_file* getRoot() const {
return root;
}
bool removeFromFS(QString saveDir) {
if(!QFile::exists(saveDir+QDir::separator()+root->path())) return true;
bool success = root->removeFromFS(saveDir);
QDir root_dir(root->path());
root_dir.rmdir(saveDir+QDir::separator()+root->path());
return success;
}
protected:
void addFile(QString path, size_type file_size, int index, float progress=0., int priority=1) {
Q_ASSERT(root->isDir());
path = QDir::cleanPath(path);
Q_ASSERT(path.startsWith(root->path()));
QString relative_path = path.remove(0, root->path().size());
if(relative_path.at(0) ==QDir::separator())
relative_path.remove(0, 1);
QStringList fileNames = relative_path.split(QDir::separator());
QString fileName;
torrent_file *dad = root;
unsigned int nb_i = 0;
unsigned int size = fileNames.size();
foreach(fileName, fileNames) {
++nb_i;
if(fileName == ".") continue;
torrent_file* child = dad->getChild(fileName);
if(!child) {
if(nb_i != size) {
// Folder
child = dad->addChild(fileName, true);
} else {
// File
child = dad->addChild(fileName, false, file_size, index, progress, priority);
}
}
dad = child;
}
}
};
#endif

113
src/bandwidth_limit.ui Normal file
View File

@@ -0,0 +1,113 @@
<ui version="4.0" >
<class>bandwidth_dlg</class>
<widget class="QDialog" name="bandwidth_dlg" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>222</width>
<height>129</height>
</rect>
</property>
<property name="windowTitle" >
<string>Bandwidth allocation</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="lblTitle" >
<property name="text" >
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="limit_lbl" >
<property name="text" >
<string/>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="kb_lbl" >
<property name="text" >
<string>KiB/s</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QSlider" name="bandwidthSlider" >
<property name="minimum" >
<number>0</number>
</property>
<property name="maximum" >
<number>1000</number>
</property>
<property name="sliderPosition" >
<number>0</number>
</property>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>bandwidth_dlg</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel" >
<x>212</x>
<y>83</y>
</hint>
<hint type="destinationlabel" >
<x>221</x>
<y>98</y>
</hint>
</hints>
</connection>
</connections>
</ui>

File diff suppressed because it is too large Load Diff

View File

@@ -21,129 +21,167 @@
#ifndef __BITTORRENT_H__
#define __BITTORRENT_H__
#include <QTimer>
#include <libtorrent/entry.hpp>
#include <libtorrent/bencode.hpp>
#include <libtorrent/session.hpp>
#include <libtorrent/fingerprint.hpp>
#include <libtorrent/session_settings.hpp>
#include <libtorrent/identify_client.hpp>
#include <libtorrent/alert_types.hpp>
#include <libtorrent/ip_filter.hpp>
#ifndef NO_PEX
#include <libtorrent/extensions/metadata_transfer.hpp>
#include <libtorrent/extensions/ut_pex.hpp>
#endif
#ifdef NO_PEX
#include <QHash>
#endif
#include <QList>
#include <QPair>
#include <QStringList>
#include <QDateTime>
#include <boost/format.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/filesystem/exception.hpp>
#include "deleteThread.h"
#include <libtorrent/session.hpp>
#include <libtorrent/ip_filter.hpp>
#include "qtorrenthandle.h"
using namespace libtorrent;
namespace fs = boost::filesystem;
class downloadThread;
class deleteThread;
class QTimer;
class FilterParserThread;
class bittorrent : public QObject{
Q_OBJECT
private:
session *s;
bool DHTEnabled;
QString scan_dir;
QTimer *timerScan;
QTimer *timerAlerts;
QTimer *fastResumeSaver;
QTimer *BigRatioTimer;
bool DHTEnabled;
downloadThread *downloader;
QStringList supported_preview_extensions;
QString defaultSavePath;
#ifdef NO_PEX
QHash<QString, torrent_handle> torrent_list;
#endif
QStringList torrentsToPauseAfterChecking;
QHash<QString, QDateTime> TorrentsStartTime;
QHash<QString, size_type> TorrentsStartData;
QHash<QString, QPair<size_type,size_type> > ratioData;
QHash<QString, QHash<QString, QString> > trackersErrors;
deleteThread *deleter;
QStringList finishedTorrents;
QStringList unfinishedTorrents;
bool preAllocateAll;
bool addInPause;
int maxConnecsPerTorrent;
int maxUploadsPerTorrent;
float max_ratio;
bool UPnPEnabled;
bool NATPMPEnabled;
bool LSDEnabled;
FilterParserThread *filterParser;
QString filterPath;
int folderScanInterval; // in seconds
protected:
QString getSavePath(const QString& hash);
QString getSavePath(QString hash);
public:
// Constructor / Destructor
bittorrent();
~bittorrent();
torrent_handle getTorrentHandle(const QString& hash) const;
#ifndef NO_PEX
std::vector<torrent_handle> getTorrentHandles() const;
#endif
#ifdef NO_PEX
QList<torrent_handle> getTorrentHandles() const;
#endif
bool isPaused(const QString& hash) const;
bool hasFilteredFiles(const QString& fileHash) const;
bool isFilePreviewPossible(const QString& fileHash) const;
QTorrentHandle getTorrentHandle(QString hash) const;
bool isPaused(QString hash) const;
bool isFilePreviewPossible(QString fileHash) const;
bool isDHTEnabled() const;
float getPayloadDownloadRate() const;
float getPayloadUploadRate() const;
QList<torrent_handle> getFinishedTorrentHandles() const;
session_status getSessionStatus() const;
int getListenPort() const;
QStringList getTorrentsToPauseAfterChecking() const;
qlonglong getETA(QString hash) const;
float getRealRatio(QString hash) const;
session* getSession() const;
QHash<QString, QString> getTrackersErrors(QString hash) const;
QStringList getFinishedTorrents() const;
QStringList getUnfinishedTorrents() const;
bool isFinished(QString hash) const;
bool has_filtered_files(QString hash) const;
unsigned int getFinishedPausedTorrentsNb() const;
unsigned int getUnfinishedPausedTorrentsNb() const;
public slots:
void addTorrent(const QString& path, bool fromScanDir = false, const QString& from_url = QString());
void downloadFromUrl(const QString& url);
void addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false);
void downloadFromUrl(QString url);
void downloadFromURLList(const QStringList& url_list);
void deleteTorrent(const QString& hash, bool permanent = false);
void pauseTorrent(const QString& hash);
void deleteTorrent(QString hash, bool permanent = false);
bool pauseTorrent(QString hash);
bool resumeTorrent(QString hash);
void pauseAllTorrents();
void resumeAllTorrents();
void resumeTorrent(const QString& hash);
void enableDHT();
void disableDHT();
void saveDHTEntry();
void saveFastResumeData();
void enableDirectoryScanning(const QString& scan_dir);
void preAllocateAllFiles(bool b);
void saveFastResumeAndRatioData();
void saveFastResumeAndRatioData(QString hash);
void enableDirectoryScanning(QString scan_dir);
void disableDirectoryScanning();
#ifndef NO_PEX
void enablePeerExchange();
#endif
void enableIPFilter(ip_filter filter);
void enableIPFilter(QString filter);
void disableIPFilter();
void reloadTorrent(const torrent_handle &h, bool compact_mode = true);
void resumeUnfinishedTorrents();
void saveTorrentSpeedLimits(QString hash);
void loadTorrentSpeedLimits(QString hash);
void saveDownloadUploadForTorrent(QString hash);
void loadDownloadUploadForTorrent(QString hash);
void handleDownloadFailure(QString url, QString reason);
void loadWebSeeds(QString fileHash);
// Session configuration - Setters
void setListeningPortsRange(std::pair<unsigned short, unsigned short> ports);
void setMaxConnections(int maxConnec);
void setDownloadRateLimit(int rate);
void setUploadRateLimit(int rate);
void setMaxConnectionsPerTorrent(int max);
void setMaxUploadsPerTorrent(int max);
void setDownloadRateLimit(long rate);
void setUploadRateLimit(long rate);
void setGlobalRatio(float ratio);
void setDeleteRatio(float ratio);
void setDHTPort(int dht_port);
void setProxySettings(proxy_settings proxySettings, bool trackers=true, bool peers=true, bool web_seeds=true, bool dht=true);
void setSessionSettings(session_settings sessionSettings);
void setDefaultSavePath(const QString& savepath);
void startTorrentsInPause(bool b);
void setDefaultSavePath(QString savepath);
void applyEncryptionSettings(pe_settings se);
void loadFilesPriorities(QTorrentHandle& h);
void setDownloadLimit(QString hash, long val);
void setUploadLimit(QString hash, long val);
void setUnfinishedTorrent(QString hash);
void setFinishedTorrent(QString hash);
void enableUPnP(bool b);
void enableNATPMP(bool b);
void enableLSD(bool b);
bool enableDHT(bool b);
void reloadTorrent(const QTorrentHandle &h, bool full_alloc);
void setTimerScanInterval(int secs);
protected slots:
void cleanDeleter(deleteThread* deleter);
void loadFilteredFiles(torrent_handle& h);
void scanDirectory();
void readAlerts();
void processDownloadedFile(const QString&, const QString&, int, const QString&);
void resumeUnfinished();
void processDownloadedFile(QString, QString);
bool loadTrackerFile(QString hash);
void saveTrackerFile(QString hash);
void deleteBigRatios();
signals:
void invalidTorrent(const QString& path);
void duplicateTorrent(const QString& path);
void addedTorrent(const QString& path, torrent_handle& h, bool fastResume);
void finishedTorrent(torrent_handle& h);
void fullDiskError(torrent_handle& h);
void trackerError(const QString& hash, const QString& time, const QString& msg);
void invalidTorrent(QString path);
void duplicateTorrent(QString path);
void addedTorrent(QString path, QTorrentHandle& h, bool fastResume);
void deletedTorrent(QString hash);
void pausedTorrent(QString hash);
void resumedTorrent(QString hash);
void finishedTorrent(QTorrentHandle& h);
void fullDiskError(QTorrentHandle& h);
void trackerError(QString hash, QString time, QString msg);
void portListeningFailure();
void trackerAuthenticationRequired(torrent_handle& h);
void downloadFromUrlFailure(const QString& url, const QString& error);
void trackerAuthenticationRequired(QTorrentHandle& h);
void scanDirFoundTorrents(const QStringList& pathList);
void newDownloadedTorrent(const QString& path, const QString& url);
void aboutToDownloadFromUrl(const QString& url);
void newDownloadedTorrent(QString path, QString url);
void aboutToDownloadFromUrl(QString url);
void updateFileSize(QString hash);
void peerBlocked(QString);
void downloadFromUrlFailure(QString url, QString reason);
void fastResumeDataRejected(QString name);
void urlSeedProblem(QString url, QString msg);
void torrentFinishedChecking(QString hash);
void torrent_ratio_deleted(QString fileName);
void UPnPError(QString msg);
void UPnPSuccess(QString msg);
};
#endif

19
src/convertPOtoTS.py Normal file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/python
import os
LANG_FOLDER = "lang/"
PO_FOLDER = 'po_files'
if __name__ == '__main__':
po_files = os.listdir(os.path.join(LANG_FOLDER, PO_FOLDER))
po_files = [x for x in po_files if os.path.splitext(x)[-1] == ".po"]
for file in po_files:
# First clean up the ts file
ts_file = os.path.join(LANG_FOLDER, os.path.splitext(file)[0]+'.ts')
po_file = os.path.join(LANG_FOLDER, PO_FOLDER, file)
if os.path.exists(ts_file):
os.remove(ts_file)
# Convert to PO
print "Converting %s..." % (po_file,)
os.system("po2ts %s -o %s" % (po_file, ts_file))

24
src/convertTStoPO.py Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/python
import os
LANG_FOLDER = 'lang/'
PO_FOLDER = 'po_files'
if __name__ == '__main__':
ts_files = os.listdir(LANG_FOLDER)
ts_files = [x for x in ts_files if os.path.splitext(x)[-1] == ".ts"]
for file in ts_files:
# First clean up the po file
po_file = os.path.join(LANG_FOLDER, PO_FOLDER, os.path.splitext(file)[0]+'.po')
ts_file = os.path.join(LANG_FOLDER, file)
if os.path.exists(po_file):
os.remove(po_file)
# create po folder if it doesn't exist
if not os.path.exists(os.path.join(LANG_FOLDER, PO_FOLDER)):
os.mkdir(os.path.join(LANG_FOLDER, PO_FOLDER))
# Convert to PO
print "Converting %s..." % (ts_file,)
os.system("ts2po %s -o %s" % (ts_file, po_file))
# Making an archive
os.system("tar czf %s %s" % (os.path.join(LANG_FOLDER, PO_FOLDER)+'.tar.gz', os.path.join(LANG_FOLDER, PO_FOLDER)))

View File

@@ -1,27 +1,18 @@
<ui version="4.0" >
<author></author>
<comment></comment>
<exportmacro></exportmacro>
<class>createTorrentDialog</class>
<widget class="QDialog" name="createTorrentDialog" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>560</width>
<height>307</height>
<width>592</width>
<height>655</height>
</rect>
</property>
<property name="windowTitle" >
<string>Torrent Creation Tool</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>9</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="createTorrent_title" >
<property name="minimumSize" >
@@ -48,63 +39,59 @@
</font>
</property>
<property name="text" >
<string>Create Torrent file</string>
<string>Torrent file creation</string>
</property>
<property name="alignment" >
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbl_input" >
<property name="text" >
<string>File or folder to add to the torrent:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="textInputPath" />
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
<item>
<widget class="QPushButton" name="addFile_button" >
<property name="text" >
<string>Add a file</string>
</property>
<property name="spacing" >
<number>6</number>
<property name="icon" >
<iconset resource="icons.qrc" >:/Icons/add_file.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="addFolder_button" >
<property name="text" >
<string>Add a folder</string>
</property>
<property name="icon" >
<iconset resource="icons.qrc" >:/Icons/add_folder.png</iconset>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QLabel" name="lbl_destination" >
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>26</height>
</size>
</property>
<property name="text" >
<string>&lt;center>Destination torrent file:&lt;/center></string>
</property>
<property name="buddy" >
<cstring>txt_destination</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbl_input" >
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>26</height>
</size>
</property>
<property name="text" >
<string>&lt;center>Input file or directory:&lt;/center></string>
</property>
<property name="buddy" >
<cstring>txt_input</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbl_announce_url" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>102</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>16777215</width>
@@ -112,7 +99,7 @@
</size>
</property>
<property name="text" >
<string>&lt;center>Announce url:&lt;br>(One per line)&lt;/center></string>
<string>Announce urls (trackers):</string>
</property>
<property name="buddy" >
<cstring></cstring>
@@ -120,9 +107,34 @@
</widget>
</item>
<item>
<widget class="QLabel" name="lbl_comment" >
<widget class="QLabel" name="urlSeeds_lbl" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>101</height>
</size>
</property>
<property name="text" >
<string>&lt;center>Comment:&lt;/center></string>
<string>Web seeds urls (optional):</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lbl_comment" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>102</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>102</height>
</size>
</property>
<property name="text" >
<string>Comment (optional):</string>
</property>
<property name="buddy" >
<cstring>txt_comment</cstring>
@@ -133,64 +145,244 @@
</item>
<item>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="txt_destination" />
</item>
<item>
<widget class="QToolButton" name="browse_destination" >
<property name="text" >
<string>...</string>
<widget class="QListWidget" name="trackers_list" >
<property name="selectionMode" >
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="addTracker_button" >
<property name="minimumSize" >
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text" >
<string/>
</property>
<property name="icon" >
<iconset resource="icons.qrc" >:/Icons/skin/add.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeTracker_button" >
<property name="minimumSize" >
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text" >
<string/>
</property>
<property name="icon" >
<iconset resource="icons.qrc" >:/Icons/skin/remove.png</iconset>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="txt_input" />
</item>
<item>
<widget class="QCheckBox" name="checkDirectory" >
<property name="text" >
<string>Directory</string>
<widget class="QListWidget" name="URLSeeds_list" >
<property name="selectionMode" >
<enum>QAbstractItemView::MultiSelection</enum>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="browse_input" >
<layout class="QVBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="addURLSeed_button" >
<property name="minimumSize" >
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text" >
<string>...</string>
<string/>
</property>
<property name="icon" >
<iconset resource="icons.qrc" >:/Icons/skin/add.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="removeURLSeed_button" >
<property name="minimumSize" >
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="maximumSize" >
<size>
<width>22</width>
<height>22</height>
</size>
</property>
<property name="text" >
<string/>
</property>
<property name="icon" >
<iconset resource="icons.qrc" >:/Icons/skin/remove.png</iconset>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>16</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QTextEdit" name="txt_announce" />
</layout>
</item>
<item>
<widget class="QTextEdit" name="txt_comment" >
<property name="maximumSize" >
<size>
<width>421</width>
<height>102</height>
</size>
</property>
<property name="acceptRichText" >
<bool>false</bool>
</property>
@@ -202,12 +394,120 @@
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<item>
<widget class="QLabel" name="txtPieceSize" >
<property name="text" >
<string>Piece size:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboPieceSize" >
<property name="currentIndex" >
<number>3</number>
</property>
<item>
<property name="text" >
<string>32 KiB</string>
</property>
</item>
<item>
<property name="text" >
<string>64 KiB</string>
</property>
</item>
<item>
<property name="text" >
<string>128 KiB</string>
</property>
</item>
<item>
<property name="text" >
<string>256 KiB</string>
</property>
</item>
<item>
<property name="text" >
<string>512 KiB</string>
</property>
</item>
<item>
<property name="text" >
<string>1 MiB</string>
</property>
</item>
<item>
<property name="text" >
<string>2 MiB</string>
</property>
</item>
<item>
<property name="text" >
<string>4 MiB</string>
</property>
</item>
</widget>
</item>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="check_private" >
<property name="text" >
<string>Private (won't be distributed on DHT network if enabled)</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkStartSeeding" >
<property name="text" >
<string>Start seeding after creation</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="progressLbl" >
<property name="text" >
<string>Progress:</string>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar" >
<property name="value" >
<number>0</number>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<item>
<spacer>
<property name="orientation" >
@@ -224,7 +524,7 @@
<item>
<widget class="QPushButton" name="createButton" >
<property name="text" >
<string>Create</string>
<string>Create and save...</string>
</property>
</widget>
</item>
@@ -252,8 +552,9 @@
</item>
</layout>
</widget>
<pixmapfunction></pixmapfunction>
<resources/>
<resources>
<include location="icons.qrc" />
</resources>
<connections>
<connection>
<sender>cancelButton</sender>

View File

@@ -21,6 +21,7 @@
#include <QFileDialog>
#include <QMessageBox>
#include <QInputDialog>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
@@ -32,12 +33,10 @@
#include <libtorrent/file.hpp>
#include <libtorrent/storage.hpp>
#include <libtorrent/hasher.hpp>
#ifndef NO_PEX
#include <libtorrent/file_pool.hpp>
#endif
#include "createtorrent_imp.h"
#include "misc.h"
using namespace libtorrent;
using namespace boost::filesystem;
@@ -45,101 +44,225 @@ using namespace boost::filesystem;
createtorrent::createtorrent(QWidget *parent): QDialog(parent){
setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
creatorThread = new torrentCreatorThread();
connect(creatorThread, SIGNAL(creationSuccess(QString)), this, SLOT(handleCreationSucess(QString)));
connect(creatorThread, SIGNAL(creationFailure(QString)), this, SLOT(handleCreationFailure(QString)));
connect(creatorThread, SIGNAL(updateProgress(int)), this, SLOT(updateProgressBar(int)));
show();
}
void createtorrent::on_browse_destination_clicked(){
QString destination = QFileDialog::getSaveFileName(this, tr("Select destination torrent file"), QDir::homePath(), tr("Torrent Files")+" (*.torrent)");
if(!destination.isEmpty()){
txt_destination->setText(destination);
createtorrent::~createtorrent() {
delete creatorThread;
}
void createtorrent::on_addFolder_button_clicked(){
QString dir = QFileDialog::getExistingDirectory(this, tr("Select a folder to add to the torrent"), QDir::homePath(), QFileDialog::ShowDirsOnly);
if(!dir.isEmpty())
textInputPath->setText(dir);
}
void createtorrent::on_addFile_button_clicked(){
QString file = QFileDialog::getOpenFileName(this, tr("Select a file to add to the torrent"), QDir::homePath(), QString(), 0, QFileDialog::ShowDirsOnly);
if(!file.isEmpty())
textInputPath->setText(file);
}
void createtorrent::on_removeTracker_button_clicked() {
QModelIndexList selectedIndexes = trackers_list->selectionModel()->selectedIndexes();
for(int i=selectedIndexes.size()-1; i>=0; --i){
QListWidgetItem *item = trackers_list->takeItem(selectedIndexes.at(i).row());
delete item;
}
}
void createtorrent::on_browse_input_clicked(){
// Can't use QFileDialog static functions for this because
// user can select a file or a directory
QFileDialog *fd = new QFileDialog(this, tr("Select input directory or file"), QDir::homePath());
if(checkDirectory->isChecked()){
fd->setFileMode(QFileDialog::DirectoryOnly);
}else{
fd->setFileMode(QFileDialog::ExistingFile);
int createtorrent::getPieceSize() const {
switch(comboPieceSize->currentIndex()) {
case 0:
return 32*1024;
case 1:
return 64*1024;
case 2:
return 128*1024;
case 3:
return 256*1024;
case 4:
return 512*1024;
case 5:
return 1024*1024;
case 6:
return 2048*1024;
default:
return 256*1024;
}
QStringList fileNames;
if (fd->exec()){
fileNames = fd->selectedFiles();
txt_input->setText(fileNames.first());
}
void createtorrent::on_addTracker_button_clicked() {
bool ok;
QString URL = QInputDialog::getText(this, tr("Please type an announce URL"),
tr("Announce URL:", "Tracker URL"), QLineEdit::Normal,
"http://", &ok);
if(ok){
if(trackers_list->findItems(URL, Qt::MatchFixedString).size() == 0)
trackers_list->addItem(URL);
}
}
void createtorrent::on_removeURLSeed_button_clicked(){
QModelIndexList selectedIndexes = URLSeeds_list->selectionModel()->selectedIndexes();
for(int i=selectedIndexes.size()-1; i>=0; --i){
QListWidgetItem *item = URLSeeds_list->takeItem(selectedIndexes.at(i).row());
delete item;
}
}
void createtorrent::on_addURLSeed_button_clicked(){
bool ok;
QString URL = QInputDialog::getText(this, tr("Please type a web seed url"),
tr("Web seed URL:"), QLineEdit::Normal,
"http://", &ok);
if(ok){
if(URLSeeds_list->findItems(URL, Qt::MatchFixedString).size() == 0)
URLSeeds_list->addItem(URL);
}
}
// Subfunction to add files to a torrent_info structure
// Written by Arvid Norberg (libtorrent Author)
void add_files(torrent_info& t, path const& p, path const& l){
qDebug("p: %s, l: %s, l.leaf(): %s", p.string().c_str(), l.string().c_str(), l.leaf().c_str());
path f(p / l);
if (is_directory(f)){
for (directory_iterator i(f), end; i != end; ++i)
add_files(t, p, l / i->leaf());
}else{
qDebug("Adding %s", l.string().c_str());
t.add_file(l, file_size(f));
}
}
QStringList createtorrent::allItems(QListWidget *list){
QStringList res;
unsigned int nbItems = list->count();
for(unsigned int i=0; i< nbItems; ++i){
res << list->item(i)->text();
}
return res;
}
// Main function that create a .torrent file
void createtorrent::on_createButton_clicked(){
QString destination = txt_destination->text();
if(destination.isEmpty()){
QMessageBox::critical(0, tr("No destination path set"), tr("Please type a destination path first"));
return;
}
QString input = txt_input->text();
QString input = textInputPath->text().trimmed();
if (input.endsWith(QDir::separator()))
input.chop(1);
if(input.isEmpty()){
QMessageBox::critical(0, tr("No input path set"), tr("Please type an input path first"));
return;
}
if(!QFile::exists(input)){
QMessageBox::critical(0, tr("Input path does not exist"), tr("Please type a valid input path first"));
QStringList trackers = allItems(trackers_list);
if(!trackers.size()){
QMessageBox::critical(0, tr("No tracker path set"), tr("Please set at least one tracker"));
return;
}
char const* creator_str = "qBittorrent";
int piece_size = 256 * 1024;
try {
torrent_info t;
path full_path = complete(path((const char*)input.toUtf8()));
ofstream out(complete(path((const char*)destination.toUtf8())), std::ios_base::binary);
add_files(t, full_path.branch_path(), full_path.leaf());
t.set_piece_size(piece_size);
#ifndef NO_PEX
file_pool fp;
storage st(t, full_path.branch_path(), fp);
#endif
#ifdef NO_PEX
storage st(t, full_path.branch_path());
#endif
QStringList trackers = txt_announce->toPlainText().split('\n');
for(int i=0; i<trackers.size(); ++i){
t.add_tracker((const char*)trackers.at(i).toUtf8());
QString destination = QFileDialog::getSaveFileName(this, tr("Select destination torrent file"), QDir::homePath(), tr("Torrent Files")+QString::fromUtf8(" (*.torrent)"));
if(!destination.isEmpty()) {
if(!destination.endsWith(QString::fromUtf8(".torrent")))
destination += QString::fromUtf8(".torrent");
} else {
return;
}
QStringList url_seeds = allItems(URLSeeds_list);
QString comment = txt_comment->toPlainText();
creatorThread->create(input, destination, trackers, url_seeds, comment, check_private->isChecked(), getPieceSize());
}
void createtorrent::handleCreationFailure(QString msg) {
QMessageBox::information(0, tr("Torrent creation"), tr("Torrent creation was unsuccessful, reason: %1").arg(msg));
hide();
}
void createtorrent::handleCreationSuccess(QString path, const char* branch_path, QString hash) {
if(checkStartSeeding->isChecked()) {
// Create save path file
QFile savepath_file(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".savepath"));
savepath_file.open(QIODevice::WriteOnly | QIODevice::Text);
savepath_file.write(branch_path);
savepath_file.close();
emit torrent_to_seed(path);
}
QMessageBox::information(0, tr("Torrent creation"), tr("Torrent was created successfully:")+" "+path);
hide();
}
void createtorrent::updateProgressBar(int progress) {
progressBar->setValue(progress);
}
//
// Torrent Creator Thread
//
void torrentCreatorThread::create(QString _input_path, QString _save_path, QStringList _trackers, QStringList _url_seeds, QString _comment, bool _is_private, int _piece_size) {
input_path = _input_path;
save_path = _save_path;
trackers = _trackers;
url_seeds = _url_seeds;
comment = _comment;
is_private = _is_private;
piece_size = _piece_size;
abort = false;
start();
}
void torrentCreatorThread::run() {
emit updateProgress(0);
char const* creator_str = "qBittorrent "VERSION;
try {
boost::intrusive_ptr<torrent_info> t(new torrent_info);
ofstream out(complete(path((const char*)save_path.toUtf8())), std::ios_base::binary);
// Adding files to the torrent
path full_path = complete(path(input_path.toUtf8().data()));
add_files(*t, full_path.branch_path(), full_path.leaf());
if(abort) return;
// Set piece size
t->set_piece_size(piece_size);
// Add url seeds
QString seed;
foreach(seed, url_seeds){
t->add_url_seed(seed.toUtf8().data());
}
for(int i=0; i<trackers.size(); ++i){
t->add_tracker(trackers.at(i).toUtf8().data());
}
if(abort) return;
// calculate the hash for all pieces
int num = t.num_pieces();
file_pool fp;
boost::scoped_ptr<storage_interface> st(default_storage_constructor(t, full_path.branch_path(), fp));
int num = t->num_pieces();
std::vector<char> buf(piece_size);
for (int i = 0; i < num; ++i)
{
st.read(&buf[0], i, 0, t.piece_size(i));
hasher h(&buf[0], t.piece_size(i));
t.set_hash(i, h.final());
for (int i = 0; i < num; ++i) {
st->read(&buf[0], i, 0, t->piece_size(i));
hasher h(&buf[0], t->piece_size(i));
t->set_hash(i, h.final());
emit updateProgress((int)(i*100./(float)num));
if(abort) return;
}
// Set qBittorrent as creator and add user comment to
// torrent_info structure
t.set_creator(creator_str);
t.set_comment((const char*)txt_comment->toPlainText().toUtf8());
t->set_creator(creator_str);
t->set_comment((const char*)comment.toUtf8());
// Is private ?
if(is_private){
t->set_priv(true);
}
if(abort) return;
// create the torrent and print it to out
entry e = t.create_torrent();
entry e = t->create_torrent();
libtorrent::bencode(std::ostream_iterator<char>(out), e);
out.flush();
emit updateProgress(100);
emit creationSuccess(save_path, full_path.branch_path().string().c_str(), misc::toQString(t->info_hash()));
}
catch (std::exception& e){
std::cerr << e.what() << "\n";
emit creationFailure(QString::fromUtf8(e.what()));
}
hide();
QMessageBox::information(0, tr("Torrent creation"), tr("Torrent was created successfully:")+" "+destination);
}

View File

@@ -22,19 +22,65 @@
#ifndef CREATE_TORRENT_IMP_H
#define CREATE_TORRENT_IMP_H
#include <QDialog>
#include <QThread>
#include "ui_createtorrent.h"
class torrentCreatorThread : public QThread {
Q_OBJECT
QString input_path;
QString save_path;
QStringList trackers;
QStringList url_seeds;
QString comment;
bool is_private;
int piece_size;
bool abort;
public:
torrentCreatorThread() {}
~torrentCreatorThread() {
abort = true;
wait();
}
void create(QString _input_path, QString _save_path, QStringList _trackers, QStringList _url_seeds, QString _comment, bool _is_private, int _piece_size);
protected:
void run();
signals:
void creationFailure(QString msg);
void creationSuccess(QString path, const char* branch_path, QString hash);
void updateProgress(int progress);
};
class createtorrent : public QDialog, private Ui::createTorrentDialog{
Q_OBJECT
private:
torrentCreatorThread *creatorThread;
public:
createtorrent(QWidget *parent = 0);
~createtorrent();
QStringList allItems(QListWidget *list);
int getPieceSize() const;
signals:
void torrent_to_seed(QString path);
protected slots:
void on_browse_destination_clicked();
void on_browse_input_clicked();
void on_createButton_clicked();
void on_addFile_button_clicked();
void on_addFolder_button_clicked();
void on_addTracker_button_clicked();
void on_removeTracker_button_clicked();
void on_addURLSeed_button_clicked();
void on_removeURLSeed_button_clicked();
void handleCreationFailure(QString msg);
void handleCreationSuccess(QString path, const char* branch_path, QString hash);
void updateProgressBar(int progress);
};
#endif

View File

@@ -23,31 +23,102 @@
#define DELETETHREAD_H
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
#include <QMutexLocker>
#include <QPair>
#include "misc.h"
#include "arborescence.h"
class subDeleteThread : public QThread {
Q_OBJECT
private:
QString save_path;
arborescence *arb;
bool abort;
public:
subDeleteThread(QObject *parent, QString saveDir, arborescence *arb) : QThread(parent), save_path(saveDir), arb(arb), abort(false){}
~subDeleteThread(){
abort = true;
wait();
}
signals:
// For subthreads
void deletionSuccessST(subDeleteThread* st);
void deletionFailureST(subDeleteThread* st);
protected:
void run(){
if(arb->removeFromFS(save_path))
emit deletionSuccessST(this);
else
emit deletionFailureST(this);
delete arb;
}
};
class deleteThread : public QThread {
Q_OBJECT
private:
QString path;
QList<QPair<QString, arborescence*> > torrents_list;
QMutex mutex;
QWaitCondition condition;
bool abort;
QList<subDeleteThread*> subThreads;
public:
deleteThread(QString _path): path(_path){
start();
}
deleteThread(QObject* parent) : QThread(parent), abort(false){}
~deleteThread(){
mutex.lock();
abort = true;
condition.wakeOne();
mutex.unlock();
qDeleteAll(subThreads);
wait();
}
signals:
void deletionFinished(deleteThread*) const;
void deleteTorrent(QString saveDir, arborescence *arb){
qDebug("deleteThread called");
QMutexLocker locker(&mutex);
torrents_list << QPair<QString, arborescence*>(saveDir, arb);
if(!isRunning()){
start();
}else{
condition.wakeOne();
}
}
private:
protected:
void run(){
misc::removePath(path);
emit deletionFinished(this);
forever{
if(abort)
return;
mutex.lock();
if(torrents_list.size() != 0){
QPair<QString, arborescence *> torrent = torrents_list.takeFirst();
mutex.unlock();
subDeleteThread *st = new subDeleteThread(0, torrent.first, torrent.second);
subThreads << st;
connect(st, SIGNAL(deletionSuccessST(subDeleteThread*)), this, SLOT(deleteSubThread(subDeleteThread*)));
connect(st, SIGNAL(deletionFailureST(subDeleteThread*)), this, SLOT(deleteSubThread(subDeleteThread*)));
st->start();
}else{
condition.wait(&mutex);
mutex.unlock();
}
}
}
protected slots:
void deleteSubThread(subDeleteThread* st){
int index = subThreads.indexOf(st);
Q_ASSERT(index != -1);
subThreads.removeAt(index);
delete st;
}
};

249
src/download.ui Normal file
View File

@@ -0,0 +1,249 @@
<ui version="4.0" >
<class>downloading</class>
<widget class="QWidget" name="downloading" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>811</width>
<height>453</height>
</rect>
</property>
<property name="windowTitle" >
<string>Search</string>
</property>
<layout class="QVBoxLayout" >
<item>
<layout class="QVBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="margin" >
<number>0</number>
</property>
<item>
<widget class="QTreeView" name="downloadList" >
<property name="minimumSize" >
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="contextMenuPolicy" >
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="autoScroll" >
<bool>true</bool>
</property>
<property name="selectionMode" >
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="indentation" >
<number>1</number>
</property>
<property name="itemsExpandable" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTabWidget" name="tabBottom" >
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>142</height>
</size>
</property>
<property name="tabPosition" >
<enum>QTabWidget::West</enum>
</property>
<property name="currentIndex" >
<number>0</number>
</property>
<widget class="QWidget" name="log_tab" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>765</width>
<height>138</height>
</rect>
</property>
<attribute name="title" >
<string>Log</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="margin" >
<number>9</number>
</property>
<item>
<widget class="QTextBrowser" name="infoBar" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>120</height>
</size>
</property>
<property name="contextMenuPolicy" >
<enum>Qt::CustomContextMenu</enum>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="filter_tab" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>765</width>
<height>138</height>
</rect>
</property>
<attribute name="title" >
<string>IP filter</string>
</attribute>
<layout class="QVBoxLayout" >
<property name="spacing" >
<number>6</number>
</property>
<property name="margin" >
<number>9</number>
</property>
<item>
<widget class="QTextBrowser" name="textBlockedUsers" >
<property name="maximumSize" >
<size>
<width>16777215</width>
<height>123</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
<action name="actionStart" >
<property name="text" >
<string>Start</string>
</property>
</action>
<action name="actionPause" >
<property name="text" >
<string>Pause</string>
</property>
</action>
<action name="actionDelete" >
<property name="text" >
<string>Delete</string>
</property>
</action>
<action name="actionClearLog" >
<property name="text" >
<string>Clear</string>
</property>
</action>
<action name="actionPreview_file" >
<property name="text" >
<string>Preview file</string>
</property>
</action>
<action name="actionSet_upload_limit" >
<property name="text" >
<string>Set upload limit</string>
</property>
</action>
<action name="actionSet_download_limit" >
<property name="text" >
<string>Set download limit</string>
</property>
</action>
<action name="actionDelete_Permanently" >
<property name="text" >
<string>Delete Permanently</string>
</property>
</action>
<action name="actionTorrent_Properties" >
<property name="text" >
<string>Torrent Properties</string>
</property>
</action>
<action name="actionOpen_destination_folder" >
<property name="icon" >
<iconset resource="icons.qrc" >
<normaloff>:/Icons/folder.png</normaloff>:/Icons/folder.png</iconset>
</property>
<property name="text" >
<string>Open destination folder</string>
</property>
</action>
<action name="actionHOSColName" >
<property name="text" >
<string>Name</string>
</property>
</action>
<action name="actionHOSColSize" >
<property name="text" >
<string>Size</string>
</property>
</action>
<action name="actionHOSColProgress" >
<property name="text" >
<string>Progress</string>
</property>
</action>
<action name="actionHOSColDownSpeed" >
<property name="text" >
<string>DLSpeed</string>
</property>
</action>
<action name="actionHOSColUpSpeed" >
<property name="text" >
<string>UpSpeed</string>
</property>
</action>
<action name="actionHOSColSeedersLeechers" >
<property name="text" >
<string>Seeds/Leechs</string>
</property>
</action>
<action name="actionHOSColRatio" >
<property name="text" >
<string>Ratio</string>
</property>
</action>
<action name="actionHOSColEta" >
<property name="text" >
<string>ETA</string>
</property>
</action>
<action name="actionBuy_it" >
<property name="icon" >
<iconset resource="icons.qrc" >
<normaloff>:/Icons/money.png</normaloff>:/Icons/money.png</iconset>
</property>
<property name="text" >
<string>Buy it</string>
</property>
</action>
<zorder>tabBottom</zorder>
<zorder></zorder>
</widget>
<resources>
<include location="icons.qrc" />
</resources>
<connections/>
</ui>

View File

@@ -37,7 +37,6 @@ class downloadFromURL : public QDialog, private Ui::downloadFromURL{
setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
icon_lbl->setPixmap(QPixmap(QString::fromUtf8(":/Icons/skin/url.png")));
connect(this, SIGNAL(urlsReadyToBeDownloaded(const QStringList&)), parent, SLOT(downloadFromURLList(const QStringList&)));
show();
}
@@ -49,7 +48,7 @@ class downloadFromURL : public QDialog, private Ui::downloadFromURL{
public slots:
void on_downloadButton_clicked(){
QString urls = textUrls->toPlainText();
QStringList url_list = urls.split("\n");
QStringList url_list = urls.split(QString::fromUtf8("\n"));
QString url;
QStringList url_list_cleaned;
foreach(url, url_list){
@@ -65,6 +64,7 @@ class downloadFromURL : public QDialog, private Ui::downloadFromURL{
return;
}
emit urlsReadyToBeDownloaded(url_list_cleaned);
qDebug("Emitted urlsReadytobedownloaded signal");
close();
}

207
src/downloadThread.cpp Normal file
View File

@@ -0,0 +1,207 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contact : chris@qbittorrent.org
*/
#include "downloadThread.h"
#include <iostream>
#include <QSettings>
#include <stdio.h>
// http://curl.rtin.bz/libcurl/c/libcurl-errors.html
QString subDownloadThread::errorCodeToString(CURLcode status) {
switch(status){
case CURLE_FTP_CANT_GET_HOST:
case CURLE_COULDNT_RESOLVE_HOST:
return tr("Host is unreachable");
case CURLE_READ_ERROR:
case CURLE_FILE_COULDNT_READ_FILE:
return tr("File was not found (404)");
case CURLE_FTP_ACCESS_DENIED:
case CURLE_LOGIN_DENIED:
case CURLE_FTP_USER_PASSWORD_INCORRECT:
return tr("Connection was denied");
case CURLE_URL_MALFORMAT:
return tr("Url is invalid");
case CURLE_COULDNT_RESOLVE_PROXY:
return tr("Could not resolve proxy");
//case 5:
// return tr("Connection forbidden (403)");
//case 6:
// return tr("Connection was not authorized (401)");
//case 7:
// return tr("Content has moved (301)");
case CURLE_COULDNT_CONNECT:
return tr("Connection failure");
case CURLE_OPERATION_TIMEOUTED:
return tr("Connection was timed out");
case CURLE_INTERFACE_FAILED:
return tr("Incorrect network interface");
default:
return tr("Unknown error");
}
}
subDownloadThread::subDownloadThread(QObject *parent, QString url) : QThread(parent), url(url), abort(false){}
subDownloadThread::~subDownloadThread(){
abort = true;
wait();
}
void subDownloadThread::run(){
// XXX: Trick to get a unique filename
QString filePath;
QTemporaryFile *tmpfile = new QTemporaryFile();
if (tmpfile->open()) {
filePath = tmpfile->fileName();
}
delete tmpfile;
FILE *f = fopen(filePath.toUtf8().data(), "wb");
if(!f) {
std::cerr << "couldn't open destination file" << "\n";
return;
}
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl) {
std::string c_url = url.toUtf8().data();
curl_easy_setopt(curl, CURLOPT_URL, c_url.c_str());
// SSL support
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
// PROXY SUPPORT
QSettings settings("qBittorrent", "qBittorrent");
int intValue = settings.value(QString::fromUtf8("Preferences/Connection/ProxyType"), 0).toInt();
if(intValue > 0) {
// Proxy enabled
QString IP = settings.value(QString::fromUtf8("Preferences/Connection/Proxy/IP"), "0.0.0.0").toString();
QString port = settings.value(QString::fromUtf8("Preferences/Connection/Proxy/Port"), 8080).toString();
qDebug("Using proxy: %s", (IP+QString(":")+port).toUtf8().data());
curl_easy_setopt(curl, CURLOPT_PROXYPORT, (IP+QString(":")+port).toUtf8().data());
// Default proxy type is HTTP, we must change if it is SOCKS5
if(intValue%2==0) {
qDebug("Proxy is SOCKS5, not HTTP");
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
}
// Authentication?
if(intValue > 2) {
qDebug("Proxy requires authentication, authenticating");
QString username = settings.value(QString::fromUtf8("Preferences/Connection/Proxy/Username"), QString()).toString();
QString password = settings.value(QString::fromUtf8("Preferences/Connection/Proxy/Password"), QString()).toString();
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, (username+QString(":")+password).toUtf8().data());
}
}
// We have to define CURLOPT_WRITEFUNCTION or it will crash on windows
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, f);
// Verbose
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
// No progress info (we don't use it)
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
// Redirections
curl_easy_setopt(curl, CURLOPT_AUTOREFERER, 1);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, -1);
qDebug("Downloading %s", url.toUtf8().data());
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
fclose(f);
if(res) {
emit downloadFailureST(this, url, errorCodeToString(res));
} else {
emit downloadFinishedST(this, url, filePath);
}
} else {
std::cerr << "Could not initialize CURL" << "\n";
}
}
/** Download Thread **/
downloadThread::downloadThread(QObject* parent) : QThread(parent), abort(false){}
downloadThread::~downloadThread(){
mutex.lock();
abort = true;
condition.wakeOne();
mutex.unlock();
qDeleteAll(subThreads);
wait();
}
void downloadThread::downloadUrl(QString url){
QMutexLocker locker(&mutex);
if(downloading_list.contains(url)) return;
url_list << url;
downloading_list << url;
if(!isRunning()){
start();
}else{
condition.wakeOne();
}
}
void downloadThread::run(){
forever{
if(abort)
return;
mutex.lock();
if(url_list.size() != 0){
QString url = url_list.takeFirst();
mutex.unlock();
subDownloadThread *st = new subDownloadThread(0, url);
subThreads << st;
connect(st, SIGNAL(downloadFinishedST(subDownloadThread*, QString, QString)), this, SLOT(propagateDownloadedFile(subDownloadThread*, QString, QString)));
connect(st, SIGNAL(downloadFailureST(subDownloadThread*, QString, QString)), this, SLOT(propagateDownloadFailure(subDownloadThread*, QString, QString)));
st->start();
}else{
condition.wait(&mutex);
mutex.unlock();
}
}
}
void downloadThread::propagateDownloadedFile(subDownloadThread* st, QString url, QString path){
int index = subThreads.indexOf(st);
Q_ASSERT(index != -1);
subThreads.removeAt(index);
delete st;
emit downloadFinished(url, path);
mutex.lock();
index = downloading_list.indexOf(url);
Q_ASSERT(index != -1);
downloading_list.removeAt(index);
mutex.unlock();
}
void downloadThread::propagateDownloadFailure(subDownloadThread* st, QString url, QString reason){
int index = subThreads.indexOf(st);
Q_ASSERT(index != -1);
subThreads.removeAt(index);
delete st;
emit downloadFailure(url, reason);
mutex.lock();
index = downloading_list.indexOf(url);
Q_ASSERT(index != -1);
downloading_list.removeAt(index);
mutex.unlock();
}

View File

@@ -28,144 +28,58 @@
#include <QMutex>
#include <QMutexLocker>
#include <QWaitCondition>
#include <QStringList>
#include <curl/curl.h>
#include <iostream>
#include "misc.h"
class subDownloadThread : public QThread {
Q_OBJECT
private:
QString url;
bool abort;
public:
subDownloadThread(QObject *parent, QString url);
~subDownloadThread();
QString errorCodeToString(CURLcode status);
signals:
// For subthreads
void downloadFinishedST(subDownloadThread* st, QString url, QString file_path);
void downloadFailureST(subDownloadThread* st, QString url, QString reason);
protected:
void run();
};
class downloadThread : public QThread {
Q_OBJECT
private:
QStringList url_list;
QStringList downloading_list;
QMutex mutex;
QWaitCondition condition;
bool abort;
QList<subDownloadThread*> subThreads;
signals:
void downloadFinished(const QString& url, const QString& file_path, int return_code, const QString& errorBuffer);
void downloadFinished(QString url, QString file_path);
void downloadFailure(QString url, QString reason);
public:
downloadThread(QObject* parent) : QThread(parent){
mutex.lock();
abort = false;
mutex.unlock();
}
downloadThread(QObject* parent);
~downloadThread(){
mutex.lock();
abort = true;
condition.wakeOne();
mutex.unlock();
wait();
}
~downloadThread();
void downloadUrl(const QString& url){
QMutexLocker locker(&mutex);
qDebug("In Download thread function, mutex locked");
url_list << url;
qDebug("In Download thread function, mutex unlocked (url added)");
if(!isRunning()){
qDebug("In Download thread function, Launching thread (was stopped)");
start();
}else{
condition.wakeOne();
}
}
void downloadUrl(QString url);
void setProxy(QString IP, int port, QString username, QString password);
protected:
void run(){
forever{
if(abort)
return;
mutex.lock();
qDebug("In Download thread RUN, mutex locked");
if(url_list.size() != 0){
QString url = url_list.takeFirst();
mutex.unlock();
qDebug("In Download thread RUN, mutex unlocked (got url)");
CURL *curl;
QString filePath;
int return_code, response;
// XXX: Trick to get a unique filename
QTemporaryFile *tmpfile = new QTemporaryFile;
if (tmpfile->open()) {
filePath = tmpfile->fileName();
}
delete tmpfile;
if(abort)
return;
FILE *file = fopen((const char*)filePath.toUtf8(), "w");
if(!file){
std::cerr << "Error: could not open temporary file...\n";
return;
}
// Initilization required by libcurl
curl = curl_easy_init();
if(!curl){
std::cerr << "Error: Failed to init curl...\n";
fclose(file);
return;
}
// Set url to download
curl_easy_setopt(curl, CURLOPT_URL, url.toLocal8Bit().constData());
qDebug("Url: %s", url.toLocal8Bit().constData());
// Define our callback to get called when there's data to be written
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, misc::my_fwrite);
// Set destination file
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
// Some SSL mambo jambo
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
// Disable progress meter
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
// Any kind of authentication
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
// Auto referrer
curl_easy_setopt(curl, CURLOPT_AUTOREFERER, 1);
// Follow redirections
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
// Enable cookies
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
// We want error message:
char errorBuffer[CURL_ERROR_SIZE];
errorBuffer[0]=0; /* prevent junk from being output */
return_code = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
if(return_code){
std::cerr << "Error: failed to set error buffer in curl\n";
fclose(file);
QFile::remove(filePath);
return;
}
unsigned short retries = 0;
bool to_many_users = false;
do{
// Perform Download
return_code = curl_easy_perform(curl);
// We want HTTP response code
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
qDebug("HTTP response code: %d", response);
if(response/100 == 5){
to_many_users = true;
++retries;
SleeperThread::msleep(1000);
}
}while(to_many_users && retries < 10);
// Cleanup
curl_easy_cleanup(curl);
// Close tmp file
fclose(file);
emit downloadFinished(url, filePath, return_code, QString(errorBuffer));
qDebug("In Download thread RUN, signal emitted, ErrorBuffer: %s", errorBuffer);
}else{
qDebug("In Download thread RUN, mutex still locked (no urls) -> sleeping");
condition.wait(&mutex);
mutex.unlock();
qDebug("In Download thread RUN, woke up, mutex unlocked");
}
}
}
void run();
protected slots:
void propagateDownloadedFile(subDownloadThread* st, QString url, QString path);
void propagateDownloadFailure(subDownloadThread* st, QString url, QString reason);
};
#endif

886
src/downloadingTorrents.cpp Normal file
View File

@@ -0,0 +1,886 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contact : chris@qbittorrent.org
*/
#include "downloadingTorrents.h"
#include "misc.h"
#include "properties_imp.h"
#include "bittorrent.h"
#include "allocationDlg.h"
#include "DLListDelegate.h"
#include "GUI.h"
#include <QFile>
#include <QSettings>
#include <QStandardItemModel>
#include <QHeaderView>
#include <QTime>
#include <QMenu>
DownloadingTorrents::DownloadingTorrents(QObject *parent, bittorrent *BTSession) : parent(parent), BTSession(BTSession), delayedSorting(false), nbTorrents(0) {
setupUi(this);
// Setting icons
actionStart->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/play.png")));
actionPause->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/pause.png")));
actionDelete->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete.png")));
actionClearLog->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete.png")));
actionPreview_file->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/preview.png")));
actionSet_upload_limit->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/seeding.png")));
actionSet_download_limit->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png")));
actionDelete_Permanently->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/delete_perm.png")));
actionTorrent_Properties->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/properties.png")));
// tabBottom->setTabIcon(0, QIcon(QString::fromUtf8(":/Icons/log.png")));
// tabBottom->setTabIcon(1, QIcon(QString::fromUtf8(":/Icons/filter.png")));
// Set Download list model
DLListModel = new QStandardItemModel(0,9);
DLListModel->setHeaderData(NAME, Qt::Horizontal, tr("Name", "i.e: file name"));
DLListModel->setHeaderData(SIZE, Qt::Horizontal, tr("Size", "i.e: file size"));
DLListModel->setHeaderData(PROGRESS, Qt::Horizontal, tr("Progress", "i.e: % downloaded"));
DLListModel->setHeaderData(DLSPEED, Qt::Horizontal, tr("DL Speed", "i.e: Download speed"));
DLListModel->setHeaderData(UPSPEED, Qt::Horizontal, tr("UP Speed", "i.e: Upload speed"));
DLListModel->setHeaderData(SEEDSLEECH, Qt::Horizontal, tr("Seeds/Leechs", "i.e: full/partial sources"));
DLListModel->setHeaderData(RATIO, Qt::Horizontal, tr("Ratio"));
DLListModel->setHeaderData(ETA, Qt::Horizontal, tr("ETA", "i.e: Estimated Time of Arrival / Time left"));
downloadList->setModel(DLListModel);
DLDelegate = new DLListDelegate(downloadList);
downloadList->setItemDelegate(DLDelegate);
// Hide hash column
downloadList->hideColumn(HASH);
loadHiddenColumns();
connect(BTSession, SIGNAL(addedTorrent(QString, QTorrentHandle&, bool)), this, SLOT(torrentAdded(QString, QTorrentHandle&, bool)));
connect(BTSession, SIGNAL(duplicateTorrent(QString)), this, SLOT(torrentDuplicate(QString)));
connect(BTSession, SIGNAL(invalidTorrent(QString)), this, SLOT(torrentCorrupted(QString)));
connect(BTSession, SIGNAL(portListeningFailure()), this, SLOT(portListeningFailure()));
connect(BTSession, SIGNAL(peerBlocked(QString)), this, SLOT(addLogPeerBlocked(const QString)));
connect(BTSession, SIGNAL(fastResumeDataRejected(QString)), this, SLOT(addFastResumeRejectedAlert(QString)));
connect(BTSession, SIGNAL(aboutToDownloadFromUrl(QString)), this, SLOT(displayDownloadingUrlInfos(QString)));
connect(BTSession, SIGNAL(urlSeedProblem(QString, QString)), this, SLOT(addUrlSeedError(QString, QString)));
connect(BTSession, SIGNAL(UPnPError(QString)), this, SLOT(displayUPnPError(QString)));
connect(BTSession, SIGNAL(UPnPSuccess(QString)), this, SLOT(displayUPnPSuccess(QString)));
// Load last columns width for download list
if(!loadColWidthDLList()) {
downloadList->header()->resizeSection(0, 200);
}
// Make download list header clickable for sorting
downloadList->header()->setClickable(true);
downloadList->header()->setSortIndicatorShown(true);
// Connecting Actions to slots
connect(downloadList, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(notifyTorrentDoubleClicked(const QModelIndex&)));
connect(downloadList->header(), SIGNAL(sectionPressed(int)), this, SLOT(sortDownloadList(int)));
connect(downloadList, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayDLListMenu(const QPoint&)));
downloadList->header()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(downloadList->header(), SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayDLHoSMenu(const QPoint&)));
connect(infoBar, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayInfoBarMenu(const QPoint&)));
// Actions
connect(actionPause, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionPause_triggered()));
connect(actionStart, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionStart_triggered()));
connect(actionDelete, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionDelete_triggered()));
connect(actionPreview_file, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionPreview_file_triggered()));
connect(actionDelete_Permanently, SIGNAL(triggered()), (GUI*)parent, SLOT(on_actionDelete_Permanently_triggered()));
connect(actionOpen_destination_folder, SIGNAL(triggered()), (GUI*)parent, SLOT(openDestinationFolder()));
connect(actionTorrent_Properties, SIGNAL(triggered()), this, SLOT(propertiesSelection()));
connect(actionBuy_it, SIGNAL(triggered()), (GUI*)parent, SLOT(goBuyPage()));
connect(actionHOSColName, SIGNAL(triggered()), this, SLOT(hideOrShowColumnName()));
connect(actionHOSColSize, SIGNAL(triggered()), this, SLOT(hideOrShowColumnSize()));
connect(actionHOSColProgress, SIGNAL(triggered()), this, SLOT(hideOrShowColumnProgress()));
connect(actionHOSColDownSpeed, SIGNAL(triggered()), this, SLOT(hideOrShowColumnDownSpeed()));
connect(actionHOSColUpSpeed, SIGNAL(triggered()), this, SLOT(hideOrShowColumnUpSpeed()));
connect(actionHOSColSeedersLeechers, SIGNAL(triggered()), this, SLOT(hideOrShowColumnSeedersLeechers()));
connect(actionHOSColRatio, SIGNAL(triggered()), this, SLOT(hideOrShowColumnRatio()));
connect(actionHOSColEta, SIGNAL(triggered()), this, SLOT(hideOrShowColumnEta()));
// Set info Bar infos
setInfoBar(tr("qBittorrent %1 started.", "e.g: qBittorrent v0.x started.").arg(QString::fromUtf8(""VERSION)));
qDebug("Download tab built");
}
DownloadingTorrents::~DownloadingTorrents() {
saveColWidthDLList();
saveHiddenColumns();
delete DLDelegate;
delete DLListModel;
}
void DownloadingTorrents::notifyTorrentDoubleClicked(const QModelIndex& index) {
unsigned int row = index.row();
QString hash = getHashFromRow(row);
emit torrentDoubleClicked(hash, false);
}
void DownloadingTorrents::addLogPeerBlocked(QString ip) {
static unsigned int nbLines = 0;
++nbLines;
if(nbLines > 200) {
textBlockedUsers->clear();
nbLines = 1;
}
textBlockedUsers->append(QString::fromUtf8("<font color='grey'>")+ QTime::currentTime().toString(QString::fromUtf8("hh:mm:ss")) + QString::fromUtf8("</font> - ")+tr("<font color='red'>%1</font> <i>was blocked</i>", "x.y.z.w was blocked").arg(ip));
}
unsigned int DownloadingTorrents::getNbTorrentsInList() const {
return nbTorrents;
}
// Note: do not actually pause the torrent in BT session
void DownloadingTorrents::pauseTorrent(QString hash) {
int row = getRowFromHash(hash);
if(row == -1)
return;
DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.0));
DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.0));
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1));
DLListModel->setData(DLListModel->index(row, NAME), QIcon(QString::fromUtf8(":/Icons/skin/paused.png")), Qt::DecorationRole);
DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(QString::fromUtf8("0/0")));
QTorrentHandle h = BTSession->getTorrentHandle(hash);
DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress()));
setRowColor(row, QString::fromUtf8("red"));
}
QString DownloadingTorrents::getHashFromRow(unsigned int row) const {
Q_ASSERT(row < (unsigned int)DLListModel->rowCount());
return DLListModel->data(DLListModel->index(row, HASH)).toString();
}
void DownloadingTorrents::setBottomTabEnabled(unsigned int index, bool b){
if(index and !b)
tabBottom->setCurrentIndex(0);
tabBottom->setTabEnabled(index, b);
}
// Show torrent properties dialog
void DownloadingTorrents::showProperties(const QModelIndex &index) {
showPropertiesFromHash(DLListModel->data(DLListModel->index(index.row(), HASH)).toString());
}
void DownloadingTorrents::showPropertiesFromHash(QString hash) {
QTorrentHandle h = BTSession->getTorrentHandle(hash);
properties *prop = new properties(this, BTSession, h);
connect(prop, SIGNAL(filteredFilesChanged(QString)), this, SLOT(updateFileSizeAndProgress(QString)));
connect(prop, SIGNAL(trackersChanged(QString)), BTSession, SLOT(saveTrackerFile(QString)));
prop->show();
}
void DownloadingTorrents::resumeTorrent(QString hash){
int row = getRowFromHash(hash);
Q_ASSERT(row != -1);
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole);
setRowColor(row, QString::fromUtf8("grey"));
}
// Remove a torrent from the download list but NOT from the BT Session
void DownloadingTorrents::deleteTorrent(QString hash) {
int row = getRowFromHash(hash);
if(row == -1){
qDebug("torrent is not in download list, nothing to delete");
return;
}
DLListModel->removeRow(row);
--nbTorrents;
emit unfinishedTorrentsNumberChanged(nbTorrents);
}
void DownloadingTorrents::displayUPnPError(QString msg) {
setInfoBar(tr("UPnP/NAT-PMP: Port mapping failure, message: %1").arg(msg), QColor("red"));
}
void DownloadingTorrents::displayUPnPSuccess(QString msg) {
DownloadingTorrents::setInfoBar(tr("UPnP/NAT-PMP: Port mapping successful, message: %1").arg(msg), QColor("blue"));
}
// Update Info Bar information
void DownloadingTorrents::setInfoBar(QString info, QColor color) {
static unsigned int nbLines = 0;
++nbLines;
// Check log size, clear it if too big
if(nbLines > 200) {
infoBar->clear();
nbLines = 1;
}
infoBar->append(QString::fromUtf8("<font color='grey'>")+ QTime::currentTime().toString(QString::fromUtf8("hh:mm:ss")) + QString::fromUtf8("</font> - <font color='") + color.name() +QString::fromUtf8("'><i>") + info + QString::fromUtf8("</i></font>"));
}
void DownloadingTorrents::addFastResumeRejectedAlert(QString name) {
setInfoBar(tr("Fast resume data was rejected for torrent %1, checking again...").arg(name), QString::fromUtf8("red"));
}
void DownloadingTorrents::addUrlSeedError(QString url, QString msg) {
setInfoBar(tr("Url seed lookup failed for url: %1, message: %2").arg(url).arg(msg), QString::fromUtf8("red"));
}
void DownloadingTorrents::on_actionSet_download_limit_triggered() {
QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes();
QModelIndex index;
QStringList hashes;
foreach(index, selectedIndexes) {
if(index.column() == NAME) {
// Get the file hash
hashes << DLListModel->data(DLListModel->index(index.row(), HASH)).toString();
}
}
Q_ASSERT(hashes.size() > 0);
new BandwidthAllocationDialog(this, false, BTSession, hashes);
}
void DownloadingTorrents::on_actionSet_upload_limit_triggered() {
QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes();
QModelIndex index;
QStringList hashes;
foreach(index, selectedIndexes) {
if(index.column() == NAME) {
// Get the file hash
hashes << DLListModel->data(DLListModel->index(index.row(), HASH)).toString();
}
}
Q_ASSERT(hashes.size() > 0);
new BandwidthAllocationDialog(this, true, BTSession, hashes);
}
// display properties of selected items
void DownloadingTorrents::propertiesSelection(){
QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes();
QModelIndex index;
foreach(index, selectedIndexes){
if(index.column() == NAME){
showProperties(index);
}
}
}
void DownloadingTorrents::displayDLListMenu(const QPoint& pos) {
QMenu myDLLlistMenu(this);
QModelIndex index;
// Enable/disable pause/start action given the DL state
QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes();
bool has_pause = false, has_start = false, has_preview = false;
foreach(index, selectedIndexes) {
if(index.column() == NAME) {
// Get the file name
QString hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString();
// Get handle and pause the torrent
QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(!h.is_valid()) continue;
if(h.is_paused()) {
if(!has_start) {
myDLLlistMenu.addAction(actionStart);
has_start = true;
}
}else{
if(!has_pause) {
myDLLlistMenu.addAction(actionPause);
has_pause = true;
}
}
if(BTSession->isFilePreviewPossible(hash) && !has_preview) {
myDLLlistMenu.addAction(actionPreview_file);
has_preview = true;
}
if(has_pause && has_start && has_preview) break;
}
}
myDLLlistMenu.addSeparator();
myDLLlistMenu.addAction(actionDelete);
myDLLlistMenu.addAction(actionDelete_Permanently);
myDLLlistMenu.addSeparator();
myDLLlistMenu.addAction(actionSet_download_limit);
myDLLlistMenu.addAction(actionSet_upload_limit);
myDLLlistMenu.addSeparator();
myDLLlistMenu.addAction(actionOpen_destination_folder);
myDLLlistMenu.addAction(actionTorrent_Properties);
myDLLlistMenu.addSeparator();
myDLLlistMenu.addAction(actionBuy_it);
// Call menu
// XXX: why mapToGlobal() is not enough?
myDLLlistMenu.exec(mapToGlobal(pos)+QPoint(10,60));
}
/*
* Hiding Columns functions
*/
// hide/show columns menu
void DownloadingTorrents::displayDLHoSMenu(const QPoint& pos){
QMenu hideshowColumn(this);
hideshowColumn.setTitle(tr("Hide or Show Column"));
for(int i=0; i<=ETA; i++) {
hideshowColumn.addAction(getActionHoSCol(i));
}
// Call menu
hideshowColumn.exec(mapToGlobal(pos)+QPoint(10,55));
}
// toggle hide/show a column
void DownloadingTorrents::hideOrShowColumn(int index) {
unsigned int nbVisibleColumns = 0;
unsigned int nbCols = DLListModel->columnCount();
// Count visible columns
for(unsigned int i=0; i<nbCols; ++i) {
if(!downloadList->isColumnHidden(i))
++nbVisibleColumns;
}
if(!downloadList->isColumnHidden(index)) {
// User wants to hide the column
// Is there at least one other visible column?
if(nbVisibleColumns <= 1) return;
// User can hide the column, do it.
downloadList->setColumnHidden(index, true);
getActionHoSCol(index)->setIcon(QIcon(QString::fromUtf8(":/Icons/button_cancel.png")));
--nbVisibleColumns;
} else {
// User want to display the column
downloadList->setColumnHidden(index, false);
getActionHoSCol(index)->setIcon(QIcon(QString::fromUtf8(":/Icons/button_ok.png")));
++nbVisibleColumns;
}
//resize all others non-hidden columns
for(unsigned int i=0; i<nbCols; ++i) {
if(!downloadList->isColumnHidden(i)) {
downloadList->setColumnWidth(i, (int)ceil(downloadList->columnWidth(i)+(downloadList->columnWidth(index)/nbVisibleColumns)));
}
}
}
// save the hidden columns in settings
void DownloadingTorrents::saveHiddenColumns() {
QSettings settings("qBittorrent", "qBittorrent");
QStringList ishidden_list;
short nbColumns = DLListModel->columnCount()-1;
for(short i=0; i<nbColumns; ++i){
if(downloadList->isColumnHidden(i)) {
ishidden_list << QString::fromUtf8(misc::toString(0).c_str());
} else {
ishidden_list << QString::fromUtf8(misc::toString(1).c_str());
}
}
settings.setValue("DownloadListColsHoS", ishidden_list.join(" "));
}
// load the previous settings, and hide the columns
bool DownloadingTorrents::loadHiddenColumns() {
bool loaded = false;
QSettings settings("qBittorrent", "qBittorrent");
QString line = settings.value("DownloadListColsHoS", QString()).toString();
QStringList ishidden_list;
if(!line.isEmpty()) {
ishidden_list = line.split(' ');
if(ishidden_list.size() == DLListModel->columnCount()-1) {
unsigned int listSize = ishidden_list.size();
for(unsigned int i=0; i<listSize; ++i){
downloadList->header()->resizeSection(i, ishidden_list.at(i).toInt());
}
loaded = true;
}
}
for(int i=0; i<DLListModel->columnCount()-1; i++) {
if(loaded && ishidden_list.at(i) == "0") {
downloadList->setColumnHidden(i, true);
getActionHoSCol(i)->setIcon(QIcon(QString::fromUtf8(":/Icons/button_cancel.png")));
} else {
getActionHoSCol(i)->setIcon(QIcon(QString::fromUtf8(":/Icons/button_ok.png")));
}
}
return loaded;
}
void DownloadingTorrents::hideOrShowColumnName() {
hideOrShowColumn(NAME);
}
void DownloadingTorrents::hideOrShowColumnSize() {
hideOrShowColumn(SIZE);
}
void DownloadingTorrents::hideOrShowColumnProgress() {
hideOrShowColumn(PROGRESS);
}
void DownloadingTorrents::hideOrShowColumnDownSpeed() {
hideOrShowColumn(DLSPEED);
}
void DownloadingTorrents::hideOrShowColumnUpSpeed() {
hideOrShowColumn(UPSPEED);
}
void DownloadingTorrents::hideOrShowColumnSeedersLeechers() {
hideOrShowColumn(SEEDSLEECH);
}
void DownloadingTorrents::hideOrShowColumnRatio() {
hideOrShowColumn(RATIO);
}
void DownloadingTorrents::hideOrShowColumnEta() {
hideOrShowColumn(ETA);
}
void DownloadingTorrents::on_actionClearLog_triggered() {
infoBar->clear();
}
// getter, return the action hide or show whose id is index
QAction* DownloadingTorrents::getActionHoSCol(int index) {
switch(index) {
case NAME :
return actionHOSColName;
break;
case SIZE :
return actionHOSColSize;
break;
case PROGRESS :
return actionHOSColProgress;
break;
case DLSPEED :
return actionHOSColDownSpeed;
break;
case UPSPEED :
return actionHOSColUpSpeed;
break;
case SEEDSLEECH :
return actionHOSColSeedersLeechers;
break;
case RATIO :
return actionHOSColRatio;
break;
case ETA :
return actionHOSColEta;
break;
default :
return NULL;
}
}
QStringList DownloadingTorrents::getSelectedTorrents(bool only_one) const{
QStringList res;
QModelIndex index;
QModelIndexList selectedIndexes = downloadList->selectionModel()->selectedIndexes();
foreach(index, selectedIndexes) {
if(index.column() == NAME) {
// Get the file hash
QString hash = DLListModel->data(DLListModel->index(index.row(), HASH)).toString();
res << hash;
if(only_one) break;
}
}
return res;
}
void DownloadingTorrents::displayInfoBarMenu(const QPoint& pos) {
// Log Menu
QMenu myLogMenu(this);
myLogMenu.addAction(actionClearLog);
// XXX: Why mapToGlobal() is not enough?
myLogMenu.exec(mapToGlobal(pos)+QPoint(44,305));
}
void DownloadingTorrents::sortProgressColumnDelayed() {
if(delayedSorting) {
sortDownloadListFloat(PROGRESS, delayedSortingOrder);
qDebug("Delayed sorting of progress column");
}
}
// get information from torrent handles and
// update download list accordingly
void DownloadingTorrents::updateDlList() {
// browse handles
QStringList unfinishedTorrents = BTSession->getUnfinishedTorrents();
QString hash;
foreach(hash, unfinishedTorrents) {
QTorrentHandle h = BTSession->getTorrentHandle(hash);
if(!h.is_valid()){
qDebug("We have an invalid handle for: %s", qPrintable(hash));
continue;
}
try{
QString hash = h.hash();
int row = getRowFromHash(hash);
if(row == -1) {
qDebug("Info: Could not find filename in download list, adding it...");
addTorrent(hash);
row = getRowFromHash(hash);
}
Q_ASSERT(row != -1);
// No need to update a paused torrent
if(h.is_paused()) continue;
if(BTSession->getTorrentsToPauseAfterChecking().indexOf(hash) != -1) {
if(!downloadList->isColumnHidden(PROGRESS)) {
DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress()));
}
continue;
}
// Parse download state
// Setting download state
switch(h.state()) {
case torrent_status::finished:
case torrent_status::seeding:
qDebug("A torrent that was in download tab just finished, moving it to finished tab");
BTSession->setUnfinishedTorrent(hash);
emit torrentFinished(hash);
deleteTorrent(hash);
continue;
case torrent_status::checking_files:
case torrent_status::queued_for_checking:
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/time.png"))), Qt::DecorationRole);
setRowColor(row, QString::fromUtf8("grey"));
if(!downloadList->isColumnHidden(PROGRESS)) {
DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress()));
}
break;
case torrent_status::connecting_to_tracker:
if(h.download_payload_rate() > 0) {
// Display "Downloading" status when connecting if download speed > 0
if(!downloadList->isColumnHidden(ETA)) {
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)BTSession->getETA(hash)));
}
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))), Qt::DecorationRole);
setRowColor(row, QString::fromUtf8("green"));
}else{
if(!downloadList->isColumnHidden(ETA)) {
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1));
}
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole);
setRowColor(row, QString::fromUtf8("grey"));
}
if(!downloadList->isColumnHidden(PROGRESS)) {
DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress()));
}
if(!downloadList->isColumnHidden(DLSPEED)) {
DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)h.download_payload_rate()));
}
if(!downloadList->isColumnHidden(UPSPEED)) {
DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)h.upload_payload_rate()));
}
break;
case torrent_status::downloading:
case torrent_status::downloading_metadata:
if(h.download_payload_rate() > 0) {
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/downloading.png"))), Qt::DecorationRole);
if(!downloadList->isColumnHidden(ETA)) {
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)BTSession->getETA(hash)));
}
setRowColor(row, QString::fromUtf8("green"));
}else{
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/stalled.png"))), Qt::DecorationRole);
if(!downloadList->isColumnHidden(ETA)) {
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1));
}
setRowColor(row, QApplication::palette().color(QPalette::WindowText));
}
if(!downloadList->isColumnHidden(PROGRESS)) {
DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress()));
}
if(!downloadList->isColumnHidden(DLSPEED)) {
DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)h.download_payload_rate()));
}
if(!downloadList->isColumnHidden(UPSPEED)) {
DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)h.upload_payload_rate()));
}
break;
default:
if(!downloadList->isColumnHidden(ETA)) {
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1));
}
}
if(!downloadList->isColumnHidden(SEEDSLEECH)) {
DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(misc::toQString(h.num_seeds(), true)+QString::fromUtf8("/")+misc::toQString(h.num_peers() - h.num_seeds(), true)));
}
if(!downloadList->isColumnHidden(RATIO)) {
DLListModel->setData(DLListModel->index(row, RATIO), QVariant(misc::toQString(BTSession->getRealRatio(hash))));
}
}catch(invalid_handle e) {
continue;
}
}
}
void DownloadingTorrents::addTorrent(QString hash) {
if(BTSession->isFinished(hash)){
BTSession->setUnfinishedTorrent(hash);
}
QTorrentHandle h = BTSession->getTorrentHandle(hash);
int row = getRowFromHash(hash);
if(row != -1) return;
row = DLListModel->rowCount();
// Adding torrent to download list
DLListModel->insertRow(row);
DLListModel->setData(DLListModel->index(row, NAME), QVariant(h.name()));
DLListModel->setData(DLListModel->index(row, SIZE), QVariant((qlonglong)h.actual_size()));
DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.));
DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.));
DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(QString::fromUtf8("0/0")));
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1));
DLListModel->setData(DLListModel->index(row, HASH), QVariant(hash));
// Pause torrent if it was paused last time
if(BTSession->isPaused(hash)) {
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/paused.png"))), Qt::DecorationRole);
setRowColor(row, QString::fromUtf8("red"));
}else{
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole);
setRowColor(row, QString::fromUtf8("grey"));
}
++nbTorrents;
emit unfinishedTorrentsNumberChanged(nbTorrents);
}
void DownloadingTorrents::sortDownloadListFloat(int index, Qt::SortOrder sortOrder) {
QList<QPair<int, double> > lines;
// insertion sorting
unsigned int nbRows = DLListModel->rowCount();
for(unsigned int i=0; i<nbRows; ++i) {
misc::insertSort(lines, QPair<int,double>(i, DLListModel->data(DLListModel->index(i, index)).toDouble()), sortOrder);
}
// Insert items in new model, in correct order
unsigned int nbRows_old = lines.size();
for(unsigned int row=0; row<nbRows_old; ++row) {
DLListModel->insertRow(DLListModel->rowCount());
unsigned int sourceRow = lines[row].first;
unsigned int nbColumns = DLListModel->columnCount();
for(unsigned int col=0; col<nbColumns; ++col) {
DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col)));
DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col), Qt::DecorationRole), Qt::DecorationRole);
DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col), Qt::ForegroundRole), Qt::ForegroundRole);
}
}
// Remove old rows
DLListModel->removeRows(0, nbRows_old);
}
void DownloadingTorrents::sortDownloadListString(int index, Qt::SortOrder sortOrder) {
QList<QPair<int, QString> > lines;
// Insertion sorting
unsigned int nbRows = DLListModel->rowCount();
for(unsigned int i=0; i<nbRows; ++i) {
misc::insertSortString(lines, QPair<int, QString>(i, DLListModel->data(DLListModel->index(i, index)).toString()), sortOrder);
}
// Insert items in new model, in correct order
unsigned int nbRows_old = lines.size();
for(unsigned int row=0; row<nbRows_old; ++row) {
DLListModel->insertRow(DLListModel->rowCount());
unsigned int sourceRow = lines[row].first;
unsigned int nbColumns = DLListModel->columnCount();
for(unsigned int col=0; col<nbColumns; ++col) {
DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col)));
DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col), Qt::DecorationRole), Qt::DecorationRole);
DLListModel->setData(DLListModel->index(nbRows_old+row, col), DLListModel->data(DLListModel->index(sourceRow, col), Qt::ForegroundRole), Qt::ForegroundRole);
}
}
// Remove old rows
DLListModel->removeRows(0, nbRows_old);
}
void DownloadingTorrents::sortDownloadList(int index, Qt::SortOrder startSortOrder, bool fromLoadColWidth) {
qDebug("Called sort download list");
static Qt::SortOrder sortOrder = startSortOrder;
if(!fromLoadColWidth && downloadList->header()->sortIndicatorSection() == index) {
if(sortOrder == Qt::AscendingOrder) {
sortOrder = Qt::DescendingOrder;
}else{
sortOrder = Qt::AscendingOrder;
}
}
QString sortOrderLetter;
if(sortOrder == Qt::AscendingOrder)
sortOrderLetter = QString::fromUtf8("a");
else
sortOrderLetter = QString::fromUtf8("d");
if(fromLoadColWidth) {
// XXX: Why is this needed?
if(sortOrder == Qt::DescendingOrder)
downloadList->header()->setSortIndicator(index, Qt::AscendingOrder);
else
downloadList->header()->setSortIndicator(index, Qt::DescendingOrder);
} else {
downloadList->header()->setSortIndicator(index, sortOrder);
}
switch(index) {
case SIZE:
case ETA:
case UPSPEED:
case DLSPEED:
sortDownloadListFloat(index, sortOrder);
break;
case PROGRESS:
if(fromLoadColWidth) {
// Progress sorting must be delayed until files are checked (on startup)
delayedSorting = true;
qDebug("Delayed sorting of the progress column");
delayedSortingOrder = sortOrder;
}else{
sortDownloadListFloat(index, sortOrder);
}
break;
default:
sortDownloadListString(index, sortOrder);
}
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
settings.setValue(QString::fromUtf8("DownloadListSortedCol"), misc::toQString(index)+sortOrderLetter);
}
// Save columns width in a file to remember them
// (download list)
void DownloadingTorrents::saveColWidthDLList() const{
qDebug("Saving columns width in download list");
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
QStringList width_list;
QStringList new_width_list;
short nbColumns = DLListModel->columnCount()-1;
QString line = settings.value("DownloadListColsWidth", QString()).toString();
if(!line.isEmpty()) {
width_list = line.split(' ');
}
for(short i=0; i<nbColumns; ++i){
if(downloadList->columnWidth(i)<1 && width_list.size() == DLListModel->columnCount()-1 && width_list.at(i).toInt()>=1) {
// load the former width
new_width_list << width_list.at(i);
} else if(downloadList->columnWidth(i)>=1) {
// usual case, save the current width
new_width_list << QString::fromUtf8(misc::toString(downloadList->columnWidth(i)).c_str());
} else {
// default width
downloadList->resizeColumnToContents(i);
new_width_list << QString::fromUtf8(misc::toString(downloadList->columnWidth(i)).c_str());
}
}
settings.setValue(QString::fromUtf8("DownloadListColsWidth"), new_width_list.join(QString::fromUtf8(" ")));
qDebug("Download list columns width saved");
}
// Load columns width in a file that were saved previously
// (download list)
bool DownloadingTorrents::loadColWidthDLList() {
qDebug("Loading columns width for download list");
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
QString line = settings.value(QString::fromUtf8("DownloadListColsWidth"), QString()).toString();
if(line.isEmpty())
return false;
QStringList width_list = line.split(QString::fromUtf8(" "));
if(width_list.size() != DLListModel->columnCount()-1) {
qDebug("Corrupted values for download list columns sizes");
return false;
}
unsigned int listSize = width_list.size();
for(unsigned int i=0; i<listSize; ++i) {
downloadList->header()->resizeSection(i, width_list.at(i).toInt());
}
// Loading last sorted column
QString sortedCol = settings.value(QString::fromUtf8("DownloadListSortedCol"), QString()).toString();
if(!sortedCol.isEmpty()) {
Qt::SortOrder sortOrder;
if(sortedCol.endsWith(QString::fromUtf8("d")))
sortOrder = Qt::DescendingOrder;
else
sortOrder = Qt::AscendingOrder;
sortedCol = sortedCol.left(sortedCol.size()-1);
int index = sortedCol.toInt();
sortDownloadList(index, sortOrder, true);
}
qDebug("Download list columns width loaded");
return true;
}
// Called when a torrent is added
void DownloadingTorrents::torrentAdded(QString path, QTorrentHandle& h, bool fastResume) {
QString hash = h.hash();
if(BTSession->isFinished(hash)) {
return;
}
int row = DLListModel->rowCount();
// Adding torrent to download list
DLListModel->insertRow(row);
DLListModel->setData(DLListModel->index(row, NAME), QVariant(h.name()));
DLListModel->setData(DLListModel->index(row, SIZE), QVariant((qlonglong)h.actual_size()));
DLListModel->setData(DLListModel->index(row, DLSPEED), QVariant((double)0.));
DLListModel->setData(DLListModel->index(row, UPSPEED), QVariant((double)0.));
DLListModel->setData(DLListModel->index(row, SEEDSLEECH), QVariant(QString::fromUtf8("0/0")));
DLListModel->setData(DLListModel->index(row, RATIO), QVariant(misc::toQString(BTSession->getRealRatio(hash))));
DLListModel->setData(DLListModel->index(row, ETA), QVariant((qlonglong)-1));
DLListModel->setData(DLListModel->index(row, HASH), QVariant(hash));
// Pause torrent if it was paused last time
// Not using isPaused function because torrents are paused after checking now
if(QFile::exists(misc::qBittorrentPath()+QString::fromUtf8("BT_backup")+QDir::separator()+hash+QString::fromUtf8(".paused"))) {
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/paused.png"))), Qt::DecorationRole);
setRowColor(row, QString::fromUtf8("red"));
}else{
DLListModel->setData(DLListModel->index(row, NAME), QVariant(QIcon(QString::fromUtf8(":/Icons/skin/connecting.png"))), Qt::DecorationRole);
setRowColor(row, QString::fromUtf8("grey"));
}
if(!fastResume) {
setInfoBar(tr("'%1' added to download list.", "'/home/y/xxx.torrent' was added to download list.").arg(path));
}else{
setInfoBar(tr("'%1' resumed. (fast resume)", "'/home/y/xxx.torrent' was resumed. (fast resume)").arg(path));
}
++nbTorrents;
emit unfinishedTorrentsNumberChanged(nbTorrents);
}
// Called when trying to add a duplicate torrent
void DownloadingTorrents::torrentDuplicate(QString path) {
setInfoBar(tr("'%1' is already in download list.", "e.g: 'xxx.avi' is already in download list.").arg(path));
}
void DownloadingTorrents::torrentCorrupted(QString path) {
setInfoBar(tr("Unable to decode torrent file: '%1'", "e.g: Unable to decode torrent file: '/home/y/xxx.torrent'").arg(path), QString::fromUtf8("red"));
setInfoBar(tr("This file is either corrupted or this isn't a torrent."),QString::fromUtf8("red"));
}
void DownloadingTorrents::updateFileSizeAndProgress(QString hash) {
int row = getRowFromHash(hash);
Q_ASSERT(row != -1);
QTorrentHandle h = BTSession->getTorrentHandle(hash);
DLListModel->setData(DLListModel->index(row, SIZE), QVariant((qlonglong)h.actual_size()));
DLListModel->setData(DLListModel->index(row, PROGRESS), QVariant((double)h.progress()));
}
// Called when we couldn't listen on any port
// in the given range.
void DownloadingTorrents::portListeningFailure() {
setInfoBar(tr("Couldn't listen on any of the given ports."), QString::fromUtf8("red"));
}
// Set the color of a row in data model
void DownloadingTorrents::setRowColor(int row, QColor color) {
unsigned int nbColumns = DLListModel->columnCount()-1;
for(unsigned int i=0; i<nbColumns; ++i) {
DLListModel->setData(DLListModel->index(row, i), QVariant(color), Qt::ForegroundRole);
}
}
// return the row of in data model
// corresponding to the given the hash
int DownloadingTorrents::getRowFromHash(QString hash) const{
unsigned int nbRows = DLListModel->rowCount();
for(unsigned int i=0; i<nbRows; ++i) {
if(DLListModel->data(DLListModel->index(i, HASH)) == hash) {
return i;
}
}
return -1;
}
void DownloadingTorrents::displayDownloadingUrlInfos(QString url) {
setInfoBar(tr("Downloading '%1', please wait...", "e.g: Downloading 'xxx.torrent', please wait...").arg(url), QPalette::WindowText);
}

112
src/downloadingTorrents.h Normal file
View File

@@ -0,0 +1,112 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contact : chris@qbittorrent.org
*/
#ifndef DOWNLOADINGTORRENTS_H
#define DOWNLOADINGTORRENTS_H
#include "ui_download.h"
#include "qtorrenthandle.h"
class QStandardItemModel;
class bittorrent;
class DLListDelegate;
using namespace libtorrent;
class DownloadingTorrents : public QWidget, public Ui::downloading{
Q_OBJECT
private:
QObject *parent;
bittorrent *BTSession;
DLListDelegate *DLDelegate;
QStandardItemModel *DLListModel;
bool delayedSorting;
unsigned int nbTorrents;
Qt::SortOrder delayedSortingOrder;
void hideOrShowColumn(int index);
bool loadHiddenColumns();
void saveHiddenColumns();
QAction* getActionHoSCol(int index);
public:
DownloadingTorrents(QObject *parent, bittorrent *BTSession);
~DownloadingTorrents();
// Methods
bool loadColWidthDLList();
int getRowFromHash(QString hash) const;
QString getHashFromRow(unsigned int row) const;
QStringList getSelectedTorrents(bool only_one=false) const;
unsigned int getNbTorrentsInList() const;
signals:
void unfinishedTorrentsNumberChanged(unsigned int);
void torrentDoubleClicked(QString hash, bool finished);
void torrentFinished(QString hash);
protected slots:
void addLogPeerBlocked(QString);
void addFastResumeRejectedAlert(QString);
void addUrlSeedError(QString url, QString msg);
void on_actionSet_download_limit_triggered();
void notifyTorrentDoubleClicked(const QModelIndex& index);
void on_actionSet_upload_limit_triggered();
void displayDLListMenu(const QPoint& pos);
void displayDLHoSMenu(const QPoint&);
void on_actionClearLog_triggered();
void displayInfoBarMenu(const QPoint& pos);
void addTorrent(QString hash);
void sortDownloadList(int index, Qt::SortOrder startSortOrder=Qt::AscendingOrder, bool fromLoadColWidth=false);
void sortDownloadListFloat(int index, Qt::SortOrder sortOrder);
void sortDownloadListString(int index, Qt::SortOrder sortOrder);
void saveColWidthDLList() const;
void torrentAdded(QString path, QTorrentHandle& h, bool fastResume);
void torrentDuplicate(QString path);
void torrentCorrupted(QString path);
void portListeningFailure();
void setRowColor(int row, QColor color);
void displayDownloadingUrlInfos(QString url);
void showProperties(const QModelIndex &index);
void hideOrShowColumnName();
void hideOrShowColumnSize();
void hideOrShowColumnProgress();
void hideOrShowColumnDownSpeed();
void hideOrShowColumnUpSpeed();
void hideOrShowColumnSeedersLeechers();
void hideOrShowColumnRatio();
void hideOrShowColumnEta();
void displayUPnPError(QString msg);
void displayUPnPSuccess(QString msg);
public slots:
void updateDlList();
void setInfoBar(QString info, QColor color=QApplication::palette().color(QPalette::WindowText));
void pauseTorrent(QString hash);
void resumeTorrent(QString hash);
void deleteTorrent(QString hash);
void setBottomTabEnabled(unsigned int index, bool b);
void propertiesSelection();
void sortProgressColumnDelayed();
void updateFileSizeAndProgress(QString hash);
void showPropertiesFromHash(QString hash);
};
#endif

125
src/engineSelect.ui Normal file
View File

@@ -0,0 +1,125 @@
<ui version="4.0" >
<class>engineSelect</class>
<widget class="QDialog" name="engineSelect" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>541</width>
<height>254</height>
</rect>
</property>
<property name="acceptDrops" >
<bool>true</bool>
</property>
<property name="windowTitle" >
<string>Search plugins</string>
</property>
<layout class="QVBoxLayout" >
<item>
<widget class="QLabel" name="lbl_engines" >
<property name="font" >
<font>
<weight>75</weight>
<bold>true</bold>
<underline>true</underline>
</font>
</property>
<property name="text" >
<string>Installed search engines:</string>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="pluginsTree" >
<property name="contextMenuPolicy" >
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="selectionMode" >
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="uniformRowHeights" >
<bool>true</bool>
</property>
<property name="itemsExpandable" >
<bool>false</bool>
</property>
<column>
<property name="text" >
<string>Name</string>
</property>
</column>
<column>
<property name="text" >
<string>Url</string>
</property>
</column>
<column>
<property name="text" >
<string>Enabled</string>
</property>
</column>
<column>
<property name="text" >
<string/>
</property>
</column>
</widget>
</item>
<item>
<widget class="QLabel" name="getNewEngine_lbl" >
<property name="font" >
<font>
<italic>true</italic>
</font>
</property>
<property name="text" >
<string>You can get new search engine plugins here: &lt;a href="http:plugins.qbittorrent.org">http://plugins.qbittorrent.org&lt;/a></string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<item>
<widget class="QPushButton" name="installButton" >
<property name="text" >
<string>Install a new one</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="updateButton" >
<property name="text" >
<string>Check for updates</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closeButton" >
<property name="text" >
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
<action name="actionEnable" >
<property name="text" >
<string>Enable</string>
</property>
</action>
<action name="actionDisable" >
<property name="text" >
<string>Disable</string>
</property>
</action>
<action name="actionUninstall" >
<property name="text" >
<string>Uninstall</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

703
src/engineSelectDlg.cpp Normal file
View File

@@ -0,0 +1,703 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contact : chris@qbittorrent.org
*/
#include "engineSelectDlg.h"
#include "downloadThread.h"
#include "misc.h"
#include "pluginSource.h"
#include <QProcess>
#include <QHeaderView>
#include <QSettings>
#include <QMenu>
#include <QMessageBox>
#include <QFileDialog>
#include <QDropEvent>
#include <QInputDialog>
#ifdef HAVE_MAGICK
#include <Magick++.h>
using namespace Magick;
#endif
#ifdef HAVE_ZZIP
#include <zzip/zzip.h>
#endif
#define ENGINE_NAME 0
#define ENGINE_URL 1
#define ENGINE_STATE 2
#define ENGINE_ID 3
engineSelectDlg::engineSelectDlg(QWidget *parent) : QDialog(parent) {
setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
pluginsTree->header()->resizeSection(0, 170);
pluginsTree->header()->resizeSection(1, 220);
pluginsTree->hideColumn(ENGINE_ID);
actionEnable->setIcon(QIcon(QString::fromUtf8(":/Icons/button_ok.png")));
actionDisable->setIcon(QIcon(QString::fromUtf8(":/Icons/button_cancel.png")));
actionUninstall->setIcon(QIcon(QString::fromUtf8(":/Icons/skin/remove.png")));
connect(actionEnable, SIGNAL(triggered()), this, SLOT(enableSelection()));
connect(actionDisable, SIGNAL(triggered()), this, SLOT(disableSelection()));
connect(pluginsTree, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayContextMenu(const QPoint&)));
downloader = new downloadThread(this);
connect(downloader, SIGNAL(downloadFinished(QString, QString)), this, SLOT(processDownloadedFile(QString, QString)));
connect(downloader, SIGNAL(downloadFailure(QString, QString)), this, SLOT(handleDownloadFailure(QString, QString)));
loadSupportedSearchEngines(true);
connect(pluginsTree, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)), this, SLOT(toggleEngineState(QTreeWidgetItem*, int)));
show();
}
engineSelectDlg::~engineSelectDlg() {
qDebug("Destroying engineSelectDlg");
saveSettings();
emit enginesChanged();
qDebug("Before deleting downloader");
delete downloader;
qDebug("Engine plugins dialog destroyed");
}
void engineSelectDlg::dropEvent(QDropEvent *event) {
event->acceptProposedAction();
QStringList files=event->mimeData()->text().split(QString::fromUtf8("\n"));
QString file;
foreach(file, files) {
qDebug("dropped %s", file.toUtf8().data());
file = file.replace("file://", "");
if(file.startsWith("http://", Qt::CaseInsensitive) || file.startsWith("https://", Qt::CaseInsensitive) || file.startsWith("ftp://", Qt::CaseInsensitive)) {
downloader->downloadUrl(file);
continue;
}
if(file.endsWith(".py", Qt::CaseInsensitive)) {
QString plugin_name = file.split(QDir::separator()).last();
plugin_name.replace(".py", "");
installPlugin(file, plugin_name);
}
#ifdef HAVE_ZZIP
if(file.endsWith(".zip", Qt::CaseInsensitive)) {
installZipPlugin(file);
}
#endif
}
}
// Decode if we accept drag 'n drop or not
void engineSelectDlg::dragEnterEvent(QDragEnterEvent *event) {
QString mime;
foreach(mime, event->mimeData()->formats()){
qDebug("mimeData: %s", mime.toUtf8().data());
}
if (event->mimeData()->hasFormat(QString::fromUtf8("text/plain")) || event->mimeData()->hasFormat(QString::fromUtf8("text/uri-list"))) {
event->acceptProposedAction();
}
}
void engineSelectDlg::saveSettings() {
qDebug("Saving engines settings");
QStringList known_engines;
QVariantList known_enginesEnabled;
QString engine;
foreach(engine, installed_engines.keys()) {
known_engines << engine;
known_enginesEnabled << QVariant(installed_engines.value(engine, true));
qDebug("Engine %s has state: %d", engine.toUtf8().data(), installed_engines.value(engine, true));
}
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
settings.setValue(QString::fromUtf8("SearchEngines/knownEngines"), known_engines);
settings.setValue(QString::fromUtf8("SearchEngines/knownEnginesEnabled"), known_enginesEnabled);
}
void engineSelectDlg::on_updateButton_clicked() {
// Download version file from primary server
downloader->downloadUrl("http://www.dchris.eu/search_engine/versions.txt");
}
void engineSelectDlg::toggleEngineState(QTreeWidgetItem *item, int) {
int index = pluginsTree->indexOfTopLevelItem(item);
QString id = item->text(ENGINE_ID);
bool new_val = !installed_engines.value(id, true);
installed_engines[id] = new_val;
QString enabledTxt;
if(new_val){
enabledTxt = tr("True");
setRowColor(index, "green");
}else{
enabledTxt = tr("False");
setRowColor(index, "red");
}
item->setText(ENGINE_STATE, enabledTxt);
}
void engineSelectDlg::displayContextMenu(const QPoint& pos) {
QMenu myContextMenu(this);
QModelIndex index;
// Enable/disable pause/start action given the DL state
QList<QTreeWidgetItem *> items = pluginsTree->selectedItems();
bool has_enable = false, has_disable = false;
QTreeWidgetItem *item;
foreach(item, items) {
QString id = item->text(ENGINE_ID);
if(installed_engines.value(id, true) and !has_disable) {
myContextMenu.addAction(actionDisable);
has_disable = true;
}
if(!installed_engines.value(id, true) and !has_enable) {
myContextMenu.addAction(actionEnable);
has_enable = true;
}
if(has_enable && has_disable) break;
}
myContextMenu.addSeparator();
myContextMenu.addAction(actionUninstall);
myContextMenu.exec(mapToGlobal(pos)+QPoint(12, 58));
}
void engineSelectDlg::on_closeButton_clicked() {
close();
}
void engineSelectDlg::on_actionUninstall_triggered() {
QList<QTreeWidgetItem *> items = pluginsTree->selectedItems();
QTreeWidgetItem *item;
bool change = false;
bool error = false;
foreach(item, items) {
int index = pluginsTree->indexOfTopLevelItem(item);
Q_ASSERT(index != -1);
QString id = item->text(ENGINE_ID);
if(QFile::exists(":/search_engine/engines/"+id+".py")) {
error = true;
// Disable it instead
installed_engines.insert(id, false);
item->setText(ENGINE_STATE, tr("False"));
setRowColor(index, "red");
continue;
}else {
// Proceed with uninstall
// remove it from hard drive
QDir enginesFolder(misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines");
QStringList filters;
filters << id+".*";
QStringList files = enginesFolder.entryList(filters, QDir::Files, QDir::Unsorted);
QString file;
foreach(file, files) {
enginesFolder.remove(file);
}
// Remove it from lists
installed_engines.remove(id);
delete item;
change = true;
}
}
if(error)
QMessageBox::warning(0, tr("Uninstall warning"), tr("Some plugins could not be uninstalled because they are included in qBittorrent.\n Only the ones you added yourself can be uninstalled.\nHowever, those plugins were disabled."));
else
QMessageBox::information(0, tr("Uninstall success"), tr("All selected plugins were uninstalled successfully"));
}
void engineSelectDlg::enableSelection() {
QList<QTreeWidgetItem *> items = pluginsTree->selectedItems();
QTreeWidgetItem *item;
foreach(item, items) {
int index = pluginsTree->indexOfTopLevelItem(item);
Q_ASSERT(index != -1);
QString id = item->text(ENGINE_ID);
installed_engines.insert(id, true);
item->setText(ENGINE_STATE, tr("True"));
setRowColor(index, "green");
}
}
void engineSelectDlg::disableSelection() {
QList<QTreeWidgetItem *> items = pluginsTree->selectedItems();
QTreeWidgetItem *item;
foreach(item, items) {
int index = pluginsTree->indexOfTopLevelItem(item);
Q_ASSERT(index != -1);
QString id = item->text(ENGINE_ID);
installed_engines.insert(id, false);
item->setText(ENGINE_STATE, tr("False"));
setRowColor(index, "red");
}
}
// Set the color of a row in data model
void engineSelectDlg::setRowColor(int row, QString color){
QTreeWidgetItem *item = pluginsTree->topLevelItem(row);
for(int i=0; i<pluginsTree->columnCount()-1; ++i){
item->setData(i, Qt::ForegroundRole, QVariant(QColor(color)));
}
}
bool engineSelectDlg::checkInstalled(QString plugin_name) const {
QProcess nova;
QStringList params;
params << misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2.py";
params << "--supported_engines";
nova.start("python", params, QIODevice::ReadOnly);
nova.waitForStarted();
nova.waitForFinished();
QByteArray result = nova.readAll();
result = result.replace("\r", "");
result = result.replace("\n", "");
QList<QByteArray> plugins_list = result.split(',');
return plugins_list.contains(plugin_name.toUtf8());
}
void engineSelectDlg::loadSupportedSearchEngines(bool first) {
// Some clean up first
pluginsTree->clear();
QHash<QString, bool> old_engines;
if(first) {
QSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent"));
QStringList known_engines = settings.value(QString::fromUtf8("SearchEngines/knownEngines"), QStringList()).toStringList();
QVariantList enabled = settings.value(QString::fromUtf8("SearchEngines/knownEnginesEnabled"), QList<QVariant>()).toList();
Q_ASSERT(known_engines.size() == enabled.size());
unsigned int nbKnownEngines = known_engines.size();
for(unsigned int i=0; i<nbKnownEngines; ++i) {
old_engines[known_engines.at(i)] = enabled.at(i).toBool();
}
} else {
old_engines = installed_engines;
}
installed_engines.clear();
QStringList params;
// Ask nova core for the supported search engines
QProcess nova;
params << misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2.py";
params << "--supported_engines";
nova.start("python", params, QIODevice::ReadOnly);
nova.waitForStarted();
nova.waitForFinished();
QByteArray result = nova.readAll();
result = result.replace("\r", "");
result = result.replace("\n", "");
qDebug("read: %s", result.data());
QByteArray e;
QStringList supported_engines_ids;
foreach(e, result.split(',')) {
QString en = QString(e);
supported_engines_ids << en;
installed_engines[en] = old_engines.value(en, true);
}
params.clear();
params << misc::qBittorrentPath()+"search_engine"+QDir::separator()+"nova2.py";
params << "--supported_engines_infos";
nova.start("python", params, QIODevice::ReadOnly);
nova.waitForStarted();
nova.waitForFinished();
result = nova.readAll();
result = result.replace("\r", "");
result = result.replace("\n", "");
qDebug("read: %s", result.data());
unsigned int i = 0;
foreach(e, result.split(',')) {
QString id = supported_engines_ids.at(i);
QString nameUrlCouple(e);
QStringList line = nameUrlCouple.split('|');
if(line.size() != 2) continue;
QString enabledTxt;
if(installed_engines.value(id, true)) {
enabledTxt = tr("True");
} else {
enabledTxt = tr("False");
}
line << enabledTxt;
line << id;
QTreeWidgetItem *item = new QTreeWidgetItem(pluginsTree, line);
QString iconPath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+id+".png";
if(QFile::exists(iconPath)) {
// Good, we already have the icon
item->setData(ENGINE_NAME, Qt::DecorationRole, QVariant(QIcon(iconPath)));
} else {
// Icon is missing, we must download it
downloader->downloadUrl(line.at(1)+"/favicon.ico");
}
if(installed_engines.value(id, true))
setRowColor(i, "green");
else
setRowColor(i, "red");
++i;
}
}
QList<QTreeWidgetItem*> engineSelectDlg::findItemsWithUrl(QString url){
QList<QTreeWidgetItem*> res;
for(int i=0; i<pluginsTree->topLevelItemCount(); ++i) {
QTreeWidgetItem *item = pluginsTree->topLevelItem(i);
if(url.startsWith(item->text(ENGINE_URL), Qt::CaseInsensitive))
res << item;
}
return res;
}
QTreeWidgetItem* engineSelectDlg::findItemWithID(QString id){
QList<QTreeWidgetItem*> res;
for(int i=0; i<pluginsTree->topLevelItemCount(); ++i) {
QTreeWidgetItem *item = pluginsTree->topLevelItem(i);
if(id == item->text(ENGINE_ID))
return item;
}
return 0;
}
bool engineSelectDlg::isUpdateNeeded(QString plugin_name, float new_version) const {
float old_version = misc::getPluginVersion(misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+plugin_name+".py");
qDebug("IsUpdate needed? tobeinstalled: %.2f, alreadyinstalled: %.2f", new_version, old_version);
return (new_version > old_version);
}
#ifdef HAVE_ZZIP
void engineSelectDlg::installZipPlugin(QString path) {
QStringList plugins;
QStringList favicons;
ZZIP_DIR* dir = zzip_dir_open(path.toUtf8().data(), 0);
if(!dir) {
QMessageBox::warning(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("Search engine plugin archive could not be read."));
return;
}
ZZIP_DIRENT dirent;
while(zzip_dir_read(dir, &dirent)) {
/* show info for first file */
QString name(dirent.d_name);
if(name.endsWith(".py", Qt::CaseInsensitive)) {
plugins << name;
} else {
if(name.endsWith(".png", Qt::CaseInsensitive)) {
favicons << name;
}
}
}
QString plugin;
std::cout << dirent.d_name << std::endl;
ZZIP_FILE* fp = zzip_file_open(dir, dirent.d_name, 0);
if (fp) {
char buf[10];
zzip_ssize_t len = zzip_file_read(fp, buf, 10);
if (len) {
/* show head of README */
std::cout << buf;
}
zzip_file_close(fp);
std::cout << std::endl;
}
foreach(plugin, plugins) {
QString plugin_name = plugin.split(QDir::separator()).last();
plugin_name.chop(3); // Remove .py extension
qDebug("Detected plugin %s in archive", plugin_name.toUtf8().data());
ZZIP_FILE* fp = zzip_file_open(dir, plugin.toUtf8().data(), 0);
if(fp) {
QTemporaryFile *tmpfile = new QTemporaryFile();
QString tmpPath;
// Write file
if(tmpfile->open()) {
tmpPath = tmpfile->fileName();
char buf[255];
zzip_ssize_t len = zzip_file_read(fp, buf, 255);
while(len) {
tmpfile->write(buf, len);
len = zzip_file_read(fp, buf, 255);
}
zzip_file_close(fp);
tmpfile->close();
} else {
qDebug("Could not open tmp file");
QMessageBox::warning(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin could not be installed.", "%1 is the name of the search engine").arg(plugin_name.toUtf8().data()));
delete tmpfile;
continue;
}
// Install plugin
installPlugin(tmpPath, plugin_name);
qDebug("installPlugin() finished");
delete tmpfile;
qDebug("Deleted tmpfile");
} else {
qDebug("Cannot read file in archive");
QMessageBox::warning(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin could not be installed.", "%1 is the name of the search engine").arg(plugin_name.toUtf8().data()));
}
}
QString favicon;
foreach(favicon, favicons) {
qDebug("Detected favicon %s in archive", favicon.toUtf8().data());
// Ok we have a favicon here
QString plugin_name = favicon.split(QDir::separator()).last();
plugin_name.chop(4); // Remove .png extension
if(!QFile::exists(misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+plugin_name+".py"))
continue;
// Check if we already have a favicon for this plugin
QString iconPath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+plugin_name+".png";
if(QFile::exists(iconPath)) continue;
ZZIP_FILE* fp = zzip_file_open(dir, favicon.toUtf8().data(), 0);
if(fp) {
QFile dest_icon(iconPath);
// Write icon
if(dest_icon.open(QIODevice::WriteOnly | QIODevice::Text)) {
char buf[255];
zzip_ssize_t len = zzip_file_read(fp, buf, 255);
while(len) {
dest_icon.write(buf, len);
len = zzip_file_read(fp, buf, 255);
}
zzip_file_close(fp);
dest_icon.close();
// Update icon in list
QTreeWidgetItem *item = findItemWithID(plugin_name);
Q_ASSERT(item);
item->setData(ENGINE_NAME, Qt::DecorationRole, QVariant(QIcon(iconPath)));
}
}
}
zzip_dir_close(dir);
}
#endif
void engineSelectDlg::installPlugin(QString path, QString plugin_name) {
qDebug("Asked to install plugin at %s", path.toUtf8().data());
float new_version = misc::getPluginVersion(path);
qDebug("Version to be installed: %.2f", new_version);
if(!isUpdateNeeded(plugin_name, new_version)) {
qDebug("Apparently update it not needed, we have a more recent version");
QMessageBox::information(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("A more recent version of %1 search engine plugin is already installed.", "%1 is the name of the search engine").arg(plugin_name.toUtf8().data()));
return;
}
// Process with install
QString dest_path = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+plugin_name+".py";
bool update = false;
if(QFile::exists(dest_path)) {
// Backup in case install fails
QFile::copy(dest_path, dest_path+".bak");
QFile::remove(dest_path);
update = true;
}
// Copy the plugin
QFile::copy(path, dest_path);
// Check if this was correctly installed
if(!checkInstalled(plugin_name)) {
if(update) {
// Remove broken file
QFile::remove(dest_path);
// restore backup
QFile::copy(dest_path+".bak", dest_path);
QFile::remove(dest_path+".bak");
QMessageBox::warning(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin could not be updated, keeping old version.", "%1 is the name of the search engine").arg(plugin_name.toUtf8().data()));
return;
} else {
// Remove broken file
QFile::remove(dest_path);
QMessageBox::warning(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin could not be installed.", "%1 is the name of the search engine").arg(plugin_name.toUtf8().data()));
return;
}
}
// Install was successful, remove backup
if(update) {
QFile::remove(dest_path+".bak");
}
// Refresh plugin list
loadSupportedSearchEngines();
if(update) {
QMessageBox::information(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin was successfully updated.", "%1 is the name of the search engine").arg(plugin_name.toUtf8().data()));
return;
} else {
QMessageBox::information(this, tr("Search plugin install")+" -- "+tr("qBittorrent"), tr("%1 search engine plugin was successfully installed.", "%1 is the name of the search engine").arg(plugin_name.toUtf8().data()));
return;
}
}
void engineSelectDlg::on_installButton_clicked() {
pluginSourceDlg *dlg = new pluginSourceDlg(this);
connect(dlg, SIGNAL(askForLocalFile()), this, SLOT(askForLocalPlugin()));
connect(dlg, SIGNAL(askForUrl()), this, SLOT(askForPluginUrl()));
}
void engineSelectDlg::askForPluginUrl() {
bool ok;
QString url = QInputDialog::getText(this, tr("New search engine plugin URL"),
tr("URL:"), QLineEdit::Normal,
"http://", &ok);
if (ok && !url.isEmpty())
downloader->downloadUrl(url);
}
void engineSelectDlg::askForLocalPlugin() {
QStringList pathsList = QFileDialog::getOpenFileNames(0,
tr("Select search plugins"), QDir::homePath(),
#ifdef HAVE_ZZIP
tr("qBittorrent search plugins")+QString::fromUtf8(" (*.py *.zip)"));
#else
tr("qBittorrent search plugins")+QString::fromUtf8(" (*.py)"));
#endif
QString path;
foreach(path, pathsList) {
if(path.endsWith(".py", Qt::CaseInsensitive)) {
QString plugin_name = path.split(QDir::separator()).last();
plugin_name.replace(".py", "", Qt::CaseInsensitive);
installPlugin(path, plugin_name);
}
#ifdef HAVE_ZZIP
else {
if(path.endsWith(".zip", Qt::CaseInsensitive)) {
installZipPlugin(path);
}
}
#endif
}
}
bool engineSelectDlg::parseVersionsFile(QString versions_file, QString updateServer) {
qDebug("Checking if update is needed");
bool file_correct = false;
QFile versions(versions_file);
if(!versions.open(QIODevice::ReadOnly | QIODevice::Text)){
qDebug("* Error: Could not read versions.txt file");
return false;
}
bool updated = false;
while(!versions.atEnd()) {
QByteArray line = versions.readLine();
line.replace("\n", "");
line = line.trimmed();
if(line.isEmpty()) continue;
if(line.startsWith("#")) continue;
QList<QByteArray> list = line.split(' ');
if(list.size() != 2) continue;
QString plugin_name = QString(list.first());
if(!plugin_name.endsWith(":")) continue;
plugin_name.chop(1); // remove trailing ':'
bool ok;
float version = list.last().toFloat(&ok);
qDebug("read line %s: %.2f", plugin_name.toUtf8().data(), version);
if(!ok) continue;
file_correct = true;
if(isUpdateNeeded(plugin_name, version)) {
qDebug("Plugin: %s is outdated", plugin_name.toUtf8().data());
// Downloading update
downloader->downloadUrl(updateServer+plugin_name+".pyqBT"); // Actually this is really a .py
downloader->downloadUrl(updateServer+plugin_name+".png");
updated = true;
}else {
qDebug("Plugin: %s is up to date", plugin_name.toUtf8().data());
}
}
// Close file
versions.close();
// Clean up tmp file
QFile::remove(versions_file);
if(file_correct && !updated) {
QMessageBox::information(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("All your plugins are already up to date."));
}
return file_correct;
}
void engineSelectDlg::processDownloadedFile(QString url, QString filePath) {
qDebug("engineSelectDlg received %s", url.toUtf8().data());
if(url.endsWith("favicon.ico", Qt::CaseInsensitive)){
// Icon downloaded
QImage fileIcon;
#ifdef HAVE_MAGICK
try{
QFile::copy(filePath, filePath+".ico");
Image image(QDir::cleanPath(filePath+".ico").toUtf8().data());
// Convert to PNG since we can't read ICO format
image.magick("PNG");
// Resize to 16x16px
image.sample(Geometry(16, 16));
image.write(filePath.toUtf8().data());
QFile::remove(filePath+".ico");
}catch(Magick::Exception &error_){
qDebug("favicon conversion to PNG failure: %s", error_.what());
}
#endif
if(fileIcon.load(filePath)) {
QList<QTreeWidgetItem*> items = findItemsWithUrl(url);
QTreeWidgetItem *item;
foreach(item, items){
QString id = item->text(ENGINE_ID);
QString iconPath = misc::qBittorrentPath()+"search_engine"+QDir::separator()+"engines"+QDir::separator()+id+".png";
QFile::copy(filePath, iconPath);
item->setData(ENGINE_NAME, Qt::DecorationRole, QVariant(QIcon(iconPath)));
}
}
// Delete tmp file
QFile::remove(filePath);
return;
}
if(url == "http://www.dchris.eu/search_engine/versions.txt") {
if(!parseVersionsFile(filePath, "http://www.dchris.eu/search_engine/")) {
qDebug("Primary update server failed, try secondary");
downloader->downloadUrl("http://hydr0g3n.free.fr/search_engine/versions.txt");
}
QFile::remove(filePath);
return;
}
if(url == "http://hydr0g3n.free.fr/search_engine/versions.txt") {
if(!parseVersionsFile(filePath, "http://hydr0g3n.free.fr/search_engine/")) {
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, update server is temporarily unavailable."));
}
QFile::remove(filePath);
return;
}
if(url.endsWith(".pyqBT", Qt::CaseInsensitive) || url.endsWith(".py", Qt::CaseInsensitive)) {
QString plugin_name = url.split('/').last();
plugin_name.replace(".pyqBT", "");
plugin_name.replace(".py", "");
installPlugin(filePath, plugin_name);
QFile::remove(filePath);
return;
}
#ifdef HAVE_ZZIP
if(url.endsWith(".zip", Qt::CaseInsensitive)) {
installZipPlugin(filePath);
QFile::remove(filePath);
return;
}
#endif
}
void engineSelectDlg::handleDownloadFailure(QString url, QString reason) {
if(url.endsWith("favicon.ico", Qt::CaseInsensitive)){
qDebug("Could not download favicon: %s, reason: %s", url.toUtf8().data(), reason.toUtf8().data());
return;
}
if(url == "http://www.dchris.eu/search_engine/versions.txt") {
// Primary update server failed, try secondary
qDebug("Primary update server failed, try secondary");
downloader->downloadUrl("http://hydr0g3n.free.fr/search_engine/versions.txt");
return;
}
if(url == "http://hydr0g3n.free.fr/search_engine/versions.txt") {
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, update server is temporarily unavailable."));
return;
}
if(url.endsWith(".pyqBT", Qt::CaseInsensitive) || url.endsWith(".py", Qt::CaseInsensitive)) {
// a plugin update download has been failed
QString plugin_name = url.split('/').last();
plugin_name.replace(".pyqBT", "", Qt::CaseInsensitive);
plugin_name.replace(".py", "", Qt::CaseInsensitive);
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, %1 search plugin install failed.", "%1 is the name of the search engine").arg(plugin_name.toUtf8().data()));
}
#ifdef HAVE_ZZIP
if(url.endsWith(".zip", Qt::CaseInsensitive)) {
QString plugin_name = url.split('/').last();
plugin_name.replace(".zip", "", Qt::CaseInsensitive);
QMessageBox::warning(this, tr("Search plugin update")+" -- "+tr("qBittorrent"), tr("Sorry, %1 search plugin install failed.", "%1 is the name of the search engine").arg(plugin_name.toUtf8().data()));
}
#endif
}

76
src/engineSelectDlg.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contact : chris@qbittorrent.org
*/
#ifndef ENGINE_SELECT_DLG_H
#define ENGINE_SELECT_DLG_H
#include "ui_engineSelect.h"
class downloadThread;
class QDropEvent;
class engineSelectDlg : public QDialog, public Ui::engineSelect{
Q_OBJECT
private:
// Search related
QHash<QString, bool> installed_engines;
downloadThread *downloader;
public:
engineSelectDlg(QWidget *parent);
~engineSelectDlg();
QList<QTreeWidgetItem*> findItemsWithUrl(QString url);
QTreeWidgetItem* findItemWithID(QString id);
protected:
bool parseVersionsFile(QString versions_file, QString updateServer);
bool isUpdateNeeded(QString plugin_name, float new_version) const;
bool checkInstalled(QString plugin_name) const;
signals:
void enginesChanged();
protected slots:
void saveSettings();
void on_closeButton_clicked();
void loadSupportedSearchEngines(bool first=false);
void toggleEngineState(QTreeWidgetItem*, int);
void setRowColor(int row, QString color);
void processDownloadedFile(QString url, QString filePath);
void handleDownloadFailure(QString url, QString reason);
void displayContextMenu(const QPoint& pos);
void enableSelection();
void disableSelection();
void on_actionUninstall_triggered();
void on_updateButton_clicked();
void on_installButton_clicked();
void dropEvent(QDropEvent *event);
void dragEnterEvent(QDragEnterEvent *event);
void installPlugin(QString plugin_path, QString plugin_name);
void askForLocalPlugin();
void askForPluginUrl();
#ifdef HAVE_ZZIP
void installZipPlugin(QString path);
#endif
};
#endif

186
src/eventmanager.cpp Normal file
View File

@@ -0,0 +1,186 @@
/*
* Copyright (C) 2007 by Ishan Arora
* ishanarora@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "eventmanager.h"
#include "json.h"
#include <QDebug>
EventManager::EventManager(QObject *parent)
: QObject(parent)
{
revision = 0;
}
void EventManager::update(QVariantMap event)
{
revision++;
events << QPair<ulong, QVariantMap>(revision, event);
emit updated();
qDebug("Added the following event");
qDebug() << event;
/* QLinkedList<QPair<ulong, QVariantMap> >::iterator i;
for (i = events.begin(); i != events.end(); i++)
qDebug() << *i;*/
}
QVariant EventManager::querySince(ulong r) const
{
QVariantList list;
QLinkedListIterator<QPair<ulong, QVariantMap> > i(events);
i.toBack();
while (i.hasPrevious())
{
QPair<ulong, QVariantMap> pair = i.previous();
if (pair.first <= r)
break;
list.prepend(QVariant(pair.second));
}
QVariantMap map;
map["events"] = QVariant(list);
map["revision"] = QVariant((qulonglong) revision);
return QVariant(map);
}
bool EventManager::isUpdated(ulong r) const
{
return (r < revision);
}
void EventManager::addedTorrent(QString, QTorrentHandle& h)
{
QVariantMap event;
event["type"] = QVariant("add");
event["hash"] = QVariant(h.hash());
event["name"] = QVariant(h.name());
update(event);
}
void EventManager::deletedTorrent(QString hash)
{
QVariantMap event;
event["type"] = QVariant("delete");
event["hash"] = QVariant(hash);
QLinkedList<QPair<ulong, QVariantMap> >::iterator i = events.end();
bool loop = true;
while (loop && i != events.begin()) {
--i;
QVariantMap oldevent = i->second;
if(oldevent["hash"] == QVariant(hash))
{
if(oldevent["type"] == QVariant("add"))
loop = false;
i = events.erase(i);
}
}
update(event);
}
void EventManager::modifiedTorrent(QTorrentHandle h)
{
QString hash = h.hash();
QVariantMap event;
QVariant v;
if(h.is_paused())
v = QVariant("paused");
else
{
switch(h.state())
{
case torrent_status::finished:
case torrent_status::seeding:
v = QVariant("seeding");
break;
case torrent_status::checking_files:
case torrent_status::queued_for_checking:
v = QVariant("checking");
break;
case torrent_status::connecting_to_tracker:
if(h.download_payload_rate() > 0)
v = QVariant("downloading");
else
v = QVariant("connecting");
break;
case torrent_status::downloading:
case torrent_status::downloading_metadata:
if(h.download_payload_rate() > 0)
v = QVariant("downloading");
else
v = QVariant("stalled");
break;
default:
v = QVariant();
}
}
if(modify(hash, "state", v))
event["state"] = v;
v = QVariant((qlonglong)h.actual_size());
if(modify(hash, "size", v))
event["size"] = v;
v = QVariant(h.progress());
if(modify(hash, "progress", v))
event["progress"] = v;
v = QVariant(h.download_payload_rate());
if(modify(hash, "dlspeed", v))
event["dlspeed"] = v;
v = QVariant(h.upload_payload_rate());
if(modify(hash, "upspeed", v))
event["upspeed"] = v;
if(event.size() > 0)
{
event["type"] = QVariant("modify");
event["hash"] = QVariant(hash);
update(event);
}
}
bool EventManager::modify(QString hash, QString key, QVariant value)
{
QLinkedList<QPair<ulong, QVariantMap> >::iterator i = events.end();
while (i != events.begin()) {
--i;
QVariantMap event = i->second;
if(event["hash"] == QVariant(hash))
{
if(event["type"] == QVariant("add"))
return true;
if(event.contains(key))
{
if(event[key] == value)
return false;
else
{
if(event.size() <= 3)
i = events.erase(i);
else
i->second.remove(key);
return true;
}
}
}
}
return true;
}

55
src/eventmanager.h Normal file
View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2007 by Ishan Arora
* ishanarora@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef EVENTMANAGER_H
#define EVENTMANAGER_H
#include "qtorrenthandle.h"
#include <QLinkedList>
#include <QPair>
#include <QVariant>
class EventManager : public QObject
{
Q_OBJECT
private:
ulong revision;
QLinkedList<QPair <ulong, QVariantMap> > events;
bool modify(QString hash, QString key, QVariant value);
protected:
void update(QVariantMap event);
public:
EventManager(QObject *parent = 0);
QVariant querySince(ulong r) const;
bool isUpdated(ulong r) const;
signals:
void updated();
public slots:
void addedTorrent(QString path, QTorrentHandle& h);
void deletedTorrent(QString hash);
void modifiedTorrent(QTorrentHandle h);
};
#endif

383
src/filterParserThread.h Normal file
View File

@@ -0,0 +1,383 @@
/*
* Bittorrent Client using Qt4 and libtorrent.
* Copyright (C) 2006 Christophe Dumez
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contact : chris@qbittorrent.org
*/
#ifndef FILTERPARSERTHREAD_H
#define FILTERPARSERTHREAD_H
#include <QThread>
#include <QFile>
#include <QDataStream>
#include <QMessageBox>
#include <libtorrent/session.hpp>
#include <libtorrent/ip_filter.hpp>
using namespace libtorrent;
using namespace std;
// P2B Stuff
#include <string.h>
#include <arpa/inet.h>
// End of P2B stuff
class FilterParserThread : public QThread {
Q_OBJECT
private:
session *s;
ip_filter filter;
bool abort;
QString filePath;
protected:
void run(){
qDebug("Processing filter file");
if(filePath.endsWith(".dat", Qt::CaseInsensitive)) {
// eMule DAT file
parseDATFilterFile(filePath);
} else {
if(filePath.endsWith(".p2p", Qt::CaseInsensitive)) {
// PeerGuardian p2p file
parseP2PFilterFile(filePath);
} else {
if(filePath.endsWith(".p2p", Qt::CaseInsensitive)) {
// PeerGuardian p2p file
parseP2BFilterFile(filePath);
} else {
// Default: eMule DAT format
parseDATFilterFile(filePath);
}
}
}
s->set_ip_filter(filter);
qDebug("IP Filter thread: finished parsing, filter applied");
}
public:
FilterParserThread(QObject* parent, session *s) : QThread(parent), s(s), abort(false) {
}
~FilterParserThread(){
abort = true;
wait();
}
// Parser for eMule ip filter in DAT format
void parseDATFilterFile(QString filePath) {
const QRegExp is_ipv6(QString::fromUtf8("^[0-9a-f]{4}(:[0-9a-f]{4}){7}$"), Qt::CaseInsensitive, QRegExp::RegExp);
const QRegExp is_ipv4(QString::fromUtf8("^(([0-1]?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))(\\.(([0-1]?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))){3}$"), Qt::CaseInsensitive, QRegExp::RegExp);
QString strStartIP, strEndIP;
bool IPv4 = true;
QFile file(filePath);
if (file.exists()){
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
QMessageBox::critical(0, tr("I/O Error", "Input/Output Error"), tr("Couldn't open %1 in read mode.").arg(filePath));
return;
}
unsigned int nbLine = 0;
while (!file.atEnd() && !abort) {
++nbLine;
QByteArray line = file.readLine();
// Ignoring empty lines
line = line.trimmed();
if(line.isEmpty()) continue;
// Ignoring commented lines
if(line.startsWith('#') || line.startsWith("//")) continue;
// Line is not commented
QList<QByteArray> partsList = line.split(',');
unsigned int nbElem = partsList.size();
// IP Range can be splitted by a dash or a comma...
// Check if there is a dash in first part
QByteArray firstPart = partsList.at(0);
int nbAccess = 0;
if(firstPart.contains('-')) {
// Range is splitted by a dash
QList<QByteArray> IPs = firstPart.split('-');
if(IPs.size() != 2) {
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
continue;
}
strStartIP = IPs.at(0).trimmed();
strEndIP = IPs.at(1).trimmed();
// Check if IPs are correct
if(strStartIP.contains(is_ipv4) && strEndIP.contains(is_ipv4)) {
IPv4 = true;
} else {
if(strStartIP.contains(is_ipv6) && strEndIP.contains(is_ipv6)) {
IPv4 = false;
} else {
// Could not determine IP format
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
continue;
}
}
// Check if there is an access value (apparently not mandatory)
if(nbElem > 1) {
// There is possibly one
bool ok;
nbAccess = partsList.at(1).trimmed().toInt(&ok);
if(!ok){
nbAccess = 0;
}
}
} else {
// Range is probably splitted by a comma
unsigned int nbElem = partsList.size();
if(nbElem > 1) {
strStartIP = firstPart.trimmed();
strEndIP = partsList.at(1).trimmed();
// Check if IPs are correct
if(strStartIP.contains(is_ipv4) && strEndIP.contains(is_ipv4)) {
IPv4 = true;
} else {
if(strStartIP.contains(is_ipv6) && strEndIP.contains(is_ipv6)) {
IPv4 = false;
} else {
// Could not determine IP format
qDebug("Ipfilter.dat: line %d is malformed.", nbLine);
continue;
}
}
// Check if there is an access value (apparently not mandatory)
if(nbElem > 2) {
// There is possibly one
bool ok;
nbAccess = partsList.at(2).trimmed().toInt(&ok);
if(!ok){
nbAccess = 0;
}
}
}
}
if(nbAccess > 127) {
// Ignoring this rule because access value is too high
continue;
}
// Now Add to the filter
QStringList IP;
if(IPv4) {
//IPv4 addresses
IP = strStartIP.split('.');
address_v4 start((IP.at(0).toInt() << 24) + (IP.at(1).toInt() << 16) + (IP.at(2).toInt() << 8) + IP.at(3).toInt());
IP = strEndIP.split('.');
address_v4 last((IP.at(0).toInt() << 24) + (IP.at(1).toInt() << 16) + (IP.at(2).toInt() << 8) + IP.at(3).toInt());
// Apply to bittorrent session
filter.add_rule(start, last, ip_filter::blocked);
} else {
// IPv6, ex : 1fff:0000:0a88:85a3:0000:0000:ac1f:8001
IP = strStartIP.split(':');
address_v6 start = address_v6::from_string(strStartIP.remove(':', 0).toUtf8().data());
IP = strEndIP.split(':');
address_v6 last = address_v6::from_string(strEndIP.remove(':', 0).toUtf8().data());
// Apply to bittorrent session
filter.add_rule(start, last, ip_filter::blocked);
}
}
file.close();
}
}
// Parser for PeerGuardian ip filter in p2p format
void parseP2PFilterFile(QString filePath) {
const QRegExp is_ipv4(QString::fromUtf8("^(([0-1]?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))(\\.(([0-1]?[0-9]?[0-9])|(2[0-4][0-9])|(25[0-5]))){3}$"), Qt::CaseInsensitive, QRegExp::RegExp);
QFile file(filePath);
QStringList IP;
if (file.exists()){
if(!file.open(QIODevice::ReadOnly | QIODevice::Text)){
QMessageBox::critical(0, tr("I/O Error", "Input/Output Error"), tr("Couldn't open %1 in read mode.").arg(filePath));
return;
}
unsigned int nbLine = 0;
while (!file.atEnd() && !abort) {
++nbLine;
QByteArray line = file.readLine();
// Ignoring empty lines
line = line.trimmed();
if(line.isEmpty()) continue;
// Ignoring commented lines
if(line.startsWith('#') || line.startsWith("//")) continue;
// Line is not commented
QList<QByteArray> partsList = line.split(':');
if(partsList.size() < 2){
qDebug("p2p file: line %d is malformed.", nbLine);
continue;
}
// Get IP range
QList<QByteArray> IPs = partsList.last().split('-');
if(IPs.size() != 2) {
qDebug("p2p file: line %d is malformed.", nbLine);
continue;
}
QString strStartIP = IPs.at(0).trimmed();
QString strEndIP = IPs.at(1).trimmed();
// Check IPs format (IPv4 only)
if(strStartIP.contains(is_ipv4) && strEndIP.contains(is_ipv4)) {
// IPv4
IP = strStartIP.split('.');
address_v4 start((IP.at(0).toInt() << 24) + (IP.at(1).toInt() << 16) + (IP.at(2).toInt() << 8) + IP.at(3).toInt());
IP = strEndIP.split('.');
address_v4 last((IP.at(0).toInt() << 24) + (IP.at(1).toInt() << 16) + (IP.at(2).toInt() << 8) + IP.at(3).toInt());
// Apply to bittorrent session
filter.add_rule(start, last, ip_filter::blocked);
} else {
qDebug("p2p file: line %d is malformed.", nbLine);
continue;
}
}
file.close();
}
}
int getlineInStream(QDataStream& stream, string& name, char delim) {
char c;
int total_read = 0;
do {
int read = stream.readRawData(&c, 1);
total_read += read;
if(read > 0) {
if(c != delim) {
name += c;
} else {
// Delim found
return total_read;
}
}
} while(read > 0);
return total_read;
}
// Parser for PeerGuardian ip filter in p2p format
void parseP2BFilterFile(QString filePath) {
QFile file(filePath);
if (file.exists()){
if(!file.open(QIODevice::ReadOnly)){
QMessageBox::critical(0, tr("I/O Error", "Input/Output Error"), tr("Couldn't open %1 in read mode.").arg(filePath));
return;
}
QDataStream stream(&file);
// Read header
char buf[7];
unsigned char version;
if(
!stream.readRawData(buf, sizeof(buf)) ||
memcmp(buf, "\xFF\xFF\xFF\xFFP2B", 7) ||
!stream.readRawData((char*)&version, sizeof(version))
) {
QMessageBox::critical(0, tr("I/O Error", "Input/Output Error"), tr("%1 is not a valid PeerGuardian P2B file.").arg(filePath));
return;
}
if(version==1 || version==2) {
qDebug ("p2b version 1 or 2");
unsigned int start, end;
string name;
while(getlineInStream(stream, name, '\0') && !abort) {
if(
!stream.readRawData((char*)&start, sizeof(start)) ||
!stream.readRawData((char*)&end, sizeof(end))
) {
QMessageBox::critical(0, tr("I/O Error", "Input/Output Error"), tr("%1 is not a valid PeerGuardian P2B file.").arg(filePath));
return;
}
// Network byte order to Host byte order
// asio address_v4 contructor expects it
// that way
address_v4 first(ntohl(start));
address_v4 last(ntohl(end));
// Apply to bittorrent session
filter.add_rule(first, last, ip_filter::blocked);
}
}
else if(version==3) {
qDebug ("p2b version 3");
unsigned int namecount;
if(!stream.readRawData((char*)&namecount, sizeof(namecount))) {
QMessageBox::critical(0, tr("I/O Error", "Input/Output Error"), tr("%1 is not a valid PeerGuardian P2B file.").arg(filePath));
return;
}
namecount=ntohl(namecount);
// Reading names although, we don't really care about them
for(unsigned int i=0; i<namecount; i++) {
string name;
if(!getlineInStream(stream, name, '\0')) {
QMessageBox::critical(0, tr("I/O Error", "Input/Output Error"), tr("%1 is not a valid PeerGuardian P2B file.").arg(filePath));
return;
}
if(abort) return;
}
// Reading the ranges
unsigned int rangecount;
if(!stream.readRawData((char*)&rangecount, sizeof(rangecount))) {
QMessageBox::critical(0, tr("I/O Error", "Input/Output Error"), tr("%1 is not a valid PeerGuardian P2B file.").arg(filePath));
return;
}
rangecount=ntohl(rangecount);
unsigned int name, start, end;
for(unsigned int i=0; i<rangecount; i++) {
if(
!stream.readRawData((char*)&name, sizeof(name)) ||
!stream.readRawData((char*)&start, sizeof(start)) ||
!stream.readRawData((char*)&end, sizeof(end))
) {
QMessageBox::critical(0, tr("I/O Error", "Input/Output Error"), tr("%1 is not a valid PeerGuardian P2B file.").arg(filePath));
return;
}
// Network byte order to Host byte order
// asio address_v4 contructor expects it
// that way
address_v4 first(ntohl(start));
address_v4 last(ntohl(end));
// Apply to bittorrent session
filter.add_rule(first, last, ip_filter::blocked);
if(abort) return;
}
} else {
QMessageBox::critical(0, tr("I/O Error", "Input/Output Error"), tr("%1 is not a valid PeerGuardian P2B file.").arg(filePath));
return;
}
file.close();
}
}
// Process ip filter file
// Supported formats:
// * eMule IP list (DAT): http://wiki.phoenixlabs.org/wiki/DAT_Format
// * PeerGuardian Text (P2P): http://wiki.phoenixlabs.org/wiki/P2P_Format
// * PeerGuardian Binary (P2B): http://wiki.phoenixlabs.org/wiki/P2B_Format
void processFilterFile(QString _filePath){
if(isRunning()) {
// Already parsing a filter, abort first
abort = true;
wait();
}
abort = false;
filePath = _filePath;
// Run it
start();
}
};
#endif

204
src/httpconnection.cpp Normal file
View File

@@ -0,0 +1,204 @@
/*
* Copyright (C) 2007 by Ishan Arora
* ishanarora@gmail.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "httpconnection.h"
#include "httpserver.h"
#include "eventmanager.h"
#include "json.h"
#include <QTcpSocket>
#include <QDateTime>
#include <QStringList>
#include <QHttpRequestHeader>
#include <QHttpResponseHeader>
#include <QFile>
#include <QDebug>
HttpConnection::HttpConnection(QTcpSocket *socket, HttpServer *parent)
: QObject(parent), socket(socket), parent(parent)
{
socket->setParent(this);
connect(socket, SIGNAL(readyRead()), this, SLOT(read()));
connect(socket, SIGNAL(disconnected()), this, SLOT(deleteLater()));
}
HttpConnection::~HttpConnection()
{
}
void HttpConnection::read()
{
QString input = socket->readAll();
qDebug(" -------");
qDebug("|REQUEST|");
qDebug(" -------");
qDebug(input.toAscii().constData());
parser.write(input);
if(parser.isError())
{
generator.setStatusLine(400, "Bad Request");
write();
}
else
if (parser.isParsable())
respond();
}
void HttpConnection::write()
{
QByteArray output = generator.toByteArray();
qDebug(" --------");
qDebug("|RESPONSE|");
qDebug(" --------");
qDebug()<<output;
socket->write(output);
socket->disconnectFromHost();
}
void HttpConnection::respond()
{
QStringList auth = parser.value("Authorization").split(" ", QString::SkipEmptyParts);
if (auth.size() != 2 || QString::compare(auth[0], "Basic", Qt::CaseInsensitive) != 0 || !parent->isAuthorized(auth[1].toUtf8()))
{
generator.setStatusLine(401, "Unauthorized");
generator.setValue("WWW-Authenticate", "Basic realm=\"you know what\"");
write();
return;
}
QString url = parser.url();
QStringList list = url.split('/', QString::SkipEmptyParts);
if (list.contains(".") || list.contains(".."))
{
respondNotFound();
return;
}
if (list.size() == 0)
list.append("index.html");
if (list.size() == 2)
{
if (list[0] == "json")
{
if (list[1] == "events")
{
EventManager* manager = parent->eventManager();
uint r = parser.get("r").toUInt();
if(manager->isUpdated(r))
respondJson();
else
connect(manager, SIGNAL(updated()), this, SLOT(respondJson()));
return;
}
}
if (list[0] == "command")
{
QString command = list[1];
respondCommand(command);
generator.setStatusLine(200, "OK");
write();
return;
}
}
if (list[0] == "images")
list[0] = "Icons";
else
list.prepend("webui");
url = ":/" + list.join("/");
QFile file(url);
if(!file.open(QIODevice::ReadOnly))
{
respondNotFound();
return;
}
QString ext = list.last();
int index = ext.lastIndexOf('.') + 1;
if (index > 0)
ext.remove(0, index);
else
ext.clear();
QByteArray data = file.readAll();
generator.setStatusLine(200, "OK");
generator.setContentTypeByExt(ext);
generator.setMessage(data);
write();
}
void HttpConnection::respondNotFound()
{
generator.setStatusLine(404, "File not found");
write();
}
void HttpConnection::respondJson()
{
EventManager* manager = parent->eventManager();
QString temp = parser.get("r");
uint r = parser.get("r").toUInt();
QVariant data = manager->querySince(r);
QString string = toJson(data);
generator.setStatusLine(200, "OK");
generator.setContentTypeByExt("js");
generator.setMessage(string);
write();
}
void HttpConnection::respondCommand(QString command)
{
if(command == "download")
{
QString urls = parser.post("urls");
QStringList list = urls.split('\n');
QStringList url_list_cleaned;
foreach(QString url, list){
url = url.trimmed();
if(!url.isEmpty()){
if(url_list_cleaned.indexOf(QRegExp(url, Qt::CaseInsensitive, QRegExp::FixedString)) < 0){
url_list_cleaned << url;
}
}
}
emit urlsReadyToBeDownloaded(url_list_cleaned);
return;
}
if(command == "resumeall")
{
emit resumeAllTorrents();
return;
}
if(command == "pauseall")
{
emit pauseAllTorrents();
return;
}
if(command == "resume")
{
emit resumeTorrent(parser.post("hash"));
return;
}
if(command == "pause")
{
emit pauseTorrent(parser.post("hash"));
return;
}
if(command == "delete")
{
emit deleteTorrent(parser.post("hash"));
return;
}
}

Some files were not shown because too many files have changed in this diff Show More