2 Commits

Author SHA1 Message Date
9c35bf150f Updated the Changes.md
FossilOrigin-Name: 2c6269f8f1b5cc9334488c2db77672deab813e1a
2015-08-23 14:11:16 +00:00
739421c31a Preparation for V1.0.1
FossilOrigin-Name: f3d5c35a93cf7285b489307240a6b75fbc8cb3b8
2015-08-21 08:58:22 +00:00
66 changed files with 2404 additions and 9183 deletions

4
dist/arch/PKGBUILD vendored
View File

@ -1,7 +1,7 @@
# Maintainer: Kostas Karanikolas <lastname[at]gmail[dot]com>
pkgname=fuel
pkgver=1.0.0
pkgrel=3
pkgver=1.0.1
pkgrel=1
pkgdesc="A GUI front-end to Fossil SCM"
arch=(i686 x86_64)
url="https://fuel-scm.org/"

View File

@ -1,42 +1,13 @@
Changes
Fuel V1.0.1 (2015-08-23)
================================================================================
Fuel V2.0.0 (2015-XX-XX)
--------------------------------------------------------------------------------
- Feature: New workspace view to visualise branches, tags, stashes and remotes
- Feature: Support for creating, merging and integrating branches
- Feature: Support for creating and deleting tags
- Feature: Support for updating the workspace to a particular revisions including
specific branches or tags
- Feature: Support for creating a branch during commit, including private branches
- Feature: Added Search Box for filtering and searching within the list of files
- Feature: Display the active tags and branches in the status bar
- Feature: Fuel now automatically detects the http port of "fossil ui"
- Feature: Added menu shortcut to display only the modified files of the workspace
- Feature: Support for arbitrary number of remote urls, including pushing and
pulling to specific remotes.
- Feature: Remote URL credentials are stored in the user keychain for systems that
support one. Thanks to the QtKeychain project (https://github.com/frankosterfeld/qtkeychain)
- Feature: Folders now have different appereance depending on the modification
status of their contents, including missing folders
- Feature: Support for multiple file user-actions
- Feature: Double-Click action also allows user actions
- Misc: Reorganised menu structure.
- Misc: Separated Fuel and Fossil settings
- Bug Fix: Retain the folder tree state when refreshing the workspace
- Bug Fix: Fixed issue with the expanding width of the commit dialog
- Major internal refactoring
Fuel V1.0.1 (2015-08-XX)
--------------------------------------------------------------------------------
- Reformated Docs into Markdown
- Added Localisations:
- Italian (Thanks maxxlupi and Zangune)
- Dutch (Thanks Rick Van Lieshout and Fly Man)
- Korean (Thanks ardiefox)
- Reformated Docs into Markdown
Fuel V1.0.0 (2015-03-28)
--------------------------------------------------------------------------------
================================================================================
- Feature: Long Operations can now be aborted by pressing the Escape key
- Improvement: Better support for commit messages with international characters
- Improvement: Fossil queries about CR/NL inconsistencies are now handled better
@ -46,7 +17,7 @@ Fuel V1.0.0 (2015-03-28)
- Portuguese (Thanks emansije)
Fuel V0.9.7 (Unreleased)
--------------------------------------------------------------------------------
================================================================================
- Feature: Optionally use the internal browser for the Fossil UI
- Feature: Support for persisting the state (Column order and sizes) of the File View
- Feature: Dropping a Fossil checkout file or workspace folder on Fuel now opens that workspace
@ -63,7 +34,7 @@ Fuel V0.9.7 (Unreleased)
- Distribution: Fuel is now available in the Arch User Repository
Fuel V0.9.6 (2012-05-13)
--------------------------------------------------------------------------------
================================================================================
- Feature: Support for fossil stashes
- Feature: Support for dragging and dropping files out of Fuel
- Feature: Allow for opening workspaces via the checkout file or a workspace folder

View File

@ -1,195 +0,0 @@
cmake_minimum_required(VERSION 2.8)
project(qtkeychain)
###
set(QTKEYCHAIN_VERSION 0.5.90)
set(QTKEYCHAIN_SOVERSION 0)
###
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${PROJECT_SOURCE_DIR}/cmake/Modules")
include(GNUInstallDirs)
option(BUILD_WITH_QT4 "Build qtkeychain with Qt4 no matter if Qt5 was found" OFF)
if( NOT BUILD_WITH_QT4 )
# try Qt5 first, and prefer that if found
find_package(Qt5Core QUIET)
endif()
if (Qt5Core_FOUND)
set(QTKEYCHAIN_VERSION_INFIX 5)
if(UNIX AND NOT APPLE)
find_package(Qt5DBus REQUIRED)
include_directories(${Qt5DBus_INCLUDE_DIRS})
set(QTDBUS_LIBRARIES ${Qt5DBus_LIBRARIES})
macro(qt_add_dbus_interface)
qt5_add_dbus_interface(${ARGN})
endmacro()
endif()
find_package(Qt5LinguistTools REQUIRED)
macro(qt_add_translation)
qt5_add_translation(${ARGN})
endmacro(qt_add_translation)
macro(qt_create_translation)
qt5_create_translation(${ARGN})
endmacro(qt_create_translation)
macro(qt_wrap_cpp)
qt5_wrap_cpp(${ARGN})
endmacro()
set(QTCORE_LIBRARIES ${Qt5Core_LIBRARIES})
include_directories(${Qt5Core_INCLUDE_DIRS})
if (Qt5_POSITION_INDEPENDENT_CODE)
if (CMAKE_VERSION VERSION_LESS 2.8.9) # TODO remove once we increase the cmake requirement
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
else()
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
endif()
else()
set(QTKEYCHAIN_VERSION_INFIX "")
if(UNIX AND NOT APPLE)
find_package(Qt4 COMPONENTS QtCore QtDBus REQUIRED)
set(QTDBUS_LIBRARIES ${QT_QTDBUS_LIBRARY})
macro(qt_add_dbus_interface)
qt4_add_dbus_interface(${ARGN})
endmacro()
else()
find_package(Qt4 COMPONENTS QtCore REQUIRED)
endif()
include_directories(${QT_INCLUDES})
set(QTCORE_LIBRARIES ${QT_QTCORE_LIBRARY})
macro(qt_add_translation)
qt4_add_translation(${ARGN})
endmacro(qt_add_translation)
macro(qt_create_translation)
qt4_create_translation(${ARGN})
endmacro(qt_create_translation)
macro(qt_wrap_cpp)
qt4_wrap_cpp(${ARGN})
endmacro()
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR})
list(APPEND qtkeychain_LIBRARIES ${QTCORE_LIBRARIES})
set(qtkeychain_SOURCES
keychain.cpp
)
ADD_DEFINITIONS( -Wall )
if(WIN32)
list(APPEND qtkeychain_SOURCES keychain_win.cpp)
list(APPEND qtkeychain_LIBRARIES crypt32)
#FIXME: mingw bug; otherwise getting undefined refs to RtlSecureZeroMemory there
if(MINGW)
add_definitions( -O2 )
endif()
endif()
if(APPLE)
list(APPEND qtkeychain_SOURCES keychain_mac.cpp)
find_library(COREFOUNDATION_LIBRARY CoreFoundation)
list(APPEND qtkeychain_LIBRARIES ${COREFOUNDATION_LIBRARY})
find_library(SECURITY_LIBRARY Security)
list(APPEND qtkeychain_LIBRARIES ${SECURITY_LIBRARY})
endif()
if(UNIX AND NOT APPLE)
list(APPEND qtkeychain_SOURCES keychain_unix.cpp gnomekeyring.cpp)
qt_add_dbus_interface(qtkeychain_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/org.kde.KWallet.xml kwallet_interface KWalletInterface)
list(APPEND qtkeychain_LIBRARIES ${QTDBUS_LIBRARIES})
endif()
QT_WRAP_CPP(qtkeychain_MOC_OUTFILES keychain.h keychain_p.h)
set(qtkeychain_TR_FILES
translations/qtkeychain_de.ts
translations/qtkeychain_ro.ts
)
file(GLOB qtkeychain_TR_SOURCES *.cpp *.h *.ui)
qt_create_translation(qtkeychain_MESSAGES ${qtkeychain_TR_SOURCES} ${qtkeychain_TR_FILES})
qt_add_translation(qtkeychain_QM_FILES ${qtkeychain_TR_FILES})
add_custom_target(messages DEPENDS ${qtkeychain_MESSAGES})
add_custom_target(translations DEPENDS ${qtkeychain_QM_FILES})
if(NOT QT_TRANSLATIONS_DIR)
# If this directory is missing, we are in a Qt5 environment.
# Extract the qmake executable location
get_target_property(QT5_QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
# Ask Qt5 where to put the translations
execute_process( COMMAND ${QT5_QMAKE_EXECUTABLE} -query QT_INSTALL_TRANSLATIONS
OUTPUT_VARIABLE qt_translations_dir OUTPUT_STRIP_TRAILING_WHITESPACE )
# make sure we have / and not \ as qmake gives on windows
FILE(TO_CMAKE_PATH "${qt_translations_dir}" qt_translations_dir)
SET(QT_TRANSLATIONS_DIR ${qt_translations_dir} CACHE PATH "The
location of the Qt translations" FORCE)
endif()
install(FILES ${qtkeychain_QM_FILES}
DESTINATION ${QT_TRANSLATIONS_DIR})
set(QTKEYCHAIN_TARGET_NAME qt${QTKEYCHAIN_VERSION_INFIX}keychain)
if(NOT QTKEYCHAIN_STATIC)
add_library(${QTKEYCHAIN_TARGET_NAME} SHARED ${qtkeychain_SOURCES} ${qtkeychain_MOC_OUTFILES} ${qtkeychain_QM_FILES})
set_target_properties(${QTKEYCHAIN_TARGET_NAME} PROPERTIES COMPILE_DEFINITIONS QKEYCHAIN_BUILD_QKEYCHAIN_LIB)
target_link_libraries(${QTKEYCHAIN_TARGET_NAME} ${qtkeychain_LIBRARIES})
else()
add_library(${QTKEYCHAIN_TARGET_NAME} STATIC ${qtkeychain_SOURCES} ${qtkeychain_MOC_OUTFILES} ${qtkeychain_QM_FILES})
set_target_properties(${QTKEYCHAIN_TARGET_NAME} PROPERTIES COMPILE_DEFINITIONS QKEYCHAIN_STATICLIB)
endif()
set_target_properties(${QTKEYCHAIN_TARGET_NAME} PROPERTIES
VERSION ${QTKEYCHAIN_VERSION}
SOVERSION ${QTKEYCHAIN_SOVERSION}
MACOSX_RPATH 1
INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}"
)
install(FILES keychain.h qkeychain_export.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qt${QTKEYCHAIN_VERSION_INFIX}keychain/
)
install(TARGETS ${QTKEYCHAIN_TARGET_NAME}
EXPORT Qt${QTKEYCHAIN_VERSION_INFIX}KeychainLibraryDepends
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
add_executable( testclient testclient.cpp )
target_link_libraries( testclient ${QTKEYCHAIN_TARGET_NAME})
###
### CMake config file
###
export(TARGETS ${QTKEYCHAIN_TARGET_NAME} FILE "${PROJECT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainLibraryDepends.cmake")
export(PACKAGE Qt${QTKEYCHAIN_VERSION_INFIX}Keychain)
configure_file(QtKeychainBuildTreeSettings.cmake.in
"${PROJECT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainBuildTreeSettings.cmake" @ONLY)
configure_file(QtKeychainConfig.cmake.in
"${PROJECT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfig.cmake" @ONLY)
configure_file(QtKeychainConfigVersion.cmake.in
"${PROJECT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfigVersion.cmake" @ONLY)
install(EXPORT Qt${QTKEYCHAIN_VERSION_INFIX}KeychainLibraryDepends
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Qt${QTKEYCHAIN_VERSION_INFIX}Keychain"
)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/Qt${QTKEYCHAIN_VERSION_INFIX}KeychainConfigVersion.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Qt${QTKEYCHAIN_VERSION_INFIX}Keychain
)

View File

@ -1,20 +0,0 @@
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,23 +0,0 @@
ChangeLog
=========
version 0.5.0 (release 2015-05-04)
* Added support for KWallet5 (KDE5/KF)
version 0.4.0 (release 2014-09-01)
* KWallet: Handle case where no wallet exists yet (Liviu Cristian Mirea Ghiban <contact@liviucmg.com>)
* Improved desktop environment detection at runtime (Daniel Molkentin <daniel@molkentin.de>)
version 0.3.0 (release 2014-03-13)
* Gnome Keyring supported added (Francois Ferrand <thetypz@gmail.com>)
* Improved Qt 5 support
* KWallet: Distinguish empty passwords from non-existing entries
* KWallet: Do not use hardcoded wallet name
* German translation (Daniel Molkentin <daniel@molkentin.de>)
* Romanian translation (Arthur Țițeică <arthur@psw.ro>)
version 0.2.0: no official release
version 0.1.0 (release 2013-01-16)
* Initial release

View File

@ -1,4 +0,0 @@
set(QTKEYCHAIN_INCLUDE_DIRS
"@PROJECT_SOURCE_DIR@"
"@PROJECT_BINARY_DIR@"
)

View File

@ -1,21 +0,0 @@
# - Config file for the QtKeychain package
# It defines the following variables
# QTKEYCHAIN_INCLUDE_DIRS - include directories for QtKeychain
# QTKEYCHAIN_LIBRARIES - libraries to link against
# Compute paths
get_filename_component(QTKEYCHAIN_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
if(EXISTS "${QTKEYCHAIN_CMAKE_DIR}/CMakeCache.txt")
# In build tree
include("${QTKEYCHAIN_CMAKE_DIR}/Qt@QTKEYCHAIN_VERSION_INFIX@KeychainBuildTreeSettings.cmake")
else()
set(QTKEYCHAIN_INCLUDE_DIRS "@CMAKE_INSTALL_FULL_INCLUDEDIR@")
endif()
# Our library dependencies (contains definitions for IMPORTED targets)
include("${QTKEYCHAIN_CMAKE_DIR}/Qt@QTKEYCHAIN_VERSION_INFIX@KeychainLibraryDepends.cmake")
# These are IMPORTED targets created by FooBarLibraryDepends.cmake
set(QTKEYCHAIN_LIBRARIES "@QTKEYCHAIN_TARGET_NAME@")
set(QTKEYCHAIN_FOUND TRUE)

View File

@ -1,11 +0,0 @@
set(PACKAGE_VERSION "@QTKEYCHAIN_VERSION@")
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()

View File

@ -1,15 +0,0 @@
QtKeychain
==========
QtKeychain is a Qt API to store passwords and other secret data securely. How the data is stored depends on the platform:
* **Mac OS X:** Passwords are stored in the OS X Keychain.
* **Linux/Unix:** If running, GNOME Keyring is used, otherwise
qtkeychain tries to use KWallet (via D-Bus), if available.
* **Windows:** Windows does not provide a service for secure storage. QtKeychain uses the Windows API function [CryptProtectData](http://msdn.microsoft.com/en-us/library/windows/desktop/aa380261%28v=vs.85%29.aspx "CryptProtectData function") to encrypt the password with the user's logon credentials. The encrypted data is then persisted via QSettings.
In unsupported environments QtKeychain will report an error. It will not store any data unencrypted unless explicitly requested (setInsecureFallback( true )).
**License:** QtKeychain is available under the [Modified BSD License](http://www.gnu.org/licenses/license-list.html#ModifiedBSD). See the file COPYING for details.

View File

@ -1,15 +0,0 @@
QtKeychain
==========
QtKeychain is a Qt API to store passwords and other secret data securely. How the data is stored depends on the platform:
* **Mac OS X:** Passwords are stored in the OS X Keychain.
* **Linux/Unix:** If running, GNOME Keyring is used, otherwise
qtkeychain tries to use KWallet (via D-Bus), if available.
* **Windows:** Windows does not provide a service for secure storage. QtKeychain uses the Windows API function [CryptProtectData](http://msdn.microsoft.com/en-us/library/windows/desktop/aa380261%28v=vs.85%29.aspx "CryptProtectData function") to encrypt the password with the user's logon credentials. The encrypted data is then persisted via QSettings.
In unsupported environments QtKeychain will report an error. It will not store any data unencrypted unless explicitly requested (setInsecureFallback( true )).
**License:** QtKeychain is available under the [Modified BSD License](http://www.gnu.org/licenses/license-list.html#ModifiedBSD). See the file COPYING for details.

View File

@ -1,188 +0,0 @@
# - Define GNU standard installation directories
# Provides install directory variables as defined for GNU software:
# http://www.gnu.org/prep/standards/html_node/Directory-Variables.html
# Inclusion of this module defines the following variables:
# CMAKE_INSTALL_<dir> - destination for files of a given type
# CMAKE_INSTALL_FULL_<dir> - corresponding absolute path
# where <dir> is one of:
# BINDIR - user executables (bin)
# SBINDIR - system admin executables (sbin)
# LIBEXECDIR - program executables (libexec)
# SYSCONFDIR - read-only single-machine data (etc)
# SHAREDSTATEDIR - modifiable architecture-independent data (com)
# LOCALSTATEDIR - modifiable single-machine data (var)
# LIBDIR - object code libraries (lib or lib64 or lib/<multiarch-tuple> on Debian)
# INCLUDEDIR - C header files (include)
# OLDINCLUDEDIR - C header files for non-gcc (/usr/include)
# DATAROOTDIR - read-only architecture-independent data root (share)
# DATADIR - read-only architecture-independent data (DATAROOTDIR)
# INFODIR - info documentation (DATAROOTDIR/info)
# LOCALEDIR - locale-dependent data (DATAROOTDIR/locale)
# MANDIR - man documentation (DATAROOTDIR/man)
# DOCDIR - documentation root (DATAROOTDIR/doc/PROJECT_NAME)
# Each CMAKE_INSTALL_<dir> value may be passed to the DESTINATION options of
# install() commands for the corresponding file type. If the includer does
# not define a value the above-shown default will be used and the value will
# appear in the cache for editing by the user.
# Each CMAKE_INSTALL_FULL_<dir> value contains an absolute path constructed
# from the corresponding destination by prepending (if necessary) the value
# of CMAKE_INSTALL_PREFIX.
#=============================================================================
# Copyright 2011 Nikita Krupen'ko <krnekit@gmail.com>
# Copyright 2011 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
# Installation directories
#
if(NOT DEFINED CMAKE_INSTALL_BINDIR)
set(CMAKE_INSTALL_BINDIR "bin" CACHE PATH "user executables (bin)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SBINDIR)
set(CMAKE_INSTALL_SBINDIR "sbin" CACHE PATH "system admin executables (sbin)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LIBEXECDIR)
set(CMAKE_INSTALL_LIBEXECDIR "libexec" CACHE PATH "program executables (libexec)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SYSCONFDIR)
set(CMAKE_INSTALL_SYSCONFDIR "etc" CACHE PATH "read-only single-machine data (etc)")
endif()
if(NOT DEFINED CMAKE_INSTALL_SHAREDSTATEDIR)
set(CMAKE_INSTALL_SHAREDSTATEDIR "com" CACHE PATH "modifiable architecture-independent data (com)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LOCALSTATEDIR)
set(CMAKE_INSTALL_LOCALSTATEDIR "var" CACHE PATH "modifiable single-machine data (var)")
endif()
if(NOT DEFINED CMAKE_INSTALL_LIBDIR)
set(_LIBDIR_DEFAULT "lib")
# Override this default 'lib' with 'lib64' iff:
# - we are on Linux system but NOT cross-compiling
# - we are NOT on debian
# - we are on a 64 bits system
# reason is: amd64 ABI: http://www.x86-64.org/documentation/abi.pdf
# For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if
# CMAKE_LIBRARY_ARCHITECTURE is set (which contains e.g. "i386-linux-gnu"
# See http://wiki.debian.org/Multiarch
if(CMAKE_SYSTEM_NAME MATCHES "Linux"
AND NOT CMAKE_CROSSCOMPILING)
if (EXISTS "/etc/debian_version") # is this a debian system ?
if(CMAKE_LIBRARY_ARCHITECTURE)
set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
endif()
else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
message(AUTHOR_WARNING
"Unable to determine default CMAKE_INSTALL_LIBDIR directory because no target architecture is known. "
"Please enable at least one language before including GNUInstallDirs.")
else()
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(_LIBDIR_DEFAULT "lib64")
endif()
endif()
endif()
endif()
set(CMAKE_INSTALL_LIBDIR "${_LIBDIR_DEFAULT}" CACHE PATH "object code libraries (${_LIBDIR_DEFAULT})")
endif()
if(NOT DEFINED CMAKE_INSTALL_INCLUDEDIR)
set(CMAKE_INSTALL_INCLUDEDIR "include" CACHE PATH "C header files (include)")
endif()
if(NOT DEFINED CMAKE_INSTALL_OLDINCLUDEDIR)
set(CMAKE_INSTALL_OLDINCLUDEDIR "/usr/include" CACHE PATH "C header files for non-gcc (/usr/include)")
endif()
if(NOT DEFINED CMAKE_INSTALL_DATAROOTDIR)
set(CMAKE_INSTALL_DATAROOTDIR "share" CACHE PATH "read-only architecture-independent data root (share)")
endif()
#-----------------------------------------------------------------------------
# Values whose defaults are relative to DATAROOTDIR. Store empty values in
# the cache and store the defaults in local variables if the cache values are
# not set explicitly. This auto-updates the defaults as DATAROOTDIR changes.
if(NOT CMAKE_INSTALL_DATADIR)
set(CMAKE_INSTALL_DATADIR "" CACHE PATH "read-only architecture-independent data (DATAROOTDIR)")
set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}")
endif()
if(NOT CMAKE_INSTALL_INFODIR)
set(CMAKE_INSTALL_INFODIR "" CACHE PATH "info documentation (DATAROOTDIR/info)")
set(CMAKE_INSTALL_INFODIR "${CMAKE_INSTALL_DATAROOTDIR}/info")
endif()
if(NOT CMAKE_INSTALL_LOCALEDIR)
set(CMAKE_INSTALL_LOCALEDIR "" CACHE PATH "locale-dependent data (DATAROOTDIR/locale)")
set(CMAKE_INSTALL_LOCALEDIR "${CMAKE_INSTALL_DATAROOTDIR}/locale")
endif()
if(NOT CMAKE_INSTALL_MANDIR)
set(CMAKE_INSTALL_MANDIR "" CACHE PATH "man documentation (DATAROOTDIR/man)")
set(CMAKE_INSTALL_MANDIR "${CMAKE_INSTALL_DATAROOTDIR}/man")
endif()
if(NOT CMAKE_INSTALL_DOCDIR)
set(CMAKE_INSTALL_DOCDIR "" CACHE PATH "documentation root (DATAROOTDIR/doc/PROJECT_NAME)")
set(CMAKE_INSTALL_DOCDIR "${CMAKE_INSTALL_DATAROOTDIR}/doc/${PROJECT_NAME}")
endif()
#-----------------------------------------------------------------------------
mark_as_advanced(
CMAKE_INSTALL_BINDIR
CMAKE_INSTALL_SBINDIR
CMAKE_INSTALL_LIBEXECDIR
CMAKE_INSTALL_SYSCONFDIR
CMAKE_INSTALL_SHAREDSTATEDIR
CMAKE_INSTALL_LOCALSTATEDIR
CMAKE_INSTALL_LIBDIR
CMAKE_INSTALL_INCLUDEDIR
CMAKE_INSTALL_OLDINCLUDEDIR
CMAKE_INSTALL_DATAROOTDIR
CMAKE_INSTALL_DATADIR
CMAKE_INSTALL_INFODIR
CMAKE_INSTALL_LOCALEDIR
CMAKE_INSTALL_MANDIR
CMAKE_INSTALL_DOCDIR
)
# Result directories
#
foreach(dir
BINDIR
SBINDIR
LIBEXECDIR
SYSCONFDIR
SHAREDSTATEDIR
LOCALSTATEDIR
LIBDIR
INCLUDEDIR
OLDINCLUDEDIR
DATAROOTDIR
DATADIR
INFODIR
LOCALEDIR
MANDIR
DOCDIR
)
if(NOT IS_ABSOLUTE ${CMAKE_INSTALL_${dir}})
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_${dir}}")
else()
set(CMAKE_INSTALL_FULL_${dir} "${CMAKE_INSTALL_${dir}}")
endif()
endforeach()

View File

@ -1,71 +0,0 @@
#include "gnomekeyring_p.h"
const char* GnomeKeyring::GNOME_KEYRING_DEFAULT = NULL;
bool GnomeKeyring::isAvailable()
{
const GnomeKeyring& keyring = instance();
return keyring.isLoaded() &&
keyring.NETWORK_PASSWORD &&
keyring.is_available &&
keyring.find_password &&
keyring.store_password &&
keyring.delete_password &&
keyring.is_available();
}
GnomeKeyring::gpointer GnomeKeyring::store_network_password( const gchar* keyring, const gchar* display_name,
const gchar* user, const gchar* server, const gchar* password,
OperationDoneCallback callback, gpointer data, GDestroyNotify destroy_data )
{
if ( !isAvailable() )
return 0;
return instance().store_password( instance().NETWORK_PASSWORD,
keyring, display_name, password, callback, data, destroy_data,
"user", user, "server", server, static_cast<char*>(0) );
}
GnomeKeyring::gpointer GnomeKeyring::find_network_password( const gchar* user, const gchar* server,
OperationGetStringCallback callback, gpointer data, GDestroyNotify destroy_data )
{
if ( !isAvailable() )
return 0;
return instance().find_password( instance().NETWORK_PASSWORD,
callback, data, destroy_data,
"user", user, "server", server, static_cast<char*>(0) );
}
GnomeKeyring::gpointer GnomeKeyring::delete_network_password( const gchar* user,
const gchar* server,
OperationDoneCallback callback,
gpointer data,
GDestroyNotify destroy_data )
{
if ( !isAvailable() )
return 0;
return instance().delete_password( instance().NETWORK_PASSWORD,
callback, data, destroy_data,
"user", user, "server", server, static_cast<char*>(0) );
}
GnomeKeyring::GnomeKeyring()
: QLibrary("gnome-keyring", 0)
{
static const PasswordSchema schema = {
ITEM_NETWORK_PASSWORD,
{{ "user", ATTRIBUTE_TYPE_STRING },
{ "server", ATTRIBUTE_TYPE_STRING },
{ 0, static_cast<AttributeType>( 0 ) }}
};
NETWORK_PASSWORD = &schema;
is_available = reinterpret_cast<is_available_fn*>( resolve( "gnome_keyring_is_available" ) );
find_password = reinterpret_cast<find_password_fn*>( resolve( "gnome_keyring_find_password" ) );
store_password = reinterpret_cast<store_password_fn*>( resolve( "gnome_keyring_store_password" ) );
delete_password = reinterpret_cast<delete_password_fn*>( resolve( "gnome_keyring_delete_password" ) );
}
GnomeKeyring& GnomeKeyring::instance() {
static GnomeKeyring keyring;
return keyring;
}

View File

@ -1,88 +0,0 @@
#ifndef QTKEYCHAIN_GNOME_P_H
#define QTKEYCHAIN_GNOME_P_H
#include <QLibrary>
class GnomeKeyring : private QLibrary {
public:
enum Result {
RESULT_OK,
RESULT_DENIED,
RESULT_NO_KEYRING_DAEMON,
RESULT_ALREADY_UNLOCKED,
RESULT_NO_SUCH_KEYRING,
RESULT_BAD_ARGUMENTS,
RESULT_IO_ERROR,
RESULT_CANCELLED,
RESULT_KEYRING_ALREADY_EXISTS,
RESULT_NO_MATCH
};
enum ItemType {
ITEM_GENERIC_SECRET = 0,
ITEM_NETWORK_PASSWORD,
ITEM_NOTE,
ITEM_CHAINED_KEYRING_PASSWORD,
ITEM_ENCRYPTION_KEY_PASSWORD,
ITEM_PK_STORAGE = 0x100
};
enum AttributeType {
ATTRIBUTE_TYPE_STRING,
ATTRIBUTE_TYPE_UINT32
};
typedef char gchar;
typedef void* gpointer;
typedef bool gboolean;
typedef struct {
ItemType item_type;
struct {
const gchar* name;
AttributeType type;
} attributes[32];
} PasswordSchema;
typedef void ( *OperationGetStringCallback )( Result result, const char* string, gpointer data );
typedef void ( *OperationDoneCallback )( Result result, gpointer data );
typedef void ( *GDestroyNotify )( gpointer data );
static const char* GNOME_KEYRING_DEFAULT;
static bool isAvailable();
static gpointer store_network_password( const gchar* keyring, const gchar* display_name,
const gchar* user, const gchar* server, const gchar* password,
OperationDoneCallback callback, gpointer data, GDestroyNotify destroy_data );
static gpointer find_network_password( const gchar* user, const gchar* server,
OperationGetStringCallback callback, gpointer data, GDestroyNotify destroy_data );
static gpointer delete_network_password( const gchar* user, const gchar* server,
OperationDoneCallback callback, gpointer data, GDestroyNotify destroy_data );
private:
GnomeKeyring();
static GnomeKeyring& instance();
const PasswordSchema* NETWORK_PASSWORD;
typedef gboolean ( is_available_fn )( void );
typedef gpointer ( store_password_fn )( const PasswordSchema* schema, const gchar* keyring,
const gchar* display_name, const gchar* password,
OperationDoneCallback callback, gpointer data, GDestroyNotify destroy_data,
... );
typedef gpointer ( find_password_fn )( const PasswordSchema* schema,
OperationGetStringCallback callback, gpointer data, GDestroyNotify destroy_data,
... );
typedef gpointer ( delete_password_fn )( const PasswordSchema* schema,
OperationDoneCallback callback, gpointer data, GDestroyNotify destroy_data,
... );
is_available_fn* is_available;
find_password_fn* find_password;
store_password_fn* store_password;
delete_password_fn* delete_password;
};
#endif

View File

@ -1,229 +0,0 @@
/******************************************************************************
* Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
* or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution *
* details, check the accompanying file 'COPYING'. *
*****************************************************************************/
#include "keychain.h"
#include "keychain_p.h"
using namespace QKeychain;
Job::Job( const QString& service, QObject *parent )
: QObject( parent )
, d ( new JobPrivate( service ) ) {
}
Job::~Job() {
delete d;
}
QString Job::service() const {
return d->service;
}
QSettings* Job::settings() const {
return d->settings;
}
void Job::setSettings( QSettings* settings ) {
d->settings = settings;
}
void Job::start() {
QMetaObject::invokeMethod( this, "doStart", Qt::QueuedConnection );
}
bool Job::autoDelete() const {
return d->autoDelete;
}
void Job::setAutoDelete( bool autoDelete ) {
d->autoDelete = autoDelete;
}
bool Job::insecureFallback() const {
return d->insecureFallback;
}
void Job::setInsecureFallback( bool insecureFallback ) {
d->insecureFallback = insecureFallback;
}
void Job::emitFinished() {
emit finished( this );
if ( d->autoDelete )
deleteLater();
}
void Job::emitFinishedWithError( Error error, const QString& errorString ) {
d->error = error;
d->errorString = errorString;
emitFinished();
}
Error Job::error() const {
return d->error;
}
QString Job::errorString() const {
return d->errorString;
}
void Job::setError( Error error ) {
d->error = error;
}
void Job::setErrorString( const QString& errorString ) {
d->errorString = errorString;
}
ReadPasswordJob::ReadPasswordJob( const QString& service, QObject* parent )
: Job( service, parent )
, d( new ReadPasswordJobPrivate( this ) )
{}
ReadPasswordJob::~ReadPasswordJob() {
delete d;
}
QString ReadPasswordJob::textData() const {
return QString::fromUtf8( d->data );
}
QByteArray ReadPasswordJob::binaryData() const {
return d->data;
}
QString ReadPasswordJob::key() const {
return d->key;
}
void ReadPasswordJob::setKey( const QString& key ) {
d->key = key;
}
void ReadPasswordJob::doStart() {
JobExecutor::instance()->enqueue( this );
}
WritePasswordJob::WritePasswordJob( const QString& service, QObject* parent )
: Job( service, parent )
, d( new WritePasswordJobPrivate( this ) ) {
}
WritePasswordJob::~WritePasswordJob() {
delete d;
}
QString WritePasswordJob::key() const {
return d->key;
}
void WritePasswordJob::setKey( const QString& key ) {
d->key = key;
}
void WritePasswordJob::setBinaryData( const QByteArray& data ) {
d->binaryData = data;
d->mode = WritePasswordJobPrivate::Binary;
}
void WritePasswordJob::setTextData( const QString& data ) {
d->textData = data;
d->mode = WritePasswordJobPrivate::Text;
}
void WritePasswordJob::doStart() {
JobExecutor::instance()->enqueue( this );
}
DeletePasswordJob::DeletePasswordJob( const QString& service, QObject* parent )
: Job( service, parent )
, d( new DeletePasswordJobPrivate( this ) ) {
}
DeletePasswordJob::~DeletePasswordJob() {
delete d;
}
void DeletePasswordJob::doStart() {
//Internally, to delete a password we just execute a write job with no data set (null byte array).
//In all current implementations, this deletes the entry so this is sufficient
WritePasswordJob* job = new WritePasswordJob( service(), this );
connect( job, SIGNAL(finished(QKeychain::Job*)), d, SLOT(jobFinished(QKeychain::Job*)) );
job->setInsecureFallback(true);
job->setSettings(settings());
job->setKey( d->key );
job->doStart();
}
QString DeletePasswordJob::key() const {
return d->key;
}
void DeletePasswordJob::setKey( const QString& key ) {
d->key = key;
}
void DeletePasswordJobPrivate::jobFinished( Job* job ) {
q->setError( job->error() );
q->setErrorString( job->errorString() );
q->emitFinished();
}
JobExecutor::JobExecutor()
: QObject( 0 )
, m_runningJob( 0 )
{
}
void JobExecutor::enqueue( Job* job ) {
m_queue.append( job );
startNextIfNoneRunning();
}
void JobExecutor::startNextIfNoneRunning() {
if ( m_queue.isEmpty() || m_runningJob )
return;
QPointer<Job> next;
while ( !next && !m_queue.isEmpty() ) {
next = m_queue.first();
m_queue.pop_front();
}
if ( next ) {
connect( next, SIGNAL(finished(QKeychain::Job*)), this, SLOT(jobFinished(QKeychain::Job*)) );
connect( next, SIGNAL(destroyed(QObject*)), this, SLOT(jobDestroyed(QObject*)) );
m_runningJob = next;
if ( ReadPasswordJob* rpj = qobject_cast<ReadPasswordJob*>( m_runningJob ) )
rpj->d->scheduledStart();
else if ( WritePasswordJob* wpj = qobject_cast<WritePasswordJob*>( m_runningJob) )
wpj->d->scheduledStart();
}
}
void JobExecutor::jobDestroyed( QObject* object ) {
Q_UNUSED( object ) // for release mode
Q_ASSERT( object == m_runningJob );
m_runningJob->disconnect( this );
m_runningJob = 0;
startNextIfNoneRunning();
}
void JobExecutor::jobFinished( Job* job ) {
Q_UNUSED( job ) // for release mode
Q_ASSERT( job == m_runningJob );
m_runningJob->disconnect( this );
m_runningJob = 0;
startNextIfNoneRunning();
}
JobExecutor* JobExecutor::s_instance = 0;
JobExecutor* JobExecutor::instance() {
if ( !s_instance )
s_instance = new JobExecutor;
return s_instance;
}

View File

@ -1,145 +0,0 @@
/******************************************************************************
* Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
* or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution *
* details, check the accompanying file 'COPYING'. *
*****************************************************************************/
#ifndef KEYCHAIN_H
#define KEYCHAIN_H
#include "qkeychain_export.h"
#include <QtCore/QObject>
#include <QtCore/QString>
class QSettings;
#define QTKEYCHAIN_VERSION 0x000100
namespace QKeychain {
/**
* Error codes
*/
enum Error {
NoError=0, /**< No error occurred, operation was successful */
EntryNotFound, /**< For the given key no data was found */
CouldNotDeleteEntry, /**< Could not delete existing secret data */
AccessDeniedByUser, /**< User denied access to keychain */
AccessDenied, /**< Access denied for other reasons */
NoBackendAvailable, /**< No platform-specific keychain service available */
NotImplemented, /**< Not implemented on platform */
OtherError /**< Something else went wrong (errorString() might provide details) */
};
class JobExecutor;
class JobPrivate;
class QKEYCHAIN_EXPORT Job : public QObject {
Q_OBJECT
public:
explicit Job( const QString& service, QObject* parent=0 );
~Job();
QSettings* settings() const;
void setSettings( QSettings* settings );
void start();
QString service() const;
Error error() const;
QString errorString() const;
bool autoDelete() const;
void setAutoDelete( bool autoDelete );
bool insecureFallback() const;
void setInsecureFallback( bool insecureFallback );
Q_SIGNALS:
void finished( QKeychain::Job* );
protected:
Q_INVOKABLE virtual void doStart() = 0;
void setError( Error error );
void setErrorString( const QString& errorString );
void emitFinished();
void emitFinishedWithError(Error, const QString& errorString);
private:
JobPrivate* const d;
};
class ReadPasswordJobPrivate;
class QKEYCHAIN_EXPORT ReadPasswordJob : public Job {
Q_OBJECT
public:
explicit ReadPasswordJob( const QString& service, QObject* parent=0 );
~ReadPasswordJob();
QString key() const;
void setKey( const QString& key );
QByteArray binaryData() const;
QString textData() const;
protected:
void doStart();
private:
friend class QKeychain::ReadPasswordJobPrivate;
friend class QKeychain::JobExecutor;
ReadPasswordJobPrivate* const d;
};
class WritePasswordJobPrivate;
class QKEYCHAIN_EXPORT WritePasswordJob : public Job {
Q_OBJECT
public:
explicit WritePasswordJob( const QString& service, QObject* parent=0 );
~WritePasswordJob();
QString key() const;
void setKey( const QString& key );
void setBinaryData( const QByteArray& data );
void setTextData( const QString& data );
protected:
void doStart();
private:
friend class QKeychain::JobExecutor;
friend class QKeychain::WritePasswordJobPrivate;
friend class DeletePasswordJob;
WritePasswordJobPrivate* const d;
};
class DeletePasswordJobPrivate;
class QKEYCHAIN_EXPORT DeletePasswordJob : public Job {
Q_OBJECT
public:
explicit DeletePasswordJob( const QString& service, QObject* parent=0 );
~DeletePasswordJob();
QString key() const;
void setKey( const QString& key );
protected:
void doStart();
private:
friend class QKeychain::DeletePasswordJobPrivate;
DeletePasswordJobPrivate* const d;
};
} // namespace QtKeychain
#endif

View File

@ -1,161 +0,0 @@
/******************************************************************************
* Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
* or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution *
* details, check the accompanying file 'COPYING'. *
*****************************************************************************/
#include "keychain_p.h"
#include <CoreFoundation/CoreFoundation.h>
#include <Security/Security.h>
#include <QDebug>
using namespace QKeychain;
template <typename T>
struct Releaser {
explicit Releaser( const T& v ) : value( v ) {}
~Releaser() {
CFRelease( value );
}
const T value;
};
static QString strForStatus( OSStatus os ) {
const Releaser<CFStringRef> str( SecCopyErrorMessageString( os, 0 ) );
const char * const buf = CFStringGetCStringPtr( str.value, kCFStringEncodingUTF8 );
if ( !buf )
return QObject::tr( "%1 (OSStatus %2)" )
.arg( "OSX Keychain Error" ).arg( os );
return QObject::tr( "%1 (OSStatus %2)" )
.arg( QString::fromUtf8( buf, strlen( buf ) ) ).arg( os );
}
static OSStatus readPw( QByteArray* pw,
const QString& service,
const QString& account,
SecKeychainItemRef* ref ) {
Q_ASSERT( pw );
pw->clear();
const QByteArray serviceData = service.toUtf8();
const QByteArray accountData = account.toUtf8();
void* data = 0;
UInt32 len = 0;
const OSStatus ret = SecKeychainFindGenericPassword( NULL, // default keychain
serviceData.size(),
serviceData.constData(),
accountData.size(),
accountData.constData(),
&len,
&data,
ref );
if ( ret == noErr ) {
*pw = QByteArray( reinterpret_cast<const char*>( data ), len );
const OSStatus ret2 = SecKeychainItemFreeContent ( 0, data );
if ( ret2 != noErr )
qWarning() << "Could not free item content: " << strForStatus( ret2 );
}
return ret;
}
void ReadPasswordJobPrivate::scheduledStart()
{
QString errorString;
Error error = NoError;
const OSStatus ret = readPw( &data, q->service(), q->key(), 0 );
switch ( ret ) {
case noErr:
break;
case errSecItemNotFound:
errorString = tr("Password not found");
error = EntryNotFound;
break;
default:
errorString = strForStatus( ret );
error = OtherError;
break;
}
q->emitFinishedWithError( error, errorString );
}
static QKeychain::Error deleteEntryImpl( const QString& service, const QString& account, QString* err ) {
SecKeychainItemRef ref;
QByteArray pw;
const OSStatus ret1 = readPw( &pw, service, account, &ref );
if ( ret1 == errSecItemNotFound )
return NoError; // No item stored, we're done
if ( ret1 != noErr ) {
*err = strForStatus( ret1 );
//TODO map error code, set errstr
return OtherError;
}
const Releaser<SecKeychainItemRef> releaser( ref );
const OSStatus ret2 = SecKeychainItemDelete( ref );
if ( ret2 == noErr )
return NoError;
//TODO map error code
*err = strForStatus( ret2 );
return CouldNotDeleteEntry;
}
static QKeychain::Error writeEntryImpl( const QString& service,
const QString& account,
const QByteArray& data,
QString* err ) {
Q_ASSERT( err );
err->clear();
const QByteArray serviceData = service.toUtf8();
const QByteArray accountData = account.toUtf8();
const OSStatus ret = SecKeychainAddGenericPassword( NULL, //default keychain
serviceData.size(),
serviceData.constData(),
accountData.size(),
accountData.constData(),
data.size(),
data.constData(),
NULL //item reference
);
if ( ret != noErr ) {
switch ( ret ) {
case errSecDuplicateItem:
{
Error derr = deleteEntryImpl( service, account, err );
if ( derr != NoError )
return CouldNotDeleteEntry;
else
return writeEntryImpl( service, account, data, err );
}
default:
*err = strForStatus( ret );
return OtherError;
}
}
return NoError;
}
void WritePasswordJobPrivate::scheduledStart()
{
QString errorString;
Error error = NoError;
if ( mode == Delete ) {
const Error derr = deleteEntryImpl( q->service(), key, &errorString );
if ( derr != NoError )
error = CouldNotDeleteEntry;
q->emitFinishedWithError( error, errorString );
return;
}
const QByteArray data = mode == Text ? textData.toUtf8() : binaryData;
error = writeEntryImpl( q->service(), key, data, &errorString );
q->emitFinishedWithError( error, errorString );
}

View File

@ -1,163 +0,0 @@
/******************************************************************************
* Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
* or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution *
* details, check the accompanying file 'COPYING'. *
*****************************************************************************/
#ifndef KEYCHAIN_P_H
#define KEYCHAIN_P_H
#include <QCoreApplication>
#include <QObject>
#include <QPointer>
#include <QSettings>
#include <QVector>
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
#include <QDBusPendingCallWatcher>
#include "kwallet_interface.h"
#else
class QDBusPendingCallWatcher;
#endif
#include "keychain.h"
namespace QKeychain {
class JobExecutor;
class JobPrivate : public QObject {
Q_OBJECT
public:
JobPrivate( const QString& service_ )
: error( NoError )
, service( service_ )
, autoDelete( true )
, insecureFallback( false ) {}
QKeychain::Error error;
QString errorString;
QString service;
bool autoDelete;
bool insecureFallback;
QPointer<QSettings> settings;
};
class ReadPasswordJobPrivate : public QObject {
Q_OBJECT
public:
explicit ReadPasswordJobPrivate( ReadPasswordJob* qq ) : q( qq ), walletHandle( 0 ), dataType( Text ) {}
void scheduledStart();
ReadPasswordJob* const q;
QByteArray data;
QString key;
int walletHandle;
enum DataType {
Binary,
Text
};
DataType dataType;
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
org::kde::KWallet* iface;
static void gnomeKeyring_cb( int result, const char* string, ReadPasswordJobPrivate* data );
friend class QKeychain::JobExecutor;
void fallbackOnError(const QDBusError& err);
private Q_SLOTS:
void kwalletWalletFound( QDBusPendingCallWatcher* watcher );
void kwalletOpenFinished( QDBusPendingCallWatcher* watcher );
void kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher );
void kwalletReadFinished( QDBusPendingCallWatcher* watcher );
#else //moc's too dumb to respect above macros, so just define empty slot implementations
private Q_SLOTS:
void kwalletWalletFound( QDBusPendingCallWatcher* ) {}
void kwalletOpenFinished( QDBusPendingCallWatcher* ) {}
void kwalletEntryTypeFinished( QDBusPendingCallWatcher* ) {}
void kwalletReadFinished( QDBusPendingCallWatcher* ) {}
#endif
};
class WritePasswordJobPrivate : public QObject {
Q_OBJECT
public:
explicit WritePasswordJobPrivate( WritePasswordJob* qq ) : q( qq ), mode( Delete ) {}
void scheduledStart();
enum Mode {
Delete,
Text,
Binary
};
static QString modeToString(Mode m);
static Mode stringToMode(const QString& s);
WritePasswordJob* const q;
Mode mode;
QString key;
QByteArray binaryData;
QString textData;
#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
org::kde::KWallet* iface;
static void gnomeKeyring_cb( int result, WritePasswordJobPrivate* self );
friend class QKeychain::JobExecutor;
void fallbackOnError(const QDBusError& err);
private Q_SLOTS:
void kwalletWalletFound( QDBusPendingCallWatcher* watcher );
void kwalletOpenFinished( QDBusPendingCallWatcher* watcher );
void kwalletWriteFinished( QDBusPendingCallWatcher* watcher );
#else
private Q_SLOTS:
void kwalletWalletFound( QDBusPendingCallWatcher* ) {}
void kwalletOpenFinished( QDBusPendingCallWatcher* ) {}
void kwalletWriteFinished( QDBusPendingCallWatcher* ) {}
#endif
};
class DeletePasswordJobPrivate : public QObject {
Q_OBJECT
public:
explicit DeletePasswordJobPrivate( DeletePasswordJob* qq ) : q( qq ) {}
void doStart();
DeletePasswordJob* const q;
QString key;
private Q_SLOTS:
void jobFinished( QKeychain::Job* );
};
class JobExecutor : public QObject {
Q_OBJECT
public:
static JobExecutor* instance();
void enqueue( Job* job );
private:
explicit JobExecutor();
void startNextIfNoneRunning();
private Q_SLOTS:
void jobFinished( QKeychain::Job* );
void jobDestroyed( QObject* object );
private:
static JobExecutor* s_instance;
Job* m_runningJob;
QVector<QPointer<Job> > m_queue;
};
}
#endif // KEYCHAIN_P_H

View File

@ -1,510 +0,0 @@
/******************************************************************************
* Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
* or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution *
* details, check the accompanying file 'COPYING'. *
*****************************************************************************/
#include "keychain_p.h"
#include "gnomekeyring_p.h"
#include <QSettings>
#include <QScopedPointer>
using namespace QKeychain;
static QString typeKey( const QString& key )
{
return QString::fromLatin1( "%1/type" ).arg( key );
}
static QString dataKey( const QString& key )
{
return QString::fromLatin1( "%1/data" ).arg( key );
}
enum KeyringBackend {
Backend_GnomeKeyring,
Backend_Kwallet4,
Backend_Kwallet5
};
enum DesktopEnvironment {
DesktopEnv_Gnome,
DesktopEnv_Kde4,
DesktopEnv_Plasma5,
DesktopEnv_Unity,
DesktopEnv_Xfce,
DesktopEnv_Other
};
// the following detection algorithm is derived from chromium,
// licensed under BSD, see base/nix/xdg_util.cc
static DesktopEnvironment getKdeVersion() {
QString value = qgetenv("KDE_SESSION_VERSION");
if ( value == "5" ) {
return DesktopEnv_Plasma5;
} else if (value == "4" ) {
return DesktopEnv_Kde4;
} else {
// most likely KDE3
return DesktopEnv_Other;
}
}
static DesktopEnvironment detectDesktopEnvironment() {
QByteArray xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP");
if ( xdgCurrentDesktop == "GNOME" ) {
return DesktopEnv_Gnome;
} else if ( xdgCurrentDesktop == "Unity" ) {
return DesktopEnv_Unity;
} else if ( xdgCurrentDesktop == "KDE" ) {
return getKdeVersion();
}
QByteArray desktopSession = qgetenv("DESKTOP_SESSION");
if ( desktopSession == "gnome" ) {
return DesktopEnv_Gnome;
} else if ( desktopSession == "kde" ) {
return getKdeVersion();
} else if ( desktopSession == "kde4" ) {
return DesktopEnv_Kde4;
} else if ( desktopSession.contains("xfce") || desktopSession == "xubuntu" ) {
return DesktopEnv_Xfce;
}
if ( !qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty() ) {
return DesktopEnv_Gnome;
} else if ( !qgetenv("KDE_FULL_SESSION").isEmpty() ) {
return getKdeVersion();
}
return DesktopEnv_Other;
}
static KeyringBackend detectKeyringBackend()
{
switch (detectDesktopEnvironment()) {
case DesktopEnv_Kde4:
return Backend_Kwallet4;
break;
case DesktopEnv_Plasma5:
return Backend_Kwallet5;
break;
// fall through
case DesktopEnv_Gnome:
case DesktopEnv_Unity:
case DesktopEnv_Xfce:
case DesktopEnv_Other:
default:
if ( GnomeKeyring::isAvailable() ) {
return Backend_GnomeKeyring;
} else {
return Backend_Kwallet4;
}
}
}
static KeyringBackend getKeyringBackend()
{
static KeyringBackend backend = detectKeyringBackend();
return backend;
}
static void kwalletReadPasswordScheduledStartImpl(const char * service, const char * path, ReadPasswordJobPrivate * priv) {
if ( QDBusConnection::sessionBus().isConnected() )
{
priv->iface = new org::kde::KWallet( QLatin1String(service), QLatin1String(path), QDBusConnection::sessionBus(), priv );
const QDBusPendingReply<QString> reply = priv->iface->networkWallet();
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, priv );
priv->connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), priv, SLOT(kwalletWalletFound(QDBusPendingCallWatcher*)) );
}
else
{
// D-Bus is not reachable so none can tell us something about KWalletd
QDBusError err( QDBusError::NoServer, ReadPasswordJobPrivate::tr("D-Bus is not running") );
priv->fallbackOnError( err );
}
}
void ReadPasswordJobPrivate::scheduledStart() {
switch ( getKeyringBackend() ) {
case Backend_GnomeKeyring:
if ( !GnomeKeyring::find_network_password( key.toUtf8().constData(), q->service().toUtf8().constData(),
reinterpret_cast<GnomeKeyring::OperationGetStringCallback>( &ReadPasswordJobPrivate::gnomeKeyring_cb ),
this, 0 ) )
q->emitFinishedWithError( OtherError, tr("Unknown error") );
break;
case Backend_Kwallet4:
kwalletReadPasswordScheduledStartImpl("org.kde.kwalletd", "/modules/kwalletd", this);
break;
case Backend_Kwallet5:
kwalletReadPasswordScheduledStartImpl("org.kde.kwalletd5", "/modules/kwalletd5", this);
break;
}
}
void ReadPasswordJobPrivate::kwalletWalletFound(QDBusPendingCallWatcher *watcher)
{
watcher->deleteLater();
const QDBusPendingReply<QString> reply = *watcher;
const QDBusPendingReply<int> pendingReply = iface->open( reply.value(), 0, q->service() );
QDBusPendingCallWatcher* pendingWatcher = new QDBusPendingCallWatcher( pendingReply, this );
connect( pendingWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) );
}
static QPair<Error, QString> mapGnomeKeyringError( int result )
{
Q_ASSERT( result != GnomeKeyring::RESULT_OK );
switch ( result ) {
case GnomeKeyring::RESULT_DENIED:
return qMakePair( AccessDenied, QObject::tr("Access to keychain denied") );
case GnomeKeyring::RESULT_NO_KEYRING_DAEMON:
return qMakePair( NoBackendAvailable, QObject::tr("No keyring daemon") );
case GnomeKeyring::RESULT_ALREADY_UNLOCKED:
return qMakePair( OtherError, QObject::tr("Already unlocked") );
case GnomeKeyring::RESULT_NO_SUCH_KEYRING:
return qMakePair( OtherError, QObject::tr("No such keyring") );
case GnomeKeyring::RESULT_BAD_ARGUMENTS:
return qMakePair( OtherError, QObject::tr("Bad arguments") );
case GnomeKeyring::RESULT_IO_ERROR:
return qMakePair( OtherError, QObject::tr("I/O error") );
case GnomeKeyring::RESULT_CANCELLED:
return qMakePair( OtherError, QObject::tr("Cancelled") );
case GnomeKeyring::RESULT_KEYRING_ALREADY_EXISTS:
return qMakePair( OtherError, QObject::tr("Keyring already exists") );
case GnomeKeyring::RESULT_NO_MATCH:
return qMakePair( EntryNotFound, QObject::tr("No match") );
default:
break;
}
return qMakePair( OtherError, QObject::tr("Unknown error") );
}
void ReadPasswordJobPrivate::gnomeKeyring_cb( int result, const char* string, ReadPasswordJobPrivate* self )
{
if ( result == GnomeKeyring::RESULT_OK ) {
if ( self->dataType == ReadPasswordJobPrivate::Text )
self->data = string;
else
self->data = QByteArray::fromBase64( string );
self->q->emitFinished();
} else {
const QPair<Error, QString> errorResult = mapGnomeKeyringError( result );
self->q->emitFinishedWithError( errorResult.first, errorResult.second );
}
}
void ReadPasswordJobPrivate::fallbackOnError(const QDBusError& err )
{
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.data();
if ( q->insecureFallback() && actual->contains( dataKey( key ) ) ) {
const WritePasswordJobPrivate::Mode mode = WritePasswordJobPrivate::stringToMode( actual->value( typeKey( key ) ).toString() );
if (mode == WritePasswordJobPrivate::Binary)
dataType = Binary;
else
dataType = Text;
data = actual->value( dataKey( key ) ).toByteArray();
q->emitFinished();
} else {
if ( err.type() == QDBusError::ServiceUnknown ) //KWalletd not running
q->emitFinishedWithError( NoBackendAvailable, tr("No keychain service available") );
else
q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
}
}
void ReadPasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
watcher->deleteLater();
const QDBusPendingReply<int> reply = *watcher;
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.data();
if ( reply.isError() ) {
fallbackOnError( reply.error() );
return;
}
if ( actual->contains( dataKey( key ) ) ) {
// We previously stored data in the insecure QSettings, but now have KWallet available.
// Do the migration
data = actual->value( dataKey( key ) ).toByteArray();
const WritePasswordJobPrivate::Mode mode = WritePasswordJobPrivate::stringToMode( actual->value( typeKey( key ) ).toString() );
actual->remove( key );
q->emitFinished();
WritePasswordJob* j = new WritePasswordJob( q->service(), 0 );
j->setSettings( q->settings() );
j->setKey( key );
j->setAutoDelete( true );
if ( mode == WritePasswordJobPrivate::Binary )
j->setBinaryData( data );
else if ( mode == WritePasswordJobPrivate::Text )
j->setTextData( QString::fromUtf8( data ) );
else
Q_ASSERT( false );
j->start();
return;
}
walletHandle = reply.value();
if ( walletHandle < 0 ) {
q->emitFinishedWithError( AccessDenied, tr("Access to keychain denied") );
return;
}
const QDBusPendingReply<int> nextReply = iface->entryType( walletHandle, q->service(), key, q->service() );
QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletEntryTypeFinished(QDBusPendingCallWatcher*)) );
}
//Must be in sync with KWallet::EntryType (kwallet.h)
enum KWalletEntryType {
Unknown=0,
Password,
Stream,
Map
};
void ReadPasswordJobPrivate::kwalletEntryTypeFinished( QDBusPendingCallWatcher* watcher ) {
watcher->deleteLater();
if ( watcher->isError() ) {
const QDBusError err = watcher->error();
q->emitFinishedWithError( OtherError, tr("Could not determine data type: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
return;
}
const QDBusPendingReply<int> reply = *watcher;
const int value = reply.value();
switch ( value ) {
case Unknown:
q->emitFinishedWithError( EntryNotFound, tr("Entry not found") );
return;
case Password:
dataType = Text;
break;
case Stream:
dataType = Binary;
break;
case Map:
q->emitFinishedWithError( EntryNotFound, tr("Unsupported entry type 'Map'") );
return;
default:
q->emitFinishedWithError( OtherError, tr("Unknown kwallet entry type '%1'").arg( value ) );
return;
}
const QDBusPendingCall nextReply = dataType == Text
? QDBusPendingCall( iface->readPassword( walletHandle, q->service(), key, q->service() ) )
: QDBusPendingCall( iface->readEntry( walletHandle, q->service(), key, q->service() ) );
QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletReadFinished(QDBusPendingCallWatcher*)) );
}
void ReadPasswordJobPrivate::kwalletReadFinished( QDBusPendingCallWatcher* watcher ) {
watcher->deleteLater();
if ( watcher->isError() ) {
const QDBusError err = watcher->error();
q->emitFinishedWithError( OtherError, tr("Could not read password: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
return;
}
if ( dataType == Binary ) {
QDBusPendingReply<QByteArray> reply = *watcher;
data = reply.value();
} else {
QDBusPendingReply<QString> reply = *watcher;
data = reply.value().toUtf8();
}
q->emitFinished();
}
static void kwalletWritePasswordScheduledStart( const char * service, const char * path, WritePasswordJobPrivate * priv ) {
if ( QDBusConnection::sessionBus().isConnected() )
{
priv->iface = new org::kde::KWallet( QLatin1String(service), QLatin1String(path), QDBusConnection::sessionBus(), priv );
const QDBusPendingReply<QString> reply = priv->iface->networkWallet();
QDBusPendingCallWatcher* watcher = new QDBusPendingCallWatcher( reply, priv );
priv->connect( watcher, SIGNAL(finished(QDBusPendingCallWatcher*)), priv, SLOT(kwalletWalletFound(QDBusPendingCallWatcher*)) );
}
else
{
// D-Bus is not reachable so none can tell us something about KWalletd
QDBusError err( QDBusError::NoServer, WritePasswordJobPrivate::tr("D-Bus is not running") );
priv->fallbackOnError( err );
}
}
void WritePasswordJobPrivate::scheduledStart() {
switch ( getKeyringBackend() ) {
case Backend_GnomeKeyring:
if ( mode == WritePasswordJobPrivate::Delete ) {
if ( !GnomeKeyring::delete_network_password( key.toUtf8().constData(), q->service().toUtf8().constData(),
reinterpret_cast<GnomeKeyring::OperationDoneCallback>( &WritePasswordJobPrivate::gnomeKeyring_cb ),
this, 0 ) )
q->emitFinishedWithError( OtherError, tr("Unknown error") );
} else {
QByteArray password = mode == WritePasswordJobPrivate::Text ? textData.toUtf8() : binaryData.toBase64();
QByteArray service = q->service().toUtf8();
if ( !GnomeKeyring::store_network_password( GnomeKeyring::GNOME_KEYRING_DEFAULT, service.constData(),
key.toUtf8().constData(), service.constData(), password.constData(),
reinterpret_cast<GnomeKeyring::OperationDoneCallback>( &WritePasswordJobPrivate::gnomeKeyring_cb ),
this, 0 ) )
q->emitFinishedWithError( OtherError, tr("Unknown error") );
}
break;
case Backend_Kwallet4:
kwalletWritePasswordScheduledStart("org.kde.kwalletd", "/modules/kwalletd", this);
break;
case Backend_Kwallet5:
kwalletWritePasswordScheduledStart("org.kde.kwalletd5", "/modules/kwalletd5", this);
break;
}
}
QString WritePasswordJobPrivate::modeToString(Mode m)
{
switch (m) {
case Delete:
return QLatin1String("Delete");
case Text:
return QLatin1String("Text");
case Binary:
return QLatin1String("Binary");
}
Q_ASSERT_X(false, Q_FUNC_INFO, "Unhandled Mode value");
return QString();
}
WritePasswordJobPrivate::Mode WritePasswordJobPrivate::stringToMode(const QString& s)
{
if (s == QLatin1String("Delete") || s == QLatin1String("0"))
return Delete;
if (s == QLatin1String("Text") || s == QLatin1String("1"))
return Text;
if (s == QLatin1String("Binary") || s == QLatin1String("2"))
return Binary;
qCritical("Unexpected mode string '%s'", qPrintable(s));
return Text;
}
void WritePasswordJobPrivate::fallbackOnError(const QDBusError &err)
{
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.data();
if ( !q->insecureFallback() ) {
q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
return;
}
if ( mode == Delete ) {
actual->remove( key );
actual->sync();
q->emitFinished();
return;
}
actual->setValue( QString::fromLatin1( "%1/type" ).arg( key ), mode );
if ( mode == Text )
actual->setValue( QString::fromLatin1( "%1/data" ).arg( key ), textData.toUtf8() );
else if ( mode == Binary )
actual->setValue( QString::fromLatin1( "%1/data" ).arg( key ), binaryData );
actual->sync();
q->emitFinished();
}
void WritePasswordJobPrivate::gnomeKeyring_cb( int result, WritePasswordJobPrivate* self )
{
if ( result == GnomeKeyring::RESULT_OK ) {
self->q->emitFinished();
} else {
const QPair<Error, QString> errorResult = mapGnomeKeyringError( result );
self->q->emitFinishedWithError( errorResult.first, errorResult.second );
}
}
void WritePasswordJobPrivate::kwalletWalletFound(QDBusPendingCallWatcher *watcher)
{
watcher->deleteLater();
const QDBusPendingReply<QString> reply = *watcher;
const QDBusPendingReply<int> pendingReply = iface->open( reply.value(), 0, q->service() );
QDBusPendingCallWatcher* pendingWatcher = new QDBusPendingCallWatcher( pendingReply, this );
connect( pendingWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletOpenFinished(QDBusPendingCallWatcher*)) );
}
void WritePasswordJobPrivate::kwalletOpenFinished( QDBusPendingCallWatcher* watcher ) {
watcher->deleteLater();
QDBusPendingReply<int> reply = *watcher;
QScopedPointer<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.data();
if ( reply.isError() ) {
fallbackOnError( reply.error() );
return;
}
if ( actual->contains( key ) )
{
// If we had previously written to QSettings, but we now have a kwallet available, migrate and delete old insecure data
actual->remove( key );
actual->sync();
}
const int handle = reply.value();
if ( handle < 0 ) {
q->emitFinishedWithError( AccessDenied, tr("Access to keychain denied") );
return;
}
QDBusPendingReply<int> nextReply;
if ( !textData.isEmpty() )
nextReply = iface->writePassword( handle, q->service(), key, textData, q->service() );
else if ( !binaryData.isEmpty() )
nextReply = iface->writeEntry( handle, q->service(), key, binaryData, q->service() );
else
nextReply = iface->removeEntry( handle, q->service(), key, q->service() );
QDBusPendingCallWatcher* nextWatcher = new QDBusPendingCallWatcher( nextReply, this );
connect( nextWatcher, SIGNAL(finished(QDBusPendingCallWatcher*)), this, SLOT(kwalletWriteFinished(QDBusPendingCallWatcher*)) );
}
void WritePasswordJobPrivate::kwalletWriteFinished( QDBusPendingCallWatcher* watcher ) {
watcher->deleteLater();
QDBusPendingReply<int> reply = *watcher;
if ( reply.isError() ) {
const QDBusError err = reply.error();
q->emitFinishedWithError( OtherError, tr("Could not open wallet: %1; %2").arg( QDBusError::errorString( err.type() ), err.message() ) );
return;
}
q->emitFinished();
}

View File

@ -1,107 +0,0 @@
/******************************************************************************
* Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
* or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution *
* details, check the accompanying file 'COPYING'. *
*****************************************************************************/
#include "keychain_p.h"
#include <QSettings>
#include <windows.h>
#include <wincrypt.h>
#include <memory>
using namespace QKeychain;
void ReadPasswordJobPrivate::scheduledStart() {
//Use settings member if there, create local settings object if not
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.get();
QByteArray encrypted = actual->value( key ).toByteArray();
if ( encrypted.isNull() ) {
q->emitFinishedWithError( EntryNotFound, tr("Entry not found") );
return;
}
DATA_BLOB blob_in, blob_out;
blob_in.pbData = reinterpret_cast<BYTE*>( encrypted.data() );
blob_in.cbData = encrypted.size();
const BOOL ret = CryptUnprotectData( &blob_in,
NULL,
NULL,
NULL,
NULL,
0,
&blob_out );
if ( !ret ) {
q->emitFinishedWithError( OtherError, tr("Could not decrypt data") );
return;
}
data = QByteArray( reinterpret_cast<char*>( blob_out.pbData ), blob_out.cbData );
SecureZeroMemory( blob_out.pbData, blob_out.cbData );
LocalFree( blob_out.pbData );
q->emitFinished();
}
void WritePasswordJobPrivate::scheduledStart() {
if ( mode == Delete ) {
//Use settings member if there, create local settings object if not
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.get();
actual->remove( key );
actual->sync();
if ( actual->status() != QSettings::NoError ) {
const QString err = actual->status() == QSettings::AccessError
? tr("Could not delete encrypted data from settings: access error")
: tr("Could not delete encrypted data from settings: format error");
q->emitFinishedWithError( OtherError, err );
} else {
q->emitFinished();
}
return;
}
QByteArray data = mode == Binary ? binaryData : textData.toUtf8();
DATA_BLOB blob_in, blob_out;
blob_in.pbData = reinterpret_cast<BYTE*>( data.data() );
blob_in.cbData = data.size();
const BOOL res = CryptProtectData( &blob_in,
L"QKeychain-encrypted data",
NULL,
NULL,
NULL,
0,
&blob_out );
if ( !res ) {
q->emitFinishedWithError( OtherError, tr("Encryption failed") ); //TODO more details available?
return;
}
const QByteArray encrypted( reinterpret_cast<char*>( blob_out.pbData ), blob_out.cbData );
LocalFree( blob_out.pbData );
//Use settings member if there, create local settings object if not
std::auto_ptr<QSettings> local( !q->settings() ? new QSettings( q->service() ) : 0 );
QSettings* actual = q->settings() ? q->settings() : local.get();
actual->setValue( key, encrypted );
actual->sync();
if ( actual->status() != QSettings::NoError ) {
const QString errorString = actual->status() == QSettings::AccessError
? tr("Could not store encrypted data in settings: access error")
: tr("Could not store encrypted data in settings: format error");
q->emitFinishedWithError( OtherError, errorString );
return;
}
q->emitFinished();
}

View File

@ -1,276 +0,0 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.kde.KWallet">
<signal name="walletListDirty">
</signal>
<signal name="walletCreated">
<arg name="wallet" type="s" direction="out"/>
</signal>
<signal name="walletOpened">
<arg name="wallet" type="s" direction="out"/>
</signal>
<signal name="walletAsyncOpened">
<arg name="tId" type="i" direction="out"/>
<arg name="handle" type="i" direction="out"/>
</signal>
<signal name="walletDeleted">
<arg name="wallet" type="s" direction="out"/>
</signal>
<signal name="walletClosed">
<arg name="wallet" type="s" direction="out"/>
</signal>
<signal name="walletClosed">
<arg name="handle" type="i" direction="out"/>
</signal>
<signal name="allWalletsClosed">
</signal>
<signal name="folderListUpdated">
<arg name="wallet" type="s" direction="out"/>
</signal>
<signal name="folderUpdated">
<arg type="s" direction="out"/>
<arg type="s" direction="out"/>
</signal>
<signal name="applicationDisconnected">
<arg name="wallet" type="s" direction="out"/>
<arg name="application" type="s" direction="out"/>
</signal>
<method name="isEnabled">
<arg type="b" direction="out"/>
</method>
<method name="open">
<arg type="i" direction="out"/>
<arg name="wallet" type="s" direction="in"/>
<arg name="wId" type="x" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="openPath">
<arg type="i" direction="out"/>
<arg name="path" type="s" direction="in"/>
<arg name="wId" type="x" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="openAsync">
<arg type="i" direction="out"/>
<arg name="wallet" type="s" direction="in"/>
<arg name="wId" type="x" direction="in"/>
<arg name="appid" type="s" direction="in"/>
<arg name="handleSession" type="b" direction="in"/>
</method>
<method name="openPathAsync">
<arg type="i" direction="out"/>
<arg name="path" type="s" direction="in"/>
<arg name="wId" type="x" direction="in"/>
<arg name="appid" type="s" direction="in"/>
<arg name="handleSession" type="b" direction="in"/>
</method>
<method name="close">
<arg type="i" direction="out"/>
<arg name="wallet" type="s" direction="in"/>
<arg name="force" type="b" direction="in"/>
</method>
<method name="close">
<arg type="i" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="force" type="b" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="sync">
<arg name="handle" type="i" direction="in"/>
<arg name="appid" type="s" direction="in"/>
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
<method name="deleteWallet">
<arg type="i" direction="out"/>
<arg name="wallet" type="s" direction="in"/>
</method>
<method name="isOpen">
<arg type="b" direction="out"/>
<arg name="wallet" type="s" direction="in"/>
</method>
<method name="isOpen">
<arg type="b" direction="out"/>
<arg name="handle" type="i" direction="in"/>
</method>
<method name="users">
<arg type="as" direction="out"/>
<arg name="wallet" type="s" direction="in"/>
</method>
<method name="changePassword">
<arg name="wallet" type="s" direction="in"/>
<arg name="wId" type="x" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="wallets">
<arg type="as" direction="out"/>
</method>
<method name="folderList">
<arg type="as" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="hasFolder">
<arg type="b" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="createFolder">
<arg type="b" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="removeFolder">
<arg type="b" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="entryList">
<arg type="as" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="readEntry">
<arg type="ay" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="readMap">
<arg type="ay" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="readPassword">
<arg type="s" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="readEntryList">
<arg type="a{sv}" direction="out"/>
<annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="readMapList">
<arg type="a{sv}" direction="out"/>
<annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="readPasswordList">
<arg type="a{sv}" direction="out"/>
<annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QVariantMap"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="renameEntry">
<arg type="i" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="oldName" type="s" direction="in"/>
<arg name="newName" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="writeEntry">
<arg type="i" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
<arg name="value" type="ay" direction="in"/>
<arg name="entryType" type="i" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="writeEntry">
<arg type="i" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
<arg name="value" type="ay" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="writeMap">
<arg type="i" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
<arg name="value" type="ay" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="writePassword">
<arg type="i" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
<arg name="value" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="hasEntry">
<arg type="b" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="entryType">
<arg type="i" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="removeEntry">
<arg type="i" direction="out"/>
<arg name="handle" type="i" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
<arg name="appid" type="s" direction="in"/>
</method>
<method name="disconnectApplication">
<arg type="b" direction="out"/>
<arg name="wallet" type="s" direction="in"/>
<arg name="application" type="s" direction="in"/>
</method>
<method name="reconfigure">
</method>
<method name="folderDoesNotExist">
<arg type="b" direction="out"/>
<arg name="wallet" type="s" direction="in"/>
<arg name="folder" type="s" direction="in"/>
</method>
<method name="keyDoesNotExist">
<arg type="b" direction="out"/>
<arg name="wallet" type="s" direction="in"/>
<arg name="folder" type="s" direction="in"/>
<arg name="key" type="s" direction="in"/>
</method>
<method name="closeAllWallets">
</method>
<method name="networkWallet">
<arg type="s" direction="out"/>
</method>
<method name="localWallet">
<arg type="s" direction="out"/>
</method>
<method name="pamOpen">
<arg name="wallet" type="s" direction="in"/>
<arg name="passwordHash" type="ay" direction="in"/>
<arg name="sessionTimeout" type="i" direction="in"/>
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
</method>
</interface>
</node>

View File

@ -1,17 +0,0 @@
#ifndef QKEYCHAIN_EXPORT_H
#define QKEYCHAIN_EXPORT_H
#include <qglobal.h>
# ifdef QKEYCHAIN_STATICLIB
# undef QKEYCHAIN_SHAREDLIB
# define QKEYCHAIN_EXPORT
# else
# ifdef QKEYCHAIN_BUILD_QKEYCHAIN_LIB
# define QKEYCHAIN_EXPORT Q_DECL_EXPORT
# else
# define QKEYCHAIN_EXPORT Q_DECL_IMPORT
# endif
# endif
#endif

View File

@ -1,98 +0,0 @@
/******************************************************************************
* Copyright (C) 2011-2015 Frank Osterfeld <frank.osterfeld@gmail.com> *
* *
* This program is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
* or FITNESS FOR A PARTICULAR PURPOSE. For licensing and distribution *
* details, check the accompanying file 'COPYING'. *
*****************************************************************************/
#include <QCoreApplication>
#include <QStringList>
#include "keychain.h"
#include <iostream>
using namespace QKeychain;
static int printUsage() {
std::cerr << "testclient store <account> <password>" << std::endl;
std::cerr << "testclient restore <account>" << std::endl;
std::cerr << "testclient delete <account>" << std::endl;
return 1;
}
int main( int argc, char** argv ) {
QCoreApplication app( argc, argv );
const QStringList args = app.arguments();
if ( args.count() < 2 )
return printUsage();
QStringList::ConstIterator it = args.constBegin();
++it;
if ( *it == QLatin1String("store") ) {
if ( ++it == args.constEnd() )
return printUsage();
const QString acc = *it;
if ( ++it == args.constEnd() )
return printUsage();
const QString pass = *it;
if ( ++it != args.constEnd() )
return printUsage();
WritePasswordJob job( QLatin1String("qtkeychain-testclient") );
job.setAutoDelete( false );
job.setKey( acc );
job.setTextData( pass );
QEventLoop loop;
job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) );
job.start();
loop.exec();
if ( job.error() ) {
std::cerr << "Storing password failed: " << qPrintable(job.errorString()) << std::endl;
return 1;
}
std::cout << "Password stored successfully" << std::endl;
} else if ( *it == QLatin1String("restore") ) {
if ( ++it == args.constEnd() )
return printUsage();
const QString acc = *it;
if ( ++it != args.constEnd() )
return printUsage();
ReadPasswordJob job( QLatin1String("qtkeychain-testclient") );
job.setAutoDelete( false );
job.setKey( acc );
QEventLoop loop;
job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) );
job.start();
loop.exec();
const QString pw = job.textData();
if ( job.error() ) {
std::cerr << "Restoring password failed: " << qPrintable(job.errorString()) << std::endl;
return 1;
}
std::cout << qPrintable(pw) << std::endl;
} else if ( *it == QLatin1String("delete") ) {
if ( ++it == args.constEnd() )
return printUsage();
const QString acc = *it;
if ( ++it != args.constEnd() )
return printUsage();
DeletePasswordJob job( QLatin1String("qtkeychain-testclient") );
job.setAutoDelete( false );
job.setKey( acc );
QEventLoop loop;
job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) );
job.start();
loop.exec();
if ( job.error() ) {
std::cerr << "Deleting password failed: " << qPrintable(job.errorString()) << std::endl;
return 1;
}
std::cout << "Password deleted successfully" << std::endl;
} else {
return printUsage();
}
}

