Merge branch 'master' into master

This commit is contained in:
lisenenkov 2017-02-12 18:44:06 +03:00 committed by GitHub
commit b4068e39f0
606 changed files with 99401 additions and 110601 deletions

View File

@ -1,7 +1,22 @@
[main]
host = https://www.transifex.com
[transmissionbt.transmission-qt]
[transmissionbt.qt]
file_filter = qt/translations/transmission_<lang>.ts
source_lang = en
type = QT
[transmissionbt.gtk]
file_filter = po/<lang>.po
source_lang = en
type = PO
[transmissionbt.mac]
file_filter = macosx/<lang>.lproj/Localizable.strings
source_lang = en
type = STRINGS
[transmissionbt.mac-ql]
file_filter = macosx/QuickLookPlugin/<lang>.lproj/Localizable.strings
source_lang = en
type = STRINGS

View File

@ -4,6 +4,7 @@ https://transmissionbt.com/
Lead Developers <dev@transmissionbt.com>
Jordan Lee, Mnemosyne LLC <jordan@transmissionbt.com> (Daemon, Backend, GTK+ client)
Mitchell Livingston, Digital Ignition LLC <livings124@transmissionbt.com> (Mac OS X client)
Mike Gelfand <mike@transmissionbt.com>
Project Contributors
John Clay <john@transmissionbt.com> (Website maintenance and troubleshooting, Mac OS X help documentation)
@ -11,7 +12,7 @@ Project Contributors
Juliusz Chroboczek (DHT, network code, BitTorrent code improvements)
Daniel Lee (Patches)
Tomas Carnecky (Profiling, patches, and detection of sneaky bugs)
Diego Jiménez (Patches)
Diego Jiménez (Patches)
Kendall Hopkins <SoftwareElves@gmail.com> (Web client)
Malcolm Jarvis <mjarvis@transmissionbt.com> (Web client)
Kevin Glowacz <kjg@transmissionbt.com> (Web client)
@ -40,8 +41,8 @@ Mac OS X Translators, current release:
Guilherme Fernandes (Brazilian Portuguese)
Sven-S. Porst (German)
Tianhao He (Simplified Chinese)
Sérgio Miranda (European Portuguese)
Daniel ¯stergaard Nielsen (Danish)
Sérgio Miranda (European Portuguese)
Daniel Østergaard Nielsen (Danish)
Emir SARI (Turkish)
GTK+ Translators:

View File

@ -3,6 +3,8 @@ project(transmission)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
set(CMAKE_MACOSX_RPATH ON)
include(CheckIncludeFile)
include(CheckIncludeFiles)
include(CheckFunctionExists)
@ -14,6 +16,7 @@ include(TrMacros)
option(ENABLE_DAEMON "Build daemon" ON)
tr_auto_option(ENABLE_GTK "Build GTK+ client" AUTO)
tr_auto_option(ENABLE_QT "Build Qt client" AUTO)
tr_auto_option(ENABLE_MAC "Build Mac client" AUTO)
option(ENABLE_UTILS "Build utils (create, edit, show)" ON)
option(ENABLE_CLI "Build command-line client" OFF)
option(ENABLE_TESTS "Build unit tests" ON)
@ -22,7 +25,6 @@ tr_auto_option(ENABLE_QT "Build Qt client" AUTO)
option(ENABLE_NLS "Enable native language support" ON)
option(INSTALL_DOC "Build/install documentation" ON)
option(INSTALL_LIB "Install the library" OFF)
option(USE_QT5 "Use Qt 5 (instead of default Qt 4)" OFF)
tr_auto_option(USE_SYSTEM_EVENT2 "Use system event2 library" AUTO)
tr_auto_option(USE_SYSTEM_DHT "Use system dht library" AUTO)
tr_auto_option(USE_SYSTEM_MINIUPNPC "Use system miniupnpc library" AUTO)
@ -59,16 +61,16 @@ endif()
set(TR_VCS_REVISION_FILE "${CMAKE_SOURCE_DIR}/REVISION")
if(NOT "$ENV{JENKINS_URL}" STREQUAL "" AND NOT "$ENV{VCS_REVISION}" STREQUAL "")
# Jenkins automated build, use the set environment variables to avoid
# version mismatches between java's svn and command line's svn
set(TR_VCS_REVISION "$ENV{VCS_REVISION}")
if(NOT "$ENV{JENKINS_URL}" STREQUAL "" AND NOT "$ENV{GIT_COMMIT}" STREQUAL "")
set(TR_VCS_REVISION "$ENV{GIT_COMMIT}")
elseif(NOT "$ENV{TEAMCITY_PROJECT_NAME}" STREQUAL "" AND NOT "$ENV{BUILD_VCS_NUMBER}" STREQUAL "")
set(TR_VCS_REVISION "$ENV{BUILD_VCS_NUMBER}")
elseif(IS_DIRECTORY ${CMAKE_SOURCE_DIR}/.git)
find_package(Git)
if(GIT_FOUND)
execute_process(
COMMAND
${GIT_EXECUTABLE} rev-list --max-count=1 --abbrev-commit HEAD
${GIT_EXECUTABLE} rev-list --max-count=1 HEAD
WORKING_DIRECTORY
${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE
@ -80,16 +82,19 @@ endif()
if("${TR_VCS_REVISION}" STREQUAL "" AND EXISTS "${TR_VCS_REVISION_FILE}")
file(READ "${TR_VCS_REVISION_FILE}" TR_VCS_REVISION)
string(STRIP "${TR_VCS_REVISION}" TR_VCS_REVISION)
endif()
string(STRIP "${TR_VCS_REVISION}" TR_VCS_REVISION)
if(NOT "${TR_VCS_REVISION}" STREQUAL "")
file(WRITE "${TR_VCS_REVISION_FILE}" "${TR_VCS_REVISION}")
file(WRITE "${TR_VCS_REVISION_FILE}" "${TR_VCS_REVISION}\n")
else()
set(TR_VCS_REVISION 0)
file(REMOVE "${TR_VCS_REVISION_FILE}")
endif()
string(SUBSTRING "${TR_VCS_REVISION}" 0 10 TR_VCS_REVISION)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
set(CURL_MINIMUM 7.15.4)
@ -102,6 +107,7 @@ set(GTK_MINIMUM 3.4.0)
set(GLIB_MINIMUM 2.32.0)
set(GIO_MINIMUM 2.26.0)
set(LIBAPPINDICATOR_MINIMUM 0.4.90)
set(QT5_MINIMUM 5.2)
if(WIN32)
foreach(L C CXX)
@ -202,67 +208,44 @@ if(ENABLE_QT)
set(ENABLE_QT_COM_INTEROP OFF)
set(ENABLE_QT_DBUS_INTEROP OFF)
if(USE_QT5)
set(QT5_REQUIRED_MODULES Core Gui Widgets Network LinguistTools)
set(QT5_OPTIONAL_MODULES DBus AxContainer AxServer)
foreach(M ${QT5_REQUIRED_MODULES})
find_package(Qt5${M} QUIET)
if(Qt5${M}_FOUND)
if(NOT M STREQUAL "LinguistTools")
list(APPEND QT_TARGETS Qt5::${M})
endif()
else()
set(QT_TARGETS)
break()
endif()
endforeach()
if(QT_TARGETS)
foreach(M ${QT5_OPTIONAL_MODULES})
find_package(Qt5${M} QUIET)
if(Qt5${M}_FOUND)
list(APPEND QT_TARGETS Qt5::${M})
endif()
endforeach()
if(Qt5AxContainer_FOUND AND Qt5AxServer_FOUND)
set(ENABLE_QT_COM_INTEROP ON)
endif()
if(Qt5DBus_FOUND)
set(ENABLE_QT_DBUS_INTEROP ON)
endif()
endif()
else()
set(QT4_REQUIRED_MODULES QtCore QtGui QtNetwork)
set(QT4_OPTIONAL_MODULES QtDBus QAxContainer QAxServer)
find_package(Qt4 4.8.0 QUIET COMPONENTS ${QT4_REQUIRED_MODULES} OPTIONAL_COMPONENTS ${QT4_OPTIONAL_MODULES})
foreach(M ${QT4_REQUIRED_MODULES})
string(TOUPPER "${M}" M_UPPER)
if(QT_${M_UPPER}_FOUND)
list(APPEND QT_TARGETS Qt4::${M})
else()
set(QT_TARGETS)
break()
endif()
endforeach()
if (QT_TARGETS)
foreach(M ${QT4_OPTIONAL_MODULES})
string(TOUPPER "${M}" M_UPPER)
if(QT_${M_UPPER}_FOUND)
list(APPEND QT_TARGETS Qt4::${M})
endif()
endforeach()
if(QT_QAXCONTAINER_FOUND AND QT_QAXSERVER_FOUND)
set(ENABLE_QT_COM_INTEROP ON)
endif()
if(QT_QTDBUS_FOUND)
set(ENABLE_QT_DBUS_INTEROP ON)
endif()
endif()
set(QT5_REQUIRED_MODULES Core Gui Widgets Network LinguistTools)
set(QT5_OPTIONAL_MODULES DBus AxContainer AxServer)
if(WIN32)
list(APPEND QT5_REQUIRED_MODULES WinExtras)
endif()
if(ENABLE_QT_COM_INTEROP)
find_program(MIDL_EXECUTABLE midl)
if(NOT MIDL_EXECUTABLE)
set(ENABLE_QT_COM_INTEROP OFF)
foreach(M ${QT5_REQUIRED_MODULES})
find_package(Qt5${M} ${QT5_MINIMUM} QUIET)
if(Qt5${M}_FOUND)
if(NOT M STREQUAL "LinguistTools")
list(APPEND QT_TARGETS Qt5::${M})
endif()
else()
set(QT_TARGETS)
break()
endif()
endforeach()
if(QT_TARGETS)
foreach(M ${QT5_OPTIONAL_MODULES})
find_package(Qt5${M} ${QT5_MINIMUM} QUIET)
if(Qt5${M}_FOUND)
list(APPEND QT_TARGETS Qt5::${M})
endif()
endforeach()
if(Qt5AxContainer_FOUND AND Qt5AxServer_FOUND)
set(ENABLE_QT_COM_INTEROP ON)
find_program(MIDL_EXECUTABLE midl)
if(NOT MIDL_EXECUTABLE)
set(ENABLE_QT_COM_INTEROP OFF)
endif()
endif()
if(Qt5DBus_FOUND)
set(ENABLE_QT_DBUS_INTEROP ON)
endif()
endif()
@ -277,6 +260,21 @@ if(ENABLE_QT)
tr_fixup_auto_option(ENABLE_QT QT_FOUND QT_IS_REQUIRED)
endif()
if(ENABLE_MAC)
tr_get_required_flag(ENABLE_MAC MAC_IS_REQUIRED)
if(APPLE)
set(MAC_FOUND ON)
else()
set(MAC_FOUND OFF)
if(MAC_IS_REQUIRED)
message(SEND_ERROR "Mac build is impossible on non-Mac system.")
endif()
endif()
tr_fixup_auto_option(ENABLE_MAC MAC_FOUND MAC_IS_REQUIRED)
endif()
find_package(ZLIB ${ZLIB_MINIMUM})
if(ZLIB_FOUND)
add_definitions(-DHAVE_ZLIB)
@ -287,10 +285,18 @@ set(THIRD_PARTY_DIR ${CMAKE_SOURCE_DIR}/third-party)
if(WIN32)
tr_add_external_auto_library(EVENT2 libevent event)
else()
set(EVENT2_CONFIGURE_FLAGS)
if(APPLE)
if(CRYPTO_PKG STREQUAL "openssl")
list(APPEND EVENT2_CONFIGURE_FLAGS "CPPFLAGS=-I${CRYPTO_INCLUDE_DIRS}")
else()
list(APPEND EVENT2_CONFIGURE_FLAGS "CPPFLAGS=-I${THIRD_PARTY_DIR}/openssl/include")
endif()
endif()
tr_add_external_auto_library(EVENT2 libevent event
BUILD_IN_SOURCE 1
CONFIGURE_COMMAND "<SOURCE_DIR>/autogen.sh"
COMMAND "<SOURCE_DIR>/configure" "--prefix=<INSTALL_DIR>" "--disable-shared")
COMMAND "<SOURCE_DIR>/configure" "--prefix=<INSTALL_DIR>" "--disable-shared" ${EVENT2_CONFIGURE_FLAGS})
endif()
tr_add_external_auto_library(NATPMP libnatpmp natpmp)
@ -510,20 +516,29 @@ if(ENABLE_TESTS)
enable_testing()
endif()
function(tr_install_web DST_DIR)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/web DESTINATION ${DST_DIR}
PATTERN *.am EXCLUDE
PATTERN *.in EXCLUDE
PATTERN *.scss EXCLUDE)
endfunction()
add_subdirectory(libtransmission)
foreach(P daemon cli utils gtk qt)
set(MAC_PROJECT_DIR macosx)
foreach(P daemon cli utils gtk qt mac)
string(TOUPPER "${P}" P_ID)
if(ENABLE_${P_ID})
if(DEFINED ${P_ID}_PROJECT_DIR)
set(P ${${P_ID}_PROJECT_DIR})
endif()
add_subdirectory(${P})
endif()
endforeach()
if(ENABLE_DAEMON OR ENABLE_GTK OR ENABLE_QT)
install(DIRECTORY web DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${TR_NAME}
PATTERN *.am EXCLUDE
PATTERN *.in EXCLUDE
PATTERN *.scss EXCLUDE)
tr_install_web(${CMAKE_INSTALL_DATAROOTDIR}/${TR_NAME})
endif()
if(ENABLE_GTK AND ENABLE_NLS)
@ -535,7 +550,7 @@ if(INSTALL_DOC)
install(FILES AUTHORS COPYING NEWS README.md extras/rpc-spec.txt extras/send-email-when-torrent-done.sh DESTINATION ${CMAKE_INSTALL_DOCDIR})
endif()
if(MSVC AND ENABLE_DAEMON AND ENABLE_QT AND ENABLE_UTILS AND USE_QT5 AND WITH_CRYPTO STREQUAL "openssl")
if(MSVC AND ENABLE_DAEMON AND ENABLE_QT AND ENABLE_UTILS AND WITH_CRYPTO STREQUAL "openssl")
add_subdirectory(dist/msi)
endif()

6
NEWS
View File

