Compare commits
	
		
			179 Commits
		
	
	
		
			release-2.
			...
			release-2.
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 6cf2b44b8a | ||
|   | ba22fa8331 | ||
|   | 5ce02cb612 | ||
|   | 1013f39a42 | ||
|   | cd5c4bf464 | ||
|   | 84bfc54b03 | ||
|   | 5b3b5eb2ef | ||
|   | 990a863d41 | ||
|   | 7f27d10735 | ||
|   | 1377a75a53 | ||
|   | bcd33fc861 | ||
|   | 46d8fa1656 | ||
|   | 28cf69b84d | ||
|   | 89389df74d | ||
|   | 77c29f48cb | ||
|   | c5d92f3d69 | ||
|   | 54487c8247 | ||
|   | be64008870 | ||
|   | 8113b150dd | ||
|   | 4a33367cb0 | ||
|   | 0af5d82114 | ||
|   | 10c4fd330a | ||
|   | 9a30d5a295 | ||
|   | 724b47d999 | ||
|   | 2c0f7c33a2 | ||
|   | ce33e266fe | ||
|   | 2f291daefa | ||
|   | 722f2aeb5d | ||
|   | d5b9598b5b | ||
|   | cc7d74b67c | ||
|   | e853b0b736 | ||
|   | 5e395b24a9 | ||
|   | 9c3789f83f | ||
|   | 758595dc8c | ||
|   | 01f9e989ef | ||
|   | eb9f0cb559 | ||
|   | 2592948182 | ||
|   | 6f6ab1c439 | ||
|   | b10e606dda | ||
|   | 9034094cf9 | ||
|   | c48766aeb7 | ||
|   | 28a6afeb02 | ||
|   | c8d0f5a104 | ||
|   | 3c396257de | ||
|   | a9be841d2d | ||
|   | 7d0581a7a5 | ||
|   | 4efeb66b73 | ||
|   | 3b05f8b4b4 | ||
|   | 6b4f09d740 | ||
|   | f1b02c1280 | ||
|   | 3d546a4c5d | ||
|   | 19368bcefa | ||
|   | dbbf26449c | ||
|   | 8f28804f8c | ||
|   | b7edfea4ce | ||
|   | 23b2f94c40 | ||
|   | 8f40f41fef | ||
|   | 33f868144b | ||
|   | b2545bb709 | ||
|   | 3b6e1e82d9 | ||
|   | 7710c88797 | ||
|   | 4d5001d18d | ||
|   | 0f4f108eb5 | ||
|   | f0d0bb7170 | ||
|   | 66157da5c2 | ||
|   | 13493e1afe | ||
|   | f6bfacda2c | ||
|   | f7a86b5484 | ||
|   | 66cd3f8184 | ||
|   | 3a237c93be | ||
|   | 4c34066727 | ||
|   | 1960008c83 | ||
|   | deffbd6321 | ||
|   | 53927c9aa0 | ||
|   | d84346616a | ||
|   | e1183dbc0b | ||
|   | 602f1574ca | ||
|   | 358f7d16da | ||
|   | e4006d6175 | ||
|   | 949b4ce4e9 | ||
|   | cbafac8ea9 | ||
|   | e4bf116ce8 | ||
|   | bccdad4b1b | ||
|   | 9b372b3cce | ||
|   | 98d0c00f85 | ||
|   | 9d2f2230ee | ||
|   | 81c6958428 | ||
|   | f976eda6a9 | ||
|   | fe8d5a3528 | ||
|   | 240c3508fe | ||
|   | 1065f5fb86 | ||
|   | 2b37986007 | ||
|   | 22d0c4a241 | ||
|   | dd47ce6767 | ||
|   | 5c80ce42e0 | ||
|   | adb727d282 | ||
|   | e17ca355ae | ||
|   | b80940ac4f | ||
|   | 1eca139db9 | ||
|   | 25278beb2f | ||
|   | 5922ffff62 | ||
|   | ff084e9681 | ||
|   | 86e5d219d2 | ||
|   | b78e0a54ed | ||
|   | 4bfacb8b91 | ||
|   | e9ad58a373 | ||
|   | 09c48539ad | ||
|   | 3693ecdd30 | ||
|   | ddc66e6005 | ||
|   | fd0b1f8931 | ||
|   | 1a4f638ff6 | ||
|   | 77239db3c5 | ||
|   | 0ea59c8d58 | ||
|   | 54e2a8c7fe | ||
|   | 245a8e0a3a | ||
|   | 51e474c893 | ||
|   | 81d3e64518 | ||
|   | 95da161be3 | ||
|   | 8618f13b7a | ||
|   | e24e7578f2 | ||
|   | a03ad3de23 | ||
|   | 9bd40a9b79 | ||
|   | b4b61b9b7d | ||
|   | 5656fe9a9b | ||
|   | fb79146ae6 | ||
|   | ba27191b2a | ||
|   | dc87aa3d5c | ||
|   | 83cf3aebab | ||
|   | dedd9bd03c | ||
|   | ab36a358b7 | ||
|   | 6ea97f09cf | ||
|   | 5f7822d202 | ||
|   | 6a87225dd0 | ||
|   | b6f56c0812 | ||
|   | c4ce2a2549 | ||
|   | 41650da297 | ||
|   | 74c61e6805 | ||
|   | e8dd7bbcc9 | ||
|   | 335d012d55 | ||
|   | 17fc58840a | ||
|   | 0e8c55b9f5 | ||
|   | d581f653c6 | ||
|   | 48dbaf05ae | ||
|   | 540da69d61 | ||
|   | 06efd64a80 | ||
|   | 62d872984b | ||
|   | 1dd11dd8f8 | ||
|   | 2ce375d8eb | ||
|   | 8ed0e58d63 | ||
|   | 660a6929fd | ||
|   | 44f6c972d4 | ||
|   | 6a6077bf1d | ||
|   | 30234a4e78 | ||
|   | dc9edf7538 | ||
|   | 92574458d0 | ||
|   | c35ef9ad15 | ||
|   | 4059bcc0fa | ||
|   | 1840d1c49f | ||
|   | cbd948f6f3 | ||
|   | 454c093033 | ||
|   | 45eaf7ce58 | ||
|   | 04b7af4df5 | ||
|   | 8c6978be82 | ||
|   | 6c9e7156f7 | ||
|   | bc89845523 | ||
|   | 9ffe9c2006 | ||
|   | 1d598d7772 | ||
|   | 7f576ccc82 | ||
|   | d5da8a6277 | ||
|   | a297204b27 | ||
|   | e0182bb03e | ||
|   | ca5bf5e9d7 | ||
|   | 5475d730ff | ||
|   | 7796520580 | ||
|   | 340500c351 | ||
|   | 043d33ff91 | ||
|   | baf991b342 | ||
|   | dc47e90126 | ||
|   | 67e3f9e686 | 
							
								
								
									
										5
									
								
								AUTHORS
									
									
									
									
									
								
							
							
						
						| @@ -6,6 +6,7 @@ Contributors: | ||||