View File

@ -1,177 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="de_DE">
<context>
<name>QKeychain::ReadPasswordJobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="140"/>
<source>Unknown error</source>
<translation>Unbekannter Fehler</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="129"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="222"/>
<source>No keychain service available</source>
<translation>Kein Schlüsselbund-Dienst verfügbar</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="224"/>
<source>Could not open wallet: %1; %2</source>
<translation>Konnte Brieftasche nicht öffnen: %1; %2</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="270"/>
<source>Access to keychain denied</source>
<translation>Zugriff auf Schlüsselbund verweigert</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="291"/>
<source>Could not determine data type: %1; %2</source>
<translation>Datentyp kann nicht ermittelt werden: %1: %2</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="309"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="312"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="327"/>
<source>Could not read password: %1; %2</source>
<translation>Passwort konnte nicht ausgelesen werden: %1; %2</translation>
</message>
<message>
<location filename="../keychain_mac.cpp" line="76"/>
<source>Password not found</source>
<translation>Passwort nicht gefunden</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="300"/>
<location filename="../keychain_win.cpp" line="27"/>
<source>Entry not found</source>
<translation>Eintrag nicht gefunden</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="44"/>
<source>Could not decrypt data</source>
<translation>Kann Daten nicht entschlüsseln</translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="364"/>
<location filename="../keychain_unix.cpp" line="372"/>
<source>Unknown error</source>
<translation>Unbekannter Fehler</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="352"/>
<source>D-Bus is not running</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="420"/>
<location filename="../keychain_unix.cpp" line="505"/>
<source>Could not open wallet: %1; %2</source>
<translation>Konnte Brieftasche nicht öffnen: %1; %2</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="483"/>
<source>Access to keychain denied</source>
<translation>Zugriff auf Schlüsselbund verweigert</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation>Kann verschlüsselte Daten nicht aus den Einstellungen entfernen: Zugriffsfehler</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation>Kann verschlüsselte Daten nicht aus den Einstellungen entfernen: Formatfehler</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="85"/>
<source>Encryption failed</source>
<translation>Verschlüsselung fehlgeschlagen</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation>Kann verschlüsselte Daten nicht in den Einstellungen speichern: Zugriffsfehler</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation>Kann verschlüsselte Daten nicht in den Einstellungen speichern: Formatfehler</translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../keychain_unix.cpp" line="167"/>
<source>Access to keychain denied</source>
<translation>Zugriff auf Schlüsselbund verweigert</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="169"/>
<source>No keyring daemon</source>
<translation>Kein Schlüsselbund-Dienst </translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="171"/>
<source>Already unlocked</source>
<translation>Bereits entsperrt</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="173"/>
<source>No such keyring</source>
<translation>Kein solcher Schlüsselbund</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="175"/>
<source>Bad arguments</source>
<translation>Ungültige Argumente</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="177"/>
<source>I/O error</source>
<translation>Ein-/Ausgabe-Fehler</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="179"/>
<source>Cancelled</source>
<translation>Abgebrochen</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="181"/>
<source>Keyring already exists</source>
<translation>Schlüsselbund existiert bereits</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="183"/>
<source>No match</source>
<translation>Kein Treffer</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="188"/>
<source>Unknown error</source>
<translation>Unbekannter Fehler</translation>
</message>
<message>
<location filename="../keychain_mac.cpp" line="31"/>
<location filename="../keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -1,178 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="ro_RO">
<context>
<name>QKeychain::ReadPasswordJobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="140"/>
<source>Unknown error</source>
<translation>Eroare necunoscută</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="129"/>
<source>D-Bus is not running</source>
<translation>D-Bus nu rulează</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="222"/>
<source>No keychain service available</source>
<translatorcomment>Nu există niciun serviciu de chei disponibil</translatorcomment>
<translation>Kein Schlüsselbund-Dienst verfügbar</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="224"/>
<source>Could not open wallet: %1; %2</source>
<translation>Nu se poate deschide portofelul: %1; %2</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="270"/>
<source>Access to keychain denied</source>
<translation>Acces interzis la serviciul de chei</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="291"/>
<source>Could not determine data type: %1; %2</source>
<translation>Nu se poate stabili tipul de date: %1: %2</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="309"/>
<source>Unsupported entry type &apos;Map&apos;</source>
<translation>Tip de înregistrare nesuportat &apos;Map&apos;</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="312"/>
<source>Unknown kwallet entry type &apos;%1&apos;</source>
<translation>Tip de înregistrare kwallet necunoscut &apos;%1&apos;</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="327"/>
<source>Could not read password: %1; %2</source>
<translation>Nu se poate citi parola: %1; %2</translation>
</message>
<message>
<location filename="../keychain_mac.cpp" line="76"/>
<source>Password not found</source>
<translation>Parola nu a fost găsită</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="300"/>
<location filename="../keychain_win.cpp" line="27"/>
<source>Entry not found</source>
<translation>Înregistrarea nu a fost găsită</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="44"/>
<source>Could not decrypt data</source>
<translation>Nu se poate decripta data</translation>
</message>
</context>
<context>
<name>QKeychain::WritePasswordJobPrivate</name>
<message>
<location filename="../keychain_unix.cpp" line="364"/>
<location filename="../keychain_unix.cpp" line="372"/>
<source>Unknown error</source>
<translation>Eroare necunoscută</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="352"/>
<source>D-Bus is not running</source>
<translation>D-Bus nu rulează</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="420"/>
<location filename="../keychain_unix.cpp" line="505"/>
<source>Could not open wallet: %1; %2</source>
<translation>Nu se poate deschide portofelul: %1; %2</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="483"/>
<source>Access to keychain denied</source>
<translation>Acces interzis la serviciul de chei</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="64"/>
<source>Could not delete encrypted data from settings: access error</source>
<translation>Nu se pot șterge datele criptate din setări: eroare de acces</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="65"/>
<source>Could not delete encrypted data from settings: format error</source>
<translation>Nu se pot șterge datele criptate din setări: eroare de format</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="85"/>
<source>Encryption failed</source>
<translation>Criptarea a eșuat</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="100"/>
<source>Could not store encrypted data in settings: access error</source>
<translation>Nu se pot stoca datele criptate în setări: eroare de acces</translation>
</message>
<message>
<location filename="../keychain_win.cpp" line="101"/>
<source>Could not store encrypted data in settings: format error</source>
<translation>Nu se pot stoca datele criptate în setări: eroare de format</translation>
</message>
</context>
<context>
<name>QObject</name>
<message>
<location filename="../keychain_unix.cpp" line="167"/>
<source>Access to keychain denied</source>
<translation>Acces interzis la serviciul de chei</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="169"/>
<source>No keyring daemon</source>
<translation>Niciun demon pentru inelul de chei</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="171"/>
<source>Already unlocked</source>
<translation>Deja deblocat</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="173"/>
<source>No such keyring</source>
<translation>Nu există astfel de inel de chei</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="175"/>
<source>Bad arguments</source>
<translation>Argumente greșite</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="177"/>
<source>I/O error</source>
<translation>Eroare de I/E</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="179"/>
<source>Cancelled</source>
<translation>Anulat</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="181"/>
<source>Keyring already exists</source>
<translation>Inelul de chei deja există</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="183"/>
<source>No match</source>
<translation>Nicio potrivire</translation>
</message>
<message>
<location filename="../keychain_unix.cpp" line="188"/>
<source>Unknown error</source>
<translation>Eroare necunoscută</translation>
</message>
<message>
<location filename="../keychain_mac.cpp" line="31"/>
<location filename="../keychain_mac.cpp" line="33"/>
<source>%1 (OSStatus %2)</source>
<translation>%1 (OSStatus %2)</translation>
</message>
</context>
</TS>

