Merge branch 'master' into master
17
.tx/config
|
@ -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
|
||||
|
|
7
AUTHORS
|
@ -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:
|
||||
|
|
163
CMakeLists.txt
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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 ,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 ,
|
||||
|
|
|
@ -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 ,
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 ,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/***
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
@interface BadgeView : NSView
|
||||
{
|
||||
tr_session * fLib;
|
||||
|
||||
|
||||
NSMutableDictionary * fAttributes;
|
||||
|
||||
|
||||
CGFloat fDownloadRate, fUploadRate;
|
||||
BOOL fQuitting;
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
@interface Badger : NSObject
|
||||
{
|
||||
tr_session * fLib;
|
||||
|
||||
|
||||
NSMutableSet * fHashes;
|
||||
}
|
||||
|
||||
|
|
|
@ -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]]];
|
||||
}
|
||||
|
|
|
@ -34,13 +34,13 @@ typedef enum
|
|||
@interface BlocklistDownloader : NSObject <NSURLDownloadDelegate>
|
||||
{
|
||||
NSURLDownload * fDownload;
|
||||
|
||||
|
||||
BlocklistDownloaderViewController * fViewController;
|
||||
|
||||
|
||||
NSString * fDestination;
|
||||
NSUInteger fCurrentSize;
|
||||
long long fExpectedSize;
|
||||
|
||||
|
||||
blocklistDownloadState fState;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
@class PrefsController;
|
||||
|
||||
@interface BlocklistDownloaderViewController : NSObject
|
||||
{
|
||||
{
|
||||
PrefsController * fPrefsController;
|
||||
|
||||
|
||||
IBOutlet NSWindow * fStatusWindow;
|
||||
IBOutlet NSProgressIndicator * fProgressBar;
|
||||
IBOutlet NSTextField * fTextField;
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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}\")
|
||||
")
|
|
@ -32,7 +32,7 @@
|
|||
- (void) setEnabled: (BOOL) flag
|
||||
{
|
||||
[super setEnabled: flag];
|
||||
|
||||
|
||||
NSColor * color = flag ? [NSColor controlTextColor] : [NSColor disabledControlTextColor];
|
||||
[self setTextColor: color];
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
1389
macosx/Controller.m
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
@interface DragOverlayView : NSView
|
||||
{
|
||||
NSImage * fBadge;
|
||||
|
||||
|
||||
NSDictionary * fMainLineAttributes, * fSubLineAttributes;
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
@interface DragOverlayWindow : NSWindow
|
||||
{
|
||||
tr_session * fLib;
|
||||
|
||||
|
||||
NSViewAnimation * fFadeInAnimation, * fFadeOutAnimation;
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
@interface FileListNode : NSObject <NSCopying>
|
||||
{
|
||||
NSMutableIndexSet * fIndexes;
|
||||
|
||||
|
||||
NSString * fName;
|
||||
NSString * fPath;
|
||||
Torrent * fTorrent;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@
|
|||
{
|
||||
Torrent * fTorrent;
|
||||
NSMutableArray * fFileList;
|
||||
|
||||
|
||||
IBOutlet FileOutlineView * fOutline;
|
||||
|
||||
|
||||
NSString * fFilterText;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
FileListNode * _node;
|
||||
void (^_completionHandler)(BOOL);
|
||||
NSString * _originalName;
|
||||
|
||||
|
||||
IBOutlet NSTextField * _labelField;
|
||||
IBOutlet NSTextField * _inputField;
|
||||
IBOutlet NSButton * _renameButton;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -39,9 +39,9 @@
|
|||
{
|
||||
IBOutlet FilterButton * fNoFilterButton, * fActiveFilterButton, * fDownloadFilterButton,
|
||||
* fSeedFilterButton, * fPauseFilterButton;
|
||||
|
||||
|
||||
IBOutlet NSSearchField * fSearchField;
|
||||
|
||||
|
||||
IBOutlet NSPopUpButton * fGroupsButton;
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]]];
|
||||
|
|
|
@ -28,11 +28,11 @@
|
|||
{
|
||||
tr_session * fHandle;
|
||||
NSUserDefaults * fDefaults;
|
||||
|
||||
|
||||
IBOutlet NSTextField * fUploadLimitField, * fDownloadLimitField;
|
||||
|
||||
|
||||
IBOutlet NSTextField * fRatioStopField, * fIdleStopField;
|
||||
|
||||
|
||||
NSString * fInitialString;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
Before Width: | Height: | Size: 537 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 290 B After Width: | Height: | Size: 290 B |
Before Width: | Height: | Size: 549 B After Width: | Height: | Size: 549 B |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 288 B After Width: | Height: | Size: 288 B |
Before Width: | Height: | Size: 541 B After Width: | Height: | Size: 541 B |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 346 B After Width: | Height: | Size: 346 B |
Before Width: | Height: | Size: 418 B After Width: | Height: | Size: 418 B |
|
@ -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"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 205 B After Width: | Height: | Size: 205 B |
Before Width: | Height: | Size: 301 B After Width: | Height: | Size: 301 B |