@ -313,7 +313,7 @@
=== Transmission 2.70 (2012/09/25) ===
[https://trac.transmissionbt.com/query?milestone=2.70&group=component&order=severity All tickets closed by this release]
==== All Platforms ====
* Improved speed with the µTP protocol
* Improved speed with the µTP protocol
* Fix bug that caused some incoming encrypted peer connections to fail
* Fix bugs with the speed limit scheduler
* Fix crasher with magnet links
@ -536,7 +536,7 @@
* Fix error caused by some "open-file-limit" configuration settings
* Fix 2.30 problem seeding to some peers
* Fix bug converting torrent file text contents to UTF-8
* Better µTP support on systems running uClibc
* Better µTP support on systems running uClibc
* Other small bug fixes
==== Mac ====
* Improved tabbing behavior
@ -559,7 +559,7 @@
=== Transmission 2.30 (2011/05/16) ===
[https://trac.transmissionbt.com/query?milestone=2.30&group=component&order=severity All tickets closed by this release]
==== All Platforms ====
* µTP support
* µTP support
* UDP tracker support
* Multiscrape support
* Download scarcest pieces first

File diff suppressed because it is too large Load Diff

View File

@ -122,8 +122,9 @@ program was written by
.An Eric Petit ,
.An Josh Elsasser ,
.An Jordan Lee ,
.An Mitchell Livingston ,
and
.An Mitchell Livingston .
.An Mike Gelfand .
.Sh SEE ALSO
.Xr transmission-create 1 ,
.Xr transmission-daemon 1 ,

View File

@ -96,6 +96,7 @@ macro(tr_add_external_auto_library ID DIRNAME LIBNAME)
CMAKE_ARGS
-Wno-dev # We don't want to be warned over unused variables
"-DCMAKE_TOOLCHAIN_FILE:PATH=${CMAKE_TOOLCHAIN_FILE}"
"-DCMAKE_USER_MAKE_RULES_OVERRIDE=${CMAKE_USER_MAKE_RULES_OVERRIDE}"
"-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS}"
"-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS}"
"-DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}"
@ -145,3 +146,53 @@ function(tr_select_library LIBNAMES FUNCNAME DIRS OVAR)
endforeach()
set(${OVAR} "${LIBNAME}" PARENT_SCOPE)
endfunction()
function(tr_fixup_bundle_item BUNDLE_DIR BUNDLE_ITEMS DEP_DIRS)
while(BUNDLE_ITEMS)
list(GET BUNDLE_ITEMS 0 ITEM)
list(REMOVE_AT BUNDLE_ITEMS 0)
set(ITEM_FULL_BUNDLE_PATH "${BUNDLE_DIR}/${ITEM}")
get_filename_component(ITEM_FULL_BUNDLE_DIR "${ITEM_FULL_BUNDLE_PATH}" PATH)
unset(ITEM_DEPS)
get_prerequisites("${ITEM_FULL_BUNDLE_PATH}" ITEM_DEPS 1 0 "${ITEM_FULL_BUNDLE_PATH}" "${DEP_DIRS}")
foreach(DEP IN LISTS ITEM_DEPS)
gp_resolve_item("${ITEM_FULL_BUNDLE_PATH}" "${DEP}" "${ITEM_FULL_BUNDLE_DIR}" "${DEP_DIRS}" DEP_FULL_PATH)
if(DEP_FULL_PATH MATCHES "[.]dylib$")
get_filename_component(DEP_NAME "${DEP_FULL_PATH}" NAME)
file(COPY "${DEP_FULL_PATH}" DESTINATION "${BUNDLE_DIR}/Contents/MacOS/")
set(DEP_BUNDLE_PATH "Contents/MacOS/${DEP_NAME}")
elseif(DEP_FULL_PATH MATCHES "^(.+)/(([^/]+[.]framework)/.+)$")
set(DEP_NAME "${CMAKE_MATCH_2}")
file(COPY "${CMAKE_MATCH_1}/${CMAKE_MATCH_3}" DESTINATION "${BUNDLE_DIR}/Contents/Frameworks/" PATTERN "Headers" EXCLUDE)
set(DEP_BUNDLE_PATH "Contents/Frameworks/${DEP_NAME}")
else()
message(FATAL_ERROR "Don't know how to fixup '${DEP_FULL_PATH}'")
endif()
execute_process(COMMAND install_name_tool -change "${DEP}" "@rpath/${DEP_NAME}" "${ITEM_FULL_BUNDLE_PATH}")
set(DEP_FULL_BUNDLE_PATH "${BUNDLE_DIR}/${DEP_BUNDLE_PATH}")
execute_process(COMMAND chmod u+w "${DEP_FULL_BUNDLE_PATH}")
execute_process(COMMAND install_name_tool -id "@rpath/${DEP_NAME}" "${DEP_FULL_BUNDLE_PATH}")
list(REMOVE_ITEM BUNDLE_ITEMS "${DEP_BUNDLE_PATH}")
list(APPEND BUNDLE_ITEMS "${DEP_BUNDLE_PATH}")
endforeach()
endwhile()
endfunction()
macro(tr_qt_wrap_ui)
qt5_wrap_ui(${ARGN})
endmacro()
macro(tr_qt_add_resources)
qt5_add_resources(${ARGN})
endmacro()
macro(tr_qt_add_translation)
qt5_add_translation(${ARGN})
endmacro()

View File

@ -155,8 +155,9 @@ See https://trac.transmissionbt.com/wiki/ConfigFiles for more information.
.An Jordan Lee ,
.An Josh Elsasser ,
.An Eric Petit ,
.An Mitchell Livingston ,
and
.An Mitchell Livingston .
.An Mike Gelfand .
.Sh SEE ALSO
.Xr transmission-create 1 ,
.Xr transmission-daemon 1 ,

View File

@ -397,8 +397,9 @@ Sets the proxy to use for http tracker announces.
.An Jordan Lee ,
.An Josh Elsasser ,
.An Eric Petit ,
.An Mitchell Livingston ,
and
.An Mitchell Livingston .
.An Mike Gelfand .
.Sh SEE ALSO
.Xr transmission-create 1 ,
.Xr transmission-daemon 1 ,

View File

@ -17,11 +17,7 @@ if(NOT TR_THIRD_PARTY_DIR)
endif()
if(NOT TR_QT_DIR)
if(USE_QT5)
set(TR_QT_DIR "$<TARGET_FILE_DIR:Qt5::Core>/..")
else()
set(TR_QT_DIR "$<TARGET_FILE_DIR:Qt4::Core>/..")
endif()
set(TR_QT_DIR "$<TARGET_FILE_DIR:Qt5::Core>/..")
endif()
set(ICONS_DIR "${CMAKE_SOURCE_DIR}/qt/icons/hicolor")

View File

@ -100,6 +100,9 @@
<Component Id="dll.qt5.widgets">
<File DiskId="1" KeyPath="yes" Name="Qt5Widgets.dll" />
</Component>
<Component Id="dll.qt5.winextras">
<File DiskId="1" KeyPath="yes" Name="Qt5WinExtras.dll" />
</Component>
</DirectoryRef>
<DirectoryRef Id="INSTALLDIR" FileSource="$(var.QtDir)\plugins">
@ -132,6 +135,7 @@
<ComponentRef Id="dll.qt5.gui" />
<ComponentRef Id="dll.qt5.network" />
<ComponentRef Id="dll.qt5.widgets" />
<ComponentRef Id="dll.qt5.winextras" />
<ComponentRef Id="dll.qt5.plugins.platforms.windows" />
<ComponentRef Id="dll.dbus" />
<ComponentRef Id="dll.expat" />

View File

@ -35,7 +35,7 @@ B is the receiver
Prime P is a 768 bit safe prime, "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563"
Generator G is "2"
Xa and Xb are a variable size random integers.
Xa and Xb are a variable size random integers.
They are the private key for each side and have to be discarded after
the DH handshake is done. Minimum length is 128 bit. Anything beyond 180 bit
is not believed to add any further security and only increases the necessary
@ -116,7 +116,7 @@ ENCRYPT() is RC4, that uses one of the following keys to send data:
The first 1024 bytes of the RC4 output are discarded.
consecutive calls to ENCRYPT() by one side continue the encryption
stream (no reinitialization, no keychange). They are only used to distinguish
semantically seperate content.
semantically seperate content.
ENCRYPT2() is the negotiated crypto method.
@ -155,7 +155,7 @@ are met the handshake can be considered as invalid.
2 (termination by B)
if A sent less than 96 Bytes within 30 seconds
if A sent more than 608 bytes
if A sent more than 608 bytes
3 (termination by A)
if B sent less than 96 Bytes within 30 seconds

View File

@ -46,7 +46,7 @@ bencoded dictionary with the following keys:
added.f
string, one byte of flags for each peer in the above added string.
according to libtorrent's ut_pex.c:
1: encryption
2: seed/upload_only
4: uTP support

View File

@ -18,7 +18,7 @@
The command-line utility "transmission-remote" uses this RPC API.
Several developers have reported using its --debug JSON output as
a reference when developing/debugging their own code.
2. Message Format
Messages are formatted as objects. There are two types:
@ -145,7 +145,7 @@
in libtransmission/transmission.h. The "source" column here
corresponds to the data structure there.
key | type | source
key | type | source
----------------------------+-----------------------------+---------
activityDate | number | tr_stat
addedDate | number | tr_stat
@ -320,7 +320,7 @@
Say we want to get the name and total size of torrents #7 and #10.
Request:
Request:
{
"arguments": {
@ -336,8 +336,8 @@
{
"arguments": {
"torrents": [
{
"torrents": [
{
"id": 10,
"name": "Fedora x86_64 DVD",
"totalSize": 34983493932,
@ -346,7 +346,7 @@
"id": 7,
"name": "Ubuntu x86_64 DVD",
"totalSize", 9923890123,
}
}
]
},
"result": "success",
@ -367,7 +367,7 @@
"metainfo" | string base64-encoded .torrent content
"paused" | boolean if true, don't start the torrent
"peer-limit" | number maximum number of peers
"bandwidthPriority" | number torrent's bandwidth tr_priority_t
"bandwidthPriority" | number torrent's bandwidth tr_priority_t
"files-wanted" | array indices of file(s) to download
"files-unwanted" | array indices of file(s) to not download
"priority-high" | array indices of high-priority file(s)
@ -379,7 +379,7 @@
The format of the "cookies" should be NAME=CONTENTS, where NAME is the
cookie name and CONTENTS is what the cookie should contain.
Set multiple cookies like this: "name1=content1; name2=content2;" etc.
Set multiple cookies like this: "name1=content1; name2=content2;" etc.
<http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTCOOKIE>
Response arguments: On success, a "torrent-added" object in the
@ -671,12 +671,12 @@
| | | |
| | yes | torrent-set | new arg "bandwidthPriority"
| | yes | torrent-set | new arg "honorsSessionLimits"
| | yes | torrent-set | new arg "seedRatioLimit"
| | yes | torrent-set | new arg "seedRatioLimited"
| | NO | torrent-set | renamed "speed-limit-down" to "downloadLimit"
| | NO | torrent-set | renamed "speed-limit-down-enabled" to "downloadLimited"
| | NO | torrent-set | renamed "speed-limit-up" to "uploadLimit"
| | NO | torrent-set | renamed "speed-limit-up-enabled" to "uploadLimited"
| | yes | torrent-set | new arg "seedRatioLimit"
| | yes | torrent-set | new arg "seedRatioLimited"
| | NO | torrent-set | renamed "speed-limit-down" to "downloadLimit"
| | NO | torrent-set | renamed "speed-limit-down-enabled" to "downloadLimited"
| | NO | torrent-set | renamed "speed-limit-up" to "uploadLimit"
| | NO | torrent-set | renamed "speed-limit-up-enabled" to "uploadLimited"
| | | |
| | yes | torrent-get | new arg "bandwidthPriority"
| | yes | torrent-get | new arg "fileStats"

View File

@ -1364,6 +1364,7 @@ show_about_dialog (GtkWindow * parent)
const char * uri = "https://transmissionbt.com/";
const char * authors[] = { "Jordan Lee (Backend; GTK+)",
"Mitchell Livingston (Backend; OS X)",
"Mike Gelfand",
NULL };
gtk_show_about_dialog (parent,

View File

@ -78,8 +78,9 @@ was written by
.An Jordan Lee ,
.An Josh Elsasser ,
.An Eric Petit ,
.An Mitchell Livingston ,
and
.An Mitchell Livingston .
.An Mike Gelfand .
.Sh SEE ALSO
.Xr transmission-create 1 ,
.Xr transmission-daemon 1 ,

View File

@ -1,8 +1,9 @@
[Desktop Entry]
_Name=Transmission
_GenericName=BitTorrent Client
_X-GNOME-FullName=Transmission BitTorrent Client
_Comment=Download and share files over BitTorrent
# Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon!
_Keywords=torrents;downloading;uploading;share;sharing;
Exec=transmission-gtk %U
Icon=transmission
Terminal=false

View File

@ -220,7 +220,7 @@ tr_clientForId (char * buf, size_t buflen, const void * id_in)
else if (strncmp (chid+1, "BX", 2) == 0) four_digits (buf, buflen, "BittorrentX", id+3);
else if (strncmp (chid+1, "EB", 2) == 0) four_digits (buf, buflen, "EBit", id+3);
else if (strncmp (chid+1, "DE", 2) == 0) four_digits (buf, buflen, "Deluge", id+3);
else if (strncmp (chid+1, "DP", 2) == 0) four_digits (buf, buflen, "Propogate Data Client", id+3);
else if (strncmp (chid+1, "DP", 2) == 0) four_digits (buf, buflen, "Propagate Data Client", id+3);
else if (strncmp (chid+1, "FC", 2) == 0) four_digits (buf, buflen, "FileCroc", id+3);
else if (strncmp (chid+1, "FT", 2) == 0) four_digits (buf, buflen, "FoxTorrent/RedSwoosh", id+3);
else if (strncmp (chid+1, "GR", 2) == 0) four_digits (buf, buflen, "GetRight", id+3);

View File

@ -116,22 +116,30 @@ test_sha1 (void)
static int
test_ssha1 (void)
{
const char * const test_data[] =
{
"test",
"QNY)(*#$B)!_X$B !_B#($^!)*&$%CV!#)&$C!@$(P*)"
};
struct
{
const char * const plain_text;
const char * const ssha1;
}
test_data[] =
{
{ "test", "{15ad0621b259a84d24dcd4e75b09004e98a3627bAMbyRHJy" },
{ "QNY)(*#$B)!_X$B !_B#($^!)*&$%CV!#)&$C!@$(P*)", "{10e2d7acbb104d970514a147cd16d51dfa40fb3c0OSwJtOL" }
};
size_t i;
#define HASH_COUNT (16 * 1024)
#define HASH_COUNT (4 * 1024)
for (i = 0; i < sizeof (test_data) / sizeof (*test_data); ++i)
{
char * const phrase = tr_strdup (test_data[i]);
char * const phrase = tr_strdup (test_data[i].plain_text);
char ** hashes = tr_new (char *, HASH_COUNT);
size_t j;
check (tr_ssha1_matches (test_data[i].ssha1, phrase));
check (tr_ssha1_matches_ (test_data[i].ssha1, phrase));
for (j = 0; j < HASH_COUNT; ++j)
{
hashes[j] = j % 2 == 0 ? tr_ssha1 (phrase) : tr_ssha1_ (phrase);
@ -173,6 +181,10 @@ test_ssha1 (void)
#undef HASH_COUNT
/* should work with different salt lengths as well */
check (tr_ssha1_matches ("{a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", "test"));
check (tr_ssha1_matches ("{d209a21d3bc4f8fc4f8faf347e69f3def597eb170pySy4ai1ZPMjeU1", "test"));
return 0;
}

View File

@ -132,6 +132,8 @@ tr_ssha1 (const char * plain_text)
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"./";
assert (plain_text != NULL);
size_t i;
unsigned char salt[saltval_len];
uint8_t sha[SHA_DIGEST_LENGTH];
@ -154,34 +156,27 @@ bool
tr_ssha1_matches (const char * ssha1,
const char * plain_text)
{
char * salt;
size_t saltlen;
char * my_ssha1;
uint8_t buf[SHA_DIGEST_LENGTH];
bool result;
const size_t sourcelen = strlen (ssha1);
assert (ssha1 != NULL);
assert (plain_text != NULL);
const size_t brace_len = 1;
const size_t brace_and_hash_len = brace_len + 2 * SHA_DIGEST_LENGTH;
const size_t source_len = strlen (ssha1);
if (source_len < brace_and_hash_len || ssha1[0] != '{')
return false;
/* extract the salt */
if (sourcelen < 2 * SHA_DIGEST_LENGTH - 1)
return false;
saltlen = sourcelen - 2 * SHA_DIGEST_LENGTH - 1;
salt = tr_malloc (saltlen);
memcpy (salt, ssha1 + 2 * SHA_DIGEST_LENGTH + 1, saltlen);
const char * const salt = ssha1 + brace_and_hash_len;
const size_t salt_len = source_len - brace_and_hash_len;
uint8_t buf[SHA_DIGEST_LENGTH * 2 + 1];
/* hash pass + salt */
my_ssha1 = tr_malloc (2 * SHA_DIGEST_LENGTH + saltlen + 2);
tr_sha1 (buf, plain_text, (int) strlen (plain_text), salt, (int) saltlen, NULL);
tr_sha1_to_hex (&my_ssha1[1], buf);
memcpy (my_ssha1 + 1 + 2 * SHA_DIGEST_LENGTH, salt, saltlen);
my_ssha1[1 + 2 * SHA_DIGEST_LENGTH + saltlen] = '\0';
my_ssha1[0] = '{';
tr_sha1 (buf, plain_text, (int) strlen (plain_text), salt, (int) salt_len, NULL);
tr_sha1_to_hex ((char *) buf, buf);
result = strcmp (ssha1, my_ssha1) == 0;
tr_free (my_ssha1);
tr_free (salt);
return result;
return strncmp (ssha1 + brace_len, (const char *) buf, SHA_DIGEST_LENGTH * 2) == 0;
}
/***

View File

@ -247,7 +247,7 @@ tr_netOpenPeerSocket (tr_session * session,
if (clientIsSeed) {
int n = 8192;
if (setsockopt (s, SOL_SOCKET, SO_RCVBUF, (const void *) &n, sizeof (n)))
tr_logAddInfo ("Unable to set SO_RCVBUF on socket %"TR_PRI_SOCK": %s", s,
tr_logAddInfo ("Unable to set SO_RCVBUF on socket %" PRIdMAX ": %s", (intmax_t) s,
tr_net_strerror (err_buf, sizeof (err_buf), sockerrno));
}
@ -264,8 +264,8 @@ tr_netOpenPeerSocket (tr_session * session,
sourcelen = setup_sockaddr (source_addr, 0, &source_sock);
if (bind (s, (struct sockaddr *) &source_sock, sourcelen))
{
tr_logAddError (_("Couldn't set source address %s on %"TR_PRI_SOCK": %s"),
tr_address_to_string (source_addr), s,
tr_logAddError (_("Couldn't set source address %s on %" PRIdMAX ": %s"),
tr_address_to_string (source_addr), (intmax_t) s,
tr_net_strerror (err_buf, sizeof (err_buf), sockerrno));
tr_netClose (session, s);
return TR_BAD_SOCKET; /* -errno */
@ -282,16 +282,16 @@ tr_netOpenPeerSocket (tr_session * session,
tmperrno = sockerrno;
if ((tmperrno != ENETUNREACH && tmperrno != EHOSTUNREACH) || addr->type == TR_AF_INET)
{
tr_logAddError (_("Couldn't connect socket %"TR_PRI_SOCK" to %s, port %d (errno %d - %s)"),
s, tr_address_to_string (addr), (int)ntohs (port), tmperrno,
tr_logAddError (_("Couldn't connect socket %" PRIdMAX " to %s, port %d (errno %d - %s)"),
(intmax_t) s, tr_address_to_string (addr), (int)ntohs (port), tmperrno,
tr_net_strerror (err_buf, sizeof (err_buf), tmperrno));
}
tr_netClose (session, s);
s = TR_BAD_SOCKET; /* -tmperrno */
}
tr_logAddDeep (__FILE__, __LINE__, NULL, "New OUTGOING connection %"TR_PRI_SOCK" (%s)",
s, tr_peerIoAddrStr (addr, port));
tr_logAddDeep (__FILE__, __LINE__, NULL, "New OUTGOING connection %" PRIdMAX " (%s)",
(intmax_t) s, tr_peerIoAddrStr (addr, port));
return s;
}
@ -382,7 +382,7 @@ tr_netBindTCPImpl (const tr_address * addr,
}
if (!suppressMsgs)
tr_logAddDebug ("Bound socket %"TR_PRI_SOCK" to port %d on %s", fd, port, tr_address_to_string (addr));
tr_logAddDebug ("Bound socket %" PRIdMAX " to port %d on %s", (intmax_t) fd, port, tr_address_to_string (addr));
if (listen (fd, 128) == -1) {
*errOut = sockerrno;

View File

@ -38,7 +38,6 @@
#ifdef _WIN32
typedef SOCKET tr_socket_t;
#define TR_BAD_SOCKET INVALID_SOCKET
#define TR_PRI_SOCK "Id" /* intentionally signed to print -1 nicely. */
#undef EADDRINUSE
#define EADDRINUSE WSAEADDRINUSE
@ -65,7 +64,6 @@
typedef int tr_socket_t;
/** @brief Platform-specific invalid socket descriptor constant. */
#define TR_BAD_SOCKET (-1)
#define TR_PRI_SOCK "d"
#define sockerrno errno
#endif

View File

@ -625,7 +625,7 @@ tr_peerIoNew (tr_session * session,
tr_bandwidthConstruct (&io->bandwidth, session, parent);
tr_bandwidthSetPeer (&io->bandwidth, io);
dbgmsg (io, "bandwidth is %p; its parent is %p", (void*)&io->bandwidth, (void*)parent);
dbgmsg (io, "socket is %"TR_PRI_SOCK", utp_socket is %p", socket, (void*)utp_socket);
dbgmsg (io, "socket is %" PRIdMAX ", utp_socket is %p", (intmax_t) socket, (void*)utp_socket);
if (io->socket != TR_BAD_SOCKET) {
io->event_read = event_new (session->event_base,
@ -686,7 +686,7 @@ tr_peerIoNewOutgoing (tr_session * session,
if (!utp_socket) {
fd = tr_netOpenPeerSocket (session, addr, port, isSeed);
dbgmsg (NULL, "tr_netOpenPeerSocket returned fd %"TR_PRI_SOCK, fd);
dbgmsg (NULL, "tr_netOpenPeerSocket returned fd %" PRIdMAX, (intmax_t) fd);
}
if (fd == TR_BAD_SOCKET && utp_socket == NULL)

View File

@ -516,12 +516,15 @@ tr_getWebClientDir (const tr_session * session UNUSED)
module_path = tr_win32_native_to_utf8 (wide_module_path, -1);
dir = tr_sys_path_dirname (module_path, NULL);
tr_free (module_path);
s = tr_buildPath (dir, "Web", NULL);
tr_free (dir);
if (!isWebClientDir (s))
if (dir != NULL)
{
tr_free (s);
s = NULL;
s = tr_buildPath (dir, "Web", NULL);
tr_free (dir);
if (!isWebClientDir (s))
{
tr_free (s);
s = NULL;
}
}
}

View File

@ -191,8 +191,8 @@ accept_incoming_peer (evutil_socket_t fd, short what UNUSED, void * vsession)
clientSocket = tr_netAccept (session, fd, &clientAddr, &clientPort);
if (clientSocket != TR_BAD_SOCKET)
{
tr_logAddDeep (__FILE__, __LINE__, NULL, "new incoming connection %"TR_PRI_SOCK" (%s)",
clientSocket, tr_peerIoAddrStr (&clientAddr, clientPort));
tr_logAddDeep (__FILE__, __LINE__, NULL, "new incoming connection %" PRIdMAX " (%s)",
(intmax_t) clientSocket, tr_peerIoAddrStr (&clientAddr, clientPort));
tr_peerMgrAddIncoming (session->peerMgr, &clientAddr, clientPort,
clientSocket, NULL);
}
@ -1866,6 +1866,9 @@ sessionCloseImplWaitForIdleUdp (evutil_socket_t foo UNUSED,
static void
sessionCloseImplFinish (tr_session * session)
{
event_free (session->saveTimer);
session->saveTimer = NULL;
/* we had to wait until UDP trackers were closed before closing these: */
evdns_base_free (session->evdns_base, 0);
session->evdns_base = NULL;
@ -2304,12 +2307,10 @@ loadBlocklists (tr_session * session)
else
{
char * binname;
char * basename;
tr_sys_path_info path_info;
tr_sys_path_info binname_info;
basename = tr_sys_path_basename (name, NULL);
binname = tr_strdup_printf ("%s" TR_PATH_DELIMITER_STR "%s.bin", dirname, basename);
binname = tr_strdup_printf ("%s" TR_PATH_DELIMITER_STR "%s.bin", dirname, name);
if (!tr_sys_path_get_info (binname, 0, &binname_info, NULL)) /* create it */
{
@ -2344,7 +2345,6 @@ loadBlocklists (tr_session * session)
tr_free (old);
}
tr_free (basename);
tr_free (binname);
}

View File

@ -635,16 +635,19 @@ tr_binary_to_hex (const void * input,
{
static const char hex[] = "0123456789abcdef";
const uint8_t * input_octets = input;
size_t i;
for (i = 0; i < byte_length; ++i)
{
const unsigned int val = *input_octets++;
*output++ = hex[val >> 4];
*output++ = hex[val & 0xf];
}
/* go from back to front to allow for in-place conversion */
input_octets += byte_length;
output += byte_length * 2;
*output = '\0';
while (byte_length-- > 0)
{
const unsigned int val = *(--input_octets);
*(--output) = hex[val & 0xf];
*(--output) = hex[val >> 4];
}
}
void

View File

@ -257,11 +257,19 @@ tr_variantParseBenc (const void * buf_in,
break;
}
if (!err && (!top->type || !tr_ptrArrayEmpty(&stack)))
if (err == 0 && (top->type == 0 || !tr_ptrArrayEmpty(&stack)))
err = EILSEQ;
if (!err && setme_end)
*setme_end = (const char*) buf;
if (err == 0)
{
if (setme_end != NULL)
*setme_end = (const char*) buf;
}
else if (top->type != 0)
{
tr_variantFree (top);
tr_variantInit (top, 0);
}
tr_ptrArrayDestruct (&stack, NULL);
return err;

View File

@ -1,5 +1,4 @@
#ifndef TR_VERSION_H
#define TR_VERSION_H
#pragma once
#define PEERID_PREFIX "${TR_PEER_ID_PREFIX}"
#define USERAGENT_PREFIX "${TR_USER_AGENT_PREFIX}"
@ -14,5 +13,3 @@
#cmakedefine TR_BETA_RELEASE 1
#cmakedefine TR_NIGHTLY_RELEASE 1
#cmakedefine TR_STABLE_RELEASE 1
#endif /* TR_VERSION_H */

View File

@ -127,6 +127,8 @@ test_construct (void)
check (wd != NULL);
check (tr_sys_path_is_same (test_dir, tr_watchdir_get_path (wd), NULL));
process_events ();
tr_watchdir_free (wd);
event_base_free (ev_base);

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="AboutWindowController">
@ -75,15 +76,13 @@
<rect key="frame" x="1" y="1" width="523" height="188"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textView editable="NO" importsGraphics="NO" horizontallyResizable="YES" verticallyResizable="YES" spellingCorrection="YES" id="28">
<textView editable="NO" importsGraphics="NO" horizontallyResizable="YES" spellingCorrection="YES" id="28">
<rect key="frame" x="0.0" y="0.0" width="523" height="188"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<size key="minSize" width="523" height="188"/>
<size key="maxSize" width="10000000" height="10000000"/>
<color key="insertionPointColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<size key="minSize" width="523" height="188"/>
<size key="maxSize" width="10000000" height="10000000"/>
</textView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@ -141,17 +140,15 @@
<rect key="frame" x="20" y="61" width="490" height="250"/>
<clipView key="contentView" id="MAJ-Tu-46J">
<rect key="frame" x="1" y="1" width="473" height="248"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textView editable="NO" importsGraphics="NO" horizontallyResizable="YES" verticallyResizable="YES" spellingCorrection="YES" id="17">
<textView editable="NO" importsGraphics="NO" horizontallyResizable="YES" spellingCorrection="YES" id="17">
<rect key="frame" x="0.0" y="0.0" width="473" height="248"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<size key="minSize" width="473" height="248"/>
<size key="maxSize" width="10000000" height="10000000"/>
<color key="insertionPointColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<size key="minSize" width="473" height="248"/>
<size key="maxSize" width="10000000" height="10000000"/>
</textView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>

View File

@ -24,7 +24,7 @@
@interface AboutWindowController : NSWindowController
{
IBOutlet NSTextView * fTextView, * fLicenseView;
IBOutlet NSTextView * fTextView, * fLicenseView;
IBOutlet NSTextField * fVersionField, * fCopyrightField;
IBOutlet NSButton * fLicenseButton, * fLicenseCloseButton;
IBOutlet NSPanel * fLicenseSheet;

View File

@ -37,19 +37,19 @@ AboutWindowController * fAboutBoxInstance = nil;
NSDictionary * info = [[NSBundle mainBundle] infoDictionary];
[fVersionField setStringValue: [NSString stringWithFormat: @"%@ (%@)",
[info objectForKey: @"CFBundleShortVersionString"], [info objectForKey: (NSString *)kCFBundleVersionKey]]];
[fCopyrightField setStringValue: [[NSBundle mainBundle] localizedStringForKey: @"NSHumanReadableCopyright"
value: nil table: @"InfoPlist"]];
[[fTextView textStorage] setAttributedString: [[[NSAttributedString alloc] initWithPath:
[[NSBundle mainBundle] pathForResource: @"Credits" ofType: @"rtf"] documentAttributes: nil] autorelease]];
//size license button
const CGFloat oldButtonWidth = NSWidth([fLicenseButton frame]);
[fLicenseButton setTitle: NSLocalizedString(@"License", "About window -> license button")];
[fLicenseButton sizeToFit];
NSRect buttonFrame = [fLicenseButton frame];
buttonFrame.size.width += 10.0;
buttonFrame.origin.x -= NSWidth(buttonFrame) - oldButtonWidth;
@ -63,7 +63,7 @@ AboutWindowController * fAboutBoxInstance = nil;
- (void) windowWillClose: (id) sender
{
[fAboutBoxInstance autorelease];
[fAboutBoxInstance autorelease];
fAboutBoxInstance = nil;
}
@ -73,8 +73,8 @@ AboutWindowController * fAboutBoxInstance = nil;
usedEncoding: nil error: NULL];
[fLicenseView setString: licenseText];
[fLicenseCloseButton setTitle: NSLocalizedString(@"OK", "About window -> license close button")];
[NSApp beginSheet: fLicenseSheet modalForWindow: [self window] modalDelegate: nil didEndSelector: nil contextInfo: nil];
[NSApp beginSheet: fLicenseSheet modalForWindow: [self window] modalDelegate: nil didEndSelector: nil contextInfo: nil];
}
- (IBAction) hideLicense: (id) sender

View File

@ -32,19 +32,19 @@
IBOutlet NSTextField * fNameField, * fLocationField;
IBOutlet NSButton * fStartCheck;
IBOutlet NSPopUpButton * fGroupPopUp, * fPriorityPopUp;
//remove these when switching to auto layout
IBOutlet NSTextField * fMagnetLinkLabel;
IBOutlet NSTextField * fDownloadToLabel, * fGroupLabel, * fPriorityLabel;
IBOutlet NSButton * fChangeDestinationButton;
IBOutlet NSBox * fDownloadToBox;
IBOutlet NSButton * fAddButton, * fCancelButton;
Controller * fController;
Torrent * fTorrent;
NSString * fDestination;
NSInteger fGroupValue;
TorrentDeterminationType fGroupDeterminationType;
}

View File

@ -52,9 +52,9 @@
{
fTorrent = torrent;
fDestination = [[path stringByExpandingTildeInPath] retain];
fController = controller;
fGroupValue = [torrent groupValue];
fGroupDeterminationType = TorrentDeterminationAutomatic;
}
@ -65,27 +65,29 @@
{
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(updateGroupMenu:)
name: @"UpdateGroups" object: nil];
NSString * name = [fTorrent name];
[[self window] setTitle: name];
[fNameField setStringValue: name];
[fNameField setToolTip: name];
[self setGroupsMenu];
[fGroupPopUp selectItemWithTag: fGroupValue];
NSInteger priorityIndex;
switch ([fTorrent priority])
{
case TR_PRI_HIGH: priorityIndex = POPUP_PRIORITY_HIGH; break;
case TR_PRI_NORMAL: priorityIndex = POPUP_PRIORITY_NORMAL; break;
case TR_PRI_LOW: priorityIndex = POPUP_PRIORITY_LOW; break;
default: NSAssert1(NO, @"Unknown priority for adding torrent: %d", [fTorrent priority]);
default:
NSAssert1(NO, @"Unknown priority for adding torrent: %d", [fTorrent priority]);
priorityIndex = POPUP_PRIORITY_NORMAL;
}
[fPriorityPopUp selectItemAtIndex: priorityIndex];
[fStartCheck setState: [[NSUserDefaults standardUserDefaults] boolForKey: @"AutoStartDownload"] ? NSOnState : NSOffState];
if (fDestination)
[self setDestinationPath: fDestination determinationType: TorrentDeterminationAutomatic];
else
@ -93,10 +95,10 @@
[fLocationField setStringValue: @""];
[fLocationImageView setImage: nil];
}
#warning when 10.7-only, switch to auto layout
[fMagnetLinkLabel sizeToFit];
const CGFloat downloadToLabelOldWidth = [fDownloadToLabel frame].size.width;
[fDownloadToLabel sizeToFit];
const CGFloat changeDestOldWidth = [fChangeDestinationButton frame].size.width;
@ -104,13 +106,13 @@
NSRect changeDestFrame = [fChangeDestinationButton frame];
changeDestFrame.origin.x -= changeDestFrame.size.width - changeDestOldWidth;
[fChangeDestinationButton setFrame: changeDestFrame];
NSRect downloadToBoxFrame = [fDownloadToBox frame];
const CGFloat downloadToBoxSizeDiff = ([fDownloadToLabel frame].size.width - downloadToLabelOldWidth) + (changeDestFrame.size.width - changeDestOldWidth);
downloadToBoxFrame.size.width -= downloadToBoxSizeDiff;
downloadToBoxFrame.origin.x -= downloadToLabelOldWidth - [fDownloadToLabel frame].size.width;
[fDownloadToBox setFrame: downloadToBoxFrame];
NSRect groupPopUpFrame = [fGroupPopUp frame];
NSRect priorityPopUpFrame = [fPriorityPopUp frame];
const CGFloat popUpOffset = groupPopUpFrame.origin.x - NSMaxX([fGroupLabel frame]);
@ -131,7 +133,7 @@
[fGroupPopUp setFrame: groupPopUpFrame];
[fPriorityLabel setFrame: priorityLabelFrame];
[fPriorityPopUp setFrame: priorityPopUpFrame];
const CGFloat minButtonWidth = 82.0;
const CGFloat oldAddButtonWidth = [fAddButton bounds].size.width;
const CGFloat oldCancelButtonWidth = [fCancelButton bounds].size.width;
@ -148,7 +150,7 @@
cancelButtonFrame.origin.x -= addButtonWidthIncrease + (buttonWidth - oldCancelButtonWidth);
[fAddButton setFrame: addButtonFrame];
[fCancelButton setFrame: cancelButtonFrame];
[fStartCheck sizeToFit];
}
@ -162,9 +164,9 @@
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
[fDestination release];
[super dealloc];
}
@ -182,10 +184,10 @@
[panel setCanChooseFiles: NO];
[panel setCanChooseDirectories: YES];
[panel setCanCreateDirectories: YES];
[panel setMessage: [NSString stringWithFormat: NSLocalizedString(@"Select the download folder for \"%@\"",
"Add -> select destination folder"), [fTorrent name]]];
[panel beginSheetModalForWindow: [self window] completionHandler: ^(NSInteger result) {
if (result == NSFileHandlingPanelOKButton)
[self setDestinationPath: [[[panel URLs] objectAtIndex: 0] path] determinationType:TorrentDeterminationUserSpecified];
@ -211,7 +213,7 @@
[alert addButtonWithTitle: NSLocalizedString(@"Cancel", "Add torrent -> same name -> button")];
[alert addButtonWithTitle: NSLocalizedString(@"Add", "Add torrent -> same name -> button")];
[alert setShowsSuppressionButton: YES];
[alert beginSheetModalForWindow: [self window] modalDelegate: self
didEndSelector: @selector(sameNameAlertDidEnd:returnCode:contextInfo:) contextInfo: nil];
}
@ -239,7 +241,9 @@
case POPUP_PRIORITY_HIGH: priority = TR_PRI_HIGH; break;
case POPUP_PRIORITY_NORMAL: priority = TR_PRI_NORMAL; break;
case POPUP_PRIORITY_LOW: priority = TR_PRI_LOW; break;
default: NSAssert1(NO, @"Unknown priority tag for adding torrent: %ld", [sender tag]);
default:
NSAssert1(NO, @"Unknown priority tag for adding torrent: %ld", [sender tag]);
priority = TR_PRI_NORMAL;
}
[fTorrent setPriority: priority];
}
@ -250,7 +254,7 @@
if (![fGroupPopUp selectItemWithTag: fGroupValue])
{
fGroupValue = -1;
fGroupDeterminationType = TorrentDeterminationAutomatic;
fGroupDeterminationType = TorrentDeterminationAutomatic;
[fGroupPopUp selectItemWithTag: fGroupValue];
}
}
@ -262,10 +266,10 @@
- (void) confirmAdd
{
[fTorrent setGroupValue: fGroupValue determinationType: fGroupDeterminationType];
if ([fStartCheck state] == NSOnState)
[fTorrent startTransfer];
[self close];
[fController askOpenMagnetConfirmed: self add: YES]; //ensure last, since it releases this controller
}
@ -274,16 +278,16 @@
{
destination = [destination stringByExpandingTildeInPath];
if (!fDestination || ![fDestination isEqualToString: destination])
{
{
[fDestination release];
fDestination = [destination retain];
[fTorrent changeDownloadFolderBeforeUsing: fDestination determinationType: determinationType];
}
[fLocationField setStringValue: [fDestination stringByAbbreviatingWithTildeInPath]];
[fLocationField setToolTip: fDestination];
ExpandedPathToIconTransformer * iconTransformer = [[ExpandedPathToIconTransformer alloc] init];
[fLocationImageView setImage: [iconTransformer transformedValue: fDestination]];
[iconTransformer release];
@ -298,7 +302,7 @@
- (void) changeGroupValue: (id) sender
{
NSInteger previousGroup = fGroupValue;
fGroupValue = [sender tag];
fGroupValue = [sender tag];
fGroupDeterminationType = TorrentDeterminationUserSpecified;
if ([[GroupsController groups] usesCustomDownloadLocationForIndex: fGroupValue])
@ -312,9 +316,9 @@
{
if ([[alert suppressionButton] state] == NSOnState)
[[NSUserDefaults standardUserDefaults] setBool: NO forKey: @"WarningFolderDataSameName"];
[alert release];
if (returnCode == NSAlertSecondButtonReturn)
[self performSelectorOnMainThread: @selector(confirmAdd) withObject: nil waitUntilDone: NO];
}

View File

@ -34,24 +34,24 @@
IBOutlet NSButton * fStartCheck, * fDeleteCheck;
IBOutlet NSPopUpButton * fGroupPopUp, * fPriorityPopUp;
IBOutlet NSProgressIndicator * fVerifyIndicator;
IBOutlet NSTextField * fFileFilterField;
IBOutlet NSButton * fCheckAllButton, *fUncheckAllButton;
IBOutlet FileOutlineController * fFileController;
IBOutlet NSScrollView * fFileScrollView;
Controller * fController;
Torrent * fTorrent;
NSString * fDestination, * fTorrentFile;
BOOL fLockDestination;
BOOL fDeleteTorrentEnableInitially, fCanToggleDelete;
NSInteger fGroupValue;
NSTimer * fTimer;
TorrentDeterminationType fGroupValueDetermination;
}

View File

@ -60,14 +60,14 @@
fTorrent = torrent;
fDestination = [[path stringByExpandingTildeInPath] retain];
fLockDestination = lockDestination;
fController = controller;
fTorrentFile = [[torrentFile stringByExpandingTildeInPath] retain];
fDeleteTorrentEnableInitially = deleteTorrent;
fCanToggleDelete = canToggleDelete;
fGroupValue = [torrent groupValue];
fGroupValueDetermination = TorrentDeterminationAutomatic;
@ -79,24 +79,24 @@
- (void) awakeFromNib
{
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(updateCheckButtons:) name: @"TorrentFileCheckChange" object: fTorrent];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(updateGroupMenu:) name: @"UpdateGroups" object: nil];
[fFileController setTorrent: fTorrent];
NSString * name = [fTorrent name];
[[self window] setTitle: name];
[fNameField setStringValue: name];
[fNameField setToolTip: name];
[fIconView setImage: [fTorrent icon]];
if (![fTorrent isFolder])
{
[fFileFilterField setHidden: YES];
[fCheckAllButton setHidden: YES];
[fUncheckAllButton setHidden: YES];
NSRect scrollFrame = [fFileScrollView frame];
const CGFloat diff = NSMinY([fFileScrollView frame]) - NSMinY([fFileFilterField frame]);
scrollFrame.origin.y -= diff;
@ -105,25 +105,27 @@
}
else
[self updateCheckButtons: nil];
[self setGroupsMenu];
[fGroupPopUp selectItemWithTag: fGroupValue];
NSInteger priorityIndex;
switch ([fTorrent priority])
{
case TR_PRI_HIGH: priorityIndex = POPUP_PRIORITY_HIGH; break;
case TR_PRI_NORMAL: priorityIndex = POPUP_PRIORITY_NORMAL; break;
case TR_PRI_LOW: priorityIndex = POPUP_PRIORITY_LOW; break;
default: NSAssert1(NO, @"Unknown priority for adding torrent: %d", [fTorrent priority]);
default:
NSAssert1(NO, @"Unknown priority for adding torrent: %d", [fTorrent priority]);
priorityIndex = POPUP_PRIORITY_NORMAL;
}
[fPriorityPopUp selectItemAtIndex: priorityIndex];
[fStartCheck setState: [[NSUserDefaults standardUserDefaults] boolForKey: @"AutoStartDownload"] ? NSOnState : NSOffState];
[fDeleteCheck setState: fDeleteTorrentEnableInitially ? NSOnState : NSOffState];
[fDeleteCheck setEnabled: fCanToggleDelete];
if (fDestination)
[self setDestinationPath: fDestination determinationType: (fLockDestination ? TorrentDeterminationUserSpecified : TorrentDeterminationAutomatic)];
else
@ -131,7 +133,7 @@
[fLocationField setStringValue: @""];
[fLocationImageView setImage: nil];
}
fTimer = [[NSTimer scheduledTimerWithTimeInterval: UPDATE_SECONDS target: self
selector: @selector(updateFiles) userInfo: nil repeats: YES] retain];
[self updateFiles];
@ -147,13 +149,13 @@
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
[fTimer invalidate];
[fTimer release];
[fDestination release];
[fTorrentFile release];
[super dealloc];
}
@ -171,10 +173,10 @@
[panel setCanChooseFiles: NO];
[panel setCanChooseDirectories: YES];
[panel setCanCreateDirectories: YES];
[panel setMessage: [NSString stringWithFormat: NSLocalizedString(@"Select the download folder for \"%@\"",
"Add -> select destination folder"), [fTorrent name]]];
[panel beginSheetModalForWindow: [self window] completionHandler: ^(NSInteger result) {
if (result == NSFileHandlingPanelOKButton)
{
@ -203,7 +205,7 @@
[alert addButtonWithTitle: NSLocalizedString(@"Cancel", "Add torrent -> same name -> button")];
[alert addButtonWithTitle: NSLocalizedString(@"Add", "Add torrent -> same name -> button")];
[alert setShowsSuppressionButton: YES];
[alert beginSheetModalForWindow: [self window] modalDelegate: self
didEndSelector: @selector(sameNameAlertDidEnd:returnCode:contextInfo:) contextInfo: nil];
}
@ -222,9 +224,9 @@
[fTimer invalidate];
[fTimer release];
fTimer = nil;
[fFileController setTorrent: nil]; //avoid a crash when window tries to update
[fController askOpenConfirmed: self add: NO];
return YES;
}
@ -258,7 +260,9 @@
case POPUP_PRIORITY_HIGH: priority = TR_PRI_HIGH; break;
case POPUP_PRIORITY_NORMAL: priority = TR_PRI_NORMAL; break;
case POPUP_PRIORITY_LOW: priority = TR_PRI_LOW; break;
default: NSAssert1(NO, @"Unknown priority tag for adding torrent: %ld", [sender tag]);
default:
NSAssert1(NO, @"Unknown priority tag for adding torrent: %ld", [sender tag]);
priority = TR_PRI_NORMAL;
}
[fTorrent setPriority: priority];
}
@ -273,7 +277,7 @@
const NSInteger filesCheckState = [fTorrent checkForFiles: [NSIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [fTorrent fileCount])]];
[fCheckAllButton setEnabled: filesCheckState != NSOnState]; //if anything is unchecked
[fUncheckAllButton setEnabled: ![fTorrent allDownloaded]]; //if there are any checked files that aren't finished
//status field
NSString * fileString;
NSInteger count = [fTorrent fileCount];
@ -282,13 +286,13 @@
[NSString formattedUInteger: count]];
else
fileString = NSLocalizedString(@"1 file", "Add torrent -> info");
NSString * selectedString = [NSString stringWithFormat: NSLocalizedString(@"%@ selected", "Add torrent -> info"),
[NSString stringForFileSize: [fTorrent totalSizeSelected]]];
statusString = [NSString stringWithFormat: @"%@, %@ (%@)", fileString, statusString, selectedString];
}
[fStatusField setStringValue: statusString];
}
@ -298,7 +302,7 @@
if (![fGroupPopUp selectItemWithTag: fGroupValue])
{
fGroupValue = -1;
fGroupValueDetermination = TorrentDeterminationAutomatic;
fGroupValueDetermination = TorrentDeterminationAutomatic;
[fGroupPopUp selectItemWithTag: fGroupValue];
}
}
@ -310,11 +314,11 @@
- (void) updateFiles
{
[fTorrent update];
[fFileController refresh];
[self updateCheckButtons: nil]; //call in case button state changed by checking
if ([fTorrent isChecking])
{
const BOOL waiting = [fTorrent isCheckingWaiting];
@ -339,12 +343,12 @@
if (fTorrentFile && fCanToggleDelete && [fDeleteCheck state] == NSOnState)
[Torrent trashFile: fTorrentFile error: nil];
if ([fStartCheck state] == NSOnState)
[fTorrent startTransfer];
[fFileController setTorrent: nil]; //avoid a crash when window tries to update
[self close];
[fController askOpenConfirmed: self add: YES]; //ensure last, since it releases this controller
}
@ -353,16 +357,16 @@
{
destination = [destination stringByExpandingTildeInPath];
if (!fDestination || ![fDestination isEqualToString: destination])
{
{
[fDestination release];
fDestination = [destination retain];
[fTorrent changeDownloadFolderBeforeUsing: fDestination determinationType: determinationType];
}
[fLocationField setStringValue: [fDestination stringByAbbreviatingWithTildeInPath]];
[fLocationField setToolTip: fDestination];
ExpandedPathToIconTransformer * iconTransformer = [[ExpandedPathToIconTransformer alloc] init];
[fLocationImageView setImage: [iconTransformer transformedValue: fDestination]];
[iconTransformer release];
@ -394,9 +398,9 @@
{
if ([[alert suppressionButton] state] == NSOnState)
[[NSUserDefaults standardUserDefaults] setBool: NO forKey: @"WarningFolderDataSameName"];
[alert release];
if (returnCode == NSAlertSecondButtonReturn)
[self performSelectorOnMainThread: @selector(confirmAdd) withObject: nil waitUntilDone: NO];
}

View File

@ -26,9 +26,9 @@
@interface BadgeView : NSView
{
tr_session * fLib;
NSMutableDictionary * fAttributes;
CGFloat fDownloadRate, fUploadRate;
BOOL fQuitting;
}

View File

@ -38,7 +38,7 @@
if ((self = [super init]))
{
fLib = lib;
fDownloadRate = 0.0;
fUploadRate = 0.0;
fQuitting = NO;
@ -57,7 +57,7 @@
//only needs update if the badges were displayed or are displayed now
if (fDownloadRate == downloadRate && fUploadRate == uploadRate)
return NO;
fDownloadRate = downloadRate;
fUploadRate = uploadRate;
return YES;
@ -71,7 +71,7 @@
- (void) drawRect: (NSRect) rect
{
[[NSApp applicationIconImage] drawInRect: rect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0];
if (fQuitting)
{
NSImage * quitBadge = [NSImage imageNamed: @"QuitBadge"];
@ -79,7 +79,7 @@
atHeight: (NSHeight(rect) - [quitBadge size].height) * 0.5 adjustForQuit: YES];
return;
}
const BOOL upload = fUploadRate >= 0.1,
download = fDownloadRate >= 0.1;
CGFloat bottom = 0.0;
@ -106,21 +106,21 @@
NSShadow * stringShadow = [[NSShadow alloc] init];
[stringShadow setShadowOffset: NSMakeSize(2.0, -2.0)];
[stringShadow setShadowBlurRadius: 4.0];
fAttributes = [[NSMutableDictionary alloc] initWithCapacity: 3];
[fAttributes setObject: [NSColor whiteColor] forKey: NSForegroundColorAttributeName];
[fAttributes setObject: stringShadow forKey: NSShadowAttributeName];
[stringShadow release];
}
NSRect badgeRect;
badgeRect.size = [badge size];
badgeRect.origin.x = 0.0;
badgeRect.origin.y = height;
[badge drawInRect: badgeRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0];
//make sure text fits on the badge
CGFloat fontSize = 26.0;
NSSize stringSize;
@ -130,13 +130,13 @@
stringSize = [string sizeWithAttributes: fAttributes];
fontSize -= 1.0;
} while (NSWidth(badgeRect) < stringSize.width);
//string is in center of image
NSRect stringRect;
stringRect.origin.x = NSMidX(badgeRect) - stringSize.width * 0.5;
stringRect.origin.y = NSMidY(badgeRect) - stringSize.height * 0.5 + (quit ? 2.0 : 1.0); //adjust for shadow, extra for quit
stringRect.size = stringSize;
[string drawInRect: stringRect withAttributes: fAttributes];
}

View File

@ -28,7 +28,7 @@
@interface Badger : NSObject
{
tr_session * fLib;
NSMutableSet * fHashes;
}

View File

@ -32,14 +32,14 @@
if ((self = [super init]))
{
fLib = lib;
BadgeView * view = [[BadgeView alloc] initWithLib: lib];
[[NSApp dockTile] setContentView: view];
[view release];
fHashes = [[NSMutableSet alloc] init];
}
return self;
}
@ -55,7 +55,7 @@
? downloadRate : 0.0;
const CGFloat displayUlRate = [[NSUserDefaults standardUserDefaults] boolForKey: @"BadgeUploadRate"]
? uploadRate : 0.0;
//only update if the badged values change
if ([(BadgeView *)[[NSApp dockTile] contentView] setRatesWithDownload: displayDlRate upload: displayUlRate])
[[NSApp dockTile] display];
@ -64,7 +64,7 @@
- (void) addCompletedTorrent: (Torrent *) torrent
{
NSParameterAssert(torrent != nil);
[fHashes addObject: [torrent hashString]];
[[NSApp dockTile] setBadgeLabel: [NSString formattedUInteger: [fHashes count]]];
}

View File

@ -34,13 +34,13 @@ typedef enum
@interface BlocklistDownloader : NSObject <NSURLDownloadDelegate>
{
NSURLDownload * fDownload;
BlocklistDownloaderViewController * fViewController;
NSString * fDestination;
NSUInteger fCurrentSize;
long long fExpectedSize;
blocklistDownloadState fState;
}

View File

@ -42,7 +42,7 @@ BlocklistDownloader * fBLDownloader = nil;
fBLDownloader = [[BlocklistDownloader alloc] init];
[fBLDownloader startDownload];
}
return fBLDownloader;
}
@ -81,11 +81,11 @@ BlocklistDownloader * fBLDownloader = nil;
- (void) cancelDownload
{
[fViewController setFinished];
[fDownload cancel];
[[BlocklistScheduler scheduler] updateSchedule];
fBLDownloader = nil;
[self release];
}
@ -105,10 +105,10 @@ BlocklistDownloader * fBLDownloader = nil;
- (void) download: (NSURLDownload *) download didReceiveResponse: (NSURLResponse *) response
{
fState = BLOCKLIST_DL_DOWNLOADING;
fCurrentSize = 0;
fExpectedSize = [response expectedContentLength];
[fViewController setStatusProgressForCurrentSize: fCurrentSize expectedSize: fExpectedSize];
}
@ -121,10 +121,10 @@ BlocklistDownloader * fBLDownloader = nil;
- (void) download: (NSURLDownload *) download didFailWithError: (NSError *) error
{
[fViewController setFailed: [error localizedDescription]];
[[NSUserDefaults standardUserDefaults] setObject: [NSDate date] forKey: @"BlocklistNewLastUpdate"];
[[BlocklistScheduler scheduler] updateSchedule];
fBLDownloader = nil;
[self release];
}
@ -132,34 +132,34 @@ BlocklistDownloader * fBLDownloader = nil;
- (void) downloadDidFinish: (NSURLDownload *) download
{
fState = BLOCKLIST_DL_PROCESSING;
[fViewController setStatusProcessing];
NSAssert(fDestination != nil, @"the blocklist file destination has not been specified");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self decompressBlocklist];
dispatch_async(dispatch_get_main_queue(), ^{
const int count = tr_blocklistSetContent([(Controller *)[NSApp delegate] sessionHandle], [fDestination UTF8String]);
//delete downloaded file
[[NSFileManager defaultManager] removeItemAtPath: fDestination error: NULL];
if (count > 0)
[fViewController setFinished];
else
[fViewController setFailed: NSLocalizedString(@"The specified blocklist file did not contain any valid rules.",
"blocklist fail message")];
//update last updated date for schedule
NSDate * date = [NSDate date];
[[NSUserDefaults standardUserDefaults] setObject: date forKey: @"BlocklistNewLastUpdate"];
[[NSUserDefaults standardUserDefaults] setObject: date forKey: @"BlocklistNewLastUpdateSuccess"];
[[BlocklistScheduler scheduler] updateSchedule];
[[NSNotificationCenter defaultCenter] postNotificationName: @"BlocklistUpdated" object: nil];
fBLDownloader = nil;
[self release];
});
@ -178,87 +178,87 @@ BlocklistDownloader * fBLDownloader = nil;
- (void) startDownload
{
fState = BLOCKLIST_DL_START;
[[BlocklistScheduler scheduler] cancelSchedule];
NSString * urlString = [[NSUserDefaults standardUserDefaults] stringForKey: @"BlocklistURL"];
if (!urlString)
urlString = @"";
else if (![urlString isEqualToString: @""] && [urlString rangeOfString: @"://"].location == NSNotFound)
urlString = [@"http://" stringByAppendingString: urlString];
NSURLRequest * request = [NSURLRequest requestWithURL: [NSURL URLWithString: urlString]];
fDownload = [[NSURLDownload alloc] initWithRequest: request delegate: self];
}
//.gz, .tar.gz, .tgz, and .bgz will be decompressed by NSURLDownload for us. However, we have to do .zip files manually.
- (void) decompressBlocklist
{
if ([[[fDestination pathExtension] lowercaseString] isEqualToString: @"zip"]) {
BOOL success = NO;
if ([[[fDestination pathExtension] lowercaseString] isEqualToString: @"zip"]) {
BOOL success = NO;
NSString * workingDirectory = [fDestination stringByDeletingLastPathComponent];
//First, perform the actual unzipping
NSTask * unzip = [[NSTask alloc] init];
[unzip setLaunchPath: @"/usr/bin/unzip"];
[unzip setCurrentDirectoryPath: workingDirectory];
[unzip setArguments: [NSArray arrayWithObjects:
//First, perform the actual unzipping
NSTask * unzip = [[NSTask alloc] init];
[unzip setLaunchPath: @"/usr/bin/unzip"];
[unzip setCurrentDirectoryPath: workingDirectory];
[unzip setArguments: [NSArray arrayWithObjects:
@"-o", /* overwrite */
@"-q", /* quiet! */
fDestination, /* source zip file */
@"-d", workingDirectory, /*destination*/
nil]];
@try
{
[unzip launch];
[unzip waitUntilExit];
if ([unzip terminationStatus] == 0)
success = YES;
}
@catch(id exc)
{
success = NO;
}
[unzip release];
if (success) {
//Now find out what file we actually extracted; don't just assume it matches the zipfile's name
NSTask *zipinfo;
zipinfo = [[NSTask alloc] init];
[zipinfo setLaunchPath: @"/usr/bin/zipinfo"];
[zipinfo setArguments: [NSArray arrayWithObjects:
@try
{
[unzip launch];
[unzip waitUntilExit];
if ([unzip terminationStatus] == 0)
success = YES;
}
@catch(id exc)
{
success = NO;
}
[unzip release];
if (success) {
//Now find out what file we actually extracted; don't just assume it matches the zipfile's name
NSTask *zipinfo;
zipinfo = [[NSTask alloc] init];
[zipinfo setLaunchPath: @"/usr/bin/zipinfo"];
[zipinfo setArguments: [NSArray arrayWithObjects:
@"-1", /* just the filename */
fDestination, /* source zip file */
nil]];
[zipinfo setStandardOutput: [NSPipe pipe]];
@try
{
NSFileHandle * zipinfoOutput = [[zipinfo standardOutput] fileHandleForReading];
[zipinfo setStandardOutput: [NSPipe pipe]];
[zipinfo launch];
[zipinfo waitUntilExit];
NSString * actualFilename = [[[NSString alloc] initWithData: [zipinfoOutput readDataToEndOfFile]
@try
{
NSFileHandle * zipinfoOutput = [[zipinfo standardOutput] fileHandleForReading];
[zipinfo launch];
[zipinfo waitUntilExit];
NSString * actualFilename = [[[NSString alloc] initWithData: [zipinfoOutput readDataToEndOfFile]
encoding: NSUTF8StringEncoding] autorelease];
actualFilename = [actualFilename stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString * newBlocklistPath = [workingDirectory stringByAppendingPathComponent: actualFilename];
//Finally, delete the ZIP file; we're done with it, and we'll return the unzipped blocklist
[[NSFileManager defaultManager] removeItemAtPath: fDestination error: NULL];
actualFilename = [actualFilename stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString * newBlocklistPath = [workingDirectory stringByAppendingPathComponent: actualFilename];
//Finally, delete the ZIP file; we're done with it, and we'll return the unzipped blocklist
[[NSFileManager defaultManager] removeItemAtPath: fDestination error: NULL];
[fDestination release];
fDestination = [newBlocklistPath retain];
}
}
@catch(id exc) {}
[zipinfo release];
}
}
[zipinfo release];
}
}
}
@end

View File

@ -26,9 +26,9 @@
@class PrefsController;
@interface BlocklistDownloaderViewController : NSObject
{
{
PrefsController * fPrefsController;
IBOutlet NSWindow * fStatusWindow;
IBOutlet NSProgressIndicator * fProgressBar;
IBOutlet NSTextField * fTextField;

View File

@ -48,14 +48,14 @@ BlocklistDownloaderViewController * fBLViewController = nil;
- (void) awakeFromNib
{
[fButton setTitle: NSLocalizedString(@"Cancel", "Blocklist -> cancel button")];
const CGFloat oldWidth = NSWidth([fButton frame]);
[fButton sizeToFit];
NSRect buttonFrame = [fButton frame];
buttonFrame.size.width += 12.0; //sizeToFit sizes a bit too small
buttonFrame.origin.x -= NSWidth(buttonFrame) - oldWidth;
[fButton setFrame: buttonFrame];
[fProgressBar setUsesThreadedAnimation: YES];
[fProgressBar startAnimation: self];
}
@ -77,14 +77,14 @@ BlocklistDownloaderViewController * fBLViewController = nil;
if (expectedSize != NSURLResponseUnknownLength)
{
[fProgressBar setIndeterminate: NO];
NSString * substring = [NSString stringForFilePartialSize: currentSize fullSize: expectedSize];
string = [string stringByAppendingFormat: @" (%@)", substring];
[fProgressBar setDoubleValue: (double)currentSize / expectedSize];
}
else
string = [string stringByAppendingFormat: @" (%@)", [NSString stringForFileSize: currentSize]];
[fTextField setStringValue: string];
}
@ -93,7 +93,7 @@ BlocklistDownloaderViewController * fBLViewController = nil;
//change to indeterminate while processing
[fProgressBar setIndeterminate: YES];
[fProgressBar startAnimation: self];
[fTextField setStringValue: [NSLocalizedString(@"Processing blocklist", "Blocklist -> message") stringByAppendingEllipsis]];
[fButton setEnabled: NO];
}
@ -102,7 +102,7 @@ BlocklistDownloaderViewController * fBLViewController = nil;
{
[NSApp endSheet: fStatusWindow];
[fStatusWindow orderOut: self];
fBLViewController = nil;
[self release];
}
@ -111,14 +111,14 @@ BlocklistDownloaderViewController * fBLViewController = nil;
{
[NSApp endSheet: fStatusWindow];
[fStatusWindow orderOut: self];
NSAlert * alert = [[[NSAlert alloc] init] autorelease];
[alert addButtonWithTitle: NSLocalizedString(@"OK", "Blocklist -> button")];
[alert setMessageText: NSLocalizedString(@"Download of the blocklist failed.", "Blocklist -> message")];
[alert setAlertStyle: NSWarningAlertStyle];
[alert setInformativeText: error];
[alert beginSheetModalForWindow: [fPrefsController window] modalDelegate: self
didEndSelector: @selector(failureSheetClosed:returnCode:contextInfo:) contextInfo: nil];
}
@ -133,25 +133,25 @@ BlocklistDownloaderViewController * fBLViewController = nil;
{
fPrefsController = prefsController;
}
return self;
}
- (void) startDownload
{
//load window and show as sheet
[NSBundle loadNibNamed: @"BlocklistStatusWindow" owner: self];
[[NSBundle mainBundle] loadNibNamed: @"BlocklistStatusWindow" owner: self topLevelObjects: NULL];
BlocklistDownloader * downloader = [BlocklistDownloader downloader];
[downloader setViewController: self]; //do before showing the sheet to ensure it doesn't slide out with placeholder text
[NSApp beginSheet: fStatusWindow modalForWindow: [fPrefsController window] modalDelegate: nil didEndSelector: nil contextInfo: nil];
}
- (void) failureSheetClosed: (NSAlert *) alert returnCode: (NSInteger) code contextInfo: (void *) info
{
[[alert window] orderOut: self];
fBLViewController = nil;
[self release];
}

View File

@ -42,7 +42,7 @@ BlocklistScheduler * fScheduler = nil;
{
if (!fScheduler)
fScheduler = [[BlocklistScheduler alloc] init];
return fScheduler;
}
@ -50,25 +50,25 @@ BlocklistScheduler * fScheduler = nil;
{
if ([BlocklistDownloader isRunning])
return;
[self cancelSchedule];
NSString * blocklistURL;
if (![[NSUserDefaults standardUserDefaults] boolForKey: @"BlocklistNew"]
|| !((blocklistURL = [[NSUserDefaults standardUserDefaults] stringForKey: @"BlocklistURL"]) &&
![blocklistURL isEqualToString: @""])
|| ![[NSUserDefaults standardUserDefaults] boolForKey: @"BlocklistAutoUpdate"])
return;
NSDate * lastUpdateDate = [[NSUserDefaults standardUserDefaults] objectForKey: @"BlocklistNewLastUpdate"];
if (lastUpdateDate)
lastUpdateDate = [lastUpdateDate dateByAddingTimeInterval: FULL_WAIT];
NSDate * closeDate = [NSDate dateWithTimeIntervalSinceNow: SMALL_DELAY];
NSDate * useDate = lastUpdateDate ? [lastUpdateDate laterDate: closeDate] : closeDate;
fTimer = [[NSTimer alloc] initWithFireDate: useDate interval: 0 target: self selector: @selector(runUpdater) userInfo: nil repeats: NO];
//current run loop usually means a second update won't work
NSRunLoop * loop = [NSRunLoop mainRunLoop];
[loop addTimer: fTimer forMode: NSDefaultRunLoopMode];

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="BlocklistDownloaderViewController">

View File

@ -33,7 +33,7 @@ BonjourController * fDefaultController = nil;
dispatch_once(&onceToken, ^{
fDefaultController = [[BonjourController alloc] init];
});
return fDefaultController;
}
@ -51,14 +51,14 @@ BonjourController * fDefaultController = nil;
- (void) startWithPort: (int) port
{
[self stop];
NSMutableString * serviceName = [NSMutableString stringWithFormat: @"Transmission (%@ - %@)", NSUserName(), [[NSHost currentHost] localizedName]];
if ([serviceName length] > BONJOUR_SERVICE_NAME_MAX_LENGTH)
[serviceName deleteCharactersInRange: NSMakeRange(BONJOUR_SERVICE_NAME_MAX_LENGTH, [serviceName length] - BONJOUR_SERVICE_NAME_MAX_LENGTH)];
fService = [[NSNetService alloc] initWithDomain: @"" type: @"_http._tcp." name: serviceName port: port];
[fService setDelegate: self];
[fService publish];
}

View File

@ -34,7 +34,7 @@
NSMenuItem * menuItem = [[NSMenuItem alloc] initWithTitle: [self label] action: [self action] keyEquivalent: @""];
[menuItem setTarget: [self target]];
[menuItem setEnabled: [[self target] validateToolbarItem: self]];
return [menuItem autorelease];
}

434
macosx/CMakeLists.txt Normal file
View File

@ -0,0 +1,434 @@
project(trmac)
find_program(IBTOOL_EXECUTABLE ibtool REQUIRED)
find_program(TIFFUTIL_EXECUTABLE tiffutil REQUIRED)
find_program(INSTALL_NAME_TOOL_EXECUTABLE install_name_tool REQUIRED)
macro(tr_wrap_xib IFILE OFILE)
get_filename_component(twx_nib_dir "${OFILE}" DIRECTORY)
add_custom_command(
OUTPUT ${OFILE}
COMMAND ${CMAKE_COMMAND} -E make_directory ${twx_nib_dir}
COMMAND ${IBTOOL_EXECUTABLE} --compile ${OFILE} ${IFILE}
DEPENDS ${IFILE}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
VERBATIM
)
endmacro()
function(tr_tiff_from_pngs OFILE)
get_filename_component(ODIR "${OFILE}" DIRECTORY)
add_custom_command(
OUTPUT ${OFILE}
COMMAND ${CMAKE_COMMAND} -E make_directory ${ODIR}
COMMAND ${TIFFUTIL_EXECUTABLE} -cathidpicheck ${ARGN} -out ${OFILE}
DEPENDS ${ARGN}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
VERBATIM
)
endfunction()
set(${PROJECT_NAME}_SOURCES
AboutWindowController.m
AddMagnetWindowController.m
AddWindowController.m
BadgeView.m
Badger.m
BlocklistDownloader.m
BlocklistDownloaderViewController.m
BlocklistScheduler.m
BonjourController.m
ButtonToolbarItem.m
ColorTextField.m
Controller.m
CreatorWindowController.m
DragOverlayView.m
DragOverlayWindow.m
ExpandedPathToIconTransformer.m
ExpandedPathToPathTransformer.m
FileListNode.m
FileNameCell.m
FileOutlineController.m
FileOutlineView.m
FilePriorityCell.m
FileRenameSheetController.m
FilterBarController.m
FilterBarView.m
FilterButton.m
GlobalOptionsPopoverViewController.m
GroupToolbarItem.m
GroupsController.m
GroupsPrefsController.m
InfoActivityViewController.m
InfoFileViewController.m
InfoGeneralViewController.m
InfoOptionsViewController.m
InfoPeersViewController.m
InfoTabButtonBack.m
InfoTabButtonCell.m
InfoTextField.m
InfoTrackersViewController.m
InfoWindowController.m
main.m
MessageWindowController.m
NSApplicationAdditions.m
NSImageAdditions.m
NSMutableArrayAdditions.m
NSStringAdditions.m
PeerProgressIndicatorCell.m
PeerTableView.m
PiecesView.m
PortChecker.m
PredicateEditorRowTemplateAny.m
PrefsController.m
PrefsWindow.m
ProgressGradients.m
ShareToolbarItem.m
ShareTorrentFileHelper.m
StatsWindowController.m
StatusBarController.m
StatusBarView.m
ToolbarSegmentedCell.m
Torrent.m
TorrentCell.m
TorrentGroup.m
TorrentTableView.m
TrackerCell.m
TrackerNode.m
TrackerTableView.m
URLSheetWindowController.m
WebSeedTableView.m
)
set(${PROJECT_NAME}_HEADERS
AboutWindowController.h
AddMagnetWindowController.h
AddWindowController.h
BadgeView.h
Badger.h
BlocklistDownloader.h
BlocklistDownloaderViewController.h
BlocklistScheduler.h
BonjourController.h
ButtonToolbarItem.h
ColorTextField.h
Controller.h
CreatorWindowController.h
DragOverlayView.h
DragOverlayWindow.h
ExpandedPathToIconTransformer.h
ExpandedPathToPathTransformer.h
FileListNode.h
FileNameCell.h
FileOutlineController.h
FileOutlineView.h
FilePriorityCell.h
FileRenameSheetController.h
FilterBarController.h
FilterBarView.h
FilterButton.h
GlobalOptionsPopoverViewController.h
GroupToolbarItem.h
GroupsController.h
GroupsPrefsController.h
InfoActivityViewController.h
InfoFileViewController.h
InfoGeneralViewController.h
InfoOptionsViewController.h
InfoPeersViewController.h
InfoTabButtonBack.h
InfoTabButtonCell.h
InfoTextField.h
InfoTrackersViewController.h
InfoViewController.h
InfoWindowController.h
MessageWindowController.h
NSApplicationAdditions.h
NSImageAdditions.h
NSMutableArrayAdditions.h
NSStringAdditions.h
PeerProgressIndicatorCell.h
PeerTableView.h
PiecesView.h
PortChecker.h
PredicateEditorRowTemplateAny.h
PrefsController.h
PrefsWindow.h
ProgressGradients.h
ShareToolbarItem.h
ShareTorrentFileHelper.h
StatsWindowController.h
StatusBarController.h
StatusBarView.h
ToolbarSegmentedCell.h
Torrent.h
TorrentCell.h
TorrentGroup.h
TorrentTableView.h
TrackerCell.h
TrackerNode.h
TrackerTableView.h
URLSheetWindowController.h
WebSeedTableView.h
)
set(${PROJECT_NAME}_XIB_FILES
AboutWindow.xib
BlocklistStatusWindow.xib
FileRenameSheetController.xib
FilterBar.xib
InfoFileView.xib
InfoPeersView.xib
InfoTrackersView.xib
InfoWindow.xib
MessageWindow.xib
StatsWindow.xib
StatusBar.xib
URLSheetWindow.xib
)
set(${PROJECT_NAME}_RESOURCES
Defaults.plist
Credits.rtf
sparkle_dsa_pub.pem
../COPYING
Images/Transmission.icns
Images/TransmissionDocument.icns
)
set_source_files_properties(${${PROJECT_NAME}_RESOURCES} PROPERTIES
MACOSX_PACKAGE_LOCATION Resources
)
set(${PROJECT_NAME}_HIDPI_IMAGES
ActionHover
ActionOn
Bandwidth
CleanupTemplate
CompleteCheck
CreateLarge
DownArrowGroupTemplate
DownArrowTemplate
FavIcon
Globe
Groups
GroupsNoneTemplate
InfoActivity
InfoFiles
InfoGeneral
InfoOptions
InfoPeers
InfoTracker
Lock
Magnet
PauseHover
PauseOff
PauseOn
PinTemplate
PriorityControlHigh
PriorityControlLow
PriorityControlNormal
PriorityHighTemplate
PriorityLowTemplate
PriorityNormalTemplate
PurpleDotFlat
PurpleDotGlossy
RedDotFlat
RedDotGlossy
Remote
ResumeHover
ResumeNoWaitHover
ResumeNoWaitOff
ResumeNoWaitOn
ResumeOff
ResumeOn
RevealHover
RevealOff
RevealOn
ToolbarCreateTemplate
ToolbarFilterTemplate
ToolbarInfoTemplate
ToolbarOpenTemplate
ToolbarOpenWebTemplate
ToolbarPauseAllTemplate
ToolbarPauseSelectedTemplate
ToolbarRemoveTemplate
ToolbarResumeAllTemplate
ToolbarResumeSelectedTemplate
Transfers
TurtleTemplate
UpArrowGroupTemplate
UpArrowTemplate
YellowDotFlat
YellowDotGlossy
YingYangGroupTemplate
YingYangTemplate
)
foreach(IMG ${${PROJECT_NAME}_HIDPI_IMAGES})
set(IMG_DIR "Images/Images.xcassets/${IMG}.imageset")
list(APPEND ${PROJECT_NAME}_RESOURCES ${IMG_DIR}/${IMG}.png ${IMG_DIR}/${IMG}@2x.png)
if(COMBINE_HIDPI_ARTWORK)
list(APPEND ${PROJECT_NAME}_RESOURCES ${PROJECT_BINARY_DIR}/Images/${IMG}.tiff)
tr_tiff_from_pngs(${PROJECT_BINARY_DIR}/Images/${IMG}.tiff ${IMG_DIR}/${IMG}.png ${IMG_DIR}/${IMG}@2x.png)
set_source_files_properties(${PROJECT_BINARY_DIR}/Images/${IMG}.tiff PROPERTIES
MACOSX_PACKAGE_LOCATION Resources
)
else()
set_source_files_properties(${IMG_DIR}/${IMG}.png ${IMG_DIR}/${IMG}@2x.png PROPERTIES
MACOSX_PACKAGE_LOCATION Resources
)
endif()
endforeach()
set(${PROJECT_NAME}_LODPI_IMAGES
DownloadBadge
QuitBadge
UploadBadge
)
foreach(IMG ${${PROJECT_NAME}_LODPI_IMAGES})
set(IMG_DIR "Images/Images.xcassets/${IMG}.imageset")
list(APPEND ${PROJECT_NAME}_RESOURCES ${IMG_DIR}/${IMG}.png)
set_source_files_properties(${IMG_DIR}/${IMG}.png PROPERTIES
MACOSX_PACKAGE_LOCATION Resources
)
endforeach()
set(${PROJECT_NAME}_LINGUAS
da
de
en
es
fr
it
nl
pt_PT
ru
tr
)
if(ENABLE_NLS)
set(${PROJECT_NAME}_ENABLED_LINGUAS ${${PROJECT_NAME}_LINGUAS})
else()
set(${PROJECT_NAME}_ENABLED_LINGUAS en)
endif()
set(${PROJECT_NAME}_LANG_XIB_FILES
AddMagnetWindow.xib
AddWindow.xib
Creator.xib
GlobalOptionsPopover.xib
GroupRules.xib
InfoActivityView.xib
InfoGeneralView.xib
InfoOptionsView.xib
MainMenu.xib
PrefsWindow.xib
)
set(${PROJECT_NAME}_LANG_STRINGS_FILES
InfoPlist.strings
Localizable.strings
)
set(${PROJECT_NAME}_NIB_FILES)
foreach(F ${${PROJECT_NAME}_XIB_FILES})
get_filename_component(F_BASE "${F}" NAME_WE)
set(F_NIB "${PROJECT_BINARY_DIR}/${F_BASE}.nib")
tr_wrap_xib("${F}" "${F_NIB}")
list(APPEND ${PROJECT_NAME}_NIB_FILES "${F_NIB}")
endforeach()
set_source_files_properties(${${PROJECT_NAME}_NIB_FILES} PROPERTIES
MACOSX_PACKAGE_LOCATION Resources)
set(${PROJECT_NAME}_LINGUAS_XIB_FILES)
set(${PROJECT_NAME}_LINGUAS_NIB_FILES)
foreach(LANG ${${PROJECT_NAME}_ENABLED_LINGUAS})
set(${PROJECT_NAME}_${LANG}_NIB_FILES)
foreach(F ${${PROJECT_NAME}_LANG_XIB_FILES})
set(F_XIB "${LANG}.lproj/${F}")
get_filename_component(F_BASE "${F}" NAME_WE)
set(F_NIB "${PROJECT_BINARY_DIR}/${LANG}.lproj/${F_BASE}.nib")
tr_wrap_xib("${F_XIB}" "${F_NIB}")
list(APPEND ${PROJECT_NAME}_LINGUAS_XIB_FILES "${F_XIB}")
list(APPEND ${PROJECT_NAME}_LINGUAS_NIB_FILES "${F_NIB}")
list(APPEND ${PROJECT_NAME}_${LANG}_NIB_FILES "${F_NIB}")
endforeach()
set(${PROJECT_NAME}_${LANG}_STRINGS_FILES)
foreach(F ${${PROJECT_NAME}_LANG_STRINGS_FILES})
list(APPEND ${PROJECT_NAME}_${LANG}_STRINGS_FILES ${LANG}.lproj/${F})
endforeach()
endforeach()
include_directories(
${CMAKE_SOURCE_DIR}/libtransmission
${PROJECT_SOURCE_DIR}/VDKQueue
)
add_definitions(
-Wno-unused-parameter
"-Wno-#warnings"
)
add_library(vdkqueue STATIC
VDKQueue/VDKQueue.m
VDKQueue/VDKQueue.h
)
foreach(LANG ${${PROJECT_NAME}_ENABLED_LINGUAS})
list(APPEND ${PROJECT_NAME}_RESOURCES ${${PROJECT_NAME}_${LANG}_NIB_FILES} ${${PROJECT_NAME}_${LANG}_STRINGS_FILES})
set_source_files_properties(${${PROJECT_NAME}_${LANG}_NIB_FILES} ${${PROJECT_NAME}_${LANG}_STRINGS_FILES} PROPERTIES
MACOSX_PACKAGE_LOCATION Resources/${LANG}.lproj)
endforeach()
add_executable(${TR_NAME}-mac MACOSX_BUNDLE
${${PROJECT_NAME}_SOURCES}
${${PROJECT_NAME}_HEADERS}
${${PROJECT_NAME}_XIB_FILES}
${${PROJECT_NAME}_NIB_FILES}
${${PROJECT_NAME}_LINGUAS_XIB_FILES}
${${PROJECT_NAME}_LINGUAS_NIB_FILES}
${${PROJECT_NAME}_RESOURCES}
)
find_library(GROWL_FRAMEWORK Growl PATHS ${PROJECT_SOURCE_DIR} NO_DEFAULT_PATHS)
find_library(SPARKLE_FRAMEWORK Sparkle PATHS ${PROJECT_SOURCE_DIR} NO_DEFAULT_PATHS)
target_link_libraries(${TR_NAME}-mac
${TR_NAME}
vdkqueue
${GROWL_FRAMEWORK}
${SPARKLE_FRAMEWORK}
"-framework AppKit"
"-framework Carbon"
"-framework Foundation"
"-framework IOKit"
"-framework Quartz"
"-framework Security"
)
set(MAC_BUNDLE_NAME Transmission)
set_target_properties(${TR_NAME}-mac PROPERTIES
OUTPUT_NAME ${MAC_BUNDLE_NAME}
MACOSX_BUNDLE_GUI_IDENTIFIER "org.m0k.transmission"
MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/Info.plist.in
INSTALL_RPATH "@executable_path;@executable_path/../Frameworks"
)
add_subdirectory(QuickLookPlugin)
install(TARGETS ${TR_NAME}-mac DESTINATION Applications)
install(DIRECTORY TransmissionHelp DESTINATION Applications/${MAC_BUNDLE_NAME}.app/Contents/Resources)
tr_install_web(Applications/${MAC_BUNDLE_NAME}.app/Contents/Resources)
install(CODE "
list(APPEND CMAKE_MODULE_PATH \"${CMAKE_SOURCE_DIR}/cmake\")
include(TrMacros)
include(GetPrerequisites)
tr_fixup_bundle_item(\"\$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/Applications/${MAC_BUNDLE_NAME}.app\" \"Contents/MacOS/${MAC_BUNDLE_NAME}\" \"${PROJECT_SOURCE_DIR}\")
")

View File

@ -32,7 +32,7 @@
- (void) setEnabled: (BOOL) flag
{
[super setEnabled: flag];
NSColor * color = flag ? [NSColor controlTextColor] : [NSColor disabledControlTextColor];
[self setTextColor: color];
}

View File

@ -51,61 +51,61 @@ typedef enum
@interface Controller : NSObject <GrowlApplicationBridgeDelegate, NSURLDownloadDelegate, NSUserNotificationCenterDelegate, NSPopoverDelegate, NSSharingServiceDelegate, NSSharingServicePickerDelegate, NSSoundDelegate, NSToolbarDelegate, NSWindowDelegate, QLPreviewPanelDataSource, QLPreviewPanelDelegate, VDKQueueDelegate>
{
tr_session * fLib;
NSMutableArray * fTorrents, * fDisplayedTorrents;
PrefsController * fPrefsController;
InfoWindowController * fInfoController;
MessageWindowController * fMessageController;
NSUserDefaults * fDefaults;
NSString * fConfigDirectory;
IBOutlet NSWindow * fWindow;
DragOverlayWindow * fOverlayWindow;
IBOutlet TorrentTableView * fTableView;
io_connect_t fRootPort;
NSTimer * fTimer;
VDKQueue * fFileWatcherQueue;
IBOutlet NSMenuItem * fOpenIgnoreDownloadFolder;
IBOutlet NSButton * fActionButton, * fSpeedLimitButton, * fClearCompletedButton;
IBOutlet NSTextField * fTotalTorrentsField;
StatusBarController * fStatusBar;
FilterBarController * fFilterBar;
IBOutlet NSMenuItem * fNextFilterItem;
IBOutlet NSMenuItem * fNextInfoTabItem, * fPrevInfoTabItem;
IBOutlet NSMenu * fSortMenu;
IBOutlet NSMenu * fGroupsSetMenu, * fGroupsSetContextMenu;
IBOutlet NSMenu * fShareMenu, * fShareContextMenu;
IBOutlet NSMenuItem * fShareMenuItem, * fShareContextMenuItem; // remove when dropping 10.6
QLPreviewPanel * fPreviewPanel;
BOOL fQuitting;
BOOL fQuitRequested;
BOOL fPauseOnLaunch;
Badger * fBadger;
NSMutableArray * fAutoImportedNames;
NSTimer * fAutoImportTimer;
NSMutableDictionary * fPendingTorrentDownloads;
NSMutableSet * fAddingTransfers;
NSMutableSet * fAddWindows;
URLSheetWindowController * fUrlSheetController;
BOOL fGlobalPopoverShown;
BOOL fSoundPlaying;
}

File diff suppressed because it is too large Load Diff

View File

@ -32,17 +32,17 @@
IBOutlet NSSegmentedControl * fTrackerAddRemoveControl;
IBOutlet NSTextView * fCommentView;
IBOutlet NSButton * fPrivateCheck, * fOpenCheck;
IBOutlet NSView * fProgressView;
IBOutlet NSProgressIndicator * fProgressIndicator;
tr_metainfo_builder * fInfo;
NSURL * fPath, * fLocation;
NSMutableArray * fTrackers;
NSTimer * fTimer;
BOOL fStarted, fOpenWhenCreated;
NSUserDefaults * fDefaults;
}

View File

@ -51,7 +51,7 @@
NSURL * path;
if (!(path = [CreatorWindowController chooseFile]))
return nil;
CreatorWindowController * creator = [[self alloc] initWithHandle: handle path: path];
[creator showWindow: nil];
return creator;
@ -69,10 +69,10 @@
if ((self = [super initWithWindowNibName: @"Creator"]))
{
fStarted = NO;
fPath = [path retain];
fInfo = tr_metaInfoBuilderCreate([[fPath path] UTF8String]);
if (fInfo->fileCount == 0)
{
NSAlert * alert = [[NSAlert alloc] init];
@ -82,10 +82,10 @@
[alert setInformativeText: NSLocalizedString(@"There must be at least one file in a folder to create a torrent file.",
"Create torrent -> no files -> warning")];
[alert setAlertStyle: NSWarningAlertStyle];
[alert runModal];
[alert release];
[self release];
return nil;
}
@ -98,21 +98,21 @@
[alert setInformativeText: NSLocalizedString(@"A torrent file cannot be created for files with no size.",
"Create torrent -> zero size -> warning")];
[alert setAlertStyle: NSWarningAlertStyle];
[alert runModal];
[alert release];
[self release];
return nil;
}
fDefaults = [NSUserDefaults standardUserDefaults];
//get list of trackers
if (!(fTrackers = [[fDefaults arrayForKey: @"CreatorTrackers"] mutableCopy]))
{
fTrackers = [[NSMutableArray alloc] init];
//check for single tracker from versions before 1.3
NSString * tracker;
if ((tracker = [fDefaults stringForKey: @"CreatorTracker"]))
@ -125,7 +125,7 @@
}
}
}
//remove potentially invalid addresses
for (NSInteger i = [fTrackers count]-1; i >= 0; i--)
{
@ -139,21 +139,21 @@
- (void) awakeFromNib
{
[[self window] setRestorationClass: [self class]];
NSString * name = [fPath lastPathComponent];
[[self window] setTitle: name];
[fNameField setStringValue: name];
[fNameField setToolTip: [fPath path]];
const BOOL multifile = fInfo->isFolder;
NSImage * icon = [[NSWorkspace sharedWorkspace] iconForFileType: multifile
? NSFileTypeForHFSTypeCode(kGenericFolderIcon) : [fPath pathExtension]];
[icon setSize: [fIconView frame].size];
[fIconView setImage: icon];
NSString * statusString = [NSString stringForFileSize: fInfo->totalSize];
if (multifile)
{
@ -167,14 +167,14 @@
statusString = [NSString stringWithFormat: @"%@, %@", fileString, statusString];
}
[fStatusField setStringValue: statusString];
if (fInfo->pieceCount == 1)
[fPiecesField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"1 piece, %@", "Create torrent -> info"),
[NSString stringForFileSize: fInfo->pieceSize]]];
else
[fPiecesField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%d pieces, %@ each", "Create torrent -> info"),
fInfo->pieceCount, [NSString stringForFileSize: fInfo->pieceSize]]];
fLocation = [[[fDefaults URLForKey: @"CreatorLocationURL"] URLByAppendingPathComponent: [name stringByAppendingPathExtension: @"torrent"]] retain];
if (!fLocation)
{
@ -184,11 +184,11 @@
fLocation = [[NSURL alloc] initFileURLWithPath: [[location stringByExpandingTildeInPath] stringByAppendingPathComponent: [name stringByAppendingPathExtension: @"torrent"]]];
}
[self updateLocationField];
//set previously saved values
if ([fDefaults objectForKey: @"CreatorPrivate"])
[fPrivateCheck setState: [fDefaults boolForKey: @"CreatorPrivate"] ? NSOnState : NSOffState];
[fOpenCheck setState: [fDefaults boolForKey: @"CreatorOpen"] ? NSOnState : NSOffState];
}
@ -196,15 +196,15 @@
{
[fPath release];
[fLocation release];
[fTrackers release];
if (fInfo)
tr_metaInfoBuilderFree(fInfo);
[fTimer invalidate];
[fTimer release];
[super dealloc];
}
@ -216,7 +216,7 @@
completionHandler(nil, [NSError errorWithDomain: NSURLErrorDomain code: NSURLErrorCannotOpenFile userInfo: nil]);
return;
}
NSWindow * window = [[self createTorrentFile: [(Controller *)[NSApp delegate] sessionHandle] forFile: path] window];
completionHandler(window, nil);
}
@ -236,11 +236,11 @@
[fLocation release];
fLocation = [[coder decodeObjectForKey: @"TRCreatorLocation"] retain];
[self updateLocationField];
[fTrackers release];
fTrackers = [[coder decodeObjectForKey: @"TRCreatorTrackers"] retain];
[fTrackerTable reloadData];
[fOpenCheck setState: [coder decodeIntegerForKey: @"TRCreatorOpenCheck"]];
[fPrivateCheck setState: [coder decodeIntegerForKey: @"TRCreatorPrivateCheck"]];
[fCommentView setString: [coder decodeObjectForKey: @"TRCreatorPrivateComment"]];
@ -252,14 +252,14 @@
[panel setPrompt: NSLocalizedString(@"Select", "Create torrent -> location sheet -> button")];
[panel setMessage: NSLocalizedString(@"Select the name and location for the torrent file.",
"Create torrent -> location sheet -> message")];
"Create torrent -> location sheet -> message")];
[panel setAllowedFileTypes: [NSArray arrayWithObjects: @"org.bittorrent.torrent", @"torrent", nil]];
[panel setCanSelectHiddenExtension: YES];
[panel setDirectoryURL: [fLocation URLByDeletingLastPathComponent]];
[panel setNameFieldStringValue: [fLocation lastPathComponent]];
[panel beginSheetModalForWindow: [self window] completionHandler: ^(NSInteger result) {
if (result == NSFileHandlingPanelOKButton)
{
@ -275,14 +275,14 @@
//make sure the trackers are no longer being verified
if ([fTrackerTable editedRow] != -1)
[[self window] endEditingFor: fTrackerTable];
const BOOL isPrivate = [fPrivateCheck state] == NSOnState;
if ([fTrackers count] == 0
&& [fDefaults boolForKey: isPrivate ? @"WarningCreatorPrivateBlankAddress" : @"WarningCreatorBlankAddress"])
{
NSAlert * alert = [[NSAlert alloc] init];
[alert setMessageText: NSLocalizedString(@"There are no tracker addresses.", "Create torrent -> blank address -> title")];
NSString * infoString = isPrivate
? NSLocalizedString(@"A transfer marked as private with no tracker addresses will be unable to connect to peers."
" The torrent file will only be useful if you plan to upload the file to a tracker website"
@ -290,7 +290,7 @@
: NSLocalizedString(@"The transfer will not contact trackers for peers, and will have to rely solely on"
" non-tracker peer discovery methods such as PEX and DHT to download and seed.",
"Create torrent -> blank address -> message");
[alert setInformativeText: infoString];
[alert addButtonWithTitle: NSLocalizedString(@"Create", "Create torrent -> blank address -> button")];
[alert addButtonWithTitle: NSLocalizedString(@"Cancel", "Create torrent -> blank address -> button")];
@ -334,11 +334,11 @@
//don't allow add/remove when currently adding - it leads to weird results
if ([fTrackerTable editedRow] != -1)
return;
if ([[sender cell] tagForSegment: [sender selectedSegment]] == TRACKER_REMOVE_TAG)
{
[fTrackers removeObjectsAtIndexes: [fTrackerTable selectedRowIndexes]];
[fTrackerTable deselectAll: self];
[fTrackerTable reloadData];
}
@ -346,7 +346,7 @@
{
[fTrackers addObject: @""];
[fTrackerTable reloadData];
const NSInteger row = [fTrackers count] - 1;
[fTrackerTable selectRowIndexes: [NSIndexSet indexSetWithIndex: row] byExtendingSelection: NO];
[fTrackerTable editColumn: 0 row: row withEvent: nil select: YES];
@ -357,12 +357,12 @@
row: (NSInteger) row
{
NSString * tracker = (NSString *)object;
tracker = [tracker stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([tracker rangeOfString: @"://"].location == NSNotFound)
tracker = [@"http://" stringByAppendingString: tracker];
if (!tr_urlIsValidTracker([tracker UTF8String]))
{
NSBeep();
@ -370,7 +370,7 @@
}
else
[fTrackers replaceObjectAtIndex: row withObject: tracker];
[fTrackerTable deselectAll: self];
[fTrackerTable reloadData];
}
@ -384,7 +384,7 @@
{
NSArray * addresses = [fTrackers objectsAtIndexes: [fTrackerTable selectedRowIndexes]];
NSString * text = [addresses componentsJoinedByString: @"\n"];
NSPasteboard * pb = [NSPasteboard generalPasteboard];
[pb clearContents];
[pb writeObjects: [NSArray arrayWithObject: text]];
@ -393,46 +393,46 @@
- (BOOL) validateMenuItem: (NSMenuItem *) menuItem
{
const SEL action = [menuItem action];
if (action == @selector(copy:))
return [[self window] firstResponder] == fTrackerTable && [fTrackerTable numberOfSelectedRows] > 0;
if (action == @selector(paste:))
return [[self window] firstResponder] == fTrackerTable
&& [[NSPasteboard generalPasteboard] canReadObjectForClasses: [NSArray arrayWithObject: [NSString class]] options: nil];
return YES;
}
- (void) paste: (id) sender
{
NSMutableArray * tempTrackers = [NSMutableArray array];
NSArray * items = [[NSPasteboard generalPasteboard] readObjectsForClasses: [NSArray arrayWithObject: [NSString class]] options: nil];
NSAssert(items != nil, @"no string items to paste; should not be able to call this method");
for (NSString * pbItem in items)
{
for (NSString * tracker in [pbItem componentsSeparatedByString: @"\n"])
[tempTrackers addObject: tracker];
}
BOOL added = NO;
for (NSString * tracker in tempTrackers)
{
tracker = [tracker stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([tracker rangeOfString: @"://"].location == NSNotFound)
tracker = [@"http://" stringByAppendingString: tracker];
if (tr_urlIsValidTracker([tracker UTF8String]))
{
[fTrackers addObject: tracker];
added = YES;
}
}
if (added)
{
[fTrackerTable deselectAll: self];
@ -456,7 +456,7 @@
+ (NSURL *) chooseFile
{
NSOpenPanel * panel = [NSOpenPanel openPanel];
[panel setTitle: NSLocalizedString(@"Create Torrent File", "Create torrent -> select file")];
[panel setPrompt: NSLocalizedString(@"Select", "Create torrent -> select file")];
[panel setAllowsMultipleSelection: NO];
@ -465,7 +465,7 @@
[panel setCanCreateDirectories: NO];
[panel setMessage: NSLocalizedString(@"Select a file or folder for the torrent file.", "Create torrent -> select file")];
BOOL success = [panel runModal] == NSOKButton;
return success ? [[panel URLs] objectAtIndex: 0] : nil;
}
@ -478,9 +478,9 @@
if ([fPrivateCheck state] == NSOnState)
[[NSUserDefaults standardUserDefaults] setBool: NO forKey: @"WarningCreatorPrivateBlankAddress"];
}
[alert release];
if (returnCode == NSAlertFirstButtonReturn)
[self performSelectorOnMainThread: @selector(createReal) withObject: nil waitUntilDone: NO];
}
@ -500,17 +500,17 @@
"Create torrent -> directory doesn't exist warning -> warning"),
[[fLocation URLByDeletingLastPathComponent] path]]];
[alert setAlertStyle: NSWarningAlertStyle];
[alert beginSheetModalForWindow: [self window] modalDelegate: self didEndSelector: nil contextInfo: nil];
return;
}
//check if a file with the same name and location already exists
if ([fLocation checkResourceIsReachableAndReturnError: NULL])
{
NSArray * pathComponents = [fLocation pathComponents];
NSInteger count = [pathComponents count];
NSAlert * alert = [[[NSAlert alloc] init] autorelease];
[alert addButtonWithTitle: NSLocalizedString(@"OK", "Create torrent -> file already exists warning -> button")];
[alert setMessageText: NSLocalizedString(@"A torrent file with this name and directory cannot be created.",
@ -521,20 +521,20 @@
"Create torrent -> file already exists warning -> warning"),
[pathComponents objectAtIndex: count-1], [pathComponents objectAtIndex: count-2]]];
[alert setAlertStyle: NSWarningAlertStyle];
[alert beginSheetModalForWindow: [self window] modalDelegate: self didEndSelector: nil contextInfo: nil];
return;
}
//parse non-empty tracker strings
tr_tracker_info * trackerInfo = tr_new0(tr_tracker_info, [fTrackers count]);
for (NSUInteger i = 0; i < [fTrackers count]; i++)
{
trackerInfo[i].announce = (char *)[[fTrackers objectAtIndex: i] UTF8String];
trackerInfo[i].tier = i;
}
//store values
[fDefaults setObject: fTrackers forKey: @"CreatorTrackers"];
[fDefaults setBool: [fPrivateCheck state] == NSOnState forKey: @"CreatorPrivate"];
@ -543,11 +543,11 @@
[fDefaults setURL: [fLocation URLByDeletingLastPathComponent] forKey: @"CreatorLocationURL"];
[[self window] setRestorable: NO];
[[NSNotificationCenter defaultCenter] postNotificationName: @"BeginCreateTorrentFile" object: fLocation userInfo: nil];
tr_makeMetaInfo(fInfo, [[fLocation path] UTF8String], trackerInfo, [fTrackers count], [[fCommentView string] UTF8String], [fPrivateCheck state] == NSOnState);
tr_free(trackerInfo);
fTimer = [[NSTimer scheduledTimerWithTimeInterval: 0.1 target: self selector: @selector(checkProgress) userInfo: nil repeats: YES] retain];
}
@ -558,7 +558,7 @@
[fTimer invalidate];
[fTimer release];
fTimer = nil;
NSAlert * alert;
switch (fInfo->result)
{
@ -569,21 +569,21 @@
[[fPath URLByDeletingLastPathComponent] path], @"Path", nil];
[[NSNotificationCenter defaultCenter] postNotificationName: @"OpenCreatedTorrentFile" object: self userInfo: dict];
}
[[self window] close];
break;
case TR_MAKEMETA_CANCELLED:
[[self window] close];
break;
default:
alert = [[[NSAlert alloc] init] autorelease];
[alert addButtonWithTitle: NSLocalizedString(@"OK", "Create torrent -> failed -> button")];
[alert setMessageText: [NSString stringWithFormat: NSLocalizedString(@"Creation of \"%@\" failed.",
"Create torrent -> failed -> title"), [fLocation lastPathComponent]]];
[alert setAlertStyle: NSWarningAlertStyle];
if (fInfo->result == TR_MAKEMETA_IO_READ)
[alert setInformativeText: [NSString stringWithFormat: NSLocalizedString(@"Could not read \"%s\": %s.",
"Create torrent -> failed -> warning"), fInfo->errfile, strerror(fInfo->my_errno)]];
@ -593,7 +593,7 @@
else //invalid url should have been caught before creating
[alert setInformativeText: [NSString stringWithFormat: @"%@ (%d)",
NSLocalizedString(@"An unknown error has occurred.", "Create torrent -> failed -> warning"), fInfo->result]];
[alert beginSheetModalForWindow: [self window] modalDelegate: self
didEndSelector: @selector(failureSheetClosed:returnCode:contextInfo:) contextInfo: nil];
}
@ -601,30 +601,30 @@
else
{
[fProgressIndicator setDoubleValue: (double)fInfo->pieceIndex / fInfo->pieceCount];
if (!fStarted)
{
fStarted = YES;
[fProgressView setHidden: YES];
NSWindow * window = [self window];
[window setFrameAutosaveName: @""];
NSRect windowRect = [window frame];
CGFloat difference = [fProgressView frame].size.height - [[window contentView] frame].size.height;
windowRect.origin.y -= difference;
windowRect.size.height += difference;
//don't allow vertical resizing
CGFloat height = windowRect.size.height;
[window setMinSize: NSMakeSize([window minSize].width, height)];
[window setMaxSize: NSMakeSize([window maxSize].width, height)];
[window setContentView: fProgressView];
[window setFrame: windowRect display: YES animate: YES];
[fProgressView setHidden: NO];
[[window standardWindowButton: NSWindowCloseButton] setEnabled: NO];
}
}

View File

@ -18,6 +18,8 @@ Lead Developers
\fs24 \cf0 \
Mitchell Livingston, Digital Ignition LLC <{\field{\*\fldinst{HYPERLINK "mailto:livings124@transmissionbt.com"}}{\fldrslt livings124@transmissionbt.com}}>
\fs20 \cf2 (Mac OS X client)
\fs24 \cf0 \
Mike Gelfand <{\field{\*\fldinst{HYPERLINK "mailto:mike@transmissionbt.com"}}{\fldrslt mike@transmissionbt.com}}>
\fs24 \cf0 \
\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\pardirnatural
\cf0 \

View File

@ -25,7 +25,7 @@
@interface DragOverlayView : NSView
{
NSImage * fBadge;
NSDictionary * fMainLineAttributes, * fSubLineAttributes;
}

View File

@ -35,23 +35,23 @@
NSShadow * stringShadow = [[NSShadow alloc] init];
[stringShadow setShadowOffset: NSMakeSize(2.0, -2.0)];
[stringShadow setShadowBlurRadius: 4.0];
NSFont * bigFont = [NSFont boldSystemFontOfSize: 18.0],
* smallFont = [NSFont systemFontOfSize: 14.0];
NSMutableParagraphStyle * paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[paragraphStyle setLineBreakMode: NSLineBreakByTruncatingMiddle];
fMainLineAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSColor whiteColor], NSForegroundColorAttributeName,
bigFont, NSFontAttributeName, stringShadow, NSShadowAttributeName,
paragraphStyle, NSParagraphStyleAttributeName, nil];
fSubLineAttributes = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSColor whiteColor], NSForegroundColorAttributeName,
smallFont, NSFontAttributeName, stringShadow, NSShadowAttributeName,
paragraphStyle, NSParagraphStyleAttributeName, nil];
[stringShadow release];
[paragraphStyle release];
}
@ -61,47 +61,47 @@
- (void) dealloc
{
[fBadge release];
[fMainLineAttributes release];
[fSubLineAttributes release];
[super dealloc];
}
- (void) setOverlay: (NSImage *) icon mainLine: (NSString *) mainLine subLine: (NSString *) subLine
{
[fBadge release];
//create badge
const NSRect badgeRect = NSMakeRect(0.0, 0.0, 325.0, 84.0);
fBadge = [[NSImage alloc] initWithSize: badgeRect.size];
[fBadge lockFocus];
NSBezierPath * bp = [NSBezierPath bezierPathWithRoundedRect: badgeRect xRadius: 15.0 yRadius: 15.0];
[[NSColor colorWithCalibratedWhite: 0.0 alpha: 0.75] set];
[bp fill];
//place icon
[icon drawInRect: NSMakeRect(PADDING, (NSHeight(badgeRect) - ICON_WIDTH) * 0.5, ICON_WIDTH, ICON_WIDTH) fromRect: NSZeroRect
operation: NSCompositeSourceOver fraction: 1.0];
//place main text
const NSSize mainLineSize = [mainLine sizeWithAttributes: fMainLineAttributes];
const NSSize subLineSize = [subLine sizeWithAttributes: fSubLineAttributes];
NSRect lineRect = NSMakeRect(PADDING + ICON_WIDTH + 5.0,
(NSHeight(badgeRect) + (subLineSize.height + 2.0 - mainLineSize.height)) * 0.5,
NSWidth(badgeRect) - (PADDING + ICON_WIDTH + 2.0) - PADDING, mainLineSize.height);
[mainLine drawInRect: lineRect withAttributes: fMainLineAttributes];
//place sub text
lineRect.origin.y -= subLineSize.height + 2.0;
lineRect.size.height = subLineSize.height;
[subLine drawInRect: lineRect withAttributes: fSubLineAttributes];
[fBadge unlockFocus];
[self setNeedsDisplay: YES];
}