View File

@ -2,11 +2,10 @@
# Fuel
#-------------------------------------------------
QT = core gui webkit
QT += core gui webkit
contains(QT_VERSION, ^5\\..*) {
QT += widgets webkitwidgets
QT -= quick multimediawidgets opengl printsupport qml multimedia positioning sensors
}
TARGET = Fuel
@ -53,86 +52,34 @@ SOURCES += src/main.cpp\
src/CommitDialog.cpp \
src/FileActionDialog.cpp \
src/SettingsDialog.cpp \
src/FslSettingsDialog.cpp \
src/CloneDialog.cpp \
src/RevisionDialog.cpp \
src/Utils.cpp \
src/FileTableView.cpp \
src/CloneDialog.cpp \
src/LoggedProcess.cpp \
src/BrowserWidget.cpp \
src/CustomWebView.cpp \
src/Fossil.cpp \
src/Workspace.cpp \
src/SearchBox.cpp \
src/Settings.cpp \
src/RemoteDialog.cpp \
src/AboutDialog.cpp
src/CustomWebView.cpp
HEADERS += src/MainWindow.h \
src/CommitDialog.h \
src/FileActionDialog.h \
src/SettingsDialog.h \
src/FslSettingsDialog.h \
src/CloneDialog.h \
src/RevisionDialog.h \
src/Utils.h \
src/FileTableView.h \
src/CloneDialog.h \
src/LoggedProcess.h \
src/BrowserWidget.h \
src/CustomWebView.h \
src/Fossil.h \
src/Workspace.h \
src/SearchBox.h \
src/Settings.h \
src/RemoteDialog.h \
src/AboutDialog.h
src/CustomWebView.h
FORMS += ui/MainWindow.ui \
ui/CommitDialog.ui \
ui/FileActionDialog.ui \
ui/SettingsDialog.ui \
ui/FslSettingsDialog.ui \
ui/CloneDialog.ui \
ui/BrowserWidget.ui \
ui/RevisionDialog.ui \
ui/RemoteDialog.ui \
ui/AboutDialog.ui
ui/BrowserWidget.ui
RESOURCES += \
rsrc/resources.qrc
# QtKeychain
SOURCES += ext/qtkeychain/keychain.cpp
HEADERS += ext/qtkeychain/keychain.h \
ext/qtkeychain/keychain_p.h \
ext/qtkeychain/qkeychain_export.h
DEFINES += QKEYCHAIN_STATICLIB
unix:!macx {
QT += dbus
SOURCES += ext/qtkeychain/keychain_unix.cpp \
ext/qtkeychain/gnomekeyring.cpp
HEADERS += ext/qtkeychain/gnomekeyring_p.h
DBUS_INTERFACES += ext/qtkeychain/org.kde.KWallet.xml
}
macx {
SOURCES += ext/qtkeychain/keychain_mac.cpp
LIBS += -framework CoreFoundation -framework Security
}
win32 {
SOURCES += ext/qtkeychain/keychain_win.cpp
LIBS += -lCrypt32
}
CODECFORTR = UTF-8
TRANSLATIONS += \