| * Ishan Arora <ishan@qbittorrent.org> | ||||
| * Arnaud Demaizière <arnaud@qbittorrent.org> | ||||
| * Grigis Gaëtan <cipher16@gmail.com> | ||||
| * Christian Kandeler <zambesi@users.sourceforge.net> | ||||
|  | ||||
| Code from other projects: | ||||
| * files src/ico.cpp src/ico.h | ||||
| @@ -60,7 +61,7 @@ Translations authors: | ||||
| * files: src/lang/*.ts | ||||
|   copyright: | ||||
|   - Brazilian: Nick Marinho (nickmarinho@gmail.com) | ||||
|   - Bulgarian: Tsvetan & Boiko Bankov (emerge_life@users.sourceforge.net) | ||||
|   - Bulgarian: Tsvetan & Boyko Bankoff (emerge_life@users.sourceforge.net) | ||||
|   - Catalan: Francisco Luque Contreras (frannoe@ya.com) | ||||
|   - Chinese (Simplified): Guo Yue (yue.guo0418@gmail.com) | ||||
|   - Chinese (Traditional): Yi-Shun Wang (dnextstep@gmail.com) | ||||
| @@ -86,5 +87,5 @@ Translations authors: | ||||
|   - Spanish: Francisco Luque Contreras (frannoe@ya.com) | ||||
|   - Swedish: Daniel Nylander (po@danielnylander.se) | ||||
|   - Turkish: Hasan Yilmaz (iletisim@hedefturkce.com) | ||||
|   - Ukrainian: Andrey Shpachenko (masterfix@users.sourceforge.net) | ||||
|   - Ukrainian: Andrey Shpachenko (masterfix@users.sourceforge.net) and Oleh Prypin (blaxpirit@gmail.com) | ||||
|   license: GPLv2 | ||||
|   | ||||
							
								
								
									
										62
									
								
								Changelog
									
									
									
									
									
								
							
							
						
						| @@ -1,17 +1,51 @@ | ||||
| * Wed Jan 20 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.1.1 | ||||
|     - BUGFIX: Fix compilation with Qt4.4 | ||||
|     - BUGFIX: Save torrent metadata so that it does not have to be re-downloaded on restart (Magnet links) | ||||
|     - BUGFIX: Fix folder renaming in a torrent (would rename children under certain conditions) | ||||
|     - BUGFIX: Nox version no longer requires libQtXml | ||||
|     - BUGFIX: Configure file now checks for pkg-config executable which is required | ||||
|     - BUGFIX: Torrents added from magnet links were not remembered on restart | ||||
|     - BUGFIX: "Add in pause" setting can be ignored from torrent addition dialog | ||||
|     - BUGFIX: Fix renaming of files with unicode characters in their name | ||||
|     - BUGFIX: Fix typo in legal notice (startup) | ||||
|     - BUGFIX: Can listen on ports < 1024 (must be root) | ||||
|     - BUGFIX: Paused torrents can now be rechecked | ||||
|     - BUGFIX: Fix "open torrent destination" feature when path contains spaces | ||||
|     - I18N: Updated translations (Hungarian, Chinese, Russian) | ||||
| * Sun Apr 04 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.2.3 | ||||
|     - BUGFIX: Fix possible crash when deleting a torrent just after pausing it | ||||
|     - BUGFIX: Enable Apply button when alternative rate limits are changed | ||||
|     - BUGFIX: Source compatibility with Windows (Thanks Ishan Arora) | ||||
|     - BUGFIX: Source compatibility with eCS (OS/2) (Thanks Silvan Scherrer) | ||||
|     - BUGFIX: Cleaner binutils gold linker support | ||||
|     - BUGFIX: Clean fix for progress display with cleanlooks style | ||||
|  | ||||
| * Mon Mar 22 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.2.2 | ||||
|     - FEATURE: DHT port can be set from Web UI | ||||
|     - BUGFIX: Fix possible crash with folder scanning | ||||
|     - BUGFIX: Fix Mac compilation | ||||
|     - BUGFIX: Save fast resume data every 3 minutes (for robustness) | ||||
|     - I18N: Updated Polish translation (thanks Szymon Świerkosz) | ||||
|  | ||||
| * Sat Mar 20 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.2.1 | ||||
|     - FEATURE: Display pieces that are being downloaded | ||||
|     - FEATURE: Added back folder watching in Web UI | ||||
|     - FEATURE: Added back file prioritizing in Web UI | ||||
|     - BUGFIX: Fix compilation with Qt 4.4 | ||||
|     - BUGFIX: Fix Web UI compatibility with Safari | ||||
|     - BUGFIX: Fix progress display with cleanlook style | ||||
|     - BUGFIX: Fix file filtering in complex torrents | ||||
|     - BUGFIX: Ask for user confirmation for recursive torrent download | ||||
|     - BUGFIX: Fix "add file" dialog in torrent creation tool | ||||
|     - BUGFIX: Fix "Ctrl+A" in Web UI | ||||
|  | ||||
| * Sun Mar 14 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.2.0 | ||||
|     - FEATURE: User can set alternative speed limits for fast toggling | ||||
|     - FEATURE: Bandwidth scheduler (automatically use alternative speed limits for a given period) | ||||
|     - FEATURE: Added "Added/Completed On" columns to transfer list | ||||
|     - FEATURE: Added "Upload/Download limit" columns to transfer list | ||||
|     - FEATURE: Torrent files can be exported to a given directory | ||||
|     - FEATURE: Outgoing ports range can be customized (for QoS) | ||||
|     - FEATURE: User can choose to apply transfer limits on LAN too | ||||
|     - FEATURE: User can choose to include the protocol overhead in transfer limits | ||||
|     - FEATURE: Torrents can be automatically rechecked on completion | ||||
|     - FEATURE: If 2 torrents have the same hash, add new trackers/URL seeds to the existing torrent | ||||
|     - FEATURE: Trackers can be added from Web UI | ||||
|     - FEATURE: Global transfer information are displayed in the new Web UI status bar | ||||
|     - FEATURE: Allow to change the priority of several files at once | ||||
|     - FEATURE: Support for multiple scan folders (Patch by Christian Kandeler) | ||||
|     - BUGFIX: Only one log window can be opened at a time | ||||
|     - BUGFIX: Optimized RSS module memory usage | ||||
|     - BUGFIX: Consider HTTP downloads >1MB as invalid .torrent files and abort | ||||
|     - BUGFIX: Fix Web UI authentication with some browsers | ||||
|     - BUGFIX: Set Web UI ban period to 1 hour | ||||
|     - COSMETIC: Improved style management | ||||
|  | ||||
| * Mon Jan 18 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.1.0 | ||||
|     - FEATURE: Graphical User Interface can be disabled at compilation time (headless running) | ||||
|   | ||||
							
								
								
									
										49
									
								
								configure
									
									
									
									
										vendored
									
									
								
							
							
						
						| @@ -21,6 +21,7 @@ Dependency options: | ||||
|   --disable-gui                      Disable qBittorrent Graphical user | ||||
|                                     interface for headless running | ||||
|   --with-libboost-inc=[path]         Path to libboost include files | ||||
|   --with-libboost-lib=[path]         Path to libboost library files | ||||
|   --disable-libnotify               Disable use of libnotify | ||||
|   --disable-geoip-database          Disable use of geoip-database | ||||
|   --with-geoip-database-embedded     Geoip Database will be embedded in | ||||
| @@ -152,6 +153,11 @@ while [ $# -gt 0 ]; do | ||||
| 			shift | ||||
| 			;; | ||||
|  | ||||
| 		--with-libboost-lib=*) | ||||
| 			QC_WITH_LIBBOOST_LIB=$optarg | ||||
| 			shift | ||||
| 			;; | ||||
|  | ||||
| 		--disable-libnotify) | ||||
| 			QC_DISABLE_libnotify="Y" | ||||
| 			shift | ||||
| @@ -190,6 +196,7 @@ echo DATADIR=$DATADIR | ||||
| echo EX_QTDIR=$EX_QTDIR | ||||
| echo QC_DISABLE_GUI=$QC_DISABLE_GUI | ||||
| echo QC_WITH_LIBBOOST_INC=$QC_WITH_LIBBOOST_INC | ||||
| echo QC_WITH_LIBBOOST_LIB=$QC_WITH_LIBBOOST_LIB | ||||
| echo QC_DISABLE_libnotify=$QC_DISABLE_libnotify | ||||
| echo QC_DISABLE_geoip_database=$QC_DISABLE_geoip_database | ||||
| echo QC_WITH_GEOIP_DATABASE_EMBEDDED=$QC_WITH_GEOIP_DATABASE_EMBEDDED | ||||
| @@ -312,11 +319,7 @@ public: | ||||
| 		if(!conf->getenv("QC_DISABLE_GUI").isEmpty()) { | ||||
| 			conf->addDefine("DISABLE_GUI"); | ||||
| 		}	 | ||||
| 		if(QT_VERSION >= 0x040500) { | ||||
|                         conf->addDefine("QT_4_5"); | ||||
|                 } | ||||
| 		return(QT_VERSION >= 0x040400); | ||||
| 		 | ||||
| 	} | ||||
| }; | ||||
| #line 1 "pkg-config.qcm" | ||||
| @@ -359,12 +362,20 @@ public: | ||||
| 			return false; | ||||
| 		for(int n = 0; n < incs.count(); ++n) | ||||
| 			conf->addIncludePath(incs[n]); | ||||
| 		if(!libs.isEmpty()) | ||||
| 			conf->addLib(libs); | ||||
| 		//if(!libs.isEmpty()) | ||||
| 		//	conf->addLib(libs); | ||||
| 		if(!conf->findPkgConfig("libtorrent-rasterbar", mode, adv_ver, &version, &incs, &libs, &other)) | ||||
|                         printf("\nWarning: libtorrent-rasterbar v%s was detected. Some feature will be disabled because they require v%s.\n", version.toLocal8Bit().data(), adv_ver.toUtf8().data()); | ||||
| 		else | ||||
| 			conf->addDefine("LIBTORRENT_0_15"); | ||||
| 		// Get linking parameters | ||||
| 		//QStringList params; | ||||
| 		//QByteArray staticlibs; | ||||
| 		//params << "--static" << "--libs" << "libtorrent-rasterbar"; | ||||
| 		//conf->doCommand("pkg-config", params, &staticlibs); | ||||
| 		//conf->addLib(staticlibs.trimmed()); | ||||
| 		//libcrypto | ||||
| 		conf->addLib("-lcrypto"); | ||||
| 		return true; | ||||
| 	} | ||||
| }; | ||||
| @@ -373,6 +384,7 @@ public: | ||||
| -----BEGIN QCMOD----- | ||||
| name: libboost | ||||
| arg: with-libboost-inc=[path], Path to libboost include files | ||||
| arg: with-libboost-lib=[path], Path to libboost library files | ||||
| -----END QCMOD----- | ||||
| */ | ||||
| class qc_libboost : public ConfObj | ||||
| @@ -422,6 +434,30 @@ public: | ||||
|       			} | ||||
| 		} | ||||
| 		conf->addIncludePath(s); | ||||
| 		// Find library | ||||
| 		s = conf->getenv("QC_WITH_LIBBOOST_LIB"); | ||||
|                 if(!s.isEmpty()) { | ||||
|                         if(!conf->checkLibrary(s, "boost_system-mt")) { | ||||
|                                 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, "boost_system-mt")) { | ||||
|                                         found = true; | ||||
|                                         break; | ||||
|                                 } | ||||
|                         } | ||||
|                         if(!found) | ||||
|                                 return false; | ||||
|                 } | ||||
|                 conf->addLib(QString("-L") + s); | ||||
| 		conf->addLib("-lboost_system-mt -lboost_filesystem-mt -lboost_thread-mt"); | ||||
| 		return true; | ||||
| 	} | ||||
| }; | ||||
| @@ -1481,6 +1517,7 @@ export DATADIR | ||||
| export EX_QTDIR | ||||
| export QC_DISABLE_GUI | ||||
| export QC_WITH_LIBBOOST_INC | ||||
| export QC_WITH_LIBBOOST_LIB | ||||
| export QC_DISABLE_libnotify | ||||
| export QC_DISABLE_geoip_database | ||||
| export QC_WITH_GEOIP_DATABASE_EMBEDDED | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| -----BEGIN QCMOD----- | ||||
| name: libboost | ||||
| arg: with-libboost-inc=[path], Path to libboost include files | ||||
| arg: with-libboost-lib=[path], Path to libboost library files | ||||
| -----END QCMOD----- | ||||
| */ | ||||
| class qc_libboost : public ConfObj | ||||
| @@ -51,6 +52,30 @@ public: | ||||
|       			} | ||||
| 		} | ||||
| 		conf->addIncludePath(s); | ||||
| 		// Find library | ||||
| 		s = conf->getenv("QC_WITH_LIBBOOST_LIB"); | ||||
|                 if(!s.isEmpty()) { | ||||
|                         if(!conf->checkLibrary(s, "boost_system-mt")) { | ||||
|                                 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, "boost_system-mt")) { | ||||
|                                         found = true; | ||||
|                                         break; | ||||
|                                 } | ||||
|                         } | ||||
|                         if(!found) | ||||
|                                 return false; | ||||
|                 } | ||||
|                 conf->addLib(QString("-L") + s); | ||||
| 		conf->addLib("-lboost_system-mt -lboost_filesystem-mt -lboost_thread-mt"); | ||||
| 		return true; | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -20,12 +20,20 @@ public: | ||||
| 			return false; | ||||
| 		for(int n = 0; n < incs.count(); ++n) | ||||
| 			conf->addIncludePath(incs[n]); | ||||
| 		if(!libs.isEmpty()) | ||||
| 			conf->addLib(libs); | ||||
| 		//if(!libs.isEmpty()) | ||||
| 		//	conf->addLib(libs); | ||||
| 		if(!conf->findPkgConfig("libtorrent-rasterbar", mode, adv_ver, &version, &incs, &libs, &other)) | ||||
|                         printf("\nWarning: libtorrent-rasterbar v%s was detected. Some feature will be disabled because they require v%s.\n", version.toLocal8Bit().data(), adv_ver.toUtf8().data()); | ||||
| 		else | ||||
| 			conf->addDefine("LIBTORRENT_0_15"); | ||||
| 		// Get linking parameters | ||||
| 		//QStringList params; | ||||
| 		//QByteArray staticlibs; | ||||
| 		//params << "--static" << "--libs" << "libtorrent-rasterbar"; | ||||
| 		//conf->doCommand("pkg-config", params, &staticlibs); | ||||
| 		//conf->addLib(staticlibs.trimmed()); | ||||
| 		//libcrypto | ||||
| 		conf->addLib("-lcrypto"); | ||||
| 		return true; | ||||
| 	} | ||||
| }; | ||||
|   | ||||
| @@ -15,10 +15,6 @@ public: | ||||
| 		if(!conf->getenv("QC_DISABLE_GUI").isEmpty()) { | ||||
| 			conf->addDefine("DISABLE_GUI"); | ||||
| 		}	 | ||||
| 		if(QT_VERSION >= 0x040500) { | ||||
|                         conf->addDefine("QT_4_5"); | ||||
|                 } | ||||
| 		return(QT_VERSION >= 0x040400); | ||||
| 		 | ||||
| 	} | ||||
| }; | ||||
|   | ||||
							
								
								
									
										178
									
								
								src/GUI.cpp
									
									
									
									
									
								
							
							
						
						
							
								
								
									
										106
									
								
								src/GUI.h
									
									
									
									
									
								
							
							
						
						| @@ -55,43 +55,28 @@ class TransferListFiltersWidget; | ||||