View File

@ -26,7 +26,7 @@
@interface DragOverlayWindow : NSWindow
{
tr_session * fLib;
NSViewAnimation * fFadeInAnimation, * fFadeOutAnimation;
}

View File

@ -38,33 +38,33 @@
backing: NSBackingStoreBuffered defer: NO])))
{
fLib = lib;
[self setBackgroundColor: [NSColor colorWithCalibratedWhite: 0.0 alpha: 0.5]];
[self setAlphaValue: 0.0];
[self setOpaque: NO];
[self setHasShadow: NO];
DragOverlayView * view = [[DragOverlayView alloc] initWithFrame: [self frame]];
[self setContentView: view];
[view release];
[self setReleasedWhenClosed: NO];
[self setIgnoresMouseEvents: YES];
fFadeInAnimation = [[NSViewAnimation alloc] initWithViewAnimations: [NSArray arrayWithObject:
[NSDictionary dictionaryWithObjectsAndKeys: self, NSViewAnimationTargetKey,
NSViewAnimationFadeInEffect, NSViewAnimationEffectKey, nil]]];
[fFadeInAnimation setDuration: 0.15];
[fFadeInAnimation setAnimationBlockingMode: NSAnimationNonblockingThreaded];
fFadeOutAnimation = [[NSViewAnimation alloc] initWithViewAnimations: [NSArray arrayWithObject:
[NSDictionary dictionaryWithObjectsAndKeys: self, NSViewAnimationTargetKey,
NSViewAnimationFadeOutEffect, NSViewAnimationEffectKey, nil]]];
[fFadeOutAnimation setDuration: 0.5];
[fFadeOutAnimation setAnimationBlockingMode: NSAnimationNonblockingThreaded];
[window addChildWindow: self ordered: NSWindowAbove];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(resizeWindow)
name: NSWindowDidResizeNotification object: window];
}
@ -74,10 +74,10 @@
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
[fFadeInAnimation release];
[fFadeOutAnimation release];
[super dealloc];
}
@ -85,11 +85,11 @@
{
uint64_t size = 0;
NSInteger count = 0;
NSString * name;
BOOL folder;
NSInteger fileCount = 0;
for (NSString * file in files)
{
if ([[[NSWorkspace sharedWorkspace] typeOfFile: file error: NULL] isEqualToString: @"org.bittorrent.torrent"]
@ -103,7 +103,7 @@
count++;
size += info.totalSize;
fileCount += info.fileCount;
//only useful when one torrent
if (count == 1)
{
@ -115,10 +115,10 @@
tr_ctorFree(ctor);
}
}
if (count <= 0)
return;
//set strings and icon
NSString * secondString = [NSString stringForFileSize: size];
if (count > 1 || folder)
@ -131,7 +131,7 @@
[NSString formattedUInteger: fileCount]];
secondString = [NSString stringWithFormat: @"%@, %@", fileString, secondString];
}
NSImage * icon;
if (count == 1)
icon = [[NSWorkspace sharedWorkspace] iconForFileType: folder ? NSFileTypeForHFSTypeCode(kGenericFolderIcon) : [name pathExtension]];
@ -142,7 +142,7 @@
secondString = [secondString stringByAppendingString: @" total"];
icon = [NSImage imageNamed: @"TransmissionDocument.icns"];
}
[[self contentView] setOverlay: icon mainLine: name subLine: secondString];
[self fadeIn];
}