View File

@ -1,14 +1,12 @@
#!/bin/sh
SCRIPTDIR="$( cd "$( dirname "$0" )" && pwd )"
#!/bin/bash
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
PRJDIR=$SCRIPTDIR/..
INTLDIR=$SCRIPTDIR
# Detect lrelease tool
if which lrelease-qt5 2>/dev/null; then
if hash lrelease-qt5 2>/dev/null; then
LRELEASE="lrelease-qt5"
elif which lrelease4 2>/dev/null; then
LRELEASE="lrelease4"
elif which lrelease 2>/dev/null; then
elif hash lrelease 2>/dev/null; then
LRELEASE="lrelease"
else
echo "lrelease not found"

View File

@ -1,5 +1,5 @@
C OSX:\sGuess\sactual\sexecutable\sfrom\sthe\sapp\sbundle\sdirectory
D 2015-08-22T17:32:24.250
C Updated\sthe\sChanges.md
D 2015-08-23T14:11:16.693
F .travis.yml 77966888a81c4ceee1fcc79bce842c9667ad8a35
F debian/changelog eb4304dfcb6bb66850ec740838090eb50ce1249b
F debian/compat b6abd567fa79cbe0196d093a067271361dc6ca8b
@ -10,36 +10,14 @@ F debian/menu aa1321fe6597a631df5cc978a3cf7b21ac1a3657
F debian/rules 468914cbcf1bcc252ab3f616e1fdc2b37bc10b5d x
F debian/source/format 1064dc0ce263680c076a1005f35ec906a5cf5a32
F debian/watch 34f0921ff100a3e16a7ad84dcc303731de830a60
F dist/arch/PKGBUILD 26623327e467028a883cd13963daa36baf10dfa3
F dist/arch/PKGBUILD c9d706805891dadfab933c703e19dc86f084d328
F dist/win/fuel.iss ef3558dbba409eb194938b930377fc9ee27d319e
F doc/Building.md 149d959751ae488829e084a9f88449a08220c1d1
F doc/Changes.md af49b873012c6b453fe8084f46b6aadbd6fe6e63
F doc/Changes.md 9546f046a1c37ea6011cdae77da24df883a8e0ee
F doc/License.txt 4cc77b90af91e615a64ae04893fdffa7939db84c
F ext/qtkeychain/CMakeLists.txt fc1afa05034f2765ba243ce758a7e9d6b6efe2d6
F ext/qtkeychain/COPYING d0f83c8198fdd5464d2373015b7b64ce7cae607e
F ext/qtkeychain/ChangeLog 1703279e17036995806ba1719033d14840a8a7e2
F ext/qtkeychain/QtKeychainBuildTreeSettings.cmake.in a50c3b646181124f15b946c3297f13012e959341
F ext/qtkeychain/QtKeychainConfig.cmake.in ac7c87e54854a06c51e00f833f21f8323d1e6884
F ext/qtkeychain/QtKeychainConfigVersion.cmake.in 3b650037d5775f28802c0471afe2cf6dbe51084e
F ext/qtkeychain/ReadMe.markdown 65fe7f400600aa98a9a7fa5c3fc842ad8699cc43
F ext/qtkeychain/ReadMe.txt 65fe7f400600aa98a9a7fa5c3fc842ad8699cc43
F ext/qtkeychain/cmake/Modules/GNUInstallDirs.cmake 7a2ccf81f25546e93a6f48c792cdebaae51857e9
F ext/qtkeychain/gnomekeyring.cpp 7fa97bd4ffb7c9df00d25e56cd9173d34109afe6
F ext/qtkeychain/gnomekeyring_p.h 7f6acaf6d00b36bd08f5f31ba9136efa969e9875
F ext/qtkeychain/keychain.cpp 427cbda7c6a76de995b1f1b4caa700cd06a9d19a
F ext/qtkeychain/keychain.h f084c671b481af6ac7ce00bf641055a3cfc9cf9b
F ext/qtkeychain/keychain_mac.cpp a028f6fc5e40f9ab88c94ebe30b8b0ae417f2f34
F ext/qtkeychain/keychain_p.h 36f4caee2cbdbde971a1105ab388681ad2924665
F ext/qtkeychain/keychain_unix.cpp 8e657da9acd9e86b2fdec19dc40f1afa4a1c5191
F ext/qtkeychain/keychain_win.cpp e52877828703650219c1c674e618c7211f588d0d
F ext/qtkeychain/org.kde.KWallet.xml f3729fda9f8fa8031a6f69415dcc29455c3c9ae6
F ext/qtkeychain/qkeychain_export.h d756528188ef9bf3c4461ecc80048f06c362b54b
F ext/qtkeychain/testclient.cpp cb1290a9584b627306a7bfdf1c02a8bbae503f5f
F ext/qtkeychain/translations/qtkeychain_de.ts 0a70c8205c066c30ed8172f0670942de1fc5eede
F ext/qtkeychain/translations/qtkeychain_ro.ts f16939382fd1a047b0692426bc82847347f14b32
F fuel.pro 2de14a4a6bd3e5af9d9e7c78f870453fedb38577
F fuel.pro d2d1fd2b3a9169a95e25235e07c7fa8f098a8c40
F intl/convert.bat 357d461ee8c6a7be6d2f60ac77c3232678ffb513 x
F intl/convert.sh ac6edc8d99b575601cf9c6b85b18c9e25875b6e0 x
F intl/convert.sh 2ca2179ff53e727f241925b75e19182607883c45 x
F intl/de_DE.ts e2faceab920ac60c97bbc6fba038e261d51fc741
F intl/el_GR.ts 1b805ee57309d02059d9e3e4cb49d945f9d9ac82
F intl/en_US.ts 7917816efedf35d5f4f798d18896d7aa0cb3c71b
@ -51,8 +29,6 @@ F intl/nl_NL.ts ff9b6ae9da5b6ffacc74fc1075a14ad80ebc0429
F intl/pt_PT.ts f93bcc3df5447ab1d85407e1dec4cd68c03d2245
F intl/ru_RU.ts 74189b3ee2b30b0b47b2db5bd7c9935db84947fc
F intl/update.sh 39d4561630ba6681bb27e7beadc225a31469728f x
F rsrc/docs/Licenses.txt 4021c1b126d55c1630ae2b43a8b805f99e39a357
F rsrc/docs/Translators.txt caf04efd7391546adda7da73679156e3ff5d5fcd
F rsrc/fuel.desktop 43145556bc61f5a91b497c38a16aec44af271d29
F rsrc/fuel.rc 8e9ac966f283102c11a77cd7f936cdc09e09bd79
F rsrc/icons/Address\sBook-01.png ef2cec80ea5a559b72e8be4a344a1869fe69cbd8
@ -210,57 +186,37 @@ F rsrc/icons/Zoom-01.png 67ca532922e9166325c5c75fce1ca3fbb0d2b6a6
F rsrc/icons/fuel.icns 81e535004b62db801a02f3e15d0a33afc9d4070b
F rsrc/icons/fuel.ico eb529ab3332a17b9302ef3e851db5b9ebce2a038
F rsrc/icons/fuel.png 40daf53b7f6bdcdd0d6aa5ef433d078ec5ea4342
F rsrc/resources.qrc 21ae6205e27ac989001eb0edc075d7e405b992c8
F src/AboutDialog.cpp fc9e3ba03aa6cb145ace610d9b38a2de157551ba
F src/AboutDialog.h 269f3a0589067c08f19b542e4576b0ef58bc6ec5
F rsrc/resources.qrc 3dee01bfbf8b9ec67a04b9259f4fd358f33356b7
F src/BrowserWidget.cpp 8b8f545cdff4a4188edc698a1b4777f5df46f056
F src/BrowserWidget.h 764d66aa9a93b890298bd0301097739cb4e16597
F src/CloneDialog.cpp c341622b01d493387d6e4928018b3392d92471e8
F src/CloneDialog.h 8813d91f893eb3eb86a4ea5e50f9a53a0ea07047
F src/CommitDialog.cpp 3d25ae2aa8af0ab417736a3f2d7f95a8dcb7480a
F src/CommitDialog.h 921bf27c0c538ab9e9d6bdc750064337d346270b
F src/CloneDialog.cpp 812ef7d361c16da21540b7047c9d4d5e74f18539
F src/CloneDialog.h e9f0fc8e5cc5ea2e7c43d6e77b5c4a9cc850b59e
F src/CommitDialog.cpp 5300522ac11bc1096a11a6ce22f8c1665d4afc05
F src/CommitDialog.h f1ee8db92103164e7db55a8407ccdcff24571b72
F src/CustomWebView.cpp b7dd0c41977c2cba005df07ed8967ba6f58d07d9
F src/CustomWebView.h fbc8ee55812d1acb3c3b2bc31be7533e8a112822
F src/FileActionDialog.cpp fcaebf9986f789b3440d5390b3458ad5f86fe0c8
F src/FileActionDialog.h 15db1650b3a13d70bc338371e4c033c66e3b79ce
F src/FileTableView.cpp 5ddf8c391c9a3ac449ec61fb1db837b577afeec2
F src/FileTableView.h 03e56d87c2d46411b9762b87f4d301619aaf18df
F src/Fossil.cpp e3451ddd8f19f1b6f2d446d9390b336e493da197
F src/Fossil.h 7acbd4a9d43f6a11c183dbffd73b71d54a4c5108
F src/FslSettingsDialog.cpp e00907d493fba469e48a008aecda88426350b5ac
F src/FslSettingsDialog.h dfe2a61884a55a74cbb9206b6f6b482b979725e7
F src/LoggedProcess.cpp 2a1e5c94bc1e57c8984563e66c210e43a14dc60c
F src/LoggedProcess.h 85df7c635c807a5a0e8c4763f17a0752aaff7261
F src/MainWindow.cpp 48ed62679d02f918479cd1610309443cd15d57ae
F src/MainWindow.h f4cffbe4d360d30aa2eeaa25fc6d50d0a39c617f
F src/RemoteDialog.cpp 8540cc5e2e41c4127ed8a028d84691604fa6ecac
F src/RemoteDialog.h 5e0438c2bd7c79b1bb44bfbd58c2181b544a9e5d
F src/RevisionDialog.cpp e58c4f8a704f00addebb15d521b76620fdafda79
F src/RevisionDialog.h b718c3009342eaabad39c8a11a253a4e4fef7a73
F src/SearchBox.cpp d4209c575baa9933e1ce5ed376e785b289a145ba
F src/SearchBox.h 0c78d3a68136dab3e0e71b83ae36f22bd2688ab2
F src/Settings.cpp 258d3f466f6a125ce2b8519d6d57a312cbc44a3f
F src/Settings.h 0a10b0b83fe804bdc7dac58eed06b5b6ee422055
F src/SettingsDialog.cpp fa0c70eaf0fa7edb15de302d041cdb552fe523d5
F src/SettingsDialog.h 5eb3ae2cbb00ab5544e1889860f5376f69fe47cd
F src/Utils.cpp cfadf3ee981f5ead8635c395610421f8e04a9a42
F src/Utils.h c6341ee49a8fc35f215facb196d70bf9b1f2fc0f
F src/Workspace.cpp c46aeb616712e42dcee72774a572af3a9803dbf1
F src/Workspace.h 54eef32658b13a34fe78ae26887420e8ff358eaa
F src/main.cpp d8c65ea5e54102e4989fef9fd8cfd4f13ef8a8f0
F src/MainWindow.cpp 96c1c733e719774038f8f4e4bb93194e358caa40
F src/MainWindow.h 77038e9c9fe8a64a1c2dfb8d4c2be7558ab5f372
F src/SettingsDialog.cpp 8fe0aacdca6694fe6711ec2b5ff4e54c7b426769
F src/SettingsDialog.h 4e2790f581e991c744ae9f86580f1972b8c7ff43
F src/Utils.cpp 9aff456712e4276b49083426301b3b96d3819c77
F src/Utils.h c546e478a1225a28c99cd4c30f70cf9be9804a2a
F src/main.cpp e1217b2331f1b0fd30756fc80a72f9676f09cf6b
F tools/git-push.sh 62cc58434cae5b7bcd6bd9d4cce8b08739f31cd7 x
F tools/pack.sh d7f38a498c4e9327fecd6a6e5ac27be270d43008 x
F ui/AboutDialog.ui 77704a7422a59ccdddbdf00979bd20a861d9ee5a
F ui/BrowserWidget.ui 994ad9ea0e9f5815d6b1a27acc2f6f39164c507f
F ui/BrowserWidget.ui 5ad98b13773afadb20a1a2c22148aaebe5dbd95d
F ui/CloneDialog.ui 4886e7d4f258ea8b852b5eefc860396e35145712
F ui/CommitDialog.ui 1e5dafa742e9ae07ec937bcda8cda3297ddc6199
F ui/CommitDialog.ui 6200f6cabdcf40a20812e811be28e0793f82516f
F ui/FileActionDialog.ui 89bb4dc2d0b8adcd41adcb11ec65f2028a09a12d
F ui/FslSettingsDialog.ui eb3d4cb764cab90b01e82922237d8c42d6ce1749
F ui/MainWindow.ui e2a18caa7482b3ee0dff477592cdc9574b35fe4f
F ui/RemoteDialog.ui 95a4750d972ed8c49bb10b95db91ff16cfe2dd0b
F ui/RevisionDialog.ui 27c3b98c665fec014a50cbf3352c0627f75e68cd
F ui/SettingsDialog.ui 2e1b6ce7a49100088c5649292c1319e62e0302e1
P cb27c4e2a0777b5c3fa64a07d19cd6b89e05c76f
R 19ead9c938bef0606914a30fe37378b3
F ui/MainWindow.ui 8677f5c8bca5bf7561d5f64bfdd0cef5157c6ac7
F ui/SettingsDialog.ui 2b7c2870e0054b0f4106f495d85d02c0b814df8b
P f3d5c35a93cf7285b489307240a6b75fbc8cb3b8
R d1cdbc42fc1a9f327c9de335a7e9bf81
U kostas
Z 6b9bc678ab29fb68e3f8be6bb65cb34f
Z 7390102f93cb735aad85da46b9b95e70

View File

@ -1 +1 @@
7988e53166771ea71d916a1ab714eb671d07dea8
2c6269f8f1b5cc9334488c2db77672deab813e1a

View File

@ -1,28 +0,0 @@
Icon Theme by Deleket - Jojo Mendoza
Available under the CC Attribution Noncommercial No Derivative 3.0 License
---------------------------------------
QtKeychain
https://github.com/frankosterfeld/qtkeychain
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------

View File

@ -1,10 +0,0 @@
stayawake: de_DE
djnavas: es_ES
Fringale: fr_FR
mouse166: ru_RU
emansije: pt_PT
maxxlupi: it_IT
Zangune: it_IT
Fly Man: nl_NL
Rick Van Lieshout: nl_NL
ardiefox: ko_KR

View File

@ -4,40 +4,37 @@
<file>icons/Adobe Illustrator CS3 Document-01.png</file>
<file>icons/Adobe PDF Document-01.png</file>
<file>icons/Adobe Photoshop CS3 Document-01.png</file>
<file alias="icon-application">icons/Battery-01.png</file>
<file>icons/Battery-01.png</file>
<file>icons/Binoculars-01.png</file>
<file alias="icon-item-tag">icons/Book-01.png</file>
<file>icons/Book-01.png</file>
<file>icons/Briefcase-01.png</file>
<file alias="icon-item-added">icons/Button Add-01.png</file>
<file>icons/Button Add-01.png</file>
<file>icons/Button Blank Blue-01.png</file>
<file alias="icon-item-unknown">icons/Button Blank Gray-01.png</file>
<file alias="icon-item-unchanged">icons/Button Blank Green-01.png</file>
<file alias="icon-item-conflicted">icons/Button Blank Red-01.png</file>
<file alias="icon-item-edited">icons/Button Blank Yellow-01.png</file>
<file>icons/Button Blank Gray-01.png</file>
<file>icons/Button Blank Green-01.png</file>
<file>icons/Button Blank Red-01.png</file>
<file>icons/Button Blank Yellow-01.png</file>
<file>icons/Button Cancel-01.png</file>
<file alias="icon-item-deleted">icons/Button Close-01.png</file>
<file alias="icon-action-tag-delete">icons/Button Close-01.png</file>
<file alias="icon-action-stop">icons/Button Close-01.png</file>
<file>icons/Button Close-01.png</file>
<file>icons/Button Delete-01.png</file>
<file alias="icon-action-pull">icons/Button Download-01.png</file>
<file>icons/Button Download-01.png</file>
<file>icons/Button Favorite-01.png</file>
<file>icons/Button Forward-01.png</file>
<file alias="icon-item-missing">icons/Button Help-01.png</file>
<file>icons/Button Help-01.png</file>
<file>icons/Button Info-01.png</file>
<file>icons/Button Log Off-01.png</file>
<file alias="icon-action-next">icons/Button Next-01.png</file>
<file>icons/Button Next-01.png</file>
<file>icons/Button Pause-01.png</file>
<file alias="icon-action-update">icons/Button Play-01.png</file>
<file alias="icon-action-previous">icons/Button Previous-01.png</file>
<file alias="icon-action-refresh">icons/Button Refresh-01.png</file>
<file alias="icon-action-undo">icons/Button Reload-01.png</file>
<file alias="icon-item-renamed">icons/Button Reload-01.png</file>
<file>icons/Button Play-01.png</file>
<file>icons/Button Previous-01.png</file>
<file>icons/Button Refresh-01.png</file>
<file>icons/Button Reload-01.png</file>
<file>icons/Button Reminder-01.png</file>
<file alias="icon-action-revert">icons/Button Rewind-01.png</file>
<file>icons/Button Rewind-01.png</file>
<file>icons/Button Talk Balloon-01.png</file>
<file alias="icon-action-quit">icons/Button Turn Off-01.png</file>
<file>icons/Button Turn Off-01.png</file>
<file>icons/Button Turn On-01.png</file>
<file alias="icon-action-push">icons/Button Upload-01.png</file>
<file>icons/Button Upload-01.png</file>
<file>icons/Button Warning-01.png</file>
<file>icons/Calculator-01.png</file>
<file>icons/Calendar Blue-01.png</file>
@ -45,28 +42,28 @@
<file>icons/Calendar Red-01.png</file>
<file>icons/Clipboard-01.png</file>
<file>icons/Clipboard Paste-01.png</file>
<file alias="icon-action-timeline">icons/Clock-01.png</file>
<file>icons/Clock-01.png</file>
<file>icons/Coin-01.png</file>
<file>icons/Compressed File RAR-01.png</file>
<file>icons/Compressed File SIT-01.png</file>
<file>icons/Compressed File Zip-01.png</file>
<file>icons/Computer Monitor-01.png</file>
<file>icons/Computer Network-01.png</file>
<file alias="icon-item-file">icons/Document-01.png</file>
<file>icons/Document-01.png</file>
<file>icons/Document Attach-01.png</file>
<file alias="icon-action-repo-new">icons/Document Blank-01.png</file>
<file>icons/Document Blank-01.png</file>
<file>icons/Document Chart-01.png</file>
<file alias="icon-item-diff">icons/Document Copy-01.png</file>
<file alias="icon-action-merge">icons/Document Flow Chart-01.png</file>
<file>icons/Document Copy-01.png</file>
<file>icons/Document Flow Chart-01.png</file>
<file>icons/Document Gant Chart-01.png</file>
<file>icons/Document Help-01.png</file>
<file>icons/Document Line Chart-01.png</file>
<file>icons/Document Microsoft Excel-01.png</file>
<file>icons/Document Microsoft PowerPoint-01.png</file>
<file>icons/Document Microsoft Word-01.png</file>
<file alias="icon-item-branch">icons/Document Organization Chart-01.png</file>
<file>icons/Document Organization Chart-01.png</file>
<file>icons/Document Preview-01.png</file>
<file alias="icon-item-revert">icons/Document-Revert-icon.png</file>
<file>icons/Document-Revert-icon.png</file>
<file>icons/Document Text-01.png</file>
<file>icons/Edit Document-01.png</file>
<file>icons/Email-01.png</file>
@ -81,33 +78,32 @@
<file>icons/File Audio MP3-01.png</file>
<file>icons/File Audio WAV-01.png</file>
<file>icons/File Audio WMA-01.png</file>
<file alias="icon-item-delete">icons/File Delete-01.png</file>
<file alias="icon-item-history">icons/File History-01.png</file>
<file alias="icon-item-add">icons/File New-01.png</file>
<file alias="icon-item-rename">icons/File Open-01.png</file>
<file>icons/File Delete-01.png</file>
<file>icons/File History-01.png</file>
<file>icons/File New-01.png</file>
<file>icons/File Open-01.png</file>
<file>icons/File Video 3GP-01.png</file>
<file>icons/File Video-01.png</file>
<file>icons/File Video AVI-01.png</file>
<file>icons/File Video MOV-01.png</file>
<file>icons/File Video MPEG-01.png</file>
<file>icons/File Video WMV-01.png</file>
<file alias="icon-item-folder">icons/Folder-01.png</file>
<file alias="icon-action-stash-new">icons/Folder Add-01.png</file>
<file alias="icon-action-stash-apply">icons/Folder Compressed-01.png</file>
<file alias="icon-action-stash-delete">icons/Folder Delete-01.png</file>
<file alias="icon-action-stash-diff">icons/Folder Explorer-01.png</file>
<file alias="icon-action-folder-explore">icons/Folder Explorer-01.png</file>
<file>icons/Folder-01.png</file>
<file>icons/Folder Add-01.png</file>
<file>icons/Folder Compressed-01.png</file>
<file>icons/Folder Delete-01.png</file>
<file>icons/Folder Explorer-01.png</file>
<file>icons/Folder Generic Blue-01.png</file>
<file alias="icon-item-folder-unchanged">icons/Folder Generic Green-01.png</file>
<file alias="icon-item-folder-modified">icons/Folder Generic Red-01.png</file>
<file alias="icon-item-folder-unknown">icons/Folder Generic Silver-01.png</file>
<file alias="icon-action-folder-rename">icons/Folder Open-01.png</file>
<file>icons/Folder Generic Green-01.png</file>
<file>icons/Folder Generic Red-01.png</file>
<file>icons/Folder Generic Silver-01.png</file>
<file>icons/Folder Open-01.png</file>
<file>icons/Folder RAR-01.png</file>
<file>icons/Games-01.png</file>
<file alias="icon-action-settings">icons/Gear-01.png</file>
<file>icons/Gear-01.png</file>
<file>icons/Highlighter Blue-01.png</file>
<file>icons/Highlighter Green-01.png</file>
<file alias="icon-action-tag-new">icons/Highlighter Yellow-01.png</file>
<file>icons/Highlighter Yellow-01.png</file>
<file>icons/Image BMP-01.png</file>
<file>icons/Image GIF-01.png</file>
<file>icons/Image JPEG-01.png</file>
@ -115,21 +111,21 @@
<file>icons/Image TIFF-01.png</file>
<file>icons/Lock Lock-01.png</file>
<file>icons/Lock Unlock-01.png</file>
<file alias="icon-action-repo-open">icons/My Documents-01.png</file>
<file>icons/My Documents-01.png</file>
<file>icons/My Ebooks-01.png</file>
<file>icons/My Music-01.png</file>
<file>icons/My Pictures.png</file>
<file>icons/My Videos-01.png</file>
<file alias="icon-action-repo-clone">icons/My Websites-01.png</file>
<file>icons/My Websites-01.png</file>
<file>icons/Network Firewall-01.png</file>
<file alias="icon-webview">icons/Network MAC-01.png</file>
<file alias="icon-item-remote" >icons/Network PC-01.png</file>
<file>icons/Network MAC-01.png</file>
<file>icons/Network PC-01.png</file>
<file>icons/Network Refresh-01.png</file>
<file>icons/Pen Blue-01.png</file>
<file>icons/Pen Green-01.png</file>
<file>icons/Pen Red-01.png</file>
<file alias="icon-action-commit">icons/Save-01.png</file>
<file alias="icon-clear-log">icons/Text Edit.png</file>
<file>icons/Save-01.png</file>
<file>icons/Text Edit.png</file>
<file>icons/USB-01.png</file>
<file>icons/User Administrator Blue-01.png</file>
<file>icons/User Administrator Green-01.png</file>
@ -167,8 +163,4 @@
<file>intl/nl_NL.qm</file>
<file>intl/ko_KR.qm</file>
</qresource>
<qresource prefix="/docs">
<file>docs/Translators.txt</file>
<file>docs/Licenses.txt</file>
</qresource>
</RCC>

View File

@ -1,41 +0,0 @@
#include "AboutDialog.h"
#include "ui_AboutDialog.h"
#include <QFile>
AboutDialog::AboutDialog(QWidget *parent, const QString &fossilVersion) :
QDialog(parent),
ui(new Ui::AboutDialog)
{
ui->setupUi(this);
QString banner(QCoreApplication::applicationName() + " " + QCoreApplication::applicationVersion());
ui->lblBanner->setText(banner + "\n" + ui->lblBanner->text());
ui->lblQtVersion->setText(tr("QT version %0").arg(QT_VERSION_STR));
if(!fossilVersion.isEmpty())
ui->lblFossilVersion->setText(tr("Fossil version %0").arg(fossilVersion));
QString additional;
QFile ftrans(":/docs/docs/Translators.txt");
if(ftrans.open(QFile::ReadOnly))
{
additional.append(tr("Translations with the help of:")+"\n");
additional.append(ftrans.readAll());
additional.append("\n\n");
ftrans.close();
}
QFile flicenses(":/docs/docs/Licenses.txt");
if(flicenses.open(QFile::ReadOnly))
{
additional.append(tr("This sofware uses the following open-source libraries and assets:")+"\n");
additional.append(flicenses.readAll());
flicenses.close();
}
ui->txtAdditional->setText(additional);
}
AboutDialog::~AboutDialog()
{
delete ui;
}

View File

@ -1,22 +0,0 @@
#ifndef ABOUTDIALOG_H
#define ABOUTDIALOG_H
#include <QDialog>
namespace Ui {
class AboutDialog;
}
class AboutDialog : public QDialog
{
Q_OBJECT
public:
explicit AboutDialog(QWidget *parent, const QString &fossilVersion);
~AboutDialog();
private:
Ui::AboutDialog *ui;
};
#endif // ABOUTDIALOG_H

View File

@ -5,7 +5,6 @@
#include <QMessageBox>
#include <QClipboard>
#include <QUrl>
#include "Utils.h"
//-----------------------------------------------------------------------------
CloneDialog::CloneDialog(QWidget *parent) :
@ -40,7 +39,7 @@ bool CloneDialog::run(QWidget *parent, QUrl &url, QString &repository, QUrl &url
dlg.ui->linePassword->setText(nurl.password());
nurl.setUserName("");
nurl.setPassword("");
dlg.ui->lineURL->setText(UrlToStringNoCredentials(nurl));
dlg.ui->lineURL->setText(nurl.toString());
}
}
@ -91,11 +90,6 @@ void CloneDialog::GetRepositoryPath(QString &pathResult)
filter,
&filter,
QFileDialog::DontConfirmOverwrite);
// Ensure that it ends in the required extension (On GTK, Qt doesn't seem to add it automatically)
QFileInfo fi(pathResult);
if(fi.suffix().toLower() != ("." FOSSIL_EXT))
pathResult += "." FOSSIL_EXT;
}
//-----------------------------------------------------------------------------

View File

@ -3,6 +3,10 @@
#include <QDialog>
#define FOSSIL_CHECKOUT1 "_FOSSIL_"
#define FOSSIL_CHECKOUT2 ".fslckout"
#define FOSSIL_EXT "fossil"
namespace Ui {
class CloneDialog;
}

