├── .gitignore
├── AUTHORS
├── CMakeLists.txt
├── ChangeLog
├── LICENSE
├── README.md
├── TODO
├── cmake
└── FindMsgfmt.cmake
├── config.h.cmake
├── icons
├── CMakeLists.txt
├── carbon.svg
├── carbon16.png
├── carbon22.png
├── carbon32.png
└── carbon48.png
├── scripts
├── CMakeLists.txt
├── carbon-runner.cmake
└── carbon-terminate
├── support
├── CMakeLists.txt
├── dialog.cpp
├── dialog.h
├── messagebox.cpp
├── messagebox.h
├── pagewidget.cpp
├── pagewidget.h
├── pathrequester.cpp
├── pathrequester.h
├── squeezedtextlabel.cpp
├── squeezedtextlabel.h
├── utils.cpp
└── utils.h
└── ui
├── CMakeLists.txt
├── basicitemdelegate.cpp
├── basicitemdelegate.h
├── carbon.desktop
├── carbon.qrc
├── default.sync
├── default.sync.exclude
├── excludefile.cpp
├── excludefile.h
├── excludewidget.cpp
├── excludewidget.h
├── excludewidget.ui
├── generaloptionswidget.cpp
├── generaloptionswidget.h
├── generaloptionswidget.ui
├── main.cpp
├── mainwindow.cpp
├── mainwindow.h
├── rsyncoptionswidget.cpp
├── rsyncoptionswidget.h
├── rsyncoptionswidget.ui
├── runnerdialog.cpp
├── runnerdialog.h
├── runnerwidget.ui
├── session.cpp
├── session.h
├── sessiondialog.cpp
├── sessiondialog.h
├── sessionwidget.cpp
├── sessionwidget.h
├── sessionwidget.ui
├── treewidget.cpp
└── treewidget.h
/.gitignore:
--------------------------------------------------------------------------------
1 | CMakeLists.txt.user
2 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | Craig Drummond
2 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | project(carbon)
2 | cmake_minimum_required(VERSION 2.4.0)
3 | # Keep CMake quiet...
4 | if(COMMAND cmake_policy)
5 | cmake_policy(SET CMP0003 NEW)
6 | endif(COMMAND cmake_policy)
7 |
8 | set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
9 | set(CPACK_GENERATOR "TBZ2")
10 | set(CPACK_SOURCE_GENERATOR "TBZ2")
11 | set(CPACK_PACKAGE_VERSION_MAJOR "0")
12 | set(CPACK_PACKAGE_VERSION_MINOR "1")
13 | set(CPACK_PACKAGE_VERSION_PATCH "0")
14 | set(CARBON_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}")
15 | set(CARBON_VERSION_FULL "${CARBON_VERSION}.${CPACK_PACKAGE_VERSION_PATCH}")
16 | set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CMAKE_PROJECT_NAME}-${CARBON_VERSION_FULL}")
17 | set(CPACK_SOURCE_IGNORE_FILES "/.svn/;/.git/;.gitignore;.project;CMakeLists.txt.user")
18 | include(CPack)
19 | set(CARBON_EXTENSION ".sync")
20 | set(CARBON_INFO_EXTENSION ".info")
21 | set(CARBON_LOCK_EXTENSION ".lock")
22 | set(CARBON_LOG_EXTENSION ".log")
23 | set(CARBON_EXCLUDE_EXTENSION ".exclude")
24 | set(CARBON_PREFIX "CARBON:")
25 | set(CARBON_MSG_PREFIX "INFO:")
26 | set(CARBON_ERROR_PREFIX "ERROR:")
27 | set(CARBON_GUI_PARENT "CARBON_GUI_PARENT")
28 | set(CARBON_LOWEST_UID 1000)
29 | set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
30 | include(CheckFunctionExists)
31 | include_directories(${CMAKE_CURRENT_BINARY_DIR})
32 |
33 | set(SHARE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}/share"
34 | CACHE PATH "Define install directory for read-only architecture-independent data")
35 |
36 | find_package(Qt5Widgets REQUIRED)
37 | set(QTLIBS ${Qt5Core_LIBRARIES} ${Qt5Widgets_LIBRARIES} ${Qt5Gui_LIBRARIES})
38 | set(QTINCLUDES ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Network_INCLUDE_DIRS} ${Qt5Core_INCLUDE_DIRS})
39 | add_definitions(${Qt5Widgets_DEFINITIONS})
40 | set(CMAKE_CXX_FLAGS "${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
41 | find_package(Qt5DBus)
42 | if (Qt5DBus_FOUND)
43 | set(QT_QTDBUS_FOUND 1) # required for config.h !!!
44 | set(QTLIBS ${QTLIBS} ${Qt5DBus_LIBRARIES})
45 | set(QTINCLUDES ${QTINCLUDES} ${Qt5DBus_INCLUDE_DIRS})
46 | add_definitions(${Qt5DBus_DEFINITIONS})
47 | endif (Qt5DBus_FOUND)
48 | set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
49 | set(CMAKE_CXX_STANDARD 11)
50 | if (Qt5_POSITION_INDEPENDENT_CODE)
51 | set(CMAKE_POSITION_INDEPENDENT_CODE ON)
52 | else ()
53 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
54 | endif ()
55 |
56 | configure_file(config.h.cmake ${CMAKE_BINARY_DIR}/config.h)
57 |
58 | add_subdirectory(support)
59 | add_subdirectory(ui)
60 | add_subdirectory(scripts)
61 | add_subdirectory(icons)
62 |
63 |
--------------------------------------------------------------------------------
/ChangeLog:
--------------------------------------------------------------------------------
1 | 0.1.0
2 | -----
3 | 1. Initial release.
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Carbon
2 |
3 | Carbon is a simple front-end to rsync. Carbon supports the following features:
4 |
5 | 1. Multiple sessions. (A session is a source -> destination synchronisation).
6 | 2. Dry-run a synchronisation.
7 | 3. Setting of various rsync options.
8 | 4. Ability to specify a set of patterns to exclude from synchronisation.
9 | 5. Increments older then a specified number of days are deleted.
10 |
--------------------------------------------------------------------------------
/TODO:
--------------------------------------------------------------------------------
1 | Advanced:
2 | Compress file data --compress
3 | Don't map uid/gid values --numeric-ids
4 | Copy hardlinks as hardlinks --hard-links
5 | Protect remote args --protect-args
6 | ? is this require, as script quotes args?
7 |
8 | Extra:
9 | Execute command before rsync: [......] Halt on failure [x]
10 | Execute command afger rsync: [.....] On rsync error only [x]
11 |
12 | * SessionDialog
13 | Add NOTES detailing URLs
14 | Add help text to most pages
15 | Always select 'Don't delete old increments' if dest is remote.
16 | Dont allow advanced scheduling if run-as-root
17 | If run-as-root, then cron scripts need to *not* call su
18 |
19 | Add Adanced settings page:
20 | Before sync:
21 | Run: [...................] [F]
22 | Terminate on failure [x]
23 |
24 | After sync:
25 | Run on success: [...............] [F]
26 | Run on failure: [...............] [F]
27 |
28 | Run session with admin privaleges
29 |
30 | * Use form-layout, and BuddyLabel's, for al UI???
31 |
32 | * Dont create backup folder if there are no changes.
33 |
34 |
--------------------------------------------------------------------------------
/cmake/FindMsgfmt.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # - Try to find the msgfmt executeable
3 | #
4 | # It will set the following variables:
5 | #
6 | # MSGFMT_FOUND
7 | # MSGFMT_EXECUTABLE
8 | #
9 | ###################################################################
10 | #
11 | # Copyright (c) 2006, Andreas Schneider
12 | #
13 | # This program is free software; you can redistribute it and/or
14 | # modify it under the terms of the GNU General Public License
15 | # as published by the Free Software Foundation; either version 2
16 | # of the License, or (at your option) any later version.
17 | #
18 | # This program is distributed in the hope that it will be useful,
19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 | # GNU General Public License for more details.
22 | #
23 | # You should have received a copy of the GNU General Public License
24 | # along with this program; if not, write to the Free Software
25 | # Foundation, Inc., 51 Franklin Street, Fifth Floor,
26 | # Boston, MA 02110-1301, USA.
27 | #
28 | ###################################################################
29 | #
30 | # Copyright (c) 2006 Andreas Schneider
31 | # All rights reserved.
32 | #
33 | # Redistribution and use in source and binary forms, with or without
34 | # modification, are permitted provided that the following conditions
35 | # are met:
36 | #
37 | # * Redistributions of source code must retain the above copyright
38 | # notice, this list of conditions and the following disclaimer.
39 | #
40 | # * Redistributions in binary form must reproduce the above copyright
41 | # notice, this list of conditions and the following disclaimer in
42 | # the documentation and/or other materials provided with the
43 | # distribution.
44 | #
45 | # * Neither the name of the cmake-modules nor the names of its
46 | # contributors may be used to endorse or promote products derived
47 | # from this software without specific prior written permission.
48 | #
49 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
52 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
53 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
54 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
55 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
56 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
57 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
59 | # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
60 | # POSSIBILITY OF SUCH DAMAGE.
61 | #
62 |
63 | IF (MSGFMT_EXECUTABLE)
64 | # in cache alread?
65 | SET(MSGFMT_FOUND TRUE)
66 | ELSE (MSGFMT_EXECUTABLE)
67 | IF (UNIX)
68 | FIND_PROGRAM(MSGFMT_EXECUTABLE
69 | NAMES
70 | msgfmt
71 | PATHS
72 | /usr/bin
73 | /usr/local/bin
74 | )
75 |
76 | IF(MSGFMT_EXECUTABLE)
77 | SET(MSGFMT_FOUND TRUE)
78 | ELSE(MSGFMT_EXECUTABLE)
79 | MESSAGE(FATAL_ERROR "msgfmt not found - po files can't be processed")
80 | ENDIF(MSGFMT_EXECUTABLE)
81 |
82 | MARK_AS_ADVANCED(MSGFMT_EXECUTABLE)
83 | ENDIF(UNIX)
84 | ENDIF (MSGFMT_EXECUTABLE)
85 |
86 | # vim:et ts=2 sw=2 comments=\:\#
87 |
--------------------------------------------------------------------------------
/config.h.cmake:
--------------------------------------------------------------------------------
1 | #ifndef __CONFIG_H__
2 | #define __CONFIG_H__
3 |
4 | /*
5 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
6 |
7 | ----
8 |
9 | This program is free software; you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation; either version 2 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 | General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program; see the file COPYING. If not, write to
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 | Boston, MA 02110-1301, USA.
23 | */
24 |
25 | #define CARBON_VERSION "@CARBON_VERSION_FULL@"
26 | #define CARBON_EXTENSION "@CARBON_EXTENSION@"
27 | #define CARBON_LOG_EXTENSION "@CARBON_LOG_EXTENSION@"
28 | #define CARBON_INFO_EXTENSION "@CARBON_INFO_EXTENSION@"
29 | #define CARBON_LOCK_EXTENSION "@CARBON_LOCK_EXTENSION@"
30 | #define CARBON_EXCLUDE_EXTENSION "@CARBON_EXCLUDE_EXTENSION@"
31 | #define CARBON_PREFIX "@CARBON_PREFIX@"
32 | #define CARBON_MSG_PREFIX "@CARBON_MSG_PREFIX@"
33 | #define CARBON_ERROR_PREFIX "@CARBON_ERROR_PREFIX@"
34 | #define CARBON_GUI_PARENT "@CARBON_GUI_PARENT@"
35 | #define CARBON_RUNNER "@CMAKE_INSTALL_PREFIX@/share/@CMAKE_PROJECT_NAME@/scripts/@CMAKE_PROJECT_NAME@-runner"
36 | #define CARBON_TERMINATE "@CMAKE_INSTALL_PREFIX@/share/@CMAKE_PROJECT_NAME@/scripts/@CMAKE_PROJECT_NAME@-terminate"
37 | #define INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@" /* No CARBON_ prefix to this name, as its used in 'support' */
38 | #define CARBON_SYSTEM_DEF_FILE "@CMAKE_INSTALL_PREFIX@/share/@CMAKE_PROJECT_NAME@/default@CARBON_EXTENSION@"
39 | #define CARBON_PACKAGE_NAME "@PROJECT_NAME@"
40 | #define SHARE_INSTALL_PREFIX "@SHARE_INSTALL_PREFIX@"
41 | #cmakedefine QT_QTDBUS_FOUND 1
42 | #endif
43 |
--------------------------------------------------------------------------------
/icons/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | if (UNIX AND NOT APPLE)
2 | macro (update_iconcache)
3 | # Update mtime of hicolor icon theme dir.
4 | # We don't always have touch command (e.g. on Windows), so instead create
5 | # and delete a temporary file in the theme dir.
6 | install(CODE "
7 | set(DESTDIR_VALUE \"\$ENV{DESTDIR}\")
8 | if (NOT DESTDIR_VALUE)
9 | file(WRITE \"${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/temp.txt\" \"update\")
10 | file(REMOVE \"${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/temp.txt\")
11 | endif (NOT DESTDIR_VALUE)
12 | ")
13 | endmacro (update_iconcache)
14 |
15 | install(FILES carbon.svg DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps)
16 | install(FILES carbon16.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/16x16/apps RENAME carbon.png)
17 | install(FILES carbon22.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/22x22/apps RENAME carbon.png)
18 | install(FILES carbon32.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/32x32/apps RENAME carbon.png)
19 | install(FILES carbon48.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/48x48/apps RENAME carbon.png)
20 | update_iconcache()
21 | endif (UNIX AND NOT APPLE)
22 |
--------------------------------------------------------------------------------
/icons/carbon.svg:
--------------------------------------------------------------------------------
1 |
2 |
199 |
--------------------------------------------------------------------------------
/icons/carbon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CDrummond/carbon/a42dac97f986c7311014f76687bfb2baa4327dcd/icons/carbon16.png
--------------------------------------------------------------------------------
/icons/carbon22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CDrummond/carbon/a42dac97f986c7311014f76687bfb2baa4327dcd/icons/carbon22.png
--------------------------------------------------------------------------------
/icons/carbon32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CDrummond/carbon/a42dac97f986c7311014f76687bfb2baa4327dcd/icons/carbon32.png
--------------------------------------------------------------------------------
/icons/carbon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CDrummond/carbon/a42dac97f986c7311014f76687bfb2baa4327dcd/icons/carbon48.png
--------------------------------------------------------------------------------
/scripts/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | configure_file (carbon-runner.cmake ${CMAKE_CURRENT_BINARY_DIR}/carbon-runner @ONLY)
2 | install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/carbon-runner carbon-terminate
3 | DESTINATION ${CMAKE_INSTALL_PREFIX}/share/${CMAKE_PROJECT_NAME}/scripts)
4 |
--------------------------------------------------------------------------------
/scripts/carbon-runner.cmake:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | appName=`basename $0`
4 |
5 | function show_help()
6 | {
7 | exName=Wibble
8 | echo
9 | echo "@CMAKE_PROJECT_NAME@ Session runner v@CARBON_VERSION_FULL@"
10 | echo
11 | echo "(C) Craig Drummond 2013 - Released under the GPL (v3 or later)"
12 | echo
13 | echo "Usage: $appName [-d] "
14 | echo " -d Perform a dry-run (i.e. show what would happen, but don't"
15 | echo " do any actual synchronisation)"
16 | echo
17 | echo "e.g. $appName $exName"
18 | echo " - This will synchronise the $exName session (as created in"
19 | echo " @CMAKE_PROJECT_NAME@). This is achieved by loading the settings"
20 | echo " from $HOME/.local/share/$projectName/$fileName@CARBON_EXTENSION@"
21 | echo
22 | echo " $appName $HOME/.local/share/$projectName/$exName@CARBON_EXTENSION@"
23 | echo " - This will perform a synchronisation using the settings"
24 | echo " within $HOME/$exName@CARBON_EXTENSION@"
25 | echo
26 | exit 101
27 | }
28 |
29 | shortOpts="dh"
30 | longOpts="dryrun,help"
31 | progName=carbon-runner
32 | args=$(getopt -s bash --options $shortOpts --longoptions $longOpts --name $progName -- "$@" )
33 |
34 | eval set -- "$args"
35 |
36 | while true; do
37 | case $1 in
38 | -h|--help)
39 | show_help
40 | ;;
41 | -d|--dryrun)
42 | shift
43 | doDryRun=true
44 | ;;
45 | *)
46 | shift
47 | break
48 | ;;
49 | esac
50 | done
51 |
52 | fileName=$1
53 | sessionName=`basename "$fileName" | sed s^@CARBON_EXTENSION@^^g`
54 |
55 | function fix_url()
56 | {
57 | # Remove file:// from URL
58 | #fixed="`echo $1/ | sed s/file://g | sed s^//^/^g | sed s^//^/^g`"
59 | fixed="`echo $1/ | sed s^file://^^g | sed s^//^/^g`"
60 | if [[ "$fixed" != */ ]] ; then
61 | fixed=$fixed/
62 | fi
63 |
64 | echo $fixed
65 | }
66 |
67 | function log_msg()
68 | {
69 | if [ "$CARBON_NO_MSG_PREFIX" = "true" ] ; then
70 | echo "$1"
71 | else
72 | echo "@CARBON_MSG_PREFIX@$1"
73 | fi
74 | }
75 |
76 | function log_error()
77 | {
78 | if [ "$CARBON_NO_MSG_PREFIX" = "true" ] ; then
79 | echo "$1"
80 | else
81 | echo "@CARBON_ERROR_PREFIX@$1"
82 | fi
83 | }
84 |
85 | projectName=`echo @CMAKE_PROJECT_NAME@ | tr "[:upper:]" "[:lower:]"`
86 |
87 | function notify()
88 | {
89 | notifyApp=`which notify-send`
90 | if [ "$notifyApp" != "" ] ; then
91 | if [ "$2" = "start" ] ;then
92 | $notifyApp --app-name=@CMAKE_PROJECT_NAME@ --icon=$projectName "Session Starting" "Starting synchronisation of \"$sessionName\"" > /dev/null 2>&1
93 | elif [ "$2" = "error" ] ;then
94 | $notifyApp --app-name=@CMAKE_PROJECT_NAME@ --icon=$projectName "Session Failed" "Synchronisation of \"$sessionName\" failed.
$3" > /dev/null 2>&1
95 | elif [ $1 -eq 0 ] ; then
96 | $notifyApp --app-name=@CMAKE_PROJECT_NAME@ --icon=$projectName "Session Complete" "Sucessfully completed synchronisation of \"$sessionName\"" > /dev/null 2>&1
97 | else
98 | $notifyApp --app-name=@CMAKE_PROJECT_NAME@ --icon=$projectName "Session Failed" "Synchronisation of \"$sessionName\" failed.
Please check log file." > /dev/null 2>&1
99 | fi
100 | fi
101 | }
102 |
103 | function log_error_and_exit()
104 | {
105 | notify $1 "error" "$2"
106 | log_error "$2"
107 | exit $1
108 | }
109 |
110 | if [ "$fileName" = "" ]; then
111 | show_help
112 | fi
113 |
114 | if [ ! -f "$fileName" ] ; then
115 | session="$HOME/.local/share/$projectName/$fileName@CARBON_EXTENSION@"
116 | if [ "$session" != "" ] ; then
117 | fileName=$session
118 | fi
119 | fi
120 |
121 | if [ ! -f "$fileName" ] ; then
122 | log_error_and_exit 102 "Could not read \"$fileName\""
123 | fi
124 |
125 | if [ -e "$fileName@CARBON_LOCK_EXTENSION@" ] ; then
126 | prevPid=`cat "$fileName@CARBON_LOCK_EXTENSION@"`
127 | if ps -p $prevPid > /dev/null ; then
128 | log_error_and_exit 113 "Session is already running"
129 | fi
130 | fi
131 |
132 | # Keys used in backup info file
133 | backupTimeKey=BackupTime
134 |
135 | maxBackupAge=0
136 | maxFileSize=0
137 |
138 | if [ "$@CARBON_GUI_PARENT@" != "true" ] ; then
139 | if [ -f "$fileName@CARBON_LOG_EXTENSION@" ] ; then
140 | rm "$fileName@CARBON_LOG_EXTENSION@"
141 | fi
142 |
143 | # We are not being run via the GUI - so we need to log all output
144 | # So re-run this script, but capture all output to log file...
145 | @CARBON_GUI_PARENT@=true CARBON_NO_MSG_PREFIX=true $0 "$@" > "$fileName@CARBON_LOG_EXTENSION@" 2>&1
146 | else
147 | notify 0 start
148 | eval `cat "$fileName" | grep -A999 "\[Settings\]" | tail -n +2`
149 | src=`fix_url $src`
150 | dest=`fix_url $dest`
151 |
152 | if [ -z "$src" ] ; then
153 | log_error_and_exit 109 "Source is empty"
154 | fi
155 |
156 | srcIsRemote=0
157 | if [ "`echo $src | grep \: | wc -l`" != "0" ] ; then
158 | srcIsRemote=1
159 | fi
160 |
161 | if [ $srcIsRemote -eq 0 ] && [ ! -e "$src" ] ; then
162 | log_error_and_exit 112 "Source does not exist"
163 | fi
164 |
165 | if [ -z "$dest" ] ; then
166 | log_error_and_exit 110 "destination is empty"
167 | fi
168 |
169 | if [ "$CARBON_NO_MSG_PREFIX" = "true" ] ; then
170 | command="rsync -v --progress --include=*.exe --exclude=@CARBON_EXTENSION@@CARBON_LOG_EXTENSION@ --out-format=%f"
171 | else
172 | command="rsync -v --progress --include=*.exe --exclude=@CARBON_EXTENSION@@CARBON_LOG_EXTENSION@ --out-format=@CARBON_PREFIX@%f"
173 | fi
174 |
175 | # Map @CARBON_EXTENSION@ file options to rsync options...
176 | if [ "$archive" = "true" ] || [ "$archive" = "" ] || [ "$makeBackups" = "true" ] || [ "$makeBackups" = "" ] ; then command="$command --archive"; fi
177 | if [ "$recursive" = "true" ] || [ "$recursive" = "" ] ; then command="$command --recursive"; fi
178 | if [ "$skipFilesOnSizeMatch" = "true" ]; then command="$command --size-only"; fi
179 | if [ "$skipReceiverNewerFiles" = "true" ] || [ "$skipReceiverNewerFiles" = "" ]; then command="$command --update"; fi
180 | if [ "$keepPartial" = "true" ]; then command="$command --partial"; fi
181 | if [ "$onlyUpdate" = "true" ]; then command="$command --existing"; fi
182 | if [ "$useCompression" = "true" ]; then command="$command --compress"; fi
183 | if [ "$checksum" = "true" ]; then command="$command --checksum"; fi
184 | if [ "$windowsCompat" = "true" ]; then command="$command --modify-window=1"; fi
185 | if [ "$ignoreExisting" = "true" ]; then command="$command --ignore-existing"; fi
186 | if [ "$archive" != "true" ] && ( [ "$preservePermissions" = "true" ] || [ "$preservePermissions" = "" ] ) ; then command="$command --perms"; fi
187 | if [ "$archive" != "true" ] && ( [ "$preserveGroup" = "true" ] || [ "$preserveGroup" = "" ] ) ; then command="$command --group"; fi
188 | if [ "$modificationTimes" = "true" ] || [ "$modificationTimes" = "" ]; then command="$command --times"; fi
189 | if ( [ "$deleteExtraFilesOnReceiver" = "true" ] || [ "$deleteExtraFilesOnReceiver" = "" ] ) && [ "$recursive" != "false" ] ; then
190 | command="$command --delete";
191 | fi
192 | if [ "$archive" != "true" ] && ( [ "$preserveOwner" = "true" ] || [ "$preserveOwner" = "" ] ) ; then command="$command --owner"; fi
193 | if [ "$archive" != "true" ] && ( [ "$preserveSpecialFiles" = "true" ] || [ "$preserveSpecialFiles" = "" ] ) ; then command="$command -D"; fi
194 | if [ "$archive" != "true" ] && ( [ "$copySymlinksAsSymlinks" = "true" ] || [ "$copySymlinksAsSymlinks" = "" ] ) ; then command="$command --links"; fi
195 | if [ "$dontLeaveFileSystem" = "true" ]; then command="$command --one-file-system"; fi
196 | if [ "$cvsExclude" = "true" ] || [ "$cvsExclude" = "" ]; then command="$command --cvs-exclude"; fi
197 | if [ "$CustomOptions" != "" ] ; then command="$command $CustomOptions"; fi
198 | if [ "$maxFileSize" != "" ] && [ $maxFileSize -gt 0 ] ; then command="$command --max-size=$maxFileSize"M ; fi
199 |
200 | destIsRemote=0
201 | if [ "`echo $dest | grep \: | wc -l`" != "0" ] ; then
202 | destIsRemote=1
203 | fi
204 |
205 | if [ $destIsRemote -eq 0 ] && [ ! -d "$dest" ] ; then
206 | log_error_and_exit 103 "$dest does not exist"
207 | fi
208 |
209 | excludeFrom="$fileName@CARBON_EXCLUDE_EXTENSION@"
210 |
211 | if [ "$doDryRun" = "true" ]; then
212 | command="$command -n"
213 | fi
214 |
215 | destFolder="$dest"
216 | linkDestFolder="$dest"
217 |
218 | if [ "$makeBackups" = "true" ]; then
219 | currentBackupTime=`date +"%Y-%m-%d %H:%M:%S"`
220 | currentBackupTimeFile="$fileName@CARBON_INFO_EXTENSION@"
221 | previousBackupTime=`cat "$currentBackupTimeFile" | grep "$backupTimeKey" | awk -F\= '{print $2}'`
222 |
223 | if [ -f "$dest$currentBackupTime" ] ; then
224 | log_error_and_exit 104 " $dest$currentBackupTime is a file!"
225 | fi
226 |
227 | if [ ! -z "$previousBackupTime" ] ; then
228 | linkDestFolder="$dest/$previousBackupTime"
229 | fi
230 | if [ ! -z "$currentBackupTime" ] ; then
231 | destFolder="$dest/$currentBackupTime"
232 | fi
233 |
234 | if [ -z "$previousBackupTime" ]; then
235 | log_msg "Full backup, as no previous backup"
236 | elif [ $destIsRemote -eq 0 ] && [ ! -d "$linkDestFolder" ] ; then
237 | log_msg "Full backup, as previous folder does not exist"
238 | linkDestFolder=""
239 | else
240 | log_msg "Incremental backup (previous $linkDestFolder)"
241 | fi
242 | fi
243 |
244 | # Store PID in lock file, to prevent multiple executions...
245 | echo $$ > "$fileName@CARBON_LOCK_EXTENSION@"
246 |
247 | if [ "$linkDestFolder" = "" ] ; then
248 | # linkDest is empty, so dont pass as arg - else rsync moans...
249 | if [ -f "$excludeFrom" ] ; then
250 | $command "$src" "$destFolder" --exclude-from="$excludeFrom"
251 | else
252 | $command "$src" "$destFolder"
253 | fi
254 | else
255 | if [ -f "$excludeFrom" ] ; then
256 | $command "$src" "$destFolder" --exclude-from="$excludeFrom" --link-dest="$linkDestFolder"
257 | else
258 | $command "$src" "$destFolder" --link-dest="$linkDestFolder"
259 | fi
260 | fi
261 |
262 | if [ "$makeBackups" = "true" ] && [ -d "$destFolder" ] ; then
263 | # Store date of this backup
264 | echo "$backupTimeKey=$currentBackupTime" > "$currentBackupTimeFile"
265 | fi
266 |
267 | rv=$?
268 |
269 | if [ $destIsRemote -eq 0 ] ; then
270 | let maxBackupAge="$maxBackupAge * 24 * 60 * 60"
271 |
272 | # Remove any old increments
273 | if [ "$makeBackups" = "true" ] && [ $maxBackupAge -gt 0 ] && [ -d "$destFolder" ] && [ "$dest" != "/" ] ; then
274 | log_msg "Cleaning old backups"
275 | touch "$destFolder"
276 | currentAge=`stat --terse --format=%Y "$destFolder"`
277 |
278 | oldIfs=$IFS
279 | IFS="
280 | "
281 |
282 | for old in "$dest"/* ; do
283 | if [ -d "$old" ] && [ "$old" != "/" ] ; then
284 | let diff="$currentAge - `stat --terse --format=%Y $old`"
285 |
286 | if [ $diff -gt $maxBackupAge ] ; then
287 | log_msg "Erasing $old"
288 | \rm -r "$old"
289 | fi
290 | fi
291 | done
292 | IFS=$oldIfs
293 | fi
294 | fi
295 |
296 | # Remove lock
297 | rm "$fileName@CARBON_LOCK_EXTENSION@"
298 |
299 | notify $rv
300 |
301 | # Return rsyncs exit value...
302 | exit $rv
303 | fi
304 |
--------------------------------------------------------------------------------
/scripts/carbon-terminate:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | ppid=$1
4 |
5 | if [ -z $ppid ] ; then
6 | echo "Termiante PID and all its children"
7 | echo "Usage: $0 PID";
8 | exit;
9 | fi
10 |
11 | for i in `ps -eaf | awk '$3 == '$ppid' { print $2 }'` ; do
12 | $0 $i "child"
13 | kill -9 $i
14 | done
15 |
16 | if [ "$2" = "" ] ; then
17 | kill $ppid
18 | fi
19 |
--------------------------------------------------------------------------------
/support/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(SUPPORT_SRCS messagebox.cpp
2 | utils.cpp dialog.cpp
3 | squeezedtextlabel.cpp pathrequester.cpp pagewidget.cpp)
4 |
5 | set(SUPPORT_MOC_HDRS pagewidget.h dialog.h pathrequester.h)
6 |
7 | qt5_wrap_cpp(SUPPORT_MOC_SRCS ${SUPPORT_MOC_HDRS} )
8 |
9 | include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR} ${QTINCLUDES} )
10 | add_library(support STATIC ${SUPPORT_MOC_SRCS} ${SUPPORT_SRCS} ${SUPPORT_UI_HDRS} )
11 |
--------------------------------------------------------------------------------
/support/dialog.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Cantata
3 | *
4 | * Copyright (c) 2011-2016 Craig Drummond
5 | *
6 | * ----
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation; either version 2 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program; see the file COPYING. If not, write to
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 | * Boston, MA 02110-1301, USA.
22 | */
23 |
24 | #include "dialog.h"
25 | #ifdef Q_OS_MAC
26 | #include "osxstyle.h"
27 | #endif
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | Dialog::Dialog(QWidget *parent, const QString &name, const QSize &defSize)
36 | : QDialog(parent)
37 | , defButton(0)
38 | , buttonTypes(0)
39 | , mw(0)
40 | , buttonBox(0)
41 | , shown(false) {
42 | if (!name.isEmpty()) {
43 | setObjectName(name);
44 | QSettings cfg;
45 | cfg.beginGroup(metaObject()->className());
46 | cfgSize = cfg.value(name + "/size", QSize()).toSize();
47 | if (!cfgSize.isEmpty()) {
48 | QDialog::resize(cfgSize);
49 | } else if (!defSize.isEmpty()) {
50 | QDialog::resize(defSize);
51 | }
52 | cfg.endGroup();
53 | }
54 |
55 | #ifdef Q_OS_MAC
56 | setWindowIcon(QIcon());
57 | #endif
58 | }
59 |
60 | Dialog::~Dialog() {
61 | if (!objectName().isEmpty() && size() != cfgSize) {
62 | QSettings cfg;
63 | cfg.beginGroup(metaObject()->className());
64 | cfg.setValue(objectName() + "/size", size());
65 | cfg.endGroup();
66 | }
67 | #ifdef Q_OS_MAC
68 | OSXStyle::self()->removeWindow(this);
69 | #endif
70 | }
71 |
72 | void Dialog::resize(const QSize &sz) {
73 | if (cfgSize.isEmpty()) {
74 | QDialog::resize(sz);
75 | cfgSize = sz;
76 | }
77 | QDialog::resize(sz);
78 | }
79 |
80 | #ifdef Q_OS_MAC
81 | Dialog::ButtonProxyStyle::ButtonProxyStyle()
82 | : QProxyStyle() {
83 | setBaseStyle(qApp->style());
84 | }
85 |
86 | int Dialog::ButtonProxyStyle::styleHint(StyleHint stylehint, const QStyleOption *opt, const QWidget *widget, QStyleHintReturn *returnData) const {
87 | if (QStyle::SH_DialogButtonLayout == stylehint) {
88 | return QDialogButtonBox::GnomeLayout;
89 | } else {
90 | return QProxyStyle::styleHint(stylehint, opt, widget, returnData);
91 | }
92 | }
93 |
94 | Dialog::ButtonProxyStyle * Dialog::buttonProxyStyle() {
95 | static ButtonProxyStyle *style = 0;
96 | if (!style) {
97 | style = new ButtonProxyStyle();
98 | }
99 | return style;
100 | }
101 | #endif
102 |
103 | static QDialogButtonBox::StandardButton mapType(int btn) {
104 | switch (btn) {
105 | case Dialog::Help: return QDialogButtonBox::Help;
106 | case Dialog::Ok: return QDialogButtonBox::Ok;
107 | case Dialog::Apply: return QDialogButtonBox::Apply;
108 | case Dialog::Cancel: return QDialogButtonBox::Cancel;
109 | case Dialog::Close: return QDialogButtonBox::Close;
110 | case Dialog::No: return QDialogButtonBox::No;
111 | case Dialog::Yes: return QDialogButtonBox::Yes;
112 | case Dialog::Reset: return QDialogButtonBox::Reset;
113 | default: return QDialogButtonBox::NoButton;
114 | }
115 | }
116 |
117 | void Dialog::setButtons(ButtonCodes buttons) {
118 | if (buttonBox && buttons == buttonTypes) {
119 | return;
120 | }
121 |
122 | QFlags btns;
123 | if (buttons & Help) {
124 | btns |= QDialogButtonBox::Help;
125 | }
126 | if (buttons & Ok) {
127 | btns |= QDialogButtonBox::Ok;
128 | }
129 | if (buttons & Apply) {
130 | btns |= QDialogButtonBox::Apply;
131 | }
132 | if (buttons & Cancel) {
133 | btns |= QDialogButtonBox::Cancel;
134 | }
135 | if (buttons & Close) {
136 | btns |= QDialogButtonBox::Close;
137 | }
138 | if (buttons & No) {
139 | btns |= QDialogButtonBox::No;
140 | }
141 | if (buttons & Yes) {
142 | btns |= QDialogButtonBox::Yes;
143 | }
144 | if (buttons & Reset) {
145 | btns |= QDialogButtonBox::Reset;
146 | }
147 |
148 | buttonTypes = (int)btns;
149 | bool needToCreate = true;
150 | if (buttonBox) {
151 | needToCreate = false;
152 | buttonBox->clear();
153 | buttonBox->setStandardButtons(btns);
154 | userButtons.clear();
155 | } else {
156 | buttonBox = new QDialogButtonBox(btns, Qt::Horizontal, this);
157 | #ifdef Q_OS_MAC
158 | buttonBox->setStyle(buttonProxyStyle());
159 | #endif
160 | }
161 |
162 | if (buttons & Help) {
163 | setButtonText(Help, tr("Help"));
164 | }
165 | if (buttons & Ok) {
166 | setButtonText(Ok, tr("OK"));
167 | }
168 | if (buttons & Apply) {
169 | setButtonText(Apply, tr("Apply"));
170 | }
171 | if (buttons & Cancel) {
172 | setButtonText(Cancel, tr("Cancel"));
173 | }
174 | if (buttons & Close) {
175 | setButtonText(Close, tr("Close"));
176 | }
177 | if (buttons & No) {
178 | setButtonText(No, tr("No"));
179 | }
180 | if (buttons & Yes) {
181 | setButtonText(Yes, tr("Yes"));
182 | }
183 | if (buttons & Reset) {
184 | setButtonText(Reset, tr("Reset"));
185 | }
186 |
187 | if (buttons & User3) {
188 | QPushButton *button = new QPushButton(buttonBox);
189 | userButtons.insert(User3, button);
190 | buttonBox->addButton(button, QDialogButtonBox::ActionRole);
191 | }
192 | if (buttons & User2) {
193 | QPushButton *button = new QPushButton(buttonBox);
194 | userButtons.insert(User2, button);
195 | buttonBox->addButton(button, QDialogButtonBox::ActionRole);
196 | }
197 | if (buttons & User1) {
198 | QPushButton *button = new QPushButton(buttonBox);
199 | userButtons.insert(User1, button);
200 | buttonBox->addButton(button, QDialogButtonBox::ActionRole);
201 | }
202 |
203 | if (needToCreate && mw && buttonBox) {
204 | create();
205 | }
206 | }
207 |
208 | void Dialog::setDefaultButton(ButtonCode button) {
209 | QAbstractButton *b = getButton(button);
210 | if (b) {
211 | qobject_cast(b)->setDefault(true);
212 | }
213 | defButton = button;
214 | }
215 |
216 | void Dialog::setButtonText(ButtonCode button, const QString &text) {
217 | QAbstractButton *b = getButton(button);
218 | if (b) {
219 | b->setText(text);
220 | }
221 | }
222 |
223 | void Dialog::setButtonIcon(ButtonCode button, const QIcon &icon) {
224 | QAbstractButton *b = getButton(button);
225 | if (b) {
226 | b->setIcon(icon);
227 | }
228 | }
229 |
230 | void Dialog::setButtonMenu(ButtonCode button, QMenu *menu) {
231 | QAbstractButton *b = getButton(button);
232 | if (b) {
233 | qobject_cast(b)->setMenu(menu);
234 | }
235 | }
236 |
237 | void Dialog::enableButton(ButtonCode button, bool enable) {
238 | QAbstractButton *b = getButton(button);
239 | if (b) {
240 | b->setEnabled(enable);
241 | }
242 | }
243 |
244 | bool Dialog::isButtonEnabled(ButtonCode button) {
245 | QAbstractButton *b = getButton(button);
246 | return b ? b->isEnabled() : false;
247 | }
248 |
249 | void Dialog::setMainWidget(QWidget *widget) {
250 | if (mw) {
251 | return;
252 | }
253 | mw = widget;
254 | if (mw && buttonBox) {
255 | create();
256 | }
257 | }
258 |
259 | void Dialog::slotButtonClicked(int button) {
260 | switch (button) {
261 | case Ok: accept(); break;
262 | case Cancel: reject(); break;
263 | case Close: reject(); break;
264 | default: break;
265 | }
266 | }
267 |
268 | void Dialog::buttonPressed(QAbstractButton *button) {
269 | if (buttonTypes & QDialogButtonBox::Help && button == buttonBox->button(QDialogButtonBox::Help)) {
270 | slotButtonClicked(Help);
271 | } else if (buttonTypes & QDialogButtonBox::Ok && button == buttonBox->button(QDialogButtonBox::Ok)) {
272 | slotButtonClicked(Ok);
273 | } else if (buttonTypes & QDialogButtonBox::Apply && button == buttonBox->button(QDialogButtonBox::Apply)) {
274 | slotButtonClicked(Apply);
275 | } else if (buttonTypes & QDialogButtonBox::Cancel && button == buttonBox->button(QDialogButtonBox::Cancel)) {
276 | slotButtonClicked(Cancel);
277 | } else if (buttonTypes & QDialogButtonBox::Close && button == buttonBox->button(QDialogButtonBox::Close)) {
278 | slotButtonClicked(Close);
279 | } else if (buttonTypes & QDialogButtonBox::No && button == buttonBox->button(QDialogButtonBox::No)) {
280 | slotButtonClicked(No);
281 | } else if (buttonTypes & QDialogButtonBox::Yes && button == buttonBox->button(QDialogButtonBox::Yes)) {
282 | slotButtonClicked(Yes);
283 | } else if (buttonTypes & QDialogButtonBox::Reset && button == buttonBox->button(QDialogButtonBox::Reset)) {
284 | slotButtonClicked(Reset);
285 | } else if (userButtons.contains(User1) && userButtons[User1] == button) {
286 | slotButtonClicked(User1);
287 | } else if (userButtons.contains(User2) && userButtons[User2] == button) {
288 | slotButtonClicked(User2);
289 | } else if (userButtons.contains(User3) && userButtons[User3] == button) {
290 | slotButtonClicked(User3);
291 | }
292 | }
293 |
294 | void Dialog::create() {
295 | QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
296 | layout->addWidget(mw);
297 | layout->addWidget(buttonBox);
298 | connect(buttonBox, SIGNAL(clicked(QAbstractButton *)), this, SLOT(buttonPressed(QAbstractButton *)));
299 | }
300 |
301 | QAbstractButton *Dialog::getButton(ButtonCode button) {
302 | QDialogButtonBox::StandardButton mapped = mapType(button);
303 | QAbstractButton *b = QDialogButtonBox::NoButton == mapped ? 0 : buttonBox->button(mapped);
304 | if (!b && userButtons.contains(button)) {
305 | b = userButtons[button];
306 | }
307 | return b;
308 | }
309 |
310 | void Dialog::showEvent(QShowEvent *e) {
311 | if (!shown) {
312 | shown = true;
313 | if (defButton) {
314 | setDefaultButton((ButtonCode)defButton);
315 | }
316 | if (buttonBox && mw) {
317 | QSize mwSize = mw->minimumSize();
318 | if (mwSize.width() < 16 || mwSize.height() < 16) {
319 | mwSize = mw->minimumSizeHint();
320 | }
321 | if (mwSize.width() > 15 && mwSize.height() > 15) {
322 | setMinimumHeight(qMax(minimumHeight(), buttonBox->height() + layout()->spacing() + mwSize.height() + (2 * layout()->margin())));
323 | setMinimumWidth(qMax(minimumWidth(), mwSize.width() + (2 * layout()->margin())));
324 | }
325 | }
326 | }
327 | #ifdef Q_OS_MAC
328 | if (!isModal()) {
329 | OSXStyle::self()->addWindow(this);
330 | }
331 | #endif
332 | QDialog::showEvent(e);
333 | }
334 |
335 | #ifdef Q_OS_MAC
336 | void Dialog::hideEvent(QHideEvent *e) {
337 | OSXStyle::self()->removeWindow(this);
338 | QDialog::hideEvent(e);
339 | }
340 |
341 | void Dialog::closeEvent(QCloseEvent *e) {
342 | OSXStyle::self()->removeWindow(this);
343 | QDialog::closeEvent(e);
344 | }
345 | #endif
346 |
--------------------------------------------------------------------------------
/support/dialog.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Cantata
3 | *
4 | * Copyright (c) 2011-2016 Craig Drummond
5 | *
6 | * ----
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation; either version 2 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program; see the file COPYING. If not, write to
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 | * Boston, MA 02110-1301, USA.
22 | */
23 |
24 | #ifndef DIALOG_H
25 | #define DIALOG_H
26 |
27 |
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #ifdef Q_OS_MAC
34 | #include
35 | #endif
36 |
37 | class QAbstractButton;
38 | class QMenu;
39 |
40 | class Dialog : public QDialog {
41 | Q_OBJECT
42 | Q_ENUMS(ButtonCode)
43 |
44 | public:
45 |
46 | #ifdef Q_OS_MAC
47 | class ButtonProxyStyle : public QProxyStyle {
48 | public:
49 | ButtonProxyStyle();
50 |
51 | int styleHint(StyleHint stylehint, const QStyleOption *opt, const QWidget *widget, QStyleHintReturn *returnData) const;
52 | };
53 |
54 | static ButtonProxyStyle * buttonProxyStyle();
55 | #endif
56 |
57 | enum ButtonCode {
58 | None = 0x00000000,
59 | Help = 0x00000001, ///< Show Help button. (this button will run the help set with setHelp)
60 | Default = 0x00000002, ///< Show Default button.
61 | Ok = 0x00000004, ///< Show Ok button. (this button accept()s the dialog; result set to QDialog::Accepted)
62 | Apply = 0x00000008, ///< Show Apply button.
63 | Try = 0x00000010, ///< Show Try button.
64 | Cancel = 0x00000020, ///< Show Cancel-button. (this button reject()s the dialog; result set to QDialog::Rejected)
65 | Close = 0x00000040, ///< Show Close-button. (this button closes the dialog)
66 | No = 0x00000080, ///< Show No button. (this button closes the dialog and sets the result to KDialog::No)
67 | Yes = 0x00000100, ///< Show Yes button. (this button closes the dialog and sets the result to KDialog::Yes)
68 | Reset = 0x00000200, ///< Show Reset button
69 | Details = 0x00000400, ///< Show Details button. (this button will show the detail widget set with setDetailsWidget)
70 | User1 = 0x00001000, ///< Show User defined button 1.
71 | User2 = 0x00002000, ///< Show User defined button 2.
72 | User3 = 0x00004000, ///< Show User defined button 3.
73 | NoDefault = 0x00008000 ///< Used when specifying a default button; indicates that no button should be marked by default.
74 | };
75 | Q_DECLARE_FLAGS(ButtonCodes, ButtonCode)
76 | enum ButtonPopupMode {
77 | InstantPopup = 0,
78 | DelayedPopup = 1
79 | };
80 |
81 | Dialog(QWidget *parent, const QString &name = QString(), const QSize &defSize = QSize());
82 | virtual ~Dialog();
83 |
84 | void setCaption(const QString &cap) {
85 | setWindowTitle(cap);
86 | }
87 | void setButtons(ButtonCodes buttons);
88 | void setDefaultButton(ButtonCode button);
89 | void setButtonText(ButtonCode button, const QString &text);
90 | void setButtonIcon(ButtonCode button, const QIcon &icon);
91 | void setButtonMenu(ButtonCode button, QMenu *menu);
92 | void enableButton(ButtonCode button, bool enable);
93 | void enableButtonOk(bool enable) {
94 | enableButton(Ok, enable);
95 | }
96 | bool isButtonEnabled(ButtonCode button);
97 | void setMainWidget(QWidget *widget);
98 | virtual void slotButtonClicked(int button);
99 | QWidget * mainWidget() {
100 | return mw;
101 | }
102 |
103 | const QSize & configuredSize() const {
104 | return cfgSize;
105 | }
106 | void resize(int w, int h) {
107 | resize(QSize(w, h));
108 | }
109 | void resize(const QSize &sz);
110 |
111 | #ifdef Q_OS_MAC
112 | virtual void hideEvent(QHideEvent *e);
113 | virtual void closeEvent(QCloseEvent *e);
114 | #endif
115 |
116 | private Q_SLOTS:
117 | void buttonPressed(QAbstractButton *button);
118 |
119 | private:
120 | void create();
121 | QAbstractButton *getButton(ButtonCode button);
122 | virtual void showEvent(QShowEvent *e);
123 |
124 | private:
125 | int defButton;
126 | int buttonTypes;
127 | QWidget *mw;
128 | QDialogButtonBox *buttonBox;
129 | QMap userButtons;
130 | QSize cfgSize;
131 | bool shown;
132 | };
133 |
134 | Q_DECLARE_OPERATORS_FOR_FLAGS(Dialog::ButtonCodes)
135 |
136 | #endif
137 |
--------------------------------------------------------------------------------
/support/messagebox.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Cantata
3 | *
4 | * Copyright (c) 2011-2016 Craig Drummond
5 | *
6 | * ----
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation; either version 2 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program; see the file COPYING. If not, write to
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 | * Boston, MA 02110-1301, USA.
22 | */
23 |
24 | #include "messagebox.h"
25 | #include "dialog.h"
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | #ifdef Q_OS_MAC
32 | static void splitMessage(const QString &orig, QString &msg, QString &sub) {
33 | static QStringList constSeps = QStringList() << QLatin1String("\n\n") << QLatin1String("
");
34 | msg = orig;
35 |
36 | foreach (const QString &sep, constSeps) {
37 | QStringList parts = orig.split(sep);
38 | if (parts.count() > 1) {
39 | msg = parts.takeAt(0);
40 | sub = parts.join(sep);
41 | return;
42 | }
43 | }
44 | }
45 |
46 | void MessageBox::error(QWidget *parent, const QString &message, const QString &title) {
47 | QString msg;
48 | QString sub;
49 | splitMessage(message, msg, sub);
50 | QMessageBox box(QMessageBox::Critical, title.isEmpty() ? i18n("Error") : title, msg, QMessageBox::Ok, parent, Qt::Sheet);
51 | box.setInformativeText(sub);
52 | box.exec();
53 | }
54 |
55 | void MessageBox::information(QWidget *parent, const QString &message, const QString &title) {
56 | QString msg;
57 | QString sub;
58 | splitMessage(message, msg, sub);
59 | QMessageBox box(QMessageBox::Information, title.isEmpty() ? i18n("Information") : title, msg, QMessageBox::Ok, parent, Qt::Sheet);
60 | box.setInformativeText(sub);
61 | box.exec();
62 | }
63 | #endif
64 |
65 | QMessageBox::StandardButton MessageBox::questionYesNoCancel(QWidget *parent, const QString &message, const QString &title,
66 | const QString &yesText, const QString &noText, bool showCancel, bool isWarning) {
67 | QMessageBox msg(parent);
68 | #ifdef Q_OS_MAC
69 | QString mainText;
70 | QString subText;
71 | splitMessage(message, mainText, subText);
72 | msg.setText(mainText);
73 | msg.setInformativeText(subText);
74 | #else
75 | msg.setText(message);
76 | #endif
77 | msg.setIcon(isWarning ? QMessageBox::Warning : QMessageBox::Question);
78 | msg.setWindowTitle(title.isEmpty() ? (isWarning ? QObject::tr("Warning") : QObject::tr("Question")) : title);
79 | QPushButton *yesBtn = msg.addButton(yesText.isEmpty() ? QObject::tr("Yes") : yesText, QMessageBox::YesRole);
80 | QPushButton *noBtn = msg.addButton(noText.isEmpty() ? QObject::tr("No") : noText, QMessageBox::NoRole);
81 | if (showCancel) {
82 | msg.addButton(QMessageBox::Cancel);
83 | }
84 | msg.exec();
85 |
86 | QAbstractButton *clicked = msg.clickedButton();
87 | return yesBtn == clicked
88 | ? QMessageBox::Yes
89 | : noBtn == clicked
90 | ? QMessageBox::No
91 | : QMessageBox::Cancel;
92 | }
93 |
94 | namespace MessageBox {
95 | class YesNoListDialog : public Dialog {
96 | public:
97 | YesNoListDialog(QWidget *p) : Dialog(p) { }
98 | void slotButtonClicked(int b) {
99 | switch (b) {
100 | case Dialog::Ok:
101 | case Dialog::Yes:
102 | accept();
103 | break;
104 | case Dialog::No:
105 | reject();
106 | break;
107 | }
108 | }
109 | };
110 | }
111 |
112 | QMessageBox::StandardButton MessageBox::msgListEx(QWidget *parent, QMessageBox::Icon type, const QString &message, const QStringList &strlist, const QString &title) {
113 | MessageBox::YesNoListDialog *dlg = new MessageBox::YesNoListDialog(parent);
114 | dlg->setAttribute(Qt::WA_DeleteOnClose);
115 | QWidget *wid = new QWidget(dlg);
116 | QGridLayout *lay = new QGridLayout(wid);
117 | QLabel *iconLabel = new QLabel(wid);
118 | int iconSize = 64; // Icon::dlgIconSize();
119 | iconLabel->setFixedSize(iconSize, iconSize);
120 | switch (type) {
121 | case QMessageBox::Critical:
122 | dlg->setCaption(title.isEmpty() ? QObject::tr("Error") : title);
123 | dlg->setButtons(Dialog::Ok);
124 | iconLabel->setPixmap(QIcon::fromTheme("dialog-error").pixmap(iconSize, iconSize));
125 | break;
126 | case QMessageBox::Question:
127 | dlg->setCaption(title.isEmpty() ? QObject::tr("Question") : title);
128 | dlg->setButtons(Dialog::Yes | Dialog::No);
129 | iconLabel->setPixmap(QIcon::fromTheme("dialog-question").pixmap(iconSize, iconSize));
130 | break;
131 | case QMessageBox::Warning:
132 | dlg->setCaption(title.isEmpty() ? QObject::tr("Warning") : title);
133 | dlg->setButtons(Dialog::Yes | Dialog::No);
134 | iconLabel->setPixmap(QIcon::fromTheme("dialog-warning").pixmap(iconSize, iconSize));
135 | break;
136 | case QMessageBox::Information:
137 | dlg->setCaption(title.isEmpty() ? QObject::tr("Information") : title);
138 | dlg->setButtons(Dialog::Ok);
139 | iconLabel->setPixmap(QIcon::fromTheme("dialog-information").pixmap(iconSize, iconSize));
140 | break;
141 | }
142 | lay->addWidget(iconLabel, 0, 0, 1, 1);
143 | QLabel *msgLabel = new QLabel(message, wid);
144 | msgLabel->setWordWrap(true);
145 | msgLabel->setTextInteractionFlags(Qt::NoTextInteraction);
146 | lay->addWidget(msgLabel, 0, 1, 1, 1);
147 | QListWidget *list = new QListWidget(wid);
148 | lay->addWidget(list, 1, 0, 1, 2);
149 | lay->setMargin(0);
150 | list->insertItems(0, strlist);
151 | dlg->setMainWidget(wid);
152 | #ifdef Q_OS_MAC
153 | dlg->setWindowFlags((dlg->windowFlags() & (~Qt::WindowType_Mask)) | Qt::Sheet);
154 | #endif
155 | return QDialog::Accepted == dlg->exec() ? QMessageBox::Yes : QMessageBox::No;
156 | }
157 |
--------------------------------------------------------------------------------
/support/messagebox.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Cantata
3 | *
4 | * Copyright (c) 2011-2016 Craig Drummond
5 | *
6 | * ----
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation; either version 2 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program; see the file COPYING. If not, write to
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 | * Boston, MA 02110-1301, USA.
22 | */
23 |
24 | #ifndef MESSAGE_BOX_H
25 | #define MESSAGE_BOX_H
26 |
27 | #include
28 |
29 | namespace MessageBox {
30 |
31 | extern QMessageBox::StandardButton questionYesNoCancel(QWidget *parent, const QString &message, const QString &title = QString(),
32 | const QString &yesText = QString(), const QString &noText = QString(), bool showCancel = true, bool isWarning = false);
33 | inline QMessageBox::StandardButton questionYesNo(QWidget *parent, const QString &message, const QString &title = QString(), const QString &yesText = QString(),
34 | const QString &noText = QString()) {
35 | return questionYesNoCancel(parent, message, title, yesText, noText, false);
36 | }
37 | inline QMessageBox::StandardButton warningYesNoCancel(QWidget *parent, const QString &message, const QString &title = QString(),
38 | const QString &yesText = QString(), const QString &noText = QString()) {
39 | return questionYesNoCancel(parent, message, title, yesText, noText, true, true);
40 | }
41 | inline QMessageBox::StandardButton warningYesNo(QWidget *parent, const QString &message, const QString &title = QString(), const QString &yesText = QString(), const QString &noText = QString()) {
42 | return questionYesNoCancel(parent, message, title, yesText, noText, false, true);
43 | }
44 | #ifdef Q_OS_MAC
45 | extern void error(QWidget *parent, const QString &message, const QString &title = QString());
46 | extern void information(QWidget *parent, const QString &message, const QString &title = QString());
47 | #else
48 | inline void error(QWidget *parent, const QString &message, const QString &title = QString()) {
49 | QMessageBox::critical(parent, title.isEmpty() ? QObject::tr("Error") : title, message);
50 | }
51 | inline void information(QWidget *parent, const QString &message, const QString &title = QString()) {
52 | QMessageBox::information(parent, title.isEmpty() ? QObject::tr("Information") : title, message);
53 | }
54 | #endif
55 | extern QMessageBox::StandardButton msgListEx(QWidget *parent, QMessageBox::Icon type, const QString &message, const QStringList &strlist, const QString &title = QString());
56 | inline void errorListEx(QWidget *parent, const QString &message, const QStringList &strlist, const QString &title = QString()) {
57 | msgListEx(parent, QMessageBox::Critical, message, strlist, title);
58 | }
59 | inline void errorList(QWidget *parent, const QString &message, const QStringList &strlist, const QString &title = QString()) {
60 | msgListEx(parent, QMessageBox::Critical, message, strlist, title);
61 | }
62 | inline QMessageBox::StandardButton questionYesNoList(QWidget *parent, const QString &message, const QStringList &strlist, const QString &title = QString()) {
63 | return msgListEx(parent, QMessageBox::Question, message, strlist, title);
64 | }
65 | inline QMessageBox::StandardButton warningYesNoList(QWidget *parent, const QString &message, const QStringList &strlist, const QString &title = QString()) {
66 | return msgListEx(parent, QMessageBox::Warning, message, strlist, title);
67 | }
68 | inline void informationList(QWidget *parent, const QString &message, const QStringList &strlist, const QString &title = QString()) {
69 | msgListEx(parent, QMessageBox::Information, message, strlist, title);
70 | }
71 |
72 | }
73 |
74 | #endif
75 |
--------------------------------------------------------------------------------
/support/pagewidget.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Cantata
3 | *
4 | * Copyright (c) 2011-2014 Craig Drummond
5 | *
6 | * ----
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation; either version 2 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program; see the file COPYING. If not, write to
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 | * Boston, MA 02110-1301, USA.
22 | */
23 |
24 | #include "pagewidget.h"
25 | //#include "gtkstyle.h"
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | static int layoutText(QTextLayout *layout, int maxWidth) {
37 | qreal height = 0;
38 | int textWidth = 0;
39 | layout->beginLayout();
40 | while (true) {
41 | QTextLine line = layout->createLine();
42 | if (!line.isValid()) {
43 | break;
44 | }
45 | line.setLineWidth(maxWidth);
46 | line.setPosition(QPointF(0, height));
47 | height += line.height();
48 | textWidth = qMax(textWidth, qRound(line.naturalTextWidth() + 0.5));
49 | }
50 | layout->endLayout();
51 | return textWidth;
52 | }
53 |
54 | class PageWidgetItemDelegate : public QAbstractItemDelegate {
55 | public:
56 | PageWidgetItemDelegate(QObject *parent)
57 | : QAbstractItemDelegate(parent)
58 | , underMouse(false) {
59 | int height = QApplication::fontMetrics().height();
60 | iconSize = height > 22 ? 48 : 32;
61 | }
62 |
63 | void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
64 | if (!index.isValid()) {
65 | return;
66 | }
67 | bool mouseOver = option.state & QStyle::State_MouseOver;
68 | bool gtk = mouseOver && qApp->style()->inherits("QGtkStyle");
69 | bool selected = option.state & QStyle::State_Selected;
70 | bool drawBgnd = true;
71 |
72 | if (!underMouse) {
73 | if (mouseOver && !selected) {
74 | drawBgnd = false;
75 | }
76 | mouseOver = false;
77 | }
78 |
79 | const QString text = index.model()->data(index, Qt::DisplayRole).toString();
80 | const QIcon icon = index.model()->data(index, Qt::DecorationRole).value();
81 | const QPixmap pixmap = icon.pixmap(iconSize, iconSize);
82 |
83 | QFontMetrics fm = painter->fontMetrics();
84 | int wp = pixmap.width();
85 | int hp = pixmap.height();
86 |
87 | QTextLayout iconTextLayout(text, option.font);
88 | QTextOption textOption(Qt::AlignHCenter);
89 | iconTextLayout.setTextOption(textOption);
90 | int maxWidth = qMax(3 * wp, 8 * fm.height());
91 | layoutText(&iconTextLayout, maxWidth);
92 |
93 | QPen pen = painter->pen();
94 | QPalette::ColorGroup cg = option.state & QStyle::State_Enabled
95 | ? QPalette::Normal : QPalette::Disabled;
96 | if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) {
97 | cg = QPalette::Inactive;
98 | }
99 |
100 | QStyleOptionViewItem opt(option);
101 | opt.showDecorationSelected = true;
102 | QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
103 |
104 | if (drawBgnd) {
105 | if (mouseOver && gtk) {
106 | painter->save();
107 | opt.state |= QStyle::State_Selected;
108 | painter->setOpacity(selected ? 0.75 : 0.25);
109 | }
110 | style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget);
111 | if (mouseOver && gtk) {
112 | painter->restore();
113 | }
114 | }
115 |
116 | if (selected) {
117 | painter->setPen(option.palette.color(cg, QPalette::HighlightedText));
118 | } else {
119 | painter->setPen(option.palette.color(cg, QPalette::Text));
120 | }
121 |
122 | painter->drawPixmap(option.rect.x() + (option.rect.width() / 2) - (wp / 2), option.rect.y() + 5, pixmap);
123 | if (!text.isEmpty()) {
124 | iconTextLayout.draw(painter, QPoint(option.rect.x() + (option.rect.width() / 2) - (maxWidth / 2), option.rect.y() + hp + 7));
125 | }
126 | painter->setPen(pen);
127 | drawFocus(painter, option, option.rect);
128 | }
129 |
130 | QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
131 | if (!index.isValid()) {
132 | return QSize(0, 0);
133 | }
134 |
135 | const QString text = index.model()->data(index, Qt::DisplayRole).toString();
136 | const QIcon icon = index.model()->data(index, Qt::DecorationRole).value();
137 | const QPixmap pixmap = icon.pixmap(iconSize, iconSize);
138 |
139 | QFontMetrics fm = option.fontMetrics;
140 | int gap = fm.height();
141 | int wp = pixmap.width();
142 | int hp = pixmap.height();
143 |
144 | if (hp == 0) {
145 | /**
146 | * No pixmap loaded yet, we'll use the default icon size in this case.
147 | */
148 | hp = iconSize;
149 | wp = iconSize;
150 | }
151 |
152 | QTextLayout iconTextLayout(text, option.font);
153 | int wt = layoutText(&iconTextLayout, qMax(3 * wp, 8 * fm.height()));
154 | int ht = iconTextLayout.boundingRect().height();
155 |
156 | int width, height;
157 | if (text.isEmpty()) {
158 | height = hp;
159 | } else {
160 | height = hp + ht + 10;
161 |
162 | }
163 |
164 | width = qMax(wt, wp) + gap;
165 | return QSize(width, height);
166 | }
167 |
168 | void drawFocus(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect) const {
169 | if (option.state & QStyle::State_HasFocus) {
170 | QStyleOptionFocusRect o;
171 | o.QStyleOption::operator=(option);
172 | o.rect = rect;
173 | o.state |= QStyle::State_KeyboardFocusChange;
174 | QPalette::ColorGroup cg = (option.state & QStyle::State_Enabled)
175 | ? QPalette::Normal : QPalette::Disabled;
176 | o.backgroundColor = option.palette.color(cg, (option.state & QStyle::State_Selected)
177 | ? QPalette::Highlight : QPalette::Background);
178 | QApplication::style()->drawPrimitive(QStyle::PE_FrameFocusRect, &o, painter);
179 | }
180 | }
181 |
182 | void setUnderMouse(bool u) {
183 | underMouse = u;
184 | }
185 |
186 | private:
187 | int iconSize;
188 | bool underMouse;
189 | };
190 |
191 | class PageWidgetViewEventHandler : public QObject {
192 | public:
193 | PageWidgetViewEventHandler(PageWidgetItemDelegate *d, QListWidget *v)
194 | : QObject(v)
195 | , delegate(d)
196 | , view(v) {
197 | }
198 |
199 | protected:
200 | bool eventFilter(QObject *obj, QEvent *event) {
201 | if (delegate) {
202 | if (QEvent::Enter == event->type()) {
203 | delegate->setUnderMouse(true);
204 | view->viewport()->update();
205 | } else if (QEvent::Leave == event->type()) {
206 | delegate->setUnderMouse(false);
207 | view->viewport()->update();
208 | }
209 | }
210 | return QObject::eventFilter(obj, event);
211 | }
212 |
213 | protected:
214 | PageWidgetItemDelegate *delegate;
215 | QListWidget *view;
216 | };
217 |
218 | PageWidgetItem::PageWidgetItem(QWidget *p, const QString &header, const QIcon &icon, QWidget *cfg)
219 | : QWidget(p)
220 | , wid(cfg) {
221 | static int size = -1;
222 |
223 | if (-1 == size) {
224 | size = QApplication::fontMetrics().height();
225 | if (size > 20) {
226 | size = 32;
227 | } else {
228 | size = 22;
229 | }
230 | }
231 |
232 | QBoxLayout *layout = new QBoxLayout(QBoxLayout::TopToBottom, this);
233 | QBoxLayout *titleLayout = new QBoxLayout(QBoxLayout::LeftToRight, 0);
234 | titleLayout->addWidget(new QLabel("" + header + "", this));
235 | titleLayout->addItem(new QSpacerItem(16, 16, QSizePolicy::Expanding, QSizePolicy::Minimum));
236 |
237 | QLabel *icn = new QLabel(this);
238 | icn->setPixmap(icon.pixmap(size, size));
239 | titleLayout->addWidget(icn);
240 | layout->addLayout(titleLayout);
241 | layout->addItem(new QSpacerItem(8, 8, QSizePolicy::Fixed, QSizePolicy::Fixed));
242 | layout->addWidget(cfg);
243 | layout->setMargin(0);
244 | cfg->setParent(this);
245 | cfg->adjustSize();
246 | adjustSize();
247 | }
248 |
249 | PageWidget::PageWidget(QWidget *p)
250 | : QWidget(p) {
251 | QBoxLayout *layout = new QBoxLayout(QBoxLayout::LeftToRight, this);
252 | list = new QListWidget(p);
253 | stack = new QStackedWidget(p);
254 | connect(list, SIGNAL(currentRowChanged(int)), stack, SLOT(setCurrentIndex(int)));
255 | connect(stack, SIGNAL(currentChanged(int)), this, SIGNAL(currentPageChanged()));
256 | layout->addWidget(list);
257 | layout->addWidget(stack);
258 | layout->setMargin(0);
259 | list->setViewMode(QListView::ListMode);
260 | list->setVerticalScrollMode(QListView::ScrollPerPixel);
261 | list->setMovement(QListView::Static);
262 | PageWidgetItemDelegate *delegate = new PageWidgetItemDelegate(list);
263 | list->setItemDelegate(delegate);
264 | list->setSelectionBehavior(QAbstractItemView::SelectItems);
265 | list->setSelectionMode(QAbstractItemView::SingleSelection);
266 | list->setAttribute(Qt::WA_MouseTracking);
267 | list->installEventFilter(new PageWidgetViewEventHandler(delegate, list));
268 | }
269 |
270 | PageWidgetItem * PageWidget::addPage(QWidget *widget, const QString &name, const QIcon &icon, const QString &header) {
271 | PageWidgetItem *page = new PageWidgetItem(stack, header, icon, widget);
272 | QListWidgetItem *listItem = new QListWidgetItem(name, list);
273 | listItem->setIcon(icon);
274 | stack->addWidget(page);
275 | list->addItem(listItem);
276 |
277 | int rows = list->model()->rowCount();
278 | int width = 0;
279 | int height = 0;
280 | for (int i = 0; i < rows; ++i) {
281 | QSize rowSize = list->sizeHintForIndex(list->model()->index(i, 0));
282 | width = qMax(width, rowSize.width());
283 | height += rowSize.height();
284 | }
285 | width += 25;
286 | list->setFixedWidth(width);
287 | list->setMinimumHeight(height);
288 |
289 | QSize stackSize = stack->size();
290 | for (int i = 0; i < stack->count(); ++i) {
291 | const QWidget *widget = stack->widget(i);
292 | if (widget) {
293 | stackSize = stackSize.expandedTo(widget->minimumSizeHint());
294 | }
295 | }
296 | stack->setMinimumSize(stackSize);
297 |
298 | QSize sz = size();
299 | sz = sz.expandedTo(stackSize);
300 | sz = sz.expandedTo(QSize(width, height));
301 | setMinimumSize(sz);
302 | list->setCurrentRow(0);
303 | stack->setCurrentIndex(0);
304 | pages.insert(listItem, page);
305 | return page;
306 | }
307 |
308 | int PageWidget::count() {
309 | return list->count();
310 | }
311 |
312 | PageWidgetItem * PageWidget::currentPage() const {
313 | return static_cast(stack->currentWidget());
314 | }
315 |
316 | void PageWidget::setCurrentPage(PageWidgetItem *item) {
317 | if (!item) {
318 | return;
319 | }
320 |
321 | QMap::ConstIterator it(pages.constBegin());
322 | QMap::ConstIterator end(pages.constEnd());
323 |
324 | for (; it != end; ++it) {
325 | if (it.value() == item) {
326 | list->setCurrentItem(it.key());
327 | }
328 | }
329 | }
330 |
--------------------------------------------------------------------------------
/support/pagewidget.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Cantata
3 | *
4 | * Copyright (c) 2011-2014 Craig Drummond
5 | *
6 | * ----
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation; either version 2 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program; see the file COPYING. If not, write to
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 | * Boston, MA 02110-1301, USA.
22 | */
23 |
24 | #ifndef PAGEWIDGET_H
25 | #define PAGEWIDGET_H
26 |
27 | #include
28 | #include
29 |
30 | class QIcon;
31 | class QListWidget;
32 | class QListWidgetItem;
33 | class QStackedWidget;
34 |
35 | class PageWidgetItem : public QWidget {
36 | public:
37 | PageWidgetItem(QWidget *p, const QString &header, const QIcon &icon, QWidget *cfg);
38 | virtual ~PageWidgetItem() { }
39 | QWidget * widget() const {
40 | return wid;
41 | }
42 |
43 | private:
44 | QWidget *wid;
45 | };
46 |
47 | class PageWidget : public QWidget {
48 | Q_OBJECT
49 |
50 | public:
51 | PageWidget(QWidget *p);
52 | virtual ~PageWidget() { }
53 | PageWidgetItem * addPage(QWidget *widget, const QString &name, const QIcon &icon, const QString &header);
54 | int count();
55 | PageWidgetItem * currentPage() const;
56 | void setCurrentPage(PageWidgetItem *item);
57 |
58 | Q_SIGNALS:
59 | void currentPageChanged();
60 |
61 | private:
62 | QListWidget *list;
63 | QStackedWidget *stack;
64 | QMap pages;
65 | };
66 |
67 | #endif
68 |
--------------------------------------------------------------------------------
/support/pathrequester.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Cantata
3 | *
4 | * Copyright (c) 2011-2014 Craig Drummond
5 | *
6 | * ----
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation; either version 2 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program; see the file COPYING. If not, write to
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 | * Boston, MA 02110-1301, USA.
22 | */
23 |
24 | #include "pathrequester.h"
25 | #include "utils.h"
26 | #include
27 | #include
28 | #include
29 |
30 | PathRequester::PathRequester(QWidget *parent)
31 | : QWidget(parent)
32 | , dirMode(true) {
33 | QHBoxLayout *layout = new QHBoxLayout(this);
34 | layout->setContentsMargins(0, 0, 0, 0);
35 | edit = new QLineEdit(this);
36 | btn = new QToolButton(this);
37 | layout->addWidget(edit);
38 | layout->addWidget(btn);
39 | btn->setAutoRaise(true);
40 | btn->setIcon(QIcon::fromTheme("document-open"));
41 | connect(btn, SIGNAL(clicked(bool)), SLOT(choose()));
42 | connect(edit, SIGNAL(textChanged(const QString &)), SIGNAL(textChanged(const QString &)));
43 | }
44 |
45 | void PathRequester::choose() {
46 | QString item = dirMode
47 | ? QFileDialog::getExistingDirectory(this, tr("Select Folder"), edit->text())
48 | : QFileDialog::getOpenFileName(this, tr("Select File"), Utils::getDir(edit->text()), filter);
49 | if (!item.isEmpty()) {
50 | edit->setText(item);
51 | }
52 | }
53 |
54 | void PathRequester::setEnabled(bool e) {
55 | edit->setEnabled(e);
56 | btn->setEnabled(e);
57 | }
58 |
--------------------------------------------------------------------------------
/support/pathrequester.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Cantata
3 | *
4 | * Copyright (c) 2011-2014 Craig Drummond
5 | *
6 | * ----
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation; either version 2 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program; see the file COPYING. If not, write to
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 | * Boston, MA 02110-1301, USA.
22 | */
23 |
24 | #ifndef PATH_REQUESER_H
25 | #define PATH_REQUESER_H
26 |
27 | #include
28 | #include
29 |
30 | class PathRequester : public QWidget {
31 | Q_OBJECT
32 | public:
33 | PathRequester(QWidget *parent);
34 | virtual ~PathRequester() { }
35 |
36 | QString text() const {
37 | return edit->text();
38 | }
39 | void setText(const QString &t) {
40 | edit->setText(t);
41 | }
42 | void setButtonVisible(bool v) {
43 | btn->setVisible(v);
44 | }
45 | void setFocus() {
46 | edit->setFocus();
47 | }
48 | void setDirMode(bool m) {
49 | dirMode = m;
50 | }
51 | QLineEdit * lineEdit() const {
52 | return edit;
53 | }
54 | QToolButton * button() const {
55 | return btn;
56 | }
57 | void setFilter(const QString &f) {
58 | filter = f;
59 | }
60 |
61 | public Q_SLOTS:
62 | void setEnabled(bool e);
63 |
64 | Q_SIGNALS:
65 | void textChanged(const QString &);
66 |
67 | private Q_SLOTS:
68 | void choose();
69 |
70 | private:
71 | QLineEdit *edit;
72 | QToolButton *btn;
73 | bool dirMode;
74 | QString filter;
75 | };
76 |
77 | #endif
78 |
--------------------------------------------------------------------------------
/support/squeezedtextlabel.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Cantata
3 | *
4 | * Copyright (c) 2011-2016 Craig Drummond
5 | *
6 | * ----
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation; either version 2 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program; see the file COPYING. If not, write to
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 | * Boston, MA 02110-1301, USA.
22 | */
23 |
24 | #include "squeezedtextlabel.h"
25 |
26 | #ifdef ENABLE_KDE_SUPPORT
27 |
28 | SqueezedTextLabel::SqueezedTextLabel(QWidget *p)
29 | : KSqueezedTextLabel(p) {
30 | bool rtl = Qt::RightToLeft == layoutDirection();
31 | setTextElideMode(rtl ? Qt::ElideLeft : Qt::ElideRight);
32 | setAlignment((rtl ? Qt::AlignRight : Qt::AlignLeft) | Qt::AlignVCenter);
33 | }
34 |
35 | #else
36 |
37 | SqueezedTextLabel::SqueezedTextLabel(QWidget *p)
38 | : QLabel(p) {
39 | bool rtl = Qt::RightToLeft == layoutDirection();
40 |
41 | setTextElideMode(rtl ? Qt::ElideLeft : Qt::ElideRight);
42 | setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
43 | }
44 |
45 | void SqueezedTextLabel::setTextElideMode(Qt::TextElideMode mode) {
46 | elideMode = mode;
47 | setAlignment((elideMode & Qt::ElideLeft ? Qt::AlignRight : Qt::AlignLeft) | Qt::AlignVCenter);
48 | }
49 |
50 | void SqueezedTextLabel::elideText() {
51 | QFontMetrics fm(fontMetrics());
52 | int labelWidth = size().width();
53 | int lineWidth = fm.width(originalText);
54 |
55 | if (lineWidth > labelWidth) {
56 | QLabel::setText(fm.elidedText(originalText, elideMode, labelWidth));
57 | setToolTip(originalText);
58 | } else {
59 | QLabel::setText(originalText);
60 | setToolTip(QString());
61 | }
62 | }
63 |
64 | #endif
65 |
--------------------------------------------------------------------------------
/support/squeezedtextlabel.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Cantata
3 | *
4 | * Copyright (c) 2011-2014 Craig Drummond
5 | *
6 | * ----
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation; either version 2 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program; see the file COPYING. If not, write to
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 | * Boston, MA 02110-1301, USA.
22 | */
23 |
24 | #ifndef SQUEEZEDTEXTLABEL_H
25 | #define SQUEEZEDTEXTLABEL_H
26 |
27 | #ifdef ENABLE_KDE_SUPPORT
28 | #include
29 | class SqueezedTextLabel : public KSqueezedTextLabel {
30 | public:
31 | SqueezedTextLabel(QWidget *p);
32 | };
33 | #else
34 | #include
35 | #include
36 | class QResizeEvent;
37 |
38 | class SqueezedTextLabel : public QLabel {
39 | public:
40 | SqueezedTextLabel(QWidget *p);
41 |
42 | void setText(const QString &text) {
43 | originalText = text;
44 | elideText();
45 | }
46 | const QString & fullText() const {
47 | return originalText;
48 | }
49 | void setTextElideMode(Qt::TextElideMode mode);
50 |
51 | protected:
52 | QSize minimumSizeHint() const {
53 | QSize sh = QLabel::minimumSizeHint();
54 | sh.setWidth(-1);
55 | return sh;
56 | }
57 |
58 | QSize sizeHint() const {
59 | return QSize(fontMetrics().width(originalText), QLabel::sizeHint().height());
60 | }
61 | void resizeEvent(QResizeEvent *) {
62 | elideText();
63 | }
64 |
65 | private:
66 | void elideText();
67 |
68 | private:
69 | QString originalText;
70 | Qt::TextElideMode elideMode;
71 | };
72 | #endif
73 |
74 | #endif // SQUEEZEDTEXTLABEL_H
75 |
--------------------------------------------------------------------------------
/support/utils.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Cantata
3 | *
4 | * Copyright (c) 2011-2014 Craig Drummond
5 | *
6 | * ----
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation; either version 2 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program; see the file COPYING. If not, write to
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 | * Boston, MA 02110-1301, USA.
22 | */
23 |
24 | #ifndef UTILS_H
25 | #define UTILS_H
26 |
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | class QString;
37 | class QWidget;
38 |
39 | namespace Utils {
40 | extern QLatin1Char constDirSep;
41 | extern QLatin1String constDirSepStr;
42 | extern const char * constDirSepCharStr;
43 |
44 | inline bool equal(double d1, double d2, double precision = 0.0001) {
45 | return (fabs(d1 - d2) < precision);
46 | }
47 | inline int random(int max) {
48 | return ::random() % max;
49 | }
50 |
51 | extern QString strippedText(QString s);
52 | extern QString stripAcceleratorMarkers(QString label);
53 | extern QString fixPath(const QString &d);
54 | // Convert directory to a format suitable fo rUI - e.g. use native separators, and remove any traling separator
55 | extern QString convertDirForDisplay(const QString &dir);
56 | // Convert directory from a UI field - convert to / separators, and add a trailing separator
57 | extern QString convertDirFromDisplay(const QString &dir);
58 | extern QString getDir(const QString &file);
59 | extern QString getFile(const QString &file);
60 | extern QString changeExtension(const QString &file, const QString &extension);
61 | extern bool makeDir(const QString &dir, int mode);
62 | extern void msleep(int msecs);
63 | inline void sleep() {
64 | msleep(100);
65 | }
66 |
67 | extern QString findExe(const QString &appname, const QString &pathstr = QString());
68 | extern QString formatByteSize(double size);
69 | extern QString formatDuration(const quint32 totalseconds);
70 | extern QString cleanPath(const QString &p);
71 | extern QString configDir(const QString &sub = QString(), bool create = false);
72 | extern QString dataDir(const QString &sub = QString(), bool create = false);
73 | extern QString cacheDir(const QString &sub = QString(), bool create = true);
74 | extern QString systemDir(const QString &sub);
75 | extern bool moveFile(const QString &from, const QString &to);
76 | extern void moveDir(const QString &from, const QString &to);
77 | extern void clearOldCache(const QString &sub, int maxAge);
78 | extern void touchFile(const QString &fileName);
79 | extern bool isDirReadable(const QString &dir);
80 |
81 | extern int layoutSpacing(QWidget *w);
82 | extern bool isHighDpi();
83 | extern QPainterPath buildPath(const QRectF &r, double radius);
84 |
85 | enum Desktop {
86 | KDE,
87 | Gnome,
88 | Unity,
89 | Other
90 | };
91 | extern Desktop currentDe();
92 | }
93 |
94 | #endif
95 |
--------------------------------------------------------------------------------
/ui/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | set(carbon_SRCS
2 | excludefile.cpp
3 | excludewidget.cpp
4 | generaloptionswidget.cpp
5 | main.cpp
6 | mainwindow.cpp
7 | rsyncoptionswidget.cpp
8 | runnerdialog.cpp
9 | sessiondialog.cpp
10 | session.cpp
11 | sessionwidget.cpp
12 | treewidget.cpp
13 | basicitemdelegate.cpp)
14 |
15 | set(carbon_MOC_HDRS
16 | excludewidget.h
17 | generaloptionswidget.h
18 | mainwindow.h
19 | rsyncoptionswidget.h
20 | runnerdialog.h
21 | sessiondialog.h
22 | sessionwidget.h)
23 |
24 | set(carbon_UIS
25 | excludewidget.ui
26 | generaloptionswidget.ui
27 | rsyncoptionswidget.ui
28 | runnerwidget.ui
29 | sessionwidget.ui)
30 |
31 | set(carbon_RCS carbon.qrc)
32 |
33 | QT5_WRAP_CPP(carbon_MOC_SRCS ${carbon_MOC_HDRS})
34 | QT5_WRAP_UI(carbon_UI_HDRS ${carbon_UIS})
35 | QT5_ADD_RESOURCES(carbon_RC_SRCS ${carbon_RCS})
36 |
37 | include_directories (${CMAKE_SOURCE_DIR}
38 | ${CMAKE_SOURCE_DIR}/support
39 | ${CMAKE_CURRENT_SOURCE_DIR}
40 | ${CMAKE_CURRENT_BINARY_DIR}
41 | ${CMAKE_BINARY_DIR}
42 | ${QTINCLUDES})
43 |
44 | add_executable(carbon ${carbon_SRCS} ${carbon_MOC_SRCS} ${carbon_UI_HDRS} ${carbon_RC_SRCS})
45 | target_link_libraries(carbon support ${QTLIBS})
46 | install(TARGETS carbon RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)
47 | set(XDG_APPS_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/applications")
48 | install(FILES carbon.desktop DESTINATION ${XDG_APPS_INSTALL_DIR})
49 | install(FILES default.sync default.sync.exclude DESTINATION ${CMAKE_INSTALL_PREFIX}/share/${CMAKE_PROJECT_NAME})
50 |
--------------------------------------------------------------------------------
/ui/basicitemdelegate.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * Cantata
3 | *
4 | * Copyright (c) 2011-2013 Craig Drummond
5 | *
6 | * ----
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation; either version 2 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program; see the file COPYING. If not, write to
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 | * Boston, MA 02110-1301, USA.
22 | */
23 |
24 | #include "basicitemdelegate.h"
25 | #include
26 | #include
27 | #include
28 |
29 | static void drawLine(QPainter *p, const QRect &r, const QColor &color, bool fadeStart, bool fadeEnd) {
30 | static const double constAlpha = 0.1;
31 | QColor col(color);
32 | QLinearGradient grad(r.bottomLeft(), r.bottomRight());
33 |
34 | if (fadeStart || fadeEnd) {
35 | double fadeSize = (fadeStart && fadeEnd ? 64.0 : 32.0);
36 | if (r.width() < (2.2 * fadeSize)) {
37 | fadeSize = r.width() / 3.0;
38 | }
39 | double fadePos = fadeSize / r.width();
40 | col.setAlphaF(fadeStart ? 0.0 : constAlpha);
41 | grad.setColorAt(0, col);
42 | col.setAlphaF(constAlpha);
43 | grad.setColorAt(fadePos, col);
44 | grad.setColorAt(1.0 - fadePos, col);
45 | col.setAlphaF(fadeEnd ? 0.0 : constAlpha);
46 | grad.setColorAt(1, col);
47 | p->setPen(QPen(grad, 1));
48 | } else {
49 | col.setAlphaF(constAlpha);
50 | p->setPen(QPen(col, 1));
51 | }
52 | p->drawLine(r.bottomLeft(), r.bottomRight());
53 | }
54 |
55 | BasicItemDelegate::BasicItemDelegate(QObject *p)
56 | : QStyledItemDelegate(p) {
57 | }
58 |
59 | BasicItemDelegate::~BasicItemDelegate() {
60 | }
61 |
62 | void BasicItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
63 | if (!index.isValid()) {
64 | return;
65 | }
66 |
67 | bool selected = option.state & QStyle::State_Selected;
68 | bool active = option.state & QStyle::State_Active;
69 | QStyledItemDelegate::paint(painter, option, index);
70 | QColor col(option.palette.color(active ? QPalette::Active : QPalette::Inactive,
71 | selected ? QPalette::HighlightedText : QPalette::Text));
72 |
73 |
74 | if (4 == option.version) {
75 | const QStyleOptionViewItem &v4 = (QStyleOptionViewItem &)option;
76 |
77 | switch (v4.viewItemPosition) {
78 | case QStyleOptionViewItem::Beginning:
79 | drawLine(painter, option.rect, col, true, false);
80 | break;
81 | case QStyleOptionViewItem::Middle:
82 | drawLine(painter, option.rect, col, false, false);
83 | break;
84 | case QStyleOptionViewItem::End:
85 | drawLine(painter, option.rect, col, false, true);
86 | break;
87 | case QStyleOptionViewItem::Invalid:
88 | case QStyleOptionViewItem::OnlyOne:
89 | drawLine(painter, option.rect, col, true, true);
90 | }
91 | } else {
92 | drawLine(painter, option.rect, col, false, false);
93 | }
94 | }
95 |
96 |
--------------------------------------------------------------------------------
/ui/basicitemdelegate.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Cantata
3 | *
4 | * Copyright (c) 2011-2013 Craig Drummond
5 | *
6 | * ----
7 | *
8 | * This program is free software; you can redistribute it and/or modify
9 | * it under the terms of the GNU General Public License as published by
10 | * the Free Software Foundation; either version 2 of the License, or
11 | * (at your option) any later version.
12 | *
13 | * This program is distributed in the hope that it will be useful,
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 | * General Public License for more details.
17 | *
18 | * You should have received a copy of the GNU General Public License
19 | * along with this program; see the file COPYING. If not, write to
20 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 | * Boston, MA 02110-1301, USA.
22 | */
23 |
24 | #ifndef BASIC_ITEM_DELEGATE_H
25 | #define BASIC_ITEM_DELEGATE_H
26 |
27 | #include
28 |
29 | class BasicItemDelegate : public QStyledItemDelegate {
30 | public:
31 | BasicItemDelegate(QObject *p);
32 | virtual ~BasicItemDelegate();
33 | void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
34 | };
35 |
36 | #endif
37 |
--------------------------------------------------------------------------------
/ui/carbon.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Carbon
3 | Comment=Folder Synchronisation
4 | Exec=carbon
5 | Icon=carbon
6 | Type=Application
7 | Terminal=false
8 | X-KDE-StartupNotify=true
9 | X-DBUS-StartupType=Unique
10 | Categories=Qt;System;
11 | Keywords=Sync; Synchronisation; Backup; rsync
12 |
--------------------------------------------------------------------------------
/ui/carbon.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | ../icons/carbon.svg
4 | ../icons/carbon16.png
5 | ../icons/carbon22.png
6 | ../icons/carbon32.png
7 | ../icons/carbon48.png
8 |
9 |
10 |
--------------------------------------------------------------------------------
/ui/default.sync:
--------------------------------------------------------------------------------
1 | [Settings]
2 | archive=true
3 | recursive=true
4 | skipFilesOnSizeMatch=false
5 | skipReceiverNewerFiles=true
6 | keepPartial=false
7 | onlyUpdate=false
8 | useCompression=false
9 | checksum=false
10 | windowsCompat=false
11 | ignoreExisting=false
12 | makeBackups=false
13 | deleteExtraFilesOnReceiver=true
14 | copySymlinksAsSymlinks=true
15 | preservePermissions=true
16 | preserveSpecialFiles=true
17 | preserveOwner=true
18 | dontLeaveFileSystem=false
19 | preserveGroup=true
20 | modificationTimes=true
21 | cvsExclude=true
22 | maxBackupAge=7
23 | customOptions=
24 |
--------------------------------------------------------------------------------
/ui/default.sync.exclude:
--------------------------------------------------------------------------------
1 | # KDE3 Desktop-Communications-Protocol file
2 | .DCOPserver*
3 | # Thumnbail cache
4 | .thumbnails/
5 | # CD Database cache
6 | .cddb/
7 | # Cross-desktop cache
8 | .cache/
9 | # Fonts cache
10 | .fontconfig/
11 | # GConf Daemon
12 | .gconfd/
13 | # GStreamer files
14 | .gstreamer*
15 | # ICE authority file
16 | .ICEauthority
17 | # KDE cache
18 | .kde*/share/cache/
19 | # KDE3 MCOP folder
20 | .mcop/
21 | # KDE3 MCOP resource file
22 | .mcoprc
23 | # Firefox cache
24 | .mozilla/firefox/**/Cache
25 | # Pulse Audio
26 | .pulse/
27 | # Pulse Audio cookie
28 | .pulse-cookie
29 | # X11 errors file
30 | .xsession-errors*
31 | # X11 authority file
32 | .Xauthority
33 | # Desktop-BUS files
34 | .dbus/
35 | # DVD-CSS
36 | .dvdcss/
37 | # Java
38 | .java/
39 | # Macromodia Flash
40 | .macromedia/
41 | # Adobe Flash
42 | .adobe/
43 | .gvfs/
44 | [Cc]ache*
45 | [Tt]rash*
46 | *.backup*
47 | .dropbox*
48 | /proc/*
49 | /sys/*
50 | /dev/*
51 | /run/*"
52 | Ubuntu One/
53 |
--------------------------------------------------------------------------------
/ui/excludefile.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
3 |
4 | ----
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; see the file COPYING. If not, write to
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA.
20 | */
21 |
22 | #include "excludefile.h"
23 | #include
24 | #include
25 | #include
26 |
27 | ExcludeFile::ExcludeFile(const QString &name)
28 | : fileName(name) {
29 | load();
30 | }
31 |
32 | void ExcludeFile::load() {
33 | QFile f(fileName);
34 |
35 | if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
36 | QString comment;
37 |
38 | while (!f.atEnd()) {
39 | QString line(f.readLine().trimmed());
40 |
41 | if (!line.isEmpty()) {
42 | if (QChar('#') == line[0] || QChar(';') == line[0]) {
43 | comment = line.mid(1).trimmed();
44 | } else {
45 | patternList.append(Pattern(line, comment));
46 | comment = QString();
47 | }
48 | }
49 | }
50 | }
51 | }
52 |
53 | bool ExcludeFile::save(const QString &n) {
54 | QString name = n.isEmpty() ? fileName : n;
55 | if (0 == patternList.count()) {
56 | bool rv = erase();
57 | fileName = name;
58 | return rv;
59 | }
60 |
61 | QFile f(name);
62 |
63 | if (f.open(QIODevice::WriteOnly | QIODevice::Text)) {
64 | QTextStream fs(&f);
65 |
66 | foreach (const Pattern &p, patternList) {
67 | if (!p.comment.isEmpty()) {
68 | fs << "# " << p.comment << endl;
69 | }
70 | fs << p.value << endl;
71 | }
72 |
73 | fs.flush();
74 | f.close();
75 |
76 | if (fileName != name) {
77 | erase();
78 | }
79 | fileName = name;
80 | return true;
81 | }
82 |
83 | return false;
84 | }
85 |
86 | bool ExcludeFile::erase() {
87 | return fileName.isEmpty() || !QFile::exists(fileName) || 0 ==::unlink(QFile::encodeName(fileName).constData());
88 | }
89 |
90 | QString ExcludeFile::Pattern::toStr() {
91 | return QString(value + QString(" # ") + comment).trimmed();
92 | }
93 |
--------------------------------------------------------------------------------
/ui/excludefile.h:
--------------------------------------------------------------------------------
1 | #ifndef __EXCLUDE_FILE_H__
2 | #define __EXCLUDE_FILE_H__
3 |
4 | /*
5 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
6 |
7 | ----
8 |
9 | This program is free software; you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation; either version 2 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 | General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program; see the file COPYING. If not, write to
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 | Boston, MA 02110-1301, USA.
23 | */
24 |
25 | #include
26 | #include
27 |
28 | class ExcludeFile {
29 | public:
30 | struct Pattern {
31 | Pattern(const QString &v = QString(), const QString &c = QString())
32 | : value(v), comment(c) { }
33 |
34 | QString toStr();
35 |
36 | QString value;
37 | QString comment;
38 | };
39 |
40 | typedef QList PatternList;
41 |
42 | ExcludeFile(const QString &name);
43 |
44 | void load();
45 | bool save(const QString &n = QString());
46 | bool erase();
47 | const PatternList & patterns() const {
48 | return patternList;
49 | }
50 | void setPatterns(const QList &v) {
51 | patternList = v;
52 | }
53 |
54 | private:
55 | QString fileName;
56 | PatternList patternList;
57 | };
58 |
59 | #endif
60 |
--------------------------------------------------------------------------------
/ui/excludewidget.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
3 |
4 | ----
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; see the file COPYING. If not, write to
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA.
20 | */
21 |
22 | #include "excludewidget.h"
23 | #include "excludefile.h"
24 | #include "session.h"
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 |
34 | #define CFG_GROUP "ExcludeWidget/"
35 | #define CFG_COL_SIZES CFG_GROUP "List"
36 |
37 | ExcludeWidget::ExcludeWidget(QWidget *parent)
38 | : QWidget(parent) {
39 | setupUi(this);
40 |
41 | addButton->setText(tr("Add"));
42 | addButton->setToolTip(tr("Add an exclude pattern."));
43 | addButton->setIcon(QIcon::fromTheme("list-add"));
44 | removeButton->setText(tr("Delete"));
45 | removeButton->setToolTip(tr("Delete the selected exclude patterns."));
46 | removeButton->setIcon(QIcon::fromTheme("list-remove"));
47 |
48 | connect(addButton, SIGNAL(clicked()), SLOT(add()));
49 | connect(removeButton, SIGNAL(clicked()), SLOT(remove()));
50 | connect(excludeList, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), SLOT(editItem(QTreeWidgetItem *, int)));
51 | connect(excludeList, SIGNAL(itemSelectionChanged()), SLOT(controlButtons()));
52 |
53 | QStringList list;
54 | QSettings cfg;
55 | list = cfg.value(CFG_COL_SIZES, list).toStringList();
56 |
57 | if (2 == list.count()) {
58 | for (int i = 0; i < 2; ++i) {
59 | excludeList->header()->resizeSection(i, list[i].toInt());
60 | }
61 | }
62 |
63 | excludeList->sortItems(0, Qt::AscendingOrder);
64 | }
65 |
66 | ExcludeWidget::~ExcludeWidget() {
67 | QStringList list;
68 | for (int i = 0; i < 2; ++i) {
69 | list << QString::number(excludeList->header()->sectionSize(i));
70 | }
71 |
72 | QSettings cfg;
73 | cfg.setValue(CFG_COL_SIZES, list);
74 | }
75 |
76 | void ExcludeWidget::set(const Session &session) {
77 | cvsExclude->setChecked(session.cvsExcludeFlag());
78 | maxSize->setValue(session.maxSize());
79 | excludeList->clear();
80 | if (session.excludeFile()) {
81 | foreach (const ExcludeFile::Pattern &p, session.excludeFile()->patterns()) {
82 | addPattern(p.value, p.comment);
83 | }
84 | }
85 | controlButtons();
86 | }
87 |
88 | void ExcludeWidget::get(Session &session) {
89 | session.setCvsExcludeFlag(cvsExclude->isChecked());
90 | session.setMaxSize(maxSize->value());
91 |
92 | ExcludeFile::PatternList list;
93 | for (int i = 0; i < excludeList->topLevelItemCount(); ++i) {
94 | QTreeWidgetItem *item = excludeList->topLevelItem(i);
95 | list.append(ExcludeFile::Pattern(item->text(0), item->text(1)));
96 | }
97 | session.setExcludePatterns(list);
98 | }
99 |
100 | void ExcludeWidget::addPattern(const QString &v, const QString &c) {
101 | QStringList list;
102 |
103 | list << v;
104 | if (!c.isEmpty()) {
105 | list << c;
106 | }
107 |
108 | QTreeWidgetItem *i = new QTreeWidgetItem(excludeList, list);
109 | i->setFlags(i->flags() | Qt::ItemIsEditable);
110 | }
111 |
112 | void ExcludeWidget::add() {
113 | QString items(QInputDialog::getText(this, tr("New Exclude Patterns"),
114 | tr("Please enter a comma separated list of patterns "
115 | "to exclude.
e.g. *.sav, *.inf
")).trimmed());
116 |
117 | if (!items.isEmpty()) {
118 | QStringList patterns(items.split(',', QString::SkipEmptyParts));
119 | QStringList::ConstIterator it(patterns.begin()),
120 | end(patterns.end());
121 |
122 | for (; it != end; ++it) {
123 | QString v((*it).trimmed());
124 |
125 | if (0 == excludeList->findItems(v, Qt::MatchExactly, 0).count()) {
126 | addPattern(v);
127 | }
128 | }
129 | }
130 | }
131 |
132 | void ExcludeWidget::remove() {
133 | QList items(excludeList->selectedItems());
134 |
135 | if (items.count() && QMessageBox::Yes == QMessageBox::warning(this, tr("Delete"), tr("Delete all the selected patterns?"), QMessageBox::Yes | QMessageBox::No)) {
136 | foreach (QTreeWidgetItem *i, items) {
137 | delete i;
138 | }
139 |
140 | controlButtons();
141 | }
142 | }
143 |
144 | void ExcludeWidget::controlButtons() {
145 | removeButton->setEnabled(excludeList->selectedItems().count());
146 | }
147 |
148 | void ExcludeWidget::editItem(QTreeWidgetItem *item, int col) {
149 | excludeList->editItem(item, col);
150 | }
151 |
--------------------------------------------------------------------------------
/ui/excludewidget.h:
--------------------------------------------------------------------------------
1 | #ifndef __EXCLUDE_WIDGET_H__
2 | #define __EXCLUDE_WIDGET_H__
3 |
4 | /*
5 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
6 |
7 | ----
8 |
9 | This program is free software; you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation; either version 2 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 | General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program; see the file COPYING. If not, write to
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 | Boston, MA 02110-1301, USA.
23 | */
24 |
25 | #include "ui_excludewidget.h"
26 |
27 | class Session;
28 | class QTreeWidgetItem;
29 |
30 | class ExcludeWidget : public QWidget, Ui::ExcludeWidget {
31 | Q_OBJECT
32 |
33 | public:
34 | ExcludeWidget(QWidget *parent);
35 | virtual ~ExcludeWidget();
36 |
37 | void set(const Session &session);
38 | void get(Session &session);
39 |
40 | private:
41 | void addPattern(const QString &v, const QString &c = QString());
42 |
43 | private Q_SLOTS:
44 | void add();
45 | void remove();
46 | void controlButtons();
47 | void editItem(QTreeWidgetItem *item, int col);
48 | };
49 |
50 | #endif
51 |
--------------------------------------------------------------------------------
/ui/excludewidget.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | ExcludeWidget
4 |
5 |
6 |
7 | 0
8 | 0
9 | 384
10 | 219
11 |
12 |
13 |
14 |
15 | 0
16 |
17 |
18 | 0
19 |
20 |
21 | 0
22 |
23 |
24 | 0
25 |
26 | -
27 |
28 |
29 |
30 | 0
31 | 0
32 |
33 |
34 |
35 |
36 | Pattern
37 |
38 |
39 |
40 |
41 | Comment
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 | 0
51 | 0
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 | 0
61 | 0
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 | Qt::Vertical
70 |
71 |
72 |
73 | 20
74 | 154
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 | Exclude files which would be ignored by <i>CVS</i>. This includes the following list of patterns:<br/><br/>
83 | RCS SCCS CVS CVS.adm RCSLOG cvslog.* tags TAGS .make.state .nse_depinfo *~ #* .#* ,* _$* *$ *.old *.bak *.BAK *.orig *.rej .del-* *.a *.olb *.o *.obj *.so *.exe *.Z *.elc *.ln core .svn/<br/><br/>
84 | (--cvs-exclude)
85 |
86 |
87 | CVS exclude
88 |
89 |
90 |
91 | -
92 |
93 |
94 | 0
95 |
96 |
-
97 |
98 |
99 | Exclude files larger than:
100 |
101 |
102 |
103 | -
104 |
105 |
106 |
107 | 0
108 | 0
109 |
110 |
111 |
112 | M
113 |
114 |
115 | 0
116 |
117 |
118 | 65535
119 |
120 |
121 | 100
122 |
123 |
124 | No Limit
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | TreeWidget
137 | QTreeWidget
138 |
139 |
140 |
141 |
142 |
--------------------------------------------------------------------------------
/ui/generaloptionswidget.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
3 |
4 | ----
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; see the file COPYING. If not, write to
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA.
20 | */
21 |
22 | #include "generaloptionswidget.h"
23 | #include "session.h"
24 |
25 | GeneralOptionsWidget::GeneralOptionsWidget(QWidget *parent, bool showName)
26 | : QWidget(parent) {
27 | setupUi(this);
28 | if (!showName) {
29 | nameEdit->setVisible(false);
30 | nameLabel->setVisible(false);
31 | }
32 | srcPath->setDirMode(true);
33 | destPath->setDirMode(true);
34 | type->insertItem(0, QObject::tr("Synchronisation"));
35 | type->insertItem(1, QObject::tr("Backup"));
36 | connect(type, SIGNAL(activated(int)), SLOT(typeChanged(int)));
37 | }
38 |
39 | void GeneralOptionsWidget::set(const Session &session, bool edit) {
40 | type->setEnabled(!edit);
41 | nameEdit->setText(session.isDefault() ? QObject::tr("New Session") : session.name());
42 | srcPath->setText(Utils::convertDirForDisplay(session.source()));
43 | destPath->setText(Utils::convertDirForDisplay(session.destination()));
44 | type->setCurrentIndex(session.makeBackupsFlag() ? 1 : 0);
45 | typeChanged(type->currentIndex());
46 | if (session.maxBackupDays()) {
47 | maxDays->setValue(session.maxBackupDays());
48 | deleteOld->setChecked(true);
49 | } else {
50 | maxDays->setValue(7);
51 | dontDeleteOld->setChecked(true);
52 | }
53 | }
54 |
55 | void GeneralOptionsWidget::get(Session &session) {
56 | session.setSource(src());
57 | session.setDestination(dest());
58 | session.setMakeBackupsFlag(type->currentIndex() ? true : false);
59 | session.setMaxBackupDays(deleteOld->isChecked() ? maxDays->value() : 0);
60 | session.setName(name());
61 | }
62 |
63 | void GeneralOptionsWidget::typeChanged(int idx) {
64 | ageWidget->setVisible(1 == idx);
65 | }
66 |
--------------------------------------------------------------------------------
/ui/generaloptionswidget.h:
--------------------------------------------------------------------------------
1 | #ifndef __GENERALOPTIONS_WIDGET_H__
2 | #define __GENERALOPTIONS_WIDGET_H__
3 |
4 | /*
5 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
6 |
7 | ----
8 |
9 | This program is free software; you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation; either version 2 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 | General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program; see the file COPYING. If not, write to
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 | Boston, MA 02110-1301, USA.
23 | */
24 |
25 | #include "ui_generaloptionswidget.h"
26 | #include "pathrequester.h"
27 | #include "utils.h"
28 |
29 | class Session;
30 |
31 | class GeneralOptionsWidget : public QWidget, Ui::GeneralOptionsWidget {
32 | Q_OBJECT
33 |
34 | public:
35 | GeneralOptionsWidget(QWidget *parent, bool showName = true);
36 |
37 | QString name() const {
38 | return nameEdit->text().trimmed();
39 | }
40 | QString src() const {
41 | return Utils::convertDirFromDisplay(srcPath->text());
42 | }
43 | QString dest() const {
44 | return Utils::convertDirFromDisplay(destPath->text());
45 | }
46 |
47 | void set(const Session &session, bool edit);
48 | void get(Session &session);
49 |
50 | private Q_SLOTS:
51 | void typeChanged(int idx);
52 | };
53 |
54 | #endif
55 |
--------------------------------------------------------------------------------
/ui/generaloptionswidget.ui:
--------------------------------------------------------------------------------
1 |
2 | GeneralOptionsWidget
3 |
4 |
5 |
6 | 0
7 | 0
8 | 435
9 | 243
10 |
11 |
12 |
13 |
14 | 0
15 |
16 | -
17 |
18 |
19 | Qt::Vertical
20 |
21 |
22 |
23 | 20
24 | 4
25 |
26 |
27 |
28 |
29 | -
30 |
31 |
32 | Name:
33 |
34 |
35 |
36 | -
37 |
38 |
39 | -
40 |
41 |
42 | Source:
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 | 0
51 | 0
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 | Destination:
60 |
61 |
62 |
63 | -
64 |
65 |
66 |
67 | 0
68 | 0
69 |
70 |
71 |
72 |
73 | -
74 |
75 |
76 | Type:
77 |
78 |
79 |
80 | -
81 |
82 |
83 |
84 | 0
85 | 0
86 |
87 |
88 |
89 |
90 | -
91 |
92 |
93 | QFrame::NoFrame
94 |
95 |
96 | QFrame::Raised
97 |
98 |
99 | 0
100 |
101 |
102 |
103 | 0
104 |
105 |
-
106 |
107 |
108 | Delete increments older than:
109 |
110 |
111 | true
112 |
113 |
114 |
115 | -
116 |
117 |
118 |
119 | 0
120 | 0
121 |
122 |
123 |
124 | day(s)
125 |
126 |
127 | 1
128 |
129 |
130 | 365
131 |
132 |
133 |
134 | -
135 |
136 |
137 |
138 | 0
139 | 0
140 |
141 |
142 |
143 | Don't delete old increments
144 |
145 |
146 |
147 | -
148 |
149 |
150 | Qt::Vertical
151 |
152 |
153 | QSizePolicy::Minimum
154 |
155 |
156 |
157 | 20
158 | 22
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 | PathRequester
171 | QFrame
172 |
173 |
174 |
175 |
176 |
177 |
178 | deleteOld
179 | toggled(bool)
180 | maxDays
181 | setEnabled(bool)
182 |
183 |
184 | 172
185 | 156
186 |
187 |
188 | 358
189 | 159
190 |
191 |
192 |
193 |
194 |
195 |
--------------------------------------------------------------------------------
/ui/main.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
3 |
4 | ----
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; see the file COPYING. If not, write to
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA.
20 | */
21 |
22 | #include "utils.h"
23 | #include "mainwindow.h"
24 | #include "messagebox.h"
25 | #include "config.h"
26 | #include
27 | #include
28 | #ifdef QT_QTDBUS_FOUND
29 | #include
30 | #endif
31 | #include
32 |
33 | static QString fixArg(QString a, const QString ¶m) {
34 | a = a.mid(param.length());
35 | if (a[0] == '\'' || a[0] == '\"') {
36 | a = a.mid(1);
37 | }
38 | if (a.endsWith('\'') || a.endsWith('\"')) {
39 | a = a.left(a.length() - 1);
40 | }
41 | return a;
42 | }
43 |
44 | int main(int argc, char **argv) {
45 | QApplication app(argc, argv);
46 |
47 | #ifdef QT_QTDBUS_FOUND
48 | if (!QDBusConnection::sessionBus().registerService("org.craigd.carbon")) {
49 | return -1;
50 | }
51 | #endif
52 |
53 | QString rsync(Utils::findExe("rsync"));
54 |
55 | if (rsync.isEmpty()) {
56 | MessageBox::error(0L, QObject::tr("Carbon is a GUI front-end for \'rsync\'\nThis tool could not be found on your system."
57 | " Please install this and restart Carbon"));
58 | return -1;
59 | } else {
60 | QCoreApplication::setApplicationName(CARBON_PACKAGE_NAME);
61 | QCoreApplication::setOrganizationName(CARBON_PACKAGE_NAME);
62 |
63 | MainWindow mw(rsync);
64 | mw.show();
65 | return app.exec();
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/ui/mainwindow.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
3 |
4 | ----
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; see the file COPYING. If not, write to
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA.
20 | */
21 |
22 | #include "mainwindow.h"
23 | #include "sessionwidget.h"
24 | #include "config.h"
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | #define CFG_GROUP "MainWindow/"
33 | #define CFG_SIZE CFG_GROUP "Size"
34 |
35 | QIcon MainWindow::appIcon;
36 |
37 | MainWindow::MainWindow(const QString &rsync)
38 | : QMainWindow(0L)
39 | , rsync(rsync) {
40 | bool root = 0 == getuid();
41 |
42 | QList appSizes = QList() << 16 << 22 << 32 << 48;
43 | foreach (int s, appSizes) {
44 | appIcon.addFile(QString(":carbon%1%2.png").arg(root ? "-root" : "").arg(s), QSize(s, s));
45 | }
46 | appIcon.addFile(root ? ":carbon-root.svg" : ":carbon.svg");
47 | setWindowIcon(appIcon);
48 |
49 | setWindowTitle(root ? tr("Carbon (root)") : tr("Carbon"));
50 | sessionWidget = new SessionWidget(this);
51 | setCentralWidget(sessionWidget);
52 | setupActions();
53 | createGUI();
54 |
55 | QSettings cfg;
56 | resize(cfg.value(CFG_SIZE, QSize(600, 300)).toSize());
57 | setMinimumSize(600, 200);
58 |
59 | if (root) {
60 | sessionWidget->setBackground(appIcon);
61 | }
62 | }
63 |
64 | MainWindow::~MainWindow() {
65 | QSettings cfg;
66 | cfg.setValue(CFG_SIZE, size());
67 | }
68 |
69 | void MainWindow::setupActions() {
70 | quitAction = new QAction(QIcon::fromTheme("application-exit"), tr("Quit"), this);
71 | connect(quitAction, SIGNAL(triggered(bool)), qApp, SLOT(quit()));
72 | quitAction->setToolTip(tr("Quit application."));
73 |
74 | aboutAction = new QAction(QIcon::fromTheme("dialog-information"), tr("About"), this);
75 | connect(aboutAction, SIGNAL(triggered(bool)), this, SLOT(about()));
76 |
77 | newSessionAction = new QAction(QIcon::fromTheme("document-new"), tr("New..."), this);
78 | connect(newSessionAction, SIGNAL(triggered(bool)), sessionWidget, SLOT(newSession()));
79 | newSessionAction->setToolTip(tr("Create a new synchronisation session (either a plain synchronisation, or a backup)."));
80 |
81 | editSessionAction = new QAction(QIcon::fromTheme("document-properties"), tr("Edit..."), this);
82 | connect(editSessionAction, SIGNAL(triggered(bool)), sessionWidget, SLOT(editSession()));
83 | editSessionAction->setToolTip(tr("Change synchronisation session properties."));
84 |
85 | deleteSessionAction = new QAction(QIcon::fromTheme("edit-delete"), tr("Delete..."), this);
86 | connect(deleteSessionAction, SIGNAL(triggered(bool)), sessionWidget, SLOT(removeSession()));
87 |
88 | QIcon icon = QIcon::fromTheme("view-history");
89 | if (icon.isNull()) {
90 | icon = QIcon::fromTheme("document");
91 | }
92 | showLogAction = new QAction(icon, tr("Show Last Log..."), this);
93 | connect(showLogAction, SIGNAL(triggered(bool)), sessionWidget, SLOT(showSessionLog()));
94 |
95 | dryRunAction = new QAction(QIcon::fromTheme("system-run"), tr("Dry-run..."), this);
96 | connect(dryRunAction, SIGNAL(triggered(bool)), sessionWidget, SLOT(dryRunSession()));
97 | dryRunAction->setToolTip(tr("Show what would happen with a sync, but don't actually do anything."));
98 |
99 | syncAction = new QAction(appIcon, tr("Synchronise..."), this);
100 | connect(syncAction, SIGNAL(triggered(bool)), sessionWidget, SLOT(syncSession()));
101 | syncAction->setToolTip(tr("Perform synchronisation."));
102 |
103 | // restoreAction=ActionCollection::get()->createAction("restore", tr("Restore..."), QIcon::fromTheme("edit-undo"));
104 | // restoreAction->setCheckable(true);
105 | // connect(restoreAction, SIGNAL(toggled(bool)), SLOT(restoreSession(bool)));
106 |
107 | deleteSessionAction->setEnabled(false);
108 | editSessionAction->setEnabled(false);
109 | showLogAction->setEnabled(false);
110 | dryRunAction->setEnabled(false);
111 | syncAction->setEnabled(false);
112 |
113 | connect(sessionWidget, SIGNAL(itemsSelected(bool)), deleteSessionAction, SLOT(setEnabled(bool)));
114 | connect(sessionWidget, SIGNAL(singleItemSelected(bool)), editSessionAction, SLOT(setEnabled(bool)));
115 | connect(sessionWidget, SIGNAL(haveLog(bool)), showLogAction, SLOT(setEnabled(bool)));
116 | connect(sessionWidget, SIGNAL(haveSessions(bool)), dryRunAction, SLOT(setEnabled(bool)));
117 | connect(sessionWidget, SIGNAL(haveSessions(bool)), syncAction, SLOT(setEnabled(bool)));
118 | // connect(sessionWidget, SIGNAL(haveSessions(bool)), restoreAction, SLOT(setEnabled(bool)));
119 |
120 | QMenu *menu = new QMenu(sessionWidget);
121 | menu->addAction(deleteSessionAction);
122 | menu->addAction(editSessionAction);
123 | menu->addSeparator();
124 | menu->addAction(showLogAction);
125 | menu->addSeparator();
126 | menu->addAction(dryRunAction);
127 | menu->addAction(syncAction);
128 | sessionWidget->setMenu(menu);
129 | }
130 |
131 | class Spacer : public QWidget {
132 | public:
133 | Spacer(QWidget *p)
134 | : QWidget(p) {
135 | setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
136 | }
137 | };
138 |
139 | void MainWindow::createGUI() {
140 | QToolBar *tb = new QToolBar(this);
141 | tb->addAction(newSessionAction);
142 | tb->addAction(editSessionAction);
143 | tb->addAction(deleteSessionAction);
144 | // tb->addSeparator();
145 | // tb->addAction(showLogAction);
146 | tb->addSeparator();
147 | tb->addAction(dryRunAction);
148 | tb->addAction(syncAction);
149 | // tb->addAction(restoreAction);
150 | tb->addWidget(new Spacer(tb));
151 | tb->addAction(aboutAction);
152 | tb->addAction(quitAction);
153 | tb->setMovable(false);
154 | tb->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
155 | tb->toggleViewAction()->setVisible(false);
156 | addToolBar(tb);
157 | }
158 |
159 | void MainWindow::restoreSession(bool on) {
160 | newSessionAction->setEnabled(!on);
161 | if (on) {
162 | editSessionAction->setEnabled(false);
163 | deleteSessionAction->setEnabled(false);
164 | showLogAction->setEnabled(false);
165 | dryRunAction->setEnabled(false);
166 | syncAction->setEnabled(false);
167 | }
168 |
169 | sessionWidget->setEnabled(!on);
170 | sessionWidget->restoreSession(on);
171 | }
172 |
173 | void MainWindow::about() {
174 | QMessageBox::about(this, tr("About Carbon"),
175 | tr("Carbon %1
rsync front-end.
"
176 | "(C) Craig Drummond 2013.
Released under the GPLv3").arg(CARBON_VERSION));
177 |
178 | }
179 |
--------------------------------------------------------------------------------
/ui/mainwindow.h:
--------------------------------------------------------------------------------
1 | #ifndef __MAIN_WINDOW_H__
2 | #define __MAIN_WINDOW_H__
3 |
4 | /*
5 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
6 |
7 | ----
8 |
9 | This program is free software; you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation; either version 2 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 | General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program; see the file COPYING. If not, write to
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 | Boston, MA 02110-1301, USA.
23 | */
24 |
25 | #include
26 |
27 | class SessionWidget;
28 | class QAction;
29 | class QIcon;
30 |
31 | class MainWindow : public QMainWindow {
32 | Q_OBJECT
33 |
34 | public:
35 | MainWindow(const QString &rsync);
36 | virtual ~MainWindow();
37 |
38 | static QIcon appIcon;
39 |
40 | private Q_SLOTS:
41 | void restoreSession(bool on);
42 | void about();
43 |
44 | private:
45 | void setupActions();
46 | void createGUI();
47 |
48 | private:
49 | QString rsync;
50 | QAction *newSessionAction;
51 | QAction *editSessionAction;
52 | QAction *deleteSessionAction;
53 | QAction *showLogAction;
54 | QAction *dryRunAction;
55 | QAction *syncAction;
56 | QAction *restoreAction;
57 | QAction *aboutAction;
58 | QAction *quitAction;
59 | SessionWidget *sessionWidget;
60 | };
61 |
62 | #endif
63 |
--------------------------------------------------------------------------------
/ui/rsyncoptionswidget.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
3 |
4 | ----
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; see the file COPYING. If not, write to
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA.
20 | */
21 |
22 | #include "rsyncoptionswidget.h"
23 | #include "session.h"
24 | #include
25 | #include
26 | #include
27 |
28 | RSyncOptionsWidget::RSyncOptionsWidget(QWidget *parent)
29 | : QWidget(parent) {
30 | setupUi(this);
31 |
32 | // if (0!=getuid()) {
33 | // preserveSpecialFiles->setEnabled(false);
34 | // preserveOwner->setEnabled(false);
35 | // preserveGroup->setEnabled(false);
36 | // }
37 |
38 | connect(archive, SIGNAL(toggled(bool)), SLOT(archiveToggled(bool)));
39 | connect(copySymlinksAsSymlinks, SIGNAL(toggled(bool)), SLOT(preserveToggled(bool)));
40 | connect(preservePermissions, SIGNAL(toggled(bool)), SLOT(preserveToggled(bool)));
41 | connect(preserveSpecialFiles, SIGNAL(toggled(bool)), SLOT(preserveToggled(bool)));
42 | connect(preserveOwner, SIGNAL(toggled(bool)), SLOT(preserveToggled(bool)));
43 | connect(preserveGroup, SIGNAL(toggled(bool)), SLOT(preserveToggled(bool)));
44 | }
45 |
46 | void RSyncOptionsWidget::set(const Session &session) {
47 | archive->setChecked(session.archiveFlag());
48 | recursive->setChecked(session.recursiveFlag());
49 | skipFilesOnSizeMatch->setChecked(session.skipFilesOnSizeMatchFlag());
50 | skipReceiverNewerFiles->setChecked(session.skipReceiverNewerFilesFlag());
51 | keepPartial->setChecked(session.keepPartialFlag());
52 | onlyUpdate->setChecked(session.onlyUpdateFlag());
53 | useCompression->setChecked(session.useCompressionFlag());
54 | checksum->setChecked(session.checksumFlag());
55 | windowsCompatability->setChecked(session.windowsFlag());
56 | ignoreExisting->setChecked(session.ignoreExistingFlag());
57 | deleteExtraFilesOnReceiver->setChecked(session.deleteExtraFilesOnReceiverFlag());
58 | copySymlinksAsSymlinks->setChecked(session.copySymlinksAsSymlinksFlag());
59 | preservePermissions->setChecked(session.preservePermissionsFlag());
60 | preserveSpecialFiles->setChecked(session.preserveSpecialFilesFlag());
61 | preserveOwner->setChecked(session.preserveOwnerFlag());
62 | dontLeaveFileSystem->setChecked(session.dontLeaveFileSystemFlag());
63 | preserveGroup->setChecked(session.preserveGroupFlag());
64 | modificationTimes->setChecked(session.modificationTimesFlag());
65 | customOptions->setText(session.customOpts());
66 | }
67 |
68 | void RSyncOptionsWidget::get(Session &session) {
69 | session.setArchiveFlag(archive->isChecked());
70 | session.setRecursiveFlag(recursive->isChecked());
71 | session.setSkipFilesOnSizeMatchFlag(skipFilesOnSizeMatch->isChecked());
72 | session.setSkipReceiverNewerFilesFlag(skipReceiverNewerFiles->isChecked());
73 | session.setKeepPartialFlag(keepPartial->isChecked());
74 | session.setOnlyUpdateFlag(onlyUpdate->isChecked());
75 | session.setUseCompressionFlag(useCompression->isChecked());
76 | session.setChecksumFlag(checksum->isChecked());
77 | session.setWindowsFlag(windowsCompatability->isChecked());
78 | session.setIgnoreExistingFlag(ignoreExisting->isChecked());
79 | session.setDeleteExtraFilesOnReceiverFlag(deleteExtraFilesOnReceiver->isChecked());
80 | session.setCopySymlinksAsSymlinksFlag(copySymlinksAsSymlinks->isChecked());
81 | session.setPreservePermissionsFlag(preservePermissions->isChecked());
82 | session.setPreserveSpecialFilesFlag(preserveSpecialFiles->isChecked());
83 | session.setPreserveOwnerFlag(preserveOwner->isChecked());
84 | session.setDontLeaveFileSystemFlag(dontLeaveFileSystem->isChecked());
85 | session.setPreserveGroupFlag(preserveGroup->isChecked());
86 | session.setModificationTimesFlag(modificationTimes->isChecked());
87 | session.setCustomOpts(customOptions->text().trimmed());
88 | }
89 |
90 | void RSyncOptionsWidget::preserveToggled(bool on) {
91 | if (!on) {
92 | archive->setChecked(false);
93 | }
94 | }
95 |
96 | void RSyncOptionsWidget::archiveToggled(bool on) {
97 | if (on) {
98 | recursive->setChecked(true);
99 | copySymlinksAsSymlinks->setChecked(true);
100 | preservePermissions->setChecked(true);
101 | preserveSpecialFiles->setChecked(true);
102 | preserveOwner->setChecked(true);
103 | preserveGroup->setChecked(true);
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/ui/rsyncoptionswidget.h:
--------------------------------------------------------------------------------
1 | #ifndef __RSYNCOPTIONS_WIDGET_H__
2 | #define __RSYNCOPTIONS_WIDGET_H__
3 |
4 | /*
5 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
6 |
7 | ----
8 |
9 | This program is free software; you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation; either version 2 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 | General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program; see the file COPYING. If not, write to
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 | Boston, MA 02110-1301, USA.
23 | */
24 |
25 | #include "ui_rsyncoptionswidget.h"
26 |
27 | class Session;
28 |
29 | class RSyncOptionsWidget : public QWidget, Ui::RSyncOptionsWidget {
30 | Q_OBJECT
31 |
32 | public:
33 | RSyncOptionsWidget(QWidget *parent);
34 |
35 | void set(const Session &session);
36 | void get(Session &session);
37 |
38 | QString getCustom() const {
39 | return customOptions->text();
40 | }
41 |
42 | private Q_SLOTS:
43 | void preserveToggled(bool on);
44 | void archiveToggled(bool on);
45 | };
46 |
47 | #endif
48 |
--------------------------------------------------------------------------------
/ui/rsyncoptionswidget.ui:
--------------------------------------------------------------------------------
1 |
2 | RSyncOptionsWidget
3 |
4 |
5 |
6 | 0
7 | 0
8 | 478
9 | 446
10 |
11 |
12 |
13 |
14 | 0
15 |
16 | -
17 |
18 |
19 | General Options
20 |
21 |
22 |
-
23 |
24 |
25 | Archive mode (--archive)
26 | Activates: Recursive, copy syymlinks as symlinks, preservce permissions/owner/group/device files.
27 |
28 |
29 | Archive mode
30 |
31 |
32 |
33 | -
34 |
35 |
36 | Keep partially transferred files (--partial)
37 |
38 |
39 | Keep partially transferred file
40 |
41 |
42 |
43 | -
44 |
45 |
46 | Recurse into folders (--recursive)
47 |
48 |
49 | Recursive
50 |
51 |
52 |
53 | -
54 |
55 |
56 | Skip creating new files on receiver (--existing)
57 |
58 |
59 | Only update existing files
60 |
61 |
62 |
63 | -
64 |
65 |
66 | Compress file data during the transfer (--compress)
67 |
68 |
69 | Compression
70 |
71 |
72 | Alt+O
73 |
74 |
75 |
76 | -
77 |
78 |
79 | Skip files that match in size (--size-only)
80 |
81 |
82 | Size only
83 |
84 |
85 |
86 | -
87 |
88 |
89 | Skip updating files that exist on receiver (--ignore-existing)
90 |
91 |
92 | Ignore existing
93 |
94 |
95 |
96 | -
97 |
98 |
99 | Skip files that are newer on the receiver (--update)
100 |
101 |
102 | Skip newer
103 |
104 |
105 |
106 | -
107 |
108 |
109 | Skip based on checksum, not modification time and size (--checksum)
110 |
111 |
112 | Always Checksum
113 |
114 |
115 |
116 | -
117 |
118 |
119 | Windows compatibility (--modify-window=1)
120 |
121 |
122 | Windows compatibility
123 |
124 |
125 |
126 |
127 |
128 |
129 | -
130 |
131 |
132 | Filesystem and Preservation Options
133 |
134 |
135 |
136 | 11
137 |
138 |
139 | 6
140 |
141 |
-
142 |
143 |
144 | Delete extraneous files from destination folder (--delete)
145 |
146 |
147 | Delete non-existing files
148 |
149 |
150 |
151 | -
152 |
153 |
154 | Don't cross filesystem boundaries (--one-file-system)
155 |
156 |
157 | Don't leave filesystem
158 |
159 |
160 |
161 | -
162 |
163 |
164 | Preserve permissions (--perms)
165 |
166 |
167 | Preserve Permissions
168 |
169 |
170 |
171 | -
172 |
173 |
174 | Preserve device files and preserve special files (-D)
175 |
176 |
177 | Preserve Device and special files
178 |
179 |
180 |
181 | -
182 |
183 |
184 | Preserve owner (--owner)
185 |
186 |
187 | Preserve Owners
188 |
189 |
190 |
191 | -
192 |
193 |
194 | Preserve group (--group)
195 |
196 |
197 | Preserve Groups
198 |
199 |
200 |
201 | -
202 |
203 |
204 | Preserve modification times (--times)
205 |
206 |
207 | Preserve Times
208 |
209 |
210 |
211 | -
212 |
213 |
214 | Copy symlinks as symlinks (--links)
215 |
216 |
217 | Copy symlinks as symlinks
218 |
219 |
220 |
221 |
222 |
223 |
224 | -
225 |
226 |
227 | Custom Options
228 |
229 |
230 |
-
231 |
232 |
233 |
234 |
235 |
236 | -
237 |
238 |
239 | Qt::Vertical
240 |
241 |
242 |
243 | 20
244 | 191
245 |
246 |
247 |
248 |
249 |
250 | GroupBox1
251 | GroupBox2
252 | groupBox5
253 | customOptions
254 |
255 |
256 | qPixmapFromMimeSource
257 |
258 |
259 |
260 |
--------------------------------------------------------------------------------
/ui/runnerdialog.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
3 |
4 | ----
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; see the file COPYING. If not, write to
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA.
20 | */
21 |
22 | #include "runnerdialog.h"
23 | #include "session.h"
24 | #include "utils.h"
25 | #include "messagebox.h"
26 | #include
27 | #include
28 | #include
29 | #ifdef QT_QTDBUS_FOUND
30 | #include
31 | #include
32 | #include
33 | #endif
34 |
35 | static inline QString removePrefixes(const QString &str) {
36 | return QString(str).replace(CARBON_PREFIX, QString()).replace(CARBON_MSG_PREFIX, QString()).replace(CARBON_ERROR_PREFIX, QString());
37 | }
38 |
39 | static QString updatedFiles(int v) {
40 | return 0 == v ? QObject::tr("Checking for updated files...") : QObject::tr("Checking for updated files...%1").arg(v);
41 | }
42 |
43 | static QString toStr(int exitCode) {
44 | switch (exitCode) {
45 | case 101:
46 | return QObject::tr("Usage error.");
47 | case 102:
48 | return QObject::tr("Could not read session file.");
49 | case 103:
50 | return QObject::tr("Destination folder does not exist, and could not be created.");
51 | case 104:
52 | return QObject::tr("Destination exists as a file.");
53 | case 105:
54 | return QObject::tr("Failed to mount destination folder.");
55 | case 106:
56 | return QObject::tr("Failed to unmount destination folder.");
57 | case 107:
58 | return QObject::tr("Mountpoint already exists.");
59 | case 108:
60 | return QObject::tr("Destination requires user@host");
61 | case 109:
62 | return QObject::tr("No source supplied.");
63 | case 110:
64 | return QObject::tr("No destination supplied.");
65 | case 111:
66 | return QObject::tr("Destination parent folder does not exist.");
67 | case 112:
68 | return QObject::tr("Source does not exist.");
69 | case 113:
70 | return QObject::tr("Session is already running.");
71 | case 1:
72 | return QObject::tr("Syntax or usage error.");
73 | case 2:
74 | return QObject::tr("Protocol incompatibility.");
75 | case 3:
76 | return QObject::tr("Errors selecting input/output files/folders.");
77 | case 4:
78 | return QObject::tr("Requested action not supported: an attempt "
79 | "was made to manipulate 64-bit files on a "
80 | "platform that cannot support them; or an "
81 | "option was specified that is supported by "
82 | "the client and not by the server.");
83 | case 5:
84 | return QObject::tr("Error starting client-server protocol.");
85 | case 6:
86 | return QObject::tr("Daemon unable to append to log-file.");
87 | case 10:
88 | return QObject::tr("Error in socket I/O.");
89 | case 11:
90 | return QObject::tr("Error in file I/O.");
91 | case 12:
92 | return QObject::tr("Error in rsync protocol data stream.");
93 | case 13:
94 | return QObject::tr("Errors with program diagnostics.");
95 | case 14:
96 | return QObject::tr("Error in IPC code.");
97 | case 20:
98 | return QObject::tr("Received SIGUSR1 or SIGINT.");
99 | case 21:
100 | return QObject::tr("Some error returned by waitpid().");
101 | case 22:
102 | return QObject::tr("Error allocating core memory buffers.");
103 | case 23:
104 | return QObject::tr("Partial transfer due to error.");
105 | case 24:
106 | return QObject::tr("Partial transfer due to vanished source files.");
107 | case 25:
108 | return QObject::tr("The --max-delete limit stopped deletions.");
109 | case 30:
110 | return QObject::tr("Timeout in data send/receive.");
111 | case 35:
112 | return QObject::tr("Timeout waiting for daemon connection.");
113 | default:
114 | return QObject::tr("Unknown error code %1.").arg(exitCode);
115 | }
116 |
117 | return QString();
118 | }
119 |
120 | RunnerDialog::RunnerDialog(QWidget *parent)
121 | : Dialog(parent)
122 | , process(0) {
123 | QWidget *mainWidget = new QWidget(this);
124 |
125 | setupUi(mainWidget);
126 | setMainWidget(mainWidget);
127 | setButtons(Cancel);
128 | output->setReadOnly(true);
129 | output->setVisible(false);
130 | setMinimumWidth(500);
131 | connect(detailsButton, SIGNAL(toggled(bool)), this, SLOT(showDetails(bool)));
132 | #ifdef QT_QTDBUS_FOUND
133 | unityMessage = QDBusMessage::createSignal("/Carbon", "com.canonical.Unity.LauncherEntry", "Update");
134 | #endif
135 | }
136 |
137 | RunnerDialog::~RunnerDialog() {
138 | disconnectProcess();
139 | }
140 |
141 | void RunnerDialog::go(const QList &sessions, bool dry) {
142 | setWindowTitle(dry ? tr("Performing Dry-Run") : tr("Performing Synchronisation"));
143 |
144 | completedSessions = 0;
145 | overallProgress->setVisible(sessions.count() > 1);
146 | overallProgressLabel->setVisible(sessions.count() > 1);
147 | sessionLabel->setText(QString());
148 | status->setText(QString());
149 | fileProgress->setValue(0);
150 | overallProgress->setValue(0);
151 | overallProgress->setMaximum(sessions.count() * 1000);
152 | sessionProgress->setValue(0);
153 | sessionProgress->setMaximum(0);
154 | detailsButton->setChecked(false);
155 | dryRun = dry;
156 |
157 | stdErr = prevStout = QString();
158 | output->setText(QString());
159 | currentSession = sessions.begin();
160 | endSession = sessions.end();
161 | sessionCount = sessions.count();
162 | if (!process) {
163 | process = new QProcess(this);
164 | QStringList env(QProcess::systemEnvironment());
165 | env.append(CARBON_GUI_PARENT"=true");
166 | process->setEnvironment(env);
167 | connect(process, SIGNAL(finished(int)), this, SLOT(processFinished(int)));
168 | connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readStdOut()));
169 | connect(process, SIGNAL(readyReadStandardError()), this, SLOT(readStdErr()));
170 | }
171 | setButtons(Cancel);
172 | QTimer::singleShot(0, this, SLOT(doNext()));
173 | QTimer::singleShot(0, this, SLOT(showDetails()));
174 | exec();
175 | }
176 |
177 | void RunnerDialog::doNext() {
178 | syncStatus = STARTUP;
179 | if (currentSession != endSession) {
180 | sessionLabel->setText((*currentSession)->name());
181 |
182 | QStringList arguments;
183 |
184 | (*currentSession)->save();
185 | arguments << (*currentSession)->fileName();
186 |
187 | if (dryRun) {
188 | arguments << "-d";
189 | }
190 |
191 | stdErr = QString();
192 | prevStout = QString();
193 | sessionProgress->setValue(0);
194 | sessionProgress->setMaximum(0);
195 | updateUnity(false);
196 | status->setText(updatedFiles(0));
197 | fileProgress->setValue(0);
198 | logFile.close();
199 | logFile.setFileName((*currentSession)->fileName() + CARBON_LOG_EXTENSION);
200 | logFile.open(QIODevice::WriteOnly);
201 | process->start(CARBON_RUNNER, arguments, QIODevice::ReadOnly);
202 | } else {
203 | fileProgress->setValue(fileProgress->maximum());
204 | setButtons(Close);
205 | }
206 | }
207 |
208 | void RunnerDialog::processFinished(int exitCode) {
209 | logFile.close();
210 |
211 | if (0 != exitCode) {
212 | QString errorMsg = tr("The rsync backend returned the following error:
%1
").arg(toStr(exitCode));
213 | status->setText(tr("An error ocurred"));
214 | if (currentSession == endSession) {
215 | MessageBox::error(this, errorMsg);
216 | return;
217 | } else if (QMessageBox::No == MessageBox::warningYesNo(this, errorMsg + "" + tr("Continue with next session?") + "
")) {
218 | return;
219 | }
220 | }
221 |
222 | completedSessions++;
223 | sessionProgress->setMaximum(1000);
224 | sessionProgress->setValue(sessionProgress->maximum());
225 | overallProgress->setValue(completedSessions * 1000);
226 | updateUnity(currentSession == endSession);
227 | if (currentSession == endSession) {
228 | status->setText(tr("Cancelled"));
229 | } else {
230 | if (0 == exitCode) {
231 | status->setText(tr("Finished"));
232 | }
233 | currentSession++;
234 | doNext();
235 | }
236 | }
237 |
238 | void RunnerDialog::readStdOut() {
239 | if (!process) {
240 | return;
241 | }
242 |
243 | QByteArray all(process->readAllStandardOutput());
244 | QString raw(prevStout + all);
245 | QString str(raw.replace('\r', '\n'));
246 | bool doLast(str.size() && '\n' == str[str.size() - 1]);
247 | QStringList lines(str.split('\n', QString::SkipEmptyParts));
248 | QStringList::Iterator it(lines.begin());
249 | QStringList::Iterator end(lines.end());
250 | int numLines(lines.count());
251 |
252 | for (int l = 1; it != end; ++it, ++l) {
253 | if (l == numLines) {
254 | if (doLast) {
255 | processLine(*it);
256 | } else {
257 | prevStout = *it;
258 | }
259 | } else {
260 | processLine(*it);
261 | }
262 | }
263 | str = removePrefixes(all);
264 | output->append(str);
265 | QTextStream(&logFile) << str;
266 | }
267 |
268 | void RunnerDialog::readStdErr() {
269 | if (!process) {
270 | return;
271 | }
272 |
273 | QString str(removePrefixes(process->readAllStandardError()));
274 |
275 | stdErr += str;
276 | output->append("" + str + "");
277 | QTextStream(&logFile) << str;
278 | }
279 |
280 | void RunnerDialog::showDetails(bool show) {
281 | int w = width();
282 | if (show) {
283 | setMaximumHeight(4096);
284 | }
285 |
286 | detailsButton->setText(show ? tr("Hide Details <<") : tr("Show Details >>"));
287 | output->setVisible(show);
288 | adjustSize();
289 | resize(width()setText(line);
304 | fileProgress->setValue(0);
305 | } else if (isMsg) {
306 | line.replace(CARBON_MSG_PREFIX, QString())
307 | .replace("Cleaning old backups", tr("Cleaning old backups"))
308 | .replace("Erasing", tr("Erasing"));
309 |
310 | status->setText(line);
311 | syncStatus = SYNCING;
312 | } else if (isError) {
313 | line.replace(CARBON_ERROR_PREFIX, QString())
314 | .replace("Cleaning old backups", tr("Cleaning old backups"))
315 | .replace("Erasing", tr("Erasing"));
316 |
317 | status->setText(QString("") + line + QString(""));
318 | syncStatus = SYNCING;
319 | } /*else if (STARTUP==syncStatus && -1!=line.indexOf("files to consider")) {
320 | QStringList lst(line.split(' ', QString::SkipEmptyParts));
321 |
322 | if (lst.size())
323 | {
324 | bool ok;
325 | int total(lst[0].toInt(&ok));
326 |
327 | if (ok)
328 | {
329 | sessionProgress->setMaximum(total);
330 | syncStatus=SYNCING;
331 | }
332 | }
333 | }*/ else if (STARTUP == syncStatus && -1 != line.indexOf(" files...")) {
334 | QStringList lst(line.split(' ', QString::SkipEmptyParts));
335 |
336 | if (lst.size()) {
337 | bool ok;
338 | int total(lst[0].toInt(&ok));
339 |
340 | if (ok) {
341 | status->setText(updatedFiles(total));
342 | }
343 | }
344 | } else if (-1 != line.indexOf("%")) {
345 | QStringList lst(line.split(' ', QString::SkipEmptyParts));
346 |
347 | if (lst.size() > 2) {
348 | int percent;
349 |
350 | if (1 == sscanf(lst[1].toLatin1().constData(), "%d%%", &percent)) {
351 | fileProgress->setValue(percent);
352 | syncStatus = SYNCING;
353 | }
354 | static const QString constGlobalCheck = QLatin1String("to-check=");
355 | foreach (const QString &str, lst) {
356 | if (str.startsWith(constGlobalCheck)) {
357 | lst = str.mid(constGlobalCheck.length()).split('/');
358 | if (lst.size() >= 2) {
359 | QString totStr = lst.at(1);
360 | totStr = totStr.left(totStr.length() - 1);
361 | int total = totStr.toInt();
362 | int left = lst.at(0).toInt();
363 | if (0 == sessionProgress->maximum()) {
364 | sessionProgress->setMaximum(1000);
365 | }
366 |
367 | if (total > 0 && left <= total) {
368 | if (0 == left) {
369 | sessionProgress->setValue(sessionProgress->maximum());
370 | } else {
371 | sessionProgress->setValue((((total - left) * 1000.0) / total) + 0.5);
372 | }
373 | overallProgress->setValue((1000 * completedSessions) + (sessionProgress->value()));
374 | updateUnity(false);
375 | }
376 | }
377 | break;
378 | }
379 | }
380 | }
381 | }
382 | }
383 |
384 | void RunnerDialog::slotButtonClicked(int btn) {
385 | if (Dialog::Cancel == btn && process && QProcess::NotRunning != process->state()) {
386 | switch (MessageBox::warningYesNoCancel(this, tr("Abort the current synchronisation?"),
387 | tr("Abort"), tr("Abort Now"),
388 | tr("Abort After Current Sync"))) {
389 | case QMessageBox::Yes:
390 | QProcess::startDetached(CARBON_TERMINATE, QStringList() << QString::number(process->pid()));
391 | for (int i = 0; i < 50 && QProcess::Running == process->state(); ++i) {
392 | Utils::msleep(10);
393 | }
394 | process->kill();
395 | disconnectProcess();
396 | if (currentSession != endSession) {
397 | (*currentSession)->removeLockFile();
398 | }
399 | updateUnity(true);
400 | QDialog::reject();
401 | break;
402 | case QMessageBox::No:
403 | currentSession = endSession;
404 | default:
405 | break;
406 | }
407 | } else {
408 | Dialog::slotButtonClicked(btn);
409 | }
410 | }
411 |
412 | void RunnerDialog::disconnectProcess() {
413 | if (process) {
414 | disconnect(process, SIGNAL(finished(int)), this, SLOT(processFinished(int)));
415 | disconnect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readStdOut()));
416 | disconnect(process, SIGNAL(readyReadStandardError()), this, SLOT(readStdErr()));
417 | process->deleteLater();
418 | process = 0;
419 | }
420 | }
421 |
422 | void RunnerDialog::updateUnity(bool finished) {
423 | #ifdef QT_QTDBUS_FOUND
424 | QList args;
425 | double progress = finished || overallProgress->maximum() < 1 ? 0.0 : (overallProgress->value() / (overallProgress->maximum() * 1.0));
426 | bool showProgress = progress > -0.1 && progress < 100 && !finished;
427 | QMap props;
428 | props["count-visible"] = !finished && sessionCount > 1;
429 | props["count"] = (long long)(sessionCount - completedSessions);
430 | props["progress-visible"] = showProgress;
431 | props["progress"] = showProgress ? progress : 0.0;
432 | args.append(0 == getuid() ? "application://carbon-root.desktop" : "application://carbon.desktop");
433 | args.append(props);
434 | unityMessage.setArguments(args);
435 | QDBusConnection::sessionBus().send(unityMessage);
436 | #else
437 | Q_UNUSED(finished)
438 | #endif
439 | }
440 |
--------------------------------------------------------------------------------
/ui/runnerdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef __RUNNER_DIALOG_H__
2 | #define __RUNNER_DIALOG_H__
3 |
4 | /*
5 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
6 |
7 | ----
8 |
9 | This program is free software; you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation; either version 2 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 | General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program; see the file COPYING. If not, write to
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 | Boston, MA 02110-1301, USA.
23 | */
24 |
25 | #include "dialog.h"
26 | #include "config.h"
27 | #include
28 | #include
29 | #ifdef QT_QTDBUS_FOUND
30 | #include
31 | #endif
32 | #include "ui_runnerwidget.h"
33 |
34 | class Session;
35 | class QProcess;
36 |
37 |
38 | class RunnerDialog : public Dialog, Ui::RunnerWidget {
39 | Q_OBJECT
40 |
41 | public:
42 | enum EStatus {
43 | STARTUP,
44 | SYNCING
45 | };
46 |
47 | RunnerDialog(QWidget *parent);
48 | virtual ~RunnerDialog();
49 |
50 | void go(const QList &sessions, bool dry);
51 |
52 | public Q_SLOTS:
53 | void doNext();
54 | void processFinished(int exitCode);
55 | void readStdOut();
56 | void readStdErr();
57 | void showDetails(bool show = false);
58 |
59 | private:
60 | void processLine(QString &line);
61 | void slotButtonClicked(int btn);
62 | void disconnectProcess();
63 | void updateUnity(bool finished);
64 |
65 | private:
66 | QList::ConstIterator currentSession;
67 | QList::ConstIterator endSession;
68 | QString prevStout;
69 | QString stdErr;
70 | bool dryRun;
71 | QProcess *process;
72 | QFile logFile;
73 | EStatus syncStatus;
74 | int sessionCount;
75 | int completedSessions;
76 | #ifdef QT_QTDBUS_FOUND
77 | QDBusMessage unityMessage;
78 | #endif
79 | };
80 |
81 | #endif
82 |
--------------------------------------------------------------------------------
/ui/runnerwidget.ui:
--------------------------------------------------------------------------------
1 |
2 | RunnerWidget
3 |
4 |
5 |
6 | 0
7 | 0
8 | 408
9 | 200
10 |
11 |
12 |
13 |
14 | 0
15 |
16 | -
17 |
18 |
19 |
20 | 0
21 | 0
22 |
23 |
24 |
25 | Session:
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 | 0
34 | 0
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | -
43 |
44 |
45 | Status:
46 |
47 |
48 |
49 | -
50 |
51 |
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 | File progress:
60 |
61 |
62 |
63 | -
64 |
65 |
66 | 0
67 |
68 |
69 |
70 | -
71 |
72 |
73 | Session progress:
74 |
75 |
76 |
77 | -
78 |
79 |
80 | 0
81 |
82 |
83 |
84 | -
85 |
86 |
87 | Overall progress:
88 |
89 |
90 |
91 | -
92 |
93 |
94 | 0
95 |
96 |
97 |
98 | -
99 |
100 |
101 | true
102 |
103 |
104 |
105 | -
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/ui/session.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
3 |
4 | ----
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; see the file COPYING. If not, write to
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA.
20 | */
21 |
22 | #include "session.h"
23 | #include "utils.h"
24 | #include "config.h"
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 | #define CFG_READ_BOOL(V, DEF) V=entries.contains(#V) ? QLatin1String("true")==entries[#V] : DEF
33 | #define CFG_READ_INT(V, DEF) V=entries.contains(#V) ? entries[#V].toInt() : DEF
34 | #define CFG_READ_STR(V, DEF) V=entries.contains(#V) ? entries[#V] : DEF
35 | #define CFG_READ_STRING(V, DEF) V=entries.contains(#V) ? entries[#V] : DEF
36 |
37 | #define CFG_WRITE_INT(V) out << #V << "=" << V << endl
38 | #define CFG_WRITE_BOOL(V) out << #V << "=" << (V ? "true" : "false") << endl
39 | #define CFG_WRITE_STR(V) out << #V << "=" << V << endl
40 |
41 | static QString getName(const QString &f) {
42 | return QFileInfo(f).fileName().remove(CARBON_EXTENSION);
43 | }
44 |
45 | Session::Session(const QString &file, bool def)
46 | : isDef(def)
47 | , exclude(0) {
48 | if (isDef) {
49 | dirName = Utils::configDir(QString(), true);
50 | sessionName = QLatin1String("default");
51 | } else {
52 | dirName = Utils::getDir(file);
53 | sessionName = getName(file);
54 | }
55 |
56 | QString fName = fileName();
57 |
58 | if (isDef) {
59 | if (!QFile::exists(fName)) {
60 | fName = QLatin1String(CARBON_SYSTEM_DEF_FILE);
61 | }
62 | QString exFileName = excludeFileName();
63 | if (!QFile::exists(exFileName)) {
64 | exFileName = QLatin1String(CARBON_SYSTEM_DEF_FILE CARBON_EXCLUDE_EXTENSION);
65 | }
66 | exclude = new ExcludeFile(exFileName);
67 | } else {
68 | exclude = new ExcludeFile(excludeFileName());
69 | }
70 |
71 | QFile f(fName);
72 | QMap entries;
73 | if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
74 | QTextStream in(&f);
75 | while (!in.atEnd()) {
76 | QString line = in.readLine();
77 | if (!line.startsWith("#") && !line.startsWith("[") && line.contains('=')) {
78 | QStringList parts = line.split("=");
79 | if (parts.length() > 1) {
80 | entries[parts.at(0)] = parts.at(1);
81 | }
82 | }
83 | }
84 | }
85 |
86 | CFG_READ_STR(src, QDir::homePath());
87 | CFG_READ_STR(dest, QLatin1String("/tmp"));
88 | CFG_READ_BOOL(archive, true);
89 | CFG_READ_BOOL(recursive, true);
90 | CFG_READ_BOOL(skipFilesOnSizeMatch, false);
91 | CFG_READ_BOOL(skipReceiverNewerFiles, true);
92 | CFG_READ_BOOL(keepPartial, false);
93 | CFG_READ_BOOL(onlyUpdate, false);
94 | CFG_READ_BOOL(useCompression, false);
95 | CFG_READ_BOOL(checksum, false);
96 | CFG_READ_BOOL(windowsCompat, false);
97 | CFG_READ_BOOL(ignoreExisting, false);
98 | CFG_READ_BOOL(makeBackups, false);
99 | CFG_READ_BOOL(deleteExtraFilesOnReceiver, true);
100 | CFG_READ_BOOL(copySymlinksAsSymlinks, true);
101 | CFG_READ_BOOL(preservePermissions, true);
102 | CFG_READ_BOOL(preserveSpecialFiles, true);
103 | CFG_READ_BOOL(preserveOwner, true);
104 | CFG_READ_BOOL(dontLeaveFileSystem, false);
105 | CFG_READ_BOOL(preserveGroup, true);
106 | CFG_READ_BOOL(modificationTimes, true);
107 | CFG_READ_BOOL(cvsExclude, true);
108 | CFG_READ_INT(maxBackupAge, 7);
109 | CFG_READ_INT(maxFileSize, 0);
110 |
111 | if (archive) {
112 | copySymlinksAsSymlinks = preservePermissions = preserveSpecialFiles = preserveOwner =
113 | preserveGroup = true;
114 | }
115 | if (maxBackupAge > 365) {
116 | maxBackupAge = 365;
117 | } else if (maxBackupAge < 0) {
118 | maxBackupAge = 0;
119 | }
120 |
121 | if (maxFileSize > 65535) {
122 | maxFileSize = 65535;
123 | } else if (maxFileSize < 0) {
124 | maxFileSize = 0;
125 | }
126 |
127 | CFG_READ_STRING(customOptions, QString());
128 |
129 | if (!customOptions.isEmpty()) {
130 | if (QLatin1Char('\"') == customOptions[0]) {
131 | customOptions = customOptions.mid(1);
132 | }
133 | if (!customOptions.isEmpty() && QChar('\"') == customOptions[customOptions.size() - 1]) {
134 | customOptions = customOptions.left(customOptions.size() - 1);
135 | }
136 | if (!customOptions.isEmpty()) {
137 | customOptions.replace("\\\"", "\"").replace("\\\'", "\'");
138 | }
139 | }
140 |
141 | updateLast();
142 | }
143 |
144 | Session::Session()
145 | : isDef(false)
146 | , exclude(0L) {
147 | }
148 |
149 | Session::~Session() {
150 | delete exclude;
151 | }
152 |
153 | void Session::updateLast() {
154 | QFile log(logFileName());
155 |
156 | lastSyncDate = !log.exists()
157 | ? QString()
158 | : QFileInfo(log).created().toString(Qt::SystemLocaleShortDate);
159 | }
160 |
161 | bool Session::save(const QString &name) {
162 | QString fName = dirName + (isDef ? sessionName : name) + QLatin1String(CARBON_EXTENSION);
163 | QFile f(fName);
164 |
165 | if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
166 | return false;
167 | }
168 |
169 | if (!isDef && name != sessionName) {
170 | removeFiles();
171 | sessionName = name;
172 | }
173 |
174 | QTextStream out(&f);
175 |
176 | out << "[Settings]" << endl;
177 | CFG_WRITE_STR(src);
178 | CFG_WRITE_STR(dest);
179 | CFG_WRITE_BOOL(archive);
180 | CFG_WRITE_BOOL(recursive);
181 | CFG_WRITE_BOOL(skipFilesOnSizeMatch);
182 | CFG_WRITE_BOOL(skipReceiverNewerFiles);
183 | CFG_WRITE_BOOL(keepPartial);
184 | CFG_WRITE_BOOL(onlyUpdate);
185 | CFG_WRITE_BOOL(useCompression);
186 | CFG_WRITE_BOOL(checksum);
187 | CFG_WRITE_BOOL(windowsCompat);
188 | CFG_WRITE_BOOL(ignoreExisting);
189 | CFG_WRITE_BOOL(makeBackups);
190 | CFG_WRITE_BOOL(deleteExtraFilesOnReceiver);
191 | CFG_WRITE_BOOL(copySymlinksAsSymlinks);
192 | CFG_WRITE_BOOL(preservePermissions);
193 | CFG_WRITE_BOOL(preserveSpecialFiles);
194 | CFG_WRITE_BOOL(preserveOwner);
195 | CFG_WRITE_BOOL(dontLeaveFileSystem);
196 | CFG_WRITE_BOOL(preserveGroup);
197 | CFG_WRITE_BOOL(modificationTimes);
198 | CFG_WRITE_BOOL(cvsExclude);
199 | CFG_WRITE_INT(maxBackupAge);
200 | CFG_WRITE_INT(maxFileSize);
201 |
202 | QString temp = customOptions;
203 | if (!temp.isEmpty()) {
204 | temp = QChar('\"') + temp.replace('\"', "\\\"").replace('\'', "\\\'") + QChar('\"');
205 | }
206 | out << "customOptions=" << temp << endl;
207 |
208 | if (exclude) {
209 | exclude->save(excludeFileName());
210 | }
211 |
212 | return true;
213 | }
214 |
215 | bool Session::erase() {
216 | bool rv(removeFiles());
217 |
218 | if (rv) {
219 | src = QString(); // Stop destructor from saving file!
220 | }
221 |
222 | return rv;
223 | }
224 |
225 | bool Session::sync(bool dryRun) {
226 | if (dryRun) {
227 | return true; // "add -d"
228 | }
229 | return false;
230 | }
231 |
232 | void Session::setName(const QString &v) {
233 | if (v != sessionName && removeFiles()) {
234 | QString oldName(sessionName),
235 | oldDir(dirName);
236 |
237 | dirName = Utils::dataDir(QString(), true);
238 | if (save(v)) {
239 | lastSyncDate = QString();
240 | sessionName = v;
241 | } else {
242 | sessionName = oldName;
243 | dirName = oldDir;
244 | save();
245 | }
246 | }
247 | }
248 |
249 | void Session::setExcludePatterns(const ExcludeFile::PatternList &list) {
250 | if (!exclude) {
251 | exclude = new ExcludeFile(excludeFileName());
252 | }
253 |
254 | exclude->setPatterns(list);
255 | }
256 |
257 | static bool removeFile(const QString &file) {
258 | return file.isEmpty() || !QFile::exists(file) || QFile::remove(file);
259 | }
260 |
261 | bool Session::removeLockFile() {
262 | return removeFile(lockFileName());
263 | }
264 |
265 | bool Session::removeFiles() {
266 | if (removeFile(logFileName()) && removeFile(infoFileName()) && removeFile(lockFileName()) &&
267 | (!exclude || exclude->erase()) && removeFile(fileName())) {
268 | return true;
269 | }
270 |
271 | return false;
272 | }
273 |
--------------------------------------------------------------------------------
/ui/session.h:
--------------------------------------------------------------------------------
1 | #ifndef __SESSION_H__
2 | #define __SESSION_H__
3 |
4 | /*
5 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
6 |
7 | ----
8 |
9 | This program is free software; you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation; either version 2 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 | General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program; see the file COPYING. If not, write to
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 | Boston, MA 02110-1301, USA.
23 | */
24 |
25 | #include
26 | #include
27 | #include "excludefile.h"
28 | #include "config.h"
29 |
30 | class Session {
31 | public:
32 | Session(const QString &name, bool def = false);
33 | Session();
34 | ~Session();
35 |
36 | operator bool() {
37 | return !src.isEmpty();
38 | }
39 | void updateLast();
40 | bool save() {
41 | return save(sessionName);
42 | }
43 | bool save(const QString &name);
44 | bool erase();
45 | bool sync(bool dryRun);
46 |
47 | bool removeLockFile();
48 | bool isDefault() const {
49 | return isDef;
50 | }
51 | const QString & name() const {
52 | return sessionName;
53 | }
54 | QString fileName() const {
55 | return dirName + sessionName + QLatin1String(CARBON_EXTENSION);
56 | }
57 | QString logFileName() const {
58 | return dirName + sessionName + QLatin1String(CARBON_EXTENSION CARBON_LOG_EXTENSION);
59 | }
60 | QString infoFileName() const {
61 | return dirName + sessionName + QLatin1String(CARBON_EXTENSION CARBON_INFO_EXTENSION);
62 | }
63 | QString lockFileName() const {
64 | return dirName + sessionName + QLatin1String(CARBON_EXTENSION CARBON_LOCK_EXTENSION);
65 | }
66 | QString excludeFileName() const {
67 | return dirName + sessionName + QLatin1String(CARBON_EXTENSION CARBON_EXCLUDE_EXTENSION);
68 | }
69 | const QString & last() const {
70 | return lastSyncDate;
71 | }
72 | const QString & source() const {
73 | return src;
74 | }
75 | const QString & destination() const {
76 | return dest;
77 | }
78 | const QString & customOpts() const {
79 | return customOptions;
80 | }
81 | ExcludeFile * excludeFile() const {
82 | return exclude;
83 | }
84 | void setName(const QString &v);
85 | void setDir(const QString &v) {
86 | dirName = v;
87 | }
88 | void setSource(const QString &v) {
89 | src = v;
90 | }
91 | void setDestination(const QString &v) {
92 | dest = v;
93 | }
94 | void setCustomOpts(const QString &v) {
95 | customOptions = v;
96 | }
97 | void setExcludePatterns(const ExcludeFile::PatternList &list);
98 | bool archiveFlag() const {
99 | return archive;
100 | }
101 | bool recursiveFlag() const {
102 | return recursive;
103 | }
104 | bool skipFilesOnSizeMatchFlag() const {
105 | return skipFilesOnSizeMatch;
106 | }
107 | bool skipReceiverNewerFilesFlag() const {
108 | return skipReceiverNewerFiles;
109 | }
110 | bool keepPartialFlag() const {
111 | return keepPartial;
112 | }
113 | bool onlyUpdateFlag() const {
114 | return onlyUpdate;
115 | }
116 | bool useCompressionFlag() const {
117 | return useCompression;
118 | }
119 | bool checksumFlag() const {
120 | return checksum;
121 | }
122 | bool windowsFlag() const {
123 | return windowsCompat;
124 | }
125 | bool ignoreExistingFlag() const {
126 | return ignoreExisting;
127 | }
128 | bool makeBackupsFlag() const {
129 | return makeBackups;
130 | }
131 | bool deleteExtraFilesOnReceiverFlag() const {
132 | return deleteExtraFilesOnReceiver;
133 | }
134 | bool copySymlinksAsSymlinksFlag() const {
135 | return copySymlinksAsSymlinks;
136 | }
137 | bool preservePermissionsFlag() const {
138 | return preservePermissions;
139 | }
140 | bool preserveSpecialFilesFlag() const {
141 | return preserveSpecialFiles;
142 | }
143 | bool preserveOwnerFlag() const {
144 | return preserveOwner;
145 | }
146 | bool dontLeaveFileSystemFlag() const {
147 | return dontLeaveFileSystem;
148 | }
149 | bool preserveGroupFlag() const {
150 | return preserveGroup;
151 | }
152 | bool modificationTimesFlag() const {
153 | return modificationTimes;
154 | }
155 | bool cvsExcludeFlag() const {
156 | return cvsExclude;
157 | }
158 | int maxBackupDays() const {
159 | return maxBackupAge;
160 | }
161 | int maxSize() const {
162 | return maxFileSize;
163 | }
164 | void setArchiveFlag(bool v) {
165 | archive = v;
166 | }
167 | void setRecursiveFlag(bool v) {
168 | recursive = v;
169 | }
170 | void setSkipFilesOnSizeMatchFlag(bool v) {
171 | skipFilesOnSizeMatch = v;
172 | }
173 | void setSkipReceiverNewerFilesFlag(bool v) {
174 | skipReceiverNewerFiles = v;
175 | }
176 | void setKeepPartialFlag(bool v) {
177 | keepPartial = v;
178 | }
179 | void setOnlyUpdateFlag(bool v) {
180 | onlyUpdate = v;
181 | }
182 | void setUseCompressionFlag(bool v) {
183 | useCompression = v;
184 | }
185 | void setChecksumFlag(bool v) {
186 | checksum = v;
187 | }
188 | void setWindowsFlag(bool v) {
189 | windowsCompat = v;
190 | }
191 | void setIgnoreExistingFlag(bool v) {
192 | ignoreExisting = v;
193 | }
194 | void setMakeBackupsFlag(bool v) {
195 | makeBackups = v;
196 | }
197 | void setDeleteExtraFilesOnReceiverFlag(bool v) {
198 | deleteExtraFilesOnReceiver = v;
199 | }
200 | void setCopySymlinksAsSymlinksFlag(bool v) {
201 | copySymlinksAsSymlinks = v;
202 | }
203 | void setPreservePermissionsFlag(bool v) {
204 | preservePermissions = v;
205 | }
206 | void setPreserveSpecialFilesFlag(bool v) {
207 | preserveSpecialFiles = v;
208 | }
209 | void setPreserveOwnerFlag(bool v) {
210 | preserveOwner = v;
211 | }
212 | void setDontLeaveFileSystemFlag(bool v) {
213 | dontLeaveFileSystem = v;
214 | }
215 | void setPreserveGroupFlag(bool v) {
216 | preserveGroup = v;
217 | }
218 | void setModificationTimesFlag(bool v) {
219 | modificationTimes = v;
220 | }
221 | void setCvsExcludeFlag(bool v) {
222 | cvsExclude = v;
223 | }
224 | void setMaxBackupDays(int v) {
225 | maxBackupAge = v;
226 | }
227 | void setMaxSize(int v) {
228 | maxFileSize = v;
229 | }
230 |
231 | private:
232 | Session(const Session &o);
233 |
234 | bool removeFiles();
235 |
236 | private:
237 | bool isDef;
238 | QString dirName;
239 | QString sessionName;
240 | QString lastSyncDate;
241 | QString src;
242 | QString dest;
243 | bool archive;
244 | bool recursive;
245 | bool skipFilesOnSizeMatch;
246 | bool skipReceiverNewerFiles;
247 | bool keepPartial;
248 | bool onlyUpdate;
249 | bool useCompression;
250 | bool checksum;
251 | bool windowsCompat;
252 | bool ignoreExisting;
253 | bool makeBackups;
254 | bool deleteExtraFilesOnReceiver;
255 | bool copySymlinksAsSymlinks;
256 | bool preservePermissions;
257 | bool preserveSpecialFiles;
258 | bool preserveOwner;
259 | bool dontLeaveFileSystem;
260 | bool preserveGroup;
261 | bool modificationTimes;
262 | bool cvsExclude;
263 | int maxBackupAge;
264 | int maxFileSize;
265 | ExcludeFile *exclude;
266 | QString customOptions;
267 | };
268 |
269 | #endif
270 |
--------------------------------------------------------------------------------
/ui/sessiondialog.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
3 |
4 | ----
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; see the file COPYING. If not, write to
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA.
20 | */
21 |
22 | #include "session.h"
23 | #include "sessiondialog.h"
24 | #include "sessionwidget.h"
25 | #include "generaloptionswidget.h"
26 | #include "excludewidget.h"
27 | #include "rsyncoptionswidget.h"
28 | #include "mainwindow.h"
29 | #include "messagebox.h"
30 | #include "pagewidget.h"
31 | #include "utils.h"
32 | #include
33 |
34 | SessionDialog::SessionDialog(QWidget *parent)
35 | : Dialog(parent, "SessionDialog", QSize(800, 600)) {
36 | pageWidget = new PageWidget(this);
37 | setButtons(Ok | Cancel | User1 | User2);
38 | setButtonText(User1, tr("Set Defaults"));
39 | setButtonText(User2, tr("Show RSync Manual"));
40 |
41 | generalOptions = new GeneralOptionsWidget(0);
42 | excludeWidget = new ExcludeWidget(0);
43 | rSyncOptionsWidget = new RSyncOptionsWidget(0);
44 |
45 | generalPage = pageWidget->addPage(generalOptions, tr("General Options"), QIcon::fromTheme("folder"), tr("Basic Synchronisation Session Options"));
46 | excludePage = pageWidget->addPage(excludeWidget, tr("Exclusions"), QIcon::fromTheme("edit-delete"), tr("Exclude Files And Folders From Synchronisation"));
47 | rSyncOptionsPage = pageWidget->addPage(rSyncOptionsWidget, tr("Backend Options"), MainWindow::appIcon, tr("RSync Backend Options"));
48 | setMainWidget(pageWidget);
49 | }
50 |
51 | bool SessionDialog::run(Session &session, bool edit) {
52 | origName = edit ? session.name() : QString();
53 | origSrcPath = edit ? session.source() : QString();
54 | setCaption(edit ? tr("Edit Session") : tr("Create New Session"));
55 | generalOptions->set(session, edit);
56 | excludeWidget->set(session);
57 | rSyncOptionsWidget->set(session);
58 | pageWidget->setCurrentPage(generalPage);
59 |
60 | return QDialog::Accepted == exec();
61 | }
62 |
63 | void SessionDialog::slotButtonClicked(int btn) {
64 | switch (btn) {
65 | case Ok: {
66 | QString newName(generalOptions->name());
67 | QString newSrc(generalOptions->src());
68 |
69 | if (newName.isEmpty()) {
70 | pageWidget->setCurrentPage(generalPage);
71 | MessageBox::error(this, tr("You must specify a name!"));
72 | } else if (generalOptions->src().isEmpty()) {
73 | pageWidget->setCurrentPage(generalPage);
74 | MessageBox::error(this, tr("You must specify a source!"));
75 | } /*else if (generalOptions->src().protocol()!="file") {
76 | pageWidget->setCurrentPage(generalPage);
77 | MessageBox::error(this, tr("Source must be on the local filesystem."));
78 | }*/ else if (generalOptions->dest().isEmpty()) {
79 | pageWidget->setCurrentPage(generalPage);
80 | MessageBox::error(this, tr("You must specify a destination!"));
81 | } /*else if (generalOptions->dest().protocol()!="file" &&
82 | generalOptions->dest().protocol()!="sftp" &&
83 | generalOptions->dest().protocol()!="fish") {
84 | pageWidget->setCurrentPage(generalPage);
85 | MessageBox::error(this, tr("Only file:/, fish:/, and sftp:/ protocols are allowed."));
86 | } else if ( (generalOptions->dest().protocol()=="sftp" ||
87 | generalOptions->dest().protocol()=="fish") &&
88 | (!generalOptions->dest().hasUser() ||
89 | !generalOptions->dest().hasHost() ) ) {
90 | setCurrentPage(generalPage);
91 | MessageBox::error(this, tr("Remote URLs require user and host."));
92 | }*/ else if (generalOptions->dest().startsWith(generalOptions->src())) {
93 | pageWidget->setCurrentPage(generalPage);
94 | MessageBox::error(this, tr("Destination must not be located within source."));
95 | } else if (newName != origName && ((SessionWidget *)parent())->exists(newName)) {
96 | pageWidget->setCurrentPage(generalPage);
97 | MessageBox::error(this, tr("A session named %1 already exists.
"
98 | "Please choose a different name.").arg(newName));
99 | } else if (newSrc != origSrcPath && ((SessionWidget *)parent())->srcExists(newSrc)) {
100 | pageWidget->setCurrentPage(generalPage);
101 | MessageBox::error(this, tr("A session with source %1 already exists.
"
102 | "Please choose a different path.").arg(newSrc));
103 | } else if (-1 != rSyncOptionsWidget->getCustom().indexOf("--out-format") ||
104 | -1 != rSyncOptionsWidget->getCustom().indexOf("--backup-dir")) {
105 | pageWidget->setCurrentPage(rSyncOptionsPage);
106 | MessageBox::error(this, tr("Sorry, custom backend options cannot contain --out-format"
107 | "or --backup-dir
"));
108 | } else {
109 | QDialog::accept();
110 | }
111 | break;
112 | }
113 | case User1:
114 | if (QMessageBox::Yes == MessageBox::warningYesNo(this, tr("Use the current session settings as the defaults for new sessions?"))) {
115 | emit setAsDefaults();
116 | }
117 | break;
118 | case User2:
119 | if (QLatin1String("KDE") == QLatin1String(qgetenv("XDG_CURRENT_DESKTOP")) && !Utils::findExe("khelpcenter").isEmpty()) {
120 | QProcess::startDetached("khelpcenter", QStringList() << "man:/rsync");
121 | } else if (!Utils::findExe("yelp").isEmpty()) {
122 | QProcess::startDetached("yelp", QStringList() << "info:rsync");
123 | }
124 | break;
125 | default:
126 | Dialog::slotButtonClicked(btn);
127 | }
128 | }
129 |
130 | void SessionDialog::get(Session &session) {
131 | excludeWidget->get(session);
132 | rSyncOptionsWidget->get(session);
133 | generalOptions->get(session);
134 | }
135 |
--------------------------------------------------------------------------------
/ui/sessiondialog.h:
--------------------------------------------------------------------------------
1 | #ifndef __SESSION_DIALOG_H__
2 | #define __SESSION_DIALOG_H__
3 |
4 | /*
5 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
6 |
7 | ----
8 |
9 | This program is free software; you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation; either version 2 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 | General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program; see the file COPYING. If not, write to
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 | Boston, MA 02110-1301, USA.
23 | */
24 |
25 | #include "dialog.h"
26 |
27 | class Session;
28 | class GeneralOptionsWidget;
29 | class ExcludeWidget;
30 | class RSyncOptionsWidget;
31 | class PageWidget;
32 | class PageWidgetItem;
33 |
34 | class SessionDialog : public Dialog {
35 | Q_OBJECT
36 |
37 | public:
38 | SessionDialog(QWidget *parent);
39 |
40 | bool run(Session &session, bool edit);
41 | void slotButtonClicked(int btn);
42 | void get(Session &session);
43 | void getRSyncDefaults(Session &session);
44 | void getExcludeDefaults(Session &session);
45 |
46 | Q_SIGNALS:
47 | void setAsDefaults();
48 |
49 | private:
50 | PageWidget *pageWidget;
51 | QString origName;
52 | QString origSrcPath;
53 | GeneralOptionsWidget *generalOptions;
54 | ExcludeWidget *excludeWidget;
55 | RSyncOptionsWidget *rSyncOptionsWidget;
56 | PageWidgetItem *generalPage;
57 | PageWidgetItem *excludePage;
58 | PageWidgetItem *rSyncOptionsPage;
59 | };
60 |
61 | #endif
62 |
--------------------------------------------------------------------------------
/ui/sessionwidget.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
3 |
4 | ----
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; see the file COPYING. If not, write to
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA.
20 | */
21 |
22 | #include "sessionwidget.h"
23 | #include "sessiondialog.h"
24 | #include "session.h"
25 | #include "runnerdialog.h"
26 | #include "config.h"
27 | #include "messagebox.h"
28 | #include "utils.h"
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 |
38 | #define CFG_GROUP "SessionWidget/"
39 | #define CFG_COL_SIZES CFG_GROUP "List"
40 |
41 | class CLogViewer : public Dialog {
42 | public:
43 |
44 | CLogViewer(QWidget *parent)
45 | : Dialog(parent) {
46 | edit = new QTextEdit(this);
47 | edit->setReadOnly(true);
48 | setMainWidget(edit);
49 | setButtons(Close);
50 | }
51 |
52 | void show(const Session &session) {
53 | QFile file(session.logFileName());
54 |
55 | edit->setText(file.open(QIODevice::ReadOnly)
56 | ? file.readAll()
57 | : tr("Could not open log file."));
58 | file.close();
59 | setCaption(tr("%1 Log").arg(session.name()));
60 | resize(800, 500);
61 | QDialog::show();
62 | }
63 |
64 | private:
65 |
66 | QTextEdit *edit;
67 | };
68 |
69 | enum EColumns {
70 | COL_NAME,
71 | COL_TYPE,
72 | COL_LAST_RUN,
73 |
74 | NUM_COLS
75 | };
76 |
77 | static QString typeStr(bool backup) {
78 | return backup ? QObject::tr("Backup") : QObject::tr("Synchronisation");
79 | }
80 |
81 | class SessionWidgetItem : public QTreeWidgetItem {
82 | public:
83 | SessionWidgetItem(QTreeWidget *parent, const QString &s)
84 | : QTreeWidgetItem(parent)
85 | , session(new Session(s)) {
86 | update();
87 | }
88 |
89 | SessionWidgetItem(QTreeWidget *parent, Session *s)
90 | : QTreeWidgetItem(parent)
91 | , session(s) {
92 | update();
93 | session->save();
94 | }
95 |
96 | void update() {
97 | setText(COL_NAME, session->name());
98 | setText(COL_TYPE, typeStr(session->makeBackupsFlag()));
99 | setText(COL_LAST_RUN, session->last().isEmpty() ? QObject::tr("Never") : session->last());
100 | setToolTip();
101 | }
102 |
103 | void setLastRun(const QString &str) {
104 | setText(COL_LAST_RUN, str);
105 | setToolTip();
106 | }
107 |
108 | operator bool() {
109 | return session;
110 | }
111 |
112 | Session & sessionData() {
113 | return *session;
114 | }
115 |
116 | void remove() {
117 | if (session->erase()) {
118 | delete session;
119 | delete this;
120 | }
121 | }
122 |
123 | private:
124 | void setToolTip() {
125 | QString tip(QObject::tr("%1
"
126 | "
"
127 | "Source: | %2 |
"
128 | "Destination: | %3 |
")
129 | .arg(text(COL_NAME))
130 | .arg(session->source())
131 | .arg(session->destination()));
132 |
133 | for (int i = 0; i < NUM_COLS; ++i) {
134 | QTreeWidgetItem::setToolTip(i, tip);
135 | }
136 | }
137 |
138 | private:
139 | Session *session;
140 | };
141 |
142 | static QStringList toNames(QList &items) {
143 | QStringList names;
144 | QList::ConstIterator it(items.constBegin());
145 | QList::ConstIterator end(items.constEnd());
146 |
147 | for (; it != end; ++it)
148 | names.append(((SessionWidgetItem *)(*it))->sessionData().name());
149 |
150 | return names;
151 | }
152 |
153 | SessionWidget::SessionWidget(QWidget *parent)
154 | : QWidget(parent)
155 | , defSession(tr("New Session"), true)
156 | , sessionDialog(0L)
157 | , runnerDialog(0L)
158 | , logViewer(0L)
159 | , menu(0L) {
160 | setupUi(this);
161 | setupWidgets();
162 | QTimer::singleShot(0, this, SLOT(loadSessions()));
163 | }
164 |
165 | SessionWidget::~SessionWidget() {
166 | QStringList list;
167 | for (int i = 0; i < NUM_COLS; ++i) {
168 | list << QString::number(sessions->header()->sectionSize(i));
169 | }
170 |
171 | QSettings cfg;
172 | cfg.setValue(CFG_COL_SIZES, list);
173 | }
174 |
175 | bool SessionWidget::exists(const QString &name) const {
176 | return 0 != sessions->findItems(name, Qt::MatchExactly).count();
177 | }
178 |
179 | bool SessionWidget::srcExists(const QString &path) const {
180 | for (int i = 0; i < sessions->topLevelItemCount(); ++i) {
181 | SessionWidgetItem *item = static_cast(sessions->topLevelItem(i));
182 | if (item->sessionData().source() == path) {
183 | return true;
184 | }
185 | }
186 | return false;
187 | }
188 |
189 | void SessionWidget::setBackground(const QIcon &icon) {
190 | sessions->setBackground(icon);
191 | }
192 |
193 | void SessionWidget::setupWidgets() {
194 | controlSyncButtons();
195 | controlButtons();
196 | connect(sessions, SIGNAL(itemSelectionChanged()), SLOT(controlButtons()));
197 | }
198 |
199 | void SessionWidget::newSession() {
200 | createSessionDialog();
201 |
202 | if (sessionDialog->run(defSession, false)) {
203 | Session *session = new Session;
204 |
205 | sessionDialog->get(*session);
206 |
207 | SessionWidgetItem *item = new SessionWidgetItem(sessions, session);
208 |
209 | if (!*item) {
210 | delete item;
211 | }
212 |
213 | controlButtons();
214 | controlSyncButtons();
215 | }
216 | }
217 |
218 | void SessionWidget::editSession() {
219 | QList sessionList(sessions->selectedItems());
220 |
221 | if (1 == sessionList.count()) {
222 | createSessionDialog();
223 |
224 | SessionWidgetItem *session = (SessionWidgetItem *)sessionList.at(0);
225 |
226 | if (sessionDialog->run(session->sessionData(), true)) {
227 | sessionDialog->get(session->sessionData());
228 | session->sessionData().save();
229 | session->update();
230 | }
231 | }
232 | }
233 |
234 | void SessionWidget::removeSession() {
235 | QList sessionList(sessions->selectedItems());
236 | QStringList names(toNames(sessionList));
237 |
238 | if ((sessionList.count() == 1 && QMessageBox::Yes == MessageBox::warningYesNo(this, tr("Delete %1?").arg(*(names.begin())))) ||
239 | (sessionList.count() > 1 && QMessageBox::Yes == MessageBox::warningYesNoList(this, tr("Delete the following sessions?"), names))) {
240 | QList::Iterator it(sessionList.begin());
241 | QList::Iterator end(sessionList.end());
242 |
243 | for (; it != end; ++it) {
244 | SessionWidgetItem *item = (SessionWidgetItem *)(*it);
245 | item->remove();
246 | }
247 |
248 | controlButtons();
249 | controlSyncButtons();
250 | }
251 | }
252 |
253 | void SessionWidget::showSessionLog() {
254 | QList sessionList(sessions->selectedItems());
255 |
256 | if (1 == sessionList.count()) {
257 | if (!logViewer) {
258 | logViewer = new CLogViewer(this);
259 | }
260 |
261 | logViewer->show(((SessionWidgetItem *)(*(sessionList.begin())))->sessionData());
262 | }
263 | }
264 |
265 | void SessionWidget::dryRunSession() {
266 | doSessions(true);
267 | }
268 |
269 | void SessionWidget::syncSession() {
270 | doSessions(false);
271 | }
272 |
273 | void SessionWidget::restoreSession(bool on) {
274 | if (!on) {
275 | controlSyncButtons();
276 | controlButtons();
277 | }
278 | }
279 |
280 | void SessionWidget::controlButtons() {
281 | QList sessionList(sessions->selectedItems());
282 |
283 | emit singleItemSelected(1 == sessionList.count());
284 | emit itemsSelected(sessionList.count() > 0);
285 | emit haveLog(1 == sessionList.count() &&
286 | !((SessionWidgetItem *)(*(sessionList.begin())))->sessionData().last().isEmpty());
287 | }
288 |
289 | void SessionWidget::setAsDefaults() {
290 | sessionDialog->get(defSession);
291 | defSession.save(QString());
292 | }
293 |
294 | void SessionWidget::controlSyncButtons() {
295 | emit haveSessions(sessions->topLevelItemCount() > 0);
296 | }
297 |
298 | void SessionWidget::loadSessions() {
299 | QFileInfoList sessionList = QDir(Utils::dataDir(QString(), true)).entryInfoList(QStringList() << "*" CARBON_EXTENSION, QDir::NoDotAndDotDot | QDir::Files);
300 | int pos;
301 | int srlen(strlen(CARBON_RUNNER));
302 |
303 | foreach (const QFileInfo &session, sessionList) {
304 | SessionWidgetItem *item = new SessionWidgetItem(sessions, session.absoluteFilePath());
305 |
306 | if (!*item) {
307 | delete item;
308 | }
309 | }
310 |
311 | controlSyncButtons();
312 |
313 | QStringList list;
314 | QSettings cfg;
315 | list = cfg.value(CFG_COL_SIZES, list).toStringList();
316 |
317 | if (NUM_COLS == list.count()) {
318 | for (int i = 0; i < NUM_COLS; ++i) {
319 | sessions->header()->resizeSection(i, list[i].toInt());
320 | }
321 | }
322 |
323 | sessions->sortItems(0, Qt::AscendingOrder);
324 | }
325 |
326 | void SessionWidget::contextMenuEvent(QContextMenuEvent *e) {
327 | if (menu) {
328 | menu->popup(e->globalPos());
329 | }
330 | }
331 |
332 | void SessionWidget::doSessions(bool dryRun) {
333 | QList sessionList(selectedSessions());
334 |
335 | if (sessionList.count()) {
336 | QStringList names(toNames(sessionList));
337 |
338 | if ((1 == names.count() &&
339 | QMessageBox::Yes == MessageBox::questionYesNo(this, dryRun
340 | ? tr("Perform a dry run of %1?").arg(*(names.begin()))
341 | : tr("Synchronise %1").arg(*(names.begin())))) ||
342 | (names.count() > 1 &&
343 | QMessageBox::Yes == MessageBox::questionYesNoList(this, dryRun
344 | ? tr("Perform a dry run of the following sessions?")
345 | : tr("Synchronise the following sessions?"),
346 | names))) {
347 | QList sessionDataList;
348 |
349 | foreach (QTreeWidgetItem *i, sessionList) {
350 | sessionDataList.append(&(((SessionWidgetItem *)(i))->sessionData()));
351 | }
352 |
353 | if (sessionDataList.count()) {
354 | if (!runnerDialog) {
355 | runnerDialog = new RunnerDialog(this);
356 | }
357 |
358 | runnerDialog->go(sessionDataList, dryRun);
359 |
360 | for (int i = 0; i < sessions->topLevelItemCount(); ++i) {
361 | SessionWidgetItem *item = (SessionWidgetItem *)(sessions->topLevelItem(i));
362 |
363 | item->sessionData().updateLast();
364 | item->setLastRun(item->sessionData().last());
365 | }
366 | }
367 | }
368 | }
369 | }
370 |
371 | void SessionWidget::createSessionDialog() {
372 | if (!sessionDialog) {
373 | sessionDialog = new SessionDialog(this);
374 | connect(sessionDialog, SIGNAL(setAsDefaults()), SLOT(setAsDefaults()));
375 | }
376 | }
377 |
378 | QList SessionWidget::selectedSessions() {
379 | QList sessionList(sessions->selectedItems());
380 |
381 | if (0 == sessionList.count()) {
382 | for (int i = 0; i < sessions->topLevelItemCount(); ++i) {
383 | sessionList.append(sessions->topLevelItem(i));
384 | }
385 | }
386 | return sessionList;
387 | }
388 |
--------------------------------------------------------------------------------
/ui/sessionwidget.h:
--------------------------------------------------------------------------------
1 | #ifndef __SESSION_WIDGET_H__
2 | #define __SESSION_WIDGET_H__
3 |
4 | /*
5 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
6 |
7 | ----
8 |
9 | This program is free software; you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation; either version 2 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 | General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program; see the file COPYING. If not, write to
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 | Boston, MA 02110-1301, USA.
23 | */
24 |
25 | #include "ui_sessionwidget.h"
26 | #include "session.h"
27 |
28 | class QContextMenuEvent;
29 | class QMenu;
30 | class SessionDialog;
31 | class RunnerDialog;
32 | class CLogViewer;
33 | class QIcon;
34 |
35 | class SessionWidget : public QWidget, Ui::SessionWidget {
36 | Q_OBJECT
37 |
38 | public:
39 | SessionWidget(QWidget *parent);
40 | virtual ~SessionWidget();
41 |
42 | const Session & defaultSession() const {
43 | return defSession;
44 | }
45 |
46 | bool exists(const QString &name) const;
47 | bool srcExists(const QString &path) const;
48 | void setMenu(QMenu *m) {
49 | menu = m;
50 | }
51 | void setBackground(const QIcon &icon);
52 |
53 | Q_SIGNALS:
54 | void singleItemSelected(bool);
55 | void itemsSelected(bool);
56 | void haveSessions(bool);
57 | void haveLog(bool);
58 |
59 | public Q_SLOTS:
60 | void newSession();
61 | void editSession();
62 | void removeSession();
63 | void showSessionLog();
64 | void dryRunSession();
65 | void syncSession();
66 | void restoreSession(bool on);
67 | void controlButtons();
68 | void setAsDefaults();
69 | void loadSessions();
70 |
71 | private:
72 | void contextMenuEvent(QContextMenuEvent *e);
73 | void controlSyncButtons();
74 | void setupWidgets();
75 | void doSessions(bool dryRun);
76 | void createSessionDialog();
77 | QList selectedSessions();
78 |
79 | private:
80 | Session defSession;
81 | SessionDialog *sessionDialog;
82 | RunnerDialog *runnerDialog;
83 | CLogViewer *logViewer;
84 | QMenu *menu;
85 | };
86 |
87 | #endif
88 |
--------------------------------------------------------------------------------
/ui/sessionwidget.ui:
--------------------------------------------------------------------------------
1 |
2 | SessionWidget
3 |
4 |
5 |
6 | 0
7 | 0
8 | 617
9 | 403
10 |
11 |
12 |
13 |
14 | 0
15 |
16 | -
17 |
18 |
19 | QAbstractItemView::ExtendedSelection
20 |
21 |
22 |
23 | Session
24 |
25 |
26 |
27 |
28 | Type
29 |
30 |
31 |
32 |
33 | Last Sync
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | TreeWidget
43 | QTreeWidget
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/ui/treewidget.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
3 |
4 | ----
5 |
6 | This program is free software; you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation; either version 2 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 | General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program; see the file COPYING. If not, write to
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 | Boston, MA 02110-1301, USA.
20 | */
21 |
22 | #include "treewidget.h"
23 | #include "basicitemdelegate.h"
24 | #include
25 | #include
26 | #include
27 |
28 | static QImage setOpacity(const QImage &orig, double opacity) {
29 | QImage img = QImage::Format_ARGB32 == orig.format() ? orig : orig.convertToFormat(QImage::Format_ARGB32);
30 | uchar *bits = img.bits();
31 | for (int i = 0; i < img.height()*img.bytesPerLine(); i += 4) {
32 | if (0 != bits[i + 3]) {
33 | bits[i + 3] = opacity * 255;
34 | }
35 | }
36 | return img;
37 | }
38 |
39 | static QPixmap createBgndPixmap(const QIcon &icon) {
40 | if (icon.isNull()) {
41 | return QPixmap();
42 | }
43 | static int bgndSize = 64;
44 |
45 | QImage img = icon.pixmap(bgndSize, bgndSize).toImage();
46 | if (img.width() != bgndSize && img.height() != bgndSize) {
47 | img = img.scaled(bgndSize, bgndSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
48 | }
49 | img = setOpacity(img, 0.075);
50 | QPixmap pix(bgndSize * 2, bgndSize * 2);
51 | pix.fill(Qt::transparent);
52 | QPainter p(&pix);
53 | p.drawImage(bgndSize / 2, bgndSize / 2, img);
54 | p.end();
55 | return pix;
56 | }
57 |
58 | TreeWidget::TreeWidget(QWidget *p)
59 | : QTreeWidget(p) {
60 | setAlternatingRowColors(false);
61 | setRootIsDecorated(false);
62 | setSortingEnabled(true);
63 | setAllColumnsShowFocus(true);
64 | setIndentation(0);
65 | setItemDelegate(new BasicItemDelegate(this));
66 | }
67 |
68 | void TreeWidget::setBackground(const QIcon &icon) {
69 | QPalette pal = parentWidget()->palette();
70 | if (!icon.isNull()) {
71 | pal.setColor(QPalette::Base, Qt::transparent);
72 | }
73 | setPalette(pal);
74 | viewport()->setPalette(pal);
75 | bgnd = createBgndPixmap(icon);
76 | }
77 |
78 | void TreeWidget::paintEvent(QPaintEvent *e) {
79 | if (!bgnd.isNull()) {
80 | QPainter p(viewport());
81 | p.fillRect(viewport()->rect(), bgnd);
82 | }
83 | QTreeWidget::paintEvent(e);
84 | }
85 |
--------------------------------------------------------------------------------
/ui/treewidget.h:
--------------------------------------------------------------------------------
1 | #ifndef TREEWIDGET_H
2 | #define TREEWIDGET_H
3 |
4 | /*
5 | Carbon (C) Craig Drummond, 2013 craig.p.drummond@gmail.com
6 |
7 | ----
8 |
9 | This program is free software; you can redistribute it and/or modify
10 | it under the terms of the GNU General Public License as published by
11 | the Free Software Foundation; either version 2 of the License, or
12 | (at your option) any later version.
13 |
14 | This program is distributed in the hope that it will be useful,
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 | General Public License for more details.
18 |
19 | You should have received a copy of the GNU General Public License
20 | along with this program; see the file COPYING. If not, write to
21 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 | Boston, MA 02110-1301, USA.
23 | */
24 |
25 | #include
26 | #include
27 |
28 | class QIcon;
29 |
30 | class TreeWidget : public QTreeWidget {
31 | public:
32 | TreeWidget(QWidget *p = 0);
33 | virtual ~TreeWidget() { }
34 |
35 | void setBackground(const QIcon &icon);
36 | void paintEvent(QPaintEvent *e);
37 |
38 | private:
39 | QPixmap bgnd;
40 | };
41 |
42 | #endif // TREEWIDGET_H
43 |
--------------------------------------------------------------------------------