View File

@ -20,6 +20,8 @@
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#import <AppKit/AppKit.h>
#import "ExpandedPathToIconTransformer.h"
@implementation ExpandedPathToIconTransformer
@ -38,7 +40,7 @@
{
if (!value)
return nil;
NSString * path = [value stringByExpandingTildeInPath];
NSImage * icon;
//show a folder icon if the folder doesn't exist
@ -46,9 +48,9 @@
icon = [[NSWorkspace sharedWorkspace] iconForFileType: NSFileTypeForHFSTypeCode(kGenericFolderIcon)];
else
icon = [[NSWorkspace sharedWorkspace] iconForFile: path];
[icon setSize: NSMakeSize(16.0, 16.0)];
return icon;
}

View File

@ -27,7 +27,7 @@
@interface FileListNode : NSObject <NSCopying>
{
NSMutableIndexSet * fIndexes;
NSString * fName;
NSString * fPath;
Torrent * fTorrent;

View File

@ -47,7 +47,7 @@
fChildren = [[NSMutableArray alloc] init];
fSize = 0;
}
return self;
}
@ -58,21 +58,21 @@
fSize = size;
[fIndexes addIndex: index];
}
return self;
}
- (void) insertChild: (FileListNode *) child
{
NSAssert(fIsFolder, @"method can only be invoked on folders");
[fChildren addObject: child];
}
- (void) insertIndex: (NSUInteger) index withSize: (uint64_t) size
{
NSAssert(fIsFolder, @"method can only be invoked on folders");
[fIndexes addIndex: index];
fSize += size;
}
@ -112,7 +112,7 @@
- (NSMutableArray *) children
{
NSAssert(fIsFolder, @"method can only be invoked on folders");
return fChildren;
}
@ -121,10 +121,10 @@
NSParameterAssert(oldName != nil);
NSParameterAssert(newName != nil);
NSParameterAssert(path != nil);
NSArray * lookupPathComponents = [path pathComponents];
NSArray * thesePathComponents = [self.path pathComponents];
if ([lookupPathComponents isEqualToArray: thesePathComponents]) //this node represents what's being renamed
{
if ([oldName isEqualToString: self.name])
@ -140,18 +140,18 @@
const BOOL allSame = NSNotFound == [lookupPathComponents indexOfObjectWithOptions: NSEnumerationConcurrent passingTest: ^BOOL(NSString * name, NSUInteger idx, BOOL * stop) {
return ![name isEqualToString: [thesePathComponents objectAtIndex: idx]];
}];
if (allSame)
{
NSString * oldPathPrefix = [path stringByAppendingPathComponent: oldName];
NSString * newPathPrefix = [path stringByAppendingPathComponent: newName];
[fPath autorelease];
fPath = [[fPath stringByReplacingCharactersInRange: NSMakeRange(0, [oldPathPrefix length]) withString: newPathPrefix] retain];
return YES;
}
}
return NO;
}
@ -166,12 +166,12 @@
fIsFolder = isFolder;
fName = [name copy];
fPath = [path copy];
fIndexes = [[NSMutableIndexSet alloc] init];
fTorrent = torrent;
}
return self;
}