View File

@ -4,7 +4,7 @@
#include "ui_CommitDialog.h"
#include "MainWindow.h" // Ugly. I know.
CommitDialog::CommitDialog(QWidget *parent, const QString &title, QStringList &files, const QStringList *history, bool stashMode) :
CommitDialog::CommitDialog(QWidget *parent, QString title, QStringList &files, const QStringList *history, bool singleLineEntry, const QString *checkBoxText, bool *checkBoxValue) :
QDialog(parent, Qt::Sheet),
ui(new Ui::CommitDialog)
{
@ -15,13 +15,16 @@ CommitDialog::CommitDialog(QWidget *parent, const QString &title, QStringList &f
setWindowTitle(title);
// Activate the appropriate control based on mode
ui->plainTextEdit->setVisible(!stashMode);
ui->lineEdit->setVisible(stashMode);
ui->plainTextEdit->setVisible(!singleLineEntry);
ui->lineEdit->setVisible(singleLineEntry);
// Activate the checkbox if we have some text
ui->chkRevertFiles->setVisible(stashMode);
ui->widgetBranchOptions->setVisible(!stashMode);
ui->checkBox->setVisible(checkBoxText!=0);
if(checkBoxText && checkBoxValue)
{
ui->checkBox->setText(*checkBoxText);
ui->checkBox->setCheckState(*checkBoxValue ? Qt::Checked : Qt::Unchecked);
}
// Activate the combo if we have history
ui->comboBox->setVisible(history!=0);
@ -74,13 +77,17 @@ CommitDialog::~CommitDialog()
}
//------------------------------------------------------------------------------
bool CommitDialog::runCommit(QWidget* parent, QStringList& files, QString& commitMsg, const QStringList& commitMsgHistory, QString &branchName, bool &privateBranch)
bool CommitDialog::run(QWidget *parent, QString title, QStringList &files, QString &commitMsg, const QStringList *history, bool singleLineEntry, const QString *checkBoxText, bool *checkBoxValue)
{
CommitDialog dlg(parent, tr("Commit Changes"), files, &commitMsgHistory, false);
CommitDialog dlg(parent, title, files, history, singleLineEntry, checkBoxText, checkBoxValue);
int res = dlg.exec();
if(singleLineEntry)
commitMsg = dlg.ui->lineEdit->text();
else
commitMsg = dlg.ui->plainTextEdit->toPlainText();
if(res!=QDialog::Accepted)
return false;
@ -93,40 +100,15 @@ bool CommitDialog::runCommit(QWidget* parent, QStringList& files, QString& commi
files.append(si->text());
}
branchName.clear();
if(dlg.ui->chkNewBranch->isChecked())
if(checkBoxText)
{
branchName = dlg.ui->lineBranchName->text().trimmed();
privateBranch = dlg.ui->chkPrivateBranch->isChecked();
Q_ASSERT(checkBoxValue);
*checkBoxValue = dlg.ui->checkBox->checkState() == Qt::Checked;
}
return true;
}
//------------------------------------------------------------------------------
bool CommitDialog::runStashNew(QWidget* parent, QStringList& stashedFiles, QString& stashName, bool& revertFiles)
{
CommitDialog dlg(parent, tr("Stash Changes"), stashedFiles, NULL, true);
int res = dlg.exec();
stashName = dlg.ui->lineEdit->text();
if(res!=QDialog::Accepted)
return false;
stashedFiles.clear();
for(int i=0; i<dlg.itemModel.rowCount(); ++i)
{
QStandardItem *si = dlg.itemModel.item(i);
if(si->checkState()!=Qt::Checked)
continue;
stashedFiles.append(si->text());
}
revertFiles = dlg.ui->chkRevertFiles->checkState() == Qt::Checked;
return true;
}
//------------------------------------------------------------------------------
void CommitDialog::on_comboBox_activated(int index)
{
@ -160,11 +142,3 @@ void CommitDialog::on_listView_clicked(const QModelIndex &)
ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(num_selected>0);
}
//------------------------------------------------------------------------------
void CommitDialog::on_chkNewBranch_toggled(bool checked)
{
ui->lblPrivateBranch->setEnabled(checked);
ui->chkPrivateBranch->setEnabled(checked);
ui->lineBranchName->setEnabled(checked);
}

View File

@ -13,17 +13,15 @@ class CommitDialog : public QDialog
Q_OBJECT
public:
explicit CommitDialog(QWidget *parent, const QString &title, QStringList &files, const QStringList *history, bool stashMode);
explicit CommitDialog(QWidget *parent, QString title, QStringList &files, const QStringList *history=0, bool singleLineEntry=false, const QString *checkBoxText=0, bool *checkBoxValue=0);
~CommitDialog();
static bool runStashNew(QWidget* parent, QStringList& stashedFiles, QString& stashName, bool &revertFiles);
static bool runCommit(QWidget* parent, QStringList& files, QString& commitMsg, const QStringList &commitMsgHistory, QString& branchName, bool& privateBranch);
static bool run(QWidget *parent, QString title, QStringList &files, QString &commitMsg, const QStringList *history=0, bool singleLineEntry=false, const QString *checkBoxText=0, bool *checkBoxValue=0);
private slots:
void on_comboBox_activated(int index);
void on_listView_doubleClicked(const QModelIndex &index);
void on_listView_clicked(const QModelIndex &index);
void on_chkNewBranch_toggled(bool checked);
private:
Ui::CommitDialog *ui;

File diff suppressed because it is too large Load Diff

View File

@ -1,152 +0,0 @@
#ifndef FOSSIL_H
#define FOSSIL_H
class QStringList;
#include <QString>
#include <QStringList>
#include <QUrl>
#include "LoggedProcess.h"
#include "Utils.h"
typedef QMap<QString, QString> stashmap_t;
enum RunFlags
{
RUNFLAGS_NONE = 0<<0,
RUNFLAGS_SILENT_INPUT = 1<<0,
RUNFLAGS_SILENT_OUTPUT = 1<<1,
RUNFLAGS_SILENT_ALL = RUNFLAGS_SILENT_INPUT | RUNFLAGS_SILENT_OUTPUT,
RUNFLAGS_DETACHED = 1<<2,
RUNFLAGS_DEBUG = 1<<3,
};
enum RepoStatus
{
REPO_OK,
REPO_NOT_FOUND,
REPO_OLD_SCHEMA
};
class Fossil
{
public:
Fossil()
: operationAborted(false)
, uiCallback(0)
{
}
void Init(UICallback *callback)
{
uiCallback = callback;
fossilPath.clear();
workspacePath.clear();
}
bool runFossil(const QStringList &args, QStringList *output=0, int runFlags=RUNFLAGS_NONE);
bool runFossilRaw(const QStringList &args, QStringList *output, int *exitCode, int runFlags);
static bool isWorkspace(const QString &path);
RepoStatus getRepoStatus();
void setWorkspacePath(const QString &workspace)
{
workspacePath = workspace;
}
const QString &getWorkspacePath() const
{
return workspacePath;
}
const QString &getProjectName() const
{
return projectName;
}
const QString &getRepositoryFile() const
{
return repositoryFile;
}
void setRepositoryFile(const QString &filename)
{
repositoryFile = filename;
}
bool openRepository(const QString &repositoryPath, const QString& workspacePath);
bool newRepository(const QString &repositoryPath);
bool closeRepository();
bool pushRepository(const QUrl& url);
bool pullRepository(const QUrl& url);
bool cloneRepository(const QString &repository, const QUrl &url, const QUrl &proxyUrl);
bool undoRepository(QStringList& result, bool explainOnly);
bool updateRepository(QStringList& result, const QString& revision, bool explainOnly);
bool getFossilVersion(QString &version);
bool uiRunning() const;
bool startUI(const QString &httpPort);
void stopUI();
bool listFiles(QStringList &files);
bool status(QStringList& result);
bool diffFile(const QString &repoFile, bool graphical);
bool commitFiles(const QStringList &fileList, const QString &comment, const QString& newBranchName, bool isPrivateBranch);
bool addFiles(const QStringList& fileList);
bool removeFiles(const QStringList& fileList, bool deleteLocal);
bool revertFiles(const QStringList& fileList);
bool renameFile(const QString& beforePath, const QString& afterPath, bool renameLocal);
bool getFossilSettings(QStringList& result);
bool setFossilSetting(const QString &name, const QString &value, bool global);
bool setRemoteUrl(const QUrl& url);
bool getRemoteUrl(QUrl &url);
bool stashNew(const QStringList& fileList, const QString& name, bool revert);
bool stashList(stashmap_t &stashes);
bool stashApply(const QString& name);
bool stashDrop(const QString& name);
bool stashDiff(const QString& name);
void abortOperation() { operationAborted = true; }
bool tagList(QStringMap& tags);
bool tagNew(const QString& name, const QString& revision);
bool tagDelete(const QString& name, const QString& revision);
bool branchList(QStringList& branches, QStringList& activeBranches);
bool branchNew(const QString& name, const QString& revisionBasis, bool isPrivate=false);
bool branchMerge(QStringList& res, const QString& revision, bool integrate, bool force, bool testOnly);
const QString &getCurrentRevision() const { return currentRevision; }
const QStringList &getActiveTags() const { return activeTags; }
const QString &getUIHttpPort() const { return fossilUIPort; }
QString getUIHttpAddress() const;
void setExecutablePath(const QString &path) { fossilPath = path; }
private:
void log(const QString &text, bool isHTML=false)
{
if(uiCallback)
uiCallback->logText(text, isHTML);
}
QString getFossilPath();
bool operationAborted;
UICallback *uiCallback;
QString workspacePath;
QString fossilPath; // The value from the settings
QString repositoryFile;
QString projectName;
QString currentRevision;
QStringList activeTags;
LoggedProcess fossilUI;
QString fossilUIPort;
};
#endif // FOSSIL_H

View File

@ -1,70 +0,0 @@
#include "FslSettingsDialog.h"
#include "ui_FslSettingsDialog.h"
#include "Utils.h"
#include <QDir>
///////////////////////////////////////////////////////////////////////////////
FslSettingsDialog::FslSettingsDialog(QWidget *parent, Settings &_settings) :
QDialog(parent, Qt::Sheet),
ui(new Ui::FslSettingsDialog),
settings(&_settings)
{
ui->setupUi(this);
ui->lineUIPort->setText(settings->GetFossilValue(FOSSIL_SETTING_HTTP_PORT).toString());
// Global Settings
ui->lineGDiffCommand->setText(settings->GetFossilValue(FOSSIL_SETTING_GDIFF_CMD).toString());
ui->lineGMergeCommand->setText(settings->GetFossilValue(FOSSIL_SETTING_GMERGE_CMD).toString());
ui->lineProxy->setText(settings->GetFossilValue(FOSSIL_SETTING_PROXY_URL).toString());
// Repository Settings
ui->lineIgnore->setText(settings->GetFossilValue(FOSSIL_SETTING_IGNORE_GLOB).toString());
ui->lineIgnoreCRNL->setText(settings->GetFossilValue(FOSSIL_SETTING_CRNL_GLOB).toString());
}
//-----------------------------------------------------------------------------
FslSettingsDialog::~FslSettingsDialog()
{
delete ui;
}
//-----------------------------------------------------------------------------
bool FslSettingsDialog::run(QWidget *parent, Settings &settings)
{
FslSettingsDialog dlg(parent, settings);
return dlg.exec() == QDialog::Accepted;
}
//-----------------------------------------------------------------------------
void FslSettingsDialog::on_buttonBox_accepted()
{
settings->SetFossilValue(FOSSIL_SETTING_HTTP_PORT, ui->lineUIPort->text());
settings->SetFossilValue(FOSSIL_SETTING_GDIFF_CMD, ui->lineGDiffCommand->text());
settings->SetFossilValue(FOSSIL_SETTING_GMERGE_CMD, ui->lineGMergeCommand->text());
settings->SetFossilValue(FOSSIL_SETTING_PROXY_URL, ui->lineProxy->text());
settings->SetFossilValue(FOSSIL_SETTING_IGNORE_GLOB, ui->lineIgnore->text());
settings->SetFossilValue(FOSSIL_SETTING_CRNL_GLOB, ui->lineIgnoreCRNL->text());
settings->ApplyEnvironment();
}
//-----------------------------------------------------------------------------
void FslSettingsDialog::on_btnSelectFossilGDiff_clicked()
{
QString path = SelectExe(this, tr("Select Graphical Diff application"));
if(!path.isEmpty())
ui->lineGDiffCommand->setText(QDir::toNativeSeparators(path));
}
//-----------------------------------------------------------------------------
void FslSettingsDialog::on_btnSelectGMerge_clicked()
{
QString path = SelectExe(this, tr("Select Graphical Merge application"));
if(!path.isEmpty())
ui->lineGMergeCommand->setText(path);
}

View File

@ -1,33 +0,0 @@
#ifndef FSLSETTINGSDIALOG_H
#define FSLSETTINGSDIALOG_H
#include <QDialog>
#include "Settings.h"
namespace Ui {
class FslSettingsDialog;
}
class FslSettingsDialog : public QDialog
{
Q_OBJECT
public:
explicit FslSettingsDialog(QWidget *parent, Settings &_settings);
~FslSettingsDialog();
static bool run(QWidget *parent, Settings &_settings);
private slots:
void on_buttonBox_accepted();
void on_btnSelectFossilGDiff_clicked();
void on_btnSelectGMerge_clicked();
private:
Ui::FslSettingsDialog *ui;
Settings *settings;
};
#endif // FSLSETTINGSDIALOG_H

File diff suppressed because it is too large Load Diff

View File

@ -2,15 +2,114 @@
#define MAINWINDOW_H
#include <QMainWindow>
#include <QStandardItemModel>
#include <QStringList>
#include <QMap>
#include <QFileInfo>
#include <QDir>
#include <QProcess>
#include <QFileIconProvider>
#include "Settings.h"
#include "Workspace.h"
#include <QSet>
#include "SettingsDialog.h"
namespace Ui {
class MainWindow;
}
class QStringList;
//////////////////////////////////////////////////////////////////////////
// RepoFile
//////////////////////////////////////////////////////////////////////////
struct RepoFile
{
enum EntryType
{
TYPE_UNKNOWN = 1<<0,
TYPE_UNCHANGED = 1<<1,
TYPE_EDITTED = 1<<2,
TYPE_ADDED = 1<<3,
TYPE_DELETED = 1<<4,
TYPE_MISSING = 1<<5,
TYPE_RENAMED = 1<<6,
TYPE_CONFLICTED = 1<<7,
TYPE_MODIFIED = TYPE_EDITTED|TYPE_ADDED|TYPE_DELETED|TYPE_MISSING|TYPE_RENAMED|TYPE_CONFLICTED,
TYPE_REPO = TYPE_UNCHANGED|TYPE_MODIFIED,
TYPE_ALL = TYPE_UNKNOWN|TYPE_REPO
};
RepoFile(QFileInfo &info, EntryType type, const QString &repoPath)
{
FileInfo = info;
Type = type;
FilePath = getRelativeFilename(repoPath);
Path = FileInfo.absolutePath();
// Strip the workspace path from the path
Q_ASSERT(Path.indexOf(repoPath)==0);
Path = Path.mid(repoPath.length()+1);
}
bool isType(EntryType t) const
{
return Type == t;
}
void setType(EntryType t)
{
Type = t;
}
EntryType getType() const
{
return Type;
}
QFileInfo getFileInfo() const
{
return FileInfo;
}
bool isRepo() const
{
return Type == TYPE_UNCHANGED || Type == TYPE_EDITTED;
}
const QString &getFilePath() const
{
return FilePath;
}
QString getFilename() const
{
return FileInfo.fileName();
}
const QString &getPath() const
{
return Path;
}
QString getRelativeFilename(const QString &path)
{
QString abs_base_dir = QDir(path).absolutePath();
QString relative = FileInfo.absoluteFilePath();
int index = relative.indexOf(abs_base_dir);
if(index<0)
return QString("");
return relative.right(relative.length() - abs_base_dir.length()-1);
}
private:
QFileInfo FileInfo;
EntryType Type;
QString FilePath;
QString Path;
};
//////////////////////////////////////////////////////////////////////////
// MainWindow
//////////////////////////////////////////////////////////////////////////
@ -21,47 +120,67 @@ class MainWindow : public QMainWindow
public:
explicit MainWindow(Settings &_settings, QWidget *parent = 0, QString *workspacePath = 0);
~MainWindow();
bool diffFile(const QString& repoFile);
bool diffFile(QString repoFile);
void fullRefresh();
private:
typedef QSet<QString> stringset_t;
enum RunFlags
{
RUNFLAGS_NONE = 0<<0,
RUNFLAGS_SILENT_INPUT = 1<<0,
RUNFLAGS_SILENT_OUTPUT = 1<<1,
RUNFLAGS_SILENT_ALL = RUNFLAGS_SILENT_INPUT | RUNFLAGS_SILENT_OUTPUT,
RUNFLAGS_DETACHED = 1<<2
};
private:
bool refresh();
void scanWorkspace();
bool runFossil(const QStringList &args, QStringList *output=0, int runFlags=RUNFLAGS_NONE);
bool runFossilRaw(const QStringList &args, QStringList *output=0, int *exitCode=0, int runFlags=RUNFLAGS_NONE);
void applySettings();
void updateSettings();
void updateRevision(const QString& revision);
const QString &getCurrentWorkspace();
void setCurrentWorkspace(const QString &workspace);
void log(const QString &text, bool isHTML=false);
void setStatus(const QString &text);
bool uiRunning() const;
void getSelectionFilenames(QStringList &filenames, int includeMask=WorkspaceFile::TYPE_ALL, bool allIfEmpty=false);
void getFileViewSelection(QStringList &filenames, int includeMask=WorkspaceFile::TYPE_ALL, bool allIfEmpty=false);
void getDirViewSelection(QStringList &filenames, int includeMask=WorkspaceFile::TYPE_ALL, bool allIfEmpty=false);
void getSelectionStashes(QStringList &stashNames);
bool uiRunning() const { return fossilUI.state() == QProcess::Running; }
void getSelectionFilenames(QStringList &filenames, int includeMask=RepoFile::TYPE_ALL, bool allIfEmpty=false);
void getFileViewSelection(QStringList &filenames, int includeMask=RepoFile::TYPE_ALL, bool allIfEmpty=false);
void getDirViewSelection(QStringList &filenames, int includeMask=RepoFile::TYPE_ALL, bool allIfEmpty=false);
void getStashViewSelection(QStringList &stashNames, bool allIfEmpty=false);
void getSelectionPaths(stringset_t &paths);
void getSelectionRemotes(QStringList& remoteUrls);
void getAllFilenames(QStringList &filenames, int includeMask=WorkspaceFile::TYPE_ALL);
void getAllFilenames(QStringList &filenames, int includeMask=RepoFile::TYPE_ALL);
bool startUI();
void stopUI();
void enableActions(bool on);
void addWorkspaceHistory(const QString &dir);
void addWorkspace(const QString &dir);
void rebuildRecent();
bool openWorkspace(const QString &path);
void loadFossilSettings();
void updateWorkspaceView();
QString getFossilPath();
QString getFossilHttpAddress();
bool scanDirectory(QFileInfoList &entries, const QString& dirPath, const QString &baseDir, const QString ignoreSpec, const bool& abort);
void updateDirView();
void updateFileView();
void updateStashView();
void selectRootDir();
void mergeRevision(const QString& defaultRevision);
void updateCustomActions();
void invokeCustomAction(int actionId);
void fossilBrowse(const QString &fossilUrl);
void dragEnterEvent(class QDragEnterEvent *event);
void dropEvent(class QDropEvent *event);
void setBusy(bool busy);
virtual QMenu *createPopupMenu();
const QIcon& getCachedIcon(const char *name);
const QIcon& getCachedFileIcon(const QFileInfo &finfo);
const QIcon& getInternalIcon(const char *name);
enum RepoStatus
{
REPO_OK,
REPO_NOT_FOUND,
REPO_OLD_SCHEMA
};
RepoStatus getRepoStatus();
enum ViewMode
{
@ -73,12 +192,9 @@ private slots:
// Manual slots.
// Use a different naming scheme to prevent warnings from Qt's automatic signaling
void onOpenRecent();
void onWorkspaceTreeViewSelectionChanged(const class QItemSelection &selected, const class QItemSelection &deselected);
void onTreeViewSelectionChanged(const class QItemSelection &selected, const class QItemSelection &deselected);
void onFileViewDragOut();
void onAbort();
void onSearchBoxTextChanged(const QString &text);
void onSearch();
void onCustomActionTriggered();
// Designer slots
void on_actionRefresh_triggered();
@ -88,13 +204,11 @@ private slots:
void on_actionTimeline_triggered();
void on_actionHistory_triggered();
void on_actionClearLog_triggered();
void on_fileTableView_doubleClicked(const QModelIndex &index);
void on_workspaceTreeView_doubleClicked(const QModelIndex &index);
void on_tableView_doubleClicked(const QModelIndex &index);
void on_treeView_doubleClicked(const QModelIndex &index);
void on_actionOpenFile_triggered();
void on_actionPush_triggered();
void on_actionPull_triggered();
void on_actionPushRemote_triggered();
void on_actionPullRemote_triggered();
void on_actionCommit_triggered();
void on_actionAdd_triggered();
void on_actionDelete_triggered();
@ -105,62 +219,26 @@ private slots:
void on_actionAbout_triggered();
void on_actionUpdate_triggered();
void on_actionSettings_triggered();
void on_actionFossilSettings_triggered();
void on_actionViewUnchanged_triggered();
void on_actionViewModified_triggered();
void on_actionViewUnknown_triggered();
void on_actionViewIgnored_triggered();
void on_actionViewAll_triggered();
void on_actionViewModifedOnly_triggered();
void on_actionViewAsList_triggered();
void on_actionViewAsFolders_triggered();
void on_actionOpenFolder_triggered();
void on_actionRenameFolder_triggered();
void on_actionNewRepository_triggered();
void on_actionOpenRepository_triggered();
void on_actionCloseRepository_triggered();
void on_actionCloneRepository_triggered();
void on_actionCreateStash_triggered();
void on_actionViewStash_triggered();
void on_actionNewStash_triggered();
void on_actionApplyStash_triggered();
void on_actionDeleteStash_triggered();
void on_actionDiffStash_triggered();
void on_textBrowser_customContextMenuRequested(const QPoint &pos);
void on_fileTableView_customContextMenuRequested(const QPoint &pos);
void on_workspaceTreeView_customContextMenuRequested(const QPoint &pos);
void on_actionCreateTag_triggered();
void on_actionDeleteTag_triggered();
void on_actionCreateBranch_triggered();
void on_actionMergeBranch_triggered();
void on_actionEditRemote_triggered();
void on_actionSetDefaultRemote_triggered();
void on_actionAddRemote_triggered();
void on_actionDeleteRemote_triggered();
void on_tableView_customContextMenuRequested(const QPoint &pos);
private:
class MainWinUICallback : public UICallback
{
public:
MainWinUICallback() : mainWindow(0)
{}
void init(class MainWindow *mainWindow)
{
this->mainWindow = mainWindow;
}
virtual void logText(const QString& text, bool isHTML);
virtual void beginProcess(const QString& text);
virtual void updateProcess(const QString& text);
virtual void endProcess();
virtual QMessageBox::StandardButton Query(const QString &title, const QString &query, QMessageBox::StandardButtons buttons);
private:
class MainWindow *mainWindow;
};
friend class MainWinUICallback;
enum
{
MAX_RECENT=5
@ -171,39 +249,30 @@ private:
Ui::MainWindow *ui;
QFileIconProvider iconProvider;
icon_map_t iconCache;
QStandardItemModel repoFileModel;
QStandardItemModel repoDirModel;
QStandardItemModel repoStashModel;
QProcess fossilUI;
class QAction *recentWorkspaceActs[MAX_RECENT];
class QAction *customActions[MAX_CUSTOM_ACTIONS];
class QAction *fileActionSeparator;
class QAction *workspaceActionSeparator;
class QProgressBar *progressBar;
class QLabel *lblTags;
class QShortcut *abortShortcut;
class SearchBox *searchBox;
class QShortcut *searchShortcut;
QMenu *menuWorkspace;
QMenu *menuStashes;
QMenu *menuTags;
QMenu *menuBranches;
QMenu *menuRemotes;
bool operationAborted;
stringset_t selectedDirs; // The directory selected in the tree
QStringList selectedTags;
QStringList selectedBranches;
QStringList versionList;
Workspace workspace;
Workspace & getWorkspace() { return workspace; }
Fossil & fossil() { return workspace.fossil(); }
const Fossil & fossil() const { return workspace.fossil(); }
bool abortOperation;
Settings &settings;
QString projectName;
QString repositoryFile;
QStringList workspaceHistory;
MainWinUICallback uiCallback;
QString currentWorkspace;
ViewMode viewMode;
stringset_t selectedDirs; // The directory selected in the tree
// Repository State
typedef QList<RepoFile*> filelist_t;
typedef QMap<QString, RepoFile*> filemap_t;
typedef QMap<QString, QString> stashmap_t;
filemap_t workspaceFiles;
stringset_t pathSet;
stashmap_t stashMap;
};
#endif // MAINWINDOW_H

View File

@ -1,95 +0,0 @@
#include "RemoteDialog.h"
#include "ui_RemoteDialog.h"
#include <QFileDialog>
#include <QDir>
#include <QMessageBox>
#include <QClipboard>
#include <QUrl>
#include "Utils.h"
//-----------------------------------------------------------------------------
RemoteDialog::RemoteDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::RemoteDialog)
{
ui->setupUi(this);
}
//-----------------------------------------------------------------------------
RemoteDialog::~RemoteDialog()
{
delete ui;
}
//-----------------------------------------------------------------------------
bool RemoteDialog::run(QWidget *parent, QUrl &url, QString &name)
{
RemoteDialog dlg(parent);
// Set URL components
if(!url.isEmpty())
{
QString url_no_credentials = UrlToStringNoCredentials(url);
dlg.ui->lineURL->setText(url_no_credentials);
dlg.ui->lineUserName->setText(url.userName());
dlg.ui->linePassword->setText(url.password());
dlg.ui->lineName->setText(name);
}
if(dlg.exec() != QDialog::Accepted)
return false;
QString urltext = dlg.ui->lineURL->text();
url = QUrl::fromUserInput(urltext);
if(url.isEmpty() || !url.isValid())
{
QMessageBox::critical(parent, tr("Error"), tr("Invalid URL."), QMessageBox::Ok );
return false;
}
if(!dlg.ui->lineUserName->text().trimmed().isEmpty())
url.setUserName(dlg.ui->lineUserName->text());
if(!dlg.ui->linePassword->text().trimmed().isEmpty())
url.setPassword(dlg.ui->linePassword->text());
name =dlg.ui->lineName->text().trimmed();
if(name.isEmpty())
name = UrlToStringNoCredentials(url);
return true;
}
//-----------------------------------------------------------------------------
void RemoteDialog::GetRepositoryPath(QString &pathResult)
{
QString filter(tr("Fossil Repository") + QString(" (*." FOSSIL_EXT ")"));
pathResult = QFileDialog::getSaveFileName(
this,
tr("Select Fossil Repository"),
QDir::toNativeSeparators(pathResult),
filter,
&filter,
QFileDialog::DontConfirmOverwrite);
}
//-----------------------------------------------------------------------------
void RemoteDialog::on_btnSelectSourceRepo_clicked()
{
QString path = ui->lineURL->text();
GetRepositoryPath(path);
if(path.trimmed().isEmpty())
return;
if(!QFile::exists(path))
{
QMessageBox::critical(this, tr("Error"), tr("Invalid Repository File."), QMessageBox::Ok);
return;
}
ui->lineURL->setText(QDir::toNativeSeparators(path));
}

View File

@ -1,29 +0,0 @@
#ifndef REMOTEDIALOG_H
#define REMOTEDIALOG_H
#include <QDialog>
namespace Ui {
class RemoteDialog;
}
class RemoteDialog : public QDialog
{
Q_OBJECT
public:
explicit RemoteDialog(QWidget *parent = 0);
~RemoteDialog();
static bool run(QWidget *parent, class QUrl &url, QString &name);
private slots:
void on_btnSelectSourceRepo_clicked();
private:
void GetRepositoryPath(QString &pathResult);
Ui::RemoteDialog *ui;
};
#endif // REMOTEDIALOG_H

View File

@ -1,100 +0,0 @@
#include "RevisionDialog.h"
#include "ui_RevisionDialog.h"
#include "Utils.h"
//-----------------------------------------------------------------------------
RevisionDialog::RevisionDialog(QWidget *parent, const QStringList &completions, const QString &defaultValue) :
QDialog(parent),
ui(new Ui::RevisionDialog),
completer(completions, parent)
{
ui->setupUi(this);
ui->cmbRevision->setCompleter(&completer);
ui->cmbRevision->addItems(completions);
if(!defaultValue.isEmpty())
{
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
int index = ui->cmbRevision->findText(defaultValue);
if(index>=0)
ui->cmbRevision->setCurrentIndex(index);
#else
ui->cmbRevision->setCurrentText(defaultValue);
#endif
}
}
//-----------------------------------------------------------------------------
RevisionDialog::~RevisionDialog()
{
delete ui;
}
//-----------------------------------------------------------------------------
QString RevisionDialog::runUpdate(QWidget *parent, const QString &title, const QStringList &completions, const QString &defaultValue)
{
RevisionDialog dlg(parent, completions, defaultValue);
dlg.setWindowTitle(title);
dlg.ui->lblName->setVisible(false);
dlg.ui->lineName->setVisible(false);
dlg.ui->lblIntegrate->setVisible(false);
dlg.ui->chkIntegrate->setVisible(false);
dlg.ui->lblForce->setVisible(false);
dlg.ui->chkForce->setVisible(false);
dlg.adjustSize();
if(dlg.exec() != QDialog::Accepted)
return QString("");
return dlg.ui->cmbRevision->currentText().trimmed();
}
//-----------------------------------------------------------------------------
QString RevisionDialog::runMerge(QWidget *parent, const QString &title, const QStringList &completions, const QString &defaultValue, bool &integrate, bool &force)
{
RevisionDialog dlg(parent, completions, defaultValue);
dlg.setWindowTitle(title);
dlg.ui->lblName->setVisible(false);
dlg.ui->lineName->setVisible(false);
dlg.ui->lblIntegrate->setVisible(true);
dlg.ui->chkIntegrate->setVisible(true);
dlg.ui->chkIntegrate->setChecked(integrate);
dlg.ui->lblForce->setVisible(true);
dlg.ui->chkForce->setVisible(true);
dlg.ui->chkForce->setChecked(force);
dlg.adjustSize();
if(dlg.exec() != QDialog::Accepted)
return QString("");
integrate = dlg.ui->chkIntegrate->checkState() == Qt::Checked;
force = dlg.ui->chkForce->checkState() == Qt::Checked;
return dlg.ui->cmbRevision->currentText().trimmed();
}
//-----------------------------------------------------------------------------
bool RevisionDialog::runNewTag(QWidget *parent, const QString &title, const QStringList &completions, const QString &defaultValue, QString &revision, QString &name)
{
RevisionDialog dlg(parent, completions, defaultValue);
dlg.setWindowTitle(title);
dlg.ui->lblName->setVisible(true);
dlg.ui->lineName->setVisible(true);
dlg.ui->lblIntegrate->setVisible(false);
dlg.ui->chkIntegrate->setVisible(false);
dlg.ui->lblForce->setVisible(false);
dlg.ui->chkForce->setVisible(false);
dlg.adjustSize();
if(dlg.exec() != QDialog::Accepted)
return false;
revision = dlg.ui->cmbRevision->currentText().trimmed();
name = dlg.ui->lineName->text().trimmed();
return true;
}

View File

@ -1,28 +0,0 @@
#ifndef REVISIONDIALOG_H
#define REVISIONDIALOG_H
#include <QDialog>
#include <QCompleter>
namespace Ui {
class RevisionDialog;
}
class RevisionDialog : public QDialog
{
Q_OBJECT
public:
explicit RevisionDialog(QWidget *parent, const QStringList &completions, const QString &defaultValue);
~RevisionDialog();
static QString runUpdate(QWidget *parent, const QString &title, const QStringList &completions, const QString &defaultValue);
static QString runMerge(QWidget* parent, const QString& title, const QStringList& completions, const QString& defaultValue, bool& integrate, bool& force);
static bool runNewTag(QWidget *parent, const QString &title, const QStringList &completions, const QString &defaultValue, QString &revision, QString &name);
private:
Ui::RevisionDialog *ui;
QCompleter completer;
};
#endif // REVISIONDIALOG_H

View File

@ -1,24 +0,0 @@
#include "SearchBox.h"
#include <QKeyEvent>
SearchBox::SearchBox(QWidget *parent) : QLineEdit(parent)
{
}
SearchBox::~SearchBox()
{
}
void SearchBox::keyPressEvent(QKeyEvent *event)
{
// Clear text on escape
if(event->key() == Qt::Key_Escape)
{
setText("");
clearFocus();
}
else
QLineEdit::keyPressEvent(event);
}

View File

@ -1,23 +0,0 @@
#ifndef SEARCHBOX_H
#define SEARCHBOX_H
#include <QLineEdit>
class SearchBox : public QLineEdit
{
Q_OBJECT
public:
explicit SearchBox(QWidget* parent=0);
~SearchBox();
signals:
public slots:
protected:
void keyPressEvent(QKeyEvent *event);
};
#endif // SEARCHBOX_H

View File

@ -1,131 +0,0 @@
#include "Settings.h"
#include <QSettings>
#include <QCoreApplication>
#include <QDir>
#include <QTranslator>
#include <QResource>
#include <QTextCodec>
///////////////////////////////////////////////////////////////////////////////
Settings::Settings(bool portableMode) : store(0)
{
Mappings.insert(FOSSIL_SETTING_GDIFF_CMD, Setting("", Setting::TYPE_FOSSIL_GLOBAL));
Mappings.insert(FOSSIL_SETTING_GMERGE_CMD, Setting("", Setting::TYPE_FOSSIL_GLOBAL));
Mappings.insert(FOSSIL_SETTING_PROXY_URL, Setting("", Setting::TYPE_FOSSIL_GLOBAL));
Mappings.insert(FOSSIL_SETTING_HTTP_PORT, Setting("", Setting::TYPE_FOSSIL_GLOBAL));
Mappings.insert(FOSSIL_SETTING_IGNORE_GLOB, Setting("", Setting::TYPE_FOSSIL_LOCAL));
Mappings.insert(FOSSIL_SETTING_CRNL_GLOB, Setting("", Setting::TYPE_FOSSIL_LOCAL));
// Go into portable mode when explicitly requested or if a config file exists next to the executable
QString ini_path = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + QDir::separator() + QCoreApplication::applicationName() + ".ini");
if( portableMode || QFile::exists(ini_path))
store = new QSettings(ini_path, QSettings::IniFormat);
else
{
// Linux: ~/.config/organizationName/applicationName.conf
// Windows: HKEY_CURRENT_USER\Software\organizationName\Fuel
store = new QSettings(QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
}
Q_ASSERT(store);
if(!HasValue(FUEL_SETTING_FILE_DBLCLICK))
SetValue(FUEL_SETTING_FILE_DBLCLICK, 0);
if(!HasValue(FUEL_SETTING_LANGUAGE) && SupportsLang(QLocale::system().name()))
SetValue(FUEL_SETTING_LANGUAGE, QLocale::system().name());
if(!HasValue(FUEL_SETTING_WEB_BROWSER))
SetValue(FUEL_SETTING_WEB_BROWSER, 0);
for(int i=0; i<MAX_CUSTOM_ACTIONS; ++i)
{
CustomAction action;
action.Id = QObject::tr("Custom Action %0").arg(i+1);
customActions.append(action);
}
ApplyEnvironment();
}
//-----------------------------------------------------------------------------
Settings::~Settings()
{
Q_ASSERT(store);
delete store;
}
//-----------------------------------------------------------------------------
void Settings::ApplyEnvironment()
{
QString lang_id = GetValue(FUEL_SETTING_LANGUAGE).toString();
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8"));
#endif
if(!InstallLang(lang_id))
SetValue(FUEL_SETTING_LANGUAGE, "en_US");
}
//-----------------------------------------------------------------------------
bool Settings::InstallLang(const QString &langId)
{
if(langId == "en_US")
{
QCoreApplication::instance()->removeTranslator(&translator);
return true;
}
QString locale_path = QString(":intl/intl/%0.qm").arg(langId);
if(!translator.load(locale_path))
return false;
Q_ASSERT(!translator.isEmpty());
QCoreApplication::instance()->installTranslator(&translator);
return true;
}
//-----------------------------------------------------------------------------
bool Settings::HasValue(const QString &name) const
{
return store->contains(name);
}
//-----------------------------------------------------------------------------
const QVariant Settings::GetValue(const QString &name)
{
if(!HasValue(name))
return QVariant();
return store->value(name);
}
//-----------------------------------------------------------------------------
void Settings::SetValue(const QString &name, const QVariant &value)
{
store->setValue(name, value);
}
//-----------------------------------------------------------------------------
QVariant &Settings::GetFossilValue(const QString &name)
{
mappings_t::iterator it=Mappings.find(name);
Q_ASSERT(it!=Mappings.end());
return it.value().Value;
}
//-----------------------------------------------------------------------------
void Settings::SetFossilValue(const QString &name, const QVariant &value)
{
mappings_t::iterator it=Mappings.find(name);
Q_ASSERT(it!=Mappings.end());
it->Value = value;
}
//-----------------------------------------------------------------------------
bool Settings::SupportsLang(const QString &langId) const
{
QString locale_path = QString(":intl/intl/%0.qm").arg(langId);
QResource res(locale_path);
return res.isValid();
}

View File

@ -1,126 +0,0 @@
#ifndef SETTINGS_H
#define SETTINGS_H
#include <QMap>
#include <QVariant>
#include <QTranslator>
#include <QVector>
#define FUEL_SETTING_FOSSIL_PATH "FossilPath"
#define FUEL_SETTING_COMMIT_MSG "CommitMsgHistory"
#define FUEL_SETTING_FILE_DBLCLICK "FileDblClickAction"
#define FUEL_SETTING_LANGUAGE "Language"
#define FUEL_SETTING_WEB_BROWSER "WebBrowser"
#define FOSSIL_SETTING_GDIFF_CMD "gdiff-command"
#define FOSSIL_SETTING_GMERGE_CMD "gmerge-command"
#define FOSSIL_SETTING_PROXY_URL "proxy"
#define FOSSIL_SETTING_IGNORE_GLOB "ignore-glob"
#define FOSSIL_SETTING_CRNL_GLOB "crnl-glob"
#define FOSSIL_SETTING_HTTP_PORT "http-port"
enum FileDblClickAction
{
FILE_DLBCLICK_ACTION_DIFF,
FILE_DLBCLICK_ACTION_OPEN,
FILE_DLBCLICK_ACTION_OPENCONTAINING,
FILE_DLBCLICK_ACTION_CUSTOM, // Custom Action 1
FILE_DLBCLICK_ACTION_MAX
};
enum CustomActionContext
{
ACTION_CONTEXT_FILES = 1 << 0,
ACTION_CONTEXT_FOLDERS = 1 << 1,
ACTION_CONTEXT_FILES_AND_FOLDERS = ACTION_CONTEXT_FILES|ACTION_CONTEXT_FOLDERS
};
enum
{
MAX_CUSTOM_ACTIONS = 9
};
struct CustomAction
{
QString Id;
QString Description;
QString Command;
CustomActionContext Context;
bool MultipleSelection;
CustomAction()
{
Clear();
}
bool IsValid() const
{
return !(Description.isEmpty() || Command.isEmpty());
}
bool IsActive(CustomActionContext context) const
{
return (Context & context) != 0;
}
void Clear()
{
Description.clear();
Command.clear();
Context = ACTION_CONTEXT_FILES;
MultipleSelection = true;
}
};
struct Settings
{
struct Setting
{
enum SettingType
{
TYPE_FOSSIL_GLOBAL,
TYPE_FOSSIL_LOCAL
};
Setting(QVariant value, SettingType type) : Value(value), Type(type)
{}
QVariant Value;
SettingType Type;
};
typedef QMap<QString, Setting> mappings_t;
typedef QVector<CustomAction> custom_actions_t;
Settings(bool portableMode = false);
~Settings();
void ApplyEnvironment();
// App configuration access
class QSettings * GetStore() { return store; }
bool HasValue(const QString &name) const; // store->contains(FUEL_SETTING_FOSSIL_PATH)
const QVariant GetValue(const QString &name); // settings.store->value
void SetValue(const QString &name, const QVariant &value); // settings.store->value
// Fossil configuration access
QVariant & GetFossilValue(const QString &name);
void SetFossilValue(const QString &name, const QVariant &value);
mappings_t & GetMappings() { return Mappings; }
bool SupportsLang(const QString &langId) const;
bool InstallLang(const QString &langId);
custom_actions_t &GetCustomActions() { return customActions; }
private:
mappings_t Mappings;
class QSettings *store;
QTranslator translator;
custom_actions_t customActions;
};
#endif // SETTINGS_H

View File

@ -1,8 +1,37 @@
#include "SettingsDialog.h"
#include "ui_SettingsDialog.h"
#include <QFileDialog>
#include "Utils.h"
#include <QSettings>
#include <QCoreApplication>
#include <QDir>
#include <QTranslator>
#include <QResource>
#include <QTextCodec>
///////////////////////////////////////////////////////////////////////////////
QString SettingsDialog::SelectExe(QWidget *parent, const QString &description)
{
QString filter(tr("Applications"));
#ifdef Q_OS_WIN
filter += " (*.exe)";
#else
filter += " (*)";
#endif
QString path = QFileDialog::getOpenFileName(
parent,
description,
QString(),
filter,
&filter);
if(!QFile::exists(path))
return QString();
return path;
}
///////////////////////////////////////////////////////////////////////////////
SettingsDialog::SettingsDialog(QWidget *parent, Settings &_settings) :
@ -17,7 +46,6 @@ SettingsDialog::SettingsDialog(QWidget *parent, Settings &_settings) :
ui->cmbDoubleClickAction->addItem(tr("Diff File"));
ui->cmbDoubleClickAction->addItem(tr("Open File"));
ui->cmbDoubleClickAction->addItem(tr("Open Containing Folder"));
ui->cmbDoubleClickAction->addItem(tr("Custom Action %0").arg(1));
ui->cmbFossilBrowser->addItem(tr("System"));
ui->cmbFossilBrowser->addItem(tr("Internal"));
@ -26,6 +54,7 @@ SettingsDialog::SettingsDialog(QWidget *parent, Settings &_settings) :
ui->lineFossilPath->setText(QDir::toNativeSeparators(settings->GetValue(FUEL_SETTING_FOSSIL_PATH).toString()));
ui->cmbDoubleClickAction->setCurrentIndex(settings->GetValue(FUEL_SETTING_FILE_DBLCLICK).toInt());
ui->cmbFossilBrowser->setCurrentIndex(settings->GetValue(FUEL_SETTING_WEB_BROWSER).toInt());
ui->lineUIPort->setText(settings->GetValue(FUEL_SETTING_HTTP_PORT).toString());
// Initialize language combo
foreach(const LangMap &m, langMap)
@ -37,22 +66,15 @@ SettingsDialog::SettingsDialog(QWidget *parent, Settings &_settings) :
ui->cmbActiveLanguage->findText(
LangIdToName(lang)));
// Global Settings
ui->lineGDiffCommand->setText(settings->GetFossilValue(FOSSIL_SETTING_GDIFF_CMD).toString());
ui->lineGMergeCommand->setText(settings->GetFossilValue(FOSSIL_SETTING_GMERGE_CMD).toString());
ui->lineProxy->setText(settings->GetFossilValue(FOSSIL_SETTING_PROXY_URL).toString());
lastActionIndex = 0;
currentCustomActions = settings->GetCustomActions();
ui->cmbCustomActionContext->addItem(tr("Files"));
ui->cmbCustomActionContext->addItem(tr("Folders"));
ui->cmbCustomActionContext->setCurrentIndex(0);
GetCustomAction(0);
for(int i=0; i<currentCustomActions.size(); ++i)
{
CustomAction &a = currentCustomActions[i];
ui->cmbCustomAction->addItem(a.Id);
}
ui->cmbCustomAction->setCurrentIndex(0);
// Repository Settings
ui->lineRemoteURL->setText(settings->GetFossilValue(FOSSIL_SETTING_REMOTE_URL).toString());
ui->lineIgnore->setText(settings->GetFossilValue(FOSSIL_SETTING_IGNORE_GLOB).toString());
ui->lineIgnoreCRNL->setText(settings->GetFossilValue(FOSSIL_SETTING_CRNL_GLOB).toString());
}
//-----------------------------------------------------------------------------
@ -75,6 +97,7 @@ void SettingsDialog::on_buttonBox_accepted()
Q_ASSERT(ui->cmbDoubleClickAction->currentIndex()>=FILE_DLBCLICK_ACTION_DIFF && ui->cmbDoubleClickAction->currentIndex()<FILE_DLBCLICK_ACTION_MAX);
settings->SetValue(FUEL_SETTING_FILE_DBLCLICK, ui->cmbDoubleClickAction->currentIndex());
settings->SetValue(FUEL_SETTING_WEB_BROWSER, ui->cmbFossilBrowser->currentIndex());
settings->SetValue(FUEL_SETTING_HTTP_PORT, ui->lineUIPort->text());
Q_ASSERT(settings->HasValue(FUEL_SETTING_LANGUAGE));
QString curr_langid = settings->GetValue(FUEL_SETTING_LANGUAGE).toString();
@ -85,16 +108,14 @@ void SettingsDialog::on_buttonBox_accepted()
if(curr_langid != new_langid)
QMessageBox::information(this, tr("Restart required"), tr("The language change will take effect after restarting the application"), QMessageBox::Ok);
for(int i=0; i<currentCustomActions.size(); ++i)
{
CustomAction &a = currentCustomActions[i];
a.Description = a.Description.trimmed();
a.Command = a.Command.trimmed();
}
settings->SetFossilValue(FOSSIL_SETTING_GDIFF_CMD, ui->lineGDiffCommand->text());
settings->SetFossilValue(FOSSIL_SETTING_GMERGE_CMD, ui->lineGMergeCommand->text());
settings->SetFossilValue(FOSSIL_SETTING_PROXY_URL, ui->lineProxy->text());
PutCustomAction(ui->cmbCustomAction->currentIndex());
settings->SetFossilValue(FOSSIL_SETTING_REMOTE_URL, ui->lineRemoteURL->text());
settings->SetFossilValue(FOSSIL_SETTING_IGNORE_GLOB, ui->lineIgnore->text());
settings->SetFossilValue(FOSSIL_SETTING_CRNL_GLOB, ui->lineIgnoreCRNL->text());
settings->GetCustomActions() = currentCustomActions;
settings->ApplyEnvironment();
}
@ -107,6 +128,22 @@ void SettingsDialog::on_btnSelectFossil_clicked()
ui->lineFossilPath->setText(QDir::toNativeSeparators(path));
}
//-----------------------------------------------------------------------------
void SettingsDialog::on_btnSelectFossilGDiff_clicked()
{
QString path = SelectExe(this, tr("Select Graphical Diff application"));
if(!path.isEmpty())
ui->lineGDiffCommand->setText(QDir::toNativeSeparators(path));
}
//-----------------------------------------------------------------------------
void SettingsDialog::on_btnSelectGMerge_clicked()
{
QString path = SelectExe(this, tr("Select Graphical Merge application"));
if(!path.isEmpty())
ui->lineGMergeCommand->setText(path);
}
//-----------------------------------------------------------------------------
void SettingsDialog::on_btnClearMessageHistory_clicked()
{
@ -153,58 +190,119 @@ QString SettingsDialog::LangNameToId(const QString &name)
return "";
}
//-----------------------------------------------------------------------------
void SettingsDialog::on_btnSelectCustomFileActionCommand_clicked()
///////////////////////////////////////////////////////////////////////////////
Settings::Settings(bool portableMode) : store(0)
{
QString path = SelectExe(this, tr("Select command"));
if(path.isEmpty())
return;
Mappings.insert(FOSSIL_SETTING_GDIFF_CMD, Setting("", Setting::TYPE_FOSSIL_GLOBAL));
Mappings.insert(FOSSIL_SETTING_GMERGE_CMD, Setting("", Setting::TYPE_FOSSIL_GLOBAL));
Mappings.insert(FOSSIL_SETTING_PROXY_URL, Setting("", Setting::TYPE_FOSSIL_GLOBAL));
// Quote path if it contains spaces
if(path.indexOf(' ')!=-1)
path = '"' + path + '"';
Mappings.insert(FOSSIL_SETTING_IGNORE_GLOB, Setting("", Setting::TYPE_FOSSIL_LOCAL));
Mappings.insert(FOSSIL_SETTING_CRNL_GLOB, Setting("", Setting::TYPE_FOSSIL_LOCAL));
Mappings.insert(FOSSIL_SETTING_REMOTE_URL, Setting("off", Setting::TYPE_FOSSIL_COMMAND));
ui->lineCustomActionCommand->setText(QDir::toNativeSeparators(path));
// Go into portable mode when explicitly requested or if a config file exists next to the executable
QString ini_path = QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + QDir::separator() + QCoreApplication::applicationName() + ".ini");
if( portableMode || QFile::exists(ini_path))
store = new QSettings(ini_path, QSettings::IniFormat);
else
{
// Linux: ~/.config/organizationName/applicationName.conf
// Windows: HKEY_CURRENT_USER\Software\organizationName\Fuel
store = new QSettings(QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
}
Q_ASSERT(store);
if(!HasValue(FUEL_SETTING_FILE_DBLCLICK))
SetValue(FUEL_SETTING_FILE_DBLCLICK, 0);
if(!HasValue(FUEL_SETTING_LANGUAGE) && SupportsLang(QLocale::system().name()))
SetValue(FUEL_SETTING_LANGUAGE, QLocale::system().name());
if(!HasValue(FUEL_SETTING_WEB_BROWSER))
SetValue(FUEL_SETTING_WEB_BROWSER, 0);
if(!HasValue(FUEL_SETTING_HTTP_PORT))
SetValue(FUEL_SETTING_HTTP_PORT, "8090");
ApplyEnvironment();
}
//-----------------------------------------------------------------------------
void SettingsDialog::GetCustomAction(int index)
Settings::~Settings()
{
Q_ASSERT(index>=0 && index < currentCustomActions.size());
CustomAction &action = currentCustomActions[index];
ui->lineCustomActionDescription->setText(action.Description);
ui->lineCustomActionCommand->setText(action.Command);
ui->cmbCustomActionContext->setCurrentIndex(action.Context-1);
ui->chkCustomActionMultipleSelection->setChecked(action.MultipleSelection);
Q_ASSERT(store);
delete store;
}
//-----------------------------------------------------------------------------
void SettingsDialog::PutCustomAction(int index)
void Settings::ApplyEnvironment()
{
Q_ASSERT(index>=0 && index < currentCustomActions.size());
CustomAction &action = currentCustomActions[index];
action.Description = ui->lineCustomActionDescription->text().trimmed();
action.Command = ui->lineCustomActionCommand->text().trimmed();
action.Context = static_cast<CustomActionContext>(ui->cmbCustomActionContext->currentIndex()+1);
action.MultipleSelection = ui->chkCustomActionMultipleSelection->isChecked();
QString lang_id = GetValue(FUEL_SETTING_LANGUAGE).toString();
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
QTextCodec::setCodecForTr(QTextCodec::codecForName("utf8"));
#endif
if(!InstallLang(lang_id))
SetValue(FUEL_SETTING_LANGUAGE, "en_US");
}
//-----------------------------------------------------------------------------
void SettingsDialog::on_cmbCustomAction_currentIndexChanged(int index)
bool Settings::InstallLang(const QString &langId)
{
if(index != lastActionIndex)
PutCustomAction(lastActionIndex);
if(langId == "en_US")
{
QCoreApplication::instance()->removeTranslator(&translator);
return true;
}
GetCustomAction(index);
lastActionIndex = index;
QString locale_path = QString(":intl/intl/%0.qm").arg(langId);
if(!translator.load(locale_path))
return false;
Q_ASSERT(!translator.isEmpty());
QCoreApplication::instance()->installTranslator(&translator);
return true;
}
//-----------------------------------------------------------------------------
void SettingsDialog::on_cmbCustomActionContext_currentIndexChanged(int index)
bool Settings::HasValue(const QString &name) const
{
int action_index = ui->cmbCustomAction->currentIndex();
if(action_index<0)
return;
Q_ASSERT(action_index>=0 && action_index < currentCustomActions.size());
currentCustomActions[action_index].Context = static_cast<CustomActionContext>(index+1);
return store->contains(name);
}
//-----------------------------------------------------------------------------
const QVariant Settings::GetValue(const QString &name)
{
if(!HasValue(name))
return QVariant();
return store->value(name);
}
//-----------------------------------------------------------------------------
void Settings::SetValue(const QString &name, const QVariant &value)
{
store->setValue(name, value);
}
//-----------------------------------------------------------------------------
QVariant &Settings::GetFossilValue(const QString &name)
{
mappings_t::iterator it=Mappings.find(name);
Q_ASSERT(it!=Mappings.end());
return it.value().Value;
}
//-----------------------------------------------------------------------------
void Settings::SetFossilValue(const QString &name, const QVariant &value)
{
mappings_t::iterator it=Mappings.find(name);
Q_ASSERT(it!=Mappings.end());
it->Value = value;
}
//-----------------------------------------------------------------------------
bool Settings::SupportsLang(const QString &langId) const
{
QString locale_path = QString(":intl/intl/%0.qm").arg(langId);
QResource res(locale_path);
return res.isValid();
}