| class QSplitter; | ||||
| class PropertiesWidget; | ||||
| class StatusBar; | ||||
| class consoleDlg; | ||||
| class about; | ||||
| class createtorrent; | ||||
| class downloadFromURL; | ||||
|  | ||||
| class GUI : public QMainWindow, private Ui::MainWindow{ | ||||
|   Q_OBJECT | ||||
|  | ||||
| private: | ||||
|   // Bittorrent | ||||
|   Bittorrent *BTSession; | ||||
|   QList<QPair<QTorrentHandle,QString> > unauthenticated_trackers; // Still needed? | ||||
|   // GUI related | ||||
|   QTimer *guiUpdater; | ||||
|   QTabWidget *tabs; | ||||
|   StatusBar *status_bar; | ||||
|   QPointer<options_imp> options; | ||||
|   QPointer<QSystemTrayIcon> systrayIcon; | ||||
|   QPointer<QTimer> systrayCreator; | ||||
|   QMenu *myTrayIconMenu; | ||||
|   TransferListWidget *transferList; | ||||
|   TransferListFiltersWidget *transferListFilters; | ||||
|   PropertiesWidget *properties; | ||||
|   bool displaySpeedInTitle; | ||||
|   bool force_exit; | ||||
|   // Keyboard shortcuts | ||||
|   QShortcut *switchSearchShortcut; | ||||
|   QShortcut *switchSearchShortcut2; | ||||
|   QShortcut *switchTransferShortcut; | ||||
|   QShortcut *switchRSSShortcut; | ||||
|   // Widgets | ||||
|   QAction *prioSeparator; | ||||
|   QAction *prioSeparator2; | ||||
|   QSplitter *hSplitter; | ||||
|   QSplitter *vSplitter; | ||||
|   // Search | ||||
|   SearchEngine *searchEngine; | ||||
|   // RSS | ||||
|   QPointer<RSSImp> rssWidget; | ||||
|   // Misc | ||||
|   QLocalServer *localServer; | ||||
| public: | ||||
|   // Construct / Destruct | ||||
|   GUI(QWidget *parent=0, QStringList torrentCmdLine=QStringList()); | ||||
|   ~GUI(); | ||||
|   // Methods | ||||
|   int getCurrentTabIndex() const; | ||||
|   TransferListWidget* getTransferList() const { return transferList; } | ||||
|  | ||||
| public slots: | ||||
|   void trackerAuthenticationRequired(QTorrentHandle& h); | ||||
|   void setTabText(int index, QString text) const; | ||||
|   void showNotificationBaloon(QString title, QString msg) const; | ||||
|   void downloadFromURLList(const QStringList& urls); | ||||
|   void updateAltSpeedsBtn(bool alternative); | ||||
|  | ||||
| protected slots: | ||||
|   // GUI related slots | ||||
| @@ -128,36 +113,59 @@ protected slots: | ||||
|   void loadPreferences(bool configure_session=true); | ||||
|   void processParams(const QStringList& params); | ||||
|   void addTorrent(QString path); | ||||
|   void addUnauthenticatedTracker(QPair<QTorrentHandle,QString> tracker); | ||||
|   void addUnauthenticatedTracker(const QPair<QTorrentHandle,QString> &tracker); | ||||
|   void processDownloadedFiles(QString path, QString url); | ||||
|   void finishedTorrent(QTorrentHandle& h) const; | ||||
|   void askRecursiveTorrentDownloadConfirmation(QTorrentHandle &h); | ||||
|   // Options slots | ||||
|   void on_actionOptions_triggered(); | ||||
|   void optionsSaved(); | ||||
|   // HTTP slots | ||||
|   void on_actionDownload_from_URL_triggered(); | ||||
|  | ||||
|  | ||||
| public slots: | ||||
|   void trackerAuthenticationRequired(QTorrentHandle& h); | ||||
|   void setTabText(int index, QString text) const; | ||||
|   void showNotificationBaloon(QString title, QString msg) const; | ||||
|   void downloadFromURLList(const QStringList& urls); | ||||
|  | ||||
| protected: | ||||
|   void closeEvent(QCloseEvent *); | ||||
|   void showEvent(QShowEvent *); | ||||
|   bool event(QEvent * event); | ||||
|   void displayRSSTab(bool enable); | ||||
|  | ||||
| public: | ||||
|   // Construct / Destruct | ||||
|   GUI(QWidget *parent=0, QStringList torrentCmdLine=QStringList()); | ||||
|   ~GUI(); | ||||
|   // Methods | ||||
|   int getCurrentTabIndex() const; | ||||
|   QPoint screenCenter() const; | ||||
|   TransferListWidget* getTransferList() const { return transferList; } | ||||
| private: | ||||
|   // Bittorrent | ||||
|   Bittorrent *BTSession; | ||||
|   QList<QPair<QTorrentHandle,QString> > unauthenticated_trackers; // Still needed? | ||||
|   // GUI related | ||||
|   QTimer *guiUpdater; | ||||
|   QTabWidget *tabs; | ||||
|   StatusBar *status_bar; | ||||
|   QPointer<options_imp> options; | ||||
|   QPointer<consoleDlg> console; | ||||
|   QPointer<about> aboutDlg; | ||||
|   QPointer<createtorrent> createTorrentDlg; | ||||
|   QPointer<downloadFromURL> downloadFromURLDialog; | ||||
|   QPointer<QSystemTrayIcon> systrayIcon; | ||||
|   QPointer<QTimer> systrayCreator; | ||||
|   QMenu *myTrayIconMenu; | ||||
|   TransferListWidget *transferList; | ||||
|   TransferListFiltersWidget *transferListFilters; | ||||
|   PropertiesWidget *properties; | ||||
|   bool displaySpeedInTitle; | ||||
|   bool force_exit; | ||||
|   // Keyboard shortcuts | ||||
|   QShortcut *switchSearchShortcut; | ||||
|   QShortcut *switchSearchShortcut2; | ||||
|   QShortcut *switchTransferShortcut; | ||||
|   QShortcut *switchRSSShortcut; | ||||
|   // Widgets | ||||
|   QAction *prioSeparator; | ||||
|   QAction *prioSeparator2; | ||||
|   QSplitter *hSplitter; | ||||
|   QSplitter *vSplitter; | ||||
|   // Search | ||||
|   SearchEngine *searchEngine; | ||||
|   // RSS | ||||
|   QPointer<RSSImp> rssWidget; | ||||
|   // Misc | ||||
|   QLocalServer *localServer; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								src/Icons/oxygen/chronometer.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 7.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/Icons/oxygen/gear32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.8 KiB | 
| @@ -1,6 +1,6 @@ | ||||
| [Desktop Entry] | ||||
| Categories=Qt;Network;P2P; | ||||
| Comment=V2.1.1 | ||||
| Comment=V2.2.3 | ||||
| Exec=qbittorrent %f | ||||
| GenericName=Bittorrent client | ||||
| GenericName[bg]=Торент клиент | ||||
|   | ||||
| Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 79 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/Icons/slow.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 910 B | 
							
								
								
									
										
											BIN
										
									
								
								src/Icons/slow48.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.2 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/Icons/slow_off.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 680 B | 
| @@ -63,7 +63,7 @@ class about : public QDialog, private Ui::AboutDlg{ | ||||
|       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>Brazilian:</u> Nick Marinho (nickmarinho@gmail.com)<br>\ | ||||
|           - <u>Bulgarian:</u> Tsvetan & Boiko Bankov (emerge_life@users.sourceforge.net)<br>\ | ||||
|           - <u>Bulgarian:</u> Tsvetan & Boyko Bankoff (emerge_life@users.sourceforge.net)<br>\ | ||||
|           - <u>Catalan:</u> Francisco Luque Contreras (frannoe@ya.com)<br>\ | ||||
|           - <u>Chinese (Simplified):</u> Guo Yue (yue.guo0418@gmail.com)<br>\ | ||||
|           - <u>Chinese (Traditional):</u> Yi-Shun Wang (dnextstep@gmail.com)<br>\ | ||||
| @@ -87,11 +87,14 @@ class about : public QDialog, private Ui::AboutDlg{ | ||||
|           - <u>Spanish:</u> Francisco Luque Contreras (frannoe@ya.com)<br>\ | ||||
|           - <u>Swedish:</u> Daniel Nylander (po@danielnylander.se)<br>\ | ||||
|           - <u>Turkish:</u> Hasan YILMAZ (iletisim@hedefturkce.com) and Erdem Bingöl (erdem84@gmail.com)<br>\ | ||||
|           - <u>Ukrainian:</u> Andrey Shpachenko (masterfix@users.sourceforge.net)<br><br>")); | ||||
|           - <u>Ukrainian:</u> Andrey Shpachenko (masterfix@users.sourceforge.net) and Oleh Prypin (blaxpirit@gmail.com)<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(QString::fromUtf8("<a name='top'></a>")); | ||||
| #ifdef Q_WS_WIN | ||||
|       te_license->append(QString::fromUtf8("qBittorrent is licensed under the GNU General Public License version 2.")); | ||||
| #else | ||||
|       te_license->append(QString::fromUtf8("qBittorrent is licensed under the GNU General Public License version 2 with the\ | ||||
| addition of the following special exception:\ | ||||
| <br><br>\ | ||||
| @@ -438,6 +441,7 @@ exception statement from your version.</i>\ | ||||
|           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>")); | ||||
| #endif | ||||
|           te_license->scrollToAnchor(QString::fromUtf8("top")); | ||||
|           show(); | ||||
|     } | ||||
|   | ||||
							
								
								
									
										146
									
								
								src/advancedsettings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,146 @@ | ||||
| #ifndef ADVANCEDSETTINGS_H | ||||
| #define ADVANCEDSETTINGS_H | ||||
|  | ||||
| #include <QTableWidget> | ||||
| #include <QHeaderView> | ||||
| #include <QSpinBox> | ||||
| #include <QCheckBox> | ||||
| #include "preferences.h" | ||||
|  | ||||
| enum AdvSettingsCols {PROPERTY, VALUE}; | ||||
| enum AdvSettingsRows {DISK_CACHE, OUTGOING_PORT_MIN, OUTGOING_PORT_MAX, IGNORE_LIMIT_LAN, COUNT_OVERHEAD, RECHECK_COMPLETED, LIST_REFRESH, RESOLVE_COUNTRIES, RESOLVE_HOSTS }; | ||||
| #define ROW_COUNT 9 | ||||
|  | ||||
| class AdvancedSettings: public QTableWidget { | ||||
|   Q_OBJECT | ||||
|  | ||||
| private: | ||||
|   QSpinBox *spin_cache, *outgoing_ports_min, *outgoing_ports_max, *spin_list_refresh; | ||||
|   QCheckBox *cb_ignore_limits_lan, *cb_count_overhead, *cb_recheck_completed, *cb_resolve_countries, *cb_resolve_hosts; | ||||
|  | ||||
| public: | ||||
|   AdvancedSettings(QWidget *parent=0): QTableWidget(parent) { | ||||
|     // Set visual appearance | ||||
|     setEditTriggers(QAbstractItemView::NoEditTriggers); | ||||
|     setAlternatingRowColors(true); | ||||
|     setColumnCount(2); | ||||
|     QStringList header; | ||||
|     header << tr("Property") << tr("Value"); | ||||
|     setHorizontalHeaderLabels(header); | ||||
|     setColumnWidth(0, width()/2); | ||||
|     horizontalHeader()->setStretchLastSection(true); | ||||
|     verticalHeader()->setVisible(false); | ||||
|     setRowCount(ROW_COUNT); | ||||
|     // Load settings | ||||
|     loadAdvancedSettings(); | ||||
|   } | ||||
|  | ||||
|   ~AdvancedSettings() { | ||||
|     delete spin_cache; | ||||
|     delete outgoing_ports_min; | ||||
|     delete outgoing_ports_max; | ||||
|     delete cb_ignore_limits_lan; | ||||
|     delete cb_count_overhead; | ||||
|     delete cb_recheck_completed; | ||||
|     delete spin_list_refresh; | ||||
|     delete cb_resolve_countries; | ||||
|     delete cb_resolve_hosts; | ||||
|   } | ||||
|  | ||||
| public slots: | ||||
|   void saveAdvancedSettings() { | ||||
|     // Disk write cache | ||||
|     Preferences::setDiskCacheSize(spin_cache->value()); | ||||
|     // Outgoing ports | ||||
|     Preferences::setOutgoingPortsMin(outgoing_ports_min->value()); | ||||
|     Preferences::setOutgoingPortsMax(outgoing_ports_max->value()); | ||||
|     // Ignore limits on LAN | ||||
|     Preferences::ignoreLimitsOnLAN(cb_ignore_limits_lan->isChecked()); | ||||
|     // Include protocol overhead in transfer limits | ||||
|     Preferences::includeOverheadInLimits(cb_count_overhead->isChecked()); | ||||
|     // Recheck torrents on completion | ||||
|     Preferences::recheckTorrentsOnCompletion(cb_recheck_completed->isChecked()); | ||||
|     // Transfer list refresh interval | ||||
|     Preferences::setRefreshInterval(spin_list_refresh->value()); | ||||
|     // Peer resolution | ||||
|     Preferences::resolvePeerCountries(cb_resolve_countries->isChecked()); | ||||
|     Preferences::resolvePeerHostNames(cb_resolve_hosts->isChecked()); | ||||
|   } | ||||
|  | ||||
| protected slots: | ||||
|   void loadAdvancedSettings() { | ||||
|     // Disk write cache | ||||
|     setItem(DISK_CACHE, PROPERTY, new QTableWidgetItem(tr("Disk write cache size"))); | ||||
|     spin_cache = new QSpinBox(); | ||||
|     connect(spin_cache, SIGNAL(valueChanged(int)), this, SLOT(emitSettingsChanged())); | ||||
|     spin_cache->setMinimum(1); | ||||
|     spin_cache->setMaximum(200); | ||||
|     spin_cache->setValue(Preferences::diskCacheSize()); | ||||
|     spin_cache->setSuffix(tr(" MiB")); | ||||
|     setCellWidget(DISK_CACHE, VALUE, spin_cache); | ||||
|     // Outgoing port Min | ||||
|     setItem(OUTGOING_PORT_MIN, PROPERTY, new QTableWidgetItem(tr("Outgoing ports (Min) [0: Disabled]"))); | ||||
|     outgoing_ports_min = new QSpinBox(); | ||||
|     connect(outgoing_ports_min, SIGNAL(valueChanged(int)), this, SLOT(emitSettingsChanged())); | ||||
|     outgoing_ports_min->setMinimum(0); | ||||
|     outgoing_ports_min->setMaximum(65535); | ||||
|     outgoing_ports_min->setValue(Preferences::outgoingPortsMin()); | ||||
|     setCellWidget(OUTGOING_PORT_MIN, VALUE, outgoing_ports_min); | ||||
|     // Outgoing port Min | ||||
|     setItem(OUTGOING_PORT_MAX, PROPERTY, new QTableWidgetItem(tr("Outgoing ports (Max) [0: Disabled]"))); | ||||
|     outgoing_ports_max = new QSpinBox(); | ||||
|     connect(outgoing_ports_max, SIGNAL(valueChanged(int)), this, SLOT(emitSettingsChanged())); | ||||
|     outgoing_ports_max->setMinimum(0); | ||||
|     outgoing_ports_max->setMaximum(65535); | ||||
|     outgoing_ports_max->setValue(Preferences::outgoingPortsMax()); | ||||
|     setCellWidget(OUTGOING_PORT_MAX, VALUE, outgoing_ports_max); | ||||
|     // Ignore transfer limits on local network | ||||
|     setItem(IGNORE_LIMIT_LAN, PROPERTY, new QTableWidgetItem(tr("Ignore transfer limits on local network"))); | ||||
|     cb_ignore_limits_lan = new QCheckBox(); | ||||
|     connect(cb_ignore_limits_lan, SIGNAL(toggled(bool)), this, SLOT(emitSettingsChanged())); | ||||
|     cb_ignore_limits_lan->setChecked(Preferences::ignoreLimitsOnLAN()); | ||||
|     setCellWidget(IGNORE_LIMIT_LAN, VALUE, cb_ignore_limits_lan); | ||||
|     // Consider protocol overhead in transfer limits | ||||
|     setItem(COUNT_OVERHEAD, PROPERTY, new QTableWidgetItem(tr("Include TCP/IP overhead in transfer limits"))); | ||||
|     cb_count_overhead = new QCheckBox(); | ||||
|     connect(cb_count_overhead, SIGNAL(toggled(bool)), this, SLOT(emitSettingsChanged())); | ||||
|     cb_count_overhead->setChecked(Preferences::includeOverheadInLimits()); | ||||
|     setCellWidget(COUNT_OVERHEAD, VALUE, cb_count_overhead); | ||||
|     // Recheck completed torrents | ||||
|     setItem(RECHECK_COMPLETED, PROPERTY, new QTableWidgetItem(tr("Recheck torrents on completion"))); | ||||
|     cb_recheck_completed = new QCheckBox(); | ||||
|     connect(cb_recheck_completed, SIGNAL(toggled(bool)), this, SLOT(emitSettingsChanged())); | ||||
|     cb_recheck_completed->setChecked(Preferences::recheckTorrentsOnCompletion()); | ||||
|     setCellWidget(RECHECK_COMPLETED, VALUE, cb_recheck_completed); | ||||
|     // Transfer list refresh interval | ||||
|     setItem(LIST_REFRESH, PROPERTY, new QTableWidgetItem(tr("Transfer list refresh interval"))); | ||||
|     spin_list_refresh = new QSpinBox(); | ||||
|     connect(spin_list_refresh, SIGNAL(valueChanged(int)), this, SLOT(emitSettingsChanged())); | ||||
|     spin_list_refresh->setMinimum(30); | ||||
|     spin_list_refresh->setMaximum(99999); | ||||
|     spin_list_refresh->setValue(Preferences::getRefreshInterval()); | ||||
|     spin_list_refresh->setSuffix(tr(" ms", " milliseconds")); | ||||
|     setCellWidget(LIST_REFRESH, VALUE, spin_list_refresh); | ||||
|     // Resolve Peer countries | ||||
|     setItem(RESOLVE_COUNTRIES, PROPERTY, new QTableWidgetItem(tr("Resolve peer countries (GeoIP)"))); | ||||
|     cb_resolve_countries = new QCheckBox(); | ||||
|     connect(cb_resolve_countries, SIGNAL(toggled(bool)), this, SLOT(emitSettingsChanged())); | ||||
|     cb_resolve_countries->setChecked(Preferences::resolvePeerCountries()); | ||||
|     setCellWidget(RESOLVE_COUNTRIES, VALUE, cb_resolve_countries); | ||||
|     // Resolve peer hosts | ||||
|     setItem(RESOLVE_HOSTS, PROPERTY, new QTableWidgetItem(tr("Resolve peer host names"))); | ||||
|     cb_resolve_hosts = new QCheckBox(); | ||||
|     connect(cb_resolve_hosts, SIGNAL(toggled(bool)), this, SLOT(emitSettingsChanged())); | ||||
|     cb_resolve_hosts->setChecked(Preferences::resolvePeerHostNames()); | ||||
|     setCellWidget(RESOLVE_HOSTS, VALUE, cb_resolve_hosts); | ||||
|   } | ||||
|  | ||||
|   void emitSettingsChanged() { | ||||
|     emit settingsChanged(); | ||||
|   } | ||||
|  | ||||
| signals: | ||||
|   void settingsChanged(); | ||||
| }; | ||||
|  | ||||
| #endif // ADVANCEDSETTINGS_H | ||||
							
								
								
									
										111
									
								
								src/bandwidthscheduler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,111 @@ | ||||
| #ifndef BANDWIDTHSCHEDULER_H | ||||
| #define BANDWIDTHSCHEDULER_H | ||||
|  | ||||
| #include <QTimer> | ||||
| #include <QTime> | ||||
| #include <QDateTime> | ||||
| #include "preferences.h" | ||||
| #include <iostream> | ||||
|  | ||||
| class BandwidthScheduler: public QTimer { | ||||
|   Q_OBJECT | ||||
|  | ||||
| private: | ||||
|   bool in_alternative_mode; | ||||
|  | ||||
| public: | ||||
|   BandwidthScheduler(QObject *parent): QTimer(parent), in_alternative_mode(false) { | ||||
|     Q_ASSERT(Preferences::isSchedulerEnabled()); | ||||
|     // Signal shot, we call start() again manually | ||||
|     setSingleShot(true); | ||||
|     // Connect Signals/Slots | ||||
|     connect(this, SIGNAL(timeout()), this, SLOT(switchMode())); | ||||
|   } | ||||
|  | ||||
| public slots: | ||||
|   void start() { | ||||
|     Q_ASSERT(Preferences::isSchedulerEnabled()); | ||||
|  | ||||
|     QTime startAltSpeeds = Preferences::getSchedulerStartTime(); | ||||
|     QTime endAltSpeeds = Preferences::getSchedulerEndTime(); | ||||
|     if(startAltSpeeds == endAltSpeeds) { | ||||
|       std::cerr << "Error: bandwidth scheduler have the same start time and end time." << std::endl; | ||||
|       std::cerr << "The bandwidth scheduler will be disabled" << std::endl; | ||||
|       stop(); | ||||
|       emit switchToAlternativeMode(false); | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     // Determine what the closest QTime is | ||||
|     QTime now = QTime::currentTime(); | ||||
|     uint time_to_start = secsTo(now, startAltSpeeds); | ||||
|     uint time_to_end = secsTo(now, endAltSpeeds); | ||||
|     if(time_to_end < time_to_start) { | ||||
|       // We should be in alternative mode | ||||
|       in_alternative_mode = true; | ||||
|       // Start counting | ||||
|       QTimer::start(time_to_end*1000); | ||||
|     } else { | ||||
|       // We should be in normal mode | ||||
|       in_alternative_mode = false; | ||||
|       // Start counting | ||||
|       QTimer::start(time_to_start*1000); | ||||
|     } | ||||
|     // Send signal to notify BTSession | ||||
|     emit switchToAlternativeMode(in_alternative_mode); | ||||
|   } | ||||
|  | ||||
|   void switchMode() { | ||||
|     // Get the day this mode was started (either today or yesterday) | ||||
|     QDate current_date = QDateTime::currentDateTime().toLocalTime().date(); | ||||
|     int day = current_date.dayOfWeek(); | ||||
|     if(in_alternative_mode) { | ||||
|       // It is possible that starttime was yesterday | ||||
|       if(QTime::currentTime().secsTo(Preferences::getSchedulerStartTime()) > 0) { | ||||
|         current_date.addDays(-1); // Go to yesterday | ||||
|         day = current_date.day(); | ||||
|       } | ||||
|     } | ||||
|     // Check if the day is in scheduler days | ||||
|     // Notify BTSession only if necessary | ||||
|     switch(Preferences::getSchedulerDays()) { | ||||
|     case EVERY_DAY: | ||||
|       emit switchToAlternativeMode(!in_alternative_mode); | ||||
|       break; | ||||
|     case WEEK_ENDS: | ||||
|       if(day == Qt::Saturday || day == Qt::Sunday) | ||||
|         emit switchToAlternativeMode(!in_alternative_mode); | ||||
|       break; | ||||
|     case WEEK_DAYS: | ||||
|       if(day != Qt::Saturday && day != Qt::Sunday) | ||||
|         emit switchToAlternativeMode(!in_alternative_mode); | ||||
|       break; | ||||
|     default: | ||||
|       // Convert our enum index to Qt enum index | ||||
|       int scheduler_day = ((int)Preferences::getSchedulerDays()) - 2; | ||||
|       if(day == scheduler_day) | ||||
|         emit switchToAlternativeMode(!in_alternative_mode); | ||||
|       break; | ||||
|     } | ||||
|     // Call start again | ||||
|     start(); | ||||
|   } | ||||
|  | ||||
| signals: | ||||
|   void switchToAlternativeMode(bool alternative); | ||||
|  | ||||
| private: | ||||
|   // Qt function can return negative values and we | ||||
|   // don't want that | ||||
|   uint secsTo(QTime now, QTime t) { | ||||
|     int diff = now.secsTo(t); | ||||
|     if(diff < 0) { | ||||
|       // 86400 seconds in a day | ||||
|       diff += 86400; | ||||
|     } | ||||
|     Q_ASSERT(diff >= 0); | ||||
|     return diff; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| #endif // BANDWIDTHSCHEDULER_H | ||||
							
								
								
									
										134
									
								
								src/bittorrent.h
									
									
									
									
									
								
							
							
						
						| @@ -41,6 +41,7 @@ | ||||
| #include <QPalette> | ||||
| #endif | ||||
| #include <QPointer> | ||||
| #include <QTimer> | ||||
|  | ||||
| #include <libtorrent/session.hpp> | ||||
| #include <libtorrent/ip_filter.hpp> | ||||
| @@ -52,9 +53,10 @@ using namespace libtorrent; | ||||
|  | ||||
| class downloadThread; | ||||
| class QTimer; | ||||
| class FileSystemWatcher; | ||||
| class FilterParserThread; | ||||
| class HttpServer; | ||||
| class BandwidthScheduler; | ||||
| class ScanFoldersModel; | ||||
|  | ||||
| class TrackerInfos { | ||||
| public: | ||||
| @@ -88,60 +90,6 @@ public: | ||||
| class Bittorrent : public QObject { | ||||
|   Q_OBJECT | ||||
|  | ||||
| private: | ||||
|   // Bittorrent | ||||
|   session *s; | ||||
|   QPointer<QTimer> timerAlerts; | ||||
|   QMap<QUrl, QString> savepath_fromurl; | ||||
|   QHash<QString, QHash<QString, TrackerInfos> > trackersInfos; | ||||
|   QStringList torrentsToPausedAfterChecking; | ||||
|   // Ratio | ||||
|   QPointer<QTimer> BigRatioTimer; | ||||
|   // HTTP | ||||
|   QPointer<downloadThread> downloader; | ||||
|   // File System | ||||
|   QPointer<FileSystemWatcher> FSWatcher; | ||||
|   // Console / Log | ||||
|   QStringList consoleMessages; | ||||
|   QStringList peerBanMessages; | ||||
|   // Settings | ||||
|   bool preAllocateAll; | ||||
|   bool addInPause; | ||||
|   float ratio_limit; | ||||
|   bool UPnPEnabled; | ||||
|   bool NATPMPEnabled; | ||||
|   bool LSDEnabled; | ||||
|   bool DHTEnabled; | ||||
|   int current_dht_port; | ||||
|   bool PeXEnabled; | ||||
|   bool queueingEnabled; | ||||
|   bool appendLabelToSavePath; | ||||
| #ifdef LIBTORRENT_0_15 | ||||
|   bool appendqBExtension; | ||||
| #endif | ||||
|   QString defaultSavePath; | ||||
|   QString defaultTempPath; | ||||
|   // GeoIP | ||||
| #ifndef DISABLE_GUI | ||||
|   bool resolve_countries; | ||||
|   bool geoipDBLoaded; | ||||
| #endif | ||||
|   // ETA Computation | ||||
|   QPointer<QTimer> timerETA; | ||||
|   QHash<QString, QList<int> > ETA_samples; | ||||
|   // IP filtering | ||||
|   QPointer<FilterParserThread> filterParser; | ||||
|   QString filterPath; | ||||
|   // Web UI | ||||
|   QPointer<HttpServer> httpServer; | ||||
|   QList<QUrl> url_skippingDlg; | ||||
|   // Fast exit (async) | ||||
|   bool exiting; | ||||
|  | ||||
| protected: | ||||
|   QString getSavePath(QString hash); | ||||
|   bool initWebUi(QString username, QString password, int port); | ||||
|  | ||||
| public: | ||||
|   // Constructor / Destructor | ||||
|   Bittorrent(); | ||||
| @@ -168,13 +116,11 @@ public: | ||||
|   qlonglong getETA(QString hash); | ||||
|   bool useTemporaryFolder() const; | ||||
|   QString getDefaultSavePath() const; | ||||
|   ScanFoldersModel* getScanFoldersModel() const; | ||||
|  | ||||
| public slots: | ||||
|   QTorrentHandle addTorrent(QString path, bool fromScanDir = false, QString from_url = QString(), bool resumed = false); | ||||
|   QTorrentHandle addMagnetUri(QString magnet_uri, bool resumed=false); | ||||
|   void importOldTorrents(); | ||||
|   void applyFormerAttributeFiles(QTorrentHandle h); | ||||
|   void importOldTempData(QString torrent_path); | ||||
|   void loadSessionState(); | ||||
|   void saveSessionState(); | ||||
|   void downloadFromUrl(QString url); | ||||
| @@ -182,6 +128,7 @@ public slots: | ||||
|   void startUpTorrents(); | ||||
|   session_proxy asyncDeletion(); | ||||
|   void recheckTorrent(QString hash); | ||||
|   void useAlternativeSpeedsLimit(bool alternative); | ||||
|   /* Needed by Web UI */ | ||||
|   void pauseAllTorrents(); | ||||
|   void pauseTorrent(QString hash); | ||||
| @@ -191,8 +138,6 @@ public slots: | ||||
|   void saveDHTEntry(); | ||||
|   void preAllocateAllFiles(bool b); | ||||
|   void saveFastResumeData(); | ||||
|   void enableDirectoryScanning(QString scan_dir); | ||||
|   void disableDirectoryScanning(); | ||||
|   void enableIPFilter(QString filter); | ||||
|   void disableIPFilter(); | ||||
|   void setQueueingEnabled(bool enable); | ||||
| @@ -208,9 +153,9 @@ public slots: | ||||
|   void setGlobalRatio(float ratio); | ||||
|   void setDeleteRatio(float ratio); | ||||
|   void setDHTPort(int dht_port); | ||||
|   void setPeerProxySettings(proxy_settings proxySettings); | ||||
|   void setHTTPProxySettings(proxy_settings proxySettings); | ||||
|   void setSessionSettings(session_settings sessionSettings); | ||||
|   void setPeerProxySettings(const proxy_settings &proxySettings); | ||||
|   void setHTTPProxySettings(const proxy_settings &proxySettings); | ||||
|   void setSessionSettings(const session_settings &sessionSettings); | ||||
|   void startTorrentsInPause(bool b); | ||||
|   void setDefaultTempPath(QString temppath); | ||||
|   void setAppendLabelToSavePath(bool append); | ||||
| @@ -238,12 +183,19 @@ public slots: | ||||
|   void downloadFromURLList(const QStringList& urls); | ||||
|   void configureSession(); | ||||
|   void banIP(QString ip); | ||||
|   void recursiveTorrentDownload(const QTorrentHandle &h); | ||||
|  | ||||
| protected: | ||||
|   QString getSavePath(QString hash, bool fromScanDir = false, QString filePath = QString()); | ||||
|   bool initWebUi(QString username, QString password, int port); | ||||
|  | ||||
| protected slots: | ||||
|   void addTorrentsFromScanFolder(QStringList&); | ||||
|   void readAlerts(); | ||||
|   void deleteBigRatios(); | ||||
|   void takeETASamples(); | ||||
|   void exportTorrentFiles(QString path); | ||||
|   void saveTempFastResumeData(); | ||||
|  | ||||
| signals: | ||||
|   void addedTorrent(QTorrentHandle& h); | ||||
| @@ -261,6 +213,62 @@ signals: | ||||
|   void metadataReceived(QTorrentHandle &h); | ||||
|   void savePathChanged(QTorrentHandle &h); | ||||
|   void newConsoleMessage(QString msg); | ||||
|   void alternativeSpeedsModeChanged(bool alternative); | ||||
|   void recursiveTorrentDownloadPossible(QTorrentHandle &h); | ||||
|  | ||||
| private: | ||||
|   // Bittorrent | ||||
|   session *s; | ||||
|   QPointer<QTimer> timerAlerts; | ||||
|   QPointer<BandwidthScheduler> bd_scheduler; | ||||
|   QMap<QUrl, QString> savepath_fromurl; | ||||
|   QHash<QString, QHash<QString, TrackerInfos> > trackersInfos; | ||||
|   QStringList torrentsToPausedAfterChecking; | ||||
|   QTimer resumeDataTimer; | ||||
|   // Ratio | ||||
|   QPointer<QTimer> BigRatioTimer; | ||||
|   // HTTP | ||||
|   QPointer<downloadThread> downloader; | ||||
|   // File System | ||||
|   ScanFoldersModel *m_scanFolders; | ||||
|   // Console / Log | ||||
|   QStringList consoleMessages; | ||||
|   QStringList peerBanMessages; | ||||
|   // Settings | ||||
|   bool preAllocateAll; | ||||
|   bool addInPause; | ||||
|   float ratio_limit; | ||||
|   bool UPnPEnabled; | ||||
|   bool NATPMPEnabled; | ||||
|   bool LSDEnabled; | ||||
|   bool DHTEnabled; | ||||
|   int current_dht_port; | ||||
|   bool PeXEnabled; | ||||
|   bool queueingEnabled; | ||||
|   bool appendLabelToSavePath; | ||||
|   bool torrentExport; | ||||
| #ifdef LIBTORRENT_0_15 | ||||
|   bool appendqBExtension; | ||||
| #endif | ||||
|   QString defaultSavePath; | ||||
|   QString defaultTempPath; | ||||
|   // ETA Computation | ||||
|   QPointer<QTimer> timerETA; | ||||
|   QHash<QString, QList<int> > ETA_samples; | ||||
|   // IP filtering | ||||
|   QPointer<FilterParserThread> filterParser; | ||||
|   QString filterPath; | ||||
|   // Web UI | ||||
|   QPointer<HttpServer> httpServer; | ||||
|   QList<QUrl> url_skippingDlg; | ||||
|   // Fast exit (async) | ||||
|   bool exiting; | ||||
|   // GeoIP | ||||
| #ifndef DISABLE_GUI | ||||
|   bool geoipDBLoaded; | ||||
|   bool resolve_countries; | ||||
| #endif | ||||
|  | ||||
| }; | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -46,6 +46,7 @@ class consoleDlg : public QDialog, private Ui_ConsoleDlg{ | ||||
|     consoleDlg(QWidget *parent, Bittorrent* _BTSession) : QDialog(parent) { | ||||
|       setupUi(this); | ||||
|       setAttribute(Qt::WA_DeleteOnClose); | ||||
|       setModal(true); | ||||
|       BTSession = _BTSession; | ||||
|       textConsole->setHtml(BTSession->getConsoleMessages().join("<br>")); | ||||
|       textBannedPeers->setHtml(BTSession->getPeerBanMessages().join("<br>")); | ||||
|   | ||||
| @@ -65,6 +65,7 @@ bool file_filter(boost::filesystem::path const& filename) | ||||
| createtorrent::createtorrent(QWidget *parent): QDialog(parent){ | ||||
|   setupUi(this); | ||||
|   setAttribute(Qt::WA_DeleteOnClose); | ||||
|   setModal(true); | ||||
|   creatorThread = new torrentCreatorThread(this); | ||||
|   connect(creatorThread, SIGNAL(creationSuccess(QString, const char*)), this, SLOT(handleCreationSuccess(QString, const char*))); | ||||
|   connect(creatorThread, SIGNAL(creationFailure(QString)), this, SLOT(handleCreationFailure(QString))); | ||||
| @@ -84,7 +85,7 @@ void createtorrent::on_addFolder_button_clicked(){ | ||||
| } | ||||
|  | ||||
| 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); | ||||
|   QString file = QFileDialog::getOpenFileName(this, tr("Select a file to add to the torrent"), QDir::homePath()); | ||||
|   if(!file.isEmpty()) | ||||
|     textInputPath->setText(file); | ||||
| } | ||||
|   | ||||
| @@ -33,6 +33,7 @@ | ||||
|  | ||||
| #include <QDialog> | ||||
| #include "ui_confirmdeletiondlg.h" | ||||
| #include "misc.h" | ||||
|  | ||||
| class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg { | ||||
|   Q_OBJECT | ||||
| @@ -40,6 +41,7 @@ class DeletionConfirmationDlg : public QDialog, private Ui::confirmDeletionDlg { | ||||
|   public: | ||||
|   DeletionConfirmationDlg(QWidget *parent=0): QDialog(parent) { | ||||
|     setupUi(this); | ||||
|     move(misc::screenCenter(this)); | ||||
|   } | ||||
|  | ||||
|   bool shouldDeleteLocalFiles() const { | ||||
|   | ||||
| @@ -53,34 +53,49 @@ public: | ||||
|     setFixedHeight(BAR_HEIGHT); | ||||
|   } | ||||
|  | ||||
|   void setProgress(bitfield pieces) { | ||||
|   void setProgress(const bitfield &pieces, const bitfield &downloading_pieces) { | ||||
|     if(pieces.empty()) { | ||||
|       // Empty bar | ||||
|       QPixmap pix = QPixmap(1, 1); | ||||
|       pix.fill(); | ||||
|       pixmap = pix; | ||||
|     } else { | ||||
|       int nb_pieces = pieces.size(); | ||||
|       const int nb_pieces = pieces.size(); | ||||
|       // Reduce the number of pieces before creating the pixmap | ||||
|       // otherwise it can crash when there are too many pieces | ||||
|       if(nb_pieces > width()) { | ||||
|         int ratio = floor(nb_pieces/(double)width()); | ||||
|         QVector<bool> scaled_pieces; | ||||
|         const int ratio = floor(nb_pieces/(double)width()); | ||||
|         std::vector<bool> scaled_pieces; | ||||
|         std::vector<bool> scaled_downloading; | ||||
|         for(int i=0; i<nb_pieces; i+= ratio) { | ||||
|           bool have = true; | ||||
|           for(int j=i; j<qMin(i+ratio, nb_pieces); ++j) { | ||||
|             if(!pieces[i]) { have = false; break; } | ||||
|           } | ||||
|           scaled_pieces << have; | ||||
|           scaled_pieces.push_back(have); | ||||
|           if(have) { | ||||
|             scaled_downloading.push_back(false); | ||||
|           } else { | ||||
|             bool downloading = false; | ||||
|             for(int j=i; j<qMin(i+ratio, nb_pieces); ++j) { | ||||
|               if(downloading_pieces[i]) { downloading = true; break; } | ||||
|             } | ||||
|             scaled_downloading.push_back(downloading); | ||||
|           } | ||||
|         } | ||||
|         QPixmap pix = QPixmap(scaled_pieces.size(), 1); | ||||
|         pix.fill(); | ||||
|         QPainter painter(&pix); | ||||
|         for(int i=0; i<scaled_pieces.size(); ++i) { | ||||
|           if(scaled_pieces[i]) | ||||
|         for(uint i=0; i<scaled_pieces.size(); ++i) { | ||||
|           if(scaled_pieces[i]) { | ||||
|             painter.setPen(Qt::blue); | ||||
|           else | ||||
|             painter.setPen(Qt::white); | ||||
|           } else { | ||||
|             if(scaled_downloading[i]) { | ||||
|               painter.setPen(Qt::yellow); | ||||
|             } else { | ||||
|               painter.setPen(Qt::white); | ||||
|             } | ||||
|           } | ||||
|           painter.drawPoint(i,0); | ||||
|         } | ||||
|         pixmap = pix; | ||||
| @@ -89,10 +104,15 @@ public: | ||||
|         pix.fill(); | ||||
|         QPainter painter(&pix); | ||||
|         for(uint i=0; i<pieces.size(); ++i) { | ||||
|           if(pieces[i]) | ||||
|           if(pieces[i]) { | ||||
|             painter.setPen(Qt::blue); | ||||
|           else | ||||
|             painter.setPen(Qt::white); | ||||
|           } else { | ||||
|             if(downloading_pieces[i]) { | ||||
|               painter.setPen(Qt::yellow); | ||||
|             } else { | ||||
|               painter.setPen(Qt::white); | ||||
|             } | ||||
|           } | ||||
|           painter.drawPoint(i,0); | ||||
|         } | ||||
|         pixmap = pix; | ||||
|   | ||||
| @@ -47,6 +47,7 @@ class downloadFromURL : public QDialog, private Ui::downloadFromURL{ | ||||
|       setupUi(this); | ||||
|       setAttribute(Qt::WA_DeleteOnClose); | ||||
|       icon_lbl->setPixmap(QPixmap(QString::fromUtf8(":/Icons/skin/url.png"))); | ||||
|       setModal(true); | ||||
|       show(); | ||||
|       // Paste clipboard if there is an URL in it | ||||
|       QString clip_txt = qApp->clipboard()->text(); | ||||
|   | ||||
| @@ -56,14 +56,27 @@ void downloadThread::processDlFinished(QNetworkReply* reply) { | ||||
|     // Failure | ||||
|     emit downloadFailure(url, errorCodeToString(reply->error())); | ||||
|   } else { | ||||
|     QVariant redirection = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); | ||||
|     if(redirection.isValid()) { | ||||
|       // We should redirect | ||||
|       qDebug("Redirecting from %s to %s", qPrintable(url), qPrintable(redirection.toUrl().toString())); | ||||
|       redirect_mapping.insert(redirection.toUrl().toString(), url); | ||||
|       downloadUrl(redirection.toUrl().toString()); | ||||
|       return; | ||||
|     } | ||||
|     // Checking if it was redirecting, restoring initial URL | ||||
|     if(redirect_mapping.contains(url)) { | ||||
|       url = redirect_mapping.take(url); | ||||
|     } | ||||
|     // Success | ||||
|     QString filePath; | ||||
|     QTemporaryFile tmpfile; | ||||
|     tmpfile.setAutoRemove(false); | ||||
|     if (tmpfile.open()) { | ||||
|       filePath = tmpfile.fileName(); | ||||
|       qDebug("Temporary filename is: %s", filePath.toLocal8Bit().data()); | ||||
|       qDebug("Temporary filename is: %s", qPrintable(filePath)); | ||||
|       if(reply->open(QIODevice::ReadOnly)) { | ||||
|         // TODO: Support GZIP compression | ||||
|         tmpfile.write(reply->readAll()); | ||||
|         reply->close(); | ||||
|         tmpfile.close(); | ||||
| @@ -82,7 +95,12 @@ void downloadThread::processDlFinished(QNetworkReply* reply) { | ||||
|   reply->deleteLater(); | ||||
| } | ||||
|  | ||||
| void downloadThread::downloadUrl(QString url){ | ||||
| void downloadThread::downloadTorrentUrl(QString url){ | ||||
|   QNetworkReply *reply = downloadUrl(url); | ||||
|   connect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(checkDownloadSize(qint64,qint64))); | ||||
| } | ||||
|  | ||||
| QNetworkReply* downloadThread::downloadUrl(QString url){ | ||||
|   // Update proxy settings | ||||
|   applyProxySettings(); | ||||
|   // Process download request | ||||
| @@ -91,8 +109,27 @@ void downloadThread::downloadUrl(QString url){ | ||||
|   // Spoof Firefox 3.5 user agent to avoid | ||||
|   // Web server banning | ||||
|   request.setRawHeader("User-Agent", "Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5"); | ||||
|   qDebug("Downloading %s...", request.url().toString().toLocal8Bit().data()); | ||||
|   networkManager->get(request); | ||||
|   qDebug("Downloading %s...", qPrintable(request.url().toString())); | ||||
|   return networkManager->get(request); | ||||
| } | ||||
|  | ||||
| void downloadThread::checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal) { | ||||
|   if(bytesTotal > 0) { | ||||
|     QNetworkReply *reply = static_cast<QNetworkReply*>(sender()); | ||||
|     // Total number of bytes is available | ||||
|     if(bytesTotal > 1048576) { | ||||
|       // More than 1MB, this is probably not a torrent file, aborting... | ||||
|       reply->abort(); | ||||
|     } else { | ||||
|       disconnect(reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(checkDownloadSize(qint64,qint64))); | ||||
|     } | ||||
|   } else { | ||||
|     if(bytesReceived  > 1048576) { | ||||
|       // More than 1MB, this is probably not a torrent file, aborting... | ||||
|       QNetworkReply *reply = static_cast<QNetworkReply*>(sender()); | ||||
|       reply->abort(); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| void downloadThread::applyProxySettings() { | ||||
| @@ -104,7 +141,7 @@ void downloadThread::applyProxySettings() { | ||||
|     QString IP = settings.value(QString::fromUtf8("Preferences/Connection/HTTPProxy/IP"), "0.0.0.0").toString(); | ||||
|     proxy.setHostName(IP); | ||||
|     QString port = settings.value(QString::fromUtf8("Preferences/Connection/HTTPProxy/Port"), 8080).toString(); | ||||
|     qDebug("Using proxy: %s", (IP+QString(":")+port).toLocal8Bit().data()); | ||||
|     qDebug("Using proxy: %s", qPrintable(IP)); | ||||
|     proxy.setPort(port.toUShort()); | ||||
|     // Default proxy type is HTTP, we must change if it is SOCKS5 | ||||
|     if(intValue == SOCKS5 || intValue == SOCKS5_PW) { | ||||
|   | ||||
| @@ -33,6 +33,7 @@ | ||||
|  | ||||
| #include <QNetworkReply> | ||||
| #include <QObject> | ||||
| #include <QHash> | ||||
|  | ||||
| class QNetworkAccessManager; | ||||
|  | ||||
| @@ -41,6 +42,7 @@ class downloadThread : public QObject { | ||||
|  | ||||
| private: | ||||
|   QNetworkAccessManager *networkManager; | ||||
|   QHash<QString, QString> redirect_mapping; | ||||
|  | ||||
| signals: | ||||
|   void downloadFinished(QString url, QString file_path); | ||||
| @@ -49,7 +51,8 @@ signals: | ||||
| public: | ||||
|   downloadThread(QObject* parent); | ||||
|   ~downloadThread(); | ||||
|   void downloadUrl(QString url); | ||||
|   QNetworkReply* downloadUrl(QString url); | ||||
|   void downloadTorrentUrl(QString url); | ||||
|   //void setProxy(QString IP, int port, QString username, QString password); | ||||
|  | ||||
| protected: | ||||
| @@ -58,6 +61,7 @@ protected: | ||||
|  | ||||
| protected slots: | ||||
|   void processDlFinished(QNetworkReply* reply); | ||||
|   void checkDownloadSize(qint64 bytesReceived, qint64 bytesTotal); | ||||
|  | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -81,7 +81,7 @@ void engineSelectDlg::dropEvent(QDropEvent *event) { | ||||
|   QStringList files=event->mimeData()->text().split(QString::fromUtf8("\n")); | ||||
|   QString file; | ||||
|   foreach(file, files) { | ||||
|     qDebug("dropped %s", file.toLocal8Bit().data()); | ||||
|     qDebug("dropped %s", qPrintable(file)); | ||||
|     file = file.replace("file://", ""); | ||||
|     if(file.startsWith("http://", Qt::CaseInsensitive) || file.startsWith("https://", Qt::CaseInsensitive) || file.startsWith("ftp://", Qt::CaseInsensitive)) { | ||||
|       downloader->downloadUrl(file); | ||||
| @@ -99,7 +99,7 @@ void engineSelectDlg::dropEvent(QDropEvent *event) { | ||||
| void engineSelectDlg::dragEnterEvent(QDragEnterEvent *event) { | ||||
|   QString mime; | ||||
|   foreach(mime, event->mimeData()->formats()){ | ||||
|     qDebug("mimeData: %s", mime.toLocal8Bit().data()); | ||||
|     qDebug("mimeData: %s", qPrintable(mime)); | ||||
|   } | ||||
|   if (event->mimeData()->hasFormat(QString::fromUtf8("text/plain")) || event->mimeData()->hasFormat(QString::fromUtf8("text/uri-list"))) { | ||||
|     event->acceptProposedAction(); | ||||
| @@ -251,12 +251,12 @@ bool engineSelectDlg::isUpdateNeeded(QString plugin_name, float new_version) con | ||||
| } | ||||
|  | ||||
| void engineSelectDlg::installPlugin(QString path, QString plugin_name) { | ||||
|   qDebug("Asked to install plugin at %s", path.toLocal8Bit().data()); | ||||
|   qDebug("Asked to install plugin at %s", qPrintable(path)); | ||||
|   float new_version = SearchEngine::getPluginVersion(path); | ||||
|   qDebug("Version to be installed: %.2f", new_version); | ||||
|   if(!isUpdateNeeded(plugin_name, new_version)) { | ||||
|     qDebug("Apparently update is 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.toLocal8Bit().data())); | ||||
|     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)); | ||||
|     return; | ||||
|   } | ||||
|   // Process with install | ||||
| @@ -280,12 +280,12 @@ void engineSelectDlg::installPlugin(QString path, QString plugin_name) { | ||||
|       // 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.toLocal8Bit().data())); | ||||
|       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)); | ||||
|       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.toLocal8Bit().data())); | ||||
|       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)); | ||||
|       return; | ||||
|     } | ||||
|   } | ||||
| @@ -294,10 +294,10 @@ void engineSelectDlg::installPlugin(QString path, QString plugin_name) { | ||||
|     QFile::remove(dest_path+".bak"); | ||||
|   } | ||||
|   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.toLocal8Bit().data())); | ||||
|     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)); | ||||
|     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.toLocal8Bit().data())); | ||||
|     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)); | ||||
|     return; | ||||
|   } | ||||
| } | ||||
| @@ -390,17 +390,17 @@ bool engineSelectDlg::parseVersionsFile(QString versions_file) { | ||||
|     plugin_name.chop(1); // remove trailing ':' | ||||
|     bool ok; | ||||
|     float version = list.last().toFloat(&ok); | ||||
|     qDebug("read line %s: %.2f", plugin_name.toLocal8Bit().data(), version); | ||||
|     qDebug("read line %s: %.2f", qPrintable(plugin_name), version); | ||||
|     if(!ok) continue; | ||||
|     file_correct = true; | ||||
|     if(isUpdateNeeded(plugin_name, version)) { | ||||
|       qDebug("Plugin: %s is outdated", plugin_name.toLocal8Bit().data()); | ||||
|       qDebug("Plugin: %s is outdated", qPrintable(plugin_name)); | ||||
|       // Downloading update | ||||
|       downloader->downloadUrl(UPDATE_URL+plugin_name+".py"); | ||||
|       //downloader->downloadUrl(UPDATE_URL+plugin_name+".png"); | ||||
|       updated = true; | ||||
|     }else { | ||||
|       qDebug("Plugin: %s is up to date", plugin_name.toLocal8Bit().data()); | ||||
|       qDebug("Plugin: %s is up to date", qPrintable(plugin_name)); | ||||
|     } | ||||
|   } | ||||
|   // Close file | ||||
| @@ -414,7 +414,7 @@ bool engineSelectDlg::parseVersionsFile(QString versions_file) { | ||||
| } | ||||
|  | ||||
| void engineSelectDlg::processDownloadedFile(QString url, QString filePath) { | ||||
|   qDebug("engineSelectDlg received %s", url.toLocal8Bit().data()); | ||||
|   qDebug("engineSelectDlg received %s", qPrintable(url)); | ||||
|   if(url.endsWith("favicon.ico", Qt::CaseInsensitive)){ | ||||
|     // Icon downloaded | ||||
|     QImage fileIcon; | ||||
| @@ -456,7 +456,7 @@ void engineSelectDlg::processDownloadedFile(QString url, QString filePath) { | ||||
|  | ||||
| void engineSelectDlg::handleDownloadFailure(QString url, QString reason) { | ||||
|   if(url.endsWith("favicon.ico", Qt::CaseInsensitive)){ | ||||
|     qDebug("Could not download favicon: %s, reason: %s", url.toLocal8Bit().data(), reason.toLocal8Bit().data()); | ||||
|     qDebug("Could not download favicon: %s, reason: %s", qPrintable(url), qPrintable(reason)); | ||||
|     return; | ||||
|   } | ||||
|   if(url.endsWith("versions.txt")) { | ||||
| @@ -467,6 +467,6 @@ void engineSelectDlg::handleDownloadFailure(QString url, QString reason) { | ||||
|     // a plugin update download has been failed | ||||
|     QString plugin_name = url.split('/').last(); | ||||
|     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.toLocal8Bit().data())); | ||||
|     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)); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -31,6 +31,7 @@ | ||||
|  | ||||
| #include "eventmanager.h" | ||||
| #include "bittorrent.h" | ||||
| #include "scannedfoldersmodel.h" | ||||
| #include "misc.h" | ||||
| #include "preferences.h" | ||||
| //#include "proplistdelegate.h" | ||||
| @@ -129,8 +130,31 @@ void EventManager::setGlobalPreferences(QVariantMap m) const { | ||||
|     Preferences::setTempPathEnabled(m["temp_path_enabled"].toBool()); | ||||
|   if(m.contains("temp_path")) | ||||
|     Preferences::setTempPath(m["temp_path"].toString()); | ||||
|   if(m.contains("scan_dir")) | ||||
|     Preferences::setScanDir(m["scan_dir"].toString()); | ||||
|   if(m.contains("scan_dirs") && m.contains("download_in_scan_dirs")) { | ||||
|     QVariantList download_at_path = m["download_in_scan_dirs"].toList(); | ||||
|     QStringList old_folders = Preferences::getScanDirs(); | ||||
|     QStringList new_folders = m["scan_dirs"].toStringList(); | ||||
|     if(download_at_path.size() == new_folders.size()) { | ||||
|       Preferences::setScanDirs(new_folders); | ||||
|       Preferences::setDownloadInScanDirs(download_at_path); | ||||
|       foreach(const QString &old_folder, old_folders) { | ||||
|         // Update deleted folders | ||||
|         if(!new_folders.contains(old_folder)) { | ||||
|           BTSession->getScanFoldersModel()->removePath(old_folder); | ||||
|         } | ||||
|       } | ||||
|       int i = 0; | ||||
|       foreach(const QString &new_folder, new_folders) { | ||||
|         // Update new folders | ||||
|         if(!old_folders.contains(new_folder)) { | ||||
|           BTSession->getScanFoldersModel()->addPath(new_folder, download_at_path.at(i).toBool()); | ||||
|         } | ||||
|         ++i; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   if(m.contains("export_dir")) | ||||
|     Preferences::setExportDir(m["export_dir"].toString()); | ||||
|   if(m.contains("preallocate_all")) | ||||
|     Preferences::preAllocateAllFiles(m["preallocate_all"].toBool()); | ||||
|   if(m.contains("queueing_enabled")) | ||||
| @@ -165,6 +189,10 @@ void EventManager::setGlobalPreferences(QVariantMap m) const { | ||||
|   // Bittorrent | ||||
|   if(m.contains("dht")) | ||||
|     Preferences::setDHTEnabled(m["dht"].toBool()); | ||||
|   if(m.contains("dhtSameAsBT")) | ||||
|     Preferences::setDHTPortSameAsBT(m["dhtSameAsBT"].toBool()); | ||||
|   if(m.contains("dht_port")) | ||||
|     Preferences::setDHTPort(m["dht_port"].toInt()); | ||||
|   if(m.contains("pex")) | ||||
|     Preferences::setPeXEnabled(m["pex"].toBool()); | ||||
|   qDebug("Pex support: %d", (int)m["pex"].toBool()); | ||||
| @@ -227,8 +255,10 @@ QVariantMap EventManager::getGlobalPreferences() const { | ||||
|   data["save_path"] = Preferences::getSavePath(); | ||||
|   data["temp_path_enabled"] = Preferences::isTempPathEnabled(); | ||||
|   data["temp_path"] = Preferences::getTempPath(); | ||||
|   data["scan_dir_enabled"] = Preferences::isDirScanEnabled(); | ||||
|   data["scan_dir"] = Preferences::getScanDir(); | ||||
|   data["scan_dirs"] = Preferences::getScanDirs(); | ||||
|   data["download_in_scan_dirs"] = Preferences::getDownloadInScanDirs(); | ||||
|   data["export_dir_enabled"] = Preferences::isTorrentExportEnabled(); | ||||
|   data["export_dir"] = Preferences::getExportDir(); | ||||
|   data["preallocate_all"] = Preferences::preAllocateAllFiles(); | ||||
|   data["queueing_enabled"] = Preferences::isQueueingSystemEnabled(); | ||||
|   data["max_active_downloads"] = Preferences::getMaxActiveDownloads(); | ||||
| @@ -248,6 +278,8 @@ QVariantMap EventManager::getGlobalPreferences() const { | ||||
|   data["max_uploads_per_torrent"] = Preferences::getMaxUploadsPerTorrent(); | ||||
|   // Bittorrent | ||||
|   data["dht"] = Preferences::isDHTEnabled(); | ||||
|   data["dhtSameAsBT"] = Preferences::isDHTPortSameAsBT(); | ||||
|   data["dht_port"] = Preferences::getDHTPort(); | ||||
|   data["pex"] = Preferences::isPeXEnabled(); | ||||
|   data["lsd"] = Preferences::isLSDEnabled(); | ||||
|   data["encryption"] = Preferences::getEncryptionSetting(); | ||||
| @@ -282,28 +314,30 @@ QVariantMap EventManager::getPropGeneralInfo(QString hash) const { | ||||
|   QTorrentHandle h = BTSession->getTorrentHandle(hash); | ||||
|   if(h.is_valid() && h.has_metadata()) { | ||||
|     // Save path | ||||
|     data["save_path"] = TorrentPersistentData::getSavePath(hash); | ||||
|     QString p = TorrentPersistentData::getSavePath(hash); | ||||
|     if(p.isEmpty()) p = h.save_path(); | ||||
|     data["save_path"] = p; | ||||
|     // Creation date | ||||
|     data["creation_date"] = h.creation_date(); | ||||
|     // Comment | ||||
|     data["comment"] = h.comment(); | ||||
|     data["total_wasted"] = misc::friendlyUnit(h.total_failed_bytes()+h.total_redundant_bytes()); | ||||
|     data["total_uploaded"] = misc::friendlyUnit(h.all_time_upload()) + " ("+misc::friendlyUnit(h.total_payload_upload())+" "+tr("this session")+")"; | ||||
|     data["total_downloaded"] = misc::friendlyUnit(h.all_time_download()) + " ("+misc::friendlyUnit(h.total_payload_download())+" "+tr("this session")+")"; | ||||
|     data["total_wasted"] = QVariant(misc::friendlyUnit(h.total_failed_bytes()+h.total_redundant_bytes())); | ||||
|     data["total_uploaded"] = QVariant(misc::friendlyUnit(h.all_time_upload()) + " ("+misc::friendlyUnit(h.total_payload_upload())+" "+tr("this session")+")"); | ||||
|     data["total_downloaded"] = QVariant(misc::friendlyUnit(h.all_time_download()) + " ("+misc::friendlyUnit(h.total_payload_download())+" "+tr("this session")+")"); | ||||
|     if(h.upload_limit() <= 0) | ||||
|       data["up_limit"] = QString::fromUtf8("∞"); | ||||
|     else | ||||
|       data["up_limit"] = misc::friendlyUnit(h.upload_limit())+tr("/s", "/second (i.e. per second)"); | ||||
|       data["up_limit"] = QVariant(misc::friendlyUnit(h.upload_limit())+tr("/s", "/second (i.e. per second)")); | ||||
|     if(h.download_limit() <= 0) | ||||
|       data["dl_limit"] = QString::fromUtf8("∞"); | ||||
|     else | ||||
|       data["dl_limit"] =  misc::friendlyUnit(h.download_limit())+tr("/s", "/second (i.e. per second)"); | ||||
|       data["dl_limit"] =  QVariant(misc::friendlyUnit(h.download_limit())+tr("/s", "/second (i.e. per second)")); | ||||
|     QString elapsed_txt = misc::userFriendlyDuration(h.active_time()); | ||||
|     if(h.is_seed()) { | ||||
|       elapsed_txt += " ("+tr("Seeded for %1", "e.g. Seeded for 3m10s").arg(misc::userFriendlyDuration(h.seeding_time()))+")"; | ||||
|     } | ||||
|     data["time_elapsed"] = elapsed_txt; | ||||
|     data["nb_connections"] = QString::number(h.num_connections())+" ("+tr("%1 max", "e.g. 10 max").arg(QString::number(h.connections_limit()))+")"; | ||||
|     data["nb_connections"] = QVariant(QString::number(h.num_connections())+" ("+tr("%1 max", "e.g. 10 max").arg(QString::number(h.connections_limit()))+")"); | ||||
|     // Update ratio info | ||||
|     double ratio = BTSession->getRealRatio(h.hash()); | ||||
|     if(ratio > 100.) | ||||
|   | ||||
| @@ -28,15 +28,16 @@ public: | ||||
|     setColumnCount(1); | ||||
|     QTreeWidgetItem *___qtreewidgetitem = headerItem(); | ||||
|     ___qtreewidgetitem->setText(0, QApplication::translate("RSS", "RSS feeds", 0, QApplication::UnicodeUTF8)); | ||||
|     connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(updateCurrentFeed(QTreeWidgetItem*))); | ||||
|     unread_item = new QTreeWidgetItem(this); | ||||
|     unread_item->setText(0, tr("Unread") + QString::fromUtf8("  (") + QString::number(rssmanager->getNbUnRead(), 10)+ QString(")")); | ||||
|     unread_item->setData(0,Qt::DecorationRole, QVariant(QIcon(":/Icons/oxygen/mail-folder-inbox.png"))); | ||||
|     itemAdded(unread_item, rssmanager); | ||||
|     connect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(updateCurrentFeed(QTreeWidgetItem*))); | ||||
|     setCurrentItem(unread_item); | ||||
|   } | ||||
|  | ||||
|   ~FeedList() { | ||||
|     disconnect(this, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), this, SLOT(updateCurrentFeed(QTreeWidgetItem*))); | ||||
|     delete unread_item; | ||||
|   } | ||||
|  | ||||
| @@ -121,19 +122,19 @@ public: | ||||
|   } | ||||
|  | ||||
|   RssFile* getRSSItem(QTreeWidgetItem *item) const { | ||||
|     return mapping[item]; | ||||
|     return mapping.value(item, 0); | ||||
|   } | ||||
|  | ||||
|   RssFile::FileType getItemType(QTreeWidgetItem *item) const { | ||||
|     return mapping[item]->getType(); | ||||
|     return mapping.value(item)->getType(); | ||||
|   } | ||||
|  | ||||
|   QString getItemID(QTreeWidgetItem *item) const { | ||||
|     return mapping[item]->getID(); | ||||
|     return mapping.value(item)->getID(); | ||||
|   } | ||||
|  | ||||
|   QTreeWidgetItem* getTreeItemFromUrl(QString url) const{ | ||||
|     return feeds_items[url]; | ||||
|     return feeds_items.value(url, 0); | ||||
|   } | ||||
|  | ||||
|   RssStream* getRSSItemFromUrl(QString url) const { | ||||
| @@ -154,7 +155,9 @@ signals: | ||||
|  | ||||
| protected slots: | ||||
|   void updateCurrentFeed(QTreeWidgetItem* new_item) { | ||||
|     if((new_item && getItemType(new_item) == RssFile::STREAM) || new_item == unread_item) | ||||
|     if(!new_item) return; | ||||
|     if(!mapping.contains(new_item)) return; | ||||
|     if((getItemType(new_item) == RssFile::STREAM) || new_item == unread_item) | ||||
|       current_feed = new_item; | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -46,7 +46,7 @@ | ||||
| #include "bittorrent.h" | ||||
| #include "ui_feeddownloader.h" | ||||
|  | ||||
| #ifdef QT_4_5 | ||||
| #if QT_VERSION >= 0x040500 | ||||
| #include <QHash> | ||||
| #else | ||||
| #include <QMap> | ||||
| @@ -64,11 +64,9 @@ public: | ||||
|  | ||||
|   bool matches(QString s) { | ||||
|     QStringList match_tokens = getMatchingTokens(); | ||||
|     //qDebug("Checking matching tokens: \"%s\"", getMatchingTokens_str().toLocal8Bit().data()); | ||||
|     foreach(const QString& token, match_tokens) { | ||||
|       if(token.isEmpty() || token == "") | ||||
|         continue; | ||||
|       //qDebug("Token: %s", token.toLocal8Bit().data()); | ||||
|       QRegExp reg(token, Qt::CaseInsensitive, QRegExp::Wildcard); | ||||
|       //reg.setMinimal(false); | ||||
|       if(reg.indexIn(s) < 0) return false; | ||||
| @@ -226,7 +224,7 @@ public: | ||||
|   void save() { | ||||
|     QSettings qBTRSS("qBittorrent", "qBittorrent-rss"); | ||||
|     QHash<QString, QVariant> all_feeds_filters = qBTRSS.value("feed_filters", QHash<QString, QVariant>()).toHash(); | ||||
|     qDebug("Saving filters for feed: %s (%d filters)", feed_url.toLocal8Bit().data(), (*this).size()); | ||||
|     qDebug("Saving filters for feed: %s (%d filters)", qPrintable(feed_url), (*this).size()); | ||||
|     all_feeds_filters[feed_url] = *this; | ||||
|     qBTRSS.setValue("feed_filters", all_feeds_filters); | ||||
|   } | ||||
| @@ -261,7 +259,6 @@ public: | ||||
|     // Restore saved info | ||||
|     enableDl_cb->setChecked(filters.isDownloadingEnabled()); | ||||
|     fillFiltersList(); | ||||
|     filtersList->sortItems(Qt::AscendingOrder); | ||||
|     if(filters.size() > 0) { | ||||
|       // Select first filter | ||||
|       filtersList->setCurrentItem(filtersList->item(0)); | ||||
| @@ -388,7 +385,6 @@ protected slots: | ||||
|       if(selected_filter == current_name) | ||||
|         selected_filter = new_name; | ||||
|       item->setText(new_name); | ||||
|       filtersList->sortItems(Qt::AscendingOrder); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -442,7 +438,6 @@ protected slots: | ||||
|       } | ||||
|     }while(!validated); | ||||
|     QListWidgetItem *it = new QListWidgetItem(filter_name, filtersList); | ||||
|     filtersList->sortItems(Qt::AscendingOrder); | ||||
|     filtersList->setCurrentItem(it); | ||||
|     //showFilterSettings(it); | ||||
|   } | ||||
|   | ||||
| @@ -34,12 +34,14 @@ | ||||
| class FileSystemWatcher: public QFileSystemWatcher { | ||||
|   Q_OBJECT | ||||
|  | ||||
| #ifndef Q_WS_WIN | ||||
| private: | ||||
|   QDir watched_folder; | ||||
| #ifndef Q_WS_WIN | ||||
|   QList<QDir> watched_folders; | ||||
|   QPointer<QTimer> watch_timer; | ||||
| #endif | ||||
|   QStringList filters; | ||||
|  | ||||
| #ifndef Q_WS_WIN | ||||
| protected: | ||||
|   bool isNetworkFileSystem(QString path) { | ||||
|     QString file = path; | ||||
| @@ -47,10 +49,10 @@ protected: | ||||
|       file += QDir::separator(); | ||||
|     file += "."; | ||||
|     struct statfs buf; | ||||
|     if(!statfs(file.toLocal8Bit().data(), &buf)) { | ||||
|     if(!statfs(file.toLocal8Bit().constData(), &buf)) { | ||||
|       return (buf.f_type == (long)CIFS_MAGIC_NUMBER || buf.f_type == (long)NFS_SUPER_MAGIC); | ||||
|     } else { | ||||
|       std::cerr << "Error: statfs() call failed for " << file.toLocal8Bit().data() << ". Supposing it is a local folder..." << std::endl; | ||||
|       std::cerr << "Error: statfs() call failed for " << qPrintable(file) << ". Supposing it is a local folder..." << std::endl; | ||||
|       switch(errno) { | ||||
|       case EACCES: | ||||
|         std::cerr << "Search permission is denied for a component of the path prefix of the path" << std::endl; | ||||
| @@ -98,13 +100,7 @@ protected: | ||||
| public: | ||||
|   FileSystemWatcher(QObject *parent): QFileSystemWatcher(parent) { | ||||
|     filters << "*.torrent"; | ||||
|     connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanFolder())); | ||||
|   } | ||||
|  | ||||
|   FileSystemWatcher(QString path, QObject *parent): QFileSystemWatcher(parent) { | ||||
|     filters << "*.torrent"; | ||||
|     connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanFolder())); | ||||
|     addPath(path); | ||||
|     connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanLocalFolder(QString))); | ||||
|   } | ||||
|  | ||||
|   ~FileSystemWatcher() { | ||||
| @@ -115,33 +111,40 @@ public: | ||||
|   } | ||||
|  | ||||
|   QStringList directories() const { | ||||
|     QStringList dirs; | ||||
| #ifndef Q_WS_WIN | ||||
|     if(watch_timer) | ||||
|       return QStringList(watched_folder.path()); | ||||
|     if(watch_timer) { | ||||
|       foreach (const QDir &dir, watched_folders) | ||||
|         dirs << dir.canonicalPath(); | ||||
|     } | ||||
| #endif | ||||
|     return QFileSystemWatcher::directories(); | ||||
|     dirs << QFileSystemWatcher::directories(); | ||||
|     return dirs; | ||||
|   } | ||||
|  | ||||
|   void addPath(const QString & path) { | ||||
| #ifndef Q_WS_WIN | ||||
|     watched_folder = QDir(path); | ||||
|     if(!watched_folder.exists()) return; | ||||
|     QDir dir(path); | ||||
|     if (!dir.exists()) | ||||
|       return; | ||||
|     // Check if the path points to a network file system or not | ||||
|     if(isNetworkFileSystem(path)) { | ||||
|       // Network mode | ||||
|       Q_ASSERT(!watch_timer); | ||||
|       qDebug("Network folder detected: %s", path.toLocal8Bit().data()); | ||||
|       qDebug("Network folder detected: %s", qPrintable(path)); | ||||
|       qDebug("Using file polling mode instead of inotify..."); | ||||
|       watched_folders << dir; | ||||
|       // Set up the watch timer | ||||
|       watch_timer = new QTimer(this); | ||||
|       connect(watch_timer, SIGNAL(timeout()), this, SLOT(scanFolder())); | ||||
|       watch_timer->start(5000); // 5 sec | ||||
|       if (!watch_timer) { | ||||
|         watch_timer = new QTimer(this); | ||||
|         connect(watch_timer, SIGNAL(timeout()), this, SLOT(scanNetworkFolders())); | ||||
|         watch_timer->start(5000); // 5 sec | ||||
|       } | ||||
|     } else { | ||||
| #endif | ||||
|       // Normal mode | ||||
|       qDebug("FS Watching is watching %s in normal mode", path.toLocal8Bit().data()); | ||||
|       qDebug("FS Watching is watching %s in normal mode", qPrintable(path)); | ||||
|       QFileSystemWatcher::addPath(path); | ||||
|       scanFolder(); | ||||
|       scanLocalFolder(path); | ||||
| #ifndef Q_WS_WIN | ||||
|     } | ||||
| #endif | ||||
| @@ -149,38 +152,58 @@ public: | ||||
|  | ||||
|   void removePath(const QString & path) { | ||||
| #ifndef Q_WS_WIN | ||||
|     if(watch_timer) { | ||||
|       // Network mode | ||||
|       if(QDir(path) == watched_folder) { | ||||
|         delete watch_timer; | ||||
|     QDir dir(path); | ||||
|     for (int i = 0; i < watched_folders.count(); ++i) { | ||||
|       if (QDir(watched_folders.at(i)) == dir) { | ||||
|         watched_folders.removeAt(i); | ||||
|         if (watched_folders.isEmpty()) | ||||
|           delete watch_timer; | ||||
|         return; | ||||
|       } | ||||
|     } else { | ||||
| #endif | ||||
|       // Normal mode | ||||
|       QFileSystemWatcher::removePath(path); | ||||
| #ifndef Q_WS_WIN | ||||
|     } | ||||
| #endif | ||||
|     // Normal mode | ||||
|     QFileSystemWatcher::removePath(path); | ||||
|   } | ||||
|  | ||||
| protected slots: | ||||
|   // XXX: Does not detect file size changes to improve performance. | ||||
|   void scanFolder() { | ||||
|     qDebug("Scan folder was called"); | ||||
|   void scanLocalFolder(QString path) { | ||||
|     qDebug("scanLocalFolder(%s) called", qPrintable(path)); | ||||
|     QStringList torrents; | ||||
|     if(watch_timer) { | ||||
|       torrents = watched_folder.entryList(filters, QDir::Files, QDir::Unsorted); | ||||
|     } else { | ||||
|       torrents = QDir(QFileSystemWatcher::directories().first()).entryList(filters, QDir::Files, QDir::Unsorted); | ||||
|       qDebug("FSWatcher: Polling manually folder %s", QFileSystemWatcher::directories().first().toLocal8Bit().data()); | ||||
|     } | ||||
|     if(!torrents.empty()) | ||||
|     // Local folders scan | ||||
|     addTorrentsFromDir(QDir(path), torrents); | ||||
|     // Report detected torrent files | ||||
|     if(!torrents.empty()) { | ||||
|       qDebug("The following files are being reported: %s", qPrintable(torrents.join("\n"))); | ||||
|       emit torrentsAdded(torrents); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void scanNetworkFolders() { | ||||
|     qDebug("scanNetworkFolders() called"); | ||||
|     QStringList torrents; | ||||
|     // Network folders scan | ||||
|     foreach (const QDir &dir, watched_folders) { | ||||
|       //qDebug("FSWatcher: Polling manually folder %s", qPrintable(dir.path())); | ||||
|       addTorrentsFromDir(dir, torrents); | ||||
|     } | ||||
|     // Report detected torrent files | ||||
|     if(!torrents.empty()) { | ||||
|       qDebug("The following files are being reported: %s", qPrintable(torrents.join("\n"))); | ||||
|       emit torrentsAdded(torrents); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| signals: | ||||
|   void torrentsAdded(QStringList &pathList); | ||||
|  | ||||
| private: | ||||
|   void addTorrentsFromDir(const QDir &dir, QStringList &torrents) { | ||||
|     const QStringList &files = dir.entryList(filters, QDir::Files, QDir::Unsorted); | ||||
|     foreach(const QString &file, files) | ||||
|       torrents << dir.canonicalPath() + '/' + file; | ||||
|   } | ||||
|  | ||||
| }; | ||||
|  | ||||
| #endif // FILESYSTEMWATCHER_H | ||||
|   | ||||