View File

@ -56,18 +56,18 @@
{
NSMutableParagraphStyle * paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[paragraphStyle setLineBreakMode: NSLineBreakByTruncatingMiddle];
fTitleAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
[NSFont messageFontOfSize: 12.0], NSFontAttributeName,
paragraphStyle, NSParagraphStyleAttributeName, nil];
NSMutableParagraphStyle * statusParagraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[statusParagraphStyle setLineBreakMode: NSLineBreakByTruncatingTail];
fStatusAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
[NSFont messageFontOfSize: 9.0], NSFontAttributeName,
statusParagraphStyle, NSParagraphStyleAttributeName, nil];
[paragraphStyle release];
[statusParagraphStyle release];
}
@ -78,17 +78,17 @@
{
[fTitleAttributes release];
[fStatusAttributes release];
[super dealloc];
}
- (id) copyWithZone: (NSZone *) zone
{
FileNameCell * copy = [super copyWithZone: zone];
copy->fTitleAttributes = [fTitleAttributes retain];
copy->fStatusAttributes = [fStatusAttributes retain];
return copy;
}
@ -101,13 +101,13 @@
- (NSRect) imageRectForBounds: (NSRect) bounds
{
NSRect result = bounds;
result.origin.x += PADDING_HORIZONAL;
const CGFloat IMAGE_SIZE = [(FileListNode *)[self objectValue] isFolder] ? IMAGE_FOLDER_SIZE : IMAGE_ICON_SIZE;
result.origin.y += (result.size.height - IMAGE_SIZE) * 0.5;
result.size = NSMakeSize(IMAGE_SIZE, IMAGE_SIZE);
return result;
}
@ -115,7 +115,7 @@
{
//icon
[[self image] drawInRect: [self imageRectForBounds: cellFrame] fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0 respectFlipped: YES hints: nil];
NSColor * titleColor, * statusColor;
if ([self backgroundStyle] == NSBackgroundStyleDark)
titleColor = statusColor = [NSColor whiteColor];
@ -126,15 +126,15 @@
titleColor = [NSColor controlTextColor];
statusColor = [NSColor darkGrayColor];
}
[fTitleAttributes setObject: titleColor forKey: NSForegroundColorAttributeName];
[fStatusAttributes setObject: statusColor forKey: NSForegroundColorAttributeName];
//title
NSAttributedString * titleString = [self attributedTitle];
NSRect titleRect = [self rectForTitleWithString: titleString inBounds: cellFrame];
[titleString drawInRect: titleRect];
//status
NSAttributedString * statusString = [self attributedStatus];
NSRect statusRect = [self rectForStatusWithString: statusString withTitleRect: titleRect inBounds: cellFrame];
@ -145,14 +145,14 @@
{
NSAttributedString * titleString = [self attributedTitle];
NSRect realRect = [self rectForTitleWithString: titleString inBounds: cellFrame];
if ([titleString size].width > NSWidth(realRect)
&& NSMouseInRect([view convertPoint: [[view window] mouseLocationOutsideOfEventStream] fromView: nil], realRect, [view isFlipped]))
{
realRect.size.width = [titleString size].width;
return NSInsetRect(realRect, -PADDING_EXPANSION_FRAME, -PADDING_EXPANSION_FRAME);
}
return NSZeroRect;
}
@ -160,7 +160,7 @@
{
cellFrame.origin.x += PADDING_EXPANSION_FRAME;
cellFrame.origin.y += PADDING_EXPANSION_FRAME;
[fTitleAttributes setObject: [NSColor controlTextColor] forKey: NSForegroundColorAttributeName];
NSAttributedString * titleString = [self attributedTitle];
[titleString drawInRect: cellFrame];
@ -173,7 +173,7 @@
- (NSRect) rectForTitleWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
{
const NSSize titleSize = [string size];
//no right padding, so that there's not too much space between this and the priority image
NSRect result;
if (![(FileListNode *)[self objectValue] isFolder])
@ -189,14 +189,14 @@
result.size.width = MIN(titleSize.width, NSMaxX(bounds) - NSMinX(result));
}
result.size.height = titleSize.height;
return result;
}
- (NSRect) rectForStatusWithString: (NSAttributedString *) string withTitleRect: (NSRect) titleRect inBounds: (NSRect) bounds;
- (NSRect) rectForStatusWithString: (NSAttributedString *) string withTitleRect: (NSRect) titleRect inBounds: (NSRect) bounds
{
const NSSize statusSize = [string size];
NSRect result;
if (![(FileListNode *)[self objectValue] isFolder])
{
@ -211,7 +211,7 @@
result.size.width = NSMaxX(bounds) - NSMaxX(titleRect);
}
result.size.height = statusSize.height;
return result;
}
@ -225,13 +225,13 @@
{
FileListNode * node = (FileListNode *)[self objectValue];
Torrent * torrent = [node torrent];
const CGFloat progress = [torrent fileProgress: node];
NSString * percentString = [NSString percentString: progress longDecimals: YES];
NSString * status = [NSString stringWithFormat: NSLocalizedString(@"%@ of %@",
"Inspector -> Files tab -> file status string"), percentString, [NSString stringForFileSize: [node size]]];
return [[[NSAttributedString alloc] initWithString: status attributes: fStatusAttributes] autorelease];
}