View File

@ -2,12 +2,82 @@
#define SETTINGSDIALOG_H
#include <QDialog>
#include "Settings.h"
#include <QMap>
#include <QVariant>
#include <QTranslator>
namespace Ui {
class SettingsDialog;
}
#define FUEL_SETTING_FOSSIL_PATH "FossilPath"
#define FUEL_SETTING_COMMIT_MSG "CommitMsgHistory"
#define FUEL_SETTING_FILE_DBLCLICK "FileDblClickAction"
#define FUEL_SETTING_LANGUAGE "Language"
#define FUEL_SETTING_WEB_BROWSER "WebBrowser"
#define FUEL_SETTING_HTTP_PORT "HTTPPort"
#define FOSSIL_SETTING_GDIFF_CMD "gdiff-command"
#define FOSSIL_SETTING_GMERGE_CMD "gmerge-command"
#define FOSSIL_SETTING_PROXY_URL "proxy"
#define FOSSIL_SETTING_IGNORE_GLOB "ignore-glob"
#define FOSSIL_SETTING_CRNL_GLOB "crnl-glob"
#define FOSSIL_SETTING_REMOTE_URL "remote-url"
enum FileDblClickAction
{
FILE_DLBCLICK_ACTION_DIFF,
FILE_DLBCLICK_ACTION_OPEN,
FILE_DLBCLICK_ACTION_OPENCONTAINING,
FILE_DLBCLICK_ACTION_MAX
};
struct Settings
{
struct Setting
{
enum SettingType
{
TYPE_FOSSIL_GLOBAL,
TYPE_FOSSIL_LOCAL,
TYPE_FOSSIL_COMMAND
};
Setting(QVariant value, SettingType type) : Value(value), Type(type)
{}
QVariant Value;
SettingType Type;
};
typedef QMap<QString, Setting> mappings_t;
Settings(bool portableMode = false);
~Settings();
void ApplyEnvironment();
// App configuration access
class QSettings * GetStore() { return store; }
bool HasValue(const QString &name) const; // store->contains(FUEL_SETTING_FOSSIL_PATH)
const QVariant GetValue(const QString &name); // settings.store->value
void SetValue(const QString &name, const QVariant &value); // settings.store->value
// Fossil configuration access
QVariant & GetFossilValue(const QString &name);
void SetFossilValue(const QString &name, const QVariant &value);
mappings_t & GetMappings() { return Mappings; }
bool SupportsLang(const QString &langId) const;
bool InstallLang(const QString &langId);
private:
mappings_t Mappings;
class QSettings *store;
QTranslator translator;
};
class SettingsDialog : public QDialog
{
Q_OBJECT
@ -22,17 +92,15 @@ public:
private slots:
void on_btnSelectFossil_clicked();
void on_buttonBox_accepted();
void on_btnSelectFossilGDiff_clicked();
void on_btnSelectGMerge_clicked();
void on_btnClearMessageHistory_clicked();
void on_btnSelectCustomFileActionCommand_clicked();
void on_cmbCustomAction_currentIndexChanged(int index);
void on_cmbCustomActionContext_currentIndexChanged(int index);
private:
static QString SelectExe(QWidget *parent, const QString &description);
QString LangIdToName(const QString &id);
QString LangNameToId(const QString &name);
void CreateLangMap();
void GetCustomAction(int index);
void PutCustomAction(int index);
struct LangMap
{
@ -48,8 +116,6 @@ private:
QList<LangMap> langMap;
Ui::SettingsDialog *ui;
Settings *settings;
Settings::custom_actions_t currentCustomActions;
int lastActionIndex;
};
#endif // SETTINGSDIALOG_H

View File

@ -1,12 +1,6 @@
#include "Utils.h"
#include <QMessageBox>
#include <QDialogButtonBox>
#include <QFileDialog>
#include <QEventLoop>
#include <QUrl>
#include <QProcess>
#include <QCryptographicHash>
#include "ext/qtkeychain/keychain.h"
///////////////////////////////////////////////////////////////////////////////
QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, const QString &query, QMessageBox::StandardButtons buttons)
@ -20,54 +14,6 @@ QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, c
return res;
}
//-----------------------------------------------------------------------------
QString QuotePath(const QString &path)
{
return path;
}
//-----------------------------------------------------------------------------
QStringList QuotePaths(const QStringList &paths)
{
QStringList res;
for(int i=0; i<paths.size(); ++i)
res.append(QuotePath(paths[i]));
return res;
}
//-----------------------------------------------------------------------------
QString SelectExe(QWidget *parent, const QString &description)
{
QString filter(QObject::tr("Applications"));
#ifdef Q_OS_WIN
filter += " (*.exe)";
#else
filter += " (*)";
#endif
QString path = QFileDialog::getOpenFileName(
parent,
description,
QString(),
filter,
&filter);
if(!QFile::exists(path))
return QString();
#ifdef Q_OS_MACX
// Guess actual executable from bundle dir
QFileInfo fi(path);
if(fi.isDir() && path.indexOf(".app")!=-1)
{
path += "/Contents/MacOS/" + fi.baseName();
if(!QFile::exists(path))
return QString();
}
#endif
return path;
}
//-----------------------------------------------------------------------------
#if 0 // Unused
#include <QInputDialog>
@ -345,294 +291,3 @@ bool ShowExplorerMenu(HWND hwnd, const QString &path, const QPoint &qpoint)
#endif
//-----------------------------------------------------------------------------
void ParseProperties(QStringMap &properties, const QStringList &lines, QChar separator)
{
properties.clear();
foreach(QString l, lines)
{
l = l.trimmed();
int index = l.indexOf(separator);
QString key;
QString value;
if(index!=-1)
{
key = l.left(index).trimmed();
value = l.mid(index+1).trimmed();
}
else
key = l;
properties.insert(key, value);
}
}
//------------------------------------------------------------------------------
void GetStandardItemTextRecursive(QString &name, const QStandardItem &item, const QChar &separator)
{
if(item.parent())
{
GetStandardItemTextRecursive(name, *item.parent());
name.append(separator);
}
name.append(item.data(Qt::DisplayRole).toString());
}
//------------------------------------------------------------------------------
void BuildNameToModelIndex(name_modelindex_map_t &map, const QStandardItem &item)
{
QString name;
GetStandardItemTextRecursive(name, item);
map.insert(name, item.index());
for(int i=0; i<item.rowCount(); ++i)
{
const QStandardItem *child = item.child(i);
Q_ASSERT(child);
BuildNameToModelIndex(map, *child);
}
}
//------------------------------------------------------------------------------
void BuildNameToModelIndex(name_modelindex_map_t &map, const QStandardItemModel &model)
{
for(int i=0; i<model.rowCount(); ++i)
{
const QStandardItem *item = model.item(i);
Q_ASSERT(item);
BuildNameToModelIndex(map, *item);
}
}
//------------------------------------------------------------------------------
bool KeychainSet(QObject *parent, const QUrl &url, QSettings &settings)
{
QEventLoop loop(parent);
QKeychain::WritePasswordJob job(UrlToStringNoCredentials(url));
#ifdef Q_OS_WIN
settings.beginGroup("Keychain");
job.setSettings(&settings);
#else
Q_UNUSED(settings)
#endif
job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()) );
job.setAutoDelete( false );
job.setInsecureFallback(false);
job.setKey(url.userName());
job.setTextData(url.password());
job.start();
loop.exec();
#ifdef Q_OS_WIN
settings.endGroup();
#endif
return job.error() == QKeychain::NoError;
}
//------------------------------------------------------------------------------
bool KeychainGet(QObject *parent, QUrl &url, QSettings &settings)
{
QEventLoop loop(parent);
QKeychain::ReadPasswordJob job(UrlToStringNoCredentials(url));
#ifdef Q_OS_WIN
settings.beginGroup("Keychain");
job.setSettings(&settings);
#else
Q_UNUSED(settings)
#endif
job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()));
job.setAutoDelete( false );
job.setInsecureFallback(false);
job.setAutoDelete( false );
job.setKey(url.userName());
job.start();
loop.exec();
#ifdef Q_OS_WIN
settings.endGroup();
#endif
if(job.error() != QKeychain::NoError)
return false;
url.setUserName(job.key());
url.setPassword(job.textData());
return true;
}
//------------------------------------------------------------------------------
bool KeychainDelete(QObject* parent, const QUrl& url, QSettings &settings)
{
QEventLoop loop(parent);
QKeychain::DeletePasswordJob job(UrlToStringNoCredentials(url));
#ifdef Q_OS_WIN
settings.beginGroup("Keychain");
job.setSettings(&settings);
#else
Q_UNUSED(settings)
#endif
job.connect( &job, SIGNAL(finished(QKeychain::Job*)), &loop, SLOT(quit()));
job.setAutoDelete( false );
job.setInsecureFallback(false);
job.setAutoDelete( false );
job.setKey(url.userName());
job.start();
loop.exec();
#ifdef Q_OS_WIN
settings.endGroup();
#endif
return job.error() == QKeychain::NoError;
}
//------------------------------------------------------------------------------
QString HashString(const QString& str)
{
QCryptographicHash hash(QCryptographicHash::Sha1);
const QByteArray ba(str.toUtf8());
hash.addData(ba.data(), ba.size());
QString str_out(hash.result().toHex());
return str_out;
}
//------------------------------------------------------------------------------
QString UrlToStringDisplay(const QUrl& url)
{
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
return url.toString(QUrl::RemovePassword);
#else
return url.toDisplayString();
#endif
}
//------------------------------------------------------------------------------
QString UrlToStringNoCredentials(const QUrl& url)
{
#if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
return url.toString(QUrl::RemoveUserInfo);
#else
return url.toString(QUrl::PrettyDecoded|QUrl::RemoveUserInfo);
#endif
}
//------------------------------------------------------------------------------
void SplitCommandLine(const QString &commandLine, QString &command, QString &extraParams)
{
// Process command string
command = commandLine.trimmed();
Q_ASSERT(!command.isEmpty());
// Split command from embedded params
extraParams.clear();
// Command ends after first space
QChar cmd_char_end = ' ';
int cmd_start = 0;
int backtrack = 0;
// ...unless it is a quoted command
if(command[0]=='"')
{
cmd_char_end = '"';
cmd_start = 1;
backtrack = 1;
}
int cmd_end = command.indexOf(cmd_char_end, cmd_start);
if(cmd_end > 0)
{
extraParams = command.mid(cmd_end+1);
command = command.mid(cmd_start, cmd_end-backtrack);
}
command = command.trimmed();
extraParams = extraParams.trimmed();
}
//------------------------------------------------------------------------------
bool SpawnExternalProcess(QObject *processParent, const QString& command, const QStringList& fileList, const stringset_t& pathSet, const QString &workspaceDir, UICallback &uiCallback)
{
static const char* MACRO_FILE = "%FILE";
static const char* MACRO_FOLDER = "%FOLDER";
static const char* MACRO_WORKSPACE = "%WORKSPACE";
QStringList params;
QString cmd, extra_params;
SplitCommandLine(command, cmd, extra_params);
// Push all additional params, except those containing macros
QString macro_file;
QString macro_folder;
if(!extra_params.isEmpty())
{
QStringList extra_param_list = extra_params.split(' ');
foreach(const QString &p, extra_param_list)
{
if(p.indexOf(MACRO_FILE)!=-1)
{
macro_file = p;
continue;
}
else if(p.indexOf(MACRO_FOLDER)!=-1)
{
macro_folder = p;
continue;
}
else if(p.indexOf(MACRO_WORKSPACE)!=-1)
{
// Add in-place
QString n = p;
n.replace(MACRO_WORKSPACE, QDir::toNativeSeparators(workspaceDir), Qt::CaseInsensitive);
params.push_back(n);
continue;
}
params.push_back(p);
}
}
// Build file params
if(!macro_file.isEmpty())
{
foreach(const QString &f, fileList)
{
QString path = QDir::toNativeSeparators(QFileInfo(workspaceDir + PATH_SEPARATOR + f).absoluteFilePath());
QString macro = macro_file;
path = macro.replace(MACRO_FILE, path, Qt::CaseInsensitive);
params.append(path);
}
}
// Build folder params
if(!macro_folder.isEmpty())
{
foreach(const QString &f, pathSet)
{
QString path = QDir::toNativeSeparators(QFileInfo(workspaceDir + PATH_SEPARATOR + f).absoluteFilePath());
QString macro = macro_folder;
path = macro.replace(MACRO_FOLDER, path, Qt::CaseInsensitive);
params.append(path);
}
}
uiCallback.logText("<b>"+cmd + " "+params.join(" ")+"</b><br>", true);
QProcess proc(processParent);
return proc.startDetached(cmd, params);
}

