Compare commits
294 Commits
release-2.
...
release-2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3513288468 | ||
|
|
1cb30d77fd | ||
|
|
126e2e7c75 | ||
|
|
9c13ed2635 | ||
|
|
e11545c8a3 | ||
|
|
ad087d7e88 | ||
|
|
c387c15eb0 | ||
|
|
345222cf42 | ||
|
|
adffd7df74 | ||
|
|
4de980c1a1 | ||
|
|
578a5c9551 | ||
|
|
c47dbfb1f5 | ||
|
|
cb0942b388 | ||
|
|
1904bc1abb | ||
|
|
5a02c56865 | ||
|
|
d7b0299416 | ||
|
|
265ab7bef2 | ||
|
|
e824bc8bb1 | ||
|
|
046ebb5a8f | ||
|
|
8b83d60732 | ||
|
|
d2754fb242 | ||
|
|
30ba1a428e | ||
|
|
0553668da8 | ||
|
|
ff63d75532 | ||
|
|
b7ec18e4f1 | ||
|
|
9c9944715a | ||
|
|
ea1a54c5f1 | ||
|
|
34cb5efb72 | ||
|
|
8597689a52 | ||
|
|
41a61ced89 | ||
|
|
da95d5e0df | ||
|
|
8276c301c2 | ||
|
|
75ff9984fa | ||
|
|
cda77d1724 | ||
|
|
583b8c60bb | ||
|
|
5c2b57052b | ||
|
|
9cf79a4a76 | ||
|
|
c4968edb79 | ||
|
|
a859a6d179 | ||
|
|
e2c75b5a11 | ||
|
|
12195b186b | ||
|
|
658d876ff7 | ||
|
|
390508e7db | ||
|
|
0a2efaf5fc | ||
|
|
6b7af5b464 | ||
|
|
a2c19302cb | ||
|
|
1638554944 | ||
|
|
1d1b49205d | ||
|
|
0ca7100168 | ||
|
|
26c680ae1f | ||
|
|
6c1eda8755 | ||
|
|
0374f9d0a8 | ||
|
|
080a36de5f | ||
|
|
071801fee7 | ||
|
|
bee507cb45 | ||
|
|
7d6df2a3c2 | ||
|
|
a2ffecd6bd | ||
|
|
1532b24448 | ||
|
|
c4dae02ef6 | ||
|
|
846962aab1 | ||
|
|
35e98b6cbb | ||
|
|
ecfc3d0118 | ||
|
|
3ecc8c8d67 | ||
|
|
a83fbf5a98 | ||
|
|
328e4fd860 | ||
|
|
b98d0282ce | ||
|
|
166dad51d5 | ||
|
|
e3ccea3b17 | ||
|
|
8a64a6441e | ||
|
|
c34000ab17 | ||
|
|
90dd337069 | ||
|
|
31e4b8dc31 | ||
|
|
5145abe5c8 | ||
|
|
7ec842929a | ||
|
|
39778baaf5 | ||
|
|
0a510db95e | ||
|
|
c73243b0d2 | ||
|
|
46b75b760f | ||
|
|
fc3ae51122 | ||
|
|
05d9f28f8b | ||
|
|
b1b2a2c775 | ||
|
|
105de3161a | ||
|
|
354d968a94 | ||
|
|
f617b74bac | ||
|
|
3664134e02 | ||
|
|
1875846326 | ||
|
|
64f0adc813 | ||
|
|
a9d4b38bd3 | ||
|
|
44fa7388d5 | ||
|
|
24df142b02 | ||
|
|
958b73f2cb | ||
|
|
1962898e24 | ||
|
|
56b88661bc | ||
|
|
5b47a762ac | ||
|
|
a5c6bcceea | ||
|
|
290932e128 | ||
|
|
f53fe96191 | ||
|
|
fc8a822dac | ||
|
|
b7a3ae2b4c | ||
|
|
26d19b33e6 | ||
|
|
4ba9dc1fed | ||
|
|
2c3f99692d | ||
|
|
a27d2dcac2 | ||
|
|
f7cb6a7da5 | ||
|
|
6855edf649 | ||
|
|
aff27558dd | ||
|
|
f6172f8c77 | ||
|
|
1562088bc8 | ||
|
|
67973515d5 | ||
|
|
7867cf68f9 | ||
|
|
1eb26bd78b | ||
|
|
a8d635f7ac | ||
|
|
289ad37f06 | ||
|
|
94de42bf2e | ||
|
|
ca9f40eb7f | ||
|
|
4013f9fefd | ||
|
|
ccf0002c0f | ||
|
|
86fb4a323a | ||
|
|
38c56a2b5f | ||
|
|
2d1286158a | ||
|
|
6e7309316c | ||
|
|
593fdad426 | ||
|
|
933a831eb1 | ||
|
|
7c55082464 | ||
|
|
fa3e70316e | ||
|
|
c9c2ab320d | ||
|
|
53d9817d8a | ||
|
|
828ecb6b3c | ||
|
|
af61ed7c72 | ||
|
|
1e86ea8c0a | ||
|
|
129bfac549 | ||
|
|
4815bb9f11 | ||
|
|
81eb8b1341 | ||
|
|
1596dc5206 | ||
|
|
76a22fabcd | ||
|
|
3d7bf26f85 | ||
|
|
69661406a0 | ||
|
|
74fba0fb7e | ||
|
|
d56fc9fcd4 | ||
|
|
124dcee7b8 | ||
|
|
b5b06ce36d | ||
|
|
ef01088411 | ||
|
|
bc87c1c409 | ||
|
|
bbe4328c06 | ||
|
|
d557410156 | ||
|
|
a150e24ce4 | ||
|
|
261d02863c | ||
|
|
c64f02c9bf | ||
|
|
790db14b51 | ||
|
|
2500ac2cb7 | ||
|
|
cd8a7cf0e0 | ||
|
|
b3be32126d | ||
|
|
643bc5516c | ||
|
|
eb94c59892 | ||
|
|
72f4c81f4c | ||
|
|
9543bd63f9 | ||
|
|
7ae7a71782 | ||
|
|
8994ca6dd5 | ||
|
|
354dceeaf0 | ||
|
|
50c7225c1e | ||
|
|
44d945b5c0 | ||
|
|
4ff6104601 | ||
|
|
80760dd7af | ||
|
|
7835a13573 | ||
|
|
9b26fd50b2 | ||
|
|
eb54d81c5e | ||
|
|
431d2f082c | ||
|
|
a0ff0cdc7e | ||
|
|
fb91558261 | ||
|
|
fc2a47ca31 | ||
|
|
dcccbaad59 | ||
|
|
99d040de3f | ||
|
|
ee30a75b57 | ||
|
|
8c001aa478 | ||
|
|
849bc11a01 | ||
|
|
5024e0b092 | ||
|
|
d93447489b | ||
|
|
33988e70ab | ||
|
|
d2b41d70c8 | ||
|
|
8e1e51d268 | ||
|
|
53500ea005 | ||
|
|
e048389dea | ||
|
|
fa7b1a205d | ||
|
|
7dd6b7e9bb | ||
|
|
78b96accda | ||
|
|
73d0e2568a | ||
|
|
92fc212a0e | ||
|
|
6f4d7b7c1b | ||
|
|
63ee1c36e8 | ||
|
|
7d07debcb5 | ||
|
|
dd67e1ee9d | ||
|
|
493efdbf10 | ||
|
|
e323175275 | ||
|
|
c1fa7f8645 | ||
|
|
275b962363 | ||
|
|
3847c33017 | ||
|
|
9e21f52213 | ||
|
|
25cf9b33ec | ||
|
|
c7a2d3589f | ||
|
|
d8dd3834c3 | ||
|
|
ee01c2c745 | ||
|
|
e7e5a2b4e9 | ||
|
|
ff16f59be1 | ||
|
|
2cd4937ddc | ||
|
|
0e9abc1762 | ||
|
|
e24ce87946 | ||
|
|
308e358d3f | ||
|
|
d15e6a4847 | ||
|
|
e311239a28 | ||
|
|
df677789d2 | ||
|
|
0af44eadb6 | ||
|
|
85cafe530e | ||
|
|
7609db28f1 | ||
|
|
fefda39284 | ||
|
|
b2f98bd059 | ||
|
|
26c69fe6d4 | ||
|
|
bf4f1a7c37 | ||
|
|
9b0dd39d9d | ||
|
|
66d4cc2ab8 | ||
|
|
0bcbaf6521 | ||
|
|
e074872b24 | ||
|
|
63ec1e618e | ||
|
|
331c15b76c | ||
|
|
d2089c9aad | ||
|
|
3c8326d3b6 | ||
|
|
2d0713ca1d | ||
|
|
afaca423cc | ||
|
|
ff08abe177 | ||
|
|
159be479cc | ||
|
|
f3066b07b5 | ||
|
|
aa58636832 | ||
|
|
5d1a584eac | ||
|
|
7ee9abd646 | ||
|
|
4d977a8d46 | ||
|
|
5c891724c4 | ||
|
|
185af18790 | ||
|
|
fa6da97cf9 | ||
|
|
9503d9b024 | ||
|
|
de7b6ca553 | ||
|
|
1788078594 | ||
|
|
3caf473424 | ||
|
|
5435bd2354 | ||
|
|
1cdb22a7e3 | ||
|
|
95a9424ae7 | ||
|
|
902196a176 | ||
|
|
dbfef8665b | ||
|
|
b3d8f2400f | ||
|
|
c12ae58868 | ||
|
|
4b77bb57ad | ||
|
|
a6b1d308c2 | ||
|
|
b483f09d11 | ||
|
|
bbb5ad31c4 | ||
|
|
3d4c1fe7da | ||
|
|
7a2c0d5d5a | ||
|
|
39d86c5f61 | ||
|
|
e2cdbbb184 | ||
|
|
e83f9245a9 | ||
|
|
52f25c44eb | ||
|
|
1ed565d8e5 | ||
|
|
10801f111b | ||
|
|
efe1655834 | ||
|
|
7f71e3981e | ||
|
|
8113f8df63 | ||
|
|
62f579fdbe | ||
|
|
1d4454c6eb | ||
|
|
310433fb54 | ||
|
|
c0520146e9 | ||
|
|
35f6675d86 | ||
|
|
9494b15bd5 | ||
|
|
3b82120923 | ||
|
|
b9a0adc311 | ||
|
|
1e21ac3d79 | ||
|
|
864bb8285e | ||
|
|
208e988c70 | ||
|
|
5cbcfb8efb | ||
|
|
107b833703 | ||
|
|
e2208a484e | ||
|
|
5ab7c91d49 | ||
|
|
a91ad3c9c7 | ||
|
|
385f950c2b | ||
|
|
4667a84939 | ||
|
|
5af0cacf0c | ||
|
|
bceb00d35f | ||
|
|
51068294f1 | ||
|
|
bcdf4e42fa | ||
|
|
214bb13843 | ||
|
|
7998395532 | ||
|
|
35aee18112 | ||
|
|
8ddbdd34ed | ||
|
|
66a5e479c7 | ||
|
|
8f5bd2bc9f | ||
|
|
5be2624cb1 | ||
|
|
f9684d662d | ||
|
|
9373796dd5 |
4
AUTHORS
@@ -12,7 +12,7 @@ Contributors:
|
|||||||
* Silvan Scherrer <silvan.scherrer@aroa.ch>
|
* Silvan Scherrer <silvan.scherrer@aroa.ch>
|
||||||
|
|
||||||
Code from other projects:
|
Code from other projects:
|
||||||
* files src/qtsingleapp/*
|
* files src/qtsingleapp/* src/lineedit/*
|
||||||
copyright: Nokia Corporation
|
copyright: Nokia Corporation
|
||||||
license: LGPL
|
license: LGPL
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ Translations authors:
|
|||||||
- German: Niels Hoffmann (zentralmaschine@users.sourceforge.net)
|
- German: Niels Hoffmann (zentralmaschine@users.sourceforge.net)
|
||||||
- Greek: Tsvetan Bankov (emerge_life@users.sourceforge.net) and Stephanos Antaris (santaris@csd.auth.gr)
|
- Greek: Tsvetan Bankov (emerge_life@users.sourceforge.net) and Stephanos Antaris (santaris@csd.auth.gr)
|
||||||
- Hungarian: Majoros Péter (majoros.j.p@t-online.hu)
|
- Hungarian: Majoros Péter (majoros.j.p@t-online.hu)
|
||||||
- Italian: Mirko Ferrari (mirkoferrari@gmail.com) and Ferraro Luciano (luciano.ferraro@gmail.com)
|
- Italian: Matteo Sechi (bu17714@gmail.com)
|
||||||
- Japanese: Nardog (alphisation@gmail.com)
|
- Japanese: Nardog (alphisation@gmail.com)
|
||||||
- Korean: Jin Woo Sin (jin828sin@users.sourceforge.net)
|
- Korean: Jin Woo Sin (jin828sin@users.sourceforge.net)
|
||||||
- Norwegian: Lars-Erik Labori (hamil@users.sourceforge.net)
|
- Norwegian: Lars-Erik Labori (hamil@users.sourceforge.net)
|
||||||
|
|||||||
28
Changelog
@@ -1,4 +1,28 @@
|
|||||||
* Unreleased - Christophe Dumez <chris@qbittorrent.org> - v2.3.0
|
* Unreleased - Christophe Dumez <chris@qbittorrent.org> - v2.5.0
|
||||||
|
- FEATURE: qBittorrent can now act as a tracker
|
||||||
|
- FEATURE: New and improved RSS feed automated downloader
|
||||||
|
- FEATURE: Added feature to shutdown qbittorrent on torrents completion
|
||||||
|
- FEATURE: Added a torrent import assistant to seed or keep downloading outside torrents
|
||||||
|
- FEATURE: qBittorrent can update itself from Sourceforge (Windows/Mac OS X only)
|
||||||
|
- FEATURE: Added a transfer list column to display the current tracker
|
||||||
|
- FEATURE: Remember the last trackers used in the torrent creation tool
|
||||||
|
- FEATURE: The optimal piece size is now automatically computed in the torrent creation tool
|
||||||
|
- FEATURE: Bring up the connection settings when clicking on the connection status icon
|
||||||
|
- COSMETIC: Replaced message box by on-screen notification for download errors
|
||||||
|
- COSMETIC: Improved the torrent creation tool appearance
|
||||||
|
- OTHERS: Dropped support for Qt <= 4.4
|
||||||
|
|
||||||
|
* Tue Aug 24 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.4.0
|
||||||
|
- FEATURE: Added actions to "Move to top/bottom" of priority queue
|
||||||
|
- FEATURE: Auto-Shutdown on downloads completion
|
||||||
|
- FEATURE: Email notification on download completion
|
||||||
|
- FEATURE: Added button to password-lock the UI
|
||||||
|
- FEATURE: Added label-level Pause/Resume/Delete actions
|
||||||
|
- FEATURE: Torrents can now be filtered by name
|
||||||
|
- FEATURE: Run external program on torrent completion
|
||||||
|
- FEATURE: Detect executable updates in order to advise the user to restart
|
||||||
|
|
||||||
|
* Tue Jul 27 2010 - Christophe Dumez <chris@qbittorrent.org> - v2.3.0
|
||||||
- FEATURE: Simplified torrent root folder renaming/truncating (< v2.3.0 is no longer forward compatible)
|
- FEATURE: Simplified torrent root folder renaming/truncating (< v2.3.0 is no longer forward compatible)
|
||||||
- FEATURE: Remember previous save paths in torrent addition dialog
|
- FEATURE: Remember previous save paths in torrent addition dialog
|
||||||
- FEATURE: Max number of half-open connections can now be edited
|
- FEATURE: Max number of half-open connections can now be edited
|
||||||
@@ -15,10 +39,12 @@
|
|||||||
- FEATURE: Torrents can be automatically paused once they reach a given ratio
|
- FEATURE: Torrents can be automatically paused once they reach a given ratio
|
||||||
- FEATURE: Several files can now be disabled at once
|
- FEATURE: Several files can now be disabled at once
|
||||||
- FEATURE: Added "Select All/None" buttons to files list
|
- FEATURE: Added "Select All/None" buttons to files list
|
||||||
|
- FEATURE: Added support for BitComet links (bc://bt/...)
|
||||||
- BUGFIX: Hide seeding torrents files priorities in Web UI
|
- BUGFIX: Hide seeding torrents files priorities in Web UI
|
||||||
- BUGFIX: The user can disable permanently recursive torrent download
|
- BUGFIX: The user can disable permanently recursive torrent download
|
||||||
- BUGFIX: Peer Exchange status is now correctly reported
|
- BUGFIX: Peer Exchange status is now correctly reported
|
||||||
- BUGFIX: Use an INI file instead of the registry on Windows (More reliable)
|
- BUGFIX: Use an INI file instead of the registry on Windows (More reliable)
|
||||||
|
- BUGFIX: Removed client spoofing feature to avoid tracker blacklisting
|
||||||
- COSMETIC: Display peers country name in tooltip
|
- COSMETIC: Display peers country name in tooltip
|
||||||
- COSMETIC: Display number of torrents in transfers tab label
|
- COSMETIC: Display number of torrents in transfers tab label
|
||||||
- COSMETIC: Simplified program preferences
|
- COSMETIC: Simplified program preferences
|
||||||
|
|||||||
2
INSTALL
@@ -10,7 +10,7 @@ qBittorrent - A BitTorrent client in C++ / Qt4
|
|||||||
will install and execute qBittorrent hopefully without any problems.
|
will install and execute qBittorrent hopefully without any problems.
|
||||||
|
|
||||||
Dependencies:
|
Dependencies:
|
||||||
- Qt >= 4.4.0 (libqt-devel, libqtgui, libqtcore, libqtnetwork, libqtxml)
|
- Qt >= 4.5.0 (libqt-devel, libqtgui, libqtcore, libqtnetwork, libqtxml)
|
||||||
|
|
||||||
- pkg-config executable
|
- pkg-config executable
|
||||||
|
|
||||||
|
|||||||
92
configure
vendored
@@ -18,15 +18,24 @@ Main options:
|
|||||||
--help This help text.
|
--help This help text.
|
||||||
|
|
||||||
Dependency options:
|
Dependency options:
|
||||||
--disable-gui Disable qBittorrent Graphical user
|
--disable-gui Disable qBittorrent
|
||||||
interface for headless running
|
Graphical user interface for
|
||||||
--with-libboost-inc=[path] Path to libboost include files
|
headless running
|
||||||
--with-libboost-lib=[path] Path to libboost library files
|
--with-libboost-inc=[path] Path to libboost include
|
||||||
--disable-libnotify Disable use of libnotify
|
files
|
||||||
--disable-geoip-database Disable use of geoip-database
|
--with-libboost-lib=[path] Path to libboost library
|
||||||
--with-geoip-database-embedded Geoip Database will be embedded in
|
files
|
||||||
qBittorrent executable (please follow
|
--disable-libnotify Disable use of libnotify
|
||||||
instructions in src/geoip/README)
|
--disable-geoip-database Disable use of geoip-database
|
||||||
|
--with-geoip-database-embedded Geoip Database will be
|
||||||
|
embedded in qBittorrent
|
||||||
|
executable (please follow
|
||||||
|
instructions in
|
||||||
|
src/geoip/README)
|
||||||
|
--disable-qtsingleapplication Disable use of libboost
|
||||||
|
--with-qtsingleapplication=[system|shipped] Use the shipped
|
||||||
|
qtsingleapplication library
|
||||||
|
or the system one
|
||||||
|
|
||||||
EOT
|
EOT
|
||||||
}
|
}
|
||||||
@@ -173,6 +182,16 @@ while [ $# -gt 0 ]; do
|
|||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
|
||||||
|
--disable-qtsingleapplication)
|
||||||
|
QC_DISABLE_qtsingleapplication="Y"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
|
||||||
|
--with-qtsingleapplication=*)
|
||||||
|
QC_WITH_QTSINGLEAPPLICATION=$optarg
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
|
||||||
--verbose)
|
--verbose)
|
||||||
QC_VERBOSE="Y"
|
QC_VERBOSE="Y"
|
||||||
shift
|
shift
|
||||||
@@ -200,6 +219,8 @@ echo QC_WITH_LIBBOOST_LIB=$QC_WITH_LIBBOOST_LIB
|
|||||||
echo QC_DISABLE_libnotify=$QC_DISABLE_libnotify
|
echo QC_DISABLE_libnotify=$QC_DISABLE_libnotify
|
||||||
echo QC_DISABLE_geoip_database=$QC_DISABLE_geoip_database
|
echo QC_DISABLE_geoip_database=$QC_DISABLE_geoip_database
|
||||||
echo QC_WITH_GEOIP_DATABASE_EMBEDDED=$QC_WITH_GEOIP_DATABASE_EMBEDDED
|
echo QC_WITH_GEOIP_DATABASE_EMBEDDED=$QC_WITH_GEOIP_DATABASE_EMBEDDED
|
||||||
|
echo QC_DISABLE_qtsingleapplication=$QC_DISABLE_qtsingleapplication
|
||||||
|
echo QC_WITH_QTSINGLEAPPLICATION=$QC_WITH_QTSINGLEAPPLICATION
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -304,7 +325,7 @@ cat >$1/modules.cpp <<EOT
|
|||||||
#line 1 "qt4.qcm"
|
#line 1 "qt4.qcm"
|
||||||
/*
|
/*
|
||||||
-----BEGIN QCMOD-----
|
-----BEGIN QCMOD-----
|
||||||
name: Qt >= 4.4
|
name: Qt >= 4.5
|
||||||
arg: disable-gui, Disable qBittorrent Graphical user interface for headless running
|
arg: disable-gui, Disable qBittorrent Graphical user interface for headless running
|
||||||
-----END QCMOD-----
|
-----END QCMOD-----
|
||||||
*/
|
*/
|
||||||
@@ -312,14 +333,14 @@ class qc_qt4 : public ConfObj
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
qc_qt4(Conf *c) : ConfObj(c) {}
|
qc_qt4(Conf *c) : ConfObj(c) {}
|
||||||
QString name() const { return "Qt >= 4.4"; }
|
QString name() const { return "Qt >= 4.5"; }
|
||||||
QString shortname() const { return "Qt 4.4"; }
|
QString shortname() const { return "Qt 4.5"; }
|
||||||
bool exec()
|
bool exec()
|
||||||
{
|
{
|
||||||
if(!conf->getenv("QC_DISABLE_GUI").isEmpty()) {
|
if(!conf->getenv("QC_DISABLE_GUI").isEmpty()) {
|
||||||
conf->addDefine("DISABLE_GUI");
|
conf->addDefine("DISABLE_GUI");
|
||||||
}
|
}
|
||||||
return(QT_VERSION >= 0x040400);
|
return(QT_VERSION >= 0x040500);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#line 1 "pkg-config.qcm"
|
#line 1 "pkg-config.qcm"
|
||||||
@@ -529,10 +550,21 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
QStringList incs3;
|
||||||
|
QString req_ver3 = "2.0";
|
||||||
|
QString version3, libs3, other3;
|
||||||
|
if(conf->findPkgConfig("gtk+-2.0", mode, req_ver3, &version3, &incs3, &libs3, &other3)) {
|
||||||
|
for(int n = 0; n < incs3.count(); ++n)
|
||||||
|
conf->addIncludePath(incs3[n]);
|
||||||
|
if(!libs3.isEmpty())
|
||||||
|
conf->addLib(libs3);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -574,6 +606,33 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
#line 1 "qtsingleapplication.qcm"
|
||||||
|
/*
|
||||||
|
-----BEGIN QCMOD-----
|
||||||
|
name: libboost
|
||||||
|
arg: with-qtsingleapplication=[system|shipped], Use the shipped qtsingleapplication library or the system one
|
||||||
|
-----END QCMOD-----
|
||||||
|
*/
|
||||||
|
class qc_qtsingleapplication : public ConfObj
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
qc_qtsingleapplication(Conf *c) : ConfObj(c) {}
|
||||||
|
QString name() const { return "qtsingleapplication library"; }
|
||||||
|
QString shortname() const { return "qtsingleapplication"; }
|
||||||
|
|
||||||
|
bool exec(){
|
||||||
|
QString s;
|
||||||
|
s = conf->getenv("QC_WITH_QTSINGLEAPPLICATION");
|
||||||
|
if(s.compare("system", Qt::CaseInsensitive) == 0) {
|
||||||
|
// System
|
||||||
|
conf->addDefine("USE_SYSTEM_QTSINGLEAPPLICATION");
|
||||||
|
printf(" [system] ");
|
||||||
|
} else {
|
||||||
|
printf(" [shipped] ");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
EOT
|
EOT
|
||||||
cat >$1/modules_new.cpp <<EOT
|
cat >$1/modules_new.cpp <<EOT
|
||||||
@@ -595,6 +654,9 @@ cat >$1/modules_new.cpp <<EOT
|
|||||||
o = new qc_geoip_database(conf);
|
o = new qc_geoip_database(conf);
|
||||||
o->required = false;
|
o->required = false;
|
||||||
o->disabled = false;
|
o->disabled = false;
|
||||||
|
o = new qc_qtsingleapplication(conf);
|
||||||
|
o->required = false;
|
||||||
|
o->disabled = false;
|
||||||
|
|
||||||
EOT
|
EOT
|
||||||
cat >$1/conf4.h <<EOT
|
cat >$1/conf4.h <<EOT
|
||||||
@@ -1546,6 +1608,8 @@ export QC_WITH_LIBBOOST_LIB
|
|||||||
export QC_DISABLE_libnotify
|
export QC_DISABLE_libnotify
|
||||||
export QC_DISABLE_geoip_database
|
export QC_DISABLE_geoip_database
|
||||||
export QC_WITH_GEOIP_DATABASE_EMBEDDED
|
export QC_WITH_GEOIP_DATABASE_EMBEDDED
|
||||||
|
export QC_DISABLE_qtsingleapplication
|
||||||
|
export QC_WITH_QTSINGLEAPPLICATION
|
||||||
export QC_VERBOSE
|
export QC_VERBOSE
|
||||||
rm -rf .qconftemp
|
rm -rf .qconftemp
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -19,4 +19,6 @@
|
|||||||
</dep>
|
</dep>
|
||||||
<dep type='geoip-database'>
|
<dep type='geoip-database'>
|
||||||
</dep>
|
</dep>
|
||||||
|
<dep type='qtsingleapplication'>
|
||||||
|
</dep>
|
||||||
</qconf>
|
</qconf>
|
||||||
|
|||||||
@@ -40,10 +40,21 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
QStringList incs3;
|
||||||
|
QString req_ver3 = "2.0";
|
||||||
|
QString version3, libs3, other3;
|
||||||
|
if(conf->findPkgConfig("gtk+-2.0", mode, req_ver3, &version3, &incs3, &libs3, &other3)) {
|
||||||
|
for(int n = 0; n < incs3.count(); ++n)
|
||||||
|
conf->addIncludePath(incs3[n]);
|
||||||
|
if(!libs3.isEmpty())
|
||||||
|
conf->addLib(libs3);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
-----BEGIN QCMOD-----
|
-----BEGIN QCMOD-----
|
||||||
name: Qt >= 4.4
|
name: Qt >= 4.5
|
||||||
arg: disable-gui, Disable qBittorrent Graphical user interface for headless running
|
arg: disable-gui, Disable qBittorrent Graphical user interface for headless running
|
||||||
-----END QCMOD-----
|
-----END QCMOD-----
|
||||||
*/
|
*/
|
||||||
@@ -8,13 +8,13 @@ class qc_qt4 : public ConfObj
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
qc_qt4(Conf *c) : ConfObj(c) {}
|
qc_qt4(Conf *c) : ConfObj(c) {}
|
||||||
QString name() const { return "Qt >= 4.4"; }
|
QString name() const { return "Qt >= 4.5"; }
|
||||||
QString shortname() const { return "Qt 4.4"; }
|
QString shortname() const { return "Qt 4.5"; }
|
||||||
bool exec()
|
bool exec()
|
||||||
{
|
{
|
||||||
if(!conf->getenv("QC_DISABLE_GUI").isEmpty()) {
|
if(!conf->getenv("QC_DISABLE_GUI").isEmpty()) {
|
||||||
conf->addDefine("DISABLE_GUI");
|
conf->addDefine("DISABLE_GUI");
|
||||||
}
|
}
|
||||||
return(QT_VERSION >= 0x040400);
|
return(QT_VERSION >= 0x040500);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
26
qcm/qtsingleapplication.qcm
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
-----BEGIN QCMOD-----
|
||||||
|
name: libboost
|
||||||
|
arg: with-qtsingleapplication=[system|shipped], Use the shipped qtsingleapplication library or the system one
|
||||||
|
-----END QCMOD-----
|
||||||
|
*/
|
||||||
|
class qc_qtsingleapplication : public ConfObj
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
qc_qtsingleapplication(Conf *c) : ConfObj(c) {}
|
||||||
|
QString name() const { return "qtsingleapplication library"; }
|
||||||
|
QString shortname() const { return "qtsingleapplication"; }
|
||||||
|
|
||||||
|
bool exec(){
|
||||||
|
QString s;
|
||||||
|
s = conf->getenv("QC_WITH_QTSINGLEAPPLICATION");
|
||||||
|
if(s.compare("system", Qt::CaseInsensitive) == 0) {
|
||||||
|
// System
|
||||||
|
conf->addDefine("USE_SYSTEM_QTSINGLEAPPLICATION");
|
||||||
|
printf(" [system] ");
|
||||||
|
} else {
|
||||||
|
printf(" [shipped] ");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
BIN
src/Icons/oxygen/emblem-favorite.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
src/Icons/oxygen/encrypted32.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
src/Icons/oxygen/go-bottom.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
src/Icons/oxygen/go-down.png
Normal file
|
After Width: | Height: | Size: 892 B |
BIN
src/Icons/oxygen/go-top.png
Normal file
|
After Width: | Height: | Size: 996 B |
BIN
src/Icons/oxygen/go-up.png
Normal file
|
After Width: | Height: | Size: 929 B |
BIN
src/Icons/qBitTorrentDocument.icns
Normal file
@@ -1,6 +1,6 @@
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Categories=Qt;Network;P2P;
|
Categories=Qt;Network;P2P;
|
||||||
Comment=V2.3.0
|
Comment=V2.5.0
|
||||||
Exec=qbittorrent %f
|
Exec=qbittorrent %f
|
||||||
GenericName=Bittorrent client
|
GenericName=Bittorrent client
|
||||||
GenericName[ar]=العميل Bittorrent
|
GenericName[ar]=العميل Bittorrent
|
||||||
|
|||||||
BIN
src/Icons/skin/arrow-right.gif
Normal file
|
After Width: | Height: | Size: 54 B |
BIN
src/Icons/skin/delete_perm22.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 75 KiB |
@@ -10,13 +10,13 @@
|
|||||||
<string>torrent</string>
|
<string>torrent</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleTypeIconFile</key>
|
<key>CFBundleTypeIconFile</key>
|
||||||
<string>qbittorrentDocument</string>
|
<string>qBitTorrentDocument</string>
|
||||||
<key>CFBundleTypeName</key>
|
<key>CFBundleTypeName</key>
|
||||||
<string>BitTorrent Document</string>
|
<string>BitTorrent Document</string>
|
||||||
<key>CFBundleTypeMIMETypes</key>
|
<key>CFBundleTypeMIMETypes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>application/x-bittorrent</string>
|
<string>application/x-bittorrent</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleTypeRole</key>
|
<key>CFBundleTypeRole</key>
|
||||||
<string>Viewer</string>
|
<string>Viewer</string>
|
||||||
<key>LSHandlerRank</key>
|
<key>LSHandlerRank</key>
|
||||||
@@ -47,7 +47,7 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleGetInfoString</key>
|
<key>CFBundleGetInfoString</key>
|
||||||
<string>2.3.0</string>
|
<string>2.5.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
|
|||||||
6
src/about.qrc
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<!DOCTYPE RCC><RCC version="1.0">
|
||||||
|
<qresource>
|
||||||
|
<file>gpl.html</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
||||||
|
|
||||||
439
src/about_imp.h
@@ -11,15 +11,15 @@
|
|||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
|
|
||||||
enum AdvSettingsCols {PROPERTY, VALUE};
|
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, MAX_HALF_OPEN, SUPER_SEEDING, NETWORK_IFACE };
|
enum AdvSettingsRows {DISK_CACHE, OUTGOING_PORT_MIN, OUTGOING_PORT_MAX, IGNORE_LIMIT_LAN, COUNT_OVERHEAD, RECHECK_COMPLETED, LIST_REFRESH, RESOLVE_COUNTRIES, RESOLVE_HOSTS, MAX_HALF_OPEN, SUPER_SEEDING, NETWORK_IFACE, PROGRAM_NOTIFICATIONS, TRACKER_STATUS, TRACKER_PORT };
|
||||||
#define ROW_COUNT 12
|
#define ROW_COUNT 15
|
||||||
|
|
||||||
class AdvancedSettings: public QTableWidget {
|
class AdvancedSettings: public QTableWidget {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QSpinBox *spin_cache, *outgoing_ports_min, *outgoing_ports_max, *spin_list_refresh, *spin_maxhalfopen;
|
QSpinBox *spin_cache, *outgoing_ports_min, *outgoing_ports_max, *spin_list_refresh, *spin_maxhalfopen, *spin_tracker_port;
|
||||||
QCheckBox *cb_ignore_limits_lan, *cb_count_overhead, *cb_recheck_completed, *cb_resolve_countries, *cb_resolve_hosts, *cb_super_seeding;
|
QCheckBox *cb_ignore_limits_lan, *cb_count_overhead, *cb_recheck_completed, *cb_resolve_countries, *cb_resolve_hosts, *cb_super_seeding, *cb_program_notifications, *cb_tracker_status;
|
||||||
QComboBox *combo_iface;
|
QComboBox *combo_iface;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -52,6 +52,9 @@ public:
|
|||||||
delete spin_maxhalfopen;
|
delete spin_maxhalfopen;
|
||||||
delete cb_super_seeding;
|
delete cb_super_seeding;
|
||||||
delete combo_iface;
|
delete combo_iface;
|
||||||
|
delete cb_program_notifications;
|
||||||
|
delete spin_tracker_port;
|
||||||
|
delete cb_tracker_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
@@ -85,6 +88,11 @@ public slots:
|
|||||||
} else {
|
} else {
|
||||||
Preferences::setNetworkInterface(combo_iface->currentText());
|
Preferences::setNetworkInterface(combo_iface->currentText());
|
||||||
}
|
}
|
||||||
|
// Program notification
|
||||||
|
Preferences::useProgramNotification(cb_program_notifications->isChecked());
|
||||||
|
// Tracker
|
||||||
|
Preferences::setTrackerEnabled(cb_tracker_status->isChecked());
|
||||||
|
Preferences::setTrackerPort(spin_tracker_port->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
@@ -175,7 +183,7 @@ protected slots:
|
|||||||
setItem(NETWORK_IFACE, PROPERTY, new QTableWidgetItem(tr("Network Interface (requires restart)")));
|
setItem(NETWORK_IFACE, PROPERTY, new QTableWidgetItem(tr("Network Interface (requires restart)")));
|
||||||
combo_iface = new QComboBox;
|
combo_iface = new QComboBox;
|
||||||
combo_iface->addItem(tr("Any interface", "i.e. Any network interface"));
|
combo_iface->addItem(tr("Any interface", "i.e. Any network interface"));
|
||||||
const QString ¤t_iface = Preferences::getNetworkInterface();
|
const QString current_iface = Preferences::getNetworkInterface();
|
||||||
int i = 1;
|
int i = 1;
|
||||||
foreach(const QNetworkInterface& iface, QNetworkInterface::allInterfaces()) {
|
foreach(const QNetworkInterface& iface, QNetworkInterface::allInterfaces()) {
|
||||||
if(iface.name() == "lo") continue;
|
if(iface.name() == "lo") continue;
|
||||||
@@ -186,6 +194,26 @@ protected slots:
|
|||||||
}
|
}
|
||||||
connect(combo_iface, SIGNAL(currentIndexChanged(int)), this, SLOT(emitSettingsChanged()));
|
connect(combo_iface, SIGNAL(currentIndexChanged(int)), this, SLOT(emitSettingsChanged()));
|
||||||
setCellWidget(NETWORK_IFACE, VALUE, combo_iface);
|
setCellWidget(NETWORK_IFACE, VALUE, combo_iface);
|
||||||
|
// Program notifications
|
||||||
|
setItem(PROGRAM_NOTIFICATIONS, PROPERTY, new QTableWidgetItem(tr("Display program notification balloons")));
|
||||||
|
cb_program_notifications = new QCheckBox();
|
||||||
|
connect(cb_program_notifications, SIGNAL(toggled(bool)), this, SLOT(emitSettingsChanged()));
|
||||||
|
cb_program_notifications->setChecked(Preferences::useProgramNotification());
|
||||||
|
setCellWidget(PROGRAM_NOTIFICATIONS, VALUE, cb_program_notifications);
|
||||||
|
// Tracker State
|
||||||
|
setItem(TRACKER_STATUS, PROPERTY, new QTableWidgetItem(tr("Enable embedded tracker")));
|
||||||
|
cb_tracker_status = new QCheckBox();
|
||||||
|
connect(cb_tracker_status, SIGNAL(toggled(bool)), this, SLOT(emitSettingsChanged()));
|
||||||
|
cb_tracker_status->setChecked(Preferences::isTrackerEnabled());
|
||||||
|
setCellWidget(TRACKER_STATUS, VALUE, cb_tracker_status);
|
||||||
|
// Tracker port
|
||||||
|
setItem(TRACKER_PORT, PROPERTY, new QTableWidgetItem(tr("Embedded tracker port")));
|
||||||
|
spin_tracker_port = new QSpinBox();
|
||||||
|
connect(spin_tracker_port, SIGNAL(valueChanged(int)), this, SLOT(emitSettingsChanged()));
|
||||||
|
spin_tracker_port->setMinimum(1);
|
||||||
|
spin_tracker_port->setMaximum(65535);
|
||||||
|
spin_tracker_port->setValue(Preferences::getTrackerPort());
|
||||||
|
setCellWidget(TRACKER_PORT, VALUE, spin_tracker_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitSettingsChanged() {
|
void emitSettingsChanged() {
|
||||||
|
|||||||
2537
src/bittorrent.cpp
@@ -31,7 +31,7 @@
|
|||||||
#ifndef CONSOLE_H
|
#ifndef CONSOLE_H
|
||||||
#define CONSOLE_H
|
#define CONSOLE_H
|
||||||
|
|
||||||
#include "bittorrent.h"
|
#include "qbtsession.h"
|
||||||
#include "ui_console.h"
|
#include "ui_console.h"
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
@@ -39,17 +39,13 @@ using namespace libtorrent;
|
|||||||
class consoleDlg : public QDialog, private Ui_ConsoleDlg{
|
class consoleDlg : public QDialog, private Ui_ConsoleDlg{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
private:
|
|
||||||
Bittorrent *BTSession;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
consoleDlg(QWidget *parent, Bittorrent* _BTSession) : QDialog(parent) {
|
consoleDlg(QWidget *parent) : QDialog(parent) {
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
setAttribute(Qt::WA_DeleteOnClose);
|
setAttribute(Qt::WA_DeleteOnClose);
|
||||||
setModal(true);
|
setModal(true);
|
||||||
BTSession = _BTSession;
|
textConsole->setHtml(QBtSession::instance()->getConsoleMessages().join("<br>"));
|
||||||
textConsole->setHtml(BTSession->getConsoleMessages().join("<br>"));
|
textBannedPeers->setHtml(QBtSession::instance()->getPeerBanMessages().join("<br>"));
|
||||||
textBannedPeers->setHtml(BTSession->getPeerBanMessages().join("<br>"));
|
|
||||||
show();
|
show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class downloadFromURL : public QDialog, private Ui::downloadFromURL{
|
|||||||
show();
|
show();
|
||||||
// Paste clipboard if there is an URL in it
|
// Paste clipboard if there is an URL in it
|
||||||
QString clip_txt = qApp->clipboard()->text();
|
QString clip_txt = qApp->clipboard()->text();
|
||||||
if(clip_txt.startsWith("http://", Qt::CaseInsensitive) || clip_txt.startsWith("https://", Qt::CaseInsensitive) || clip_txt.startsWith("ftp://", Qt::CaseInsensitive) || clip_txt.startsWith("magnet:", Qt::CaseInsensitive)) {
|
if(clip_txt.startsWith("http://", Qt::CaseInsensitive) || clip_txt.startsWith("https://", Qt::CaseInsensitive) || clip_txt.startsWith("ftp://", Qt::CaseInsensitive) || clip_txt.startsWith("magnet:", Qt::CaseInsensitive) || clip_txt.startsWith("bc://bt/", Qt::CaseInsensitive)) {
|
||||||
textUrls->setText(clip_txt);
|
textUrls->setText(clip_txt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,6 @@
|
|||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include "qinisettings.h"
|
#include "qinisettings.h"
|
||||||
|
|
||||||
enum ProxyType {HTTP=1, SOCKS5=2, HTTP_PW=3, SOCKS5_PW=4, SOCKS4=5};
|
|
||||||
|
|
||||||
/** Download Thread **/
|
/** Download Thread **/
|
||||||
|
|
||||||
downloadThread::downloadThread(QObject* parent) : QObject(parent) {
|
downloadThread::downloadThread(QObject* parent) : QObject(parent) {
|
||||||
@@ -101,7 +99,7 @@ void downloadThread::processDlFinished(QNetworkReply* reply) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void downloadThread::loadCookies(const QString &host_name, QString url) {
|
void downloadThread::loadCookies(const QString &host_name, QString url) {
|
||||||
const QList<QByteArray> &raw_cookies = Preferences::getHostNameCookies(host_name);
|
const QList<QByteArray> raw_cookies = Preferences::getHostNameCookies(host_name);
|
||||||
QNetworkCookieJar *cookie_jar = networkManager.cookieJar();
|
QNetworkCookieJar *cookie_jar = networkManager.cookieJar();
|
||||||
QList<QNetworkCookie> cookies;
|
QList<QNetworkCookie> cookies;
|
||||||
qDebug("Loading cookies for host name: %s", qPrintable(host_name));
|
qDebug("Loading cookies for host name: %s", qPrintable(host_name));
|
||||||
@@ -135,7 +133,7 @@ QNetworkReply* downloadThread::downloadUrl(QString url){
|
|||||||
loadCookies(host_name, url);
|
loadCookies(host_name, url);
|
||||||
// Process download request
|
// Process download request
|
||||||
qDebug("url is %s", qPrintable(url));
|
qDebug("url is %s", qPrintable(url));
|
||||||
const QUrl &qurl = QUrl::fromEncoded(url.toLocal8Bit());
|
const QUrl qurl = QUrl::fromEncoded(url.toLocal8Bit());
|
||||||
QNetworkRequest request(qurl);
|
QNetworkRequest request(qurl);
|
||||||
// Spoof Firefox 3.5 user agent to avoid
|
// Spoof Firefox 3.5 user agent to avoid
|
||||||
// Web server banning
|
// Web server banning
|
||||||
@@ -180,7 +178,7 @@ void downloadThread::applyProxySettings() {
|
|||||||
qDebug("Using proxy: %s", qPrintable(IP));
|
qDebug("Using proxy: %s", qPrintable(IP));
|
||||||
proxy.setPort(port.toUShort());
|
proxy.setPort(port.toUShort());
|
||||||
// Default proxy type is HTTP, we must change if it is SOCKS5
|
// Default proxy type is HTTP, we must change if it is SOCKS5
|
||||||
if(intValue == SOCKS5 || intValue == SOCKS5_PW) {
|
if(intValue == Proxy::SOCKS5 || intValue == Proxy::SOCKS5_PW) {
|
||||||
qDebug("Proxy is SOCKS5, not HTTP");
|
qDebug("Proxy is SOCKS5, not HTTP");
|
||||||
proxy.setType(QNetworkProxy::Socks5Proxy);
|
proxy.setType(QNetworkProxy::Socks5Proxy);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
221
src/feedList.h
@@ -1,221 +0,0 @@
|
|||||||
#ifndef FEEDLIST_H
|
|
||||||
#define FEEDLIST_H
|
|
||||||
|
|
||||||
#include <QTreeWidget>
|
|
||||||
#include <QTreeWidgetItem>
|
|
||||||
#include <QDropEvent>
|
|
||||||
#include <QDragMoveEvent>
|
|
||||||
#include <QStringList>
|
|
||||||
#include <QHash>
|
|
||||||
#include <QUrl>
|
|
||||||
#include "rss.h"
|
|
||||||
|
|
||||||
class FeedList: public QTreeWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
private:
|
|
||||||
RssManager *rssmanager;
|
|
||||||
QHash<QTreeWidgetItem*, RssFile*> mapping;
|
|
||||||
QHash<QString, QTreeWidgetItem*> feeds_items;
|
|
||||||
QTreeWidgetItem* current_feed;
|
|
||||||
QTreeWidgetItem *unread_item;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FeedList(QWidget *parent, RssManager *rssmanager): QTreeWidget(parent), rssmanager(rssmanager) {
|
|
||||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
|
||||||
setDragDropMode(QAbstractItemView::InternalMove);
|
|
||||||
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
||||||
setColumnCount(1);
|
|
||||||
QTreeWidgetItem *___qtreewidgetitem = headerItem();
|
|
||||||
___qtreewidgetitem->setText(0, QApplication::translate("RSS", "RSS feeds", 0, QApplication::UnicodeUTF8));
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void itemAdded(QTreeWidgetItem *item, RssFile* file) {
|
|
||||||
mapping[item] = file;
|
|
||||||
if(file->getType() == RssFile::STREAM) {
|
|
||||||
feeds_items[file->getID()] = item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void itemAboutToBeRemoved(QTreeWidgetItem *item) {
|
|
||||||
RssFile* file = mapping.take(item);
|
|
||||||
if(file->getType() == RssFile::STREAM) {
|
|
||||||
feeds_items.remove(file->getID());
|
|
||||||
} else {
|
|
||||||
QList<RssStream*> feeds = ((RssFolder*)file)->getAllFeeds();
|
|
||||||
foreach(RssStream* feed, feeds) {
|
|
||||||
feeds_items.remove(feed->getID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasFeed(QString url) const {
|
|
||||||
return feeds_items.contains(QUrl(url).toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QTreeWidgetItem*> getAllFeedItems() const {
|
|
||||||
return feeds_items.values();
|
|
||||||
}
|
|
||||||
|
|
||||||
QTreeWidgetItem* getUnreadItem() const {
|
|
||||||
return unread_item;
|
|
||||||
}
|
|
||||||
|
|
||||||
QStringList getItemPath(QTreeWidgetItem* item) const {
|
|
||||||
QStringList path;
|
|
||||||
if(item) {
|
|
||||||
if(item->parent())
|
|
||||||
path << getItemPath(item->parent());
|
|
||||||
path.append(getRSSItem(item)->getID());
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QTreeWidgetItem*> getAllOpenFolders(QTreeWidgetItem *parent=0) const {
|
|
||||||
QList<QTreeWidgetItem*> open_folders;
|
|
||||||
int nbChildren;
|
|
||||||
if(parent)
|
|
||||||
nbChildren = parent->childCount();
|
|
||||||
else
|
|
||||||
nbChildren = topLevelItemCount();
|
|
||||||
for(int i=0; i<nbChildren; ++i) {
|
|
||||||
QTreeWidgetItem *item;
|
|
||||||
if(parent)
|
|
||||||
item = parent->child(i);
|
|
||||||
else
|
|
||||||
item = topLevelItem(i);
|
|
||||||
if(getItemType(item) == RssFile::FOLDER && item->isExpanded()) {
|
|
||||||
QList<QTreeWidgetItem*> open_subfolders = getAllOpenFolders(item);
|
|
||||||
if(!open_subfolders.empty()) {
|
|
||||||
open_folders << open_subfolders;
|
|
||||||
} else {
|
|
||||||
open_folders << item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return open_folders;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QTreeWidgetItem*> getAllFeedItems(QTreeWidgetItem* folder) {
|
|
||||||
QList<QTreeWidgetItem*> feeds;
|
|
||||||
int nbChildren = folder->childCount();
|
|
||||||
for(int i=0; i<nbChildren; ++i) {
|
|
||||||
QTreeWidgetItem *item = folder->child(i);
|
|
||||||
if(getItemType(item) == RssFile::STREAM) {
|
|
||||||
feeds << item;
|
|
||||||
} else {
|
|
||||||
feeds << getAllFeedItems(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return feeds;
|
|
||||||
}
|
|
||||||
|
|
||||||
RssFile* getRSSItem(QTreeWidgetItem *item) const {
|
|
||||||
return mapping.value(item, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
RssFile::FileType getItemType(QTreeWidgetItem *item) const {
|
|
||||||
return mapping.value(item)->getType();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString getItemID(QTreeWidgetItem *item) const {
|
|
||||||
return mapping.value(item)->getID();
|
|
||||||
}
|
|
||||||
|
|
||||||
QTreeWidgetItem* getTreeItemFromUrl(QString url) const{
|
|
||||||
return feeds_items.value(url, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
RssStream* getRSSItemFromUrl(QString url) const {
|
|
||||||
return (RssStream*)getRSSItem(getTreeItemFromUrl(url));
|
|
||||||
}
|
|
||||||
|
|
||||||
QTreeWidgetItem* currentItem() const {
|
|
||||||
return current_feed;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTreeWidgetItem* currentFeed() const {
|
|
||||||
return current_feed;
|
|
||||||
}
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void foldersAltered(QList<QTreeWidgetItem*> folders);
|
|
||||||
void overwriteAttempt(QString filename);
|
|
||||||
|
|
||||||
protected slots:
|
|
||||||
void updateCurrentFeed(QTreeWidgetItem* new_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void dragMoveEvent(QDragMoveEvent * event) {
|
|
||||||
QTreeWidgetItem *item = itemAt(event->pos());
|
|
||||||
if(item == unread_item) {
|
|
||||||
event->ignore();
|
|
||||||
} else {
|
|
||||||
if(item && getItemType(item) != RssFile::FOLDER)
|
|
||||||
event->ignore();
|
|
||||||
else {
|
|
||||||
if(selectedItems().contains(unread_item)) {
|
|
||||||
event->ignore();
|
|
||||||
} else {
|
|
||||||
QTreeWidget::dragMoveEvent(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dropEvent(QDropEvent *event) {
|
|
||||||
qDebug("dropEvent");
|
|
||||||
QList<QTreeWidgetItem*> folders_altered;
|
|
||||||
QTreeWidgetItem *dest_folder_item = itemAt(event->pos());
|
|
||||||
RssFolder *dest_folder;
|
|
||||||
if(dest_folder_item) {
|
|
||||||
dest_folder = (RssFolder*)getRSSItem(dest_folder_item);
|
|
||||||
folders_altered << dest_folder_item;
|
|
||||||
} else {
|
|
||||||
dest_folder = rssmanager;
|
|
||||||
}
|
|
||||||
QList<QTreeWidgetItem *> src_items = selectedItems();
|
|
||||||
// Check if there is not going to overwrite another file
|
|
||||||
foreach(QTreeWidgetItem *src_item, src_items) {
|
|
||||||
RssFile *file = getRSSItem(src_item);
|
|
||||||
if(dest_folder->hasChild(file->getID())) {
|
|
||||||
emit overwriteAttempt(file->getID());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Proceed with the move
|
|
||||||
foreach(QTreeWidgetItem *src_item, src_items) {
|
|
||||||
QTreeWidgetItem *parent_folder = src_item->parent();
|
|
||||||
if(parent_folder && !folders_altered.contains(parent_folder))
|
|
||||||
folders_altered << parent_folder;
|
|
||||||
// Actually move the file
|
|
||||||
RssFile *file = getRSSItem(src_item);
|
|
||||||
rssmanager->moveFile(file, dest_folder);
|
|
||||||
}
|
|
||||||
QTreeWidget::dropEvent(event);
|
|
||||||
if(dest_folder_item)
|
|
||||||
dest_folder_item->setExpanded(true);
|
|
||||||
// Emit signal for update
|
|
||||||
if(!folders_altered.empty())
|
|
||||||
emit foldersAltered(folders_altered);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // FEEDLIST_H
|
|
||||||
@@ -3,11 +3,12 @@
|
|||||||
|
|
||||||
#include <QFileSystemWatcher>
|
#include <QFileSystemWatcher>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
||||||
#ifndef Q_WS_WIN
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QHash>
|
||||||
|
|
||||||
|
#ifndef Q_WS_WIN
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -19,6 +20,8 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
#ifndef CIFS_MAGIC_NUMBER
|
#ifndef CIFS_MAGIC_NUMBER
|
||||||
#define CIFS_MAGIC_NUMBER 0xFF534D42
|
#define CIFS_MAGIC_NUMBER 0xFF534D42
|
||||||
#endif
|
#endif
|
||||||
@@ -27,6 +30,9 @@
|
|||||||
#define NFS_SUPER_MAGIC 0x6969
|
#define NFS_SUPER_MAGIC 0x6969
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
const int WATCH_INTERVAL = 10000; // 10 sec
|
||||||
|
const int MAX_PARTIAL_RETRIES = 5;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Subclassing QFileSystemWatcher in order to support Network File
|
* Subclassing QFileSystemWatcher in order to support Network File
|
||||||
* System watching (NFS, CIFS) on Linux and Mac OS.
|
* System watching (NFS, CIFS) on Linux and Mac OS.
|
||||||
@@ -39,11 +45,14 @@ private:
|
|||||||
QList<QDir> watched_folders;
|
QList<QDir> watched_folders;
|
||||||
QPointer<QTimer> watch_timer;
|
QPointer<QTimer> watch_timer;
|
||||||
#endif
|
#endif
|
||||||
QStringList filters;
|
QStringList m_filters;
|
||||||
|
// Partial torrents
|
||||||
|
QHash<QString, int> m_partialTorrents;
|
||||||
|
QPointer<QTimer> m_partialTorrentTimer;
|
||||||
|
|
||||||
#ifndef Q_WS_WIN
|
#ifndef Q_WS_WIN
|
||||||
protected:
|
private:
|
||||||
bool isNetworkFileSystem(QString path) {
|
static bool isNetworkFileSystem(QString path) {
|
||||||
QString file = path;
|
QString file = path;
|
||||||
if(!file.endsWith(QDir::separator()))
|
if(!file.endsWith(QDir::separator()))
|
||||||
file += QDir::separator();
|
file += QDir::separator();
|
||||||
@@ -99,7 +108,7 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
FileSystemWatcher(QObject *parent): QFileSystemWatcher(parent) {
|
FileSystemWatcher(QObject *parent): QFileSystemWatcher(parent) {
|
||||||
filters << "*.torrent";
|
m_filters << "*.torrent";
|
||||||
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanLocalFolder(QString)));
|
connect(this, SIGNAL(directoryChanged(QString)), this, SLOT(scanLocalFolder(QString)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,6 +117,8 @@ public:
|
|||||||
if(watch_timer)
|
if(watch_timer)
|
||||||
delete watch_timer;
|
delete watch_timer;
|
||||||
#endif
|
#endif
|
||||||
|
if(m_partialTorrentTimer)
|
||||||
|
delete m_partialTorrentTimer;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList directories() const {
|
QStringList directories() const {
|
||||||
@@ -137,7 +148,7 @@ public:
|
|||||||
if (!watch_timer) {
|
if (!watch_timer) {
|
||||||
watch_timer = new QTimer(this);
|
watch_timer = new QTimer(this);
|
||||||
connect(watch_timer, SIGNAL(timeout()), this, SLOT(scanNetworkFolders()));
|
connect(watch_timer, SIGNAL(timeout()), this, SLOT(scanNetworkFolders()));
|
||||||
watch_timer->start(5000); // 5 sec
|
watch_timer->start(WATCH_INTERVAL); // 5 sec
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
#endif
|
#endif
|
||||||
@@ -196,14 +207,72 @@ protected slots:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void processPartialTorrents() {
|
||||||
|
QStringList no_longer_partial;
|
||||||
|
|
||||||
|
// Check which torrents are still partial
|
||||||
|
foreach(const QString& torrent_path, m_partialTorrents.keys()) {
|
||||||
|
if(!QFile::exists(torrent_path)) {
|
||||||
|
m_partialTorrents.remove(torrent_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(misc::isValidTorrentFile(torrent_path)) {
|
||||||
|
no_longer_partial << torrent_path;
|
||||||
|
m_partialTorrents.remove(torrent_path);
|
||||||
|
} else {
|
||||||
|
if(m_partialTorrents[torrent_path] >= MAX_PARTIAL_RETRIES) {
|
||||||
|
m_partialTorrents.remove(torrent_path);
|
||||||
|
QFile::rename(torrent_path, torrent_path+".invalid");
|
||||||
|
} else {
|
||||||
|
m_partialTorrents[torrent_path]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the partial timer if necessary
|
||||||
|
if(m_partialTorrents.empty()) {
|
||||||
|
m_partialTorrentTimer->stop();
|
||||||
|
m_partialTorrentTimer->deleteLater();
|
||||||
|
qDebug("No longer any partial torrent.");
|
||||||
|
} else {
|
||||||
|
qDebug("Still %d partial torrents after delayed processing.", m_partialTorrents.count());
|
||||||
|
m_partialTorrentTimer->start(WATCH_INTERVAL);
|
||||||
|
}
|
||||||
|
// Notify of new torrents
|
||||||
|
if(!no_longer_partial.isEmpty())
|
||||||
|
emit torrentsAdded(no_longer_partial);
|
||||||
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void torrentsAdded(QStringList &pathList);
|
void torrentsAdded(QStringList &pathList);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void startPartialTorrentTimer() {
|
||||||
|
Q_ASSERT(!m_partialTorrents.isEmpty());
|
||||||
|
if(!m_partialTorrentTimer) {
|
||||||
|
m_partialTorrentTimer = new QTimer();
|
||||||
|
connect(m_partialTorrentTimer, SIGNAL(timeout()), SLOT(processPartialTorrents()));
|
||||||
|
m_partialTorrentTimer->setSingleShot(true);
|
||||||
|
m_partialTorrentTimer->start(WATCH_INTERVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void addTorrentsFromDir(const QDir &dir, QStringList &torrents) {
|
void addTorrentsFromDir(const QDir &dir, QStringList &torrents) {
|
||||||
const QStringList &files = dir.entryList(filters, QDir::Files, QDir::Unsorted);
|
const QStringList files = dir.entryList(m_filters, QDir::Files, QDir::Unsorted);
|
||||||
foreach(const QString &file, files)
|
foreach(const QString &file, files) {
|
||||||
torrents << dir.canonicalPath() + '/' + file;
|
const QString file_abspath = dir.absoluteFilePath(file);
|
||||||
|
if(misc::isValidTorrentFile(file_abspath)) {
|
||||||
|
torrents << file_abspath;
|
||||||
|
} else {
|
||||||
|
if(!m_partialTorrents.contains(file_abspath)) {
|
||||||
|
qDebug("Partial torrent detected at: %s", qPrintable(file_abspath));
|
||||||
|
qDebug("Delay the file's processing...");
|
||||||
|
m_partialTorrents.insert(file_abspath, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!m_partialTorrents.empty())
|
||||||
|
startPartialTorrentTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||