View File

@ -29,9 +29,9 @@
{
Torrent * fTorrent;
NSMutableArray * fFileList;
IBOutlet FileOutlineView * fOutline;
NSString * fFilterText;
}

View File

@ -59,16 +59,16 @@ typedef enum
- (void) awakeFromNib
{
fFileList = [[NSMutableArray alloc] init];
[fOutline setDoubleAction: @selector(revealFile:)];
[fOutline setTarget: self];
//set table header tool tips
[[fOutline tableColumnWithIdentifier: @"Check"] setHeaderToolTip: NSLocalizedString(@"Download", "file table -> header tool tip")];
[[fOutline tableColumnWithIdentifier: @"Priority"] setHeaderToolTip: NSLocalizedString(@"Priority", "file table -> header tool tip")];
[fOutline setMenu: [self menu]];
[self setTorrent: nil];
}
@ -76,7 +76,7 @@ typedef enum
{
[fFileList release];
[fFilterText release];
[super dealloc];
}
@ -88,12 +88,12 @@ typedef enum
- (void) setTorrent: (Torrent *) torrent
{
fTorrent = torrent;
[fFileList setArray: [fTorrent fileList]];
[fFilterText release];
fFilterText = nil;
[fOutline reloadData];
[fOutline deselectAll: nil]; //do this after reloading the data #4575
}
@ -106,18 +106,18 @@ typedef enum
text = nil;
components = nil;
}
if ((!text && !fFilterText) || (text && fFilterText && [text isEqualToString: fFilterText]))
return;
[fOutline beginUpdates];
NSUInteger currentIndex = 0, totalCount = 0;
NSMutableArray * itemsToAdd = [NSMutableArray array];
NSMutableIndexSet * itemsToAddIndexes = [NSMutableIndexSet indexSet];
NSMutableDictionary * removedIndexesForParents = nil; //ugly, but we can't modify the actual file nodes
NSArray * tempList = !text ? [fTorrent fileList] : [fTorrent flatFileList];
for (FileListNode * item in tempList)
{
@ -132,12 +132,12 @@ typedef enum
}
}];
}
if (!filter)
{
FileListNode * parent = nil;
NSUInteger previousIndex = ![item isFolder] ? [self findFileNode: item inList: fFileList atIndexes: [NSIndexSet indexSetWithIndexesInRange: NSMakeRange(currentIndex, [fFileList count]-currentIndex)] currentParent: nil finalParent: &parent] : NSNotFound;
if (previousIndex == NSNotFound)
{
[itemsToAdd addObject: item];
@ -156,11 +156,11 @@ typedef enum
else
{
[fFileList insertObject: item atIndex: currentIndex];
//figure out the index within the semi-edited table - UGLY
if (!removedIndexesForParents)
removedIndexesForParents = [NSMutableDictionary dictionary];
NSMutableIndexSet * removedIndexes = [removedIndexesForParents objectForKey: parent];
if (!removedIndexes)
{
@ -173,17 +173,17 @@ typedef enum
previousIndex -= [removedIndexes countOfIndexesInRange: NSMakeRange(0, previousIndex)];
}
}
if (move)
[fOutline moveItemAtIndex: previousIndex inParent: parent toIndex: currentIndex inParent: nil];
++currentIndex;
}
++totalCount;
}
}
//remove trailing items - those are the unused
if (currentIndex < [fFileList count])
{
@ -191,13 +191,13 @@ typedef enum
[fFileList removeObjectsInRange: removeRange];
[fOutline removeItemsAtIndexes: [NSIndexSet indexSetWithIndexesInRange: removeRange] inParent: nil withAnimation: NSTableViewAnimationSlideDown];
}
//add new items
[fFileList insertObjects: itemsToAdd atIndexes: itemsToAddIndexes];
[fOutline insertItemsAtIndexes: itemsToAddIndexes inParent: nil withAnimation: NSTableViewAnimationSlideUp];
[fOutline endUpdates];
[fFilterText release];
fFilterText = [text retain];
}
@ -205,7 +205,7 @@ typedef enum
- (void) refresh
{
[fTorrent updateFileStat];
[fOutline setNeedsDisplay: YES];
}
@ -226,7 +226,7 @@ typedef enum
}
}
- (BOOL) outlineView: (NSOutlineView *) outlineView isItemExpandable: (id) item
- (BOOL) outlineView: (NSOutlineView *) outlineView isItemExpandable: (id) item
{
return [(FileListNode *)item isFolder];
}
@ -252,7 +252,7 @@ typedef enum
else if ([identifier isEqualToString: @"Priority"])
{
[cell setRepresentedObject: item];
NSInteger hoveredRow = [fOutline hoveredRow];
[(FilePriorityCell *)cell setHovered: hoveredRow != -1 && hoveredRow == [fOutline rowForItem: item]];
}
@ -269,10 +269,10 @@ typedef enum
indexSet = [NSIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [fTorrent fileCount])];
else
indexSet = [(FileListNode *)item indexes];
[fTorrent setFileCheckState: [object intValue] != NSOffState ? NSOnState : NSOffState forIndexes: indexSet];
[fOutline setNeedsDisplay: YES];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
}
}
@ -328,7 +328,7 @@ typedef enum
}
}
else;
return nil;
}
@ -343,12 +343,12 @@ typedef enum
- (void) setCheck: (id) sender
{
NSInteger state = [sender tag] == FILE_UNCHECK_TAG ? NSOffState : NSOnState;
NSIndexSet * indexSet = [fOutline selectedRowIndexes];
NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
[itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
[fTorrent setFileCheckState: state forIndexes: itemIndexes];
[fOutline setNeedsDisplay: YES];
}
@ -359,13 +359,13 @@ typedef enum
NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
[itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
[fTorrent setFileCheckState: NSOnState forIndexes: itemIndexes];
NSMutableIndexSet * remainingItemIndexes = [NSMutableIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [fTorrent fileCount])];
[remainingItemIndexes removeIndexes: itemIndexes];
[fTorrent setFileCheckState: NSOffState forIndexes: remainingItemIndexes];
[fOutline setNeedsDisplay: YES];
}
@ -397,12 +397,12 @@ typedef enum
case FILE_PRIORITY_LOW_TAG:
priority = TR_PRI_LOW;
}
NSIndexSet * indexSet = [fOutline selectedRowIndexes];
NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
[itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
[fTorrent setFilePriority: priority forIndexes: itemIndexes];
[fOutline setNeedsDisplay: YES];
}
@ -417,7 +417,7 @@ typedef enum
if (path)
[paths addObject: [NSURL fileURLWithPath: path]];
}
if ([paths count] > 0)
[[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs: paths];
}
@ -426,7 +426,7 @@ typedef enum
{
NSIndexSet * indexes = [fOutline selectedRowIndexes];
NSAssert([indexes count] == 1, @"1 file needs to be selected to rename, but %ld are selected", [indexes count]);
FileListNode * node = [fOutline itemAtRow: [indexes firstIndex]];
Torrent * torrent = [node torrent];
if (![torrent isFolder])
@ -454,9 +454,9 @@ typedef enum
{
if (!fTorrent)
return NO;
SEL action = [menuItem action];
if (action == @selector(revealFile:))
{
NSIndexSet * indexSet = [fOutline selectedRowIndexes];
@ -465,34 +465,34 @@ typedef enum
return YES;
return NO;
}
if (action == @selector(setCheck:))
{
if ([fOutline numberOfSelectedRows] == 0)
return NO;
NSIndexSet * indexSet = [fOutline selectedRowIndexes];
NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
[itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
NSInteger state = ([menuItem tag] == FILE_CHECK_TAG) ? NSOnState : NSOffState;
return [fTorrent checkForFiles: itemIndexes] != state && [fTorrent canChangeDownloadCheckForFiles: itemIndexes];
}
if (action == @selector(setOnlySelectedCheck:))
{
if ([fOutline numberOfSelectedRows] == 0)
return NO;
NSIndexSet * indexSet = [fOutline selectedRowIndexes];
NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
[itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
return [fTorrent canChangeDownloadCheckForFiles: itemIndexes];
}
if (action == @selector(setPriority:))
{
if ([fOutline numberOfSelectedRows] == 0)
@ -500,7 +500,7 @@ typedef enum
[menuItem setState: NSOffState];
return NO;
}
//determine which priorities are checked
NSIndexSet * indexSet = [fOutline selectedRowIndexes];
tr_priority_t priority;
@ -516,14 +516,14 @@ typedef enum
priority = TR_PRI_LOW;
break;
}
BOOL current = NO, canChange = NO;
for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
{
NSIndexSet * fileIndexSet = [[fOutline itemAtRow: i] indexes];
if (![fTorrent canChangeDownloadCheckForFiles: fileIndexSet])
continue;
canChange = YES;
if ([fTorrent hasFilePriority: priority forIndexes: fileIndexSet])
{
@ -531,16 +531,16 @@ typedef enum
break;
}
}
[menuItem setState: current ? NSOnState : NSOffState];
return canChange;
}
if (action == @selector(renameSelected:))
{
return [fOutline numberOfSelectedRows] == 1;
}
return YES;
}
@ -551,7 +551,7 @@ typedef enum
- (NSMenu *) menu
{
NSMenu * menu = [[NSMenu alloc] initWithTitle: @"File Outline Menu"];
//check and uncheck
NSMenuItem * item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Check Selected", "File Outline -> Menu")
action: @selector(setCheck:) keyEquivalent: @""];
@ -559,30 +559,30 @@ typedef enum
[item setTag: FILE_CHECK_TAG];
[menu addItem: item];
[item release];
item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Uncheck Selected", "File Outline -> Menu")
action: @selector(setCheck:) keyEquivalent: @""];
[item setTarget: self];
[item setTag: FILE_UNCHECK_TAG];
[menu addItem: item];
[item release];
//only check selected
item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Only Check Selected", "File Outline -> Menu")
action: @selector(setOnlySelectedCheck:) keyEquivalent: @""];
[item setTarget: self];
[menu addItem: item];
[item release];
[menu addItem: [NSMenuItem separatorItem]];
//priority
item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Priority", "File Outline -> Menu") action: NULL keyEquivalent: @""];
NSMenu * priorityMenu = [[NSMenu alloc] initWithTitle: @"File Priority Menu"];
[item setSubmenu: priorityMenu];
[menu addItem: item];
[item release];
item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"High", "File Outline -> Priority Menu")
action: @selector(setPriority:) keyEquivalent: @""];
[item setTarget: self];
@ -590,7 +590,7 @@ typedef enum
[item setImage: [NSImage imageNamed: @"PriorityHighTemplate"]];
[priorityMenu addItem: item];
[item release];
item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Normal", "File Outline -> Priority Menu")
action: @selector(setPriority:) keyEquivalent: @""];
[item setTarget: self];
@ -598,7 +598,7 @@ typedef enum
[item setImage: [NSImage imageNamed: @"PriorityNormalTemplate"]];
[priorityMenu addItem: item];
[item release];
item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Low", "File Outline -> Priority Menu")
action: @selector(setPriority:) keyEquivalent: @""];
[item setTarget: self];
@ -606,43 +606,43 @@ typedef enum
[item setImage: [NSImage imageNamed: @"PriorityLowTemplate"]];
[priorityMenu addItem: item];
[item release];
[priorityMenu release];
[menu addItem: [NSMenuItem separatorItem]];
//reveal in finder
item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Show in Finder", "File Outline -> Menu")
action: @selector(revealFile:) keyEquivalent: @""];
[item setTarget: self];
[menu addItem: item];
[item release];
[menu addItem: [NSMenuItem separatorItem]];
//rename
item = [[NSMenuItem alloc] initWithTitle: [NSLocalizedString(@"Rename File", "File Outline -> Menu") stringByAppendingEllipsis]
action: @selector(renameSelected:) keyEquivalent: @""];
[item setTarget: self];
[menu addItem: item];
[item release];
return [menu autorelease];
}
- (NSUInteger) findFileNode: (FileListNode *) node inList: (NSArray *) list atIndexes: (NSIndexSet *) indexes currentParent: (FileListNode *) currentParent finalParent: (FileListNode **) parent
{
NSAssert(![node isFolder], @"Looking up folder node!");
__block NSUInteger retIndex = NSNotFound;
[list enumerateObjectsAtIndexes: indexes options: NSEnumerationConcurrent usingBlock: ^(id checkNode, NSUInteger index, BOOL * stop) {
if ([[checkNode indexes] containsIndex: [[node indexes] firstIndex]])
{
if (![checkNode isFolder])
{
NSAssert2([checkNode isEqualTo: node], @"Expected file nodes to be equal: %@ %@", checkNode, node);
*parent = currentParent;
retIndex = index;
}
@ -652,11 +652,11 @@ typedef enum
NSAssert(subIndex != NSNotFound, @"We didn't find an expected file node.");
retIndex = subIndex;
}
*stop = YES;
}
}];
return retIndex;
}

View File

@ -34,14 +34,14 @@
FileNameCell * nameCell = [[FileNameCell alloc] init];
[[self tableColumnWithIdentifier: @"Name"] setDataCell: nameCell];
[nameCell release];
FilePriorityCell * priorityCell = [[FilePriorityCell alloc] init];
[[self tableColumnWithIdentifier: @"Priority"] setDataCell: priorityCell];
[priorityCell release];
[self setAutoresizesOutlineColumn: NO];
[self setIndentationPerLevel: 14.0];
fMouseRow = -1;
}
@ -59,7 +59,7 @@
- (NSMenu *) menuForEvent: (NSEvent *) event
{
const NSInteger row = [self rowAtPoint: [self convertPoint: [event locationInWindow] fromView: nil]];
if (row >= 0)
{
if (![self isRowSelected: row])
@ -67,7 +67,7 @@
}
else
[self deselectAll: self];
return [self menu];
}
@ -75,7 +75,7 @@
{
FileNameCell * cell = (FileNameCell *)[self preparedCellAtColumn: [self columnWithIdentifier: @"Name"] row: row];
NSRect iconRect = [cell imageRectForBounds: [self rectOfRow: row]];
iconRect.origin.x += [self indentationPerLevel] * (CGFloat)([self levelForRow: row] + 1);
return iconRect;
}
@ -83,23 +83,23 @@
- (void) updateTrackingAreas
{
[super updateTrackingAreas];
for (NSTrackingArea * area in [self trackingAreas])
{
if ([area owner] == self && [[area userInfo] objectForKey: @"Row"])
[self removeTrackingArea: area];
}
NSRange visibleRows = [self rowsInRect: [self visibleRect]];
if (visibleRows.length == 0)
return;
NSPoint mouseLocation = [self convertPoint: [[self window] mouseLocationOutsideOfEventStream] fromView: nil];
for (NSInteger row = visibleRows.location, col = [self columnWithIdentifier: @"Priority"]; row < NSMaxRange(visibleRows); row++)
for (NSInteger row = visibleRows.location, col = [self columnWithIdentifier: @"Priority"]; (NSUInteger)row < NSMaxRange(visibleRows); row++)
{
FilePriorityCell * cell = (FilePriorityCell *)[self preparedCellAtColumn: col row: row];
NSDictionary * userInfo = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: row] forKey: @"Row"];
[cell addTrackingAreasForView: self inRect: [self frameOfCellAtColumn: col row: row] withUserInfo: userInfo
mouseLocation: mouseLocation];

View File