View File

@ -3,73 +3,12 @@
#include <QString>
#include <QMessageBox>
#include <QMap>
#include <QStandardItem>
#include <QSet>
#include <QSettings>
#define COUNTOF(array) (sizeof(array)/sizeof(array[0]))
#define FOSSIL_CHECKOUT1 "_FOSSIL_"
#define FOSSIL_CHECKOUT2 ".fslckout"
#define FOSSIL_EXT "fossil"
#define PATH_SEPARATOR "/"
typedef QSet<QString> stringset_t;
class UICallback
{
public:
virtual void logText(const QString &text, bool isHTML)=0;
virtual void beginProcess(const QString &text)=0;
virtual void updateProcess(const QString &text)=0;
virtual void endProcess()=0;
virtual QMessageBox::StandardButton Query(const QString &title, const QString &query, QMessageBox::StandardButtons buttons)=0;
};
class ScopedStatus
{
public:
ScopedStatus(UICallback *callback, const QString &text) : uiCallback(callback)
{
uiCallback->beginProcess(text);
}
~ScopedStatus()
{
uiCallback->endProcess();
}
private:
UICallback *uiCallback;
};
QMessageBox::StandardButton DialogQuery(QWidget *parent, const QString &title, const QString &query, QMessageBox::StandardButtons buttons = QMessageBox::Yes|QMessageBox::No);
QString QuotePath(const QString &path);
QStringList QuotePaths(const QStringList &paths);
QString SelectExe(QWidget *parent, const QString &description);
typedef QMap<QString, QModelIndex> name_modelindex_map_t;
void GetStandardItemTextRecursive(QString &name, const QStandardItem &item, const QChar &separator='/');
void BuildNameToModelIndex(name_modelindex_map_t &map, const QStandardItem &item);
void BuildNameToModelIndex(name_modelindex_map_t &map, const QStandardItemModel &model);
bool KeychainSet(QObject* parent, const QUrl& url, QSettings &settings);
bool KeychainGet(QObject* parent, QUrl& url, QSettings &settings);
bool KeychainDelete(QObject* parent, const QUrl& url, QSettings &settings);
QString HashString(const QString &str);
QString UrlToStringDisplay(const QUrl &url);
QString UrlToStringNoCredentials(const QUrl& url);
void SplitCommandLine(const QString &commandLine, QString &command, QString &extraParams);
bool SpawnExternalProcess(QObject *processParent, const QString& command, const QStringList& fileList, const stringset_t& pathSet, const QString &workspaceDir, UICallback &uiCallback);
typedef QMap<QString, QString> QStringMap;
void ParseProperties(QStringMap &properties, const QStringList &lines, QChar separator=' ');
#ifdef Q_OS_WIN
bool ShowExplorerMenu(HWND hwnd, const QString &path, const QPoint &qpoint);
#endif
#endif // UTILS_H

View File

@ -1,431 +0,0 @@
#include "Workspace.h"
#include <QCoreApplication>
#include "Utils.h"
//-----------------------------------------------------------------------------
Workspace::Workspace()
{
}
//-----------------------------------------------------------------------------
Workspace::~Workspace()
{
clearState();
remotes.clear();
}
//------------------------------------------------------------------------------
void Workspace::clearState()
{
// Dispose RepoFiles
foreach(WorkspaceFile *r, getFiles())
delete r;
getFiles().clear();
getPaths().clear();
pathState.clear();
stashMap.clear();
branchList.clear();
tags.clear();
isIntegrated = false;
}
//------------------------------------------------------------------------------
void Workspace::storeWorkspace(QSettings &store)
{
QString workspace = fossil().getWorkspacePath();
if(workspace.isEmpty())
return;
store.beginGroup("Remotes");
QString workspace_hash = HashString(QDir::toNativeSeparators(workspace));
store.beginWriteArray(workspace_hash);
int index = 0;
for(remote_map_t::iterator it=remotes.begin(); it!=remotes.end(); ++it, ++index)
{
store.setArrayIndex(index);
store.setValue("Name", it->name);
QUrl url = it->url;
url.setPassword("");
store.setValue("Url", url);
if(it->isDefault)
store.setValue("Default", it->isDefault);
else
store.remove("Default");
}
store.endArray();
store.endGroup();
}
//------------------------------------------------------------------------------
bool Workspace::switchWorkspace(const QString& workspace, QSettings &store)
{
// Save Remotes
storeWorkspace(store);
clearState();
remotes.clear();
fossil().setWorkspacePath("");
if(workspace.isEmpty())
return true;
QString new_workspace = QFileInfo(workspace).absoluteFilePath();
if(!QDir::setCurrent(new_workspace))
return false;
fossil().setWorkspacePath(new_workspace);
// Load Remotes
QString workspace_hash = HashString(QDir::toNativeSeparators(new_workspace));
QString gr = store.group();
store.beginGroup("Remotes");
gr = store.group();
int num_remotes = store.beginReadArray(workspace_hash);
for(int i=0; i<num_remotes; ++i)
{
store.setArrayIndex(i);
QString name = store.value("Name").toString();
QUrl url = store.value("Url").toUrl();
bool def = store.value("Default", false).toBool();
addRemote(url, name);
if(def)
setRemoteDefault(url);
}
store.endArray();
store.endGroup();
#if 0 // FIXME: Disabled this because if fossil's remote does not match exactly what we have stored (url and username), it will be automatically added every-time
// Add the default url from fossil
QUrl default_remote;
if(fossil().getRemoteUrl(default_remote) && default_remote.isValid() && !default_remote.isEmpty())
{
default_remote.setPassword("");
// Add Default remote if not available already
if(findRemote(default_remote)==NULL)
{
addRemote(default_remote, UrlToStringDisplay(default_remote));
if(getRemoteDefault().isEmpty())
setRemoteDefault(default_remote);
}
}
#endif
return true;
}
//------------------------------------------------------------------------------
bool Workspace::scanDirectory(QFileInfoList &entries, const QString& dirPath, const QString &baseDir, const QString ignoreSpec, const bool &abort, UICallback &uiCallback)
{
QDir dir(dirPath);
uiCallback.updateProcess(dirPath);
QFileInfoList list = dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::Hidden | QDir::NoDotAndDotDot);
for (int i=0; i<list.count(); ++i)
{
if(abort)
return false;
QFileInfo info = list[i];
QString filepath = info.filePath();
QString rel_path = filepath;
rel_path.remove(baseDir+PATH_SEPARATOR);
// Skip ignored files
if(!ignoreSpec.isEmpty() && QDir::match(ignoreSpec, rel_path))
continue;
if (info.isDir())
{
if(!scanDirectory(entries, filepath, baseDir, ignoreSpec, abort, uiCallback))
return false;
}
else
entries.push_back(info);
}
return true;
}
//------------------------------------------------------------------------------
static bool StringLengthDescending(const QString &l, const QString &r)
{
return l.length() > r.length();
}
//------------------------------------------------------------------------------
void Workspace::scanWorkspace(bool scanLocal, bool scanIgnored, bool scanModified, bool scanUnchanged, const QString &ignoreGlob, UICallback &uiCallback, bool &operationAborted)
{
// Scan all workspace files
QFileInfoList all_files;
QString wkdir = fossil().getWorkspacePath();
if(wkdir.isEmpty())
return;
// Retrieve the status of files tracked by fossil
QStringList res;
if(!fossil().listFiles(res))
return;
bool scan_files = scanLocal;
clearState();
QStringList paths;
operationAborted = false;
uiCallback.beginProcess("");
if(scan_files)
{
QCoreApplication::processEvents();
QString ignore;
// If we should not be showing ignored files, fill in the ignored spec
if(!scanIgnored)
{
// QDir expects multiple specs being separated by a semicolon
ignore = ignoreGlob;
ignore.replace(',',';');
}
if(!scanDirectory(all_files, wkdir, wkdir, ignore, operationAborted, uiCallback))
goto _done;
for(QFileInfoList::iterator it=all_files.begin(); it!=all_files.end(); ++it)
{
QString filename = it->fileName();
QString fullpath = it->absoluteFilePath();
// Skip fossil files
if(filename == FOSSIL_CHECKOUT1 || filename == FOSSIL_CHECKOUT2 || (!fossil().getRepositoryFile().isEmpty() && QFileInfo(fullpath) == QFileInfo(fossil().getRepositoryFile())))
continue;
WorkspaceFile::Type type = WorkspaceFile::TYPE_UNKNOWN;
WorkspaceFile *rf = new WorkspaceFile(*it, type, wkdir);
const QString &path = rf->getPath();
getFiles().insert(rf->getFilePath(), rf);
getPaths().insert(path);
// Add or merge file state into directory state
pathstate_map_t::iterator state_it = pathState.find(path);
if(state_it != pathState.end())
state_it.value() = static_cast<WorkspaceFile::Type>(state_it.value() | type);
else
{
pathState.insert(path, type);
paths.append(path); // keep path in list for depth sort
}
}
}
uiCallback.endProcess();
uiCallback.beginProcess(QObject::tr("Updating..."));
// Update Files and Directories
for(QStringList::iterator line_it=res.begin(); line_it!=res.end(); ++line_it)
{
QString line = (*line_it).trimmed();
if(line.length()==0)
continue;
int space_index = line.indexOf(' ');
if(space_index==-1)
continue;
QString status_text = line.left(space_index);
QString fname = line.right(line.length() - space_index).trimmed();
WorkspaceFile::Type type = WorkspaceFile::TYPE_UNKNOWN;
// Generate a RepoFile for all non-existant fossil files
// or for all files if we skipped scanning the workspace
bool add_missing = !scan_files;
if(status_text=="EDITED")
type = WorkspaceFile::TYPE_EDITTED;
else if(status_text=="ADDED")
type = WorkspaceFile::TYPE_ADDED;
else if(status_text=="DELETED")
{
type = WorkspaceFile::TYPE_DELETED;
add_missing = true;
}
else if(status_text=="MISSING")
{
type = WorkspaceFile::TYPE_MISSING;
add_missing = true;
}
else if(status_text=="RENAMED")
type = WorkspaceFile::TYPE_RENAMED;
else if(status_text=="UNCHANGED")
type = WorkspaceFile::TYPE_UNCHANGED;
else if(status_text=="CONFLICT")
type = WorkspaceFile::TYPE_CONFLICTED;
else if(status_text=="UPDATED_BY_MERGE" || status_text=="ADDED_BY_MERGE" || status_text=="ADDED_BY_INTEGRATE" || status_text=="UPDATED_BY_INTEGRATE")
type = WorkspaceFile::TYPE_MERGED;
// Filter unwanted file types
if( ((type & WorkspaceFile::TYPE_MODIFIED) && !scanModified) ||
((type & WorkspaceFile::TYPE_UNCHANGED) && !scanUnchanged))
{
getFiles().remove(fname);
continue;
}
else
add_missing = true;
Workspace::filemap_t::iterator it = getFiles().find(fname);
WorkspaceFile *rf = 0;
if(add_missing && it==getFiles().end())
{
QFileInfo info(wkdir+QDir::separator()+fname);
rf = new WorkspaceFile(info, type, wkdir);
getFiles().insert(rf->getFilePath(), rf);
}
if(!rf)
{
it = getFiles().find(fname);
Q_ASSERT(it!=getFiles().end());
rf = *it;
}
rf->setType(type);
QString path = rf->getPath();
getPaths().insert(path);
// Add or merge file state into directory state
pathstate_map_t::iterator state_it = pathState.find(path);
if(state_it != pathState.end())
state_it.value() = static_cast<WorkspaceFile::Type>(state_it.value() | type);
else
{
pathState.insert(path, type);
paths.append(path); // keep path in list for depth sort
}
}
// Sort paths, so that children (longer path) are before parents (shorter path)
std::sort(paths.begin(), paths.end(), StringLengthDescending);
foreach(const QString &p, paths)
{
pathstate_map_t::iterator state_it = pathState.find(p);
Q_ASSERT(state_it != pathState.end());
WorkspaceFile::Type state = state_it.value();
// Propagate child dir state to parents
QString parent_path = p;
while(!parent_path.isEmpty())
{
// Extract parent path
int sep_index = parent_path.lastIndexOf(PATH_SEPARATOR);
if(sep_index>=0)
parent_path = parent_path.left(sep_index);
else
parent_path = "";
// Merge path of child to parent
pathstate_map_t::iterator state_it = pathState.find(parent_path);
if(state_it != pathState.end())
state_it.value() = static_cast<WorkspaceFile::Type>(state_it.value() | state);
else
pathState.insert(parent_path, state);
}
}
// Check if the repository needs integration
res.clear();
fossil().status(res);
isIntegrated = false;
foreach(const QString &l, res)
{
if(l.trimmed().indexOf("INTEGRATE")==0)
{
isIntegrated = true;
break;
}
}
// Load the stashes, branches and tags
fossil().stashList(getStashes());
fossil().branchList(branchList, branchList);
fossil().tagList(tags);
// Fossil includes the branches in the tag list
// So remove them
foreach(const QString &name, branchList)
tags.remove(name);
_done:
uiCallback.endProcess();
}
//------------------------------------------------------------------------------
bool Workspace::addRemote(const QUrl& url, const QString& name)
{
if(remotes.contains(url))
return false;
Q_ASSERT(url.password().isEmpty());
Remote r(name, url);
remotes.insert(url, r);
return true;
}
//------------------------------------------------------------------------------
bool Workspace::removeRemote(const QUrl& url)
{
return remotes.remove(url) > 0;
}
//------------------------------------------------------------------------------
bool Workspace::setRemoteDefault(const QUrl& url)
{
Q_ASSERT(url.password().isEmpty());
bool found = false;
for(remote_map_t::iterator it=remotes.begin(); it!=remotes.end(); ++it)
{
if(it->url == url)
{
it->isDefault = true;
found = true;
}
else
it->isDefault = false;
}
return found;
}
//------------------------------------------------------------------------------
QUrl Workspace::getRemoteDefault() const
{
for(remote_map_t::const_iterator it=remotes.begin(); it!=remotes.end(); ++it)
{
if(it->isDefault)
return it->url;
}
return QUrl();
}
//------------------------------------------------------------------------------
Remote * Workspace::findRemote(const QUrl& url)
{
remote_map_t::iterator it = remotes.find(url);
if(it!=remotes.end())
return &(*it);
return NULL;
}

View File

@ -1,180 +0,0 @@
#ifndef WORKSPACE_H
#define WORKSPACE_H
#include <QStandardItemModel>
#include <QFileInfo>
#include <QDir>
#include <QSet>
#include <QMap>
#include <QSettings>
#include "Utils.h"
#include "Fossil.h"
//////////////////////////////////////////////////////////////////////////
// WorkspaceFile
//////////////////////////////////////////////////////////////////////////
struct WorkspaceFile
{
enum Type
{
TYPE_UNKNOWN = 1<<0,
TYPE_UNCHANGED = 1<<1,
TYPE_EDITTED = 1<<2,
TYPE_ADDED = 1<<3,
TYPE_DELETED = 1<<4,
TYPE_MISSING = 1<<5,
TYPE_RENAMED = 1<<6,
TYPE_CONFLICTED = 1<<7,
TYPE_MERGED = 1<<8,
TYPE_MODIFIED = TYPE_EDITTED|TYPE_ADDED|TYPE_DELETED|TYPE_MISSING|TYPE_RENAMED|TYPE_CONFLICTED|TYPE_MERGED,
TYPE_REPO = TYPE_UNCHANGED|TYPE_MODIFIED,
TYPE_ALL = TYPE_UNKNOWN|TYPE_REPO
};
WorkspaceFile(const QFileInfo &info, Type type, const QString &repoPath)
{
FileInfo = info;
FileType = type;
FilePath = getRelativeFilename(repoPath);
Path = FileInfo.absolutePath();
// Strip the workspace path from the path
Q_ASSERT(Path.indexOf(repoPath)==0);
Path = Path.mid(repoPath.length()+1);
}
bool isType(Type t) const
{
return FileType == t;
}
void setType(Type t)
{
FileType = t;
}
Type getType() const
{
return FileType;
}
QFileInfo getFileInfo() const
{
return FileInfo;
}
const QString &getFilePath() const
{
return FilePath;
}
QString getFilename() const
{
return FileInfo.fileName();
}
const QString &getPath() const
{
return Path;
}
QString getRelativeFilename(const QString &path)
{
QString abs_base_dir = QDir(path).absolutePath();
QString relative = FileInfo.absoluteFilePath();
int index = relative.indexOf(abs_base_dir);
if(index<0)
return QString("");
return relative.right(relative.length() - abs_base_dir.length()-1);
}
private:
QFileInfo FileInfo;
Type FileType;
QString FilePath;
QString Path;
};
class Remote
{
public:
Remote(const QString &_name, const QUrl &_url, bool _isDefault=false)
: name(_name), url(_url), isDefault(_isDefault)
{
}
QString name;
QUrl url;
bool isDefault;
};
typedef QMap<QUrl, Remote> remote_map_t;
typedef QMap<QString, WorkspaceFile::Type> pathstate_map_t;
//////////////////////////////////////////////////////////////////////////
// Workspace
//////////////////////////////////////////////////////////////////////////
class Workspace
{
public:
Workspace();
~Workspace();
typedef QList<WorkspaceFile*> filelist_t;
typedef QMap<QString, WorkspaceFile*> filemap_t;
void clearState();
Fossil & fossil() { return bridge; }
const Fossil & fossil() const { return bridge; }
const QString & getPath() const { return fossil().getWorkspacePath(); }
bool switchWorkspace(const QString &workspace, QSettings &store);
void scanWorkspace(bool scanLocal, bool scanIgnored, bool scanModified, bool scanUnchanged, const QString &ignoreGlob, UICallback &uiCallback, bool &operationAborted);
QStandardItemModel &getFileModel() { return repoFileModel; }
QStandardItemModel &getTreeModel() { return repoTreeModel; }
filemap_t &getFiles() { return workspaceFiles; }
stringset_t &getPaths() { return pathSet; }
pathstate_map_t &getPathState() { return pathState; }
stashmap_t &getStashes() { return stashMap; }
QStringMap &getTags() { return tags; }
QStringList &getBranches() { return branchList; }
bool otherChanges() const { return isIntegrated; }
const QString &getCurrentRevision() const { return fossil().getCurrentRevision(); }
const QStringList &getActiveTags() const { return fossil().getActiveTags(); }
const QString &getProjectName() const { return fossil().getProjectName(); }
// Remotes
const remote_map_t &getRemotes() const { return remotes; }
bool addRemote(const QUrl &url, const QString &name);
bool removeRemote(const QUrl &url);
bool setRemoteDefault(const QUrl& url);
QUrl getRemoteDefault() const;
Remote * findRemote(const QUrl& url);
void storeWorkspace(QSettings &store);
private:
static bool scanDirectory(QFileInfoList &entries, const QString& dirPath, const QString &baseDir, const QString ignoreSpec, const bool& abort, UICallback &uiCallback);
private:
Fossil bridge;
filemap_t workspaceFiles;
stringset_t pathSet;
pathstate_map_t pathState;
stashmap_t stashMap;
QStringList branchList;
QStringMap tags;
remote_map_t remotes;
bool isIntegrated;
QStandardItemModel repoFileModel;
QStandardItemModel repoTreeModel;
};
#endif // WORKSPACE_H