@ -37,17 +37,17 @@
[self setTrackingMode: NSSegmentSwitchTrackingSelectAny];
[self setControlSize: NSMiniControlSize];
[self setSegmentCount: 3];
for (NSInteger i = 0; i < [self segmentCount]; i++)
{
[self setLabel: @"" forSegment: i];
[self setWidth: 9.0f forSegment: i]; //9 is minimum size to get proper look
}
[self setImage: [NSImage imageNamed: @"PriorityControlLow"] forSegment: 0];
[self setImage: [NSImage imageNamed: @"PriorityControlNormal"] forSegment: 1];
[self setImage: [NSImage imageNamed: @"PriorityControlHigh"] forSegment: 2];
fHoverRow = NO;
}
return self;
@ -63,7 +63,7 @@
- (void) setSelected: (BOOL) flag forSegment: (NSInteger) segment
{
[super setSelected: flag forSegment: segment];
//only for when clicking manually
NSInteger priority;
switch (segment)
@ -78,10 +78,10 @@
priority = TR_PRI_HIGH;
break;
}
Torrent * torrent = [(FileListNode *)[self representedObject] torrent];
[torrent setFilePriority: priority forIndexes: [(FileListNode *)[self representedObject] indexes]];
FileOutlineView * controlView = (FileOutlineView *)[self controlView];
[controlView setNeedsDisplay: YES];
}
@ -90,13 +90,13 @@
mouseLocation: (NSPoint) mouseLocation
{
NSTrackingAreaOptions options = NSTrackingEnabledDuringMouseDrag | NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways;
if (NSMouseInRect(mouseLocation, cellFrame, [controlView isFlipped]))
{
options |= NSTrackingAssumeInside;
[controlView setNeedsDisplayInRect: cellFrame];
}
NSTrackingArea * area = [[NSTrackingArea alloc] initWithRect: cellFrame options: options owner: controlView userInfo: userInfo];
[controlView addTrackingArea: area];
[area release];
@ -112,21 +112,21 @@
FileListNode * node = [self representedObject];
Torrent * torrent = [node torrent];
NSSet * priorities = [torrent filePrioritiesForIndexes: [node indexes]];
const NSUInteger count = [priorities count];
if (fHoverRow && count > 0)
{
[super setSelected: [priorities containsObject: [NSNumber numberWithInteger: TR_PRI_LOW]] forSegment: 0];
[super setSelected: [priorities containsObject: [NSNumber numberWithInteger: TR_PRI_NORMAL]] forSegment: 1];
[super setSelected: [priorities containsObject: [NSNumber numberWithInteger: TR_PRI_HIGH]] forSegment: 2];
[super drawWithFrame: cellFrame inView: controlView];
}
else
{
NSMutableArray * images = [NSMutableArray arrayWithCapacity: MAX(count, 1)];
NSMutableArray * images = [NSMutableArray arrayWithCapacity: MAX(count, 1u)];
CGFloat totalWidth;
if (count == 0)
{
//if ([self backgroundStyle] != NSBackgroundStyleDark)
@ -139,7 +139,7 @@
else
{
NSColor * priorityColor = [self backgroundStyle] == NSBackgroundStyleDark ? [NSColor whiteColor] : [NSColor darkGrayColor];
totalWidth = 0.0;
if ([priorities containsObject: [NSNumber numberWithInteger: TR_PRI_LOW]])
{
@ -160,19 +160,19 @@
totalWidth += [image size].width;
}
}
if (count > 1)
totalWidth -= IMAGE_OVERLAP * (count-1);
CGFloat currentWidth = floor(NSMidX(cellFrame) - totalWidth * 0.5);
for (NSImage * image in images)
{
const NSSize imageSize = [image size];
const NSRect imageRect = NSMakeRect(currentWidth, floor(NSMidY(cellFrame) - imageSize.height * 0.5), imageSize.width, imageSize.height);
[image drawInRect: imageRect fromRect: NSZeroRect operation: NSCompositeSourceOver fraction: 1.0 respectFlipped: YES hints: nil];
currentWidth += imageSize.width - IMAGE_OVERLAP;
}
}

View File

@ -17,7 +17,7 @@
FileListNode * _node;
void (^_completionHandler)(BOOL);
NSString * _originalName;
IBOutlet NSTextField * _labelField;
IBOutlet NSTextField * _inputField;
IBOutlet NSButton * _renameButton;

View File

@ -38,12 +38,12 @@ typedef void (^CompletionBlock)(BOOL);
{
NSParameterAssert(torrent != nil);
NSParameterAssert(window != nil);
FileRenameSheetController * renamer = [[FileRenameSheetController alloc] initWithWindowNibName: @"FileRenameSheetController"];
renamer.torrent = torrent;
renamer.completionHandler = completionHandler;
[NSApp beginSheet: [renamer window] modalForWindow: window modalDelegate: self didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:) contextInfo: renamer];
}
@ -51,13 +51,13 @@ typedef void (^CompletionBlock)(BOOL);
{
NSParameterAssert(node != nil);
NSParameterAssert(window != nil);
FileRenameSheetController * renamer = [[FileRenameSheetController alloc] initWithWindowNibName: @"FileRenameSheetController"];
renamer.torrent = [node torrent];
renamer.node = node;
renamer.completionHandler = completionHandler;
[NSApp beginSheet: [renamer window] modalForWindow: window modalDelegate: self didEndSelector: @selector(sheetDidEnd:returnCode:contextInfo:) contextInfo: renamer];
}
@ -65,9 +65,9 @@ typedef void (^CompletionBlock)(BOOL);
{
FileRenameSheetController * renamer = contextInfo;
NSParameterAssert([renamer isKindOfClass:[FileRenameSheetController class]]);
renamer.completionHandler(returnCode == NSOKButton);
//TODO: retain/release logic needs to be figured out for ARC (when ARC is enabled)
[renamer release];
[sheet orderOut: self];
@ -85,42 +85,42 @@ typedef void (^CompletionBlock)(BOOL);
- (void) windowDidLoad
{
[super windowDidLoad];
self.originalName = [self.node name] ?: [self.torrent name];
NSString * label = [NSString stringWithFormat: NSLocalizedString(@"Rename the file \"%@\":", "rename sheet label"), self.originalName];
[self.labelField setStringValue: label];
[self.inputField setStringValue: self.originalName];
[self.renameButton setEnabled: NO];
//resize the buttons so that they're long enough and the same width
const NSRect oldRenameFrame = [self.renameButton frame];
const NSRect oldCancelFrame = [self.cancelButton frame];
//get the extra width of the rename button from the English xib - the width from sizeToFit is too squished
[self.renameButton sizeToFit];
const CGFloat extra = NSWidth(oldRenameFrame) - NSWidth([self.renameButton frame]);
[self.renameButton setTitle: NSLocalizedString(@"Rename", "rename sheet button")];
[self.cancelButton setTitle: NSLocalizedString(@"Cancel", "rename sheet button")];
[self.renameButton sizeToFit];
[self.cancelButton sizeToFit];
NSRect newRenameFrame = [self.renameButton frame];
NSRect newCancelFrame = [self.cancelButton frame];
newRenameFrame.size.width = MAX(NSWidth(newRenameFrame), NSWidth(newCancelFrame)) + extra;
newCancelFrame.size.width = MAX(NSWidth(newRenameFrame), NSWidth(newCancelFrame)) + extra;
const CGFloat renameWidthIncrease = NSWidth(newRenameFrame) - NSWidth(oldRenameFrame);
newRenameFrame.origin.x -= renameWidthIncrease;
[self.renameButton setFrame:newRenameFrame];
const CGFloat cancelWidthIncrease = NSWidth(newCancelFrame) - NSWidth(oldCancelFrame);
newCancelFrame.origin.x -= renameWidthIncrease + cancelWidthIncrease;
[self.cancelButton setFrame:newCancelFrame];
}
- (IBAction) rename: (id) sender;
- (IBAction) rename: (id) sender
{
void (^completionHandler)(BOOL) = ^(BOOL didRename) {
if (didRename)
@ -131,7 +131,7 @@ typedef void (^CompletionBlock)(BOOL);
NSBeep();
}
};
if (self.node)
[self.torrent renameFileNode: self.node withName: [self.inputField stringValue] completionHandler: completionHandler];
else

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="FileRenameSheetController">

View File

@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9531" systemVersion="15B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9531"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="11762"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="FilterBarController">
@ -58,12 +59,9 @@
</menu>
</popUpButtonCell>
</popUpButton>
<box horizontalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="5">
<box horizontalHuggingPriority="750" boxType="separator" id="5">
<rect key="frame" x="34" y="5" width="5" height="13"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<font key="titleFont" metaFont="system"/>
</box>
<button verticalHuggingPriority="750" id="6" customClass="FilterButton">
<rect key="frame" x="273" y="2" width="55" height="17"/>

View File

@ -39,9 +39,9 @@
{
IBOutlet FilterButton * fNoFilterButton, * fActiveFilterButton, * fDownloadFilterButton,
* fSeedFilterButton, * fPauseFilterButton;
IBOutlet NSSearchField * fSearchField;
IBOutlet NSPopUpButton * fGroupsButton;
}

View File

@ -54,26 +54,26 @@
[fDownloadFilterButton setTitle: NSLocalizedString(@"Downloading", "Filter Bar -> filter button")];
[fSeedFilterButton setTitle: NSLocalizedString(@"Seeding", "Filter Bar -> filter button")];
[fPauseFilterButton setTitle: NSLocalizedString(@"Paused", "Filter Bar -> filter button")];
[[fNoFilterButton cell] setBackgroundStyle: NSBackgroundStyleRaised];
[[fActiveFilterButton cell] setBackgroundStyle: NSBackgroundStyleRaised];
[[fDownloadFilterButton cell] setBackgroundStyle: NSBackgroundStyleRaised];
[[fSeedFilterButton cell] setBackgroundStyle: NSBackgroundStyleRaised];
[[fPauseFilterButton cell] setBackgroundStyle: NSBackgroundStyleRaised];
[[[[fSearchField cell] searchMenuTemplate] itemWithTag: FILTER_TYPE_TAG_NAME] setTitle:
NSLocalizedString(@"Name", "Filter Bar -> filter menu")];
[[[[fSearchField cell] searchMenuTemplate] itemWithTag: FILTER_TYPE_TAG_TRACKER] setTitle:
NSLocalizedString(@"Tracker", "Filter Bar -> filter menu")];
[[[fGroupsButton menu] itemWithTag: GROUP_FILTER_ALL_TAG] setTitle:
NSLocalizedString(@"All Groups", "Filter Bar -> group filter menu")];
[self resizeBar];
//set current filter
NSString * filterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"Filter"];
NSButton * currentFilterButton;
if ([filterType isEqualToString: FILTER_ACTIVE])
currentFilterButton = fActiveFilterButton;
@ -91,10 +91,10 @@
currentFilterButton = fNoFilterButton;
}
[currentFilterButton setState: NSOnState];
//set filter search type
NSString * filterSearchType = [[NSUserDefaults standardUserDefaults] stringForKey: @"FilterSearchType"];
NSMenu * filterSearchMenu = [[fSearchField cell] searchMenuTemplate];
NSString * filterSearchTypeTitle;
if ([filterSearchType isEqualToString: FILTER_TYPE_TRACKER])
@ -107,16 +107,16 @@
filterSearchTypeTitle = [[filterSearchMenu itemWithTag: FILTER_TYPE_TAG_NAME] title];
}
[[fSearchField cell] setPlaceholderString: filterSearchTypeTitle];
NSString * searchString;
if ((searchString = [[NSUserDefaults standardUserDefaults] stringForKey: @"FilterSearchString"]))
[fSearchField setStringValue: searchString];
[self updateGroupsButton];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(resizeBar)
name: NSWindowDidResizeNotification object: [[self view] window]];
//update when groups change
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(updateGroups:)
name: @"UpdateGroups" object: nil];
@ -125,14 +125,14 @@
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
[super dealloc];
}
- (void) setFilter: (id) sender
{
NSString * oldFilterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"Filter"];
NSButton * prevFilterButton;
if ([oldFilterType isEqualToString: FILTER_PAUSE])
prevFilterButton = fPauseFilterButton;
@ -144,7 +144,7 @@
prevFilterButton = fDownloadFilterButton;
else
prevFilterButton = fNoFilterButton;
if (sender != prevFilterButton)
{
[prevFilterButton setState: NSOffState];
@ -166,14 +166,14 @@
}
else
[sender setState: NSOnState];
[[NSNotificationCenter defaultCenter] postNotificationName: @"ApplyFilter" object: nil];
}
- (void) switchFilter: (BOOL) right
{
NSString * filterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"Filter"];
NSButton * button;
if ([filterType isEqualToString: FILTER_NONE])
button = right ? fActiveFilterButton : fPauseFilterButton;
@ -187,7 +187,7 @@
button = right ? fNoFilterButton : fSeedFilterButton;
else
button = fNoFilterButton;
[self setFilter: button];
}
@ -205,13 +205,13 @@
- (void) setSearchType: (id) sender
{
NSString * oldFilterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"FilterSearchType"];
NSInteger prevTag, currentTag = [sender tag];
if ([oldFilterType isEqualToString: FILTER_TYPE_TRACKER])
prevTag = FILTER_TYPE_TAG_TRACKER;
else
prevTag = FILTER_TYPE_TAG_NAME;
if (currentTag != prevTag)
{
NSString * filterType;
@ -219,12 +219,12 @@
filterType = FILTER_TYPE_TRACKER;
else
filterType = FILTER_TYPE_NAME;
[[NSUserDefaults standardUserDefaults] setObject: filterType forKey: @"FilterSearchType"];
[[fSearchField cell] setPlaceholderString: [sender title]];
}
[[NSNotificationCenter defaultCenter] postNotificationName: @"ApplyFilter" object: nil];
}
@ -232,20 +232,20 @@
{
[[NSUserDefaults standardUserDefaults] setInteger: [sender tag] forKey: @"FilterGroup"];
[self updateGroupsButton];
[[NSNotificationCenter defaultCenter] postNotificationName: @"ApplyFilter" object: nil];
}
- (void) reset: (BOOL) updateUI
{
[[NSUserDefaults standardUserDefaults] setInteger: GROUP_FILTER_ALL_TAG forKey: @"FilterGroup"];
if (updateUI)
{
{
[self updateGroupsButton];
[self setFilter: fNoFilterButton];
[fSearchField setStringValue: @""];
[self setSearchText: fSearchField];
}
@ -277,9 +277,9 @@
{
for (NSInteger i = [menu numberOfItems]-1; i >= 3; i--)
[menu removeItemAtIndex: i];
NSMenu * groupMenu = [[GroupsController groups] groupMenuWithTarget: self action: @selector(setGroupFilter:) isSmall: YES];
const NSInteger groupMenuCount = [groupMenu numberOfItems];
for (NSInteger i = 0; i < groupMenuCount; i++)
{
@ -294,29 +294,29 @@
- (BOOL) validateMenuItem: (NSMenuItem *) menuItem
{
const SEL action = [menuItem action];
//check proper filter search item
if (action == @selector(setSearchType:))
{
NSString * filterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"FilterSearchType"];
BOOL state;
if ([menuItem tag] == FILTER_TYPE_TAG_TRACKER)
state = [filterType isEqualToString: FILTER_TYPE_TRACKER];
else
state = [filterType isEqualToString: FILTER_TYPE_NAME];
[menuItem setState: state ? NSOnState : NSOffState];
return YES;
}
if (action == @selector(setGroupFilter:))
{
[menuItem setState: [menuItem tag] == [[NSUserDefaults standardUserDefaults] integerForKey: @"FilterGroup"]
? NSOnState : NSOffState];
return YES;
}
return YES;
}
@ -332,18 +332,18 @@
[fDownloadFilterButton sizeToFit];
[fSeedFilterButton sizeToFit];
[fPauseFilterButton sizeToFit];
NSRect allRect = [fNoFilterButton frame];
NSRect activeRect = [fActiveFilterButton frame];
NSRect downloadRect = [fDownloadFilterButton frame];
NSRect seedRect = [fSeedFilterButton frame];
NSRect pauseRect = [fPauseFilterButton frame];
//size search filter to not overlap buttons
NSRect searchFrame = [fSearchField frame];
searchFrame.origin.x = NSMaxX(pauseRect) + 5.0;
searchFrame.size.width = NSWidth([[self view] frame]) - searchFrame.origin.x - 5.0;
//make sure it is not too long
if (NSWidth(searchFrame) > SEARCH_MAX_WIDTH)
{
@ -354,13 +354,13 @@
{
searchFrame.origin.x += NSWidth(searchFrame) - SEARCH_MIN_WIDTH;
searchFrame.size.width = SEARCH_MIN_WIDTH;
//calculate width the buttons can take up
const CGFloat allowedWidth = (searchFrame.origin.x - 5.0) - allRect.origin.x;
const CGFloat currentWidth = NSWidth(allRect) + NSWidth(activeRect) + NSWidth(downloadRect) + NSWidth(seedRect)
+ NSWidth(pauseRect) + 4.0; //add 4 for space between buttons
const CGFloat ratio = allowedWidth / currentWidth;
//decrease button widths proportionally
allRect.size.width = NSWidth(allRect) * ratio;
activeRect.size.width = NSWidth(activeRect) * ratio;
@ -369,25 +369,25 @@
pauseRect.size.width = NSWidth(pauseRect) * ratio;
}
else;
activeRect.origin.x = NSMaxX(allRect) + 1.0;
downloadRect.origin.x = NSMaxX(activeRect) + 1.0;
seedRect.origin.x = NSMaxX(downloadRect) + 1.0;
pauseRect.origin.x = NSMaxX(seedRect) + 1.0;
[fNoFilterButton setFrame: allRect];
[fActiveFilterButton setFrame: activeRect];
[fDownloadFilterButton setFrame: downloadRect];
[fSeedFilterButton setFrame: seedRect];
[fPauseFilterButton setFrame: pauseRect];
[fSearchField setFrame: searchFrame];
}
- (void) updateGroupsButton
{
const NSInteger groupIndex = [[NSUserDefaults standardUserDefaults] integerForKey: @"FilterGroup"];
NSImage * icon;
NSString * toolTip;
if (groupIndex == GROUP_FILTER_ALL_TAG)
@ -402,7 +402,7 @@
: NSLocalizedString(@"None", "Groups -> Button");
toolTip = [NSLocalizedString(@"Group", "Groups -> Button") stringByAppendingFormat: @": %@", groupName];
}
[[[fGroupsButton menu] itemAtIndex: 0] setImage: icon];
[fGroupsButton setToolTip: toolTip];
}

View File

@ -59,7 +59,7 @@
if ([NSApp isOnYosemiteOrBetter]) {
[[NSColor windowBackgroundColor] setFill];
NSRectFill(rect);
const NSRect lineBorderRect = NSMakeRect(NSMinX(rect), 0.0, NSWidth(rect), 1.0);
if (NSIntersectsRect(lineBorderRect, rect))
{
@ -71,34 +71,34 @@
NSInteger count = 0;
NSRect gridRects[2];
NSColor * colorRects[2];
NSRect lineBorderRect = NSMakeRect(NSMinX(rect), NSHeight([self bounds]) - 1.0, NSWidth(rect), 1.0);
if (NSIntersectsRect(lineBorderRect, rect))
{
gridRects[count] = lineBorderRect;
colorRects[count] = [NSColor whiteColor];
++count;
rect.size.height -= 1.0;
}
lineBorderRect.origin.y = 0.0;
if (NSIntersectsRect(lineBorderRect, rect))
{
gridRects[count] = lineBorderRect;
colorRects[count] = [NSColor colorWithCalibratedWhite: 0.65 alpha: 1.0];
++count;
rect.origin.y += 1.0;
rect.size.height -= 1.0;
}
if (!NSIsEmptyRect(rect))
{
const NSRect gradientRect = NSMakeRect(NSMinX(rect), 1.0, NSWidth(rect), NSHeight([self bounds]) - 1.0 - 1.0); //proper gradient requires the full height of the bar
[fGradient drawInRect: gradientRect angle: 270.0];
}
NSRectFillListWithColors(gridRects, colorRects, count);
}
}

View File

@ -38,9 +38,9 @@
{
if (count == fCount)
return;
fCount = count;
[self setToolTip: fCount == 1 ? NSLocalizedString(@"1 transfer", "Filter Button -> tool tip")
: [NSString stringWithFormat: NSLocalizedString(@"%@ transfers", "Filter Bar Button -> tool tip"),
[NSString formattedUInteger: fCount]]];

View File

@ -28,11 +28,11 @@
{
tr_session * fHandle;
NSUserDefaults * fDefaults;
IBOutlet NSTextField * fUploadLimitField, * fDownloadLimitField;
IBOutlet NSTextField * fRatioStopField, * fIdleStopField;
NSString * fInitialString;
}

View File

@ -29,10 +29,10 @@
if ((self = [super initWithNibName: @"GlobalOptionsPopover" bundle: nil]))
{
fHandle = handle;
fDefaults = [NSUserDefaults standardUserDefaults];
}
return self;
}
@ -40,7 +40,7 @@
{
[fUploadLimitField setIntValue: [fDefaults integerForKey: @"UploadLimit"]];
[fDownloadLimitField setIntValue: [fDefaults integerForKey: @"DownloadLimit"]];
[fRatioStopField setFloatValue: [fDefaults floatForKey: @"RatioLimit"]];
[fIdleStopField setIntegerValue: [fDefaults integerForKey: @"IdleLimitMinutes"]];
@ -55,7 +55,7 @@
- (IBAction) setDownSpeedSetting: (id) sender
{
tr_sessionLimitSpeed(fHandle, TR_DOWN, [fDefaults boolForKey: @"CheckDownload"]);
[[NSNotificationCenter defaultCenter] postNotificationName: @"SpeedLimitUpdate" object: nil];
}
@ -64,7 +64,7 @@
const NSInteger limit = [sender integerValue];
[fDefaults setInteger: limit forKey: @"DownloadLimit"];
tr_sessionSetSpeedLimit_KBps(fHandle, TR_DOWN, limit);
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateSpeedLimitValuesOutsidePrefs" object: nil];
[[NSNotificationCenter defaultCenter] postNotificationName: @"SpeedLimitUpdate" object: nil];
}
@ -72,7 +72,7 @@
- (IBAction) setUpSpeedSetting: (id) sender
{
tr_sessionLimitSpeed(fHandle, TR_UP, [fDefaults boolForKey: @"CheckUpload"]);
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateSpeedLimitValuesOutsidePrefs" object: nil];
[[NSNotificationCenter defaultCenter] postNotificationName: @"SpeedLimitUpdate" object: nil];
}
@ -82,17 +82,17 @@
const NSInteger limit = [sender integerValue];
[fDefaults setInteger: limit forKey: @"UploadLimit"];
tr_sessionSetSpeedLimit_KBps(fHandle, TR_UP, limit);
[[NSNotificationCenter defaultCenter] postNotificationName: @"SpeedLimitUpdate" object: nil];
}
- (IBAction) setRatioStopSetting: (id) sender
{
tr_sessionSetRatioLimited(fHandle, [fDefaults boolForKey: @"RatioCheck"]);
//reload main table for seeding progress
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
//reload global settings in inspector
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGlobalOptions" object: nil];
}
@ -102,12 +102,12 @@
const CGFloat value = [sender floatValue];
[fDefaults setFloat: value forKey: @"RatioLimit"];
tr_sessionSetRatioLimit(fHandle, value);
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateRatioStopValueOutsidePrefs" object: nil];
//reload main table for seeding progress
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
//reload global settings in inspector
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGlobalOptions" object: nil];
}
@ -115,10 +115,10 @@
- (IBAction) setIdleStopSetting: (id) sender
{
tr_sessionSetIdleLimited(fHandle, [fDefaults boolForKey: @"IdleLimitCheck"]);
//reload main table for remaining seeding time
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
//reload global settings in inspector
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGlobalOptions" object: nil];
}
@ -128,12 +128,12 @@
const NSInteger value = [sender integerValue];
[fDefaults setInteger: value forKey: @"IdleLimitMinutes"];
tr_sessionSetIdleLimit(fHandle, value);
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateIdleStopValueOutsidePrefs" object: nil];
//reload main table for remaining seeding time
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
//reload global settings in inspector
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGlobalOptions" object: nil];
}
@ -142,7 +142,7 @@
{
[fInitialString release];
fInitialString = [[control stringValue] retain];
return YES;
}

View File