View File

@ -5,7 +5,7 @@ int main(int argc, char *argv[])
{
QApplication app(argc, argv);
app.setApplicationName("Fuel");
app.setApplicationVersion("2.0.0");
app.setApplicationVersion("1.0.1");
app.setOrganizationDomain("fuel-scm.org");
app.setOrganizationName("Fuel-SCM");

View File

@ -1,132 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AboutDialog</class>
<widget class="QDialog" name="AboutDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>577</width>
<height>349</height>
</rect>
</property>
<property name="windowTitle">
<string>About Fuel...</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="lblIcon">
<property name="maximumSize">
<size>
<width>64</width>
<height>64</height>
</size>
</property>
<property name="text">
<string notr="true"/>
</property>
<property name="pixmap">
<pixmap resource="../rsrc/resources.qrc">:/icons/icon-application</pixmap>
</property>
<property name="scaledContents">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignHCenter|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblBanner">
<property name="text">
<string>A GUI front-end for the Fossil SCM by Kostas Karanikolas
Released under the GNU GPL</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="lblFossilVersion">
<property name="text">
<string notr="true">FOSSIL VERSION</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="lblQtVersion">
<property name="text">
<string notr="true">QT VERSION</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QTextEdit" name="txtAdditional">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../rsrc/resources.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>AboutDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>AboutDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -14,16 +14,7 @@
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>0</number>
</property>
<item>
@ -53,7 +44,7 @@
<action name="actionBrowserBack">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-previous</normaloff>:/icons/icon-action-previous</iconset>
<normaloff>:/icons/icons/Button Previous-01.png</normaloff>:/icons/icons/Button Previous-01.png</iconset>
</property>
<property name="text">
<string>Back</string>
@ -65,7 +56,7 @@
<action name="actionBrowserForward">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-next</normaloff>:/icons/icon-action-next</iconset>
<normaloff>:/icons/icons/Button Next-01.png</normaloff>:/icons/icons/Button Next-01.png</iconset>
</property>
<property name="text">
<string>Forward</string>
@ -77,7 +68,7 @@
<action name="actionBrowserRefresh">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-refresh</normaloff>:/icons/icon-action-refresh</iconset>
<normaloff>:/icons/icons/Button Refresh-01.png</normaloff>:/icons/icons/Button Refresh-01.png</iconset>
</property>
<property name="text">
<string>Refresh</string>
@ -89,7 +80,7 @@
<action name="actionBrowserStop">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-stop</normaloff>:/icons/icon-action-stop</iconset>
<normaloff>:/icons/icons/Button Close-01.png</normaloff>:/icons/icons/Button Close-01.png</iconset>
</property>
<property name="text">
<string>Stop</string>

View File

@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>400</width>
<height>394</height>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
@ -21,11 +21,7 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QComboBox" name="comboBox">
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum>
</property>
</widget>
<widget class="QComboBox" name="comboBox"/>
</item>
<item>
<widget class="QLineEdit" name="lineEdit"/>
@ -66,99 +62,12 @@
</widget>
</item>
<item>
<widget class="QWidget" name="widgetBranchOptions" native="true">
<layout class="QFormLayout" name="formLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Commit to new branch</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="chkNewBranch">
<widget class="QCheckBox" name="checkBox">
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="lblPrivateBranch">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Private branch</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="chkPrivateBranch">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Branch name</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineBranchName">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QCheckBox" name="chkRevertFiles">
<property name="text">
<string>Revert stashed files</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">

View File

@ -1,272 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FslSettingsDialog</class>
<widget class="QDialog" name="FslSettingsDialog">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>457</width>
<height>235</height>
</rect>
</property>
<property name="windowTitle">
<string>Fossil Settings</string>
</property>
<property name="windowIcon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-application</normaloff>:/icons/icon-application</iconset>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QFormLayout" name="formLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Graphical Diff </string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLineEdit" name="lineGDiffCommand">
<property name="toolTip">
<string>Path to graphical diff tool</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSelectFossilGDiff">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Graphical Merge</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<widget class="QLineEdit" name="lineGMergeCommand">
<property name="toolTip">
<string>Path to the graphical merge tool</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSelectGMerge">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_44">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>HTTP Proxy</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineProxy">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>The URL of the HTTP proxy</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="uILanguageLabel_3">
<property name="text">
<string>HTTP Port</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineUIPort">
<property name="toolTip">
<string>HTTP port to use for the Fossil web interface</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_7">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Ignore CR/NL</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineIgnoreCRNL">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>A comma separated list of glob-style file patterns to exclude from Fossil's CR/NL consistency checking</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_4">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Ignore List</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="lineIgnore">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>A comma separated list of glob-style file/path patterns ignored in Fossil file operations</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../rsrc/resources.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>FslSettingsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>FslSettingsDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -18,7 +18,7 @@
</property>
<property name="windowIcon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-application</normaloff>:/icons/icon-application</iconset>
<normaloff>:/icons/icons/Battery-01.png</normaloff>:/icons/icons/Battery-01.png</iconset>
</property>
<property name="unifiedTitleAndToolBarOnMac">
<bool>true</bool>
@ -38,7 +38,7 @@
<number>4</number>
</property>
<item>
<widget class="QSplitter" name="splitterVertical">
<widget class="QSplitter" name="splitter_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
@ -48,7 +48,7 @@
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QSplitter" name="splitterHorizontal">
<widget class="QSplitter" name="splitter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
@ -58,7 +58,7 @@
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTreeView" name="workspaceTreeView">
<widget class="QTreeView" name="treeView">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>20</horstretch>
@ -66,7 +66,7 @@
</sizepolicy>
</property>
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
@ -78,13 +78,16 @@
<enum>QAbstractItemView::SelectItems</enum>
</property>
<property name="sortingEnabled">
<bool>false</bool>
<bool>true</bool>
</property>
<attribute name="headerVisible">
<bool>true</bool>
</attribute>
<attribute name="headerShowSortIndicator" stdset="0">
<bool>false</bool>
</attribute>
</widget>
<widget class="FileTableView" name="fileTableView">
<widget class="FileTableView" name="tableView">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>80</horstretch>
@ -137,6 +140,44 @@
<number>30</number>
</attribute>
</widget>
<widget class="QTableView" name="tableViewStash">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>20</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="showGrid">
<bool>false</bool>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<attribute name="horizontalHeaderHighlightSections">
<bool>false</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
</widget>
</widget>
<widget class="QTabWidget" name="tabWidget">
<property name="sizePolicy">
@ -149,7 +190,7 @@
<enum>QTabWidget::South</enum>
</property>
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="tabLog">
<attribute name="title">
@ -222,7 +263,7 @@
<x>0</x>
<y>0</y>
<width>865</width>
<height>23</height>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
@ -250,39 +291,16 @@
<property name="title">
<string>&amp;View</string>
</property>
<addaction name="actionViewAll"/>
<addaction name="actionViewModifedOnly"/>
<addaction name="separator"/>
<addaction name="actionViewModified"/>
<addaction name="actionViewUnchanged"/>
<addaction name="actionViewUnknown"/>
<addaction name="actionViewIgnored"/>
<addaction name="separator"/>
<addaction name="actionViewStash"/>
<addaction name="separator"/>
<addaction name="actionViewAsList"/>
<addaction name="actionViewAsFolders"/>
</widget>
<widget class="QMenu" name="menuWorkspace">
<property name="title">
<string>&amp;Workspace</string>
</property>
<addaction name="actionRefresh"/>
<addaction name="separator"/>
<addaction name="actionCommit"/>
<addaction name="actionUpdate"/>
<addaction name="separator"/>
<addaction name="actionPush"/>
<addaction name="actionPull"/>
<addaction name="separator"/>
<addaction name="actionUndo"/>
<addaction name="separator"/>
<addaction name="actionCreateBranch"/>
<addaction name="actionCreateTag"/>
<addaction name="actionCreateStash"/>
<addaction name="separator"/>
<addaction name="actionFossilSettings"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuWorkspace"/>
<addaction name="menuView"/>
<addaction name="menuHelp"/>
</widget>
@ -325,6 +343,8 @@
<addaction name="actionRevert"/>
<addaction name="actionDelete"/>
<addaction name="separator"/>
<addaction name="actionNewStash"/>
<addaction name="separator"/>
<addaction name="actionDiff"/>
<addaction name="actionHistory"/>
<addaction name="separator"/>
@ -337,10 +357,10 @@
<action name="actionRefresh">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-refresh</normaloff>:/icons/icon-action-refresh</iconset>
<normaloff>:/icons/icons/Button Refresh-01.png</normaloff>:/icons/icons/Button Refresh-01.png</iconset>
</property>
<property name="text">
<string>&amp;Refresh</string>
<string>Refresh</string>
</property>
<property name="toolTip">
<string>Refresh the views</string>
@ -355,10 +375,10 @@
<action name="actionCommit">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-commit</normaloff>:/icons/icon-action-commit</iconset>
<normaloff>:/icons/icons/Save-01.png</normaloff>:/icons/icons/Save-01.png</iconset>
</property>
<property name="text">
<string>&amp;Commit</string>
<string>Commit</string>
</property>
<property name="toolTip">
<string>Commit modifications</string>
@ -373,7 +393,7 @@
<action name="actionDiff">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-item-diff</normaloff>:/icons/icon-item-diff</iconset>
<normaloff>:/icons/icons/Document Copy-01.png</normaloff>:/icons/icons/Document Copy-01.png</iconset>
</property>
<property name="text">
<string>Diff</string>
@ -391,7 +411,7 @@
<action name="actionAdd">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-item-add</normaloff>:/icons/icon-item-add</iconset>
<normaloff>:/icons/icons/File New-01.png</normaloff>:/icons/icons/File New-01.png</iconset>
</property>
<property name="text">
<string>Add</string>
@ -409,7 +429,7 @@
<action name="actionDelete">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-item-delete</normaloff>:/icons/icon-item-delete</iconset>
<normaloff>:/icons/icons/File Delete-01.png</normaloff>:/icons/icons/File Delete-01.png</iconset>
</property>
<property name="text">
<string>Delete</string>
@ -427,7 +447,7 @@
<action name="actionNewRepository">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-repo-new</normaloff>:/icons/icon-action-repo-new</iconset>
<normaloff>:/icons/icons/Document Blank-01.png</normaloff>:/icons/icons/Document Blank-01.png</iconset>
</property>
<property name="text">
<string>&amp;New...</string>
@ -445,7 +465,7 @@
<action name="actionOpenRepository">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-repo-open</normaloff>:/icons/icon-action-repo-open</iconset>
<normaloff>:/icons/icons/My Documents-01.png</normaloff>:/icons/icons/My Documents-01.png</iconset>
</property>
<property name="text">
<string>&amp;Open...</string>
@ -477,10 +497,10 @@
<action name="actionCloneRepository">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-repo-clone</normaloff>:/icons/icon-action-repo-clone</iconset>
<normaloff>:/icons/icons/My Websites-01.png</normaloff>:/icons/icons/My Websites-01.png</iconset>
</property>
<property name="text">
<string>C&amp;lone...</string>
<string>Clone...</string>
</property>
<property name="statusTip">
<string>Clone a remote repository</string>
@ -489,13 +509,13 @@
<action name="actionPush">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-push</normaloff>:/icons/icon-action-push</iconset>
<normaloff>:/icons/icons/Button Upload-01.png</normaloff>:/icons/icons/Button Upload-01.png</iconset>
</property>
<property name="text">
<string>&amp;Push</string>
<string>Push</string>
</property>
<property name="toolTip">
<string>Push changes to the default remote repository</string>
<string>Push changes to the remote repository</string>
</property>
<property name="statusTip">
<string>Push changes to the remote repository</string>
@ -507,13 +527,13 @@
<action name="actionPull">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-pull</normaloff>:/icons/icon-action-pull</iconset>
<normaloff>:/icons/icons/Button Download-01.png</normaloff>:/icons/icons/Button Download-01.png</iconset>
</property>
<property name="text">
<string>Pu&amp;ll</string>
<string>Pull</string>
</property>
<property name="toolTip">
<string>Pull changes from the default remote repository</string>
<string>Pull changes from the remote repository</string>
</property>
<property name="statusTip">
<string>Pull changes from the remote repository</string>
@ -522,40 +542,10 @@
<string>Ctrl+L</string>
</property>
</action>
<action name="actionPushRemote">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-push</normaloff>:/icons/icon-action-push</iconset>
</property>
<property name="text">
<string>&amp;Push to Remote</string>
</property>
<property name="toolTip">
<string>Push changes to a remote repository</string>
</property>
<property name="statusTip">
<string>Push changes to a remote repository</string>
</property>
</action>
<action name="actionPullRemote">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-pull</normaloff>:/icons/icon-action-pull</iconset>
</property>
<property name="text">
<string>Pu&amp;ll from Remote</string>
</property>
<property name="toolTip">
<string>Pull changes from a remote repository</string>
</property>
<property name="statusTip">
<string>Pull changes from a remote repository</string>
</property>
</action>
<action name="actionRename">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-item-rename</normaloff>:/icons/icon-item-rename</iconset>
<normaloff>:/icons/icons/File Open-01.png</normaloff>:/icons/icons/File Open-01.png</iconset>
</property>
<property name="text">
<string>Rename</string>
@ -573,7 +563,7 @@
<action name="actionQuit">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-quit</normaloff>:/icons/icon-action-quit</iconset>
<normaloff>:/icons/icons/Button Turn Off-01.png</normaloff>:/icons/icons/Button Turn Off-01.png</iconset>
</property>
<property name="text">
<string>&amp;Quit</string>
@ -594,7 +584,7 @@
<action name="actionHistory">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-item-history</normaloff>:/icons/icon-item-history</iconset>
<normaloff>:/icons/icons/File History-01.png</normaloff>:/icons/icons/File History-01.png</iconset>
</property>
<property name="text">
<string>History</string>
@ -615,7 +605,7 @@
</property>
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-webview</normaloff>:/icons/icon-webview</iconset>
<normaloff>:/icons/icons/Network MAC-01.png</normaloff>:/icons/icons/Network MAC-01.png</iconset>
</property>
<property name="text">
<string>Fossil UI</string>
@ -630,7 +620,7 @@
<action name="actionRevert">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-item-revert</normaloff>:/icons/icon-item-revert</iconset>
<normaloff>:/icons/icons/Document-Revert-icon.png</normaloff>:/icons/icons/Document-Revert-icon.png</iconset>
</property>
<property name="text">
<string>Revert</string>
@ -645,7 +635,7 @@
<action name="actionClearLog">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-clear-log</normaloff>:/icons/icon-clear-log</iconset>
<normaloff>:/icons/icons/Text Edit.png</normaloff>:/icons/icons/Text Edit.png</iconset>
</property>
<property name="text">
<string>Clear Log</string>
@ -660,7 +650,7 @@
<action name="actionTimeline">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-timeline</normaloff>:/icons/icon-action-timeline</iconset>
<normaloff>:/icons/icons/Clock-01.png</normaloff>:/icons/icons/Clock-01.png</iconset>
</property>
<property name="text">
<string>Timeline</string>
@ -675,7 +665,7 @@
<action name="actionOpenFile">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-item-file</normaloff>:/icons/icon-item-file</iconset>
<normaloff>:/icons/icons/Document-01.png</normaloff>:/icons/icons/Document-01.png</iconset>
</property>
<property name="text">
<string>Open File</string>
@ -693,7 +683,7 @@
<action name="actionOpenContaining">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-folder-explore</normaloff>:/icons/icon-action-folder-explore</iconset>
<normaloff>:/icons/icons/Folder-01.png</normaloff>:/icons/icons/Folder-01.png</iconset>
</property>
<property name="text">
<string>Open Containing</string>
@ -711,10 +701,10 @@
<action name="actionUndo">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-undo</normaloff>:/icons/icon-action-undo</iconset>
<normaloff>:/icons/icons/Button Reload-01.png</normaloff>:/icons/icons/Button Reload-01.png</iconset>
</property>
<property name="text">
<string>U&amp;ndo</string>
<string>Undo</string>
</property>
<property name="toolTip">
<string>Undo the last Fossil action</string>
@ -729,7 +719,7 @@
<action name="actionAbout">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-application</normaloff>:/icons/icon-application</iconset>
<normaloff>:/icons/icons/Battery-01.png</normaloff>:/icons/icons/Battery-01.png</iconset>
</property>
<property name="text">
<string>&amp;About...</string>
@ -744,13 +734,13 @@
<action name="actionUpdate">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-update</normaloff>:/icons/icon-action-update</iconset>
<normaloff>:/icons/icons/Button Play-01.png</normaloff>:/icons/icons/Button Play-01.png</iconset>
</property>
<property name="text">
<string>&amp;Update</string>
<string>Update</string>
</property>
<property name="toolTip">
<string>Update the workspace to a revision</string>
<string>Update the workspace to the latest version</string>
</property>
<property name="statusTip">
<string>Update the workspace to the latest version</string>
@ -762,7 +752,7 @@
<action name="actionSettings">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-settings</normaloff>:/icons/icon-action-settings</iconset>
<normaloff>:/icons/icons/Gear-01.png</normaloff>:/icons/icons/Gear-01.png</iconset>
</property>
<property name="text">
<string>&amp;Preferences...</string>
@ -785,7 +775,7 @@
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Modified Files</string>
<string>&amp;Modified</string>
</property>
<property name="statusTip">
<string>Show modifed files</string>
@ -799,7 +789,7 @@
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Unchanged Files</string>
<string>&amp;Unchanged</string>
</property>
<property name="statusTip">
<string>Show unchanged files</string>
@ -813,7 +803,7 @@
<bool>true</bool>
</property>
<property name="text">
<string>Un&amp;known Files</string>
<string>Un&amp;known</string>
</property>
<property name="statusTip">
<string>Show unknown files</string>
@ -824,7 +814,7 @@
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Ignored Files</string>
<string>&amp;Ignored</string>
</property>
<property name="statusTip">
<string>Show ignored files</string>
@ -850,7 +840,7 @@
<action name="actionOpenFolder">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-item-folder</normaloff>:/icons/icon-item-folder</iconset>
<normaloff>:/icons/icons/Folder-01.png</normaloff>:/icons/icons/Folder-01.png</iconset>
</property>
<property name="text">
<string>Open Folder</string>
@ -865,7 +855,7 @@
<action name="actionRenameFolder">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-folder-rename</normaloff>:/icons/icon-action-folder-rename</iconset>
<normaloff>:/icons/icons/Folder Open-01.png</normaloff>:/icons/icons/Folder Open-01.png</iconset>
</property>
<property name="text">
<string>Rename Folder</string>
@ -877,13 +867,13 @@
<string>Rename the selected folder</string>
</property>
</action>
<action name="actionCreateStash">
<action name="actionNewStash">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-stash-new</normaloff>:/icons/icon-action-stash-new</iconset>
<normaloff>:/icons/icons/Folder Add-01.png</normaloff>:/icons/icons/Folder Add-01.png</iconset>
</property>
<property name="text">
<string>&amp;Stash Changes</string>
<string>Stash changes</string>
</property>
<property name="statusTip">
<string>Stash changes</string>
@ -892,7 +882,7 @@
<action name="actionApplyStash">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-stash-apply</normaloff>:/icons/icon-action-stash-apply</iconset>
<normaloff>:/icons/icons/Folder Open-01.png</normaloff>:/icons/icons/Folder Open-01.png</iconset>
</property>
<property name="text">
<string>Apply Stash</string>
@ -904,10 +894,27 @@
<string>Apply stashed changes</string>
</property>
</action>
<action name="actionViewStash">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Stashed Changes</string>
</property>
<property name="iconText">
<string>View Stashed Changes</string>
</property>
<property name="toolTip">
<string>View Stashed Changes</string>
</property>
<property name="statusTip">
<string>Show the list of stashed changes</string>
</property>
</action>
<action name="actionDeleteStash">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-stash-delete</normaloff>:/icons/icon-action-stash-delete</iconset>
<normaloff>:/icons/icons/Folder Delete-01.png</normaloff>:/icons/icons/Folder Delete-01.png</iconset>
</property>
<property name="text">
<string>Delete Stash</string>
@ -916,137 +923,12 @@
<action name="actionDiffStash">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-stash-diff</normaloff>:/icons/icon-action-stash-diff</iconset>
<normaloff>:/icons/icons/Folder Explorer-01.png</normaloff>:/icons/icons/Folder Explorer-01.png</iconset>
</property>
<property name="text">
<string>Diff Stash</string>
</property>
</action>
<action name="actionCreateTag">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-tag-new</normaloff>:/icons/icon-action-tag-new</iconset>
</property>
<property name="text">
<string>Create &amp;Tag</string>
</property>
<property name="toolTip">
<string>Create a tag for a revision</string>
</property>
<property name="statusTip">
<string>Create a tag for a revision</string>
</property>
</action>
<action name="actionDeleteTag">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-tag-delete</normaloff>:/icons/icon-action-tag-delete</iconset>
</property>
<property name="text">
<string>Delete Tag</string>
</property>
<property name="toolTip">
<string>Delete Tag</string>
</property>
</action>
<action name="actionCreateBranch">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-item-branch</normaloff>:/icons/icon-item-branch</iconset>
</property>
<property name="text">
<string>Create &amp;Branch</string>
</property>
<property name="toolTip">
<string>Create a branch from a revision</string>
</property>
<property name="statusTip">
<string>Create a branch from a revision</string>
</property>
</action>
<action name="actionMergeBranch">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-merge</normaloff>:/icons/icon-action-merge</iconset>
</property>
<property name="text">
<string>Merge Branch</string>
</property>
<property name="toolTip">
<string>Merge with a branch</string>
</property>
<property name="statusTip">
<string>Merge with a branch</string>
</property>
</action>
<action name="actionViewAsFolders">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Files and F&amp;olders</string>
</property>
<property name="toolTip">
<string>View files and folders</string>
</property>
<property name="statusTip">
<string>View the workspace as files and folders</string>
</property>
</action>
<action name="actionViewAll">
<property name="text">
<string>&amp;All Files</string>
</property>
<property name="statusTip">
<string>Show all files</string>
</property>
</action>
<action name="actionViewModifedOnly">
<property name="text">
<string>Mo&amp;dified Files Only</string>
</property>
<property name="statusTip">
<string>Show modified files only</string>
</property>
</action>
<action name="actionFossilSettings">
<property name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-action-settings</normaloff>:/icons/icon-action-settings</iconset>
</property>
<property name="text">
<string>F&amp;ossil Settings</string>
</property>
</action>
<action name="actionEditRemote">
<property name="text">
<string>Edit Remote</string>
</property>
<property name="toolTip">
<string>Edit Remote URL</string>
</property>
</action>
<action name="actionSetDefaultRemote">
<property name="text">
<string>Set Remote as Default</string>
</property>
<property name="statusTip">
<string>Makes the selected remote </string>
</property>
</action>
<action name="actionAddRemote">
<property name="text">
<string>Add Remote</string>
</property>
<property name="statusTip">
<string>Adds a Remote Url</string>
</property>
</action>
<action name="actionDeleteRemote">
<property name="text">
<string>Delete Remote</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>

View File

@ -1,165 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RemoteDialog</class>
<widget class="QDialog" name="RemoteDialog">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>478</width>
<height>189</height>
</rect>
</property>
<property name="windowTitle">
<string>Remote Repository</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_1">
<property name="text">
<string>URL</string>
</property>
</widget>
</item>
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_11">
<item>
<widget class="QLineEdit" name="lineURL">
<property name="toolTip">
<string>The URL of the source repository</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSelectSourceRepo">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>User Name</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineUserName">
<property name="toolTip">
<string>The user name used to access the remote repository. Leave blank if not required</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Password</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="linePassword">
<property name="toolTip">
<string>The password used to access the remote repository. Leave blank if not required</string>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineName">
<property name="toolTip">
<string>The password used to access the remote repository. Leave blank if not required</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="Name">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>lineURL</tabstop>
<tabstop>btnSelectSourceRepo</tabstop>
<tabstop>lineUserName</tabstop>
<tabstop>linePassword</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>RemoteDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>RemoteDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,129 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RevisionDialog</class>
<widget class="QDialog" name="RevisionDialog">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>478</width>
<height>177</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>0</height>
</size>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="lblRevision">
<property name="text">
<string>Revision</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cmbRevision">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblName">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineName"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblIntegrate">
<property name="text">
<string>Integrate</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblForce">
<property name="text">
<string>Force</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="chkIntegrate">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QCheckBox" name="chkForce">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>RevisionDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>RevisionDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -9,23 +9,30 @@
<rect>
<x>0</x>
<y>0</y>
<width>449</width>
<height>428</height>
<width>457</width>
<height>352</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<property name="windowIcon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icon-application</normaloff>:/icons/icon-application</iconset>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="widget" native="true">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabApp">
<attribute name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icons/Battery-01.png</normaloff>:/icons/icons/Battery-01.png</iconset>
</attribute>
<attribute name="title">
<string>Application</string>
</attribute>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
@ -71,137 +78,6 @@
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Commit Messages</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="btnClearMessageHistory">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Clear the commit message history</string>
</property>
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="uILanguageLabel_2">
<property name="text">
<string>Web Browser</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="cmbFossilBrowser">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Web browser to use for the Fossil web interface</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_8">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Double-click Action</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="cmbDoubleClickAction">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Action to perfom when double-clicking a file</string>
</property>
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="uILanguageLabel">
<property name="text">
<string>Language</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="cmbActiveLanguage">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Language for the user interface</string>
</property>
</widget>
</item>
<item row="5" column="0" colspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Custom Actions</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Action</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cmbCustomAction">
<property name="toolTip">
<string>Custom action</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineCustomActionDescription">
<property name="toolTip">
<string>Name of custom action</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="minimumSize">
<size>
@ -210,34 +86,21 @@
</size>
</property>
<property name="text">
<string>Description</string>
<string>Graphical Diff </string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Command</string>
</property>
</widget>
</item>
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item row="1" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLineEdit" name="lineCustomActionCommand">
<widget class="QLineEdit" name="lineGDiffCommand">
<property name="toolTip">
<string>Custom action command-line. Information about the selected items is available via the macros %FILE %FOLDER %WORKSPACE</string>
<string>Path to graphical diff tool</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSelectCustomFileActionCommand">
<widget class="QPushButton" name="btnSelectFossilGDiff">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
@ -257,42 +120,287 @@
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Context</string>
<string>Graphical Merge</string>
</property>
</widget>
</item>
<item row="2" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<widget class="QLineEdit" name="lineGMergeCommand">
<property name="toolTip">
<string>Path to the graphical merge tool</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSelectGMerge">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_44">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>HTTP Proxy</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineProxy">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>The URL of the HTTP proxy</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="uILanguageLabel_3">
<property name="text">
<string>HTTP Port</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="cmbCustomActionContext">
<widget class="QLineEdit" name="lineUIPort">
<property name="toolTip">
<string>The context where this action will be available</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="chkCustomActionMultipleSelection">
<property name="toolTip">
<string>When checked this action supports multiple selected items</string>
</property>
<property name="text">
<string/>
<string>HTTP port to use for the Fossil web interface</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_7">
<widget class="QLabel" name="label_6">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Multiple Selection</string>
<string>Commit Messages</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QPushButton" name="btnClearMessageHistory">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Clear the commit message history</string>
</property>
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="uILanguageLabel_2">
<property name="text">
<string>Web Browser</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="cmbFossilBrowser">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Web browser to use for the Fossil web interface</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_8">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Double-click Action</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QComboBox" name="cmbDoubleClickAction">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Action to perfom when double-clicking a file</string>
</property>
<property name="currentIndex">
<number>-1</number>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="uILanguageLabel">
<property name="text">
<string>Language</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QComboBox" name="cmbActiveLanguage">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Language for the user interface</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabRepo">
<attribute name="icon">
<iconset resource="../rsrc/resources.qrc">
<normaloff>:/icons/icons/Book-01.png</normaloff>:/icons/icons/Book-01.png</iconset>
</attribute>
<attribute name="title">
<string>Repository</string>
</attribute>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::ExpandingFieldsGrow</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_5">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Remote Url</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="lineRemoteURL">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>The remote url used to push/pull changes.
URL style user names and passwords are also supported.
For example http://username:password@server.com/fossil</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Ignore List</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="lineIgnore">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>A comma separated list of glob-style file/path patterns ignored in Fossil file operations</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Ignore CR/NL</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineIgnoreCRNL">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>A comma separated list of glob-style file patterns to exclude from Fossil's CR/NL consistency checking</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">