@ -39,7 +39,7 @@
- (void) validate
{
NSSegmentedControl * control = (NSSegmentedControl *)[self view];
for (NSInteger i = 0; i < [control segmentCount]; i++)
[control setEnabled: [[self target] validateToolbarItem:
[[[NSToolbarItem alloc] initWithItemIdentifier: [fIdentifiers objectAtIndex: i]] autorelease]] forSegment: i];
@ -50,20 +50,20 @@
NSMenuItem * menuItem = [[NSMenuItem alloc] initWithTitle: [self label] action: NULL keyEquivalent: @""];
NSMenu * menu = [[NSMenu alloc] initWithTitle: [self label]];
[menuItem setSubmenu: menu];
[menu setAutoenablesItems: NO];
const NSInteger count = [(NSSegmentedControl *)[self view] segmentCount];
for (NSInteger i = 0; i < count; i++)
{
NSMenuItem * addItem = [[NSMenuItem alloc] initWithTitle: [labels objectAtIndex: i] action: [self action] keyEquivalent: @""];
[addItem setTarget: [self target]];
[addItem setTag: i];
[menu addItem: addItem];
[addItem release];
}
[menu release];
[self setMenuFormRepresentation: menuItem];
[menuItem release];
@ -72,12 +72,12 @@
- (NSMenuItem *) menuFormRepresentation
{
NSMenuItem * menuItem = [super menuFormRepresentation];
const NSInteger count = [(NSSegmentedControl *)[self view] segmentCount];
for (NSInteger i = 0; i < count; i++)
[[[menuItem submenu] itemAtIndex: i] setEnabled: [[self target] validateToolbarItem:
[[[NSToolbarItem alloc] initWithItemIdentifier: [fIdentifiers objectAtIndex: i]] autorelease]]];
return menuItem;
}

View File

@ -66,42 +66,42 @@ GroupsController * fGroupsInstance = nil;
[NSColor redColor], @"Color",
NSLocalizedString(@"Red", "Groups -> Name"), @"Name",
[NSNumber numberWithInteger: 0], @"Index", nil];
NSMutableDictionary * orange = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSColor orangeColor], @"Color",
NSLocalizedString(@"Orange", "Groups -> Name"), @"Name",
[NSNumber numberWithInteger: 1], @"Index", nil];
NSMutableDictionary * yellow = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSColor yellowColor], @"Color",
NSLocalizedString(@"Yellow", "Groups -> Name"), @"Name",
[NSNumber numberWithInteger: 2], @"Index", nil];
NSMutableDictionary * green = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSColor greenColor], @"Color",
NSLocalizedString(@"Green", "Groups -> Name"), @"Name",
[NSNumber numberWithInteger: 3], @"Index", nil];
NSMutableDictionary * blue = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSColor blueColor], @"Color",
NSLocalizedString(@"Blue", "Groups -> Name"), @"Name",
[NSNumber numberWithInteger: 4], @"Index", nil];
NSMutableDictionary * purple = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSColor purpleColor], @"Color",
NSLocalizedString(@"Purple", "Groups -> Name"), @"Name",
[NSNumber numberWithInteger: 5], @"Index", nil];
NSMutableDictionary * gray = [NSMutableDictionary dictionaryWithObjectsAndKeys:
[NSColor grayColor], @"Color",
NSLocalizedString(@"Gray", "Groups -> Name"), @"Name",
[NSNumber numberWithInteger: 6], @"Index", nil];
fGroups = [[NSMutableArray alloc] initWithObjects: red, orange, yellow, green, blue, purple, gray, nil];
[self saveGroups]; //make sure this is saved right away
}
}
return self;
}
@ -120,7 +120,7 @@ GroupsController * fGroupsInstance = nil;
{
if (index != -1)
{
for (NSInteger i = 0; i < [fGroups count]; i++)
for (NSUInteger i = 0; i < [fGroups count]; i++)
if (index == [[[fGroups objectAtIndex: i] objectForKey: @"Index"] integerValue])
return i;
}
@ -143,7 +143,7 @@ GroupsController * fGroupsInstance = nil;
NSInteger orderIndex = [self rowValueForIndex: index];
[[fGroups objectAtIndex: orderIndex] setObject: name forKey: @"Name"];
[self saveGroups];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGroups" object: self];
}
@ -164,9 +164,9 @@ GroupsController * fGroupsInstance = nil;
{
NSMutableDictionary * dict = [fGroups objectAtIndex: [self rowValueForIndex: index]];
[dict removeObjectForKey: @"Icon"];
[dict setObject: color forKey: @"Color"];
[[GroupsController groups] saveGroups];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGroups" object: self];
}
@ -183,9 +183,9 @@ GroupsController * fGroupsInstance = nil;
- (void) setUsesCustomDownloadLocation: (BOOL) useCustomLocation forIndex: (NSInteger) index
{
NSMutableDictionary * dict = [fGroups objectAtIndex: [self rowValueForIndex: index]];
[dict setObject: [NSNumber numberWithBool: useCustomLocation] forKey: @"UsesCustomDownloadLocation"];
[[GroupsController groups] saveGroups];
}
@ -199,7 +199,7 @@ GroupsController * fGroupsInstance = nil;
{
NSMutableDictionary * dict = [fGroups objectAtIndex: [self rowValueForIndex: index]];
[dict setObject: location forKey: @"CustomDownloadLocation"];
[[GroupsController groups] saveGroups];
}
@ -208,7 +208,7 @@ GroupsController * fGroupsInstance = nil;
NSInteger orderIndex = [self rowValueForIndex: index];
if (orderIndex == -1)
return NO;
NSNumber * assignRules = [[fGroups objectAtIndex: orderIndex] objectForKey: @"UsesAutoGroupRules"];
return assignRules && [assignRules boolValue];
}
@ -216,9 +216,9 @@ GroupsController * fGroupsInstance = nil;
- (void) setUsesAutoAssignRules: (BOOL) useAutoAssignRules forIndex: (NSInteger) index
{
NSMutableDictionary * dict = [fGroups objectAtIndex: [self rowValueForIndex: index]];
[dict setObject: [NSNumber numberWithBool: useAutoAssignRules] forKey: @"UsesAutoGroupRules"];
[[GroupsController groups] saveGroups];
}
@ -226,15 +226,15 @@ GroupsController * fGroupsInstance = nil;
{
NSInteger orderIndex = [self rowValueForIndex: index];
if (orderIndex == -1)
return nil;
return [[fGroups objectAtIndex: orderIndex] objectForKey: @"AutoGroupRules"];
return nil;
return [[fGroups objectAtIndex: orderIndex] objectForKey: @"AutoGroupRules"];
}
- (void) setAutoAssignRules: (NSPredicate *) predicate forIndex: (NSInteger) index
{
NSMutableDictionary * dict = [fGroups objectAtIndex: [self rowValueForIndex: index]];
if (predicate)
{
[dict setObject: predicate forKey: @"AutoGroupRules"];
@ -253,12 +253,12 @@ GroupsController * fGroupsInstance = nil;
NSMutableIndexSet * candidates = [NSMutableIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [fGroups count]+1)];
for (NSDictionary * dict in fGroups)
[candidates removeIndex: [[dict objectForKey: @"Index"] integerValue]];
const NSInteger index = [candidates firstIndex];
[fGroups addObject: [NSMutableDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInteger: index], @"Index",
[NSColor colorWithCalibratedRed: 0.0 green: 0.65 blue: 1.0 alpha: 1.0], @"Color", @"", @"Name", nil]];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGroups" object: self];
[self saveGroups];
}
@ -267,13 +267,13 @@ GroupsController * fGroupsInstance = nil;
{
NSInteger index = [[[fGroups objectAtIndex: row] objectForKey: @"Index"] integerValue];
[fGroups removeObjectAtIndex: row];
[[NSNotificationCenter defaultCenter] postNotificationName: @"GroupValueRemoved" object: self userInfo:
[NSDictionary dictionaryWithObject: [NSNumber numberWithInteger: index] forKey: @"Index"]];
if (index == [[NSUserDefaults standardUserDefaults] integerForKey: @"FilterGroup"])
[[NSUserDefaults standardUserDefaults] setInteger: -2 forKey: @"FilterGroup"];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGroups" object: self];
[self saveGroups];
}
@ -281,7 +281,7 @@ GroupsController * fGroupsInstance = nil;
- (void) moveGroupAtRow: (NSInteger) oldRow toRow: (NSInteger) newRow
{
[fGroups moveObjectAtIndex: oldRow toIndex: newRow];
[self saveGroups];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGroups" object: self];
}
@ -289,54 +289,54 @@ GroupsController * fGroupsInstance = nil;
- (NSMenu *) groupMenuWithTarget: (id) target action: (SEL) action isSmall: (BOOL) small
{
NSMenu * menu = [[NSMenu alloc] initWithTitle: @"Groups"];
NSMenuItem * item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"None", "Groups -> Menu") action: action
keyEquivalent: @""];
[item setTarget: target];
[item setTag: -1];
NSImage * icon = [NSImage imageNamed: @"GroupsNoneTemplate"];
if (small)
{
icon = [icon copy];
[icon setSize: NSMakeSize(ICON_WIDTH_SMALL, ICON_WIDTH_SMALL)];
[item setImage: icon];
[icon release];
}
else
[item setImage: icon];
[menu addItem: item];
[item release];
for (NSMutableDictionary * dict in fGroups)
{
item = [[NSMenuItem alloc] initWithTitle: [dict objectForKey: @"Name"] action: action keyEquivalent: @""];
[item setTarget: target];
[item setTag: [[dict objectForKey: @"Index"] integerValue]];
NSImage * icon = [self imageForGroup: dict];
if (small)
{
icon = [icon copy];
[icon setSize: NSMakeSize(ICON_WIDTH_SMALL, ICON_WIDTH_SMALL)];
[item setImage: icon];
[icon release];
}
else
[item setImage: icon];
[menu addItem: item];
[item release];
}
return [menu autorelease];
}
- (NSInteger) groupIndexForTorrent: (Torrent *) torrent;
- (NSInteger) groupIndexForTorrent: (Torrent *) torrent
{
for (NSDictionary * group in fGroups)
{
@ -362,7 +362,7 @@ GroupsController * fGroupsInstance = nil;
[groups addObject: tempDict];
[tempDict release];
}
[[NSUserDefaults standardUserDefaults] setObject: [NSKeyedArchiver archivedDataWithRootObject: groups] forKey: @"GroupDicts"];
}
@ -371,34 +371,34 @@ GroupsController * fGroupsInstance = nil;
NSImage * image;
if ((image = [dict objectForKey: @"Icon"]))
return image;
NSRect rect = NSMakeRect(0.0, 0.0, ICON_WIDTH, ICON_WIDTH);
NSBezierPath * bp = [NSBezierPath bezierPathWithRoundedRect: rect xRadius: 3.0 yRadius: 3.0];
NSImage * icon = [[NSImage alloc] initWithSize: rect.size];
NSColor * color = [dict objectForKey: @"Color"];
[icon lockFocus];
//border
NSGradient * gradient = [[NSGradient alloc] initWithStartingColor: [color blendedColorWithFraction: 0.45 ofColor:
[NSColor whiteColor]] endingColor: color];
[gradient drawInBezierPath: bp angle: 270.0];
[gradient release];
//inside
bp = [NSBezierPath bezierPathWithRoundedRect: NSInsetRect(rect, 1.0, 1.0) xRadius: 3.0 yRadius: 3.0];
gradient = [[NSGradient alloc] initWithStartingColor: [color blendedColorWithFraction: 0.75 ofColor: [NSColor whiteColor]]
endingColor: [color blendedColorWithFraction: 0.2 ofColor: [NSColor whiteColor]]];
[gradient drawInBezierPath: bp angle: 270.0];
[gradient release];
[icon unlockFocus];
[dict setObject: icon forKey: @"Icon"];
[icon release];
return icon;
}
@ -406,7 +406,7 @@ GroupsController * fGroupsInstance = nil;
{
if (![self usesAutoAssignRulesForIndex: index])
return NO;
NSPredicate * predicate = [self autoAssignRulesForIndex: index];
BOOL eval = NO;
@try

View File

@ -26,19 +26,14 @@
{
IBOutlet NSTableView * fTableView;
IBOutlet NSSegmentedControl * fAddRemoveControl;
IBOutlet NSColorWell * fSelectedColorView;
IBOutlet NSTextField * fSelectedColorNameField;
IBOutlet NSButton * fCustomLocationEnableCheck;
IBOutlet NSPopUpButton * fCustomLocationPopUp;
IBOutlet NSButton * fAutoAssignRulesEnableCheck;
IBOutlet NSButton * fAutoAssignRulesEditButton;
IBOutlet NSWindow * fGroupRulesSheetWindow;
IBOutlet NSPredicateEditor * fRuleEditor;
IBOutlet NSLayoutConstraint * fRuleEditorHeightConstraint;
}
- (void) addRemoveGroup: (id) sender;

View File

@ -31,6 +31,14 @@
#define ADD_TAG 0
#define REMOVE_TAG 1
@interface GroupsPrefsController ()
@property (nonatomic, retain) IBOutlet NSWindow * groupRulesSheetWindow;
@property (nonatomic, assign) IBOutlet NSPredicateEditor * ruleEditor;
@property (nonatomic, assign) IBOutlet NSLayoutConstraint * ruleEditorHeightConstraint;
@end
@interface GroupsPrefsController (Private)
- (void) updateSelectedGroup;
@ -40,12 +48,16 @@
@implementation GroupsPrefsController
@synthesize groupRulesSheetWindow;
@synthesize ruleEditor;
@synthesize ruleEditorHeightConstraint;
- (void) awakeFromNib
{
[fTableView registerForDraggedTypes: [NSArray arrayWithObject: GROUP_TABLE_VIEW_DATA_TYPE]];
[fSelectedColorView addObserver: self forKeyPath: @"color" options: 0 context: NULL];
[self updateSelectedGroup];
}
@ -58,7 +70,7 @@
{
GroupsController * groupsController = [GroupsController groups];
NSInteger groupsIndex = [groupsController indexForRow: row];
NSString * identifier = [tableColumn identifier];
if ([identifier isEqualToString: @"Color"])
return [groupsController imageForIndex: groupsIndex];
@ -107,7 +119,7 @@
[fTableView setDropRow: row dropOperation: NSTableViewDropAbove];
return NSDragOperationGeneric;
}
return NSDragOperationNone;
}
@ -119,18 +131,18 @@
{
NSIndexSet * indexes = [NSKeyedUnarchiver unarchiveObjectWithData: [pasteboard dataForType: GROUP_TABLE_VIEW_DATA_TYPE]];
NSInteger oldRow = [indexes firstIndex];
if (oldRow < newRow)
newRow--;
[fTableView beginUpdates];
[[GroupsController groups] moveGroupAtRow: oldRow toRow: newRow];
[fTableView moveRowAtIndex: oldRow toIndex: newRow];
[fTableView endUpdates];
}
return YES;
}
@ -140,37 +152,37 @@
[[NSColorPanel sharedColorPanel] close];
NSInteger row;
switch ([[sender cell] tagForSegment: [sender selectedSegment]])
{
case ADD_TAG:
[fTableView beginUpdates];
[[GroupsController groups] addNewGroup];
row = [fTableView numberOfRows];
[fTableView insertRowsAtIndexes: [NSIndexSet indexSetWithIndex: row] withAnimation: NSTableViewAnimationSlideUp];
[fTableView endUpdates];
[fTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: row] byExtendingSelection: NO];
[fTableView scrollRowToVisible: row];
[[fSelectedColorNameField window] makeFirstResponder: fSelectedColorNameField];
break;
case REMOVE_TAG:
row = [fTableView selectedRow];
[fTableView beginUpdates];
[[GroupsController groups] removeGroupWithRowIndex: row];
[[GroupsController groups] removeGroupWithRowIndex: row];
[fTableView removeRowsAtIndexes: [NSIndexSet indexSetWithIndex: row] withAnimation: NSTableViewAnimationSlideUp];
[fTableView endUpdates];
if ([fTableView numberOfRows] > 0)
{
if (row == [fTableView numberOfRows])
@ -178,10 +190,10 @@
[fTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: row] byExtendingSelection: NO];
[fTableView scrollRowToVisible: row];
}
break;
}
[self updateSelectedGroup];
}
@ -194,7 +206,7 @@
[panel setCanChooseFiles: NO];
[panel setCanChooseDirectories: YES];
[panel setCanCreateDirectories: YES];
[panel beginSheetModalForWindow: [fCustomLocationPopUp window] completionHandler: ^(NSInteger result) {
const NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]];
if (result == NSFileHandlingPanelOKButton)
@ -208,9 +220,9 @@
if (![[GroupsController groups] customDownloadLocationForIndex: index])
[[GroupsController groups] setUsesCustomDownloadLocation: NO forIndex: index];
}
[self refreshCustomLocationWithSingleGroup];
[fCustomLocationPopUp selectItemAtIndex: 0];
}];
}
@ -234,7 +246,7 @@
#pragma mark -
#pragma mark Rule editor
- (IBAction) toggleUseAutoAssignRules: (id) sender;
- (IBAction) toggleUseAutoAssignRules: (id) sender
{
NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]];
if ([fAutoAssignRulesEnableCheck state] == NSOnState)
@ -250,27 +262,27 @@
[fAutoAssignRulesEditButton setEnabled: [fAutoAssignRulesEnableCheck state] == NSOnState];
}
- (IBAction) orderFrontRulesSheet: (id) sender;
- (IBAction) orderFrontRulesSheet: (id) sender
{
if (!fGroupRulesSheetWindow)
[NSBundle loadNibNamed: @"GroupRules" owner: self];
if (!self.groupRulesSheetWindow)
[[NSBundle mainBundle] loadNibNamed: @"GroupRules" owner: self topLevelObjects: NULL];
NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]];
NSPredicate *predicate = [[GroupsController groups] autoAssignRulesForIndex: index];
[fRuleEditor setObjectValue: predicate];
if ([fRuleEditor numberOfRows] == 0)
[fRuleEditor addRow: nil];
[NSApp beginSheet: fGroupRulesSheetWindow modalForWindow: [fTableView window] modalDelegate: nil didEndSelector: NULL
NSPredicate *predicate = [[GroupsController groups] autoAssignRulesForIndex: index];
[self.ruleEditor setObjectValue: predicate];
if ([self.ruleEditor numberOfRows] == 0)
[self.ruleEditor addRow: nil];
[NSApp beginSheet: self.groupRulesSheetWindow modalForWindow: [fTableView window] modalDelegate: nil didEndSelector: NULL
contextInfo: NULL];
}
- (IBAction) cancelRules: (id) sender;
- (IBAction) cancelRules: (id) sender
{
[fGroupRulesSheetWindow orderOut: nil];
[NSApp endSheet: fGroupRulesSheetWindow];
[self.groupRulesSheetWindow orderOut: nil];
[NSApp endSheet: self.groupRulesSheetWindow];
NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]];
if (![[GroupsController groups] autoAssignRulesForIndex: index])
{
@ -280,32 +292,32 @@
}
}
- (IBAction) saveRules: (id) sender;
- (IBAction) saveRules: (id) sender
{
[fGroupRulesSheetWindow orderOut: nil];
[NSApp endSheet: fGroupRulesSheetWindow];
[self.groupRulesSheetWindow orderOut: nil];
[NSApp endSheet: self.groupRulesSheetWindow];
NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]];
[[GroupsController groups] setUsesAutoAssignRules: YES forIndex: index];
NSPredicate * predicate = [fRuleEditor objectValue];
NSPredicate * predicate = [self.ruleEditor objectValue];
[[GroupsController groups] setAutoAssignRules: predicate forIndex: index];
[fAutoAssignRulesEnableCheck setState: [[GroupsController groups] usesAutoAssignRulesForIndex: index]];
[fAutoAssignRulesEditButton setEnabled: [fAutoAssignRulesEnableCheck state] == NSOnState];
}
- (void) ruleEditorRowsDidChange: (NSNotification *) notification
{
NSScrollView * ruleEditorScrollView = [fRuleEditor enclosingScrollView];
const CGFloat rowHeight = [fRuleEditor rowHeight];
NSScrollView * ruleEditorScrollView = [self.ruleEditor enclosingScrollView];
const CGFloat rowHeight = [self.ruleEditor rowHeight];
const CGFloat bordersHeight = [ruleEditorScrollView frame].size.height - [ruleEditorScrollView contentSize].height;
const CGFloat requiredRowCount = [fRuleEditor numberOfRows];
const CGFloat maxVisibleRowCount = (long)((NSHeight([[[fRuleEditor window] screen] visibleFrame]) * 2 / 3) / rowHeight);
[fRuleEditorHeightConstraint setConstant: MIN(requiredRowCount, maxVisibleRowCount) * rowHeight + bordersHeight];
const CGFloat requiredRowCount = [self.ruleEditor numberOfRows];
const CGFloat maxVisibleRowCount = (long)((NSHeight([[[self.ruleEditor window] screen] visibleFrame]) * 2 / 3) / rowHeight);
[self.ruleEditorHeightConstraint setConstant: MIN(requiredRowCount, maxVisibleRowCount) * rowHeight + bordersHeight];
[ruleEditorScrollView setHasVerticalScroller: requiredRowCount > maxVisibleRowCount];
}
@ -323,7 +335,7 @@
[fSelectedColorView setEnabled: YES];
[fSelectedColorNameField setStringValue: [[GroupsController groups] nameForIndex: index]];
[fSelectedColorNameField setEnabled: YES];
[self refreshCustomLocationWithSingleGroup];
[fAutoAssignRulesEnableCheck setState: [[GroupsController groups] usesAutoAssignRulesForIndex: index]];
@ -346,12 +358,12 @@
- (void) refreshCustomLocationWithSingleGroup
{
const NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]];
const BOOL hasCustomLocation = [[GroupsController groups] usesCustomDownloadLocationForIndex: index];
[fCustomLocationEnableCheck setState: hasCustomLocation];
[fCustomLocationEnableCheck setEnabled: YES];
[fCustomLocationPopUp setEnabled: hasCustomLocation];
NSString * location = [[GroupsController groups] customDownloadLocationForIndex: index];
if (location)
{

View File

@ -2,8 +2,6 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildMachineOSBuild</key>
<string>11C74</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
@ -20,20 +18,6 @@
<string>GRRR</string>
<key>CFBundleVersion</key>
<string>1.3.1</string>
<key>DTCompiler</key>
<string>com.apple.compilers.llvm.clang.1_0</string>
<key>DTPlatformBuild</key>
<string>4D199</string>
<key>DTPlatformVersion</key>
<string>GM</string>
<key>DTSDKBuild</key>
<string>11C63</string>
<key>DTSDKName</key>
<string>macosx10.7</string>
<key>DTXcode</key>
<string>0420</string>
<key>DTXcodeBuild</key>
<string>4D199</string>
<key>NSPrincipalClass</key>
<string>GrowlApplicationBridge</string>
</dict>

View File

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>files</key>
<dict>
<key>Resources/Info.plist</key>
<data>
SwzGt9RQsuVafBBrfBalB75dCwU=
</data>
</dict>
<key>rules</key>
<dict>
<key>^Resources/</key>
<true/>
<key>^Resources/.*\.lproj/</key>
<dict>
<key>optional</key>
<true/>
<key>weight</key>
<real>1000</real>
</dict>
<key>^Resources/.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
<key>^version.plist$</key>
<true/>
</dict>
</dict>
</plist>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 537 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 290 B

View File

Before

Width:  |  Height:  |  Size: 549 B

After

Width:  |  Height:  |  Size: 549 B

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "mac",
"filename" : "ActionHover.png",
"scale" : "1x"
},
{
"idiom" : "mac",
"filename" : "ActionHover@2x.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "original"
}
}

View File

Before

Width:  |  Height:  |  Size: 288 B

After

Width:  |  Height:  |  Size: 288 B

View File

Before

Width:  |  Height:  |  Size: 541 B

After

Width:  |  Height:  |  Size: 541 B

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "mac",
"filename" : "ActionOn.png",
"scale" : "1x"
},
{
"idiom" : "mac",
"filename" : "ActionOn@2x.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "original"
}
}

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "mac",
"filename" : "Bandwidth.png",
"scale" : "1x"
},
{
"idiom" : "mac",
"filename" : "Bandwidth@2x.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "original"
}
}

View File

Before

Width:  |  Height:  |  Size: 346 B

After

Width:  |  Height:  |  Size: 346 B

View File

Before

Width:  |  Height:  |  Size: 418 B

After

Width:  |  Height:  |  Size: 418 B

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "mac",
"filename" : "CleanupTemplate.png",
"scale" : "1x"
},
{
"idiom" : "mac",
"filename" : "CleanupTemplate@2x.png",
"scale" : "2x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
},
"properties" : {
"template-rendering-intent" : "template"
}
}

View File

Before

Width:  |  Height:  |  Size: 205 B

After

Width:  |  Height:  |  Size: 205 B

View File

Before

Width:  |  Height:  |  Size: 301 B

After

Width:  |  Height:  |  Size: 301 B

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