diff --git a/.gitignore b/.gitignore
index d76b74e..a5c618a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,16 @@
-build
+# Build files and dirs
+build*
+
+# KDevelop and other IDE-specific project files
+*.kdev*
+
+# Doxygen files
+apidocs/
+kmess.tag
+
+# Mac stuff
.DS_Store
+finkbuild
+
+# ./configure script stuff
+Makefile
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..72173c7
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "contrib/isf-qt"]
+ path = contrib/isf-qt
+ url = git://gitorious.org/kmess/libisf-qt.git
diff --git a/.kdev4/kmess.kdev4 b/.kdev4/kmess.kdev4
deleted file mode 100644
index 64cb04c..0000000
--- a/.kdev4/kmess.kdev4
+++ /dev/null
@@ -1,43 +0,0 @@
-[Buildset]
-Number of Builditems=1
-
-[Buildset][Builditem0]
-Itemname=KMess
-Itempath=./
-Projectname=KMess
-
-[CMake]
-BuildDirs=./build
-CMakeDir=/usr/share/cmake/Modules
-Current CMake binary=cmake
-CurrentBuildDir=./build
-CurrentInstallDir=
-ProjectRootRelative=./
-
-[Chat Window debug-Run Options]
-Arguments=--runtest chatwindow
-Executable=./build/src/kmess
-Working Directory=./build/src/
-
-[Contact List debug-Run Options]
-Arguments=--runtest contactlist
-Executable=./build/src/kmess
-Working Directory=./build/src/
-
-[Debug-Run Options]
-Executable=./build/src/kmess
-
-[MakeBuilder]
-Abort on First Error=false
-Number Of Jobs=3
-Run Multiple Jobs=true
-
-[Project]
-VersionControlSupport=kdevsubversion
-
-[Run Options]
-Run Targets=Chat Window debug,Contact List debug,Debug
-
-[Veritas]
-executables=
-framework=QTest
diff --git a/AUTHORS b/AUTHORS
index 8995ded..de05a1f 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -83,6 +83,10 @@
Barthe Guillaume
Scias
+ Galician:
+
+ Indalecio Freiría Santos
+
German:
Jan Tönjes
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 344ad2d..c2eb1f8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,8 +25,7 @@ IF( NOT KDE4_FOUND )
" \n"
" You will need this package and the matching development package.\n"
" Usually the package names for this library are:\n"
- " on Debian: 'kdebase-runtime' and 'kdelibs4-dev'\n"
- " on Ubuntu: 'kdebase-runtime' and 'kdelibs5-dev'\n"
+ " on Debian and Ubuntu: 'kdebase-runtime' and 'kdelibs5-dev'\n"
" on openSUSE: 'kdebase4-runtime' and 'libkde4-devel'\n"
" \n"
" Please refer to the KMess board for more info,\n"
@@ -49,7 +48,7 @@ FIND_PACKAGE( LibXslt )
MACRO_LOG_FEATURE( LIBXSLT_FOUND "LibXSLT" "A library to transform XML into other formats" "http://www.xmlsoft.org/XSLT" TRUE ""
"Required for the chat styles system.
* Usually the package names for this library are:
- on Debian and Ubuntu: 'libxslt' and 'libxslt-dev'
+ on Debian and Ubuntu: 'libxslt' and 'libxslt1-dev'
on openSUSE: 'libxslt' and 'libxslt-devel'
* Please refer to the KMess board for more info,
and specially to this guide: http://trac.kmess.org/wiki/Compiling%20KMess" )
@@ -63,7 +62,7 @@ IF( NOT GCRYPT_FOUND )
MACRO_LOG_FEATURE( GCRYPT_FOUND "GCrypt" "A library to encrypt messages with various cyphers" "http://www.gnupg.org/" TRUE ""
"It is required for the Live Messenger login process.
* Usually the package names for this library are:
- on Debian and Ubuntu: 'libgcrypt' and 'libgcrypt-dev'
+ on Debian and Ubuntu: 'libgcrypt' and 'libgcrypt11-dev'
on openSUSE: 'libgcrypt' and 'libgcrypt-devel'
on Fedora: 'gcrypt' and 'gcrypt-devel'
* Please refer to the KMess board for more info,
@@ -109,6 +108,18 @@ MACRO_LOG_FEATURE( ISFQT_FOUND "LibISF-Qt" "Library to manage Microsoft's Mobile
In absence of an installed isf-qt version, the bundled version will be compiled.")
MACRO_BOOL_TO_01( ISFQT_FOUND HAVE_LIBISFQT ) # For config-kmess.h.in
+# Check for KNotificationItem. KDE 4.3.1 and later have it integrated in kdelibs/experimental.
+# It will be available by default in 4.4.
+IF( ${KDE_VERSION} VERSION_LESS 4.3.70 ) # KDE trunk has a higher version number than this.
+ MACRO_OPTIONAL_FIND_PACKAGE(LibKNotificationItem-1)
+ MACRO_LOG_FEATURE( LIBKNOTIFICATIONITEM-1_FOUND "LibKNotificationItem-1" "The experimental new KDE systray library" "http://www.kde.org" FALSE ""
+ "LibKNotificationItem-1 is the experimental new KDE systray library. It will be included
+ by default in KDE 4.4 and is available for use in KDE 4.3.1 and above." )
+ MACRO_BOOL_TO_01( LIBKNOTIFICATIONITEM-1_FOUND HAVE_NEW_TRAY )
+ELSE()
+ SET( HAVE_NEW_TRAY 1 )
+ENDIF()
+
# Display the dependency collection results
MACRO_DISPLAY_FEATURE_LOG()
@@ -138,8 +149,8 @@ INCLUDE_DIRECTORIES( ${KDE4_INCLUDES} ${KDE4_INCLUDE_DIR} ${QT_INCLUDES} ${LIBXM
#### Define the app version number ####
# Switch between the following two commands to force using a predefined version number
-# EXECUTE_PROCESS( COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/get-svn-version.sh OUTPUT_VARIABLE KMESS_VERSION )
-SET( KMESS_VERSION "2.0.3" )
+# EXECUTE_PROCESS( COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/get-git-version.sh OUTPUT_VARIABLE KMESS_VERSION )
+SET( KMESS_VERSION "2.0.4" )
#### Define compiler flags ####
@@ -167,7 +178,7 @@ ENDIF( CMAKE_COMPILER_IS_GNUCXX )
# - relwithdebinfo (release with debug info)
# - minsizerel (minsize release)
# Uncomment the next line to always force building in full debug mode
-SET( CMAKE_BUILD_TYPE debugfull )
+# SET( CMAKE_BUILD_TYPE debugfull )
# Enable the KMess debug output when compiling a debug build
IF( CMAKE_BUILD_TYPE STREQUAL debugfull OR KMESS_DEBUG_OUTPUT EQUAL 1 )
diff --git a/ChangeLog b/ChangeLog
index c3551a4..27f8c98 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,179 @@
+2010-07-25 (Adam)
+ * Merge fix for ticket #524, thanks to Timo Tambert
+
+2010-07-24 (Adam)
+ * Properly handle non-messenger Hotmail contacts that appear on our address book.
+ They need to be marked as Messenger users once we add them to our contact list.
+
+2010-07-23 (Adam)
+ * Add get-git-version.sh script to return the HEAD revision KMess was built with.
+ Removed get-svn-version.sh accordingly.
+ * When adding a contact, the contact type should be "Regular" AFAIK.
+ * Add AddressBookService::removePending to remove a handle from the Pending list.
+ * AddressBookService::getMembershipListUpdate now calls the correct method when
+ deleting a membership.
+
+2010-07-22 (Valerio)
+ * Fixed the conditions to enable the "Save chat" and "Clear chat" options in the chat view's context menu.
+
+2010-07-21 (Valerio)
+ * Fixed contact frame tooltips, there were HTML entities exposed.
+
+2010-07-20 (Pano)
+ * Merged an updated Traditional Chinese translation by Yen-chou Chen.
+
+2010-07-17 (Adam)
+ * Improve the handling of contacts that are on the address book and
+ the pending list at the same time (shouldn't happen, but it does).
+ * If a user is already on the friend list, don't allow the "add" option
+ to be chosen in ContactAddedUserDialog.
+ * Index all contacts by lower case handle to avoid any casing issues on retrieval.
+
+2010-07-17 (Adam)
+ * Attempt to solve some of the memory issues on KDE 4.5.
+
+2010-07-12 (Adam)
+ * Fix contact list background issues on KDE 4.5
+
+2010-07-10 (Pano)
+ * Merged an updated Japanese translation by Daniel E. Moctezuma.
+ * Merged an updated Brazilian Portuguese translation by Morris Arozi Moraes.
+
+2010-07-06 (Pano)
+ * Merged an updated French translation by Grégory Bellier.
+ * Merged an updated German translation.
+
+2010-07-06 (Valerio)
+ * Fixed sending messages only containing whitespace.
+
+2010-07-05 (Valerio)
+ * Fixed pressing Enter to send a drawing worked even when nothing was in the drawing.
+
+2010-07-04 (Valerio)
+ * Fixed the ability to drag'n'drop into the message editor a received Ink drawing, and an issue with
+ the Ink editor button when doing so.
+
+2010-06-27 (Pano)
+ * Merged an updated Traditional Chinese translation by the Tryneeds-Chinese Translation Platform.
+
+2010-06-27 (Valerio)
+ * Made immutable the display picture size in the contacts dock, to avoid weird picture resizes.
+ * Made the chat history box to respect the "Show the emails of contacts instead of the friendly name" option.
+ * Merged patch by dah_, changing the contact list to be sorted by status, then alphabetically.
+
+2010-06-27 (Adam)
+ * Add a check to ABService to prevent it recognising memberships for
+ non-passport members. Otherwise when we try to manipulate the memberships
+ for non-passport members we'll get errors since we're not handling them
+ correctly.
+ * Only pop up the "Contact Added User" dialog if a user is on the Pending list.
+ * Fix comments in kmess.notifyrc
+
+2010-06-26 (Valerio)
+ * Fixed wrong URL when retrieving a display picture from the server.
+ * Changed X11 libraries inclusion to fix building KMess from Fedora 13.
+
+2010-06-24 (Pano)
+ * Merged an updated Dutch translation by Heimen Stoffels.
+
+2010-06-20 (Adam)
+ * Fix a i18n bug in the system tray code.
+
+2010-06-19 (Valerio)
+ * Added support for a new ISF-Qt feature, PNG fortification. This allows users
+ to drag and drop their and their contacts' drawings into the message editor
+ to be edited.
+
+2010-06-19 (Adam)
+ * Backported the new KDE4 system tray spec. Remains optional for people who
+ are using KDE < 4.3.
+
+2010-06-13 (Sjors)
+ * Workarounded a documented limitation in KDE4_ADD_APP_ICON() to show the
+ KMess icon correctly.
+
+2010-06-13 (Pano)
+ * Merged an updated Japanese translation by Daniel E. Moctezuma.
+
+2010-06-07 (Sjors) (noknotify branch)
+ * Fixed a crash because QSystemTrayIcon was constructed statically before
+ main().
+ * Taught MacNotification class how to play sounds.
+ * Made MacNotification class take some predefined actions on receiving
+ certain events.
+
+2010-06-03 (Sjors) (noknotify branch)
+ * Added MacNotification class, which currently makes the KMess icon in the
+ Dock 'jump' when its method is called.
+ * Made the NotificationManager use MacNotification instead when doing
+ notifications on the Mac.
+ * Added support to MacNotification class to display Growl messages through
+ QSystemTrayIcon.
+ * Added support to MacNotification for stripping HTML off messages, so they
+ display correctly in Growl.
+
+2010-05-31 (Adam)
+ * Fix bug in chatwindow.ui: use the global include for IsfInkCanvas.
+
+2010-05-29 (Pano)
+* Merged an updated Japanese translation by Daniel E. Moctezuma.
+
+2010-05-25 (Pano)
+ * Merged an updated Catalan translation by Adrià Arrufat.
+
+2010-05-13 (Valerio)
+ * Fixed bug which made login to fail when the roaming service gives us a changed display
+ picture before setting the initial status.
+
+2010-05-08 (Pano)
+ * Merged an updated Dutch translation by Heimen Stoffels.
+
+2010-05-08 (sifcenter)
+ * Fixed bug on show listening music when the user is busy (maybe also with other states): the bit operation doesn't work
+ if the flags (STATUS_*) have more "1" bits set.
+
+2010-05-03 (Pano)
+ * Merged an updated Japanese translation by Daniel E. Moctezuma.
+
+2010-04-25 (Pano)
+ * Merged an updated Japanese translation by Daniel E. Moctezuma.
+
+2010-04-15 (Pano)
+ * Merged an updated German translation.
+
+2010-04-02 (Pano)
+ * Merged an updated Dutch translation by Heimen Stoffels.
+
+2010-04-01 (Pano)
+ * Merged an updated Japanese translation by Daniel E. Moctezuma.
+
+2010-03-30 (Adam)
+ * Add Francesco Nwokeka to the credits dialog for the Now Playing toggle button.
+ * Workaround a Qt 4.6.1/4.6.2 bug which was causing multiple copies of a single DP to appear in the "set previous
+ display picture" dialog and the contact properties dialog.
+
+2010-03-28 (Adam)
+ * Bug fix on MPRIS querying - the Identity method is located on the root interface, not the /Player interface.
+ * Reduce the number of debug messages coming out of NowListeningClient. Emits a debug message only when the song changes.
+ * Remove "contact does not have you on their contact list" text from the tool tips.
+
+2010-03-27 (Adam)
+ * Merge a modified patch by z3r0 from the boards; adds a toggle button for "now listening" to the contact list.
+ * Display the currently playing song above the CL even while appearing offline.
+ * Make the size of the CL DP depend on whether or not music is playing.
+ * Adjust font size of now listening label to match personal message.
+
+2010-03-17 (Adam)
+ * Fix bug where account properties were not properly updated in some cases.
+ * Fix bug where "Log in Automatically" was not obeyed and saved if it was unchecked after being enabled.
+ * When removing a contact that is already blocked, do not add them to the allow list.
+
+2010-03-16 (Pano)
+ * Added a Galician translation by Indalecio Freiría Santos.
+
+2010-03-13 (Adam)
+ * Fix bug where the status was set to "Idle" upon waking up from sleep.
+ * Fix bug where IDL status was kept after disconnection.
--- 2.0.3 released ---
diff --git a/Doxyfile b/Doxyfile
index 7962fa2..963b92f 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -5,7 +5,7 @@
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = KMess
-PROJECT_NUMBER = 2.0.3
+PROJECT_NUMBER = 2.0.4
OUTPUT_DIRECTORY = ./apidocs
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
diff --git a/FEATURES b/FEATURES
index 8e9c64b..ed81280 100644
--- a/FEATURES
+++ b/FEATURES
@@ -1,5 +1,11 @@
KMess Feature list
========================
+- 2.0.4 -
+New system tray icon when KMess is loaded onto KDE 4.4+.
+Improved support for notifications on Mac.
+Added a button on the contact list for quick "now listening" toggling.
+Ability to drag and drop drawings into the editor to re-send them.
+
- 2.0.3 -
Setting your friendly name and personal message by clicking on their labels in the contact list.
A display of the unread email count in the system tray tooltip.
diff --git a/NEWS b/NEWS
index 20569a8..09db855 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,43 @@
+Changes between KMess 2.0.4 and 2.0.3:
+--------------------------------------
+- added ability to drag and drop drawings into the message editor to be re-sent.
+- added support for the new KDE 4.4+ system tray icon.
+- added a toggle button for "now listening" to the contact list.
+- added displaying the currently playing song above the contact list, even while appearing offline.
+- added Galician translation by Indalecio Freiría Santos.
+- removed the "contact does not have you on their contact list" text from the tool tips,
+ as this feature is currently broken (the servers report incorrect data).
+- fixed "contact added you" dialogs from appearing when they should not.
+- fixed sending messages only containing whitespace.
+- fixed pressing Enter to send a drawing worked even when nothing was in the drawing.
+- fixed the ability to drag'n'drop into the message editor a received Ink drawing.
+- fixed dimensions of the display picture in the contacts dock.
+- fixed chat history box, now it respects the "Show contacts emails instead of friendly names" option.
+- fixed ignoring non-messenger contacts, who are not supported by KMess 2.0.x .
+- fixed retrieving display pictures from the server.
+- fixed building KMess from Fedora 13.
+- fixed compatibility with KDE 4.5 .
+- fixed error at login when the user had a new display picture to download.
+- fixed multiple copies of a single DP were appearing in the "set previous
+ display picture" dialog and the contact properties dialog.
+- fixed bug in Now Listening when querying MPRIS-compatible media players.
+- fixed account properties updating in some cases.
+- fixed "Log in Automatically" option saving in some cases.
+- fixed bug where the status was set to "Idle" upon waking up from sleep or disconnection.
+- fixed the application icon under Windows and Mac.
+- improved the contact list to be sorted by status, then alphabetically.
+- improved notifications support on Mac.
+- updated Traditional Chinese translation by Yen-chou Chen and the Tryneeds-Chinese Translation Platform.
+- updated Japanese translation by Daniel E. Moctezuma.
+- updated Brazilian Portuguese translation by Morris Arozi Moraes.
+- updated French translation by Grégory Bellier.
+- updated German translation.
+- updated Dutch translation by Heimen Stoffels.
+- updated Dutch translation by Heimen Stoffels.
+- updated Japanese translation by Daniel E. Moctezuma.
+- updated Catalan translation by Adrià Arrufat.
+
Changes between KMess 2.0.3 and 2.0.2:
--------------------------------------
- added ability to drag-and-drop images into display picture frames.
diff --git a/cmake/config-kmess.h.in b/cmake/config-kmess.h.in
index 3745061..15d9d1c 100644
--- a/cmake/config-kmess.h.in
+++ b/cmake/config-kmess.h.in
@@ -22,3 +22,6 @@
/* Define whether Ink support is enabled */
#define KMESS_ENABLE_INK ${HAVE_LIBISFQT}
+
+/* Define whether we have the new system tray */
+#cmakedefine HAVE_NEW_TRAY
\ No newline at end of file
diff --git a/cmake/get-git-version.sh b/cmake/get-git-version.sh
new file mode 100755
index 0000000..f9d7eff
--- /dev/null
+++ b/cmake/get-git-version.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+cd `dirname $0`/..
+
+# second sed expression fixes Mac OS X 10.4
+appver="`egrep 'SET.*KMESS_VERSION' CMakeLists.txt | sed -e 's/.*"\([^"]*\)".*/\1/'`"
+date="`date +%Y%m%d`"
+
+# Make sure we have the right repository
+if [ ! -f kmess.kdevelop ]; then
+ /bin/echo -n "git (unknown)"
+ exit
+fi
+
+# display app version if git isn't installed.
+if [ ! -x `which git` ]; then
+ /bin/echo -n "$appver"
+ exit
+fi
+
+# Display subversion version if this is a working copy
+gitver=`git rev-parse HEAD`
+
+# display last 8 digits of HEAD SHA-1 + date
+/bin/echo -n "$appver-git (${gitver:0:8} >= $date)"
diff --git a/cmake/get-svn-version.sh b/cmake/get-svn-version.sh
deleted file mode 100755
index 68cbbac..0000000
--- a/cmake/get-svn-version.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/bin/sh
-
-cd `dirname $0`/..
-
-# second sed expression fixes Mac OS X 10.4
-appver="`egrep 'SET.*KMESS_VERSION' CMakeLists.txt | sed -e 's/.*"\([^"]*\)".*/\1/'`"
-date="`date +%Y%m%d`"
-
-# Make sure we have the right repository
-if [ ! -f kmess.kdevelop ]; then
- /bin/echo -n "svn (unknown)"
- exit
-fi
-
-# Display normal version if subversion is not installed
-if [ ! -x `which svnversion 2>/dev/null` ]; then
- /bin/echo -n "$appver"
- exit
-fi
-
-# Display subversion version if this is a working copy
-svnver=`LANG=C svnversion`
-
-# see if this is not a repository.
-if [ "$svnver" = "exported" ]; then
- if [ -z "$KMESS_VER" ]; then
- /bin/echo -n "$appver";
- else
- /bin/echo -n "$KMESS_VER";
- fi
- exit;
-fi
-
-# display subversion version and date
-/bin/echo -n "$appver-svn (`svnversion` >= $date)"
diff --git a/configure b/configure
index 52f4049..275ceb9 100755
--- a/configure
+++ b/configure
@@ -54,7 +54,7 @@ DEBUG=0
# Globals
cd `dirname $0`
SRC_DIR="$PWD"
-KMESS_VER="`./cmake/get-svn-version.sh`"
+KMESS_VER="`./cmake/get-git-version.sh`"
diff --git a/contrib/isf-qt/.gitignore b/contrib/isf-qt/.gitignore
new file mode 100644
index 0000000..90deaf9
--- /dev/null
+++ b/contrib/isf-qt/.gitignore
@@ -0,0 +1,6 @@
+
+# Build files and dirs
+build*
+
+# KDevelop and other IDE-specific project files
+*.kdev*
diff --git a/contrib/isf-qt/CMakeLists.txt b/contrib/isf-qt/CMakeLists.txt
index 2803ebc..9a5a230 100644
--- a/contrib/isf-qt/CMakeLists.txt
+++ b/contrib/isf-qt/CMakeLists.txt
@@ -4,27 +4,42 @@ CMAKE_MINIMUM_REQUIRED( VERSION 2.6 )
#### Main switches ####
-# Define the default build type
-# Possible values:
-# - none
-# - release
-# - debug
-# - debugfull (even fewer optimisations)
-# - relwithdebinfo (release with debug info)
-# - minsizerel (minimum size release)
-# Uncomment the next line to force building in full debug mode
-SET( CMAKE_BUILD_TYPE debugfull )
+# Bundled mode: you can add Isf-Qt as a subdirectory
+# of your CMake-based prjoect easily. Just use:
+# SET( USE_BUNDLED_LIBRARIES ISFQT )
+# and Isf-Qt will be built and statically linked in your
+# application, without installing anything
+IF( ISFQT_IS_BUNDLED OR USE_BUNDLED_LIBRARIES MATCHES "ISFQT" )
+ SET( ISFQT_IS_BUNDLED TRUE )
+ MESSAGE( "-- Will build Isf-Qt in bundled mode." )
+ELSE()
+ SET( ISFQT_IS_BUNDLED FALSE )
+ENDIF()
+
+# Only set the build type if we're not being bundled: if we are, we'll
+# use the build type specified by the parent project
+IF( NOT ISFQT_IS_BUNDLED )
+
+ # Define the default build type
+ # Possible values:
+ # - none
+ # - release
+ # - debug
+ # - debugfull (even fewer optimisations)
+ # - relwithdebinfo (release with debug info)
+ # - minsizerel (minimum size release)
+ # Uncomment the next line to force building in full debug mode
+ SET( CMAKE_BUILD_TYPE debugfull )
+ENDIF()
# Define the library version number
-SET( ISFQT_VERSION "0.9" )
+SET( ISFQT_VERSION "1.0dev" )
#### Inclusions ####
FIND_PACKAGE( Qt4 REQUIRED )
-ENABLE_TESTING()
-
OPTION( WANT_GIF "Enable support for reading and writing Fortified-GIF images" ON )
IF( WANT_GIF )
MESSAGE( "-- Looking for GifLib" )
@@ -68,13 +83,27 @@ IF( CMAKE_COMPILER_IS_GNUCXX )
"-O0 -g3 -fno-inline -Wall -Woverloaded-virtual -Wsign-compare -Wundef -fvisibility=default" )
ENDIF( CMAKE_COMPILER_IS_GNUCXX )
+IF( NOT ISFQT_DEBUG_OUTPUT STREQUAL "1" AND NOT ISFQT_DEBUG_OUTPUT STREQUAL "0" )
+ IF( CMAKE_BUILD_TYPE MATCHES debug )
+ SET( ISFQT_DEBUG_OUTPUT 1 )
+ ELSE()
+ SET( ISFQT_DEBUG_OUTPUT 0 )
+ ENDIF()
+ENDIF()
+
+
+
INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} src include )
CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/isfqtconfig.h.in
${CMAKE_CURRENT_BINARY_DIR}/isfqtconfig.h )
ADD_SUBDIRECTORY( src )
-ADD_SUBDIRECTORY( tests )
+
+IF( NOT ISFQT_IS_BUNDLED )
+ ENABLE_TESTING()
+ ADD_SUBDIRECTORY( tests )
+ENDIF()
#### Project CMake configuration files creation ####
@@ -87,16 +116,17 @@ SET( LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib"
SET( SHARED_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share"
CACHE STRING "Directory where the shared data will be installed" )
-# Prepare the IsfQtConfig.cmake file, which allows other projects to find us
+# Prepare thej IsfQtConfig.cmake file, which allows other projects to find us
CONFIGURE_FILE( cmake/IsfQtConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/IsfQtConfig.cmake" @ONLY )
#### Installation ####
-# Do not install the resources if we're bundling it in KMess
-IF( NOT USE_BUNDLED_LIBRARIES MATCHES "ISFQT" )
+# Do not install the resources if we're bundling it into an application
+IF( NOT ISFQT_IS_BUNDLED )
INSTALL( FILES ${CMAKE_CURRENT_BINARY_DIR}/IsfQtConfig.cmake
DESTINATION ${LIB_INSTALL_DIR}/isfqt )
INSTALL( FILES cmake/FindIsfQt.cmake
DESTINATION ${CMAKE_ROOT}/Modules )
ENDIF()
+
diff --git a/contrib/isf-qt/ChangeLog b/contrib/isf-qt/ChangeLog
index 1c5820f..bd25fd3 100644
--- a/contrib/isf-qt/ChangeLog
+++ b/contrib/isf-qt/ChangeLog
@@ -1,3 +1,35 @@
+2010-07-23 (Valerio)
+ * Fixed the copy constructor in Stroke, it was not copying all the necessary properties.
+ * Fixed some compiler warnings.
+ * Improved bundled compilation mode.
+
+2010-07-22 (Valerio)
+ * Improved the InkEdit text - added a checkbox to show the usage of Canvas::isEmpty() and a label
+ to show usage of the Canvas::inkChanged() signal.
+ * Fixed inkChanged() signal emission in Canvas: it was emitted too early, when the drawing was not
+ updated yet: slots connected to inkChanged() could then call isEmpty() and get a true return value,
+ even if the drawing wasn't empty.
+
+2010-06-27 (Adam)
+ * Use Q_ASSERT_X instead of qWarning where appropriate.
+
+2010-06-19 (Valerio)
+ * Changed the default behavior of InkCanvas::pixmap(), now paints on a transparent
+ background, instead of a white one.
+
+2010-06-19 (Valerio)
+ * Added support for PNG fortification. Like GIF fortification, this feature allows to
+ write a PNG containing the full ISF drawing inside itself. Of course, it's now also
+ possible to read a PNG containing ISF data and retrieve the actual drawing.
+
+2010-03-20 (Adam)
+ * Slight optimisation to painting - we no longer draw the background color, Qt does it for us.
+ Also, only render the parts of the buffer that have changed.
+
+2010-03-13 (Adam)
+ * Add a bezier curve smoothing algorithm. Strokes with the FitToCurve flag set are
+ rendered with an approximate bezier curve. Gives much smoother looking strokes.
+
2010-02-21 (Adam)
* Optimise the painting of strokes. Cache logic added to IsfQtDrawing and only
strokes that have been added are painted. Also, no longer do a full bounding rect
diff --git a/contrib/isf-qt/README b/contrib/isf-qt/README
index 1ba3a43..83db1c6 100644
--- a/contrib/isf-qt/README
+++ b/contrib/isf-qt/README
@@ -5,9 +5,16 @@ About LibISF-Qt:
LibISF-Qt is a Qt4 library made to encode and decode Microsoft's
Ink Serialized Format (ISF) files.
-Q. What the hell is this?
-A. It's a library, written in C++/Qt4, to read and write ISF
- image files.
+Q. What is ISF?
+A. Ink Serialized Format is an open specification initially
+ made by Microsoft, and then freed up with their "Open
+ Specification Promise" initiative. ISF is a file format
+ made to store handwriting very efficiently: an ISF file
+ with a somewhat complex handwritten drawing takes less than
+ 1000 bytes. ISF supports metrics to adapt drawings to
+ different form factors, bezier smoothing of drawn strokes,
+ coloring, stroke size varying by pen pressure, linking
+ in static data, and more.
Q. How does this library differ from aMSN's or Emesene's?
A. It's written with Qt, which makes it easily portable on
@@ -42,6 +49,16 @@ If everything went right again, install it:
$ make install
Aaand now you're set. :)
+LibISF-Qt natively supports being bundled into other applications.
+Bundling means that the library does not get installed system-wide
+along with your application, but instead it gets statically linked
+into the application.
+The idea is that you copy the Isf-Qt source tree (with an SVN export
+or a Git submodule) into your project's tree, and then set up your
+CMake listfile to add this library as a subdirectory:
+> SET( ISFQT_IS_BUNDLED TRUE )
+> ADD_SUBDIRECTORY( contrib/isf-qt )
+And again, you're done!
Documentation:
diff --git a/contrib/isf-qt/TODO b/contrib/isf-qt/TODO
index 1abb764..b67c58d 100644
--- a/contrib/isf-qt/TODO
+++ b/contrib/isf-qt/TODO
@@ -14,7 +14,7 @@ OUTSTANDING
- Read and write user-defined custom tags
- Interpret, use and write pressure information
- Associating text recognized by OCR to the drawn strokes
-- Modify strokes
+- Alter stroke points
DONE
----
@@ -38,4 +38,5 @@ DONE
- Add new strokes to an IsfDrawing
- Stroke attributes: width, colour, pressure
- Export IsfDrawing to raw-isf, isf-base64 and fortified-gif
+- Export IsfDrawing to PNG
- Delete strokes
diff --git a/contrib/isf-qt/cmake/isfqtconfig.h.in b/contrib/isf-qt/cmake/isfqtconfig.h.in
index 85b1989..30514c2 100644
--- a/contrib/isf-qt/cmake/isfqtconfig.h.in
+++ b/contrib/isf-qt/cmake/isfqtconfig.h.in
@@ -8,7 +8,9 @@
#define ISFQT_VERSION "${ISFQT_VERSION}"
// Define if debug output should be enabled
-#define ISFQT_DEBUG ${ISFQT_DEBUG_OUTPUT}
+#if ${ISFQT_DEBUG_OUTPUT}
+ #define ISFQT_DEBUG
+#endif
// Define if fortified-GIF support is enabled
#define ISFQT_GIF_ENABLED ${GIF_ENABLED}
diff --git a/contrib/isf-qt/include/IsfQtStroke b/contrib/isf-qt/include/IsfQtStroke
new file mode 100644
index 0000000..df27abc
--- /dev/null
+++ b/contrib/isf-qt/include/IsfQtStroke
@@ -0,0 +1 @@
+#include "isfqtstroke.h"
diff --git a/contrib/isf-qt/include/isfinkcanvas.h b/contrib/isf-qt/include/isfinkcanvas.h
index c81e6a0..eb79938 100644
--- a/contrib/isf-qt/include/isfinkcanvas.h
+++ b/contrib/isf-qt/include/isfinkcanvas.h
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -42,7 +40,7 @@ namespace Isf
* @class InkCanvas
* @brief This is a control designed for the drawing and display of Ink.
*
- * InkCanvas is used for drawing and displaying Ink. The currently displayed Ink drawing can be retrieved
+ * InkCanvas is used for drawing and displaying Ink. The currently displayed Ink drawing can be retrieved
* or set using the drawing() and setDrawing() methods.
*
* To set the properties of the current pen, use the setPenColor(), setPenSize() and setPenType() methods.
@@ -51,7 +49,7 @@ namespace Isf
* Example:
*
* \code
- * InkCanvas *canvas = new Isf::InkCanvas( this );
+ * InkCanvas* canvas = new Isf::InkCanvas( this );
* canvas->setPenColor( Qt::blue );
* canvas->setPenSize( 10 );
*
@@ -62,7 +60,7 @@ namespace Isf
* // now an eraser will be used and strokes can be erased individually.
* \endcode
*
- * To return the currently displayed Ink as a QImage, use image(). To return the raw ISF data, suitable
+ * To return the currently displayed Ink as a QImage, use image(). To return the raw ISF data, suitable
* for saving to disk or sending over a network, use bytes().
*
* To write the ISF data directly to a QIODevice, such as a file, use the save() method.
@@ -94,37 +92,37 @@ namespace Isf
};
public: // public constructors
- InkCanvas( QWidget *parent = 0 );
- ~InkCanvas();
+ InkCanvas( QWidget* = 0 );
+ ~InkCanvas();
public: // public methods
QByteArray bytes();
- Isf::Drawing *drawing();
+ Isf::Drawing* drawing();
QImage image();
bool isEmpty();
QColor penColor();
int penSize();
PenType penType();
- void save( QIODevice &device, bool base64 = false );
- void setDrawing( Isf::Drawing *drawing );
+ void save( QIODevice&, bool = false );
+ void setDrawing( Isf::Drawing* );
virtual QSize sizeHint() const;
public slots:
void clear();
- void setCanvasColor( QColor newColor );
- void setPenColor( QColor newColor );
- void setPenSize( int pixels );
- void setPenType( PenType type );
+ void setCanvasColor( QColor );
+ void setPenColor( QColor );
+ void setPenSize( int );
+ void setPenType( PenType );
protected: // protected methods
- void mousePressEvent( QMouseEvent *event );
- void mouseMoveEvent( QMouseEvent *event );
- void mouseReleaseEvent( QMouseEvent *event );
- void paintEvent( QPaintEvent *event );
- void resizeEvent( QResizeEvent *event );
+ void mousePressEvent( QMouseEvent* );
+ void mouseMoveEvent( QMouseEvent* );
+ void mouseReleaseEvent( QMouseEvent* );
+ void paintEvent( QPaintEvent* );
+ void resizeEvent( QResizeEvent* );
private: // private methods
- void drawLineTo( const QPoint &endPoint );
+ void drawLineTo( const QPoint& );
void clearBuffer();
void updateCursor();
@@ -140,7 +138,7 @@ namespace Isf
/// It's true if the erase brush was selected
bool erasingImage_;
/// Current drawing being manipulated
- Isf::Drawing *drawing_;
+ Isf::Drawing* drawing_;
/// Initial drawing, can be overridden with drawing_
Isf::Drawing initialDrawing_;
/// Last point where the mouse pointer was released
@@ -152,7 +150,7 @@ namespace Isf
/// Pen type
PenType penType_;
/// The current stroke being drawn
- Isf::Stroke *currentStroke_;
+ Isf::Stroke* currentStroke_;
/// The pixmap buffer where in progress strokes are drawn
QPixmap bufferPixmap_;
/// Cache pixmap so the Ink isn't redrawn on every mouse move
@@ -161,7 +159,7 @@ namespace Isf
bool drawingDirty_;
signals:
- /// Emitted when the ink representation is modified (stroke drawn,
+ /// Emitted when the ink representation is modified (stroke drawn,
/// stroke deleted, current drawing changed).
void inkChanged();
};
diff --git a/contrib/isf-qt/include/isfqt.h b/contrib/isf-qt/include/isfqt.h
index 59a7d44..3760f62 100644
--- a/contrib/isf-qt/include/isfqt.h
+++ b/contrib/isf-qt/include/isfqt.h
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -41,6 +39,7 @@ namespace Isf
{
// Forward declarations
class Drawing;
+ class StreamData;
@@ -137,8 +136,8 @@ namespace Isf
, IsHighlighter = 0x0100 ///< This stroke is an highlighter stroke
, IsRectangle = 0x0200 ///< Meaning unknown
};
- Q_DECLARE_FLAGS( StrokeFlags, StrokeFlag )
- Q_DECLARE_OPERATORS_FOR_FLAGS( StrokeFlags )
+ Q_DECLARE_FLAGS( StrokeFlags, StrokeFlag );
+ Q_DECLARE_OPERATORS_FOR_FLAGS( StrokeFlags );
@@ -183,6 +182,14 @@ namespace Isf
, resolution( vResolution )
{
}
+ /// Quick comparison operator
+ bool operator ==( const Metric& other )
+ {
+ return min == other.min
+ && max == other.max
+ && units == other.units
+ && resolution == other.resolution;
+ }
/// Minimum value
qint64 min;
@@ -232,52 +239,6 @@ namespace Isf
- /**
- * Drawing attributes for points.
- */
- struct AttributeSet
- {
- /// Constructor
- AttributeSet()
- : color( Qt::black )
- , flags( 0x10 ) // Meaning unknown
- , penSize( 8.f, 8.f ) // Default pen is 8.0 pixels wide
- {
- }
-
- /// The stroke color, optionally with alpha channel
- QColor color;
- /// Mask of StrokeFlags, @see StrokeFlags
- StrokeFlags flags;
- /// Dimensions of the pencil in pixels
- QSizeF penSize;
- };
-
-
-
- /**
- * Drawing attributes for strokes.
- */
- struct StrokeInfo
- {
- /// Constructor
- StrokeInfo()
- : hasPressureData( false )
- , hasXData( true )
- , hasYData( true )
- {
- }
-
- /// Whether the stroke contains pressure info or not
- bool hasPressureData;
- /// Whether the stroke contains X coordinates or not
- bool hasXData;
- /// Whether the stroke contains Y coordinates or not
- bool hasYData;
- };
-
-
-
/**
* A single point within a stroke.
*/
@@ -290,17 +251,23 @@ namespace Isf
{
}
/// Constructor with point only
- Point( const QPoint &point )
+ Point( const QPoint& point )
: position( point )
, pressureLevel( 0 )
{
}
/// Constructor with point and pressure
- Point( const QPoint &point, const qint64 pressure )
+ Point( const QPoint& point, const qint64 pressure )
: position( point )
, pressureLevel( pressure )
{
}
+ /// Quick comparison operator
+ bool operator ==( const Point& other )
+ {
+ return position == other.position
+ && pressureLevel == other.pressureLevel;
+ }
/// coordinates
QPoint position;
@@ -311,32 +278,9 @@ namespace Isf
/**
- * A pen stroke.
+ * A list of Point items.
*/
- struct Stroke
- {
- /// Constructor
- Stroke()
- : attributes( 0 )
- , info( 0 )
- , metrics( 0 )
- , transform( 0 )
- {
- }
-
- /// Bounding rectangle of this stroke
- QRect boundingRect;
- /// Link to the attributes of this stroke's points, if any
- AttributeSet *attributes;
- /// Link to this stroke's attributes, if any
- StrokeInfo *info;
- /// Link to this stroke's metrics, if any
- Metrics *metrics;
- /// List of points
- QList points;
- /// Link to this stroke's transformation, if any
- QMatrix *transform;
- };
+ typedef QList PointList;
@@ -359,12 +303,16 @@ namespace Isf
public: // Public static methods
- static Drawing &reader( const QByteArray &isfData, bool decodeFromBase64 = false );
- static Drawing &readerGif( const QByteArray &gifRawBytes, bool decodeFromBase64 = false );
+ static Drawing &reader( const QByteArray&, bool = false );
+ static Drawing &readerGif( const QByteArray&, bool = false );
+ static Drawing &readerPng( const QByteArray&, bool = false );
static bool supportsGif();
- static QByteArray writer( const Drawing &drawing, bool encodeToBase64 = false );
- static QByteArray writerGif( const Drawing &drawing, bool encodeToBase64 = false );
+ static QByteArray writer( const Drawing&, bool = false );
+ static QByteArray writerGif( const Drawing&, bool = false );
+ static QByteArray writerPng( const Drawing&, bool = false );
+ private: // Private static properties
+ static StreamData* streamData_;
};
}
diff --git a/contrib/isf-qt/include/isfqtdrawing.h b/contrib/isf-qt/include/isfqtdrawing.h
index d67ed6f..dce9936 100644
--- a/contrib/isf-qt/include/isfqtdrawing.h
+++ b/contrib/isf-qt/include/isfqtdrawing.h
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -27,6 +25,7 @@
#define ISFQTDRAWING_H
#include
+#include
#include
#include
@@ -38,6 +37,8 @@
// Forward declarations
class QByteArray;
+class AttributeSet;
+
namespace Isf
@@ -65,38 +66,33 @@ namespace Isf
public: // public constructors
Drawing();
- Drawing( const Drawing &other );
+ Drawing( const Drawing& );
~Drawing();
public: // public state retrieval methods
- AttributeSet *attributeSet( quint32 index );
- const QList attributeSets();
- QRect boundingRect();
+ QRect boundingRect() const;
void clear();
IsfError error() const;
+ qint32 indexOfStroke( const Stroke* ) const;
+ bool isEmpty() const;
bool isNull() const;
- QPixmap pixmap( const QColor backgroundColor = Qt::white );
- QSize size();
- Stroke *stroke( quint32 index );
- Stroke *strokeAtPoint( const QPoint &point );
+ QPixmap pixmap( const QColor = Qt::transparent );
+ void setBoundingRect( QRect );
+ QSize size() const;
+ Stroke* stroke( quint32 );
+ Stroke* strokeAtPoint( const QPoint& );
const QList strokes();
- QMatrix *transform( quint32 index );
- const QList transforms();
public: // public manipulation methods
- qint32 addAttributeSet( AttributeSet *newAttributeSet );
- qint32 addStroke( Stroke *newStroke );
- qint32 addTransform( QMatrix *newTransform );
- bool deleteAttributeSet( quint32 index );
- bool deleteStroke( quint32 index );
- bool deleteStroke( Stroke *stroke ) ;
- bool deleteTransform( quint32 index );
- bool setCurrentAttributeSet( AttributeSet *attributeSet );
- bool setCurrentTransform( QMatrix *transform );
+ qint32 addStroke( Stroke* );
+ qint32 addStroke( PointList = PointList() );
+ bool deleteStroke( quint32 );
+ bool deleteStroke( Stroke* );
+
+ private:
+ void updateBoundingRect();
private: // Private properties
- /// List of attributes of the points in the drawing
- QList attributeSets_;
/// Bounding rectangle of the drawing
QRect boundingRect_;
/// Cached bounding rectangle
@@ -107,22 +103,6 @@ namespace Isf
QRect canvas_;
/// A list of strokes that need to be repainted.
QList changedStrokes_;
- /// Link to the currently used metric data
- Metrics *currentMetrics_;
- /// Link to the currently used point info data
- AttributeSet *currentAttributeSet_;
- /// Link to the currently used stroke info data
- StrokeInfo *currentStrokeInfo_;
- /// Link to the currently used transformation
- QMatrix *currentTransform_;
- /// Link to the default metric data
- Metrics defaultMetrics_;
- /// Link to the default point info data
- AttributeSet defaultAttributeSet_;
- /// Link to the default stroke info data
- StrokeInfo defaultStrokeInfo_;
- /// Link to the default transformation
- QMatrix defaultTransform_;
/// Is the drawing dirty? i.e, requires repainting?
bool dirty_;
/// Last parsing error (if there is one)
@@ -139,16 +119,8 @@ namespace Isf
quint64 maxGuid_;
/// Maximum thickness of the strokes
QSizeF maxPenSize_;
- /// List of metrics used in the drawing
- QList metrics_;
- /// Pixel size of the drawing
- QSize size_;
- /// List of information about the drawing's strokes
- QList strokeInfo_;
/// List of strokes composing this drawing
QList strokes_;
- /// Transformation matrices
- QList transforms_;
};
diff --git a/contrib/isf-qt/include/isfqtstroke.h b/contrib/isf-qt/include/isfqtstroke.h
new file mode 100644
index 0000000..ec64e9c
--- /dev/null
+++ b/contrib/isf-qt/include/isfqtstroke.h
@@ -0,0 +1,117 @@
+/***************************************************************************
+ * Copyright (C) 2010 by Valerio Pilo *
+ * valerio@kmess.org *
+ * *
+ * Copyright (C) 2010 by Adam Goossens *
+ * adam@kmess.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation; either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * 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. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#ifndef ISFQTSTROKE_H
+#define ISFQTSTROKE_H
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+
+// Forward declarations
+class QPainterPath;
+
+
+
+namespace Isf
+{
+
+
+
+ // Forward declarations
+ class AttributeSet;
+
+
+
+ /**
+ * A pen stroke.
+ */
+ class Stroke
+ {
+ public:
+ Stroke();
+ Stroke( const Stroke& );
+ ~Stroke();
+
+ void addPoint( Point );
+ void addPoints( PointList );
+ QRect boundingRect() const;
+ QColor color() const;
+ void finalize();
+ StrokeFlags flags() const;
+ bool hasPressureData() const;
+ Metrics* metrics();
+ QPainterPath painterPath();
+ QSizeF penSize() const;
+ PointList& points();
+ void setColor( QColor );
+ void setFlag( StrokeFlag, bool = true );
+ void setFlags( StrokeFlags );
+ void setMetrics( Metrics* );
+ void setPenSize( QSizeF );
+ void setTransform( QMatrix* );
+ QMatrix* transform();
+
+ private:
+ void bezierCalculateControlPoints();
+ void bezierGetFirstControlPoints( double[], double*, int );
+
+ private:
+ /// Bezier data
+ QList bezierControlPoints1_;
+ QList bezierControlPoints2_;
+ QList bezierKnots_;
+ /// Bounding rectangle of this stroke
+ QRect boundingRect_;
+ /// The stroke color, optionally with alpha channel
+ QColor color_;
+ /// Whether the stroke data needs to be analyzed or not
+ bool finalized_;
+ /// Mask of StrokeFlags, @see StrokeFlags
+ StrokeFlags flags_;
+ /// Whether the stroke contains pressure information or not
+ bool hasPressureData_;
+ /// Link to this stroke's metrics, if any
+ Metrics* metrics_;
+ /// Dimensions of the pencil in pixels
+ QSizeF penSize_;
+ /// List of points
+ PointList points_;
+ /// Link to this stroke's transformation, if any
+ QMatrix* transform_;
+
+
+ };
+
+
+
+}; // namespace Isf
+
+
+
+#endif // ISFQTSTROKE_H
diff --git a/contrib/isf-qt/src/CMakeLists.txt b/contrib/isf-qt/src/CMakeLists.txt
index bb3bc8b..eed2b4e 100644
--- a/contrib/isf-qt/src/CMakeLists.txt
+++ b/contrib/isf-qt/src/CMakeLists.txt
@@ -14,15 +14,18 @@ SET( ISFQT_SOURCES
tagswriter.cpp
isfqt.cpp
isfinkcanvas.cpp
+ isfqtstroke.cpp
)
SET( ISFQT_PUBLIC_HEADERS
../include/isfqt.h
../include/isfqtdrawing.h
../include/isfinkcanvas.h
- ../include/IsfQt
+ ../include/isfqtstroke.h
../include/IsfQtDrawing
../include/IsfInkCanvas
+ ../include/IsfQtStroke
+ ../include/IsfQt
)
SET( ISFQT_LIBS
@@ -48,11 +51,11 @@ QT4_ADD_RESOURCES( ISFQT_RCC_SRCS ${ISFQT_RCCS} )
INCLUDE_DIRECTORIES( ${QT_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR} )
-# Do not install the library if we're bundling it in KMess
-IF( NOT USE_BUNDLED_LIBRARIES MATCHES "ISFQT" )
- ADD_LIBRARY( isf-qt SHARED ${ISFQT_SOURCES} ${MOC_SRCS} ${ISFQT_RCC_SRCS} )
-ELSE()
+# Do not install the library if we're bundling it into an application
+IF( ISFQT_IS_BUNDLED )
ADD_LIBRARY( isf-qt STATIC ${ISFQT_SOURCES} ${MOC_SRCS} ${ISFQT_RCC_SRCS} )
+ELSE()
+ ADD_LIBRARY( isf-qt SHARED ${ISFQT_SOURCES} ${MOC_SRCS} ${ISFQT_RCC_SRCS} )
ENDIF()
TARGET_LINK_LIBRARIES( isf-qt ${ISFQT_LIBS} )
@@ -64,7 +67,7 @@ SET_TARGET_PROPERTIES( isf-qt PROPERTIES
#### Installation ####
# Do not install the library if we're bundling it in KMess
-IF( NOT USE_BUNDLED_LIBRARIES MATCHES "ISFQT" )
+IF( NOT ISFQT_IS_BUNDLED )
INSTALL( TARGETS isf-qt LIBRARY
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" )
INSTALL( FILES ${ISFQT_PUBLIC_HEADERS}
diff --git a/contrib/isf-qt/src/data/algorithms/bitpacking.cpp b/contrib/isf-qt/src/data/algorithms/bitpacking.cpp
index 3c48e17..f91c266 100644
--- a/contrib/isf-qt/src/data/algorithms/bitpacking.cpp
+++ b/contrib/isf-qt/src/data/algorithms/bitpacking.cpp
@@ -36,7 +36,7 @@ using namespace Isf::Compress;
* @param data Data to analyze
* @return Block size
*/
-quint8 BitPackingAlgorithm::blockSize( const QList &data )
+quint8 BitPackingAlgorithm::blockSize( const QList& data )
{
quint8 blockSize = 0;
qint64 num;
@@ -78,7 +78,7 @@ quint8 BitPackingAlgorithm::blockSize( const QList &data )
* @param source List of values to compress
* @return bool
*/
-bool BitPackingAlgorithm::deflate( QByteArray &encodedData, quint8 blockSize, const QList &source )
+bool BitPackingAlgorithm::deflate( QByteArray& encodedData, quint8 blockSize, const QList& source )
{
if( blockSize > 64 )
{
@@ -158,7 +158,7 @@ bool BitPackingAlgorithm::deflate( QByteArray &encodedData, quint8 blockSize, co
* @param decodedData List where to place decompressed values
* @return bool
*/
-bool BitPackingAlgorithm::inflate( DataSource &source, quint64 length, quint8 blockSize, QList &decodedData )
+bool BitPackingAlgorithm::inflate( DataSource* source, quint64 length, quint8 blockSize, QList& decodedData )
{
if( blockSize > 64 )
{
@@ -166,7 +166,7 @@ bool BitPackingAlgorithm::inflate( DataSource &source, quint64 length, quint8 bl
blockSize = 64; // Fuck it :P
}
- if( source.atEnd() )
+ if( source->atEnd() )
{
qWarning() << "Cannot inflate: no more bits available!";
return true;
@@ -178,7 +178,7 @@ bool BitPackingAlgorithm::inflate( DataSource &source, quint64 length, quint8 bl
while( index++ < length )
{
- value = source.getBits( blockSize );
+ value = source->getBits( blockSize );
// If the mask matches, the sign bit is set, so ORing value and mask will
// set all leftmost bits to 1, making it a real 64bit signed integer
diff --git a/contrib/isf-qt/src/data/algorithms/bitpacking.h b/contrib/isf-qt/src/data/algorithms/bitpacking.h
index 6235330..b1c28e0 100644
--- a/contrib/isf-qt/src/data/algorithms/bitpacking.h
+++ b/contrib/isf-qt/src/data/algorithms/bitpacking.h
@@ -32,9 +32,9 @@ namespace Isf
namespace BitPackingAlgorithm
{
- quint8 blockSize( const QList &data );
- bool deflate( QByteArray &encodedData, quint8 blockSize, const QList &source );
- bool inflate( DataSource &source, quint64 length, quint8 blockSize, QList &decodedData );
+ quint8 blockSize( const QList& data );
+ bool deflate( QByteArray& encodedData, quint8 blockSize, const QList& source );
+ bool inflate( DataSource* source, quint64 length, quint8 blockSize, QList& decodedData );
}
}
diff --git a/contrib/isf-qt/src/data/algorithms/bitpacking_byte.cpp b/contrib/isf-qt/src/data/algorithms/bitpacking_byte.cpp
index cbfc244..0abffcd 100644
--- a/contrib/isf-qt/src/data/algorithms/bitpacking_byte.cpp
+++ b/contrib/isf-qt/src/data/algorithms/bitpacking_byte.cpp
@@ -33,7 +33,7 @@ using namespace Isf::Compress;
* @param data Data to analyze
* @return Index value
*/
-quint8 BitPackingByteAlgorithm::index( const QList &data )
+quint8 BitPackingByteAlgorithm::index( const QList& data )
{
Q_UNUSED( data );
@@ -78,7 +78,7 @@ quint8 BitPackingByteAlgorithm::index( const QList &data )
* @param source List of values to compress
* @return bool
*/
-bool BitPackingByteAlgorithm::deflate( QByteArray &encodedData, quint8 index, const QList &source )
+bool BitPackingByteAlgorithm::deflate( QByteArray& encodedData, quint8 index, const QList& source )
{
Q_UNUSED( encodedData );
Q_UNUSED( index );
@@ -163,7 +163,7 @@ bool BitPackingByteAlgorithm::deflate( QByteArray &encodedData, quint8 index, co
* @param decodedData List where to place decompressed values
* @return bool
*/
-bool BitPackingByteAlgorithm::inflate( DataSource &source, quint64 length, quint8 index, QList &decodedData )
+bool BitPackingByteAlgorithm::inflate( DataSource* source, quint64 length, quint8 index, QList& decodedData )
{
if( index > 24 )
{
@@ -171,7 +171,7 @@ bool BitPackingByteAlgorithm::inflate( DataSource &source, quint64 length, quint
index = 24; // Fuck it :P
}
- if( source.atEnd() )
+ if( source->atEnd() )
{
qWarning() << "Cannot inflate: no more bits available!";
return true;
@@ -185,7 +185,7 @@ bool BitPackingByteAlgorithm::inflate( DataSource &source, quint64 length, quint
quint64 pos = 0;
while( pos++ < count )
{
- quint8 byte = source.getBits( cBits, &ok );
+ quint8 byte = source->getBits( cBits, &ok );
if( ! ok )
{
diff --git a/contrib/isf-qt/src/data/algorithms/bitpacking_byte.h b/contrib/isf-qt/src/data/algorithms/bitpacking_byte.h
index edf8daa..a15bdff 100644
--- a/contrib/isf-qt/src/data/algorithms/bitpacking_byte.h
+++ b/contrib/isf-qt/src/data/algorithms/bitpacking_byte.h
@@ -32,9 +32,9 @@ namespace Isf
namespace BitPackingByteAlgorithm
{
- quint8 index( const QList &data );
- bool deflate( QByteArray &encodedData, quint8 index, const QList &source );
- bool inflate( DataSource &source, quint64 length, quint8 index, QList &decodedData );
+ quint8 index( const QList& data );
+ bool deflate( QByteArray& encodedData, quint8 index, const QList& source );
+ bool inflate( DataSource* source, quint64 length, quint8 index, QList& decodedData );
}
}
diff --git a/contrib/isf-qt/src/data/algorithms/deltatransform.cpp b/contrib/isf-qt/src/data/algorithms/deltatransform.cpp
index af2565a..2b3effa 100644
--- a/contrib/isf-qt/src/data/algorithms/deltatransform.cpp
+++ b/contrib/isf-qt/src/data/algorithms/deltatransform.cpp
@@ -31,7 +31,7 @@ using namespace Isf::Compress;
* @param data Data to transform - the list will be modified.
* @return bool
*/
-bool Delta::transform( QList &data )
+bool Delta::transform( QList& data )
{
qint64 currentDelta = 0;
qint64 previousDelta = 0;
@@ -57,7 +57,7 @@ bool Delta::transform( QList &data )
* @param data Data to transform - the list will be modified.
* @return bool
*/
-bool Delta::inverseTransform( QList &data )
+bool Delta::inverseTransform( QList& data )
{
qint64 currentDelta = 0;
qint64 previousDelta = 0;
diff --git a/contrib/isf-qt/src/data/algorithms/deltatransform.h b/contrib/isf-qt/src/data/algorithms/deltatransform.h
index fcb48a2..aea7308 100644
--- a/contrib/isf-qt/src/data/algorithms/deltatransform.h
+++ b/contrib/isf-qt/src/data/algorithms/deltatransform.h
@@ -31,8 +31,8 @@ namespace Isf
namespace Delta
{
- bool transform( QList &data );
- bool inverseTransform( QList &data );
+ bool transform( QList& data );
+ bool inverseTransform( QList& data );
}
}
diff --git a/contrib/isf-qt/src/data/algorithms/huffman.cpp b/contrib/isf-qt/src/data/algorithms/huffman.cpp
index 338709c..c38aa68 100644
--- a/contrib/isf-qt/src/data/algorithms/huffman.cpp
+++ b/contrib/isf-qt/src/data/algorithms/huffman.cpp
@@ -67,7 +67,7 @@ const int huffmanBases_[HUFFMAN_BASES_NUM][HUFFMAN_BASE_SIZE] =
* @param data Data to analyze
* @return index value
*/
-quint8 HuffmanAlgorithm::index( const QList &data )
+quint8 HuffmanAlgorithm::index( const QList& data )
{
quint8 index = 0;
@@ -88,14 +88,14 @@ quint8 HuffmanAlgorithm::index( const QList &data )
* @param source List of values to compress
* @return bool
*/
-bool HuffmanAlgorithm::deflate( QByteArray &encodedData, quint8 index, const QList &source )
+bool HuffmanAlgorithm::deflate( QByteArray& encodedData, quint8 index, const QList& source )
{
DataSource output( encodedData );
output.skipToNextByte();
foreach( quint64 value, source )
{
- if( ! deflateValue( output, index, value ) )
+ if( ! deflateValue( &output, index, value ) )
{
#ifdef ISFQT_DEBUG
qDebug() << "Deflating failure for value:" << value;
@@ -121,7 +121,7 @@ bool HuffmanAlgorithm::deflate( QByteArray &encodedData, quint8 index, const QLi
* @param value Value to compress
* @return bool
*/
-bool HuffmanAlgorithm::deflateValue( DataSource &output, quint8 index, qint64 value )
+bool HuffmanAlgorithm::deflateValue( DataSource* output, quint8 index, qint64 value )
{
qint64 temp = value;
quint8 requiredBits = 0;
@@ -182,8 +182,8 @@ bool HuffmanAlgorithm::deflateValue( DataSource &output, quint8 index, qint64 va
}
// Add the bits to the data source
- output.append( bits );
- output.append( valueBits );
+ output->append( bits );
+ output->append( valueBits );
return true;
}
@@ -199,7 +199,7 @@ bool HuffmanAlgorithm::deflateValue( DataSource &output, quint8 index, qint64 va
* @param decodedData List where to place decompressed values
* @return bool
*/
-bool HuffmanAlgorithm::inflate( DataSource &source, quint64 length, quint8 index, QList &decodedData )
+bool HuffmanAlgorithm::inflate( DataSource* source, quint64 length, quint8 index, QList& decodedData )
{
QVector huffmanBases;
QVector bitAmounts( HUFFMAN_BASE_SIZE );
@@ -238,7 +238,7 @@ bool HuffmanAlgorithm::inflate( DataSource &source, quint64 length, quint8 index
while( (uint)decodedData.length() < length )
{
- bit = source.getBit();
+ bit = source->getBit();
if( bit )
{
@@ -252,7 +252,7 @@ bool HuffmanAlgorithm::inflate( DataSource &source, quint64 length, quint8 index
}
else if( count < (uint)bitAmounts.size() )
{
- quint64 offset = source.getBits( bitAmounts[ count ] );
+ quint64 offset = source->getBits( bitAmounts[ count ] );
bool sign = offset & 0x1;
offset /= 2;
value = huffmanBases[ count ] + offset;
diff --git a/contrib/isf-qt/src/data/algorithms/huffman.h b/contrib/isf-qt/src/data/algorithms/huffman.h
index f59cd5b..9fe735c 100644
--- a/contrib/isf-qt/src/data/algorithms/huffman.h
+++ b/contrib/isf-qt/src/data/algorithms/huffman.h
@@ -32,13 +32,13 @@ namespace Isf
namespace HuffmanAlgorithm
{
- bool deflate( QByteArray &encodedData, quint8 index, const QList &source );
- bool inflate( DataSource &source, quint64 length, quint8 index, QList &decodedData );
- quint8 index( const QList &data );
+ bool deflate( QByteArray& encodedData, quint8 index, const QList& source );
+ bool inflate( DataSource* source, quint64 length, quint8 index, QList& decodedData );
+ quint8 index( const QList& data );
// Internal use methods
- bool deflateValue( DataSource &output, quint8 index, qint64 value );
+ bool deflateValue( DataSource* output, quint8 index, qint64 value );
}
}
diff --git a/contrib/isf-qt/src/data/compression.cpp b/contrib/isf-qt/src/data/compression.cpp
index 58770a2..8d8d1d7 100644
--- a/contrib/isf-qt/src/data/compression.cpp
+++ b/contrib/isf-qt/src/data/compression.cpp
@@ -42,9 +42,9 @@ using namespace Isf;
* @param decodedData List where to store the decoded values
* @return bool
*/
-bool Compress::inflatePacketData( DataSource &source, quint64 length, QList &decodedData )
+bool Compress::inflatePacketData( DataSource* source, quint64 length, QList& decodedData )
{
- if( source.atEnd() )
+ if( source->atEnd() )
{
#ifdef ISFQT_DEBUG
qWarning() << "Source was at end!";
@@ -52,8 +52,8 @@ bool Compress::inflatePacketData( DataSource &source, quint64 length, QListgetByte();
qint16 algorithm = ( byte & AlgorithmMask );
quint8 algorithmData = 0;
@@ -68,7 +68,7 @@ bool Compress::inflatePacketData( DataSource &source, quint64 length, QListgetByte(), 16 ) << "hex]";
return false;
}
// Use the "default compression" algorithm, which is Huffman
@@ -137,15 +137,15 @@ bool Compress::inflatePacketData( DataSource &source, quint64 length, QListseekRelative( -1 );
break;
}
// Discard any partially read bytes
- if( ! source.atEnd() )
+ if( ! source->atEnd() )
{
- source.skipToNextByte();
+ source->skipToNextByte();
}
return result;
@@ -163,7 +163,7 @@ bool Compress::inflatePacketData( DataSource &source, quint64 length, QList &source )
+bool Compress::deflatePacketData( QByteArray& encodedData, const QList& source )
{
bool result;
@@ -244,9 +244,9 @@ bool Compress::deflatePacketData( QByteArray &encodedData, const QList &
* @param decodedData List where to store the decoded values
* @return bool
*/
-bool Compress::inflatePropertyData( DataSource &source, quint64 length, QList &decodedData )
+bool Compress::inflatePropertyData( DataSource* source, quint64 length, QList& decodedData )
{
- if( source.atEnd() )
+ if( source->atEnd() )
{
#ifdef ISFQT_DEBUG
qWarning() << "Source was at end!";
@@ -255,7 +255,7 @@ bool Compress::inflatePropertyData( DataSource &source, quint64 length, QListgetByte();
qint16 algorithm = ( byte & AlgorithmMask );
quint8 algorithmData = 0;
@@ -270,7 +270,7 @@ bool Compress::inflatePropertyData( DataSource &source, quint64 length, QListgetByte(), 16 ) << "hex]";
return false;
}
// Use the "best compression" algorithm, which is Huffman
@@ -379,15 +379,15 @@ bool Compress::inflatePropertyData( DataSource &source, quint64 length, QListseekRelative( -1 );
break;
}
// Discard any partially read bytes
- if( ! source.atEnd() )
+ if( ! source->atEnd() )
{
- source.skipToNextByte();
+ source->skipToNextByte();
}
return result;
@@ -406,7 +406,7 @@ bool Compress::inflatePropertyData( DataSource &source, quint64 length, QList &source )
+bool Compress::deflatePropertyData( QByteArray& encodedData, const QList& source )
{
Q_UNUSED( encodedData );
Q_UNUSED( source );
diff --git a/contrib/isf-qt/src/data/compression.h b/contrib/isf-qt/src/data/compression.h
index 978f12f..7919fc5 100644
--- a/contrib/isf-qt/src/data/compression.h
+++ b/contrib/isf-qt/src/data/compression.h
@@ -112,11 +112,11 @@ namespace Isf
};
- bool inflatePacketData( DataSource &source, quint64 length, QList &decodedData );
- bool deflatePacketData( QByteArray &destination, const QList &decodedData );
+ bool inflatePacketData( DataSource* source, quint64 length, QList& decodedData );
+ bool deflatePacketData( QByteArray& destination, const QList& decodedData );
- bool inflatePropertyData( DataSource &source, quint64 length, QList &decodedData );
- bool deflatePropertyData( QByteArray &destination, const QList &decodedData );
+ bool inflatePropertyData( DataSource* source, quint64 length, QList& decodedData );
+ bool deflatePropertyData( QByteArray& destination, const QList& decodedData );
}
}
diff --git a/contrib/isf-qt/src/data/datasource.cpp b/contrib/isf-qt/src/data/datasource.cpp
index dd74643..a2f93b4 100644
--- a/contrib/isf-qt/src/data/datasource.cpp
+++ b/contrib/isf-qt/src/data/datasource.cpp
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -29,7 +27,7 @@
using namespace Isf;
-using namespace Compress;
+using namespace Isf::Compress;
@@ -51,7 +49,7 @@ DataSource::DataSource()
*
* @param data Byte array to copy and use as data source
*/
-DataSource::DataSource( const QByteArray &data )
+DataSource::DataSource( const QByteArray& data )
: currentBitIndex_( 8 )
{
buffer_.setData( data );
@@ -109,7 +107,7 @@ void DataSource::append( char byte )
*
* @param constBits The list of bits to append
*/
-void DataSource::append( const QBitArray &constBits )
+void DataSource::append( const QBitArray& constBits )
{
if( constBits.size() == 0 )
{
@@ -202,7 +200,7 @@ void DataSource::append( const QBitArray &constBits )
*
* @param bytes The bytes to append
*/
-void DataSource::append( const QByteArray &bytes )
+void DataSource::append( const QByteArray& bytes )
{
bool wasEmpty = ( buffer_.size() == 0 );
@@ -274,7 +272,7 @@ void DataSource::clear()
*
* @return byte array
*/
-const QByteArray &DataSource::data() const
+const QByteArray& DataSource::data() const
{
return buffer_.data();
}
@@ -328,7 +326,7 @@ quint8 DataSource::getBitIndex()
* @param ok If set, it will contain whether the call was successful or not.
* @return bool
*/
-bool DataSource::getBit( bool *ok )
+bool DataSource::getBit( bool* ok )
{
if( currentBitIndex_ >= 8 )
{
@@ -367,7 +365,7 @@ bool DataSource::getBit( bool *ok )
* @param ok If set, it will contain whether the call was successful or not.
* @return quint64 with the set of read bits
*/
-quint64 DataSource::getBits( quint8 amount, bool *ok )
+quint64 DataSource::getBits( quint8 amount, bool* ok )
{
if( amount > 64 )
{
@@ -436,7 +434,7 @@ quint64 DataSource::getBits( quint8 amount, bool *ok )
* @param ok If set, it will contain whether the call was successful or not.
* @return char
*/
-char DataSource::getByte( bool *ok )
+char DataSource::getByte( bool* ok )
{
bool gotBitOk;
quint8 pos = 0;
@@ -480,7 +478,7 @@ char DataSource::getByte( bool *ok )
* @param ok If set, it will contain whether the call was successful or not.
* @return byte array of read bytes
*/
-QByteArray DataSource::getBytes( quint8 amount, bool *ok )
+QByteArray DataSource::getBytes( quint8 amount, bool* ok )
{
QByteArray bytes;
bool gotByteOk;
@@ -600,7 +598,7 @@ void DataSource::prepend( char byte )
*
* @param bytes Bytes to add
*/
-void DataSource::prepend( const QByteArray &bytes )
+void DataSource::prepend( const QByteArray& bytes )
{
buffer_.buffer().prepend( bytes );
@@ -663,7 +661,7 @@ void DataSource::seekRelative( int pos )
*
* @param data New array to copy and use as the data source
*/
-void DataSource::setData( const QByteArray &data )
+void DataSource::setData( const QByteArray& data )
{
buffer_.close();
buffer_.setData( data );
diff --git a/contrib/isf-qt/src/data/datasource.h b/contrib/isf-qt/src/data/datasource.h
index 1c76d30..1e10fce 100644
--- a/contrib/isf-qt/src/data/datasource.h
+++ b/contrib/isf-qt/src/data/datasource.h
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -49,30 +47,30 @@ namespace Isf
public: // Public constructors
DataSource();
- DataSource( const QByteArray &data );
+ DataSource( const QByteArray& data );
~DataSource();
public: // Public status retrieval methods
bool atEnd( bool considerBits = false ) const;
- const QByteArray &data() const;
+ const QByteArray& data() const;
qint64 pos() const;
qint64 size() const;
public: // Public data manipulation methods
void append( char byte );
- void append( const QBitArray &bits );
- void append( const QByteArray &bytes );
+ void append( const QBitArray& bits );
+ void append( const QByteArray& bytes );
void clear();
void flush();
- bool getBit( bool *ok = 0 );
- quint64 getBits( quint8 amount, bool *ok = 0 );
+ bool getBit( bool* ok = 0 );
+ quint64 getBits( quint8 amount, bool* ok = 0 );
quint8 getBitIndex();
- char getByte( bool *ok = 0 );
- QByteArray getBytes( quint8 amount, bool *ok = 0 );
+ char getByte( bool* ok = 0 );
+ QByteArray getBytes( quint8 amount, bool* ok = 0 );
void prepend( char byte );
- void prepend( const QByteArray &bytes );
+ void prepend( const QByteArray& bytes );
void reset();
- void setData( const QByteArray &data );
+ void setData( const QByteArray& data );
void seekRelative( int pos );
void skipToNextByte();
void skipToPrevByte();
diff --git a/contrib/isf-qt/src/data/multibytecoding.cpp b/contrib/isf-qt/src/data/multibytecoding.cpp
index 86408b6..ba27789 100644
--- a/contrib/isf-qt/src/data/multibytecoding.cpp
+++ b/contrib/isf-qt/src/data/multibytecoding.cpp
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -40,7 +38,7 @@ using namespace Isf;
* @param source Data Source where to read bytes from
* @return quint64
*/
-quint64 Compress::decodeUInt( DataSource &source )
+quint64 Compress::decodeUInt( DataSource* source )
{
quint8 byte; // Current byte
quint8 flag; // Used to find out if there are more bytes to convert
@@ -49,7 +47,7 @@ quint64 Compress::decodeUInt( DataSource &source )
do
{
- byte = source.getByte();
+ byte = source->getByte();
flag = byte & 0x80;
value |= (byte & 0x7F) << count;
count += 7;
@@ -67,7 +65,7 @@ quint64 Compress::decodeUInt( DataSource &source )
* @param source Data Source where to read bytes from
* @return qint64
*/
-qint64 Compress::decodeInt( DataSource &source )
+qint64 Compress::decodeInt( DataSource* source )
{
bool isNegative = false;
qint64 value = decodeUInt( source );
@@ -98,7 +96,7 @@ qint64 Compress::decodeInt( DataSource &source )
* @param source Data Source where to read bytes from
* @return float
*/
-float Compress::decodeFloat( DataSource &source )
+float Compress::decodeFloat( DataSource* source )
{
qint8 index;
@@ -113,14 +111,14 @@ float Compress::decodeFloat( DataSource &source )
index = 3;
do
{
- data.bytes[ index-- ] = source.getByte();
+ data.bytes[ index-- ] = source->getByte();
}
while( index >= 0 );
#else
index = 0;
do
{
- data.bytes[ index++ ] = source.getByte();
+ data.bytes[ index++ ] = source->getByte();
}
while( index <= 3 );
#endif
@@ -170,17 +168,17 @@ QByteArray Compress::encodeUInt( quint64 value )
* @param prepend False (default value) to append the encoded value to the existing data
* True to prepend the new value to the existing data
*/
-void Compress::encodeUInt( DataSource &source, quint64 value, bool prepend )
+void Compress::encodeUInt( DataSource* source, quint64 value, bool prepend )
{
QByteArray result( encodeUInt( value ) );
if( prepend )
{
- source.prepend( result );
+ source->prepend( result );
}
else
{
- source.append( result );
+ source->append( result );
}
}
@@ -226,17 +224,17 @@ QByteArray Compress::encodeInt( qint64 value )
* @param prepend False (default value) to append the encoded value to the existing data
* True to prepend the new value to the existing data
*/
-void Compress::encodeInt( DataSource &source, qint64 value, bool prepend )
+void Compress::encodeInt( DataSource* source, qint64 value, bool prepend )
{
QByteArray result( encodeInt( value ) );
if( prepend )
{
- source.prepend( result );
+ source->prepend( result );
}
else
{
- source.append( result );
+ source->append( result );
}
}
@@ -291,17 +289,17 @@ QByteArray Compress::encodeFloat( float value )
* @param prepend False (default value) to append the encoded value to the existing data
* True to prepend the new value to the existing data
*/
-void Compress::encodeFloat( DataSource &source, float value, bool prepend )
+void Compress::encodeFloat( DataSource* source, float value, bool prepend )
{
QByteArray result( encodeFloat( value ) );
if( prepend )
{
- source.prepend( result );
+ source->prepend( result );
}
else
{
- source.append( result );
+ source->append( result );
}
}
diff --git a/contrib/isf-qt/src/data/multibytecoding.h b/contrib/isf-qt/src/data/multibytecoding.h
index 56d4229..bfab442 100644
--- a/contrib/isf-qt/src/data/multibytecoding.h
+++ b/contrib/isf-qt/src/data/multibytecoding.h
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -37,18 +35,18 @@ namespace Isf
namespace Compress
{
- quint64 decodeUInt( DataSource &source );
- qint64 decodeInt( DataSource &source );
- float decodeFloat( DataSource &source );
+ quint64 decodeUInt( DataSource* source );
+ qint64 decodeInt( DataSource* source );
+ float decodeFloat( DataSource* source );
QByteArray encodeUInt( quint64 value );
- void encodeUInt( DataSource &source, quint64 value, bool prepend = false );
+ void encodeUInt( DataSource* source, quint64 value, bool prepend = false );
QByteArray encodeInt( qint64 value );
- void encodeInt( DataSource &source, qint64 value, bool prepend = false );
+ void encodeInt( DataSource* source, qint64 value, bool prepend = false );
QByteArray encodeFloat( float value );
- void encodeFloat( DataSource &source, float value, bool prepend = false );
+ void encodeFloat( DataSource* source, float value, bool prepend = false );
quint8 getMultiByteSize( quint64 value );
quint8 getMultiByteSize( qint64 value );
diff --git a/contrib/isf-qt/src/gif-support.h b/contrib/isf-qt/src/gif-support.h
index 04d2d93..90640d0 100644
--- a/contrib/isf-qt/src/gif-support.h
+++ b/contrib/isf-qt/src/gif-support.h
@@ -28,18 +28,18 @@
// Internal helper function to read GIF data from a byte array
-int GifReadFromByteArray( GifFileType *gif, GifByteType* bytes, int size )
+int GifReadFromByteArray( GifFileType* gif, GifByteType* bytes, int size )
{
- QBuffer *buffer = (QBuffer*) gif->UserData;
+ QBuffer* buffer = (QBuffer*) gif->UserData;
return buffer->read( (char*)bytes, size );
}
// Internal helper function to write GIF data into a byte array
-int GifWriteToByteArray( GifFileType *gif, const GifByteType* bytes, int size )
+int GifWriteToByteArray( GifFileType* gif, const GifByteType* bytes, int size )
{
- QBuffer *buffer = (QBuffer*) gif->UserData;
+ QBuffer* buffer = (QBuffer*) gif->UserData;
return buffer->write( (char*)bytes, size );
}
diff --git a/contrib/isf-qt/src/isfinkcanvas.cpp b/contrib/isf-qt/src/isfinkcanvas.cpp
index 26715a8..13df213 100644
--- a/contrib/isf-qt/src/isfinkcanvas.cpp
+++ b/contrib/isf-qt/src/isfinkcanvas.cpp
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -43,7 +41,7 @@ using namespace Isf;
*
* @param parent The parent widget.
*/
-InkCanvas:: InkCanvas( QWidget *parent )
+InkCanvas:: InkCanvas( QWidget* parent )
: QWidget( parent )
, erasingImage_( false )
, drawing_( 0 )
@@ -59,6 +57,10 @@ InkCanvas:: InkCanvas( QWidget *parent )
setPenColor( Qt::black );
setPenSize( 4 );
+ setAttribute( Qt::WA_StaticContents, true ); // only give us paint events for the parts of us that become visible on resize.
+
+ setAutoFillBackground( true );
+
clear();
// prepare the buffer
@@ -69,8 +71,6 @@ InkCanvas:: InkCanvas( QWidget *parent )
// start with a drawing pen by default.
setPenType( DrawingPen );
-
- setAttribute( Qt::WA_StaticContents );
}
@@ -90,62 +90,13 @@ InkCanvas::~InkCanvas()
/**
- * Creates a QCursor displayed when the mouse pointer moves over the widget.
+ * Returns the drawing's ISF representation.
*
- * The cursor becomes a point, drawn with the current stroke colour and pen size.
+ * @return A QByteArray filled with ISF data.
*/
-void InkCanvas::updateCursor()
+QByteArray InkCanvas::bytes()
{
- if ( cursorPixmap_.isNull() )
- {
- cursorPixmap_ = QPixmap( QSize( 32, 32 ) );
- }
-
- if ( penType_ == EraserPen )
- {
- cursorPixmap_ = QPixmap( ":pics/draw-eraser.png" );
- cursor_ = QCursor( cursorPixmap_, 0, cursorPixmap_.height() );
- }
- else
- {
- cursorPixmap_.fill( Qt::transparent );
-
- QPainter painter( &cursorPixmap_ );
-
- painter.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform, true );
- painter.setPen( QPen( color_, penSize_, Qt::SolidLine, Qt::RoundCap,
- Qt::RoundJoin ) );
-
- // now draw a point.
- painter.drawPoint( QPoint( cursorPixmap_.size().width() / 2, cursorPixmap_.size().height() / 2 ) );
-
- cursor_ = QCursor( cursorPixmap_ );
- }
-
- // create our cursor.
- setCursor( cursor_ );
-}
-
-
-
-/**
- * Return the suggested size for the canvas.
- *
- * The actual size hint will depend on the size of the drawing on the canvas. By default,
- * the size hint is 300x300 pixels.
- */
-QSize InkCanvas::sizeHint() const
-{
- if ( drawing_->isNull() )
- {
- return QSize( 300, 300 );
- }
- else
- {
- QRect boundingRect = drawing_->boundingRect();
- boundingRect.setTopLeft( QPoint( 0, 0 ) );
- return boundingRect.size();
- }
+ return Isf::Stream::writer( *drawing_ );
}
@@ -174,58 +125,47 @@ void InkCanvas::clear()
/**
- * Change the color of the pen used to draw on the Ink canvas.
+ * Clear the internal pixmap buffer.
*
- * @param newColor The new color for the pen.
+ * The buffer used to quickly render on the widget painting area
+ * the new and old strokes: every new stroke is saved here.
+ * This allows to avoid repainting all strokes at every paint event.
*/
-void InkCanvas::setPenColor( QColor newColor )
+void InkCanvas::clearBuffer()
{
-#ifdef ISFQT_DEBUG
- qDebug() << "Setting new pen color:" << newColor.name();
-#endif
-
- color_ = newColor;
-
- updateCursor();
+ bufferPixmap_ = QPixmap( size() );
+ bufferPixmap_.fill( Qt::transparent );
}
/**
- * Change the size of the pen. This value is in pixels.
+ * Retrieve the Isf::Drawing instance that the canvas is currently manipulating.
*
- * @param pixels The size of the pen, in pixels
+ * Beware: if you have not set your own Isf::Drawing instance via setDrawing(), you must not delete
+ * the object that this method returns. In this case this method returns a pointer to an internal
+ * Isf::Drawing instance that must not be deleted. If you have previously used setDrawing() then you
+ * are free to do whatever you like with this pointer.
+ *
+ * \code
+ * InkCanvas* canvas = new InkCanvas( this );
+ *
+ * Isf::Drawing* drawing = canvas->drawing();
+ * delete drawing; // bad! deleting an object internal to InkCanvas.
+ *
+ * canvas->setDrawing( existingIsfDrawingInstance );
+ *
+ * drawing = canvas->drawing();
+ * delete drawing; // good - drawing points to existingIsfDrawingInstance.
+ * \endcode
+ *
+ *
+ * @see setDrawing()
+ * @return The current Isf::Drawing instance.
*/
-void InkCanvas::setPenSize( int pixels )
+Isf::Drawing* InkCanvas::drawing()
{
-#ifdef ISFQT_DEBUG
- qDebug() << "Setting new pen size:" << pixels;
-#endif
- penSize_ = pixels;
-
- updateCursor();
-}
-
-
-
-/**
- * Change the pen type.
- *
- * Currently, only PenType::EraserPen and PenType::DrawingPen are supported. See the PenType
- * enum for more information.
- *
- * @see PenType
- * @param type The new pen type
- */
-void InkCanvas::setPenType( PenType type )
-{
-#ifdef ISFQT_DEBUG
- qDebug() << "Setting new pen type:" << type;
-#endif
-
- penType_ = type;
-
- updateCursor();
+ return drawing_;
}
@@ -239,16 +179,12 @@ void InkCanvas::setPenType( PenType type )
* @see mousePressEvent()
* @param endPoint Final point of the line
*/
-void InkCanvas::drawLineTo( const QPoint &endPoint )
+void InkCanvas::drawLineTo( const QPoint& endPoint )
{
- if( drawing_ == 0 )
- {
- qWarning() << "Uninitialized usage of InkCanvas!";
- return;
- }
+ Q_ASSERT_X( drawing_, "drawLineTo", "Drawing is null" );
// draw the "in progress" strokes on the buffer.
- QPainter painter( &(bufferPixmap_) );
+ QPainter painter( &bufferPixmap_ );
painter.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform, true );
QColor color = color_;
@@ -282,6 +218,18 @@ void InkCanvas::drawLineTo( const QPoint &endPoint )
+/**
+ * Renders the ink drawing to a QImage and returns it.
+ *
+ * @return A QImage containing the rendered Ink.
+ */
+QImage InkCanvas::image()
+{
+ return drawing_->pixmap( Qt::white ).toImage();
+}
+
+
+
/**
* Get whether the drawing is empty (i.e., contains no strokes).
*
@@ -306,13 +254,9 @@ bool InkCanvas::isEmpty()
* @see mouseReleaseEvent()
* @param event The mouse button press event
*/
-void InkCanvas::mousePressEvent( QMouseEvent *event )
+void InkCanvas::mousePressEvent( QMouseEvent* event )
{
- if( drawing_ == 0 )
- {
- qWarning() << "Uninitialized usage of InkCanvas!";
- return;
- }
+ Q_ASSERT_X( drawing_, "mousePressEvent", "Drawing is null" );
if( event->button() != Qt::LeftButton )
{
@@ -325,7 +269,7 @@ void InkCanvas::mousePressEvent( QMouseEvent *event )
{
// is there a stroke here?
QPoint point = event->pos();
- Stroke *s = drawing_->strokeAtPoint( point );
+ Stroke* s = drawing_->strokeAtPoint( point );
if ( s != 0 )
{
drawing_->deleteStroke( s );
@@ -338,47 +282,19 @@ void InkCanvas::mousePressEvent( QMouseEvent *event )
lastPoint_ = event->pos();
- // Search if there already is an attributes set compatible with the current one
- Isf::AttributeSet *reusableAttributeSet = 0;
- foreach( Isf::AttributeSet *set, drawing_->attributeSets() )
- {
- if( abs( (qreal)penSize_ - set->penSize.width() ) < 1.0f
- && color_ == set->color )
- {
- reusableAttributeSet = set;
-#ifdef ISFQT_DEBUG
- qDebug() << "Found an usable ISF attribute set";
-#endif
- break;
- }
- }
-
- // If none is found, create a new one
- if( ! reusableAttributeSet )
- {
-#ifdef ISFQT_DEBUG
- qDebug() << "Creating new attribute set";
-#endif
- reusableAttributeSet = new Isf::AttributeSet;
- reusableAttributeSet->color = color_;
- reusableAttributeSet->penSize.setWidth ( (qreal)penSize_ );
- reusableAttributeSet->penSize.setHeight( (qreal)penSize_ );
-
- drawing_->addAttributeSet( reusableAttributeSet );
- }
-
- // Use it for the next strokes
- drawing_->setCurrentAttributeSet( reusableAttributeSet );
-
// If there already is a stroke, add it
if( currentStroke_ )
{
+ currentStroke_->finalize();
drawing_->addStroke( currentStroke_ );
currentStroke_ = 0;
}
- currentStroke_ = new Isf::Stroke;
- currentStroke_->points.append( Isf::Point( lastPoint_ ) );
+ currentStroke_ = new Isf::Stroke();
+ currentStroke_->addPoint( lastPoint_ );
+ currentStroke_->setColor( color_ );
+ currentStroke_->setPenSize( QSizeF( (qreal)penSize_, (qreal)penSize_ ) );
+ currentStroke_->setFlag( FitToCurve, true );
// Draw the initial point
drawLineTo( lastPoint_ );
@@ -390,7 +306,7 @@ void InkCanvas::mousePressEvent( QMouseEvent *event )
* Continue drawing the current stroke.
*
* As the cursor moves across the canvas we continue drawing the stroke started in
- * mousePressEvent(). A line is drawn between the last point and the current point
+ * mousePressEvent(). A line is drawn between the last point and the current point
* as given by QMouseEvent::pos().
*
* Once the mouse button is released, drawing ends.
@@ -399,18 +315,20 @@ void InkCanvas::mousePressEvent( QMouseEvent *event )
* @see mouseReleaseEvent()
* @param event The mouse move event
*/
-void InkCanvas::mouseMoveEvent( QMouseEvent *event )
+void InkCanvas::mouseMoveEvent( QMouseEvent* event )
{
if( ! ( event->buttons() & Qt::LeftButton ) || ! scribbling_ )
{
return;
}
+ Q_ASSERT_X( drawing_, "mouseMoveEvent", "Drawing is null" );
+
if ( penType_ == EraserPen )
{
// is there a stroke here?
QPoint point = event->pos();
- Stroke *s = drawing_->strokeAtPoint( point );
+ Stroke* s = drawing_->strokeAtPoint( point );
if ( s != 0 )
{
drawing_->deleteStroke( s );
@@ -421,12 +339,6 @@ void InkCanvas::mouseMoveEvent( QMouseEvent *event )
return;
}
- if( drawing_ == 0 )
- {
- qWarning() << "Uninitialized usage of InkCanvas!";
- return;
- }
-
QPoint position( event->pos() );
// Don't add duplicate points. Mainly useful when drawing dots.
@@ -437,16 +349,10 @@ void InkCanvas::mouseMoveEvent( QMouseEvent *event )
drawLineTo( position );
- if( currentStroke_ == 0 )
- {
-#ifdef KMESSDEBUG_INKEDIT_GENERAL
- qWarning() << "The stroke isn't ready!";
-#endif
- return;
- }
+ Q_ASSERT_X( currentStroke_, "mouseMoveEvent", "currentStroke_ is null" );
// Add the new point to the stroke
- currentStroke_->points.append( Isf::Point( lastPoint_ ) );
+ currentStroke_->addPoint( lastPoint_ );
}
@@ -460,13 +366,9 @@ void InkCanvas::mouseMoveEvent( QMouseEvent *event )
* @see mouseMoveEvent()
* @param event The mouse release event
*/
-void InkCanvas::mouseReleaseEvent( QMouseEvent *event )
+void InkCanvas::mouseReleaseEvent( QMouseEvent* event )
{
- if( drawing_ == 0 )
- {
- qWarning() << "Uninitialized usage of InkCanvas!";
- return;
- }
+ Q_ASSERT_X( drawing_, "mouseReleaseEvent", "Drawing is null" );
if( event->button() != Qt::LeftButton || ! scribbling_ )
{
@@ -486,16 +388,7 @@ void InkCanvas::mouseReleaseEvent( QMouseEvent *event )
drawLineTo( position );
}
- scribbling_ = false;
- emit inkChanged();
-
- if( ! currentStroke_ )
- {
-#ifdef KMESSDEBUG_INKEDIT_GENERAL
- qWarning() << "The stroke isn't ready!";
-#endif
- return;
- }
+ Q_ASSERT_X( currentStroke_, "mouseReleaseEvent", "currentStroke_ is null" );
#ifdef KMESSDEBUG_INKEDIT_GENERAL
qDebug() << "Finishing up stroke";
@@ -504,9 +397,10 @@ void InkCanvas::mouseReleaseEvent( QMouseEvent *event )
// Don't add duplicate points. Mainly useful when drawing dots.
if( lastPoint_ != position )
{
- currentStroke_->points.append( Isf::Point( lastPoint_ ) );
+ currentStroke_->addPoint( lastPoint_ );
}
+ currentStroke_->finalize();
drawing_->addStroke( currentStroke_ );
currentStroke_ = 0;
@@ -515,24 +409,12 @@ void InkCanvas::mouseReleaseEvent( QMouseEvent *event )
// clear the buffer.
clearBuffer();
-
+
// update
update();
-}
-
-
-/**
- * Clear the internal pixmap buffer.
- *
- * The buffer used to quickly render on the widget painting area
- * the new and old strokes: every new stroke is saved here.
- * This allows to avoid repainting all strokes at every paint event.
- */
-void InkCanvas::clearBuffer()
-{
- bufferPixmap_ = QPixmap( size() );
- bufferPixmap_.fill( Qt::transparent );
+ scribbling_ = false;
+ emit inkChanged();
}
@@ -542,28 +424,19 @@ void InkCanvas::clearBuffer()
*
* For performance reasons an internal buffer is used to ensure that
* the entire Ink drawing is not re-rendered on each paintEvent call.
- * This buffer is invalidated only when a stroke is added or removed, the
+ * This buffer is invalidated only when a stroke is added or removed, the
* drawing is changed or the canvas cleared.
*
*
* @param event The paint event from Qt.
*/
-void InkCanvas::paintEvent( QPaintEvent *event )
+void InkCanvas::paintEvent( QPaintEvent* event )
{
Q_UNUSED( event );
QPainter painter( this );
- painter.save();
- painter.setBrush( QBrush( canvasColor_ ) );
- painter.drawRect( QRect(-1, -1, width() + 1 , height() + 1 ) );
- painter.restore();
-
- if( drawing_ == 0 )
- {
- qWarning() << "Uninitialized usage of InkCanvas!";
- return;
- }
+ Q_ASSERT_X( drawing_, "paintEvent", "Drawing is null" );
// draw the ISF first, then the buffer over the top.
// buffer has a transparent background.
@@ -586,42 +459,13 @@ void InkCanvas::paintEvent( QPaintEvent *event )
painter.drawPixmap( boundingRect.topLeft(), isfPixmap );
// draw the buffer from 0,0.
- painter.drawPixmap( QPoint(0, 0), bufferPixmap_ );
+ painter.drawPixmap( event->rect(), bufferPixmap_, event->rect() );
QWidget::paintEvent( event );
}
-/**
- * The widget has changed size, re-draw everything.
- *
- * @param event The resizing event.
- */
-void InkCanvas::resizeEvent( QResizeEvent *event )
-{
- // need to resize the buffer pixmap.
- clearBuffer();
-
- update();
-
- QWidget::resizeEvent( event );
-}
-
-
-
-/**
- * Renders the ink drawing to a QImage and returns it.
- *
- * @return A QImage containing the rendered Ink.
- */
-QImage InkCanvas::image()
-{
- return drawing_->pixmap().toImage();
-}
-
-
-
/**
* Get the current pen color.
*
@@ -662,32 +506,18 @@ InkCanvas::PenType InkCanvas::penType()
/**
- * Retrieve the Isf::Drawing instance that the canvas is currently manipulating.
+ * The widget has changed size, re-draw everything.
*
- * Beware: if you have not set your own Isf::Drawing instance via setDrawing(), you must not delete
- * the object that this method returns. In this case this method returns a pointer to an internal
- * Isf::Drawing instance that must not be deleted. If you have previously used setDrawing() then you
- * are free to do whatever you like with this pointer.
- *
- * \code
- * InkCanvas *canvas = new InkCanvas( this );
- *
- * Isf::Drawing *drawing = canvas->drawing();
- * delete drawing; // bad! deleting an object internal to InkCanvas.
- *
- * canvas->setDrawing( existingIsfDrawingInstance );
- *
- * drawing = canvas->drawing();
- * delete drawing; // good - drawing points to existingIsfDrawingInstance.
- * \endcode
- *
- *
- * @see setDrawing()
- * @return The current Isf::Drawing instance.
+ * @param event The resizing event.
*/
-Isf::Drawing *InkCanvas::drawing()
+void InkCanvas::resizeEvent( QResizeEvent* event )
{
- return drawing_;
+ // need to resize the buffer pixmap.
+ clearBuffer();
+
+ update();
+
+ QWidget::resizeEvent( event );
}
@@ -695,8 +525,8 @@ Isf::Drawing *InkCanvas::drawing()
/**
* Save the current ISF drawing to a QIODevice.
*
- * If the base64 param is True, then the drawing will be written base64-encoded.
- * This is helpful for transmission over mediums which are not binary-friendly.
+ * If the base64 param is true, then the drawing will be written base64-encoded.
+ * This is helpful for transmission over binary-unfriendly media.
*
* @param dev The QIODevice to save to.
* @param base64 If true, the drawing is written encoded with base64.
@@ -709,18 +539,6 @@ void InkCanvas::save( QIODevice &dev, bool base64 )
-/**
- * Returns the drawing's ISF representation.
- *
- * @return A QByteArray filled with ISF data.
- */
-QByteArray InkCanvas::bytes()
-{
- return Isf::Stream::writer( *drawing_ );
-}
-
-
-
/**
* Set the canvas colour (i.e., the background colour of the InkCanvas control)
*
@@ -734,6 +552,10 @@ void InkCanvas::setCanvasColor( QColor newColor )
qDebug() << "Setting new canvas color:" << newColor.name();
#endif
canvasColor_ = newColor;
+
+ QPalette p = palette();
+ p.setColor( QPalette::Window, newColor );
+ setPalette( p );
update();
}
@@ -743,11 +565,11 @@ void InkCanvas::setCanvasColor( QColor newColor )
* Changes the currently displayed Ink to the one supplied.
*
* Note: InkCanvas does not take ownership of Isf::Drawing instances supplied here.
- * You are still responsible for ensuring they are deleted appropriately.
+ * You are still responsible of ensuring they are deleted appropriately.
*
* @param drawing The new Ink drawing to display.
*/
-void InkCanvas::setDrawing( Isf::Drawing *drawing )
+void InkCanvas::setDrawing( Isf::Drawing* drawing )
{
drawing_ = drawing;
@@ -760,7 +582,126 @@ void InkCanvas::setDrawing( Isf::Drawing *drawing )
drawingDirty_ = true;
+ updateGeometry();
update();
}
+
+/**
+ * Change the color of the pen used to draw on the Ink canvas.
+ *
+ * @param newColor The new color for the pen.
+ */
+void InkCanvas::setPenColor( QColor newColor )
+{
+#ifdef ISFQT_DEBUG
+ qDebug() << "Setting new pen color:" << newColor.name();
+#endif
+
+ color_ = newColor;
+
+ updateCursor();
+}
+
+
+
+/**
+ * Change the size of the pen. This value is in pixels.
+ *
+ * @param pixels The size of the pen, in pixels
+ */
+void InkCanvas::setPenSize( int pixels )
+{
+#ifdef ISFQT_DEBUG
+ qDebug() << "Setting new pen size:" << pixels;
+#endif
+ penSize_ = pixels;
+
+ updateCursor();
+}
+
+
+
+/**
+ * Change the pen type.
+ *
+ * Currently, only PenType::EraserPen and PenType::DrawingPen are supported. See the PenType
+ * enum for more information.
+ *
+ * @see PenType
+ * @param type The new pen type
+ */
+void InkCanvas::setPenType( PenType type )
+{
+#ifdef ISFQT_DEBUG
+ qDebug() << "Setting new pen type:" << type;
+#endif
+
+ penType_ = type;
+
+ updateCursor();
+}
+
+
+
+/**
+ * Return the suggested size for the canvas.
+ *
+ * The actual size hint will depend on the size of the drawing on the canvas. By default,
+ * the size hint is 300x300 pixels.
+ */
+QSize InkCanvas::sizeHint() const
+{
+ if ( drawing_->isNull() )
+ {
+ return QSize( 300, 300 );
+ }
+ else
+ {
+ QRect boundingRect = drawing_->boundingRect();
+ boundingRect.setTopLeft( QPoint( 0, 0 ) );
+ return boundingRect.size();
+ }
+}
+
+
+
+/**
+ * Creates a QCursor displayed when the mouse pointer moves over the widget.
+ *
+ * The cursor becomes a point, drawn with the current stroke colour and pen size.
+ */
+void InkCanvas::updateCursor()
+{
+ if ( cursorPixmap_.isNull() )
+ {
+ cursorPixmap_ = QPixmap( QSize( 32, 32 ) );
+ }
+
+ if ( penType_ == EraserPen )
+ {
+ cursorPixmap_ = QPixmap( ":pics/draw-eraser.png" );
+ cursor_ = QCursor( cursorPixmap_, 0, cursorPixmap_.height() );
+ }
+ else
+ {
+ cursorPixmap_.fill( Qt::transparent );
+
+ QPainter painter( &cursorPixmap_ );
+
+ painter.setRenderHints( QPainter::Antialiasing | QPainter::SmoothPixmapTransform, true );
+ painter.setPen( QPen( color_, penSize_, Qt::SolidLine, Qt::RoundCap,
+ Qt::RoundJoin ) );
+
+ // now draw a point.
+ painter.drawPoint( QPoint( cursorPixmap_.size().width() / 2, cursorPixmap_.size().height() / 2 ) );
+
+ cursor_ = QCursor( cursorPixmap_ );
+ }
+
+ // create our cursor.
+ setCursor( cursor_ );
+}
+
+
diff --git a/contrib/isf-qt/src/isfqt-internal.h b/contrib/isf-qt/src/isfqt-internal.h
index c07ec6e..95eb5ba 100644
--- a/contrib/isf-qt/src/isfqt-internal.h
+++ b/contrib/isf-qt/src/isfqt-internal.h
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -44,6 +42,12 @@
namespace Isf
{
+ // Forward declarations
+ class Stroke;
+ namespace Compress
+ {
+ class DataSource;
+ }
@@ -114,6 +118,104 @@ namespace Isf
+ /**
+ * Drawing attributes for points.
+ */
+ struct AttributeSet
+ {
+ /// Constructor
+ AttributeSet()
+ : color( Qt::black )
+ , flags( 0x10 ) // Meaning unknown
+ , penSize( 8.f, 8.f ) // Default pen is 8.0 pixels wide
+ {
+ }
+ /// Quick comparison operator
+ bool operator ==( const AttributeSet& other )
+ {
+ return color == other.color
+ && flags == other.flags
+ && penSize == other.penSize;
+ }
+ /// Quick comparison operator
+ bool operator !=( const AttributeSet& other )
+ {
+ return color != other.color
+ || flags != other.flags
+ || penSize != other.penSize;
+ }
+
+ /// The stroke color, optionally with alpha channel
+ QColor color;
+ /// Mask of StrokeFlags, @see StrokeFlags
+ StrokeFlags flags;
+ /// Dimensions of the pencil in pixels
+ QSizeF penSize;
+ };
+
+
+
+ /**
+ * Drawing attributes for strokes.
+ */
+ struct StrokeInfo
+ {
+ /// Constructor
+ StrokeInfo()
+ : hasPressureData( false )
+ , hasXData( true )
+ , hasYData( true )
+ {
+ }
+
+ /// Whether the stroke contains pressure info or not
+ bool hasPressureData;
+ /// Whether the stroke contains X coordinates or not
+ bool hasXData;
+ /// Whether the stroke contains Y coordinates or not
+ bool hasYData;
+ };
+
+
+
+ /**
+ * Internal parser data
+ */
+ struct StreamData
+ {
+ StreamData()
+ : currentAttributeSetIndex( 0 )
+ , currentMetricsIndex( 0 )
+ , currentStrokeInfoIndex( 0 )
+ , currentTransformsIndex( 0 )
+ , dataSource( 0 )
+ {
+ }
+
+ /// List of attributes of the points in the drawing
+ QList attributeSets;
+ /// Drawing's bounding rectangle
+ QRect boundingRect;
+ /// Current attribute set
+ quint64 currentAttributeSetIndex;
+ /// Current metrics set
+ quint64 currentMetricsIndex;
+ /// Current stroke info
+ quint64 currentStrokeInfoIndex;
+ /// Current transform
+ quint64 currentTransformsIndex;
+ /// Raw bytes source used to read and write streams
+ Compress::DataSource* dataSource;
+ /// List of metrics used in the drawing
+ QList metrics;
+ /// List of stroke info
+ QList strokeInfos;
+ /// Transformation matrices
+ QList transforms;
+ };
+
+
+
}
diff --git a/contrib/isf-qt/src/isfqt.cpp b/contrib/isf-qt/src/isfqt.cpp
index e0dfeef..f7777f2 100644
--- a/contrib/isf-qt/src/isfqt.cpp
+++ b/contrib/isf-qt/src/isfqt.cpp
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -48,6 +46,10 @@ using namespace Compress;
#define SUPPORTED_ISF_VERSION 0
+// Initialization of static properties
+StreamData* Stream::streamData_( 0 );
+
+
/**
* Convert a raw ISF data stream into a drawing.
@@ -59,23 +61,26 @@ using namespace Compress;
* need to be decoded first
* @return an Isf::Drawing, with null contents on error
*/
-Drawing &Stream::reader( const QByteArray &rawData, bool decodeFromBase64 )
+Drawing& Stream::reader( const QByteArray& rawData, bool decodeFromBase64 )
{
// Create a new drawing on the heap to ensure it will keep
// living after this method returns
- Drawing *drawing = new Drawing;
- DataSource isfData( decodeFromBase64
- ? QByteArray::fromBase64( rawData )
- : rawData );
- int size = isfData.size();
-
- if( size == 0 )
- {
- return *drawing;
- }
+ Drawing* drawing = new Drawing();
ParserState state = ISF_PARSER_START;
+ streamData_ = new StreamData();
+ streamData_->dataSource = new DataSource( decodeFromBase64
+ ? QByteArray::fromBase64( rawData )
+ : rawData );
+
+ int size = streamData_->dataSource->size();
+ if( size == 0 )
+ {
+ state = ISF_PARSER_FINISH;
+ drawing->error_ = ISF_ERROR_BAD_STREAMSIZE;
+ }
+
while( state != ISF_PARSER_FINISH )
{
switch( state )
@@ -83,7 +88,7 @@ Drawing &Stream::reader( const QByteArray &rawData, bool decodeFromBase64 )
case ISF_PARSER_START:
{
// step 1: read ISF version.
- quint8 version = decodeUInt( isfData );
+ quint8 version = decodeUInt( streamData_->dataSource );
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "Version:" << version;
#endif
@@ -106,13 +111,13 @@ Drawing &Stream::reader( const QByteArray &rawData, bool decodeFromBase64 )
{
// read ISF stream size.
// check it matches the length of the data array.
- quint64 streamSize = decodeUInt( isfData );
+ quint64 streamSize = decodeUInt( streamData_->dataSource );
- if ( streamSize != (quint64)( isfData.size() - isfData.pos() ) )
+ if ( streamSize != (quint64)( streamData_->dataSource->size() - streamData_->dataSource->pos() ) )
{
#ifdef ISFQT_DEBUG
qDebug() << "Invalid stream size" << streamSize
- << ", expected" << ( isfData.size() - isfData.pos() );
+ << ", expected" << ( streamData_->dataSource->size() - streamData_->dataSource->pos() );
#endif
// streamsize is bad.
drawing->error_ = ISF_ERROR_BAD_STREAMSIZE;
@@ -126,12 +131,6 @@ Drawing &Stream::reader( const QByteArray &rawData, bool decodeFromBase64 )
// Validate the drawing
drawing->isNull_ = false;
- // Fill up the default properties
- drawing->currentMetrics_ = &drawing->defaultMetrics_;
- drawing->currentAttributeSet_ = &drawing->defaultAttributeSet_;
- drawing->currentStrokeInfo_ = &drawing->defaultStrokeInfo_;
- drawing->currentTransform_ = &drawing->defaultTransform_;
-
// start looking for ISF tags.
state = ISF_PARSER_TAG;
}
@@ -139,331 +138,16 @@ Drawing &Stream::reader( const QByteArray &rawData, bool decodeFromBase64 )
break;
}
- // ******************
- // This is the key point of the state machine. This will continually loop looking for ISF
- // tags and farming off to the appropriate method.
- // *******************
case ISF_PARSER_TAG:
{
- if( isfData.atEnd() )
+ if( streamData_->dataSource->atEnd() )
{
state = ISF_PARSER_FINISH;
break;
}
- QString place( "0x" + QString::number( isfData.pos(), 16 ).toUpper() );
- quint64 tagIndex = decodeUInt( isfData );
-
- switch( tagIndex )
- {
- case TAG_INK_SPACE_RECT:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_INK_SPACE_RECT";
-#endif
- drawing->error_ = TagsParser::parseInkSpaceRectangle( isfData, *drawing );
- break;
-
- case TAG_GUID_TABLE:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_GUID_TABLE";
-#endif
- drawing->error_ = TagsParser::parseGuidTable( isfData, *drawing );
- break;
-
- case TAG_DRAW_ATTRS_TABLE:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_DRAW_ATTRS_TABLE";
-#endif
- drawing->error_ = TagsParser::parseAttributeTable( isfData, *drawing );
- break;
-
- case TAG_DRAW_ATTRS_BLOCK:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_DRAW_ATTRS_BLOCK";
-#endif
- drawing->error_ = TagsParser::parseAttributeBlock( isfData, *drawing );
- break;
-
- case TAG_STROKE_DESC_TABLE:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_STROKE_DESC_TABLE";
-#endif
- drawing->error_ = TagsParser::parseStrokeDescTable( isfData, *drawing );
- break;
-
- case TAG_STROKE_DESC_BLOCK:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_STROKE_DESC_BLOCK";
-#endif
- drawing->error_ = TagsParser::parseStrokeDescBlock( isfData, *drawing );
- break;
-
- case TAG_BUTTONS:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_BUTTONS";
-#endif
- drawing->error_ = TagsParser::parseUnsupported( isfData, "TAG_BUTTONS" );
- break;
-
- case TAG_NO_X:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_NO_X";
-#endif
- drawing->error_ = ISF_ERROR_NONE;
-
- drawing->hasXData_ = false;
- break;
-
- case TAG_NO_Y:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_NO_Y";
-#endif
- drawing->hasYData_ = false;
- break;
-
- case TAG_DIDX:
- {
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_DIDX";
-#endif
-
- quint64 value = decodeUInt( isfData );
-
- if( value < (uint)drawing->attributeSets_.count() )
- {
- drawing->currentAttributeSet_ = drawing->attributeSets_[ value ];
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Next strokes will use drawing attributes #" << value;
-#endif
- }
- else
- {
-#ifdef ISFQT_DEBUG
- qWarning() << "Invalid drawing attribute ID!";
-#endif
- }
- break;
- }
-
- case TAG_STROKE:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_STROKE";
-#endif
- drawing->error_ = TagsParser::parseStroke( isfData, *drawing );
- break;
-
- case TAG_STROKE_PROPERTY_LIST:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_STROKE_PROPERTY_LIST";
-#endif
- drawing->error_ = TagsParser::parseUnsupported( isfData, "TAG_STROKE_PROPERTY_LIST" );
- break;
-
- case TAG_POINT_PROPERTY:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_POINT_PROPERTY";
-#endif
- drawing->error_ = TagsParser::parseUnsupported( isfData, "TAG_POINT_PROPERTY" );
- break;
-
- case TAG_SIDX:
- {
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_SIDX";
-#endif
-
- quint64 value = decodeUInt( isfData );
-
- if( value < (uint)drawing->strokeInfo_.count() )
- {
- drawing->currentStrokeInfo_ = drawing->strokeInfo_[ value ];
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Next strokes will use stroke info #" << value;
-#endif
- }
- else
- {
-#ifdef ISFQT_DEBUG
- qWarning() << "Invalid stroke ID!";
-#endif
- }
- break;
- }
-
- case TAG_COMPRESSION_HEADER:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_COMPRESSION_HEADER";
-#endif
- drawing->error_ = TagsParser::parseUnsupported( isfData, "TAG_COMPRESSION_HEADER" );
- break;
-
- case TAG_TRANSFORM_TABLE:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_TABLE";
-#endif
- drawing->error_ = TagsParser::parseTransformationTable( isfData, *drawing );
- break;
-
- case TAG_TRANSFORM:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM";
-#endif
- drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
- break;
-
- case TAG_TRANSFORM_ISOTROPIC_SCALE:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_ISOTROPIC_SCALE";
-#endif
- drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
- break;
-
- case TAG_TRANSFORM_ANISOTROPIC_SCALE:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_ANISOTROPIC_SCALE";
-#endif
- drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
- break;
-
- case TAG_TRANSFORM_ROTATE:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_ROTATE";
-#endif
- drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
- break;
-
- case TAG_TRANSFORM_TRANSLATE:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_TRANSLATE";
-#endif
- drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
- break;
-
- case TAG_TRANSFORM_SCALE_AND_TRANSLATE:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_SCALE_AND_TRANSLATE";
-#endif
- drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
- break;
-
- case TAG_TRANSFORM_QUAD:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_QUAD";
-#endif
- drawing->error_ = TagsParser::parseTransformation( isfData, *drawing, tagIndex );
- break;
-
- case TAG_TIDX:
- {
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_TIDX";
-#endif
-
- quint64 value = decodeUInt( isfData );
-
- if( value < (uint)drawing->transforms_.count() )
- {
- drawing->currentTransform_ = drawing->transforms_[ value ];
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Next strokes will use transform #" << value;
-#endif
- }
- else
- {
-#ifdef ISFQT_DEBUG
- qWarning() << "Invalid transform ID!";
-#endif
- }
-
- break;
- }
-
- case TAG_METRIC_TABLE:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_METRIC_TABLE";
-#endif
- drawing->error_ = TagsParser::parseMetricTable( isfData, *drawing );
- break;
-
- case TAG_METRIC_BLOCK:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_METRIC_BLOCK";
-#endif
- drawing->error_ = TagsParser::parseMetricBlock( isfData, *drawing );
- break;
-
- case TAG_MIDX:
- {
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_MIDX";
-#endif
-
- quint64 value = decodeUInt( isfData );
-
- if( value < (uint)drawing->metrics_.count() )
- {
- drawing->currentMetrics_ = drawing->metrics_[ value ];
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Next strokes will use metrics #" << value;
-#endif
- }
- else
- {
-#ifdef ISFQT_DEBUG
- qWarning() << "Invalid metrics ID!";
-#endif
- }
-
- break;
- }
-
- case TAG_MANTISSA:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_MANTISSA";
-#endif
- drawing->error_ = TagsParser::parseUnsupported( isfData, "TAG_MANTISSA" );
- break;
-
- case TAG_PERSISTENT_FORMAT:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_PERSISTENT_FORMAT";
-#endif
- drawing->error_ = TagsParser::parsePersistentFormat( isfData, *drawing );
- break;
-
- case TAG_HIMETRIC_SIZE:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_HIMETRIC_SIZE";
-#endif
- drawing->error_ = TagsParser::parseHiMetricSize( isfData, *drawing );
- break;
-
- case TAG_STROKE_IDS:
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_STROKE_IDS";
-#endif
-
- drawing->error_ = TagsParser::parseUnsupported( isfData, "TAG_STROKE_IDS" );
- break;
-
- default:
-
- // If the tagIndex is known from the GUID table, show it differently
- if( drawing->maxGuid_ > 0
- && tagIndex >= DEFAULT_TAGS_NUMBER && tagIndex <= drawing->maxGuid_ )
- {
-#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Got tag (@" << place << "): TAG_CUSTOM:" << tagIndex;
-#endif
- TagsParser::parseCustomTag( isfData, *drawing, tagIndex );
- }
- else
- {
- TagsParser::parseUnsupported( isfData, "Unknown " + QString::number( tagIndex ) );
- }
- break;
-
- } // End of tagIndex switch
+ // Read the next tag from the stream
+ drawing->error_ = TagsParser::nextTag( streamData_, drawing );
if( drawing->error_ != ISF_ERROR_NONE )
{
@@ -489,8 +173,12 @@ Drawing &Stream::reader( const QByteArray &rawData, bool decodeFromBase64 )
qDebug();
#endif
+ delete streamData_->dataSource;
+
if( drawing->error_ != ISF_ERROR_NONE )
{
+ delete streamData_;
+ streamData_ = 0;
return *drawing;
}
@@ -498,15 +186,17 @@ Drawing &Stream::reader( const QByteArray &rawData, bool decodeFromBase64 )
// Adjust the bounding rectangle to include the strokes borders
QSize penSize( drawing->maxPenSize_.toSize() );
- drawing->boundingRect_.adjust( -penSize.width() - 1, -penSize.height() - 1,
- +penSize.width() + 1, +penSize.height() + 1 );
-
+ streamData_->boundingRect.adjust( -penSize.width() - 1, -penSize.height() - 1,
+ +penSize.width() + 1, +penSize.height() + 1 );
+ drawing->setBoundingRect( streamData_->boundingRect );
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Drawing bounding rectangle:" << drawing->boundingRect_;
+ qDebug() << "Drawing bounding rectangle:" << drawing->boundingRect();
qDebug() << "Maximum thickness:" << drawing->maxPenSize_;
#endif
+ delete streamData_;
+ streamData_ = 0;
return *drawing;
}
@@ -528,7 +218,7 @@ Drawing &Stream::reader( const QByteArray &rawData, bool decodeFromBase64 )
* need to be decoded first
* @return an Isf::Drawing, with null contents on error
*/
-Drawing &Stream::readerGif( const QByteArray &gifRawBytes, bool decodeFromBase64 )
+Drawing& Stream::readerGif( const QByteArray& gifRawBytes, bool decodeFromBase64 )
{
QByteArray isfData;
@@ -549,7 +239,7 @@ Drawing &Stream::readerGif( const QByteArray &gifRawBytes, bool decodeFromBase64
gifData.open( QIODevice::ReadOnly );
// Open the gif file
- GifFileType *gifImage = DGifOpen( (void*)&gifData, GifReadFromByteArray );
+ GifFileType* gifImage = DGifOpen( (void*)&gifData, GifReadFromByteArray );
if( gifImage != 0 )
{
DGifGetComment( gifImage, data?? );
@@ -622,6 +312,51 @@ Drawing &Stream::readerGif( const QByteArray &gifRawBytes, bool decodeFromBase64
+/**
+ * Convert a Fortified-PNG image into a drawing.
+ *
+ * If the PNG image or the ISF data within it are invalid, or if the PNG did not
+ * have any ISF stream within, then a null Drawing is returned.
+ *
+ * @param gifRawBytes Source byte array with a Fortified PNG image
+ * @param decodeFromBase64 True if the bytes are in the Base64 format and
+ * need to be decoded first
+ * @return an Isf::Drawing, with null contents on error
+ */
+Drawing& Stream::readerPng( const QByteArray& pngRawBytes, bool decodeFromBase64 )
+{
+ QByteArray isfData;
+
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Reading a PNG-Fortified file";
+#endif
+
+ QByteArray pngBytes( decodeFromBase64
+ ? QByteArray::fromBase64( pngRawBytes )
+ : pngRawBytes );
+
+ QImage imageData( QImage::fromData( pngBytes, "PNG" ) );
+ if( ! imageData.isNull() )
+ {
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Picture data is valid: checking for the ISF data tag...";
+#endif
+ isfData = imageData.text( "application/x-ms-ink" ).toAscii();
+
+ if( ! isfData.isEmpty() )
+ {
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "ISF data found! Decoding from Base64 and parsing it...";
+#endif
+ isfData = QByteArray::fromBase64( isfData );
+ }
+ }
+
+ return reader( isfData );
+}
+
+
+
/**
* Return whether the library was built with Fortified GIF support or not.
*
@@ -644,7 +379,7 @@ bool Stream::supportsGif()
* encoded with Base64 or not
* @return Byte array with an ISF data stream
*/
-QByteArray Stream::writer( const Drawing &drawing, bool encodeToBase64 )
+QByteArray Stream::writer( const Drawing& drawing, bool encodeToBase64 )
{
if( &drawing == 0 || drawing.isNull() || drawing.error() != ISF_ERROR_NONE )
{
@@ -654,41 +389,51 @@ QByteArray Stream::writer( const Drawing &drawing, bool encodeToBase64 )
return QByteArray();
}
- DataSource isfData;
+ streamData_ = new StreamData();
+ streamData_->dataSource = new DataSource();
+ DataSource* dataSource = streamData_->dataSource;
+
+ // Add the initial data
+ TagsWriter::prepare( streamData_, &drawing );
// Write the persistent format tag
- TagsWriter::addPersistentFormat( isfData, drawing );
+ TagsWriter::addPersistentFormat( streamData_, &drawing );
// Write the drawing size
- TagsWriter::addHiMetricSize( isfData, drawing );
+ TagsWriter::addHiMetricSize( streamData_, &drawing );
// Write the attributes
- TagsWriter::addAttributeTable( isfData, drawing );
+ TagsWriter::addAttributeTable( streamData_, &drawing );
// Write the metrics
- TagsWriter::addMetricsTable( isfData, drawing );
+ TagsWriter::addMetricsTable( streamData_, &drawing );
// Write the transforms
- TagsWriter::addTransformationTable( isfData, drawing );
+ TagsWriter::addTransformationTable( streamData_, &drawing );
// Write the strokes
- TagsWriter::addStrokes( isfData, drawing );
+ TagsWriter::addStrokes( streamData_, &drawing );
// Write the stream size (at the start of the stream)
- encodeUInt( isfData, isfData.size(), true/*prepend*/ );
+ encodeUInt( dataSource, dataSource->size(), true/*prepend*/ );
// Write the version number (at the start of the stream)
- encodeUInt( isfData, SUPPORTED_ISF_VERSION, true/*prepend*/ );
+ encodeUInt( dataSource, SUPPORTED_ISF_VERSION, true/*prepend*/ );
+ QByteArray data( dataSource->data() );
+
+ delete streamData_->dataSource;
+ delete streamData_;
+ streamData_ = 0;
// Convert to Base64 if needed
if( encodeToBase64 )
{
- return isfData.data().toBase64();
+ return data.toBase64();
}
else
{
- return isfData.data();
+ return data;
}
}
@@ -703,13 +448,16 @@ QByteArray Stream::writer( const Drawing &drawing, bool encodeToBase64 )
* withous GIF support. Use Stream::supportsGif() to verify whether
* GIF was compiled in or not.
*
+ * The Fortified-GIF format is nothing more than a GIF image with the original
+ * ISF drawing added as a GIF Comment field.
+ *
* @see supportsGif()
* @param drawing Source drawing
- * @param encodeToBase64 Whether the converted ISF stream should be
+ * @param encodeToBase64 Whether the converted GIF should be
* encoded with Base64 or not
- * @return Byte array with an ISF data stream
+ * @return Byte array with a GIF data stream (optionally encoded with Base64)
*/
-QByteArray Stream::writerGif( const Drawing &drawing, bool encodeToBase64 )
+QByteArray Stream::writerGif( const Drawing& drawing, bool encodeToBase64 )
{
QByteArray imageBytes;
@@ -730,8 +478,8 @@ QByteArray Stream::writerGif( const Drawing &drawing, bool encodeToBase64 )
// Initialise the gif variables
QBuffer gifData;
- GifFileType *gifImage = NULL;
- ColorMapObject *cmap = NULL;
+ GifFileType* gifImage = NULL;
+ ColorMapObject* cmap = NULL;
int height = isfImage.height();
int width = isfImage.width();
int numColors = 0;
@@ -908,3 +656,53 @@ writeError:
}
+
+/**
+ * Convert a drawing into a Fortified-PNG image.
+ *
+ * The resulting byte array will be empty if the drawing is not valid.
+ *
+ * The Fortified-PNG format is nothing more than a PNG image with the original
+ * ISF drawing added as a PNG text field.
+ *
+ * @param drawing Source drawing
+ * @param encodeToBase64 Whether the converted ISF stream should be
+ * encoded with Base64 or not
+ * @return Byte array with a PNG data stream (optionally encoded with Base64)
+ */
+QByteArray Stream::writerPng( const Drawing& drawing, bool encodeToBase64 )
+{
+ Drawing source( drawing );
+
+ // Get the ISF data stream
+ QByteArray isfData( writer( source ) );
+
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "PNG-Fortifying an ISF stream of size" << isfData.size();
+#endif
+
+ // Get the actual image
+ QImage isfImage( source.pixmap().toImage() );
+
+ // Add to it the Base64 version of the ISF drawing, as a comment and in Base64 form
+ // (that's because the PNG text fields are only meant to hold text)
+ isfImage.setText( "application/x-ms-ink", isfData.toBase64() );
+
+ // Save it as a PNG image
+ QBuffer imageBytes;
+ imageBytes.open( QIODevice::WriteOnly );
+ isfImage.save( &imageBytes, "PNG" );
+ imageBytes.close();
+
+ // Convert to Base64 if needed
+ if( encodeToBase64 )
+ {
+ return imageBytes.data().toBase64();
+ }
+ else
+ {
+ return imageBytes.data();
+ }
+}
+
+
diff --git a/contrib/isf-qt/src/isfqtdrawing.cpp b/contrib/isf-qt/src/isfqtdrawing.cpp
index ec62c72..b91ecc2 100644
--- a/contrib/isf-qt/src/isfqtdrawing.cpp
+++ b/contrib/isf-qt/src/isfqtdrawing.cpp
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -48,11 +46,7 @@ using namespace Compress;
* As soon as you add data, the instance becomes non-NULL.
*/
Drawing::Drawing()
-: currentMetrics_( 0 )
-, currentAttributeSet_( 0 )
-, currentStrokeInfo_( 0 )
-, currentTransform_( 0 )
-, error_( ISF_ERROR_NONE )
+: error_( ISF_ERROR_NONE )
, hasXData_( true )
, hasYData_( true )
, isNull_( true )
@@ -71,17 +65,9 @@ Drawing::Drawing()
*
* @param other The instance to duplicate.
*/
-Drawing::Drawing( const Drawing &other )
+Drawing::Drawing( const Drawing& other )
: boundingRect_( other.boundingRect_ )
, canvas_( other.canvas_ )
-, currentMetrics_( 0 )
-, currentAttributeSet_( 0 )
-, currentStrokeInfo_( 0 )
-, currentTransform_( 0 )
-, defaultMetrics_( other.defaultMetrics_ )
-, defaultAttributeSet_( other.defaultAttributeSet_ )
-, defaultStrokeInfo_( other.defaultStrokeInfo_ )
-, defaultTransform_( other.defaultTransform_ )
, error_( other.error_ )
, guids_( other.guids_ )
, hasXData_( other.hasXData_ )
@@ -89,114 +75,26 @@ Drawing::Drawing( const Drawing &other )
, isNull_( other.isNull_ )
, maxGuid_( other.maxGuid_ )
, maxPenSize_( other.maxPenSize_ )
-, size_( other.size_ )
{
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "** Copying ISF drawing:" << (void*)&other << "into new:" << this << "**";
#endif
- // First: create copies of all the local lists
-
- foreach( Metrics *metrics, other.metrics_ )
+ // Clone the stroke objects
+ foreach( Stroke* stroke, other.strokes_ )
{
- Metrics *newMetrics = new Metrics( *metrics );
- metrics_.append( newMetrics );
-
- if( metrics == other.currentMetrics_ )
- {
- currentMetrics_ = newMetrics;
- }
- }
-
- foreach( StrokeInfo *strokeInfo, other.strokeInfo_ )
- {
- StrokeInfo *newStrokeInfo = new StrokeInfo( *strokeInfo );
- strokeInfo_.append( newStrokeInfo );
-
- if( strokeInfo == other.currentStrokeInfo_ )
- {
- currentStrokeInfo_ = newStrokeInfo;
- }
- }
-
- foreach( QMatrix *transform, other.transforms_ )
- {
- QMatrix *newTransform = new QMatrix( *transform );
- transforms_.append( newTransform );
-
- if( transform == other.currentTransform_ )
- {
- currentTransform_ = newTransform;
- }
- }
-
- foreach( AttributeSet *attributeSet, other.attributeSets_ )
- {
- AttributeSet *newAttributeSet = new AttributeSet( *attributeSet );
- attributeSets_.append( newAttributeSet );
-
- if( attributeSet == other.currentAttributeSet_ )
- {
- currentAttributeSet_ = newAttributeSet;
- }
- }
-
- // Then: clone the strokes. Each stroke is linked to a certain
- // attribute set, metrics set, etc, so we need to associate the
- // original stroke's properties to the current one's
- foreach( Stroke *stroke, other.strokes_ )
- {
- Stroke *newStroke = new Stroke( *stroke );
+ Stroke* newStroke = new Stroke( *stroke );
strokes_.append( newStroke );
-
- // Get the indices of the various stroke properties; and
- // for the new stroke, use the same indices
-
- // It is probably safe to simply use the same index, since the
- // lists are copied in order.
- if( stroke->attributes && other.attributeSets_.count() > 0 )
- {
- int otherAttributeSet = other.attributeSets_.indexOf( stroke->attributes );
- newStroke->attributes = ( otherAttributeSet >= 0 )
- ? attributeSets_.at( otherAttributeSet )
- : 0;
- }
- if( stroke->info && other.strokeInfo_.count() > 0 )
- {
- int otherStrokeInfo = other.strokeInfo_.indexOf( stroke->info );
- newStroke->info = ( otherStrokeInfo >= 0 )
- ? strokeInfo_.at( otherStrokeInfo )
- : 0;
- }
- if( stroke->metrics && other.metrics_.count() > 0 )
- {
- int otherMetrics = other.metrics_.indexOf( stroke->metrics );
- newStroke->metrics = ( otherMetrics >= 0 )
- ? metrics_.at( otherMetrics )
- : 0;
- }
- if( stroke->transform && other.transforms_.count() > 0 )
- {
- int otherTransforms = other.transforms_.indexOf( stroke->transform );
- newStroke->transform = ( otherTransforms >= 0 )
- ? transforms_.at( otherTransforms )
- : 0;
- }
}
}
-
/**
* Destructor
*/
Drawing::~Drawing()
{
- qDeleteAll( metrics_ );
- qDeleteAll( strokeInfo_ );
qDeleteAll( strokes_ );
- qDeleteAll( transforms_ );
- qDeleteAll( attributeSets_ );
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "** Destroyed ISF drawing:" << this << "**";
@@ -205,104 +103,65 @@ Drawing::~Drawing()
-/**
- * Add new a attribute set to the drawing.
- *
- * @param newAttributeSet The attribute set to add
- * @return Index of the new attribute set or -1 on failure
- */
-qint32 Drawing::addAttributeSet( AttributeSet *newAttributeSet )
-{
- if( newAttributeSet == 0 )
- {
- return -1;
- }
-
- isNull_ = false;
-
- attributeSets_.append( newAttributeSet );
-
- // This value is used to adjust the drawing borders to include thick strokes
- if( newAttributeSet->penSize.width() > maxPenSize_.width() )
- {
- maxPenSize_.setWidth( newAttributeSet->penSize.width() );
- }
- if( newAttributeSet->penSize.height() > maxPenSize_.height() )
- {
- maxPenSize_.setHeight( newAttributeSet->penSize.height() );
- }
-
- return ( attributeSets_.count() - 1 );
-}
-
-
-
/**
* Add a new stroke to the drawing.
*
* @param newStroke The stroke to add
* @return Index of the new stroke or -1 on failure
*/
-qint32 Drawing::addStroke( Stroke *newStroke )
+qint32 Drawing::addStroke( PointList points )
+{
+ Stroke* newStroke = new Stroke();
+
+ newStroke->addPoints( points );
+ newStroke->finalize();
+
+ return addStroke( newStroke );
+}
+
+
+
+/**
+ * Add a new stroke to the drawing.
+ *
+ * @param newStroke The stroke to add
+ * @return Index of the new stroke or -1 on failure
+ */
+qint32 Drawing::addStroke( Stroke* newStroke )
{
if( newStroke == 0 )
{
return -1;
}
- quint64 numPoints = newStroke->points.count();
-
- // The polygon is used to determine the stroke's bounding rect
- QPolygon polygon( numPoints );
- for( quint64 index = 0; index < numPoints; ++index )
- {
- polygon.setPoint( index, newStroke->points.at( index ).position );
- }
-
- // assign the attributes to the stroke.
- newStroke->attributes = currentAttributeSet_;
-
- // add FitToCurve (Windows will use Bezier smoothing to make the ink look nice)
- newStroke->attributes->flags |= FitToCurve;
-
- float halfPenSize = newStroke->attributes->penSize.width() / 2;
-
- // set bounding rectangle, expanded it to accommodate pen size.
- newStroke->boundingRect = polygon.boundingRect().adjusted( -( halfPenSize ), - ( halfPenSize ),
- halfPenSize, halfPenSize );
-
isNull_ = false;
strokes_.append( newStroke );
+ maxPenSize_ = maxPenSize_.width() < newStroke->penSize().width() ? newStroke->penSize() : maxPenSize_;
- boundingRect_ = boundingRect_.united( newStroke->boundingRect );
-
- // this stroke needs to be repainted.
+ // This stroke needs to be painted
changedStrokes_.append( newStroke );
dirty_ = true;
+ updateBoundingRect();
+
return ( strokes_.count() - 1 );
}
+
/**
- * Add a new transformation to the drawing.
+ * Return the current bounding rectangle of the drawing.
*
- * @param newTransform The transform to add
- * @return Index of the new transform or -1 on failure
+ * The bounding rectangle (or bounding box) is a QRect large enough (and as
+ * small as) to hold all of the strokes in this Drawing instance.
+ *
+ * @return The current bounding box.
*/
-qint32 Drawing::addTransform( QMatrix *newTransform )
+QRect Drawing::boundingRect() const
{
- if( newTransform == 0 )
- {
- return -1;
- }
-
- isNull_ = false;
- transforms_.append( newTransform );
-
- return ( transforms_.count() - 1 );
+ return boundingRect_;
}
@@ -315,24 +174,10 @@ qint32 Drawing::addTransform( QMatrix *newTransform )
void Drawing::clear()
{
// Clean up the internal property lists
- qDeleteAll( metrics_ );
- qDeleteAll( strokeInfo_ );
qDeleteAll( strokes_ );
- qDeleteAll( transforms_ );
- qDeleteAll( attributeSets_ );
- metrics_ .clear();
- strokeInfo_ .clear();
- strokes_ .clear();
- transforms_ .clear();
- attributeSets_.clear();
+ strokes_ .clear();
changedStrokes_.clear();
- // Invalidate the current item pointers
- currentMetrics_ = 0;
- currentAttributeSet_ = 0;
- currentStrokeInfo_ = 0;
- currentTransform_ = 0;
-
// Nullify the other properties
boundingRect_ = QRect();
canvas_ = QRect();
@@ -343,48 +188,8 @@ void Drawing::clear()
isNull_ = true;
maxGuid_ = 0;
maxPenSize_ = QSizeF();
- size_ = QSize();
dirty_ = false;
cachePixmap_ = QPixmap();
-
- // set the default transform
- defaultTransform_.scale( 1.f, 1.f );
- defaultTransform_.translate( .0f, .0f );
-}
-
-
-
-/**
- * Remove an attribute set from the drawing.
- *
- * @param index Index of the attribute set to delete
- * @return bool
- */
-bool Drawing::deleteAttributeSet( quint32 index )
-{
- if( (qint64)index >= attributeSets_.count() )
- {
- return false;
- }
-
- delete attributeSets_.takeAt( index );
-
- // re-calculate max pen size
- foreach( AttributeSet *set, attributeSets_ )
- {
- // This value is used to adjust the drawing borders to include thick strokes
- if( set->penSize.width() > maxPenSize_.width() )
- {
- maxPenSize_.setWidth( set->penSize.width() );
- }
- if( set->penSize.height() > maxPenSize_.height() )
- {
- maxPenSize_.setHeight( set->penSize.height() );
- }
- }
-
- qDebug() << "Max Pen Size:"<= transforms_.count() )
- {
- return false;
- }
-
- delete transforms_.takeAt( index );
- return true;
-}
-
-
-
/**
* Return the last error that has occurred.
*
@@ -469,84 +255,45 @@ IsfError Drawing::error() const
-
/**
- * Retrieve an attribute set to manipulate.
+ * Return the index of a certain stroke.
*
- * @param index Index of the attribute set to get
- * @return AttributeSet or 0 if not found
+ * @param stroke Stroke to search
+ * @return Index or -1 if not found
*/
-AttributeSet *Drawing::attributeSet( quint32 index )
+qint32 Drawing::indexOfStroke( const Stroke* stroke ) const
{
- if( (qint64)index >= attributeSets_.count() )
- {
- return 0;
- }
-
- return attributeSets_.at( index );
+ return strokes_.indexOf( const_cast( stroke ) );
}
/**
- * Retrieve the attribute sets.
+ * Return whether this drawing is empty.
*
- * @return The list of existing attribute sets
+ * A Drawing is empty when there are no strokes in it.
+ *
+ * @return True if this is an empty Drawing, false otherwise.
*/
-const QList Drawing::attributeSets()
+bool Drawing::isEmpty() const
{
- return attributeSets_;
-}
-
-
-
-
-/**
- * Return the current bounding rectangle of the drawing.
- *
- * The bounding rectangle (or bounding box) is a QRect large enough (and as
- * small as) to hold all of the strokes in this Drawing instance.
- *
- * @return The current bounding box.
- */
-QRect Drawing::boundingRect()
-{
- // if the boundingRect_ is invalid, update it.
- // it becomes invalid after a stroke is deleted.
- if ( boundingRect_ == QRect() )
- {
- foreach( Stroke *stroke, strokes_ )
- {
- if ( stroke->transform != 0 )
- {
- boundingRect_ = boundingRect_.united( stroke->transform->mapRect( stroke->boundingRect ) );
- }
- else
- {
- boundingRect_ = boundingRect_.united( stroke->boundingRect );
- }
- }
-
- QSize penSize( maxPenSize_.toSize() );
- boundingRect_.adjust( -penSize.width() - 1, -penSize.height() - 1,
- +penSize.width() + 1, +penSize.height() + 1 );
-
- size_ = boundingRect_.size();
- }
-
- return boundingRect_;
+ return strokes_.empty();
}
/**
- * Return the size of this drawing.
+ * Return whether this drawing is null.
*
- * @return Size of the drawing, in pixels.
+ * A Drawing is null when there are no strokes, attributes or anything in it,
+ * for example when it has just been initialized, cleared, or when a copy from
+ * another drawing fails.
+ *
+ * @return True if this is an null Drawing, false otherwise.
*/
-QSize Drawing::size()
+bool Drawing::isNull() const
{
- return boundingRect().size();
+ return isNull_;
}
@@ -562,76 +309,77 @@ QSize Drawing::size()
* drawing.
*
* @param backgroundColor The color used as background in the returned image.
+ * Default is transparent.
* @return The rendered drawing, or a null one on error.
*/
QPixmap Drawing::pixmap( const QColor backgroundColor )
{
- if ( isNull() )
+ if( isNull() )
{
return QPixmap();
}
- if ( ! dirty_ && ! cachePixmap_.isNull() )
+ if( ! dirty_ && ! cachePixmap_.isNull() )
{
return cachePixmap_;
}
-
- QSize size_ = size();
- if( size_.width() > 2000 || size_.height() > 2000 )
+ QSize drawingSize( size() );
+
+ if( drawingSize.width() > 2000 || drawingSize.height() > 2000 )
{
qWarning() << "Cannot render a drawing so big!";
- qDebug() << "[Information - Size:" << size_ << "pixels]";
+ qDebug() << "[Information - Size:" << drawingSize << "pixels]";
return QPixmap();
}
// is the cache null, or are we repainting everything? if so, create a new pixmap.
- if ( cachePixmap_.isNull() || changedStrokes_.isEmpty() )
+ if( cachePixmap_.isNull() || changedStrokes_.isEmpty() )
{
- cachePixmap_ = QPixmap( size_ );
- cachePixmap_.fill( Qt::transparent );
- cacheRect_ = boundingRect();
+ cachePixmap_ = QPixmap( drawingSize );
+ cachePixmap_.fill( backgroundColor );
+ cacheRect_ = boundingRect_;
}
else
{
// otherwise, resize and repaint the cache.
- QRect newRect = boundingRect();
-
- // has the size of the drawing changed? if so, resize the cachePixmap_.
- if ( cacheRect_.size() != newRect.size() )
- {
- // qDebug() << "Cache pixmap needs resizing to" << size_;
- // qDebug() << "Cache rect:" << cacheRect_;
- // qDebug() << "New rect:" << newRect;
+ QRect newRect = boundingRect_;
- QPixmap pixmap( size_ );
- pixmap.fill( Qt::transparent );
+ // has the size of the drawing changed? if so, resize the cachePixmap_.
+ if( cacheRect_.size() != newRect.size() )
+ {
+// qDebug() << "Cache pixmap needs resizing to" << drawingSize;
+// qDebug() << "Cache rect:" << cacheRect_;
+// qDebug() << "New rect:" << newRect;
+
+ QPixmap pixmap( drawingSize );
+ pixmap.fill( backgroundColor );
QPainter painter( &pixmap );
int xOffset = ( newRect.x() - cacheRect_.x() ) * -1;
int yOffset = ( newRect.y() - cacheRect_.y() ) * -1;
- // qDebug() << "x-offset:"< strokes = ( changedStrokes_.isEmpty() ? strokes_ : changedStrokes_ );
#ifdef ISFQT_DEBUG
- qDebug() << "Rendering a drawing of size" << size_;
+ qDebug() << "Rendering a drawing of size" << drawingSize;
#endif
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "The drawing contains" << strokes_.count() << "strokes; rendering" << strokes.count() << "strokes.";
+ qDebug() << "Rendering" << strokes.count() << "out of" << strokes_.count() << "strokes in the drawing.";
#endif
// if there are no strokes there's no point going
@@ -642,8 +390,8 @@ QPixmap Drawing::pixmap( const QColor backgroundColor )
}
QPainter painter( &cachePixmap_ );
-
- painter.setWindow( boundingRect() );
+
+ painter.setWindow( boundingRect_ );
painter.setWorldMatrixEnabled( true );
painter.setRenderHints( QPainter::Antialiasing
| QPainter::SmoothPixmapTransform
@@ -655,93 +403,73 @@ QPixmap Drawing::pixmap( const QColor backgroundColor )
pen.setCapStyle ( Qt::RoundCap );
pen.setJoinStyle( Qt::RoundJoin );
- // Keep record of the currently used properties, to avoid re-setting them for each stroke
- currentMetrics_ = 0;
- currentAttributeSet_ = 0;
- currentStrokeInfo_ = 0;
- currentTransform_ = 0;
+ // Keep record of the last used properties, to avoid re-setting them for each stroke
+ AttributeSet currentAttributes;
+ Metrics* currentMetrics = 0;
+ QMatrix* currentTransform = 0;
int index = 0;
- foreach( const Stroke *stroke, strokes )
+ foreach( Stroke* stroke, strokes )
{
- if( currentMetrics_ != stroke->metrics )
+ if( currentAttributes.color != stroke->color()
+ || currentAttributes.flags != stroke->flags()
+ || currentAttributes.penSize != stroke->penSize() )
{
- currentMetrics_ = stroke->metrics;
+ currentAttributes.color = stroke->color();
+ currentAttributes.flags = stroke->flags();
+ currentAttributes.penSize = stroke->penSize();
+
+ pen.setColor( stroke->color() );
+ pen.setWidthF( stroke->penSize().width() );
+ painter.setPen( pen );
+ }
+ if( stroke->metrics() && currentMetrics != stroke->metrics() )
+ {
+ currentMetrics = stroke->metrics();
// TODO need to convert all units somehow?
// painter.setSomething( currentMetrics );
}
- if( currentAttributeSet_ != stroke->attributes && stroke->attributes != 0)
+ if( stroke->transform() && currentTransform != stroke->transform() )
{
- currentAttributeSet_ = stroke->attributes;
-
- pen.setColor( currentAttributeSet_->color );
- pen.setWidthF( currentAttributeSet_->penSize.width() );
- painter.setPen( pen );
- }
- if( currentStrokeInfo_ != stroke->info )
- {
- currentStrokeInfo_ = stroke->info;
- }
- if( currentTransform_ != stroke->transform && stroke->transform != 0 )
- {
- currentTransform_ = stroke->transform;
- painter.setWorldTransform( QTransform( *currentTransform_ ), false );
+ currentTransform = stroke->transform();
+ painter.setWorldTransform( QTransform( *currentTransform ), false );
// the problem with setting the world transform is that it will scale the pen size too.
// we don't want that. so we have to artificially beef up the pen size.
QPen pen = painter.pen();
- pen.setWidthF( currentAttributeSet_->penSize.width() / currentTransform_->m22() );
+ pen.setWidthF( stroke->penSize().width() / currentTransform->m22() );
+
+/*
+ // FIXME Ignoring pressure data - need to find out how pressure must be applied
+ pen.setWidth( pen.widthF() + points??.pressureLevel );
+*/
+
painter.setPen( pen );
+ painter.setBrush( Qt::transparent );
}
+ const PointList& points = stroke->points();
+
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "Rendering stroke" << index << "containing" << stroke->points.count() << "points";
- qDebug() << "- Stroke color:" << currentAttributeSet_->color.name() << "Pen size:" << pen.widthF();
+ qDebug() << "Rendering stroke" << index << "containing" << stroke->points().count() << "points";
+ qDebug() << "- Stroke color:" << stroke->color().name() << "Pen size:" << pen.widthF();
#endif
- if( stroke->points.count() > 1 )
+ ++index;
+
+ if( points.count() == 0 )
{
- Point lastPoint;
- foreach( const Point &point, stroke->points )
- {
-// qDebug() << "Point:" << point.position;
+ continue;
+ }
- if( lastPoint.position.isNull() )
- {
- lastPoint = point;
- continue;
- }
-
- if( currentStrokeInfo_->hasPressureData )
- {
- // FIXME Ignoring pressure data - need to find out how pressure must be applied
-// pen.setWidth( pen.widthF() + point.pressureLevel );
-// painter.setPen( pen );
- }
-
- // How nice of QPainter! Lines drawn from and to the same point
- // won't be drawn at all
- if( point.position == lastPoint.position )
- {
- painter.drawPoint( point.position );
- }
- else
- {
- painter.drawLine( lastPoint.position, point.position );
- }
-
- lastPoint = point;
- }
+ // TODO: pressure data.
+ if( points.count() > 1 )
+ {
+ painter.drawPath( stroke->painterPath() );
}
else
{
- Point point = stroke->points.first();
- if( currentStrokeInfo_->hasPressureData )
- {
- // FIXME Ignoring pressure data - need to find out how pressure must be applied
-// pen.setWidth( pen.widthF() + point.pressureLevel );
-// painter.setPen( pen );
- }
+ Point point = stroke->points().first();
// qDebug() << "Point:" << point.position;
painter.drawPoint( point.position );
@@ -757,14 +485,12 @@ QPixmap Drawing::pixmap( const QColor backgroundColor )
painter.setPen( pen );
#endif
*/
-
- ++index;
}
painter.end();
changedStrokes_.clear();
-
+
#ifdef ISFQT_DEBUG
qDebug() << "Rendering complete.";
#endif
@@ -776,13 +502,39 @@ QPixmap Drawing::pixmap( const QColor backgroundColor )
+/**
+ * Change the bounding rectangle of the drawing.
+ *
+ * Adding, removing or changing the strokes will change it back to the real rectangle.
+ *
+ * @param newRect the new bounding rectangle
+ */
+void Drawing::setBoundingRect( QRect newRect )
+{
+ boundingRect_ = newRect;
+}
+
+
+
+/**
+ * Return the size of this drawing.
+ *
+ * @return Size of the drawing, in pixels.
+ */
+QSize Drawing::size() const
+{
+ return boundingRect_.size();
+}
+
+
+
/**
* Retrieve a stroke to manipulate.
*
* @param index Index of the stroke to get
* @return Stroke or 0 if not found
*/
-Stroke *Drawing::stroke( quint32 index )
+Stroke* Drawing::stroke( quint32 index )
{
if( (qint64)index >= strokes_.count() )
{
@@ -806,7 +558,7 @@ Stroke *Drawing::stroke( quint32 index )
* @param point Point to check
* @return A Stroke instance or NULL if no Stroke passes through that point.
*/
-Stroke *Drawing::strokeAtPoint( const QPoint &point )
+Stroke* Drawing::strokeAtPoint( const QPoint& point )
{
/*
Here's how this algorithm works:
@@ -830,23 +582,23 @@ Stroke *Drawing::strokeAtPoint( const QPoint &point )
thus height = ( 2 * area ) / base.
*/
- QListIterator i( strokes_ );
+ QListIterator i( strokes_ );
i.toBack();
while( i.hasPrevious() )
{
- Stroke *s = i.previous();;
+ Stroke* s = i.previous();
// skip strokes where we're not near.
- if ( ! s->boundingRect.contains( point ) )
+ if ( ! s->boundingRect().contains( point ) )
{
continue;
}
// what's the pen size of this stroke? That way we have a "fudge factor"
- AttributeSet *set = s->attributes;
- float penSize = set->penSize.width();
+ float penSize = s->penSize().width();
float penHalfSize = penSize / 2;
+ float penHalfSizeFixed = penHalfSize * 1.25;
// only want points that fall near the cursor. prevents searching unnecessary points.
QRect searchRect;
@@ -858,7 +610,9 @@ Stroke *Drawing::strokeAtPoint( const QPoint &point )
if ( penHalfSize > 5 )
{
// 25% extra room to move.
- searchRect = QRect( point.x() - penHalfSize * 1.25, point.y() - penHalfSize * 1.25, penHalfSize * 1.25, penHalfSize * 1.25 );
+ searchRect = QRect( point.x() - penHalfSizeFixed,
+ point.y() - penHalfSizeFixed,
+ penHalfSizeFixed, penHalfSizeFixed );
}
else
{
@@ -867,23 +621,25 @@ Stroke *Drawing::strokeAtPoint( const QPoint &point )
// special case: a single point (sometimes it'll appear as a single point but
// be made up of two).
- if ( s->points.size() == 1 || s->points.size() == 2 )
+ const PointList& points( s->points() );
+ if( points.size() == 1 || points.size() == 2 )
{
- QLineF dist = QLineF( QPointF( s->points.at(0).position ), QPointF( point ) );
- if ( dist.length() <= penHalfSize * 1.25 )
+ QLineF dist = QLineF( QPointF( points.at(0).position ), QPointF( point ) );
+ if( dist.length() <= penHalfSizeFixed )
{
return s;
}
+
continue;
}
// multiple points.
- for( int j = 0; j < s->points.size() - 1; j++)
+ for( int j = 0; j < points.size() - 1; j++)
{
- QPoint p1 = s->points.at(j).position;
- QPoint p2 = s->points.at(j+1).position;
+ QPoint p1 = points.at(j).position;
+ QPoint p2 = points.at(j+1).position;
- if ( ! searchRect.contains( p1 ) && ! searchRect.contains( p2 ) )
+ if( ! searchRect.contains( p1 ) && ! searchRect.contains( p2 ) )
{
continue;
}
@@ -901,7 +657,7 @@ Stroke *Drawing::strokeAtPoint( const QPoint &point )
// so, use Heron's Formula to get the area, plus A=0.5*base*height, re-arrange to get height.
//
// easy!
- float sp = 0.5*( lineA.length() + base.length() + lineC.length() );
+ float sp = 0.5 * ( lineA.length() + base.length() + lineC.length() );
float a = lineA.length();
float b = base.length();
float c = lineC.length();
@@ -909,7 +665,7 @@ Stroke *Drawing::strokeAtPoint( const QPoint &point )
float height = ( 2 * area ) / b;
- if ( height <= penHalfSize * 1.25 )
+ if ( height <= penHalfSizeFixed )
{
// got one
return s;
@@ -934,91 +690,40 @@ const QList Drawing::strokes()
+
/**
- * Retrieve a transformation to manipulate.
- *
- * @param index Index of the transform to get
- * @return QMatrix or 0 if not found
+ * Update the bounding rectangle of the drawing.
*/
-QMatrix *Drawing::transform( quint32 index )
+void Drawing::updateBoundingRect()
{
- if( (qint64)index >= transforms_.count() )
+#ifdef ISFQT_DEBUG_VERBOSE
+ QRect oldRect( boundingRect_ );
+#endif
+
+ boundingRect_ = QRect();
+ foreach( Stroke* stroke, strokes_ )
{
- return 0;
+ const QRect rect( stroke->boundingRect() );
+ QMatrix* transform = stroke->transform();
+ if( transform != 0 )
+ {
+ boundingRect_ = boundingRect_.united( transform->mapRect( rect ) );
+ }
+ else
+ {
+ boundingRect_ = boundingRect_.united( rect );
+ }
+
+ maxPenSize_ = maxPenSize_.width() < stroke->penSize().width() ? stroke->penSize() : maxPenSize_;
}
- return transforms_.at( index );
-}
-
-
-
-/**
- * Retrieve the transformations.
- *
- * @return The list of existing transformations
- */
-const QList Drawing::transforms()
-{
- return transforms_;
-}
-
-
-
-/**
- * Return whether this drawing is empty.
- *
- * @return True if this is an empty (null) Drawing, false otherwise.
- */
-bool Drawing::isNull() const
-{
- return isNull_;
-}
-
-
-
-
-/**
- * Change the current attribute set.
- *
- * This will change the attribute set which will be applied
- * to the next strokes.
- *
- * @param attributeSet the new attribute set
- * @return bool
- */
-bool Drawing::setCurrentAttributeSet( AttributeSet *attributeSet )
-{
- if( ! attributeSets_.contains( attributeSet ) )
- {
- return false;
- }
-
- currentAttributeSet_ = attributeSet;
-
- return true;
-}
-
-
-
-/**
- * Change the current transformation.
- *
- * This will change the transformation which will be applied
- * to the next strokes.
- *
- * @param transform the new transformation
- * @return bool
- */
-bool Drawing::setCurrentTransform( QMatrix *transform )
-{
- if( ! transforms_.contains( transform ) )
- {
- return false;
- }
-
- currentTransform_ = transform;
-
- return true;
+ const QSize penSize( maxPenSize_.toSize() );
+ boundingRect_.adjust( -penSize.width() - 1, -penSize.height() - 1,
+ +penSize.width() + 1, +penSize.height() + 1 );
+
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Bounding rectangle updated: from" << oldRect << "to" << boundingRect_;
+#endif
}
diff --git a/contrib/isf-qt/src/isfqtstroke.cpp b/contrib/isf-qt/src/isfqtstroke.cpp
new file mode 100644
index 0000000..45303cf
--- /dev/null
+++ b/contrib/isf-qt/src/isfqtstroke.cpp
@@ -0,0 +1,517 @@
+/***************************************************************************
+ * Copyright (C) 2010 by Valerio Pilo *
+ * valerio@kmess.org *
+ * *
+ * Copyright (C) 2010 by Adam Goossens *
+ * adam@kmess.org *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU Lesser General Public License as *
+ * published by the Free Software Foundation; either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * 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. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+
+#include "isfqtstroke.h"
+
+#include "isfqt-internal.h"
+
+#include
+
+
+using namespace Isf;
+
+
+
+/**
+ * Constructor
+ */
+Stroke::Stroke()
+: finalized_( true )
+, metrics_( 0 )
+, transform_( 0 )
+{
+}
+
+
+
+/**
+ * Copy constructor
+ *
+ * @param other The object to clone
+ */
+Stroke::Stroke( const Stroke& other )
+{
+ bezierControlPoints1_ = other.bezierControlPoints1_;
+ bezierControlPoints2_ = other.bezierControlPoints2_;
+ bezierKnots_ = other.bezierKnots_;
+
+ boundingRect_ = other.boundingRect_;
+ color_ = other.color_;
+ finalized_ = other.finalized_;
+ flags_ = other.flags_;
+ hasPressureData_ = other.hasPressureData_;
+ metrics_ = other.metrics_;
+ penSize_ = other.penSize_;
+ points_ = other.points_;
+ transform_ = other.transform_;
+}
+
+
+
+/**
+ * Destructor
+ */
+Stroke::~Stroke()
+{
+}
+
+
+
+void Stroke::addPoint( Point point )
+{
+ // Avoid splitting up the logic
+ addPoints( PointList() << point );
+}
+
+
+
+void Stroke::addPoints( PointList points )
+{
+ points_.append( points );
+
+ // Hunt for pressure info
+ if( ! hasPressureData_ )
+ {
+ foreach( Point point, points )
+ {
+ if( point.pressureLevel != 0 )
+ {
+ hasPressureData_ = true;
+ break;
+ }
+ }
+ }
+
+ finalized_ = false;
+}
+
+
+
+/**
+ * Given a series of known (knot) points, knots, calculates the control points (c1, c2) to approximate a series of
+ * bezier curves passing smoothly through the knot points.
+ */
+void Stroke::bezierCalculateControlPoints()
+{
+// bezierKnots_.clear();
+// bezierControlPoints1_.clear();
+// bezierControlPoints2_.clear();
+
+ int numPoints = points_.size();
+
+ // For a better curve, don't pass through all of points:
+ // skip about 70% of them
+ int toSkip = 0.70 * numPoints;
+ int step = numPoints / ( numPoints - toSkip );
+ step = ( step < 1 ) ? 1 : step; // Sanity check
+
+ for( int i = 0; i < numPoints; i += step )
+ {
+ bezierKnots_.append( points_.at(i).position );
+ }
+
+ // always pass through the last point.
+ bezierKnots_.append( points_.last().position );
+
+ /////////////////////////////////////////////////////////////////////////////
+
+ if( bezierKnots_.size() == 0 )
+ {
+ return;
+ }
+
+ int n = bezierKnots_.size() - 1;
+ if( n < 1 )
+ {
+#ifdef ISFQT_DEBUG
+ qWarning() << "Require at least two knot points to generate Bezier control points; ignoring.";
+#endif
+ return;
+ }
+
+ // special case: Bezier curve should be a straight line.
+ if( n == 1 )
+ {
+ QPointF cp1, cp2;
+ QPointF k1 = bezierKnots_.at(0); // knot point 1
+ QPointF k2 = bezierKnots_.at(1); // knot point 2
+
+ cp1.setX( ( 2 * k1.x() + k2.x() ) / 3.0 );
+ cp1.setY( ( 2 * k1.y() + k2.y() ) / 3.0 );
+
+ cp2.setX( ( 2 * cp1.x() - k1.x() ) );
+ cp2.setY( ( 2 * cp1.y() - k1.y() ) );
+
+ bezierControlPoints1_.append( cp1 );
+ bezierControlPoints2_.append( cp2 );
+
+ return; // done!
+ }
+
+ // right hand side vector.
+ double rhs[n];
+
+ // set RHS x values
+ for( int i = 1; i < n-1; i++ )
+ {
+ rhs[i] = 4 * bezierKnots_[i].x() + 2 * bezierKnots_[i+1].x();
+ }
+
+ rhs[0] = bezierKnots_[0].x() + 2 * bezierKnots_[1].x();
+ rhs[n-1] = ( 8 * bezierKnots_[n-1].x() + bezierKnots_[n].x() ) / 2.0;
+
+ // get the first ctl points x values.
+ double x[n];
+ bezierGetFirstControlPoints( rhs, x, n );
+
+
+ // now set RHS y-values.
+ for(int i = 1; i < n-1; i++ )
+ {
+ rhs[i] = 4 * bezierKnots_[i].y() + 2 * bezierKnots_[i+1].y();
+ }
+
+ rhs[0] = bezierKnots_[0].y() + 2 * bezierKnots_[1].y();
+ rhs[n-1] = ( 8 * bezierKnots_[n-1].y() + bezierKnots_[n].y() ) / 2.0;
+
+ double y[n];
+ bezierGetFirstControlPoints( rhs, y, n );
+
+ // now fill the output QList.
+ for( int i = 0; i < n; i++ )
+ {
+ QPointF cp1( x[i], y[i] );
+ QPointF cp2;
+
+ // second ctl point
+ if ( i < n-1 )
+ {
+ cp2 = QPointF( 2 * bezierKnots_[i+1].x() - x[i+1],
+ 2 * bezierKnots_[i+1].y() - y[i+1] );
+ }
+ else
+ {
+ cp2 = QPointF( ( bezierKnots_[n].x() + x[n-1] ) / 2,
+ ( bezierKnots_[n].y() + y[n-1] ) / 2 );
+ }
+
+ bezierControlPoints1_.append( cp1 );
+ bezierControlPoints2_.append( cp2 );
+ }
+}
+
+
+
+// Solves the system for the first control points.
+void Stroke::bezierGetFirstControlPoints( double rhs[], double* xOut, int n )
+{
+ double* x = xOut; // solution vector.
+ double tmp[n]; // temp workspace.
+
+ double b = 2.0;
+ x[0] = rhs[0] / b;
+ for( int i = 1; i < n; i++ ) // decomposition and forward substitution
+ {
+ tmp[i] = 1 / b;
+ b = ( i < n - 1 ? 4.0 : 3.5 ) - tmp[i];
+ x[i] = (rhs[i] - x[i-1]) / b;
+ }
+
+ for( int i = 1; i < n; i++ )
+ {
+ x[n-i-1] -= tmp[n-i] * x[n-i]; // back substitution.
+ }
+
+ // results are in xOut.
+}
+
+
+
+/**
+ * Returns the rectangle which contains this stroke.
+ *
+ * @return Rectangle
+ */
+QRect Stroke::boundingRect() const
+{
+ return boundingRect_;
+}
+
+
+
+QColor Stroke::color() const
+{
+ return color_;
+}
+
+
+
+/**
+ * Apply the changes to the stroke.
+ *
+ * Calculating the stroke bounds is complex, so a lazy approach was
+ * chosen instead of recalculating them for every added point.
+ */
+void Stroke::finalize()
+{
+ if( finalized_ )
+ {
+ return;
+ }
+
+ // A polygon is used to determine the stroke's bounding rect
+ quint64 numPoints = points_.count();
+ QPolygon polygon( numPoints );
+ for( quint64 index = 0; index < numPoints; ++index )
+ {
+ polygon.setPoint( index, points_.at( index ).position );
+ }
+
+ // Transform the bounding rect with the current transformation
+ if( transform_ )
+ {
+ polygon = transform_->map( polygon );
+ }
+
+ // Set the bounding rectangle, expanded it to also accommodate pen size
+ float halfPenSize = penSize_.width() / 2;
+ boundingRect_ = polygon.boundingRect().adjusted( -( halfPenSize ), -( halfPenSize ),
+ halfPenSize, halfPenSize );
+
+ // Finally, pre-calculate the stroke paths
+ painterPath();
+
+ finalized_ = true;
+}
+
+
+
+/**
+ * Get the stroke drawing flags.
+ *
+ * @return Stroke flags
+ */
+StrokeFlags Stroke::flags() const
+{
+ return flags_;
+}
+
+
+
+/**
+ * Get whether the stroke contains pressure information.
+ *
+ * @return bool
+ */
+bool Stroke::hasPressureData() const
+{
+ return hasPressureData_;
+}
+
+
+
+/**
+ * Get the stroke metrics.
+ *
+ * @return Metrics*
+ */
+Metrics* Stroke::metrics()
+{
+ return metrics_;
+}
+
+
+
+/**
+ * Get a painter path to draw this stroke.
+ *
+ * The path is adjusted according to the drawing flags.
+ * Given a list of knot points, generates a QPainterPath that describes the stroke.
+ *
+ * If the FitToCurve flag is present, the stroke path is generated using bezier curves
+ * to approximate the stroke, giving a much smoother appearance.
+ *
+ * @see calculateControlPoints()
+ * @return QPainterPath
+ */
+QPainterPath Stroke::painterPath()
+{
+ int numPoints = points_.size();
+
+ if( numPoints == 0 )
+ {
+ return QPainterPath();
+ }
+
+ QPointF startPos( points_.first().position );
+
+ QPainterPath path( startPos );
+
+ if( ( flags_ & FitToCurve ) == false )
+ {
+ foreach( Point point, points_ )
+ {
+ path.lineTo( point.position );
+ }
+ return path;
+ }
+
+ // don't calculate control points if they've
+ // already been calculated.
+ if( bezierKnots_.isEmpty() )
+ {
+ bezierCalculateControlPoints();
+ }
+
+ for( int i = 0; i < bezierControlPoints1_.size(); i++ )
+ {
+ // draw the bezier curve!
+ path.cubicTo( bezierControlPoints1_[ i ], bezierControlPoints2_[ i ], bezierKnots_[ i + 1 ] );
+ }
+
+ return path;
+}
+
+
+
+/**
+ * Get the current pen size
+ *
+ * @return QSizeF of the stroke pen
+ */
+QSizeF Stroke::penSize() const
+{
+ return penSize_;
+}
+
+
+
+/**
+ * Get the list of points
+ *
+ * @return List of stroke points
+ */
+PointList& Stroke::points()
+{
+ return points_;
+}
+
+
+
+/**
+ * Change pen color
+ *
+ * @param newColor new pen color
+ */
+void Stroke::setColor( QColor newColor )
+{
+ color_ = newColor;
+}
+
+
+
+
+/**
+ * Change a flag
+ *
+ * @param flag The flag to alter
+ * @param set If true, the flag will be set. If false, it will be unset.
+ */
+void Stroke::setFlag( StrokeFlag flag, bool set )
+{
+ if( set )
+ {
+ flags_ |= flag;
+ }
+ else
+ {
+ flags_ ^= flag;
+ }
+}
+
+
+
+/**
+ * Change stroke flags all at once.
+ *
+ * @param newFlags Flags bitfield
+ */
+void Stroke::setFlags( StrokeFlags newFlags )
+{
+ flags_ = newFlags;
+}
+
+
+
+/**
+ * Get the current pen size
+ *
+ * @param newMetrics The new metrics object
+ */
+void Stroke::setMetrics( Metrics* newMetrics )
+{
+ metrics_ = newMetrics;
+}
+
+
+
+/**
+ * Get the current pen size
+ *
+ * @return QSizeF of the stroke pen
+ */
+void Stroke::setPenSize( QSizeF newSize )
+{
+ penSize_ = newSize;
+
+ // The bounding box changes with pen size
+ finalized_ = false;
+}
+
+
+
+/**
+ * Apply a transformation to the stroke.
+ *
+ * The stroke doesn't take ownership of the transformation.
+ *
+ * @param newTransform Transformation to apply
+ */
+void Stroke::setTransform( QMatrix* newTransform )
+{
+ transform_ = newTransform;
+}
+
+
+
+/**
+ * Get the stroke transformation, if any
+ *
+ * @return QMatrix, possibly null
+ */
+QMatrix* Stroke::transform()
+{
+ return transform_;
+}
+
+
diff --git a/contrib/isf-qt/src/tagsparser.cpp b/contrib/isf-qt/src/tagsparser.cpp
index 3934d00..290200a 100644
--- a/contrib/isf-qt/src/tagsparser.cpp
+++ b/contrib/isf-qt/src/tagsparser.cpp
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -25,12 +23,13 @@
#include "tagsparser.h"
-#include "isfqt-internal.h"
-
#include "data/compression.h"
#include "data/datasource.h"
#include "data/multibytecoding.h"
+#include "isfqt-internal.h"
+
+#include
#include
#include
@@ -38,20 +37,355 @@
using namespace Isf;
+using namespace Isf::Compress;
/**
* Read away an unsupported tag.
*
- * @param source Data Source where to read bytes from
+ * This is the key point of the state machine. This will look for ISF
+ * tags and farm off to the appropriate method.
+ *
+ * @param streamData StreamData object with the stream data
* @param tagName Name of the tag if known, index number if not
* @return IsfError
*/
-IsfError TagsParser::parseUnsupported( DataSource &source, const QString &tagName )
+IsfError TagsParser::nextTag( StreamData* streamData, Drawing* drawing )
+{
+ IsfError error = ISF_ERROR_NONE;
+ QString place( "0x" + QString::number( streamData->dataSource->pos(), 16 ).toUpper() );
+
+ quint64 tagIndex = decodeUInt( streamData->dataSource );
+ switch( tagIndex )
+ {
+ case TAG_INK_SPACE_RECT:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_INK_SPACE_RECT";
+#endif
+ error = parseInkSpaceRectangle( streamData, drawing );
+ break;
+
+ case TAG_GUID_TABLE:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_GUID_TABLE";
+#endif
+ error = parseGuidTable( streamData, drawing );
+ break;
+
+ case TAG_DRAW_ATTRS_TABLE:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_DRAW_ATTRS_TABLE";
+#endif
+ error = parseAttributeTable( streamData, drawing );
+ break;
+
+ case TAG_DRAW_ATTRS_BLOCK:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_DRAW_ATTRS_BLOCK";
+#endif
+ error = parseAttributeBlock( streamData, drawing );
+ break;
+
+ case TAG_STROKE_DESC_TABLE:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_STROKE_DESC_TABLE";
+#endif
+ error = parseStrokeDescTable( streamData, drawing );
+ break;
+
+ case TAG_STROKE_DESC_BLOCK:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_STROKE_DESC_BLOCK";
+#endif
+ error = parseStrokeDescBlock( streamData, drawing );
+ break;
+
+ case TAG_BUTTONS:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_BUTTONS";
+#endif
+ error = parseUnsupported( streamData, "TAG_BUTTONS" );
+ break;
+
+ case TAG_NO_X:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_NO_X";
+#endif
+ drawing->error_ = ISF_ERROR_NONE;
+
+ drawing->hasXData_ = false;
+ break;
+
+ case TAG_NO_Y:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_NO_Y";
+#endif
+ drawing->hasYData_ = false;
+ break;
+
+ case TAG_DIDX:
+ {
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_DIDX";
+#endif
+
+ quint64 value = decodeUInt( streamData->dataSource );
+
+ if( value < (uint)streamData->attributeSets.count() )
+ {
+ streamData->currentAttributeSetIndex = value;
+
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "- Next strokes will use drawing attributes #" << value;
+#endif
+ }
+ else
+ {
+#ifdef ISFQT_DEBUG
+ qWarning() << "Invalid drawing attribute ID!";
+#endif
+ }
+ break;
+ }
+
+ case TAG_STROKE:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_STROKE";
+#endif
+ error = parseStroke( streamData, drawing );
+ break;
+
+ case TAG_STROKE_PROPERTY_LIST:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_STROKE_PROPERTY_LIST";
+#endif
+ error = parseUnsupported( streamData, "TAG_STROKE_PROPERTY_LIST" );
+ break;
+
+ case TAG_POINT_PROPERTY:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_POINT_PROPERTY";
+#endif
+ error = parseUnsupported( streamData, "TAG_POINT_PROPERTY" );
+ break;
+
+ case TAG_SIDX:
+ {
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_SIDX";
+#endif
+
+ quint64 value = decodeUInt( streamData->dataSource );
+
+ if( value < (uint)streamData->strokeInfos.count() )
+ {
+ streamData->currentStrokeInfoIndex = value;
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "- Next strokes will use stroke info #" << value;
+#endif
+ }
+ else
+ {
+#ifdef ISFQT_DEBUG
+ qWarning() << "Invalid stroke ID!";
+#endif
+ }
+ break;
+ }
+
+ case TAG_COMPRESSION_HEADER:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_COMPRESSION_HEADER";
+#endif
+ error = parseUnsupported( streamData, "TAG_COMPRESSION_HEADER" );
+ break;
+
+ case TAG_TRANSFORM_TABLE:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_TABLE";
+#endif
+ error = parseTransformationTable( streamData, drawing );
+ break;
+
+ case TAG_TRANSFORM:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM";
+#endif
+ error = parseTransformation( streamData, drawing, tagIndex );
+ break;
+
+ case TAG_TRANSFORM_ISOTROPIC_SCALE:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_ISOTROPIC_SCALE";
+#endif
+ error = parseTransformation( streamData, drawing, tagIndex );
+ break;
+
+ case TAG_TRANSFORM_ANISOTROPIC_SCALE:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_ANISOTROPIC_SCALE";
+#endif
+ error = parseTransformation( streamData, drawing, tagIndex );
+ break;
+
+ case TAG_TRANSFORM_ROTATE:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_ROTATE";
+#endif
+ error = parseTransformation( streamData, drawing, tagIndex );
+ break;
+
+ case TAG_TRANSFORM_TRANSLATE:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_TRANSLATE";
+#endif
+ error = parseTransformation( streamData, drawing, tagIndex );
+ break;
+
+ case TAG_TRANSFORM_SCALE_AND_TRANSLATE:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_SCALE_AND_TRANSLATE";
+#endif
+ error = parseTransformation( streamData, drawing, tagIndex );
+ break;
+
+ case TAG_TRANSFORM_QUAD:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_TRANSFORM_QUAD";
+#endif
+ error = parseTransformation( streamData, drawing, tagIndex );
+ break;
+
+ case TAG_TIDX:
+ {
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_TIDX";
+#endif
+
+ quint64 value = decodeUInt( streamData->dataSource );
+
+ if( value < (uint)streamData->transforms.count() )
+ {
+ streamData->currentTransformsIndex = value;
+
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "- Next strokes will use transform #" << value;
+#endif
+ }
+ else
+ {
+#ifdef ISFQT_DEBUG
+ qWarning() << "Invalid transform ID!";
+#endif
+ }
+
+ break;
+ }
+
+ case TAG_METRIC_TABLE:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_METRIC_TABLE";
+#endif
+ error = parseMetricTable( streamData, drawing );
+ break;
+
+ case TAG_METRIC_BLOCK:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_METRIC_BLOCK";
+#endif
+ error = parseMetricBlock( streamData, drawing );
+ break;
+
+ case TAG_MIDX:
+ {
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_MIDX";
+#endif
+
+ quint64 value = decodeUInt( streamData->dataSource );
+
+ if( value < (uint)streamData->metrics.count() )
+ {
+ streamData->currentMetricsIndex = value;
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "- Next strokes will use metrics #" << value;
+#endif
+ }
+ else
+ {
+#ifdef ISFQT_DEBUG
+ qWarning() << "Invalid metrics ID!";
+#endif
+ }
+
+ break;
+ }
+
+ case TAG_MANTISSA:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_MANTISSA";
+#endif
+ error = parseUnsupported( streamData, "TAG_MANTISSA" );
+ break;
+
+ case TAG_PERSISTENT_FORMAT:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_PERSISTENT_FORMAT";
+#endif
+ error = parsePersistentFormat( streamData, drawing );
+ break;
+
+ case TAG_HIMETRIC_SIZE:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_HIMETRIC_SIZE";
+#endif
+ error = parseHiMetricSize( streamData, drawing );
+ break;
+
+ case TAG_STROKE_IDS:
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_STROKE_IDS";
+#endif
+
+ error = parseUnsupported( streamData, "TAG_STROKE_IDS" );
+ break;
+
+ default:
+
+ // If the tagIndex is known from the GUID table, show it differently
+ if( drawing->maxGuid_ > 0
+ && tagIndex >= DEFAULT_TAGS_NUMBER && tagIndex <= drawing->maxGuid_ )
+ {
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "Got tag (@" << place << "): TAG_CUSTOM:" << tagIndex;
+#endif
+ error = TagsParser::parseCustomTag( streamData, drawing, tagIndex );
+ }
+ else
+ {
+ error = TagsParser::parseUnsupported( streamData, "Unknown " + QString::number( tagIndex ) );
+ }
+ break;
+
+ } // End of tagIndex switch
+
+ return error;
+}
+
+
+
+/**
+ * Read away an unsupported tag.
+ *
+ * @param streamData StreamData object with the stream data
+ * @param tagName Name of the tag if known, index number if not
+ * @return IsfError
+ */
+IsfError TagsParser::parseUnsupported( StreamData* streamData, const QString& tagName )
{
// Unsupported content
- analyzePayload( source, tagName + " (Unsupported)" );
+ analyzePayload( streamData, tagName + " (Unsupported)" );
return ISF_ERROR_NONE;
}
@@ -65,17 +399,17 @@ IsfError TagsParser::parseUnsupported( DataSource &source, const QString &tagNam
* As soon as new tags will be identified, this method will recognize them and
* delegate their parsing to another method in this class.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @param tagIndex Index number of the custom tag
* @return IsfError
*/
-IsfError TagsParser::parseCustomTag( DataSource &source, Drawing &drawing, quint64 tagIndex )
+IsfError TagsParser::parseCustomTag( StreamData* streamData, Drawing* drawing, quint64 tagIndex )
{
quint64 tag = tagIndex - FIRST_CUSTOM_TAG_ID;
// Find if we have this tag registered in the GUID table
- if( tag >= (quint64)drawing.guids_.count() )
+ if( tag >= (quint64)drawing->guids_.count() )
{
#ifdef ISFQT_DEBUG
qDebug() << "Custom tag" << QString::number( tagIndex ) << "was not registered!";
@@ -84,12 +418,12 @@ IsfError TagsParser::parseCustomTag( DataSource &source, Drawing &drawing, quint
}
QList data;
- QUuid guid = drawing.guids_.at( tag );
- quint64 payloadSize = decodeUInt( source ) + 1;
+ QUuid guid = drawing->guids_.at( tag );
+ quint64 payloadSize = decodeUInt( streamData->dataSource ) + 1;
// Decompress the property data
- DataSource payload( source.getBytes( payloadSize ) );
- Compress::inflatePropertyData( payload, payloadSize-1, data );
+ DataSource payload( streamData->dataSource->getBytes( payloadSize ) );
+ Compress::inflatePropertyData( &payload, payloadSize-1, data );
// String values
if(
@@ -133,13 +467,13 @@ IsfError TagsParser::parseCustomTag( DataSource &source, Drawing &drawing, quint
/**
* Read the table of custom GUIDs.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @return IsfError
*/
-IsfError TagsParser::parseGuidTable( DataSource &source, Drawing &drawing )
+IsfError TagsParser::parseGuidTable( StreamData* streamData, Drawing* drawing )
{
- if( ! drawing.guids_.isEmpty() )
+ if( ! drawing->guids_.isEmpty() )
{
#ifdef ISFQT_DEBUG
qDebug() << "Duplicated TAG_GUID_TABLE!";
@@ -147,41 +481,41 @@ IsfError TagsParser::parseGuidTable( DataSource &source, Drawing &drawing )
return ISF_ERROR_INVALID_STREAM;
}
- quint64 guidTableSize = decodeUInt( source );
+ quint64 guidTableSize = decodeUInt( streamData->dataSource );
// GUIDs are 16 bytes long
quint8 numGuids = guidTableSize / 16;
// Maximum GUID present in the file
- drawing.maxGuid_ = 99 + numGuids;
+ drawing->maxGuid_ = 99 + numGuids;
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- New maximum GUID index:" << drawing.maxGuid_;
+ qDebug() << "- New maximum GUID index:" << drawing->maxGuid_;
qDebug() << "- GUID table has" << numGuids << "entries for total" << guidTableSize << "bytes:";
#endif
bool ok = true;
quint8 index = 0;
- while( ! source.atEnd() && index < numGuids )
+ while( ! streamData->dataSource->atEnd() && index < numGuids )
{
int block1;
short block2;
short block3;
char block4[ 8 ];
- block1 = source.getBytes( 4, &ok ).toHex().toUInt( &ok, 16 );
+ block1 = streamData->dataSource->getBytes( 4, &ok ).toHex().toUInt( &ok, 16 );
if( ! ok )
{
break;
}
- block2 = source.getBytes( 2, &ok ).toHex().toUShort( &ok, 16 );
+ block2 = streamData->dataSource->getBytes( 2, &ok ).toHex().toUShort( &ok, 16 );
if( ! ok )
{
break;
}
- block3 = source.getBytes( 2, &ok ).toHex().toUShort( &ok, 16 );
+ block3 = streamData->dataSource->getBytes( 2, &ok ).toHex().toUShort( &ok, 16 );
if( ! ok )
{
break;
@@ -189,7 +523,7 @@ IsfError TagsParser::parseGuidTable( DataSource &source, Drawing &drawing )
for( int i = 0; ok && i < 8; ++i )
{
- block4[ i ] = source.getBytes( 1, &ok ).at( 0 );
+ block4[ i ] = streamData->dataSource->getBytes( 1, &ok ).at( 0 );
}
if( ! ok )
{
@@ -200,9 +534,9 @@ IsfError TagsParser::parseGuidTable( DataSource &source, Drawing &drawing )
block4[0], block4[1], block4[2], block4[3],
block4[4], block4[5], block4[6], block4[7] );
- drawing.guids_.append( guid );
+ drawing->guids_.append( guid );
- if( index != ( drawing.guids_.count() - 1 ) )
+ if( index != ( drawing->guids_.count() - 1 ) )
{
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << " - Tag/index mismatch!";
@@ -240,16 +574,16 @@ IsfError TagsParser::parseGuidTable( DataSource &source, Drawing &drawing )
* with a payload size of 3 bytes.
*
* @see ISF_PERSISTENT_FORMAT_VERSION
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @return IsfError
*/
-IsfError TagsParser::parsePersistentFormat( DataSource &source, Drawing &drawing )
+IsfError TagsParser::parsePersistentFormat( StreamData* streamData, Drawing* drawing )
{
Q_UNUSED( drawing )
- quint64 payloadSize = decodeUInt( source );
- quint64 sourcePosition = source.pos();
+ quint64 payloadSize = decodeUInt( streamData->dataSource );
+ quint64 sourcePosition = streamData->dataSource->pos();
if( payloadSize == 0 )
{
@@ -260,17 +594,17 @@ IsfError TagsParser::parsePersistentFormat( DataSource &source, Drawing &drawing
}
// Try reading one multibyte value
- quint64 version = decodeUInt( source );
+ quint64 version = decodeUInt( streamData->dataSource );
// If we read some unexpected contents, dump them to help improving the library
- quint32 actualPayloadSize = source.pos() - sourcePosition;
+ quint32 actualPayloadSize = streamData->dataSource->pos() - sourcePosition;
if( actualPayloadSize != payloadSize )
{
#ifdef ISFQT_DEBUG
qDebug() << "Invalid payload contents for TAG_PERSISTENT_FORMAT!"
<< "Read" << actualPayloadSize << "bytes instead of" << payloadSize;
- source.seekRelative( - actualPayloadSize );
- analyzePayload( source, payloadSize, "TAG_PERSISTENT_FORMAT unknown contents" );
+ streamData->dataSource->seekRelative( - actualPayloadSize );
+ analyzePayload( streamData, payloadSize, "TAG_PERSISTENT_FORMAT unknown contents" );
#endif
}
@@ -297,13 +631,15 @@ IsfError TagsParser::parsePersistentFormat( DataSource &source, Drawing &drawing
/**
* Read the drawing dimensions.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @return IsfError
*/
-IsfError TagsParser::parseHiMetricSize( DataSource &source, Drawing &drawing )
+IsfError TagsParser::parseHiMetricSize( StreamData* streamData, Drawing* drawing )
{
- quint64 payloadSize = decodeUInt( source );
+ Q_UNUSED( drawing );
+
+ quint64 payloadSize = decodeUInt( streamData->dataSource );
if( payloadSize == 0 )
{
@@ -313,7 +649,7 @@ IsfError TagsParser::parseHiMetricSize( DataSource &source, Drawing &drawing )
return ISF_ERROR_INVALID_PAYLOAD;
}
- if( drawing.size_.isValid() )
+ if( streamData->boundingRect.isValid() )
{
#ifdef ISFQT_DEBUG
qDebug() << "Duplicated TAG_HIMETRIC_SIZE!";
@@ -321,11 +657,14 @@ IsfError TagsParser::parseHiMetricSize( DataSource &source, Drawing &drawing )
return ISF_ERROR_INVALID_STREAM;
}
- drawing.size_.setWidth ( decodeInt( source ) );
- drawing.size_.setHeight( decodeInt( source ) );
+
+ streamData->boundingRect = QRect( 0, 0, 0, 0 );
+ streamData->boundingRect.setWidth ( decodeInt( streamData->dataSource ) );
+ streamData->boundingRect.setHeight( decodeInt( streamData->dataSource ) );
+
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Drawing dimensions:" << drawing.size_;
+ qDebug() << "- Drawing dimensions:" << drawing->size();
#endif
return ISF_ERROR_NONE;
@@ -336,13 +675,14 @@ IsfError TagsParser::parseHiMetricSize( DataSource &source, Drawing &drawing )
/**
* Read a block of points attributes.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @return IsfError
*/
-IsfError TagsParser::parseAttributeBlock( DataSource &source, Drawing &drawing )
+IsfError TagsParser::parseAttributeBlock( StreamData* streamData, Drawing* drawing )
{
- quint64 payloadSize = decodeUInt( source );
+ DataSource* dataSource = streamData->dataSource;
+ quint64 payloadSize = decodeUInt( dataSource );
if( payloadSize == 0 )
{
@@ -352,27 +692,26 @@ IsfError TagsParser::parseAttributeBlock( DataSource &source, Drawing &drawing )
return ISF_ERROR_INVALID_PAYLOAD;
}
- drawing.attributeSets_.append( new AttributeSet() );
- AttributeSet *set = drawing.attributeSets_.last();
+ AttributeSet set;
// set this once when we get the first DRAW_ATTRS_BLOCK. then,
// everytime we get a DIDX we can update it. if we don't do this
// then the first stroke will have the same colour as the last stroke.
- if ( drawing.currentAttributeSet_ == &drawing.defaultAttributeSet_ )
- {
- drawing.currentAttributeSet_ = set;
- }
+// if ( drawing->currentAttributeSetIndex == &drawing->defaultAttributeSet_ )
+// {
+// streamData->currentAttributeSetIndex = streamData->attributeSets.indexOf( set );
+// }
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Added drawing attribute block #" << ( drawing.attributeSets_.count() - 1 );
+ qDebug() << "- Added drawing attribute block #" << ( streamData->attributeSets.count() - 1 );
#endif
- qint64 payloadEnd = source.pos() + payloadSize;
- while( source.pos() < payloadEnd && ! source.atEnd() )
+ qint64 payloadEnd = dataSource->pos() + payloadSize;
+ while( dataSource->pos() < payloadEnd && ! dataSource->atEnd() )
{
// Read the property and its value
- quint64 property = decodeUInt( source ); // contains a PacketProperty value
- quint64 value = decodeUInt( source );
+ quint64 property = decodeUInt( dataSource ); // contains a PacketProperty value
+ quint64 value = decodeUInt( dataSource );
switch( property )
{
@@ -389,11 +728,11 @@ IsfError TagsParser::parseAttributeBlock( DataSource &source, Drawing &drawing )
// as QRgb stores the value in BGR order: QRgb(RRGGBB) <-- value(BBGGRR).
// TODO: It also contains an alpha value, ignored here for now because it's unknown if
// it is needed or not
- set->color = QColor( qBlue ( invertedColor ),
- qGreen( invertedColor ),
- qRed ( invertedColor ) );
+ set.color = QColor( qBlue ( invertedColor ),
+ qGreen( invertedColor ),
+ qRed ( invertedColor ) );
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Got pen color" << set->color.name().toUpper();
+ qDebug() << "- Got pen color" << set.color.name().toUpper();
#endif
break;
}
@@ -404,15 +743,15 @@ IsfError TagsParser::parseAttributeBlock( DataSource &source, Drawing &drawing )
<< "(" << (value/HiMetricToPixel) << "pixels )";
#endif
// In square/round pens the width will be the only value present.
- set->penSize.setWidth ( (float)value / HiMetricToPixel );
- set->penSize.setHeight( (float)value / HiMetricToPixel );
+ set.penSize.setWidth ( (float)value / HiMetricToPixel );
+ set.penSize.setHeight( (float)value / HiMetricToPixel );
break;
case GUID_PEN_HEIGHT:
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "- Got pen height" << QString::number( (float)value, 'g', 16 );
#endif
- set->penSize.setHeight( (float)value / HiMetricToPixel );
+ set.penSize.setHeight( (float)value / HiMetricToPixel );
break;
case GUID_PEN_TIP:
@@ -421,12 +760,12 @@ IsfError TagsParser::parseAttributeBlock( DataSource &source, Drawing &drawing )
#endif
if( value )
{
- set->flags |= IsRectangle;
+ set.flags |= IsRectangle;
}
break;
case GUID_DRAWING_FLAGS:
- set->flags = (StrokeFlags)( ( 0XFF00 & set->flags ) | (ushort) value );
+ set.flags = (StrokeFlags)( ( 0XFF00 & set.flags ) | (ushort) value );
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "- Got flags value:" << value;
if( value & FitToCurve )
@@ -458,7 +797,7 @@ IsfError TagsParser::parseAttributeBlock( DataSource &source, Drawing &drawing )
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "- Got pen transparency" << value;
#endif
- set->color.setAlpha( value );
+ set.color.setAlpha( value );
break;
case GUID_ROP:
@@ -466,7 +805,7 @@ IsfError TagsParser::parseAttributeBlock( DataSource &source, Drawing &drawing )
qDebug() << "- Got ROP property (Run Of Press? Reject Occasional Partners?)";
// We already read the first value, go back
// source.seekRelative( getMultiByteSize( value ) );
- analyzePayload( source, 3 );
+ analyzePayload( streamData, 3 );
#endif
// info.flags |= IsHighlighter;
break;
@@ -477,13 +816,13 @@ IsfError TagsParser::parseAttributeBlock( DataSource &source, Drawing &drawing )
#endif
// If the tag *should* be known, record it differently
- if( drawing.maxGuid_ > 0 && property >= 100 && property <= drawing.maxGuid_ )
+ if( drawing->maxGuid_ > 0 && property >= 100 && property <= drawing->maxGuid_ )
{
- analyzePayload( source, "TAG_PROPERTY_" + QString::number( property ) );
+ analyzePayload( streamData, "TAG_PROPERTY_" + QString::number( property ) );
}
else
{
- analyzePayload( source, "Unknown property " + QString::number( property ) );
+ analyzePayload( streamData, "Unknown property " + QString::number( property ) );
}
break;
}
@@ -491,15 +830,16 @@ IsfError TagsParser::parseAttributeBlock( DataSource &source, Drawing &drawing )
// Update the drawing's maximum pen size.
// This value is used to adjust the drawing borders to include thick strokes
- if( set->penSize.width() > drawing.maxPenSize_.width() )
+ if( set.penSize.width() > drawing->maxPenSize_.width() )
{
- drawing.maxPenSize_.setWidth( set->penSize.width() );
+ drawing->maxPenSize_.setWidth( set.penSize.width() );
}
- if( set->penSize.height() > drawing.maxPenSize_.height() )
+ if( set.penSize.height() > drawing->maxPenSize_.height() )
{
- drawing.maxPenSize_.setHeight( set->penSize.height() );
+ drawing->maxPenSize_.setHeight( set.penSize.height() );
}
+ streamData->attributeSets.append( set );
return ISF_ERROR_NONE;
}
@@ -509,14 +849,15 @@ IsfError TagsParser::parseAttributeBlock( DataSource &source, Drawing &drawing )
/**
* Read a table of points attributes.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @return IsfError
*/
-IsfError TagsParser::parseAttributeTable( DataSource &source, Drawing &drawing )
+IsfError TagsParser::parseAttributeTable( StreamData* streamData, Drawing* drawing )
{
IsfError result = ISF_ERROR_NONE;
- quint64 payloadSize = decodeUInt( source );
+ DataSource* dataSource = streamData->dataSource;
+ quint64 payloadSize = decodeUInt( dataSource );
if( payloadSize == 0 )
{
@@ -526,13 +867,13 @@ IsfError TagsParser::parseAttributeTable( DataSource &source, Drawing &drawing )
return ISF_ERROR_INVALID_PAYLOAD;
}
- qint64 payloadEnd = source.pos() + payloadSize;
- while( result == ISF_ERROR_NONE && source.pos() < payloadEnd && ! source.atEnd() )
+ qint64 payloadEnd = dataSource->pos() + payloadSize;
+ while( result == ISF_ERROR_NONE && dataSource->pos() < payloadEnd && ! dataSource->atEnd() )
{
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "Got tag: TAG_DRAW_ATTRS_BLOCK";
#endif
- result = parseAttributeBlock( source, drawing );
+ result = parseAttributeBlock( streamData, drawing );
}
return result;
@@ -543,13 +884,13 @@ IsfError TagsParser::parseAttributeTable( DataSource &source, Drawing &drawing )
/**
* Read the ink canvas dimensions.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @return IsfError
*/
-IsfError TagsParser::parseInkSpaceRectangle( DataSource &source, Drawing &drawing )
+IsfError TagsParser::parseInkSpaceRectangle( StreamData* streamData, Drawing* drawing )
{
- if( drawing.canvas_.isValid() )
+ if( drawing->canvas_.isValid() )
{
#ifdef ISFQT_DEBUG
qDebug() << "Duplicated TAG_INK_SPACE_RECT!";
@@ -558,13 +899,14 @@ IsfError TagsParser::parseInkSpaceRectangle( DataSource &source, Drawing &drawin
}
// This tag has a fixed 4-byte size
- drawing.canvas_.setLeft ( decodeInt( source ) );
- drawing.canvas_.setTop ( decodeInt( source ) );
- drawing.canvas_.setRight ( decodeInt( source ) );
- drawing.canvas_.setBottom( decodeInt( source ) );
+ DataSource* dataSource = streamData->dataSource;
+ drawing->canvas_.setLeft ( decodeInt( dataSource ) );
+ drawing->canvas_.setTop ( decodeInt( dataSource ) );
+ drawing->canvas_.setRight ( decodeInt( dataSource ) );
+ drawing->canvas_.setBottom( decodeInt( dataSource ) );
#ifdef ISFQT_DEBUG
- qDebug() << "- Got drawing canvas:" << drawing.canvas_;
+ qDebug() << "- Got drawing canvas:" << drawing->canvas_;
#endif
return ISF_ERROR_NONE;
@@ -575,14 +917,16 @@ IsfError TagsParser::parseInkSpaceRectangle( DataSource &source, Drawing &drawin
/**
* Read a Metrics table.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @return IsfError
*/
-IsfError TagsParser::parseMetricTable( DataSource &source, Drawing &drawing )
+IsfError TagsParser::parseMetricTable( StreamData* streamData, Drawing* drawing )
{
IsfError result = ISF_ERROR_NONE;
- quint64 payloadSize = decodeUInt( source );
+ DataSource* dataSource = streamData->dataSource;
+
+ quint64 payloadSize = decodeUInt( dataSource );
if( payloadSize == 0 )
{
@@ -592,10 +936,10 @@ IsfError TagsParser::parseMetricTable( DataSource &source, Drawing &drawing )
return ISF_ERROR_INVALID_PAYLOAD;
}
- qint64 payloadEnd = source.pos() + payloadSize;
- while( result == ISF_ERROR_NONE && source.pos() < payloadEnd && ! source.atEnd() )
+ qint64 payloadEnd = dataSource->pos() + payloadSize;
+ while( result == ISF_ERROR_NONE && dataSource->pos() < payloadEnd && ! dataSource->atEnd() )
{
- result = parseMetricBlock( source, drawing );
+ result = parseMetricBlock( streamData, drawing );
}
return result;
@@ -606,15 +950,16 @@ IsfError TagsParser::parseMetricTable( DataSource &source, Drawing &drawing )
/**
* Read a Metrics block.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @return IsfError
*/
-IsfError TagsParser::parseMetricBlock( DataSource &source, Drawing &drawing )
+IsfError TagsParser::parseMetricBlock( StreamData* streamData, Drawing* drawing )
{
Q_UNUSED( drawing )
- quint64 payloadSize = decodeUInt( source );
+ DataSource* dataSource = streamData->dataSource;
+ quint64 payloadSize = decodeUInt( dataSource );
if( payloadSize == 0 )
{
@@ -624,14 +969,16 @@ IsfError TagsParser::parseMetricBlock( DataSource &source, Drawing &drawing )
return ISF_ERROR_INVALID_PAYLOAD;
}
- Metrics *metricsList = new Metrics();
- qint64 payloadEnd = source.pos() + payloadSize;
- while( source.pos() < payloadEnd && ! source.atEnd() )
+ Metrics* metricsList = new Metrics();
+ qint64 payloadEnd = dataSource->pos() + payloadSize;
+ while( dataSource->pos() < payloadEnd && ! dataSource->atEnd() )
{
- quint64 property = Isf::Compress::decodeUInt( source );
+ quint64 property = Isf::Compress::decodeUInt( dataSource );
- qint64 initialPos = source.pos();
- payloadSize = Isf::Compress::decodeUInt( source );
+#ifdef ISFQT_DEBUG
+ qint64 initialPos = dataSource->pos();
+#endif
+ payloadSize = Isf::Compress::decodeUInt( dataSource );
// Two multibyte signed ints, one byte, one float: minimum 7 bytes
if( payloadSize < 7 )
@@ -639,16 +986,16 @@ IsfError TagsParser::parseMetricBlock( DataSource &source, Drawing &drawing )
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "- Metric id" << property << "has an invalid payload size:" << payloadSize;
#endif
- analyzePayload( source, payloadSize );
+ analyzePayload( streamData, payloadSize );
continue;
}
// Get the metric values
Metric metric;
- metric.min = Isf::Compress::decodeInt( source );
- metric.max = Isf::Compress::decodeInt( source );
- metric.units = (MetricScale) source.getByte();
- metric.resolution = Isf::Compress::decodeFloat( source );
+ metric.min = Isf::Compress::decodeInt( dataSource );
+ metric.max = Isf::Compress::decodeInt( dataSource );
+ metric.units = (MetricScale) dataSource->getByte();
+ metric.resolution = Isf::Compress::decodeFloat( dataSource );
// Identify the metric
switch( property )
@@ -675,17 +1022,17 @@ IsfError TagsParser::parseMetricBlock( DataSource &source, Drawing &drawing )
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "- Unknown metric, id:" << property << "size:" << payloadSize;
#endif
- analyzePayload( source, payloadSize );
+ analyzePayload( streamData, payloadSize );
continue;
}
#ifdef ISFQT_DEBUG
// If there's extra data, show it
- quint64 parsedPayload = ( source.pos() - initialPos );
+ quint64 parsedPayload = ( dataSource->pos() - initialPos );
if( parsedPayload < payloadSize )
{
qDebug() << "- Extra data:";
- analyzePayload( source, payloadSize - parsedPayload );
+ analyzePayload( streamData, payloadSize - parsedPayload );
}
#endif
@@ -699,16 +1046,16 @@ IsfError TagsParser::parseMetricBlock( DataSource &source, Drawing &drawing )
}
// Save the obtained metrics
- drawing.metrics_.append( metricsList );
- Metrics *savedMetrics = drawing.metrics_.last();
+ streamData->metrics.append( metricsList );
// set this once when we get the first METRIC_BLOCK. then,
// everytime we get a MIDX we can update it. if we don't do this
// then the first stroke will have the same metrics as the last stroke.
- if ( drawing.currentMetrics_ == &drawing.defaultMetrics_ )
- {
- drawing.currentMetrics_ = savedMetrics;
- }
+// Metrics* savedMetrics = streamData->metrics.last();
+// if ( drawing->currentMetrics_ == &drawing->defaultMetrics_ )
+// {
+// drawing->currentMetrics_ = savedMetrics;
+// }
return ISF_ERROR_NONE;
}
@@ -718,14 +1065,15 @@ IsfError TagsParser::parseMetricBlock( DataSource &source, Drawing &drawing )
/**
* Read a table of transformation matrices.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @return IsfError
*/
-IsfError TagsParser::parseTransformationTable( DataSource &source, Drawing &drawing )
+IsfError TagsParser::parseTransformationTable( StreamData* streamData, Drawing* drawing )
{
IsfError result = ISF_ERROR_NONE;
- quint64 payloadSize = decodeUInt( source );
+ DataSource* dataSource = streamData->dataSource;
+ quint64 payloadSize = decodeUInt( dataSource );
if( payloadSize == 0 )
{
@@ -735,13 +1083,13 @@ IsfError TagsParser::parseTransformationTable( DataSource &source, Drawing &draw
return ISF_ERROR_INVALID_PAYLOAD;
}
- qint64 payloadEnd = source.pos() + payloadSize;
- while( result == ISF_ERROR_NONE && source.pos() < payloadEnd && ! source.atEnd() )
+ qint64 payloadEnd = dataSource->pos() + payloadSize;
+ while( result == ISF_ERROR_NONE && dataSource->pos() < payloadEnd && ! dataSource->atEnd() )
{
// Read the type of the next transformation
- DataTag tagIndex = (DataTag) Compress::decodeUInt( source );
+ DataTag tagIndex = (DataTag) Compress::decodeUInt( dataSource );
- result = parseTransformation( source, drawing, tagIndex );
+ result = parseTransformation( streamData, drawing, tagIndex );
}
return result;
@@ -752,14 +1100,17 @@ IsfError TagsParser::parseTransformationTable( DataSource &source, Drawing &draw
/**
* Read a drawing transformation matrix.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @param transformType Type of transform to read
* @return IsfError
*/
-IsfError TagsParser::parseTransformation( DataSource &source, Drawing &drawing, quint64 transformType )
+IsfError TagsParser::parseTransformation( StreamData* streamData, Drawing* drawing, quint64 transformType )
{
- QMatrix *transform = new QMatrix();
+ Q_UNUSED( drawing );
+
+ QMatrix* transform = new QMatrix();
+ DataSource* dataSource = streamData->dataSource;
/*
* Unlike the other transformations, scale is expressed in HiMetric units,
@@ -778,12 +1129,12 @@ IsfError TagsParser::parseTransformation( DataSource &source, Drawing &drawing,
{
case TAG_TRANSFORM:
{
- float scaleX = Compress::decodeFloat( source ) / HiMetricToPixel;
- float scaleY = Compress::decodeFloat( source ) / HiMetricToPixel;
- float shearX = Compress::decodeFloat( source );
- float shearY = Compress::decodeFloat( source );
- float dx = Compress::decodeFloat( source );
- float dy = Compress::decodeFloat( source );
+ float scaleX = Compress::decodeFloat( dataSource ) / HiMetricToPixel;
+ float scaleY = Compress::decodeFloat( dataSource ) / HiMetricToPixel;
+ float shearX = Compress::decodeFloat( dataSource );
+ float shearY = Compress::decodeFloat( dataSource );
+ float dx = Compress::decodeFloat( dataSource );
+ float dy = Compress::decodeFloat( dataSource );
transform->setMatrix( scaleX, scaleY, shearX, shearY, dx, dy );
@@ -801,7 +1152,7 @@ IsfError TagsParser::parseTransformation( DataSource &source, Drawing &drawing,
case TAG_TRANSFORM_ISOTROPIC_SCALE:
{
- float scaleAmount = Compress::decodeFloat( source ) / HiMetricToPixel;
+ float scaleAmount = Compress::decodeFloat( dataSource ) / HiMetricToPixel;
transform->scale( scaleAmount, scaleAmount );
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "- Transformation details - "
@@ -812,8 +1163,8 @@ IsfError TagsParser::parseTransformation( DataSource &source, Drawing &drawing,
case TAG_TRANSFORM_ANISOTROPIC_SCALE:
{
- float scaleX = Compress::decodeFloat( source ) / HiMetricToPixel;
- float scaleY = Compress::decodeFloat( source ) / HiMetricToPixel;
+ float scaleX = Compress::decodeFloat( dataSource ) / HiMetricToPixel;
+ float scaleY = Compress::decodeFloat( dataSource ) / HiMetricToPixel;
transform->scale( scaleX, scaleY );
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "- Transformation details - "
@@ -825,7 +1176,7 @@ IsfError TagsParser::parseTransformation( DataSource &source, Drawing &drawing,
case TAG_TRANSFORM_ROTATE:
{
- float rotateAmount = Compress::decodeFloat( source ) / 100.0f;
+ float rotateAmount = Compress::decodeFloat( dataSource ) / 100.0f;
transform->rotate( rotateAmount );
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "- Transformation details - "
@@ -836,8 +1187,8 @@ IsfError TagsParser::parseTransformation( DataSource &source, Drawing &drawing,
case TAG_TRANSFORM_TRANSLATE:
{
- float dx = Compress::decodeFloat( source );
- float dy = Compress::decodeFloat( source );
+ float dx = Compress::decodeFloat( dataSource );
+ float dy = Compress::decodeFloat( dataSource );
transform->translate( dx, dy );
#ifdef ISFQT_DEBUG_VERBOSE
@@ -850,10 +1201,10 @@ IsfError TagsParser::parseTransformation( DataSource &source, Drawing &drawing,
case TAG_TRANSFORM_SCALE_AND_TRANSLATE:
{
- float scaleX = Compress::decodeFloat( source ) / HiMetricToPixel;
- float scaleY = Compress::decodeFloat( source ) / HiMetricToPixel;
- float dx = Compress::decodeFloat( source );
- float dy = Compress::decodeFloat( source );
+ float scaleX = Compress::decodeFloat( dataSource ) / HiMetricToPixel;
+ float scaleY = Compress::decodeFloat( dataSource ) / HiMetricToPixel;
+ float dx = Compress::decodeFloat( dataSource );
+ float dy = Compress::decodeFloat( dataSource );
transform->scale ( scaleX, scaleY );
transform->translate( dx, dy );
@@ -875,18 +1226,18 @@ IsfError TagsParser::parseTransformation( DataSource &source, Drawing &drawing,
return ISF_ERROR_INVALID_BLOCK;
}
- drawing.transforms_.append( transform );
+ streamData->transforms.append( transform );
// set this once when we get the first transformation. then,
// everytime we get a TIDX we can update it. if we don't do this
// then the first stroke will have the same transform as the last stroke.
- if ( drawing.currentTransform_ == &drawing.defaultTransform_ )
- {
- drawing.currentTransform_ = drawing.transforms_.last();
- }
+// if ( drawing->currentTransform_ == &drawing->defaultTransform_ )
+// {
+// drawing->currentTransform_ = drawing->transforms_.last();
+// }
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Added transform block #" << ( drawing.transforms_.count() - 1 );
+ qDebug() << "- Added transform block #" << ( streamData->transforms.count() - 1 );
#endif
return ISF_ERROR_NONE;
@@ -897,14 +1248,15 @@ IsfError TagsParser::parseTransformation( DataSource &source, Drawing &drawing,
/**
* Read a stroke.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @return IsfError
*/
-IsfError TagsParser::parseStroke( DataSource &source, Drawing &drawing )
+IsfError TagsParser::parseStroke( StreamData* streamData, Drawing* drawing )
{
- quint64 payloadSize = decodeUInt( source );
- quint64 initialPos = source.pos();
+ DataSource* dataSource = streamData->dataSource;
+ quint64 payloadSize = decodeUInt( dataSource );
+ quint64 initialPos = dataSource->pos();
if( payloadSize == 0 )
{
@@ -915,14 +1267,18 @@ IsfError TagsParser::parseStroke( DataSource &source, Drawing &drawing )
}
// Get the number of points which comprise this stroke
- quint64 numPoints = decodeUInt( source );
+ quint64 numPoints = decodeUInt( dataSource );
+
+ QList xPointsData, yPointsData, pressureData;
+
+ // If the stream has pressure info, parse it
+ bool streamHasPressureData = streamData->strokeInfos.count() && streamData->strokeInfos.last()->hasPressureData;
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "- Tag size:" << payloadSize << "Points stored:" << numPoints;
#endif
- QList xPointsData, yPointsData, pressureData;
- if( ! Compress::inflatePacketData( source, numPoints, xPointsData ) )
+ if( ! Compress::inflatePacketData( dataSource, numPoints, xPointsData ) )
{
#ifdef ISFQT_DEBUG
qWarning() << "Decompression failure while extracting X points data!";
@@ -930,7 +1286,7 @@ IsfError TagsParser::parseStroke( DataSource &source, Drawing &drawing )
#endif
}
- if( ! Compress::inflatePacketData( source, numPoints, yPointsData ) )
+ if( ! Compress::inflatePacketData( dataSource, numPoints, yPointsData ) )
{
#ifdef ISFQT_DEBUG
qWarning() << "Decompression failure while extracting Y points data!";
@@ -938,8 +1294,8 @@ IsfError TagsParser::parseStroke( DataSource &source, Drawing &drawing )
#endif
}
- if( drawing.currentStrokeInfo_->hasPressureData
- && ! Compress::inflatePacketData( source, numPoints, pressureData ) )
+ if( streamHasPressureData
+ && ! Compress::inflatePacketData( dataSource, numPoints, pressureData ) )
{
#ifdef ISFQT_DEBUG
qWarning() << "Decompression failure while extracting pressure data!";
@@ -955,7 +1311,7 @@ IsfError TagsParser::parseStroke( DataSource &source, Drawing &drawing )
#endif
}
- if( drawing.currentStrokeInfo_->hasPressureData
+ if( streamHasPressureData
&& (uint)pressureData.size() != numPoints )
{
#ifdef ISFQT_DEBUG
@@ -965,62 +1321,77 @@ IsfError TagsParser::parseStroke( DataSource &source, Drawing &drawing )
}
// Add a new stroke
- drawing.strokes_.append( new Stroke() );
- Stroke *stroke = drawing.strokes_[ drawing.strokes_.size() - 1 ];
+ drawing->strokes_.append( new Stroke() );
+ Stroke* stroke = drawing->strokes_.last();
+
+ // Apply the stroke style, transforms and metrics
+ if( streamData->attributeSets.count() )
+ {
+ AttributeSet set = streamData->attributeSets.at( streamData->currentAttributeSetIndex );
+
+ stroke->setColor ( set.color );
+ stroke->setFlags ( set.flags );
+ stroke->setPenSize( set.penSize );
+ }
+ if( streamData->metrics.count() )
+ {
+ Metrics* metrics = streamData->metrics.at( streamData->currentMetricsIndex );
+
+ if( ! metrics )
+ {
+ qWarning() << "Invalid reference to metrics" << streamData->currentMetricsIndex;
+ }
+ else
+ {
+ stroke->setMetrics( metrics );
+ }
+ }
+ if( streamData->transforms.count() )
+ {
+ QMatrix* transform = streamData->transforms.at( streamData->currentTransformsIndex );
+
+ if( ! transform )
+ {
+ qWarning() << "Invalid reference to transform" << streamData->currentTransformsIndex;
+ }
+ else
+ {
+ stroke->setTransform( transform );
+ }
+ }
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Added stroke #" << ( drawing.strokes_.count() - 1 );
+ qDebug() << "- Added stroke #" << ( drawing->strokes_.count() - 1 );
#endif
- // The polygon is used to obtain the stroke's bounding rect
- QPolygon polygon( numPoints );
+ // Add the points to the stroke
+ PointList list;
for( quint64 i = 0; i < numPoints; ++i )
{
- stroke->points.append( Point() );
- Point &point = stroke->points[ stroke->points.size() - 1 ];
+ list.append( Point() );
+ Point &point = list.last();
point.position.setX( xPointsData[ i ] );
point.position.setY( yPointsData[ i ] );
- polygon.setPoint( i, xPointsData[ i ], yPointsData[ i ] );
-
- if( drawing.currentStrokeInfo_->hasPressureData )
+ if( streamHasPressureData )
{
point.pressureLevel = pressureData[ i ];
}
}
-
- if ( drawing.currentTransform_ != 0 )
- {
- polygon = drawing.currentTransform_->map( polygon );
- }
-
- stroke->boundingRect = polygon.boundingRect();
-
- // set the bounding rectangle.
- if ( stroke->boundingRect.size() == QSize(1, 1) )
- {
- // can't have a 1px by 1px bounding rect - the eraser will never hit it.
- // make the bounding rectange completely cover the drawn stroke.
- float penSize = drawing.currentAttributeSet_->penSize.width();
- stroke->boundingRect.setSize( QSize( penSize, penSize ) );
- stroke->boundingRect.translate( -( penSize / 2 ), -( penSize / 2 ) );
- }
-
- stroke->attributes = drawing.currentAttributeSet_;
- stroke->info = drawing.currentStrokeInfo_;
- stroke->metrics = drawing.currentMetrics_;
- stroke->transform = drawing.currentTransform_;
+ // And finish it out
+ stroke->addPoints( list );
+ stroke->finalize();
// Update the entire drawing's bounding rect
- drawing.boundingRect_ = drawing.boundingRect_.united( stroke->boundingRect );
+ drawing->boundingRect_ = drawing->boundingRect_.united( stroke->boundingRect() );
- qint64 remainingPayloadSize = payloadSize - ( source.pos() - initialPos );
+ qint64 remainingPayloadSize = payloadSize - ( dataSource->pos() - initialPos );
if( remainingPayloadSize > 0 )
{
- analyzePayload( source,
+ analyzePayload( streamData,
remainingPayloadSize,
- "Remaining stroke data: " + QString::number(remainingPayloadSize) +
+ "Remaining stroke data: " + QString::number( remainingPayloadSize ) +
" bytes" );
}
@@ -1032,13 +1403,16 @@ IsfError TagsParser::parseStroke( DataSource &source, Drawing &drawing )
/**
* Read a stroke description block.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @return IsfError
*/
-IsfError TagsParser::parseStrokeDescBlock( DataSource &source, Drawing &drawing )
+IsfError TagsParser::parseStrokeDescBlock( StreamData* streamData, Drawing* drawing )
{
- quint64 payloadSize = decodeUInt( source );
+ Q_UNUSED( drawing );
+
+ DataSource* dataSource = streamData->dataSource;
+ quint64 payloadSize = decodeUInt( dataSource );
if( payloadSize == 0 )
{
@@ -1052,25 +1426,25 @@ IsfError TagsParser::parseStrokeDescBlock( DataSource &source, Drawing &drawing
qDebug() << "- Finding stroke description properties in the next" << payloadSize << "bytes";
#endif
- drawing.strokeInfo_.append( new StrokeInfo() );
- StrokeInfo *info = drawing.strokeInfo_.last();
+ streamData->strokeInfos.append( new StrokeInfo() );
+ StrokeInfo* info = streamData->strokeInfos.last();
// set this once when we get the first TAG_STROKE_DESC_BLOCK. then,
// everytime we get a SIDX we can update it. if we don't do this
// then the first stroke will have the same stroke info as the last stroke.
- if ( drawing.currentStrokeInfo_ == &drawing.defaultStrokeInfo_ )
- {
- drawing.currentStrokeInfo_ = info;
- }
+// if ( drawing->currentStrokeInfo_ == &drawing->defaultStrokeInfo_ )
+// {
+// drawing->currentStrokeInfo_ = info;
+// }
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Added stroke info block #" << ( drawing.strokeInfo_.count() - 1 );
+ qDebug() << "- Added stroke info block #" << ( streamData->strokeInfos.count() - 1 );
#endif
- qint64 payloadEnd = source.pos() + payloadSize;
- while( source.pos() < payloadEnd && ! source.atEnd() )
+ qint64 payloadEnd = dataSource->pos() + payloadSize;
+ while( dataSource->pos() < payloadEnd && ! dataSource->atEnd() )
{
- quint64 tag = decodeUInt( source );
+ quint64 tag = decodeUInt( dataSource );
switch( tag )
{
@@ -1127,14 +1501,16 @@ IsfError TagsParser::parseStrokeDescBlock( DataSource &source, Drawing &drawing
/**
* Read a stroke description table.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param drawing Drawing into which the data obtained from the tag should be read
* @return IsfError
*/
-IsfError TagsParser::parseStrokeDescTable( DataSource &source, Drawing &drawing )
+IsfError TagsParser::parseStrokeDescTable( StreamData* streamData, Drawing* drawing )
{
IsfError result = ISF_ERROR_NONE;
- quint64 payloadSize = decodeUInt( source );
+ DataSource* dataSource = streamData->dataSource;
+
+ quint64 payloadSize = decodeUInt( dataSource );
if( payloadSize == 0 )
{
@@ -1144,10 +1520,10 @@ IsfError TagsParser::parseStrokeDescTable( DataSource &source, Drawing &drawing
return ISF_ERROR_INVALID_PAYLOAD;
}
- qint64 payloadEnd = source.pos() + payloadSize;
- while( result == ISF_ERROR_NONE && source.pos() < payloadEnd && ! source.atEnd() )
+ qint64 payloadEnd = dataSource->pos() + payloadSize;
+ while( result == ISF_ERROR_NONE && dataSource->pos() < payloadEnd && ! dataSource->atEnd() )
{
- result = parseStrokeDescBlock( source, drawing );
+ result = parseStrokeDescBlock( streamData, drawing );
}
return result;
@@ -1163,15 +1539,15 @@ IsfError TagsParser::parseStrokeDescTable( DataSource &source, Drawing &drawing
* - a payload size (multibyte-encoded)
* - the actual tag data
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param tagName Name of the tag if known, index number if not
* @return Byte array with the contents of the tag
*/
-QByteArray TagsParser::analyzePayload( DataSource &source, const QString &tagName )
+QByteArray TagsParser::analyzePayload( StreamData* streamData, const QString& tagName )
{
- quint64 payloadSize = decodeUInt( source );
+ quint64 payloadSize = decodeUInt( streamData->dataSource );
- return analyzePayload( source,
+ return analyzePayload( streamData,
payloadSize,
"Got tag: " + tagName + " with " + QString::number( payloadSize ) + " bytes of payload" );
}
@@ -1183,12 +1559,12 @@ QByteArray TagsParser::analyzePayload( DataSource &source, const QString &tagNam
*
* This variant can be used to print out an arbitrarily sized data block.
*
- * @param source Data Source where to read bytes from
+ * @param streamData StreamData object with the stream data
* @param payloadSize Size of the payload to print out
* @param message Message to show as label for the printed out data
* @return Byte array with the contents of the tag
*/
-QByteArray TagsParser::analyzePayload( DataSource &source, const quint64 payloadSize, const QString &message )
+QByteArray TagsParser::analyzePayload( StreamData* streamData, const quint64 payloadSize, const QString& message )
{
QByteArray result;
QByteArray output;
@@ -1200,7 +1576,7 @@ QByteArray TagsParser::analyzePayload( DataSource &source, const quint64 payload
#ifndef ISFQT_DEBUG_VERBOSE
Q_UNUSED( message )
- source.seekRelative( +payloadSize );
+ streamData->dataSource->seekRelative( +payloadSize );
return output;
#endif
@@ -1211,9 +1587,9 @@ QByteArray TagsParser::analyzePayload( DataSource &source, const quint64 payload
qDebug() << message;
}
qDebug() << "--------------------------------------------------------------------";
- while( ! source.atEnd() && pos < payloadSize )
+ while( ! streamData->dataSource->atEnd() && pos < payloadSize )
{
- quint8 byte = source.getByte();
+ quint8 byte = streamData->dataSource->getByte();
result.append( byte );
output.append( QByteArray::number( byte, 16 ).rightJustified( 2, '0').toUpper() + " " );
diff --git a/contrib/isf-qt/src/tagsparser.h b/contrib/isf-qt/src/tagsparser.h
index 3b4c718..a83e65d 100644
--- a/contrib/isf-qt/src/tagsparser.h
+++ b/contrib/isf-qt/src/tagsparser.h
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -39,11 +37,7 @@ namespace Isf
// Forward declarations
- namespace Compress
- {
- class DataSource;
- }
- using Compress::DataSource;
+ class StreamData;
class Drawing;
@@ -57,27 +51,29 @@ namespace Isf
{
public: // Static public methods
- static IsfError parseCustomTag( DataSource &source, Drawing &drawing, quint64 tagIndex );
- static IsfError parseGuidTable( DataSource &source, Drawing &drawing );
- static IsfError parseHiMetricSize( DataSource &source, Drawing &drawing );
- static IsfError parseInkSpaceRectangle( DataSource &source, Drawing &drawing );
- static IsfError parseAttributeBlock( DataSource &source, Drawing &drawing );
- static IsfError parseAttributeTable( DataSource &source, Drawing &drawing );
- static IsfError parsePersistentFormat( DataSource &source, Drawing &drawing );
- static IsfError parseMetricBlock( DataSource &source, Drawing &drawing );
- static IsfError parseMetricTable( DataSource &source, Drawing &drawing );
- static IsfError parseTransformation( DataSource &source, Drawing &drawing, quint64 transformType );
- static IsfError parseTransformationTable( DataSource &source, Drawing &drawing );
- static IsfError parseStroke( DataSource &source, Drawing &drawing );
- static IsfError parseStrokeDescBlock( DataSource &source, Drawing &drawing );
- static IsfError parseStrokeDescTable( DataSource &source, Drawing &drawing );
+ static IsfError nextTag( StreamData* streamData, Drawing* drawing );
+
+ static IsfError parseCustomTag( StreamData* streamData, Drawing* drawing, quint64 tagIndex );
+ static IsfError parseGuidTable( StreamData* streamData, Drawing* drawing );
+ static IsfError parseHiMetricSize( StreamData* streamData, Drawing* drawing );
+ static IsfError parseInkSpaceRectangle( StreamData* streamData, Drawing* drawing );
+ static IsfError parseAttributeBlock( StreamData* streamData, Drawing* drawing );
+ static IsfError parseAttributeTable( StreamData* streamData, Drawing* drawing );
+ static IsfError parsePersistentFormat( StreamData* streamData, Drawing* drawing );
+ static IsfError parseMetricBlock( StreamData* streamData, Drawing* drawing );
+ static IsfError parseMetricTable( StreamData* streamData, Drawing* drawing );
+ static IsfError parseTransformation( StreamData* streamData, Drawing* drawing, quint64 transformType );
+ static IsfError parseTransformationTable( StreamData* streamData, Drawing* drawing );
+ static IsfError parseStroke( StreamData* streamData, Drawing* drawing );
+ static IsfError parseStrokeDescBlock( StreamData* streamData, Drawing* drawing );
+ static IsfError parseStrokeDescTable( StreamData* streamData, Drawing* drawing );
public: // Static public debugging methods
- static IsfError parseUnsupported( DataSource &source, const QString &tagName );
+ static IsfError parseUnsupported( StreamData* streamData, const QString& tagName );
private: // Static private debugging methods
- static QByteArray analyzePayload( DataSource &source, const QString &tagName );
- static QByteArray analyzePayload( DataSource &source, const quint64 payloadSize, const QString &message = QString() );
+ static QByteArray analyzePayload( StreamData* streamData, const QString& tagName );
+ static QByteArray analyzePayload( StreamData* streamData, const quint64 payloadSize, const QString& message = QString() );
};
}
diff --git a/contrib/isf-qt/src/tagswriter.cpp b/contrib/isf-qt/src/tagswriter.cpp
index aeaa4ca..82564e5 100644
--- a/contrib/isf-qt/src/tagswriter.cpp
+++ b/contrib/isf-qt/src/tagswriter.cpp
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -46,7 +44,7 @@ using namespace Isf::Compress;
* @param drawing Drawing from which to obtain the data to write
* @return IsfError
*/
-IsfError TagsWriter::addPersistentFormat( DataSource &source, const Drawing &drawing )
+IsfError TagsWriter::addPersistentFormat( StreamData* streamData, const Drawing* drawing )
{
Q_UNUSED( drawing );
@@ -57,7 +55,7 @@ IsfError TagsWriter::addPersistentFormat( DataSource &source, const Drawing &dra
tagContents.prepend( encodeUInt( tagContents.size() ) );
tagContents.prepend( encodeUInt( TAG_PERSISTENT_FORMAT ) );
- source.append( tagContents );
+ streamData->dataSource->append( tagContents );
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "- Persistent Format version";
@@ -75,19 +73,20 @@ IsfError TagsWriter::addPersistentFormat( DataSource &source, const Drawing &dra
* @param drawing Drawing from which to obtain the data to write
* @return IsfError
*/
-IsfError TagsWriter::addHiMetricSize( DataSource &source, const Drawing &drawing )
+IsfError TagsWriter::addHiMetricSize( StreamData* streamData, const Drawing* drawing )
{
QByteArray tagContents;
- tagContents.append( encodeInt( drawing.size_.width () ) );
- tagContents.append( encodeInt( drawing.size_.height() ) );
+ QPoint size( drawing->boundingRect().bottomRight() );
+ tagContents.append( encodeInt( size.x() ) );
+ tagContents.append( encodeInt( size.y() ) );
- encodeUInt( source, TAG_HIMETRIC_SIZE );
- encodeUInt( source, tagContents.size() );
- source.append( tagContents );
+ encodeUInt( streamData->dataSource, TAG_HIMETRIC_SIZE );
+ encodeUInt( streamData->dataSource, tagContents.size() );
+ streamData->dataSource->append( tagContents );
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Added drawing dimensions:" << drawing.size_;
+ qDebug() << "- Added drawing dimensions:" << size;
#endif
return ISF_ERROR_NONE;
@@ -105,68 +104,85 @@ IsfError TagsWriter::addHiMetricSize( DataSource &source, const Drawing &drawing
* @param drawing Drawing from which to obtain the data to write
* @return IsfError
*/
-IsfError TagsWriter::addAttributeTable( DataSource &source, const Drawing &drawing )
+IsfError TagsWriter::addAttributeTable( StreamData* streamData, const Drawing* drawing )
{
+ Q_UNUSED( drawing );
+
QByteArray blockData;
QByteArray tagContents;
AttributeSet defaultAttributeSet;
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Adding" << drawing.attributeSets_.count() << "attributes...";
quint8 counter = 0;
#endif
- foreach( const AttributeSet *info, drawing.attributeSets_ )
+ // Add default attributes if the drawing didn't contain any
+ if( streamData->attributeSets.isEmpty() )
+ {
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "- Adding a default attribute set...";
+#endif
+ AttributeSet set;
+ streamData->attributeSets.append( set );
+ }
+#ifdef ISFQT_DEBUG_VERBOSE
+ else
+ {
+ qDebug() << "- Adding" << streamData->attributeSets.count() << "attributes...";
+ }
+#endif
+
+ foreach( const AttributeSet set, streamData->attributeSets )
{
// Add the color to the attribute block
- if( info->color != defaultAttributeSet.color )
+ if( set.color != defaultAttributeSet.color )
{
blockData.append( encodeUInt( GUID_COLORREF ) );
// Prepare the color value, it needs to be stored in BGR format,
// in the 24 least significant bits
- quint64 value = ( info->color.blue () << 16 )
- | ( info->color.green() << 8 )
- | ( info->color.red () << 0 );
+ quint64 value = ( set.color.blue () << 16 )
+ | ( set.color.green() << 8 )
+ | ( set.color.red () << 0 );
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << " - Color:" << info->color.name();
+ qDebug() << " - Color:" << set.color.name();
#endif
blockData.append( encodeUInt( value ) );
// Add the transparency if needed
- if( info->color.alpha() < 255 )
+ if( set.color.alpha() < 255 )
{
blockData.append( encodeUInt( GUID_TRANSPARENCY ) );
- blockData.append( encodeUInt( info->color.alpha() ) );
+ blockData.append( encodeUInt( set.color.alpha() ) );
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << " - Alpha:" << info->color.alpha();
+ qDebug() << " - Alpha:" << set.color.alpha();
#endif
}
}
// Add the pen size
- if( info->penSize != defaultAttributeSet.penSize )
+ if( set.penSize != defaultAttributeSet.penSize )
{
blockData.append( encodeUInt( GUID_PEN_WIDTH ) );
- blockData.append( encodeUInt( info->penSize.width() * HiMetricToPixel ) );
+ blockData.append( encodeUInt( set.penSize.width() * HiMetricToPixel ) );
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << " - Pen width:" << ( info->penSize.width() * HiMetricToPixel );
+ qDebug() << " - Pen width:" << ( set.penSize.width() * HiMetricToPixel );
#endif
- if( info->penSize.width() != info->penSize.height() )
+ if( set.penSize.width() != set.penSize.height() )
{
blockData.append( encodeUInt( GUID_PEN_HEIGHT ) );
- blockData.append( encodeUInt( info->penSize.height() * HiMetricToPixel ) );
+ blockData.append( encodeUInt( set.penSize.height() * HiMetricToPixel ) );
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << " - Pen height:" << ( info->penSize.height() * HiMetricToPixel );
+ qDebug() << " - Pen height:" << ( set.penSize.height() * HiMetricToPixel );
#endif
}
}
// Add the other drawing flags
- if( info->flags != defaultAttributeSet.flags )
+ if( set.flags != defaultAttributeSet.flags )
{
- StrokeFlags flags = info->flags;
+ StrokeFlags flags = set.flags;
if( flags & IsRectangle )
{
blockData.append( encodeUInt( GUID_PEN_TIP ) );
@@ -185,9 +201,6 @@ IsfError TagsWriter::addAttributeTable( DataSource &source, const Drawing &drawi
}
*/
- // Add FitToCurve too for now, as a test
- flags |= FitToCurve;
-
// Copy the other flags as they are
blockData.append( encodeUInt( GUID_DRAWING_FLAGS ) );
blockData.append( encodeUInt( flags ) );
@@ -207,7 +220,7 @@ IsfError TagsWriter::addAttributeTable( DataSource &source, const Drawing &drawi
#endif
}
- if( drawing.attributeSets_.count() > 1 )
+ if( streamData->attributeSets.count() > 1 )
{
tagContents.prepend( encodeUInt( tagContents.size() ) );
tagContents.prepend( encodeUInt( TAG_DRAW_ATTRS_TABLE ) );
@@ -217,7 +230,7 @@ IsfError TagsWriter::addAttributeTable( DataSource &source, const Drawing &drawi
tagContents.prepend( encodeUInt( TAG_DRAW_ATTRS_BLOCK ) );
}
- source.append( tagContents );
+ streamData->dataSource->append( tagContents );
return ISF_ERROR_NONE;
}
@@ -234,27 +247,29 @@ IsfError TagsWriter::addAttributeTable( DataSource &source, const Drawing &drawi
* @param drawing Drawing from which to obtain the data to write
* @return IsfError
*/
-IsfError TagsWriter::addMetricsTable( DataSource &source, const Drawing &drawing )
+IsfError TagsWriter::addMetricsTable( StreamData* streamData, const Drawing* drawing )
{
+ Q_UNUSED( drawing );
+
QByteArray metricData;
QByteArray metricBlockData;
QByteArray tagData;
Metrics defaultMetrics;
- Metric *defaultMetric;
+ Metric* defaultMetric;
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Adding" << drawing.metrics_.count() << "metrics...";
+ qDebug() << "- Adding" << streamData->metrics.count() << "metrics...";
quint8 counter = 0;
#endif
- foreach( const Metrics *metrics, drawing.metrics_ )
+ foreach( const Metrics* metrics, streamData->metrics )
{
QMapIterator it( metrics->items );
while( it.hasNext() )
{
it.next();
- const quint64 &property = it.key ();
- const Metric &metric = it.value();
+ const quint64& property = it.key ();
+ const Metric& metric = it.value();
// Skip metrics which are set to the default
defaultMetric = &defaultMetrics.items[ property ];
@@ -293,17 +308,17 @@ IsfError TagsWriter::addMetricsTable( DataSource &source, const Drawing &drawing
#endif
}
- if( drawing.metrics_.count() > 1 )
+ if( streamData->metrics.count() > 1 )
{
tagData.prepend( encodeUInt( TAG_METRIC_TABLE ) );
}
- else if ( drawing.metrics_.count() == 1 )
+ else if ( streamData->metrics.count() == 1 )
{
tagData.prepend( encodeUInt( TAG_METRIC_BLOCK ) );
}
// else: don't do anything.
- source.append( tagData );
+ streamData->dataSource->append( tagData );
return ISF_ERROR_NONE;
}
@@ -320,8 +335,10 @@ IsfError TagsWriter::addMetricsTable( DataSource &source, const Drawing &drawing
* @param drawing Drawing from which to obtain the data to write
* @return IsfError
*/
-IsfError TagsWriter::addTransformationTable( DataSource &source, const Drawing &drawing )
+IsfError TagsWriter::addTransformationTable( StreamData* streamData, const Drawing* drawing )
{
+ Q_UNUSED( drawing );
+
QByteArray blockData;
QByteArray tagContents;
quint64 transformTag;
@@ -337,11 +354,11 @@ IsfError TagsWriter::addTransformationTable( DataSource &source, const Drawing &
*/
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Adding" << drawing.transforms_.count() << "transformations...";
+ qDebug() << "- Adding" << streamData->transforms.count() << "transformations...";
quint8 counter = 0;
#endif
- foreach( const QMatrix *trans, drawing.transforms_ )
+ foreach( const QMatrix* trans, streamData->transforms )
{
/*
* All transforms are written backwards because they're stored my most
@@ -443,24 +460,27 @@ IsfError TagsWriter::addTransformationTable( DataSource &source, const Drawing &
}
- if ( drawing.transforms_.size() == 0 )
+ if ( streamData->transforms.size() == 0 )
{
#ifdef ISFQT_DEBUG_VERBOSE
qDebug() << "- Added default transformation";
#endif
- // write the default transform.
- const QMatrix *transform = &drawing.defaultTransform_;
+ // Write the default transform
+ QMatrix defaultTransform;
+ defaultTransform.scale( 1.f, 1.f );
+ defaultTransform.translate( .0f, .0f );
+
tagContents.append( TAG_TRANSFORM_ISOTROPIC_SCALE );
- tagContents.append( encodeFloat( transform->m11() * HiMetricToPixel ) );
+ tagContents.append( encodeFloat( defaultTransform.m11() * HiMetricToPixel ) );
}
- else if ( drawing.transforms_.size() > 1 )
+ else if ( streamData->transforms.size() > 1 )
{
tagContents.prepend( encodeUInt( tagContents.size() ) );
tagContents.prepend( encodeUInt( TAG_TRANSFORM_TABLE ) );
}
- source.append( tagContents );
+ streamData->dataSource->append( tagContents );
return ISF_ERROR_NONE;
}
@@ -474,76 +494,75 @@ IsfError TagsWriter::addTransformationTable( DataSource &source, const Drawing &
* @param drawing Drawing from which to obtain the data to write
* @return IsfError
*/
-IsfError TagsWriter::addStrokes( DataSource &source, const Drawing &drawing )
+IsfError TagsWriter::addStrokes( StreamData* streamData, const Drawing* drawing )
{
QByteArray blockData;
QByteArray tagContents;
#ifdef ISFQT_DEBUG_VERBOSE
- qDebug() << "- Adding" << drawing.strokes_.count() << "strokes...";
+ qDebug() << "- Adding" << drawing->strokes_.count() << "strokes...";
quint8 counter = 0;
#endif
// Last set of attibutes applied to a stroke
- Metrics *currentMetrics = 0;
- AttributeSet *currentAttributeSet = 0;
- QMatrix *currentTransform = 0;
+ AttributeSet currentAttributeSet;
+ const Metrics* currentMetrics = 0;
+ const QMatrix* currentTransform = 0;
- foreach( const Stroke *stroke, drawing.strokes_ )
+ foreach( Stroke* stroke, drawing->strokes_ )
{
// There is more than one set of metrics, assign each stroke to its own
- if( drawing.metrics_.count() > 1 )
+ if( streamData->metrics.count() > 1 )
{
// Make sure that the first strokes use the first metrics list (write a MIDX only
// when needed)
if( currentMetrics == 0 )
{
- currentMetrics = drawing.metrics_.first();
+ currentMetrics = streamData->metrics.first();
}
// Only write a MIDX if this stroke needs different metrics than the last stroke
- if( currentMetrics != stroke->metrics && stroke->metrics != 0 )
+ Metrics* metrics = stroke->metrics();
+ if( metrics && currentMetrics != metrics )
{
- currentMetrics = stroke->metrics;
+ currentMetrics = metrics;
blockData.append( encodeUInt( TAG_MIDX ) );
- blockData.append( encodeUInt( drawing.metrics_.indexOf( stroke->metrics ) ) );
+ blockData.append( encodeUInt( streamData->metrics.indexOf( metrics ) ) );
}
}
// There is more than one set of attributes, assign each stroke to its own
- if( drawing.attributeSets_.count() > 1 )
+ if( streamData->attributeSets.count() > 1 )
{
- // Make sure that the first strokes use the first attribute set (write a DIDX only
- // when needed)
- if( currentAttributeSet == 0 )
- {
- currentAttributeSet = drawing.attributeSets_.first();
- }
-
// Only write a DIDX if this stroke needs a different attribute set than the last stroke
- if( currentAttributeSet != stroke->attributes && stroke->attributes != 0 )
+ if( currentAttributeSet.color != stroke->color()
+ || currentAttributeSet.flags != stroke->flags()
+ || currentAttributeSet.penSize != stroke->penSize() )
{
- currentAttributeSet = stroke->attributes;
+ currentAttributeSet.color = stroke->color();
+ currentAttributeSet.flags = stroke->flags();
+ currentAttributeSet.penSize = stroke->penSize();
+
blockData.append( encodeUInt( TAG_DIDX ) );
- blockData.append( encodeUInt( drawing.attributeSets_.indexOf( stroke->attributes ) ) );
+ blockData.append( encodeUInt( streamData->attributeSets.indexOf( currentAttributeSet ) ) );
}
}
// Make sure that the first strokes use the first transform (write a TIDX only
// when needed)
- if ( drawing.transforms_.count() > 0 )
+ if ( streamData->transforms.count() > 0 )
{
if( currentTransform == 0 )
{
- currentTransform = drawing.transforms_.first();
+ currentTransform = streamData->transforms.first();
}
// Only write a TIDX if this stroke needs a different transform than the last stroke
- if( currentTransform != stroke->transform && stroke->transform != 0 )
+ if( currentTransform != stroke->transform() && stroke->transform() != 0 )
{
- currentTransform = stroke->transform;
+ currentTransform = stroke->transform();
blockData.append( encodeUInt( TAG_TIDX ) );
- blockData.append( encodeUInt( drawing.transforms_.indexOf( stroke->transform ) ) );
+ blockData.append( encodeUInt( streamData->transforms.indexOf( stroke->transform() ) ) );
}
}
@@ -557,7 +576,7 @@ IsfError TagsWriter::addStrokes( DataSource &source, const Drawing &drawing )
// Write this stroke in the stream
QList xPoints, yPoints;
- foreach( const Point &point, stroke->points )
+ foreach( const Point& point, stroke->points() )
{
xPoints.append( point.position.x() );
yPoints.append( point.position.y() );
@@ -568,7 +587,7 @@ IsfError TagsWriter::addStrokes( DataSource &source, const Drawing &drawing )
// The stroke is made by tag, then payload size, then number of points, then
// the compressed points data
- blockData.prepend( encodeUInt( stroke->points.count() ) );
+ blockData.prepend( encodeUInt( stroke->points().count() ) );
blockData.prepend( encodeUInt( blockData.size() ) );
blockData.prepend( encodeUInt( TAG_STROKE ) );
@@ -580,7 +599,80 @@ IsfError TagsWriter::addStrokes( DataSource &source, const Drawing &drawing )
#endif
}
- source.append( tagContents );
+ streamData->dataSource->append( tagContents );
+
+ return ISF_ERROR_NONE;
+}
+
+
+
+/**
+ * Prepare the stream data for writing.
+ *
+ * @param source Data Source where to write bytes to
+ * @param drawing Drawing from which to obtain the data to write
+ * @return IsfError
+ */
+IsfError TagsWriter::prepare( StreamData* streamData, const Drawing* drawing )
+{
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "- Optimizing data...";
+#endif
+
+ streamData->attributeSets.clear();
+ streamData->metrics.clear();
+ streamData->transforms.clear();
+
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << " - " << drawing->strokes_.count() << "strokes to optimize";
+#endif
+
+ // Prepare the list of attributes
+ foreach( Stroke* stroke, drawing->strokes_ )
+ {
+ AttributeSet set;
+ set.color = stroke->color();
+ set.flags = stroke->flags();
+ set.penSize = stroke->penSize();
+
+ Metrics* metrics = stroke->metrics();
+ QMatrix* transform = stroke->transform();
+
+ if( ! streamData->attributeSets.contains( set ) )
+ {
+ streamData->attributeSets.append( set );
+ }
+ if( metrics && ! streamData->metrics.contains( metrics ) )
+ {
+ streamData->metrics.append( metrics );
+ }
+ if( transform && ! streamData->transforms.contains( transform ) )
+ {
+ streamData->transforms.append( transform );
+ }
+ }
+
+#ifdef ISFQT_DEBUG_VERBOSE
+ int count = 0;
+#endif
+
+ // Add default elements if the drawing didn't contain any
+ if( streamData->attributeSets.isEmpty() )
+ {
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << " - Added " << count << "default elements";
+#endif
+ AttributeSet set;
+ streamData->attributeSets.append( set );
+ }
+
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << " - Added " << count << "default elements";
+#endif
+
+#ifdef ISFQT_DEBUG_VERBOSE
+ qDebug() << "- Optimization phase complete";
+#endif
return ISF_ERROR_NONE;
}
diff --git a/contrib/isf-qt/src/tagswriter.h b/contrib/isf-qt/src/tagswriter.h
index 4de19d7..a106ae4 100644
--- a/contrib/isf-qt/src/tagswriter.h
+++ b/contrib/isf-qt/src/tagswriter.h
@@ -4,9 +4,7 @@
* *
* Copyright (C) 2009 by Adam Goossens *
* adam@kmess.org *
- ***************************************************************************/
-
-/***************************************************************************
+ * *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2.1 of the *
@@ -52,13 +50,13 @@ namespace Isf
class TagsWriter
{
public: // Static public methods
- static IsfError addPersistentFormat( DataSource &source, const Drawing &drawing );
- static IsfError addHiMetricSize( DataSource &source, const Drawing &drawing );
- static IsfError addAttributeTable( DataSource &source, const Drawing &drawing );
- static IsfError addMetricsTable( DataSource &source, const Drawing &drawing );
- static IsfError addTransformationTable( DataSource &source, const Drawing &drawing );
- static IsfError addStrokes( DataSource &source, const Drawing &drawing );
-
+ static IsfError addPersistentFormat( StreamData* streamData, const Drawing* drawing );
+ static IsfError addHiMetricSize( StreamData* streamData, const Drawing* drawing );
+ static IsfError addAttributeTable( StreamData* streamData, const Drawing* drawing );
+ static IsfError addMetricsTable( StreamData* streamData, const Drawing* drawing );
+ static IsfError addTransformationTable( StreamData* streamData, const Drawing* drawing );
+ static IsfError addStrokes( StreamData* streamData, const Drawing* drawing );
+ static IsfError prepare( StreamData* streamData, const Drawing* drawing );
};
}
diff --git a/contrib/isf-qt/tests/CMakeLists.txt b/contrib/isf-qt/tests/CMakeLists.txt
index 285d1af..79c9f98 100644
--- a/contrib/isf-qt/tests/CMakeLists.txt
+++ b/contrib/isf-qt/tests/CMakeLists.txt
@@ -7,7 +7,7 @@ MACRO( add_multiple_tests )
QT4_AUTOMOC( test_${test}.cpp )
ADD_EXECUTABLE( test_${test} test_${test}.cpp )
ADD_TEST( libisf-${test} test_${test} )
- TARGET_LINK_LIBRARIES( test_${test} ${QT_QTTEST_LIBRARY} ${QT_QTCORE_LIBRARY} isf-qt )
+ TARGET_LINK_LIBRARIES( test_${test} ${QT_QTTEST_LIBRARY} ${QT_QTGUI_LIBRARY} isf-qt )
ENDFOREACH( test )
ENDMACRO( add_multiple_tests )
@@ -15,6 +15,7 @@ ADD_MULTIPLE_TESTS(
isfdrawing
multibyte_coding
algorithms
+ png_fortification
)
diff --git a/contrib/isf-qt/tests/decode/main.cpp b/contrib/isf-qt/tests/decode/main.cpp
index 5068a53..72d48dc 100644
--- a/contrib/isf-qt/tests/decode/main.cpp
+++ b/contrib/isf-qt/tests/decode/main.cpp
@@ -130,7 +130,7 @@ class TestDecode : public QMainWindow, private Ui::TestDecode
// read some test raw ISF data from a file on the filesystem and
// return it as a QByteArray.
- QByteArray readTestIsfData( const QString &filename )
+ QByteArray readTestIsfData( const QString& filename )
{
QFile file( filename );
if ( !file.exists() )
@@ -154,7 +154,7 @@ class TestDecode : public QMainWindow, private Ui::TestDecode
// read some test raw ISF data from a file on the filesystem and
// return it as a QByteArray.
- void saveTestIsfData( const QByteArray &data )
+ void saveTestIsfData( const QByteArray& data )
{
static int number = 1;
QString fileName( "test" + QString::number( number ) + "." );
diff --git a/contrib/isf-qt/tests/inkedit/main.cpp b/contrib/isf-qt/tests/inkedit/main.cpp
index 30f7127..caa35b5 100644
--- a/contrib/isf-qt/tests/inkedit/main.cpp
+++ b/contrib/isf-qt/tests/inkedit/main.cpp
@@ -33,6 +33,7 @@
#include
#include
#include
+#include
#include
@@ -46,22 +47,24 @@ TestInkEdit::TestInkEdit()
connect( cmdSave_, SIGNAL(clicked()), this, SLOT( saveInk() ) );
connect( cmdLoad_, SIGNAL(clicked()), this, SLOT( loadInk() ) );
connect( cmdClear_, SIGNAL(clicked()), this, SLOT( clearInk() ) );
-
+
connect( cmdStrokeColor_, SIGNAL(clicked()), this, SLOT( chooseColor() ) );
connect( cmdCanvasColor_, SIGNAL(clicked()), this, SLOT( chooseColor() ) );
-
+
+ connect( editor_, SIGNAL(inkChanged()), this, SLOT( inkChanged() ) );
+
QButtonGroup *grp = new QButtonGroup( this );
grp->addButton( rbDrawing_ );
grp->addButton( rbEraser_ );
-
+
connect( grp, SIGNAL( buttonClicked( QAbstractButton * ) ), this, SLOT( penTypeChanged( QAbstractButton * ) ) );
-
+
connect( spinWidth_, SIGNAL( valueChanged( int ) ), editor_, SLOT( setPenSize( int ) ) );
editor_->setPenSize( spinWidth_->value() );
/*
setWindowTitle("Ink Edit Test");
-
+
editor_ = new Isf::InkEdit();
editor_->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum ) );
@@ -72,29 +75,29 @@ TestInkEdit::TestInkEdit()
cmdSave_ = new QPushButton();
cmdSave_->setText( "Save Ink" );
connect( cmdSave_, SIGNAL(clicked()), this, SLOT( saveInk() ) );
-
+
cmdLoad_ = new QPushButton();
cmdLoad_->setText( "Load Ink" );
connect( cmdLoad_, SIGNAL(clicked()), this, SLOT( loadInk() ) );
-
+
QPushButton *cmdClear_ = new QPushButton();
cmdClear_->setText( "Clear Ink" );
connect( cmdClear_, SIGNAL(clicked()), this, SLOT( clearInk() ) );
QVBoxLayout *layout = new QVBoxLayout();
QHBoxLayout *strokeBtnLayout = new QHBoxLayout();
-
+
layout->addWidget( sayLabel_ );
layout->addWidget( editor_ );
-
+
QHBoxLayout *ctlBtnLayout = new QHBoxLayout();
ctlBtnLayout->addWidget(cmdSave_);
ctlBtnLayout->addWidget(cmdLoad_);
ctlBtnLayout->addWidget(cmdClear_);
layout->addLayout( ctlBtnLayout );
-
+
setLayout( layout );
*/
}
@@ -135,7 +138,7 @@ void TestInkEdit::saveInk()
{
QString filter;
QString saveFile = QFileDialog::getSaveFileName( this, "Save Ink", QString(), "Raw ISF (*.isf);;base64-encoded ISF (*.isf64)", &filter );
- if ( saveFile != QString() )
+ if ( saveFile != QString() )
{
QFile file(saveFile);
file.open(QIODevice::WriteOnly);
@@ -148,18 +151,18 @@ void TestInkEdit::saveInk()
{
editor_->save( file );
}
-
+
file.close();
-
+
QMessageBox::information(0, "Save complete", "Saved to " + saveFile );
}
}
-void TestInkEdit::loadInk()
+void TestInkEdit::loadInk()
{
QString filter;
QString filename = QFileDialog::getOpenFileName( this, "Open Ink", QString(), "Raw ISF (*.isf);;base64-encoded ISF (*.isf64)", &filter );
- if ( ! filename.isEmpty() )
+ if ( ! filename.isEmpty() )
{
QFile file(filename);
file.open(QIODevice::ReadOnly);
@@ -170,7 +173,7 @@ void TestInkEdit::loadInk()
// got some ink.
Isf::Drawing *drawing = &Isf::Stream::reader(data);
-
+
editor_->setDrawing( drawing );
editor_->updateGeometry();
@@ -182,12 +185,20 @@ void TestInkEdit::clearInk()
editor_->clear();
}
+void TestInkEdit::inkChanged()
+{
+ emptyDrawingCheckbox_->setChecked( editor_->isEmpty() );
+
+ statusLabel_->setText( "Drawing changed!" );
+ QTimer::singleShot( 3000, statusLabel_, SLOT(clear()) );
+}
+
int main( int argc, char **argv )
{
QApplication app( argc, argv );
TestInkEdit edit;
edit.show();
-
+
return app.exec();
}
diff --git a/contrib/isf-qt/tests/inkedit/main.h b/contrib/isf-qt/tests/inkedit/main.h
index 5bc2602..c89464a 100644
--- a/contrib/isf-qt/tests/inkedit/main.h
+++ b/contrib/isf-qt/tests/inkedit/main.h
@@ -40,19 +40,20 @@
class TestInkEdit : public QWidget, public Ui::TestInkEdit
{
Q_OBJECT
-
+
public:
-
+
TestInkEdit();
~TestInkEdit();
-
+
public slots:
-
+
void saveInk();
void loadInk();
void clearInk();
void penTypeChanged( QAbstractButton *button );
void chooseColor();
+ void inkChanged();
};
diff --git a/contrib/isf-qt/tests/inkedit/testinkedit.ui b/contrib/isf-qt/tests/inkedit/testinkedit.ui
index 268e747..4e0d57b 100644
--- a/contrib/isf-qt/tests/inkedit/testinkedit.ui
+++ b/contrib/isf-qt/tests/inkedit/testinkedit.ui
@@ -130,6 +130,9 @@ p, li { white-space: pre-wrap; }
Drawing
+
+ true
+
-
@@ -142,6 +145,19 @@ p, li { white-space: pre-wrap; }
+ -
+
+
+ false
+
+
+ Is empty?
+
+
+ true
+
+
+
-
@@ -161,6 +177,9 @@ p, li { white-space: pre-wrap; }
-
+
-
+
+
-
diff --git a/contrib/isf-qt/tests/test_isfdrawing.cpp b/contrib/isf-qt/tests/test_isfdrawing.cpp
index 0ab77e1..a3f7274 100644
--- a/contrib/isf-qt/tests/test_isfdrawing.cpp
+++ b/contrib/isf-qt/tests/test_isfdrawing.cpp
@@ -116,7 +116,7 @@ void TestIsfDrawing::createDrawing()
// read some test raw ISF data from a file on the filesystem and
// return it as a QByteArray.
-void TestIsfDrawing::readTestIsfData( const QString &filename, QByteArray &byteArray )
+void TestIsfDrawing::readTestIsfData( const QString& filename, QByteArray& byteArray )
{
QFile file( filename );
QVERIFY( file.exists() );
diff --git a/contrib/isf-qt/tests/test_isfdrawing.h b/contrib/isf-qt/tests/test_isfdrawing.h
index 3d6c2a5..c5fa64f 100644
--- a/contrib/isf-qt/tests/test_isfdrawing.h
+++ b/contrib/isf-qt/tests/test_isfdrawing.h
@@ -23,7 +23,7 @@ class TestIsfDrawing : public QObject
Q_OBJECT
public:
TestIsfDrawing();
- void readTestIsfData( const QString &filename, QByteArray &byteArray );
+ void readTestIsfData( const QString& filename, QByteArray& byteArray );
private slots:
void emptyConstructor_NullDrawing();
diff --git a/contrib/isf-qt/tests/test_multibyte_coding.cpp b/contrib/isf-qt/tests/test_multibyte_coding.cpp
index 0ae5a06..3d43c4d 100644
--- a/contrib/isf-qt/tests/test_multibyte_coding.cpp
+++ b/contrib/isf-qt/tests/test_multibyte_coding.cpp
@@ -138,7 +138,7 @@ void TestMultibyteCoding::unsignedDecode()
data.append( Q_UINT64_C(0x7D) ); // decimal 125
data.reset(); // To re-read the appended bytes
- result = Isf::Compress::decodeUInt( data );
+ result = Isf::Compress::decodeUInt( &data );
QVERIFY(result == Q_UINT64_C(0x7D) );
@@ -150,7 +150,7 @@ void TestMultibyteCoding::unsignedDecode()
data.append( Q_UINT64_C(0x01) );
data.reset(); // To re-read the appended bytes
- result = Isf::Compress::decodeUInt( data );
+ result = Isf::Compress::decodeUInt( &data );
QVERIFY( result == Q_UINT64_C(0x80) );
data.clear();
@@ -162,7 +162,7 @@ void TestMultibyteCoding::unsignedDecode()
data.append( Q_UINT64_C(0x03) );
data.reset(); // To re-read the appended bytes
- result = Isf::Compress::decodeUInt( data );
+ result = Isf::Compress::decodeUInt( &data );
QVERIFY( result == Q_UINT64_C(0xFFFF) );
}
@@ -189,7 +189,7 @@ void TestMultibyteCoding::signedDecode()
data.append( (char)((0x0A << 1) | 0x01) );
data.reset(); // To re-read the appended byte
- result = Isf::Compress::decodeInt( data );
+ result = Isf::Compress::decodeInt( &data );
QVERIFY( result == Q_INT64_C(-10) );
data.clear();
@@ -200,7 +200,7 @@ void TestMultibyteCoding::signedDecode()
data.append( Q_INT64_C(0x01) );
data.reset(); // To re-read the appended byte
- result = Isf::Compress::decodeInt( data );
+ result = Isf::Compress::decodeInt( &data );
QVERIFY( result == Q_INT64_C(-64) );
data.clear();
@@ -211,7 +211,7 @@ void TestMultibyteCoding::signedDecode()
data.append( Q_INT64_C(0x01) );
data.reset(); // To re-read the appended byte
- result = Isf::Compress::decodeInt( data );
+ result = Isf::Compress::decodeInt( &data );
QVERIFY( result == Q_INT64_C(100) );
data.clear();
@@ -222,7 +222,7 @@ void TestMultibyteCoding::signedDecode()
data.append( Q_INT64_C(0x07) );
data.reset(); // To re-read the appended byte
- result = Isf::Compress::decodeInt( data );
+ result = Isf::Compress::decodeInt( &data );
QVERIFY( result == Q_INT64_C(-500) );
}
@@ -254,7 +254,7 @@ void TestMultibyteCoding::floatDecode()
data.append( Q_INT64_C(0xC1) );
data.reset(); // To re-read the appended bytes
- result = Isf::Compress::decodeFloat( data );
+ result = Isf::Compress::decodeFloat( &data );
QVERIFY( result == -12.345678901f );
}
diff --git a/contrib/isf-qt/tests/test_png_fortification.cpp b/contrib/isf-qt/tests/test_png_fortification.cpp
new file mode 100644
index 0000000..6d0e6fc
--- /dev/null
+++ b/contrib/isf-qt/tests/test_png_fortification.cpp
@@ -0,0 +1,90 @@
+/*
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.*/
+
+#include "test_png_fortification.h"
+
+#include
+
+#include "isfqt-internal.h"
+
+#include
+#include
+
+
+using namespace Isf;
+using namespace Isf::Compress;
+
+
+
+
+void TestPngFortification::testEncode()
+{
+ QPixmap pix( QSize( 135, 114 ) );
+ pix.fill( Qt::transparent );
+ qDebug() << "pix size:" << pix.size();
+
+ qDebug() << "#################### ENCODER TEST ####################";
+
+ QFile file( "../../tests/test2.isf" );
+ QVERIFY( file.exists() );
+
+ // read file into qbytearray.
+ QVERIFY( file.open( QIODevice::ReadOnly ) );
+
+ Drawing drawing = Stream::reader( file.readAll(), false );
+
+ QVERIFY( ! drawing.isNull() );
+
+ QByteArray byteArray( Stream::writerPng( drawing, false ) );
+
+ QVERIFY( ! byteArray.isEmpty() );
+
+ QImage img = QImage::fromData( byteArray, "PNG" );
+
+ QVERIFY( ! img.isNull() );
+ qDebug() << "Image size:" << img.size();
+
+ QVERIFY( tempFile.open() );
+
+ tempFile.write( byteArray );
+ tempFile.close();
+}
+
+
+void TestPngFortification::testDecode()
+{
+ qDebug() << "#################### DECODER TEST ####################";
+
+ QVERIFY( tempFile.exists() );
+
+ // read file and convert to qbytearray.
+ QVERIFY( tempFile.open() );
+
+ QByteArray byteArray( tempFile.readAll() );
+
+ Drawing drawing = Stream::readerPng( byteArray, false );
+
+ QVERIFY( ! drawing.isNull() );
+
+ qDebug() << "Drawing size:" << drawing.size();
+}
+
+
+
+QTEST_MAIN(TestPngFortification)
+
+
+
+#include "test_png_fortification.moc"
diff --git a/contrib/isf-qt/tests/test_png_fortification.h b/contrib/isf-qt/tests/test_png_fortification.h
new file mode 100644
index 0000000..7befdca
--- /dev/null
+++ b/contrib/isf-qt/tests/test_png_fortification.h
@@ -0,0 +1,36 @@
+/*
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library 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. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.*/
+
+#ifndef TESTPNG_FORTIFICATION_H
+#define TESTPNG_FORTIFICATION_H
+
+#include
+#include
+
+
+
+class TestPngFortification : public QObject
+{
+Q_OBJECT
+private slots:
+ void testEncode();
+ void testDecode();
+
+private:
+
+ QTemporaryFile tempFile;
+};
+
+#endif // TESTPNG_FORTIFICATION_H
diff --git a/data/kmess.desktop b/data/kmess.desktop
index ee7cde3..36caed2 100644
--- a/data/kmess.desktop
+++ b/data/kmess.desktop
@@ -1,5 +1,4 @@
[Desktop Entry]
-Encoding=UTF-8
Name=KMess
Exec=kmess -caption "%c" %i
Icon=kmess
diff --git a/data/kmess.notifyrc b/data/kmess.notifyrc
index 68d06ec..9ac2573 100644
--- a/data/kmess.notifyrc
+++ b/data/kmess.notifyrc
@@ -2,6 +2,10 @@
Name=KMess
IconName=kmess
Comment=KMess Messenger Client
+# Please note that all the events listed in this file are implemented
+# differently; apart from knotify, in the MacNotification class in
+# KMess. It can be found in src/notification. If you modify this file,
+# please keep that one up to date too.
[Event/contact online]
Name=Contact Online
diff --git a/data/sounds/kmess_chat.mp3 b/data/sounds/kmess_chat.mp3
new file mode 100644
index 0000000..e48b0a4
Binary files /dev/null and b/data/sounds/kmess_chat.mp3 differ
diff --git a/data/sounds/kmess_logoff.mp3 b/data/sounds/kmess_logoff.mp3
new file mode 100644
index 0000000..07319ce
Binary files /dev/null and b/data/sounds/kmess_logoff.mp3 differ
diff --git a/data/sounds/kmess_logon.mp3 b/data/sounds/kmess_logon.mp3
new file mode 100644
index 0000000..70ff82d
Binary files /dev/null and b/data/sounds/kmess_logon.mp3 differ
diff --git a/data/sounds/kmess_msg.mp3 b/data/sounds/kmess_msg.mp3
new file mode 100644
index 0000000..b3a6e7b
Binary files /dev/null and b/data/sounds/kmess_msg.mp3 differ
diff --git a/kmess.kdev4 b/kmess.kdev4
index 98ddfcb..ee5fcfe 100644
--- a/kmess.kdev4
+++ b/kmess.kdev4
@@ -1,3 +1,3 @@
[Project]
-Name=KMess
+Name=KMess (2.0.x branch)
Manager=KDevCMakeManager
diff --git a/kmess.supp b/kmess.supp
deleted file mode 100644
index 41d289e..0000000
--- a/kmess.supp
+++ /dev/null
@@ -1,606 +0,0 @@
-{
-
- Memcheck:Param
- write(buf)
- fun:__write_nocancel
- obj:/usr/lib/libICE.so.6.3.0
- fun:_IceWrite
- fun:IceFlush
- fun:_ZL14sm_setPropertyPKcS0_iP11SmPropValue
- fun:_ZL14sm_setPropertyRK7QStringS1_
- fun:_ZL22sm_performSaveYourselfP22QSessionManagerPrivate
- fun:_ZL23sm_saveYourselfCallbackP8_SmcConnPviiii
- fun:_SmcProcessMessage
- fun:IceProcessMessages
- fun:_ZN17QSmSocketReceiver11qt_metacallEN11QMetaObject4CallEiPPv
- fun:_ZN11QMetaObject8activateEP7QObjectiiPPv
-}
-{
-
- Memcheck:Cond
- fun:BN_mod_inverse
- fun:BN_MONT_CTX_set
- fun:BN_MONT_CTX_set_locked
- obj:/lib/libcrypto.so.0.9.8
- fun:RSA_verify
- fun:EVP_VerifyFinal
- fun:ASN1_item_verify
- obj:/lib/libcrypto.so.0.9.8
- fun:X509_verify_cert
- fun:ssl_verify_cert_chain
- fun:ssl3_get_server_certificate
- fun:ssl3_connect
-}
-{
-
- Memcheck:Cond
- fun:BN_div
- fun:BN_nnmod
- fun:BN_mod_inverse
- fun:BN_MONT_CTX_set
- fun:BN_MONT_CTX_set_locked
- obj:/lib/libcrypto.so.0.9.8
- fun:RSA_verify
- fun:EVP_VerifyFinal
- fun:ASN1_item_verify
- obj:/lib/libcrypto.so.0.9.8
- fun:X509_verify_cert
- fun:ssl_verify_cert_chain
-}
-{
-
- Memcheck:Cond
- fun:BN_div
- fun:BN_nnmod
- fun:BN_mod_inverse
- fun:BN_MONT_CTX_set
- fun:BN_MONT_CTX_set_locked
- obj:/lib/libcrypto.so.0.9.8
- fun:RSA_verify
- fun:EVP_VerifyFinal
- fun:ASN1_item_verify
- obj:/lib/libcrypto.so.0.9.8
- fun:X509_verify_cert
- fun:ssl_verify_cert_chain
-}
-{
-
- Memcheck:Cond
- fun:BN_mod_inverse
- fun:BN_MONT_CTX_set
- fun:BN_MONT_CTX_set_locked
- obj:/lib/libcrypto.so.0.9.8
- fun:ssl3_send_client_key_exchange
- fun:ssl3_connect
- fun:_ZN24QSslSocketBackendPrivate14testConnectionEv
- fun:_ZN24QSslSocketBackendPrivate8transmitEv
- fun:_ZN10QSslSocket11qt_metacallEN11QMetaObject4CallEiPPv
- fun:_ZN11QMetaObject8activateEP7QObjectiiPPv
- fun:_ZN22QAbstractSocketPrivate19canReadNotificationEv
- fun:_ZN13QReadNotifier5eventEP6QEvent
-}
-{
-
- Memcheck:Cond
- fun:BN_div
- fun:BN_MONT_CTX_set
- fun:BN_MONT_CTX_set_locked
- obj:/lib/libcrypto.so.0.9.8
- fun:ssl3_send_client_key_exchange
- fun:ssl3_connect
- fun:_ZN24QSslSocketBackendPrivate14testConnectionEv
- fun:_ZN24QSslSocketBackendPrivate8transmitEv
- fun:_ZN10QSslSocket11qt_metacallEN11QMetaObject4CallEiPPv
- fun:_ZN11QMetaObject8activateEP7QObjectiiPPv
- fun:_ZN22QAbstractSocketPrivate19canReadNotificationEv
- fun:_ZN13QReadNotifier5eventEP6QEvent
-}
-{
-
- Memcheck:Cond
- fun:deflate
- obj:/usr/lib/libpng12.so.0.27.0
- obj:/usr/lib/libpng12.so.0.27.0
- obj:/usr/lib/libpng12.so.0.27.0
- fun:png_write_row
- fun:png_write_image
- fun:_ZN15QPNGImageWriter10writeImageERK6QImageiRK7QStringii
- fun:_ZN11QPngHandler5writeERK6QImage
- fun:_ZN12QImageWriter5writeERK6QImage
- fun:_ZlsR11QDataStreamRK6QImage
- fun:_ZlsR11QDataStreamRK7QPixmap
- fun:_ZN20KNotificationManager6notifyEP13KNotificationRK7QPixmapRK11QStringListRK5QListI5QPairI7QStringSA_EERKSA_
-}
-{
-
- Memcheck:Value8
- fun:crc32
- obj:/usr/lib/libpng12.so.0.27.0
- fun:png_write_chunk_data
- fun:png_write_chunk
- obj:/usr/lib/libpng12.so.0.27.0
- obj:/usr/lib/libpng12.so.0.27.0
- obj:/usr/lib/libpng12.so.0.27.0
- obj:/usr/lib/libpng12.so.0.27.0
- fun:png_write_row
- fun:png_write_image
- fun:_ZN15QPNGImageWriter10writeImageERK6QImageiRK7QStringii
- fun:_ZN11QPngHandler5writeERK6QImage
-}
-{
-
- Memcheck:Value8
- fun:crc32
- obj:/usr/lib/libpng12.so.0.27.0
- fun:png_write_chunk_data
- fun:png_write_chunk
- obj:/usr/lib/libpng12.so.0.27.0
- obj:/usr/lib/libpng12.so.0.27.0
- obj:/usr/lib/libpng12.so.0.27.0
- obj:/usr/lib/libpng12.so.0.27.0
- fun:png_write_row
- fun:png_write_image
- fun:_ZN15QPNGImageWriter10writeImageERK6QImageiRK7QStringii
- fun:_ZN11QPngHandler5writeERK6QImage
-}
-{
-
- Memcheck:Param
- writev(vector[...])
- fun:writev
- obj:/lib/libdbus-1.so.3.4.0
- obj:/lib/libdbus-1.so.3.4.0
- obj:/lib/libdbus-1.so.3.4.0
- obj:/lib/libdbus-1.so.3.4.0
- obj:/lib/libdbus-1.so.3.4.0
- obj:/lib/libdbus-1.so.3.4.0
- obj:/lib/libdbus-1.so.3.4.0
- fun:dbus_connection_send_with_reply
- fun:_ZN22QDBusConnectionPrivate18sendWithReplyAsyncERK12QDBusMessagei
- fun:_ZN22QDBusConnectionPrivate18sendWithReplyAsyncERK12QDBusMessageP7QObjectPKcS6_i
- fun:_ZNK15QDBusConnection16callWithCallbackERK12QDBusMessageP7QObjectPKcS6_i
-}
-{
-
- Memcheck:Param
- write(buf)
- obj:/lib/libc-2.9.so
- obj:/usr/lib/libICE.so.6.3.0
- fun:_IceWrite
- fun:IceFlush
- fun:SmcCloseConnection
- fun:_ZN15QSessionManagerD0Ev
- fun:_ZN12QApplicationD2Ev
- fun:_ZN16KMessApplicationD1Ev
- fun:main
-}
-{
-
- Memcheck:Leak
- fun:malloc
- fun:_ZN7QString7reallocEi
- fun:_ZN7QString6resizeEi
- fun:_ZN7QString8fromUtf8EPKci
- fun:_ZL26fromPercentEncodingMutableP10QByteArray
- fun:_ZNK11QUrlPrivate5parseENS_12ParseOptionsE
- fun:_ZNK4QUrl7isValidEv
- fun:_ZN4KUrl14_setEncodedUrlERK10QByteArray
- fun:_ZN4KUrlC1ERK7QString
- fun:_ZN5khtml6Loader20servePendingRequestsEv
- fun:_ZN5khtml19CachedCSSStyleSheetC1EPNS_9DocLoaderERKN3DOM9DOMStringEN3KIO12CacheControlEPKc
- fun:_ZN5khtml5Cache13requestObjectINS_19CachedCSSStyleSheetELNS_12CachedObject4TypeE1EEEPT_PNS_9DocLoaderERK4KUrlPKc
-}
-{
-
- Memcheck:Leak
- fun:malloc
- obj:/usr/lib/libxml2.so.2.6.32
- fun:xmlSAX2StartElementNs
- obj:/usr/lib/libxml2.so.2.6.32
- fun:xmlParseElement
- fun:xmlParseContent
- fun:xmlParseElement
- fun:xmlParseDocument
- fun:xmlSAXParseMemoryWithData
- fun:_ZN17XslTransformation13setStylesheetERK7QString
- fun:_ZN16ChatMessageStyle8setStyleERK7QString
- fun:_ZN15ChatMessageView15updateChatStyleEv
-}
-{
-
- Memcheck:Leak
- fun:_Znwm
- fun:_ZN19QDockAreaLayoutInfo12restoreStateER11QDataStreamR5QListIP11QDockWidgetEb
- fun:_ZN15QDockAreaLayout12restoreStateER11QDataStreamRK5QListIP11QDockWidgetEb
- fun:_ZN22QMainWindowLayoutState11checkFormatER11QDataStreamb
- fun:_ZN22QMainWindowLayoutState12restoreStateER11QDataStreamRKS_
- fun:_ZN17QMainWindowLayout12restoreStateER11QDataStream
- fun:_ZN11QMainWindow12restoreStateERK10QByteArrayi
- fun:_ZN11KMainWindow23applyMainWindowSettingsERK12KConfigGroupb
- fun:_ZN13KXmlGuiWindow23applyMainWindowSettingsERK12KConfigGroupb
- fun:_ZN10ChatWindow10initializeEv
- fun:_ZN10ChatMaster16createChatWindowEP4Chat
- fun:_ZN10ChatMaster10createChatEP24MsnSwitchboardConnectionb
-}
-{
-
- Memcheck:Leak
- fun:malloc
- fun:_ZN8QMapData11node_createEPPNS_4NodeEi
- fun:_ZN4QMapI10QByteArray11QStringListE11node_createEP8QMapDataPPNS3_4NodeERKS0_RKS1_
- fun:_ZNK13KStandardDirs12resourceDirsEPKc
- fun:_ZN10KIconThemeC1ERK7QStringS2_
- fun:_ZN18KIconLoaderPrivate14initIconThemesEv
- fun:_ZN11KIconLoader9addAppDirERK7QString
- fun:_ZN16KMessApplication15initializePathsEv
- fun:_ZN16KMessApplicationC1Ev
- fun:main
-}
-{
-
- Memcheck:Leak
- fun:malloc
- obj:/usr/lib/libxslt.so.1.1.24
- fun:xsltParseStylesheetProcess
- fun:xsltParseStylesheetImportedDoc
- fun:xsltParseStylesheetDoc
- fun:_ZN17XslTransformation13setStylesheetERK7QString
- fun:_ZN16ChatMessageStyle8setStyleERK7QString
- fun:_ZN15ChatMessageView15updateChatStyleEv
- fun:_ZN8ChatView10initializeEv
- fun:_ZN4Chat10initializeEP24MsnSwitchboardConnection
- fun:_ZN10ChatMaster10createChatEP24MsnSwitchboardConnectionb
- fun:_ZN10ChatMaster11qt_metacallEN11QMetaObject4CallEiPPv
-}
-{
-
- Memcheck:Leak
- fun:malloc
- obj:/usr/lib/libfontconfig.so.1.3.0
- obj:/usr/lib/libfontconfig.so.1.3.0
- obj:/usr/lib/libfontconfig.so.1.3.0
- obj:/usr/lib/libfontconfig.so.1.3.0
- obj:/usr/lib/libexpat.so.1.5.2
- obj:/usr/lib/libexpat.so.1.5.2
- obj:/usr/lib/libexpat.so.1.5.2
- obj:/usr/lib/libexpat.so.1.5.2
- fun:XML_ParseBuffer
- fun:FcConfigParseAndLoad
- fun:FcConfigParseAndLoad
-}
-{
-
- Memcheck:Leak
- fun:malloc
- fun:nss_parse_service_list
- fun:__nss_database_lookup
- obj:*
- obj:*
- fun:getpwuid_r@@GLIBC_2.2.5
- fun:_ZL22sm_performSaveYourselfP22QSessionManagerPrivate
- fun:_ZL23sm_saveYourselfCallbackP8_SmcConnPviiii
- fun:_SmcProcessMessage
- fun:IceProcessMessages
- fun:_ZN17QSmSocketReceiver11qt_metacallEN11QMetaObject4CallEiPPv
- fun:_ZN11QMetaObject8activateEP7QObjectiiPPv
-}
-{
-
- Memcheck:Leak
- fun:malloc
- fun:_XimOpenIM
- fun:_XimRegisterIMInstantiateCallback
- fun:XRegisterIMInstantiateCallback
- fun:_ZN16QXIMInputContextC1Ev
- fun:_ZN20QInputContextFactory6createERK7QStringP7QObject
- fun:_ZNK12QApplication12inputContextEv
- fun:_ZN19QApplicationPrivate14setFocusWidgetEP7QWidgetN2Qt11FocusReasonE
- fun:_ZN7QWidget8setFocusEN2Qt11FocusReasonE
- fun:_ZN12QApplication15setActiveWindowEP7QWidget
- fun:_ZN12QApplication15x11ProcessEventEP7_XEvent
- fun:_ZL22x11EventSourceDispatchP8_GSourcePFiPvES1_
-}
-{
-
- Memcheck:Leak
- fun:_Znwm
- fun:_ZN5khtml11RenderStyleC1Eb
- fun:_ZN5khtml11RenderStyleC1Ev
- fun:_ZN5khtml16CSSStyleSelector21setupDefaultRootStyleEPN3DOM12DocumentImplE
- fun:_ZN5khtml16CSSStyleSelectorC1EPN3DOM12DocumentImplE7QStringPNS1_18StyleSheetListImplERK4KUrlb
- fun:_ZN3DOM12DocumentImpl6attachEv
- fun:_ZN9KHTMLPart5beginERK4KUrlii
- fun:_ZN15ChatMessageView7setHtmlERK7QString
- fun:_ZN15ChatMessageView9clearViewEb
- fun:_ZN15ChatMessageViewC1EP7QWidget
- fun:_ZN8ChatViewC2EP7QWidget
- fun:_ZN4ChatC1EP7QWidget
-}
-{
-
- Memcheck:Leak
- fun:malloc
- fun:CRYPTO_malloc
- fun:c2i_ASN1_BIT_STRING
- fun:asn1_ex_c2i
- obj:/lib/libcrypto.so.0.9.8
- fun:ASN1_item_ex_d2i
- obj:/lib/libcrypto.so.0.9.8
- obj:/lib/libcrypto.so.0.9.8
- fun:ASN1_item_ex_d2i
- obj:/lib/libcrypto.so.0.9.8
- obj:/lib/libcrypto.so.0.9.8
- fun:ASN1_item_ex_d2i
-}
-{
-
- Memcheck:Leak
- fun:realloc
- obj:/usr/lib/libfontconfig.so.1.3.0
- obj:/usr/lib/libfontconfig.so.1.3.0
- fun:FcDefaultSubstitute
- fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei
- fun:_ZNK12QFontPrivate15engineForScriptEi
- fun:_ZNK12QFontMetrics6heightEv
- fun:_ZN10QStatusBar8reformatEv
- fun:_ZN10QStatusBar18setSizeGripEnabledEb
- fun:_ZN10QStatusBarC2EP7QWidget
- fun:_ZN10KStatusBarC1EP7QWidget
- fun:_ZN11KMainWindow9statusBarEv
-}
-{
-
- Memcheck:Leak
- fun:malloc
- fun:_ZN8QMapData11node_createEPPNS_4NodeEi
- fun:_ZN4QMapI9KEntryKey6KEntryE6insertERKS0_RKS1_
- fun:_ZN9KEntryMap8setEntryERK10QByteArrayS2_S2_6QFlagsINS_11EntryOptionEE
- fun:_ZN17KConfigIniBackend11parseConfigERK10QByteArrayR9KEntryMap6QFlagsIN14KConfigBackend11ParseOptionEEb
- fun:_ZN17KConfigIniBackend11parseConfigERK10QByteArrayR9KEntryMap6QFlagsIN14KConfigBackend11ParseOptionEE
- fun:_ZN14KConfigPrivate16parseConfigFilesEv
- fun:_ZN7KConfig20reparseConfigurationEv
- fun:_ZN7KConfigC1ERK7QString6QFlagsINS_8OpenFlagEEPKc
- fun:_ZN11KMessConfig15getGlobalConfigERK7QString
- fun:_ZN13NetworkWindowD0Ev
- fun:_ZN13NetworkWindow7destroyEv
-}
-{
-
- Memcheck:Leak
- fun:malloc
- fun:CRYPTO_malloc
- fun:SSL_new
- fun:_ZN24QSslSocketBackendPrivate14initSslContextEv
- fun:_ZN24QSslSocketBackendPrivate21startClientEncryptionEv
- fun:_ZN17QSslSocketPrivate16_q_connectedSlotEv
- fun:_ZN10QSslSocket11qt_metacallEN11QMetaObject4CallEiPPv
- fun:_ZN11QMetaObject8activateEP7QObjectiiPPv
- fun:_ZN22QAbstractSocketPrivate25fetchConnectionParametersEv
- fun:_ZN22QAbstractSocketPrivate17_q_testConnectionEv
- fun:_ZN14QWriteNotifier5eventEP6QEvent
- fun:_ZN19QApplicationPrivate13notify_helperEP7QObjectP6QEvent
-}
-{
-
- Memcheck:Cond
- fun:BN_div
- fun:BN_MONT_CTX_set
- fun:BN_MONT_CTX_set_locked
- obj:/lib/libcrypto.so.0.9.8
- fun:RSA_verify
- fun:EVP_VerifyFinal
- fun:ASN1_item_verify
- obj:/lib/libcrypto.so.0.9.8
- fun:X509_verify_cert
- fun:ssl_verify_cert_chain
- fun:ssl3_get_server_certificate
- fun:ssl3_connect
-}
-{
-
- Memcheck:Leak
- fun:_Znwm
- fun:_ZNK14QX11PixmapData11paintEngineEv
- fun:_ZN8QPainter5beginEP12QPaintDevice
- fun:_ZN11KIconEngine6pixmapERK5QSizeN5QIcon4ModeENS3_5StateE
- fun:_ZNK5QIcon6pixmapERK5QSizeNS_4ModeENS_5StateE
- fun:_ZN14QWidgetPrivate17setWindowIcon_sysEb
- fun:_ZN7QWidget6createEmbb
- fun:_ZN7QWidget10setVisibleEb
- fun:_ZN7QWidget4showEv
- fun:_ZN11LikeBackBar8autoMoveEv
- fun:_ZN11LikeBackBar11qt_metacallEN11QMetaObject4CallEiPPv
- fun:_ZN11QMetaObject8activateEP7QObjectiiPPv
-}
-{
-
- Memcheck:Leak
- fun:malloc
- fun:CRYPTO_malloc
- fun:ssl3_setup_buffers
- fun:ssl3_connect
- fun:_ZN24QSslSocketBackendPrivate14testConnectionEv
- fun:_ZN24QSslSocketBackendPrivate21startClientEncryptionEv
- fun:_ZN17QSslSocketPrivate16_q_connectedSlotEv
- fun:_ZN10QSslSocket11qt_metacallEN11QMetaObject4CallEiPPv
- fun:_ZN11QMetaObject8activateEP7QObjectiiPPv
- fun:_ZN22QAbstractSocketPrivate25fetchConnectionParametersEv
- fun:_ZN22QAbstractSocketPrivate17_q_testConnectionEv
- fun:_ZN14QWriteNotifier5eventEP6QEvent
-}
-{
-
- Memcheck:Leak
- fun:malloc
- fun:CRYPTO_malloc
- fun:ASN1_OBJECT_new
- fun:c2i_ASN1_OBJECT
- fun:asn1_ex_c2i
- obj:/lib/libcrypto.so.0.9.8
- fun:ASN1_item_ex_d2i
- obj:/lib/libcrypto.so.0.9.8
- obj:/lib/libcrypto.so.0.9.8
- fun:ASN1_item_ex_d2i
- obj:/lib/libcrypto.so.0.9.8
- obj:/lib/libcrypto.so.0.9.8
-}
-{
-
- Memcheck:Cond
- fun:_ZL13PolygonRegionPK6QPointii
- fun:_ZN7QRegionC1ERK8QPolygonN2Qt8FillRuleE
- fun:_ZN15QX11PaintEngine11updateStateERK17QPaintEngineState
- fun:_ZN15QPainterPrivate15updateStateImplEP13QPainterState
- fun:_ZN15QPainterPrivate11updateStateEP13QPainterState
- fun:_ZN8QPainter13setClipRegionERK7QRegionN2Qt13ClipOperationE
- fun:_ZNK14QWidgetPrivate15paintBackgroundEP8QPainterRK7QRegionRK6QPointi
- fun:_ZN14QWidgetPrivate10drawWidgetEP12QPaintDeviceRK7QRegionRK6QPointiP8QPainterP19QWidgetBackingStore
- fun:_ZN19QWidgetBackingStore4syncEv
- fun:_ZN14QWidgetPrivate16syncBackingStoreEv
- fun:_ZN7QWidget5eventEP6QEvent
- fun:_ZN11QMainWindow5eventEP6QEvent
-}
-{
-
- Memcheck:Cond
- fun:_ZL13PolygonRegionPK6QPointii
- fun:_ZN7QRegionC1ERK8QPolygonN2Qt8FillRuleE
- fun:_ZN15QX11PaintEngine11updateStateERK17QPaintEngineState
- fun:_ZN15QPainterPrivate15updateStateImplEP13QPainterState
- fun:_ZN15QPainterPrivate11updateStateEP13QPainterState
- fun:_ZN8QPainter13setClipRegionERK7QRegionN2Qt13ClipOperationE
- fun:_ZNK14QWidgetPrivate15paintBackgroundEP8QPainterRK7QRegionRK6QPointi
- fun:_ZN14QWidgetPrivate10drawWidgetEP12QPaintDeviceRK7QRegionRK6QPointiP8QPainterP19QWidgetBackingStore
- fun:_ZN19QWidgetBackingStore4syncEv
- fun:_ZN14QWidgetPrivate16syncBackingStoreEv
- fun:_ZN7QWidget5eventEP6QEvent
- fun:_ZN11QMainWindow5eventEP6QEvent
-}
-{
-
- Memcheck:Leak
- fun:malloc
- fun:_ZN7QString7reallocEi
- fun:_ZN7QString6resizeEi
- fun:_ZN7QString8fromUtf8EPKci
- fun:_ZL26fromPercentEncodingMutableP10QByteArray
- fun:_ZNK11QUrlPrivate5parseENS_12ParseOptionsE
- fun:_ZNK4QUrl7isValidEv
- fun:_ZN4KUrl14_setEncodedUrlERK10QByteArray
- fun:_ZN4KUrlC1ERK7QString
- obj:/usr/lib/libkhtml.so.5.2.0
- obj:/usr/lib/libkhtml.so.5.2.0
- fun:_ZN11QMetaObject8activateEP7QObjectiiPPv
-}
-{
-
- Memcheck:Leak
- fun:realloc
- obj:/usr/lib/libfontconfig.so.1.3.0
- obj:/usr/lib/libfontconfig.so.1.3.0
- fun:FcPatternDuplicate
- fun:_ZL14tryPatternLoadP10_FcPatterniRK8QFontDefiPS0_
- fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei
- fun:_ZNK12QFontPrivate15engineForScriptEi
- fun:_ZNK12QFontMetrics6ascentEv
- obj:/usr/lib/libkhtml.so.5.2.0
- obj:/usr/lib/libkhtml.so.5.2.0
- obj:/usr/lib/libkhtml.so.5.2.0
- obj:/usr/lib/libkhtml.so.5.2.0
-}
-{
-
- Memcheck:Leak
- fun:malloc
- fun:_ZN8QMapData11node_createEPPNS_4NodeEi
- fun:_ZN4QMapI7QStringS0_E11node_createEP8QMapDataPPNS2_4NodeERKS0_S8_
- fun:_ZN4QMapI7QStringS0_E13detach_helperEv
- fun:_ZN4QMapI7QStringS0_E6detachEv
- fun:_ZN4QMapI7QStringS0_E5beginEv
- fun:_ZN17XslTransformation20updateParametersListEv
- fun:_ZN17XslTransformation13setParametersE4QMapI7QStringS1_E
- fun:_ZN16ChatMessageStyle8setStyleERK7QString
- fun:_ZN13ChatStylePage20slotChatStyleChangedERK7QString
- fun:_ZN13ChatStylePage12loadSettingsEPK7Account
- fun:_ZN21AccountSettingsDialog12loadSettingsEP7AccountbNS_4PageE
-}
-{
-
- Memcheck:Leak
- fun:_Znwm
- obj:/usr/lib/libkhtml.so.5.2.0
- obj:/usr/lib/libkhtml.so.5.2.0
- obj:/usr/lib/libkhtml.so.5.2.0
- obj:/usr/lib/libkhtml.so.5.2.0
- obj:/usr/lib/libkhtml.so.5.2.0
- fun:_ZN9KHTMLPart5beginERK4KUrlii
- fun:_ZN15ChatMessageView7setHtmlERK7QString
- fun:_ZN15ChatMessageView9clearViewEb
- fun:_ZN15ChatMessageViewC1EP7QWidget
- fun:_ZN8ChatViewC2EP7QWidget
- fun:_ZN4ChatC1EP7QWidget
-}
-{
-
- Memcheck:Leak
- fun:_Znwm
- fun:_ZN19QDockAreaLayoutInfo12restoreStateER11QDataStreamR5QListIP11QDockWidgetEb
- fun:_ZN15QDockAreaLayout12restoreStateER11QDataStreamRK5QListIP11QDockWidgetEb
- fun:_ZN22QMainWindowLayoutState11checkFormatER11QDataStreamb
- fun:_ZN22QMainWindowLayoutState12restoreStateER11QDataStreamRKS_
- fun:_ZN17QMainWindowLayout12restoreStateER11QDataStream
- fun:_ZN11QMainWindow12restoreStateERK10QByteArrayi
- fun:_ZN10ChatWindow14readPropertiesERK12KConfigGroup
- fun:_ZN10ChatWindow10initializeEv
- fun:_ZN10ChatMaster16createChatWindowEP4Chat
- fun:_ZN10ChatMaster10createChatEP24MsnSwitchboardConnectionb
- fun:_ZN10ChatMaster11qt_metacallEN11QMetaObject4CallEiPPv
-}
-{
-
- Memcheck:Leak
- fun:malloc
- fun:_ZN7QVectorI5QListIN14QObjectPrivate10ConnectionEEE7reallocEii
- fun:_ZN14QObjectPrivate13addConnectionEiPNS_10ConnectionE
- fun:_ZN11QMetaObject7connectEPK7QObjectiS2_iiPi
- fun:_ZN7QObject7connectEPKS_PKcS1_S3_N2Qt14ConnectionTypeE
- fun:_ZN14KActionPrivate4initEP7KAction
- fun:_ZN7KActionC1ERK5KIconRK7QStringP7QObject
- fun:_ZN8LikeBack18sendACommentActionEP17KActionCollection
- fun:_ZN14KMessInterface10initializeEv
- fun:_ZN5KMess10initializeEv
- fun:_ZN16KMessApplication20initializeMainWindowEv
- fun:_ZN16KMessApplicationC1Ev
-}
-{
-
- Memcheck:Leak
- fun:realloc
- fun:_ZN9QListData7reallocEi
- fun:_ZN9QListData6appendEv
- fun:_ZN5QListIP7QObjectE6appendERKS1_
- fun:_ZN14QObjectPrivate16setParent_helperEP7QObject
- fun:_ZN15QSocketNotifierC2EiNS_4TypeEP7QObject
- fun:_ZN19QNativeSocketEngine27setWriteNotificationEnabledEb
- fun:_ZN22QAbstractSocketPrivate23_q_connectToNextAddressEv
- fun:_ZN22QAbstractSocketPrivate18_q_startConnectingERK9QHostInfo
- fun:_ZN15QAbstractSocket27connectToHostImplementationERK7QStringt6QFlagsIN9QIODevice12OpenModeFlagEE
- fun:_ZN15QAbstractSocket11qt_metacallEN11QMetaObject4CallEiPPv
- fun:_ZNK11QMetaMethod6invokeEP7QObjectN2Qt14ConnectionTypeE22QGenericReturnArgument16QGenericArgumentS5_S5_S5_S5_S5_S5_S5_S5_S5_
-}
-{
-
- Memcheck:Leak
- fun:realloc
- obj:/usr/lib/libfontconfig.so.1.3.0
- obj:/usr/lib/libfontconfig.so.1.3.0
- fun:FcDefaultSubstitute
- fun:_ZN13QFontDatabase4loadEPK12QFontPrivatei
- fun:_ZNK12QFontPrivate15engineForScriptEi
- fun:_ZNK12QFontMetrics6ascentEv
- fun:_ZN5khtml18CachedFontInstanceC1EPNS_16CachedFontFamilyEi
- fun:_ZN5khtml16CachedFontFamily9queryFontEi
- fun:_ZNK5khtml4Font6updateEi
- fun:_ZN5khtml4Font11initDefaultEv
- fun:_ZN5khtml11RenderStyleC1Eb
-}
diff --git a/po/ar.po b/po/ar.po
index bb4b24b..34765ee 100644
--- a/po/ar.po
+++ b/po/ar.po
@@ -9,10 +9,11 @@ msgid ""
msgstr ""
"Project-Id-Version: ar\n"
"Report-Msgid-Bugs-To: http://www.kmess.org/board/\n"
-"POT-Creation-Date: 2010-02-25 15:16+0100\n"
+"POT-Creation-Date: 2010-06-27 13:57+0200\n"
"PO-Revision-Date: 2009-07-24 21:18+0200\n"
"Last-Translator: Ma'moun Diraneyya \n"
"Language-Team: Arabic \n"
+"Language: ar\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -22,7 +23,7 @@ msgstr ""
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
-#: account.cpp:45 account.cpp:744
+#: account.cpp:45 account.cpp:755
msgid "I am away from my computer"
msgstr "أنا بعيد عن حاسوبي"
@@ -30,7 +31,7 @@ msgstr "أنا بعيد عن حاسوبي"
msgid "Your name"
msgstr "اسمك"
-#: account.cpp:57 settings/accountpage.cpp:218
+#: account.cpp:57 settings/accountpage.cpp:220
#: settings/accountsettingsdialog.cpp:205
msgid "you@hotmail.com"
msgstr "you@hotmail.com"
@@ -471,39 +472,39 @@ msgstr "اكتب على الملف"
msgid "Over&write"
msgstr "ا&كتب عليه"
-#: chat/chatview.cpp:925
+#: chat/chatview.cpp:934
msgid "Add this &Emoticon..."
msgstr "أ&ضف هذا الوجه..."
-#: chat/chatview.cpp:928
+#: chat/chatview.cpp:937
msgid "Hide this &Emoticon"
msgstr "أ&خفِ هذا الوجه..."
-#: chat/chatview.cpp:934
+#: chat/chatview.cpp:943
msgid "Send &Email"
msgstr "أ&رسل رسالة بريدية"
-#: chat/chatview.cpp:938
+#: chat/chatview.cpp:947
msgid "Add &Contact"
msgstr "أضف الم&تراسل"
-#: chat/chatview.cpp:942
+#: chat/chatview.cpp:951
msgid "Copy E&mail Address"
msgstr "انس&خ عنوان البريد"
-#: chat/chatview.cpp:948
+#: chat/chatview.cpp:957
msgid "Visit &Link"
msgstr "&زُر الرابط"
-#: chat/chatview.cpp:952
+#: chat/chatview.cpp:961
msgid "Copy &Address"
msgstr "انسخ ال&عنوان"
-#: chat/chatview.cpp:965 chat/chatwindow.cpp:540
+#: chat/chatview.cpp:974 chat/chatwindow.cpp:540
msgid "C&lear Chat"
msgstr "امحِ المحادثة"
-#: chat/chatview.cpp:966
+#: chat/chatview.cpp:975
msgid "Save Chat to &File..."
msgstr "ا&حفظ المحادثة في ملف..."
@@ -642,7 +643,7 @@ msgstr "&لون الخط"
msgid "C&lear Chat Window"
msgstr "امحِ &نافذة المحادثة"
-#: chat/chatwindow.cpp:1106
+#: chat/chatwindow.cpp:1149
msgid ""
"You used an incorrect syntax for the /status command. The correct "
"syntax is: /status online|away|idle|brb|busy|lunch|phone|invisible."
@@ -652,30 +653,30 @@ msgstr ""
"online|away|idle|brb|busy|lunch|phone|invisible.
تستطيع أيضًا استخدام "
"الاختصارات /online أو /phone."
-#: chat/chatwindow.cpp:1109
+#: chat/chatwindow.cpp:1152
msgctxt "Dialog box caption for wrong command syntax warning"
msgid "Incorrect /status Syntax"
msgstr "صياغة /status خاطئة"
-#: chat/chatwindow.cpp:1172
+#: chat/chatwindow.cpp:1215
msgid "You cannot use the /block command in a group chat."
msgstr "لا تستطيع استخدام الأمر /block في محادثة جماعية."
-#: chat/chatwindow.cpp:1174
+#: chat/chatwindow.cpp:1217
msgctxt "Caption when trying to block someone in a group chat"
msgid "Cannot use /block command"
msgstr "لا يمكن استخدام الأمر /block"
-#: chat/chatwindow.cpp:1185
+#: chat/chatwindow.cpp:1228
msgid "You cannot use the /unblock command in a group chat."
msgstr "لا تستطيع استخدام الأمر /unblock في محادثة جماعية."
-#: chat/chatwindow.cpp:1187
+#: chat/chatwindow.cpp:1230
msgctxt "Caption when trying to unblock someone in a group chat"
msgid "Cannot use /unblock command!"
msgstr "لا يمكن استخدام الأمر /unblock!"
-#: chat/chatwindow.cpp:1217
+#: chat/chatwindow.cpp:1260
#, kde-format
msgid ""
"Unknown command %1. If you did not want this message to be a "
@@ -684,18 +685,18 @@ msgstr ""
"أمر مجهول %1. إذا لم تكن تريد لهذه الرسالة أن تكون أمرًا فألحق "
"رسالتك بشرطة / ثانية."
-#: chat/chatwindow.cpp:1220
+#: chat/chatwindow.cpp:1263
msgctxt "Caption when an unknown command was requested"
msgid "Unknown Command"
msgstr "أمر مجهول"
-#: chat/chatwindow.cpp:1496
+#: chat/chatwindow.cpp:1539
#, fuzzy
msgctxt "Error message shown in chat"
msgid "Failed to send the handwritten message: the contacts do not support it."
msgstr "فشل إرسال الرسالة المخطوطة إلى %1."
-#: chat/chatwindow.cpp:1534
+#: chat/chatwindow.cpp:1577
#, fuzzy
msgctxt "Error message shown in chat"
msgid ""
@@ -703,18 +704,18 @@ msgid ""
"it."
msgstr "فشل إرسال الرسالة المخطوطة إلى %1."
-#: chat/chatwindow.cpp:1824
+#: chat/chatwindow.cpp:1858
msgctxt "Chat window caption, without contact name"
msgid "Chat"
msgstr "محادثة"
-#: chat/chatwindow.cpp:1828
+#: chat/chatwindow.cpp:1862
#, kde-format
msgctxt "Chat window caption, with contact name"
msgid "%1 - Chat"
msgstr "محادثة - %1"
-#: chat/chatwindow.cpp:1848 kmessinterface.cpp:674
+#: chat/chatwindow.cpp:1882 kmessinterface.cpp:676
#, kde-format
msgctxt "Question dialog box message"
msgid ""
@@ -724,38 +725,38 @@ msgstr ""
"هل أنت متأكد أنك تريد إخفاء شريط القوائم؟ ستكون قادرًا على إظهاره مجددًا "
"باستخدام اختصار لوحة المفاتيح: %1"
-#: chat/chatwindow.cpp:1852 kmessinterface.cpp:678
+#: chat/chatwindow.cpp:1886 kmessinterface.cpp:680
msgctxt "Dialog box caption: hiding the menu bar"
msgid "Hiding the Menu"
msgstr "إخفاء شريط القوائم"
-#: chat/chatwindow.cpp:1938
+#: chat/chatwindow.cpp:1972
#, fuzzy
msgid "Drawing brush"
msgstr "فرشاة المسح"
#. i18n: file: chat/chatwindow.ui:364
#. i18n: ectx: property (toolTip), widget (QToolButton, inkEraseButton_)
-#: chat/chatwindow.cpp:1944 rc.cpp:41
+#: chat/chatwindow.cpp:1978 rc.cpp:41
msgid "Erase brush"
msgstr "فرشاة المسح"
-#: chat/chatwindow.cpp:2137
+#: chat/chatwindow.cpp:2171
#, kde-format
msgid "%1 is typing..."
msgstr "%1 يكتب..."
-#: chat/chatwindow.cpp:2147
+#: chat/chatwindow.cpp:2181
#, kde-format
msgid "%1 and %2 are typing..."
msgstr "%1 و%2 يكتبان..."
-#: chat/chatwindow.cpp:2151
+#: chat/chatwindow.cpp:2185
#, fuzzy, kde-format
msgid "%1, %2 and %3 others are typing..."
msgstr "%1 و%2 و%3 آخر/ون يكتبون..."
-#: chat/chatwindow.cpp:2638
+#: chat/chatwindow.cpp:2672
#, kde-format
msgctxt "Tool tip for chat tabs"
msgid ""
@@ -763,24 +764,24 @@ msgid ""
"ul>Chat started on:%2Connected with "
"account:%3"
msgstr ""
-"معلومات المحادثة
- المتراسلون:
- بدأت المحادثة في:
- %2
- متصل من "
+"
معلومات المحادثة
- المتراسلون:
- بدأت المحادثة في:
- %2
- متصل من "
"الحساب:
- %3
"
#. i18n: file: chat/chatwindow.ui:212
#. i18n: ectx: property (toolTip), widget (QToolButton, inkButton_)
-#: chat/chatwindow.cpp:2774 rc.cpp:11
+#: chat/chatwindow.cpp:2808 rc.cpp:11
msgid "Handwriting mode"
msgstr "وضع التخطيط"
-#: chat/chatwindow.cpp:2783
+#: chat/chatwindow.cpp:2817
msgctxt "Label text"
msgid ""
"Handwriting is disabled: some of the contacts do not support receiving "
"handwritten messages."
msgstr ""
-#: chat/chatwindow.cpp:2789
+#: chat/chatwindow.cpp:2823
msgctxt "Label text"
msgid ""
"Handwriting is disabled: this contact does not support receiving handwritten "
@@ -789,17 +790,17 @@ msgstr ""
#. i18n: file: chat/chatwindow.ui:276
#. i18n: ectx: property (toolTip), widget (QToolButton, winksButton_)
-#: chat/chatwindow.cpp:2797 rc.cpp:29
+#: chat/chatwindow.cpp:2831 rc.cpp:29
msgid "Winks"
msgstr "الغمزات"
-#: chat/chatwindow.cpp:2806
+#: chat/chatwindow.cpp:2840
msgctxt "Label text"
msgid ""
"Winks are disabled: some of the contacts do not support receiving winks."
msgstr ""
-#: chat/chatwindow.cpp:2812
+#: chat/chatwindow.cpp:2846
#, fuzzy
msgctxt "Label text"
msgid "Winks are disabled: this contact does not support receiving winks."
@@ -809,51 +810,51 @@ msgstr "الغمزات معطلة: لا يستطيع خميس إرسال غمز
msgid "&Start Private Chat"
msgstr "ابدأ محادثة &خاصة"
-#: chat/contactframe.cpp:355 kmessview.cpp:689
+#: chat/contactframe.cpp:355 kmessview.cpp:706
msgid "&Send Email"
msgstr "أر&سل رسالة بريدية"
-#: chat/contactframe.cpp:356 kmessview.cpp:690
+#: chat/contactframe.cpp:356 kmessview.cpp:707
msgid "&View Profile"
msgstr "أظ&هر صفحته الشخصية"
-#: chat/contactframe.cpp:358 chat/contactframe.cpp:411 kmessview.cpp:692
+#: chat/contactframe.cpp:358 chat/contactframe.cpp:411 kmessview.cpp:709
msgid "&Properties"
msgstr "ال&خصائص"
-#: chat/contactframe.cpp:360 kmessview.cpp:694
+#: chat/contactframe.cpp:360 kmessview.cpp:711
msgid "&Add Contact"
msgstr "أ&ضف المتراسل"
-#: chat/contactframe.cpp:361 kmessview.cpp:695
+#: chat/contactframe.cpp:361 kmessview.cpp:712
msgid "A&llow Contact"
msgstr "ا&قبل المتراسل"
-#: chat/contactframe.cpp:362 kmessview.cpp:698
+#: chat/contactframe.cpp:362 kmessview.cpp:715
msgid "&Delete Contact"
msgstr "ا&حذف المتراسل"
-#: chat/contactframe.cpp:364 kmessview.cpp:696
+#: chat/contactframe.cpp:364 kmessview.cpp:713
msgid "&Block Contact"
msgstr "اح&ظر المتراسل"
-#: chat/contactframe.cpp:365 kmessview.cpp:697
+#: chat/contactframe.cpp:365 kmessview.cpp:714
msgid "&Unblock Contact"
msgstr "أل&غِ حظر المتراسل"
-#: chat/contactframe.cpp:367 kmessview.cpp:701
+#: chat/contactframe.cpp:367 kmessview.cpp:718
msgid "&Friendly Name"
msgstr "الاس&م"
-#: chat/contactframe.cpp:368 kmessview.cpp:702
+#: chat/contactframe.cpp:368 kmessview.cpp:719
msgid "&Personal Message"
msgstr "الر&سالة الشخصية"
-#: chat/contactframe.cpp:369 kmessview.cpp:703
+#: chat/contactframe.cpp:369 kmessview.cpp:720
msgid "&Email Address"
msgstr "ع&نوان البريد الإلكتروني"
-#: chat/contactframe.cpp:370 kmessview.cpp:704
+#: chat/contactframe.cpp:370 kmessview.cpp:721
msgid "Song &Name"
msgstr "اسم الأ&غنية"
@@ -879,15 +880,15 @@ msgstr "الملاح&ظات"
msgid "&Emoticons"
msgstr "الو&جوه"
-#: chat/contactframe.cpp:404 kmessview.cpp:739
+#: chat/contactframe.cpp:404 kmessview.cpp:756
msgid "&Copy"
msgstr "ا&نسخ"
-#: chat/contactframe.cpp:809
+#: chat/contactframe.cpp:812
msgid "Blocked"
msgstr "محظور"
-#: chat/contactframe.cpp:821
+#: chat/contactframe.cpp:824
#, kde-format
msgctxt ""
"Tooltip for a contact's status icon, arg %1 is the Live Messenger status, "
@@ -895,17 +896,18 @@ msgctxt ""
msgid "The contact is %1"
msgstr "المتراسل %1"
-#: chat/contactswidget.cpp:298 kmessview.cpp:523 settings/accountpage.cpp:489
+#: chat/contactswidget.cpp:298 kmessview.cpp:540 settings/accountpage.cpp:496
msgid "Downloading of display picture failed"
msgstr "فشل تنزيل صورة العرض"
-#: chat/contactswidget.cpp:298 chat/contactswidget.cpp:334 kmessview.cpp:523
-#: kmessview.cpp:560 main.cpp:43 settings/accountpage.cpp:489
-#: settings/accountpage.cpp:550
+#: chat/contactswidget.cpp:298 chat/contactswidget.cpp:334 kmessview.cpp:540
+#: kmessview.cpp:577 main.cpp:43 notification/newsystemtraywidget.cpp:64
+#: notification/newsystemtraywidget.cpp:224 settings/accountpage.cpp:496
+#: settings/accountpage.cpp:557
msgid "KMess"
msgstr "خميس"
-#: chat/contactswidget.cpp:332 kmessview.cpp:558 settings/accountpage.cpp:548
+#: chat/contactswidget.cpp:332 kmessview.cpp:575 settings/accountpage.cpp:555
msgid ""
"An error occurred while trying to change the display picture.\n"
"Make sure that you have selected an existing image file."
@@ -934,7 +936,7 @@ msgstr "أضف جديدًا"
msgid "Edit"
msgstr "حرِّر"
-#: chat/emoticonswidget.cpp:442 kmess.cpp:580
+#: chat/emoticonswidget.cpp:442 kmess.cpp:583
msgid "Remove"
msgstr "أزل"
@@ -990,52 +992,52 @@ msgstr "متوافق مع مرسال وِندُز لايف %1"
msgid "Windows Live Messenger compatible"
msgstr "متوافق مع مرسال وِندُز لايف"
-#: contact/msnstatus.cpp:159 contact/msnstatus.cpp:172 initialview.cpp:85
-#: model/contactlist.cpp:1825 settings/accountpage.cpp:99
+#: contact/msnstatus.cpp:193 contact/msnstatus.cpp:206 initialview.cpp:85
+#: model/contactlist.cpp:1825 settings/accountpage.cpp:101
msgid "Online"
msgstr "متصل"
-#: contact/msnstatus.cpp:160 initialview.cpp:88 settings/accountpage.cpp:102
+#: contact/msnstatus.cpp:194 initialview.cpp:88 settings/accountpage.cpp:104
msgid "Busy"
msgstr "مشغول"
-#: contact/msnstatus.cpp:161 initialview.cpp:86 settings/accountpage.cpp:100
+#: contact/msnstatus.cpp:195 initialview.cpp:86 settings/accountpage.cpp:102
msgid "Away"
msgstr "بعيد"
-#: contact/msnstatus.cpp:162
+#: contact/msnstatus.cpp:196
msgid "Away with Auto-Reply"
msgstr "بعيد، مع رد آلي"
-#: contact/msnstatus.cpp:163
+#: contact/msnstatus.cpp:197
msgid "Idle"
msgstr "خامل"
-#: contact/msnstatus.cpp:164 initialview.cpp:87 settings/accountpage.cpp:101
+#: contact/msnstatus.cpp:198 initialview.cpp:87 settings/accountpage.cpp:103
msgid "Be Right Back"
msgstr "سأعود حالاً"
-#: contact/msnstatus.cpp:165 initialview.cpp:90 settings/accountpage.cpp:104
+#: contact/msnstatus.cpp:199 initialview.cpp:90 settings/accountpage.cpp:106
msgid "On the Phone"
msgstr "على الهاتف"
-#: contact/msnstatus.cpp:166 initialview.cpp:89 settings/accountpage.cpp:103
+#: contact/msnstatus.cpp:200 initialview.cpp:89 settings/accountpage.cpp:105
msgid "Out to Lunch"
msgstr "خارج للغداء"
-#: contact/msnstatus.cpp:167 initialview.cpp:91 settings/accountpage.cpp:105
+#: contact/msnstatus.cpp:201 initialview.cpp:91 settings/accountpage.cpp:107
msgid "Invisible"
msgstr "متخفٍّ"
-#: contact/msnstatus.cpp:168 model/contactlist.cpp:1826
+#: contact/msnstatus.cpp:202 model/contactlist.cpp:1826
msgid "Offline"
msgstr "غير متصل"
-#: contact/msnstatus.cpp:195 contact/msnstatus.cpp:197
+#: contact/msnstatus.cpp:229 contact/msnstatus.cpp:231
msgid "&My Status"
msgstr "&حالتي"
-#: contact/msnstatus.cpp:218
+#: contact/msnstatus.cpp:252
msgctxt "Menu action name"
msgid "Disconnect"
msgstr "اقطع الاتصال"
@@ -1137,16 +1139,16 @@ msgstr ""
msgid "Contact Properties for %1"
msgstr "خصائص المتراسل %1"
-#: dialogs/contactpropertiesdialog.cpp:399 kmess.cpp:816 kmessview.cpp:1290
+#: dialogs/contactpropertiesdialog.cpp:399 kmess.cpp:819 kmessview.cpp:1308
#: network/msnsockethttp.cpp:199 network/msnsockettcp.cpp:386
msgid "Connected"
msgstr "متصل"
-#: dialogs/contactpropertiesdialog.cpp:405 kmessview.cpp:1296
+#: dialogs/contactpropertiesdialog.cpp:405 kmessview.cpp:1314
msgid "Not seen yet"
msgstr "لم يُشاهَد بعد"
-#: dialogs/contactpropertiesdialog.cpp:416 kmessview.cpp:1313
+#: dialogs/contactpropertiesdialog.cpp:416 kmessview.cpp:1331
msgid "No messages yet"
msgstr "لا رسائل بعد"
@@ -1174,20 +1176,20 @@ msgctxt "Contact props dialog info"
msgid "Client: %1"
msgstr "العميل: %1"
-#: dialogs/contactpropertiesdialog.cpp:665
+#: dialogs/contactpropertiesdialog.cpp:666
msgctxt "Dialog box text"
msgid "Are you sure you want to use the display picture of this contact?"
msgstr "أمتأكد أنك تريد استخدام صورة عرض هذا المتراسل؟"
-#: dialogs/contactpropertiesdialog.cpp:667
+#: dialogs/contactpropertiesdialog.cpp:668
msgid "Copy Contact Picture"
msgstr "انسخ صورة المتراسل"
-#: dialogs/contactpropertiesdialog.cpp:720
+#: dialogs/contactpropertiesdialog.cpp:721
msgid "The selected filetype is not supported by Phonon."
msgstr "نوع الملف المُختار غير مدعوم في فُنُن."
-#: dialogs/contactpropertiesdialog.cpp:720
+#: dialogs/contactpropertiesdialog.cpp:721
msgid "Unsupported filetype"
msgstr "أنواع ملفات غير مدعومة"
@@ -1696,8 +1698,8 @@ msgstr "إعادة الاتصال غير ممكنة: ليس لهذا الحسا
#, kde-format
msgctxt "Status message on login screen"
msgid ""
-"Waiting for an Internet connection to reconnect...
Reconnect now!"
+"Waiting for an Internet connection to reconnect...
Reconnect now!"
msgstr ""
"ينتظر اتصالاً بالإنترنت حتى يعيد الاتصال...
أعد الاتصال "
"الآن!"
@@ -1770,22 +1772,22 @@ msgstr "إضافة مجموعة"
msgid "Enter a name for the new group:"
msgstr "أدخل اسمًا للمجموعة الجديدة:"
-#: kmess.cpp:577
+#: kmess.cpp:580
#, kde-format
msgid ""
"Are you sure you want to remove the contact %1 from your contact "
"list?"
msgstr "أمتأكد أنك تريد إزالة %1 من لائحة متراسليك؟"
-#: kmess.cpp:579
+#: kmess.cpp:582
msgid "Remove Contact"
msgstr "أزل المتراسل"
-#: kmess.cpp:581
+#: kmess.cpp:584
msgid "Remove and Block"
msgstr "أزله واحظره"
-#: kmess.cpp:627
+#: kmess.cpp:630
#, kde-format
msgctxt "dialog text"
msgid ""
@@ -1794,12 +1796,12 @@ msgid ""
msgstr ""
"المجموعة %1 ليست فارغة: أزل جميع المتراسلين منها، ثم حاول مجددًا!"
-#: kmess.cpp:629 kmess.cpp:636
+#: kmess.cpp:632 kmess.cpp:639
msgctxt "dialog title"
msgid "Group Removal"
msgstr "إزالة مجموعة"
-#: kmess.cpp:634
+#: kmess.cpp:637
#, kde-format
msgctxt "dialog text"
msgid ""
@@ -1807,24 +1809,24 @@ msgid ""
"list?"
msgstr "أمتأكد أنك تريد إزالة المجموعة %1 من لائحة متراسليك؟"
-#: kmess.cpp:637
+#: kmess.cpp:640
msgctxt "dialog button"
msgid "Remove"
msgstr "أزل"
-#: kmess.cpp:666
+#: kmess.cpp:669
msgid "This is a special group, which cannot be changed."
msgstr "هذه مجموعة خاصة، ولايمكن تغييرها."
-#: kmess.cpp:677
+#: kmess.cpp:680
msgid "Rename Group"
msgstr "&غيِّر اسم المجموعة"
-#: kmess.cpp:678
+#: kmess.cpp:681
msgid "Enter a new name for this group:"
msgstr "أدخل اسمًا جديدًا لهذه المجموعة:"
-#: kmess.cpp:755
+#: kmess.cpp:758
#, kde-format
msgctxt "dialog text"
msgid ""
@@ -1833,21 +1835,21 @@ msgid ""
msgstr ""
"لا يمكن الولوج آليًا بالحساب %1:
يجب عليك أولاً حفظ كلمة سره!
"
-#: kmess.cpp:758
+#: kmess.cpp:761
msgctxt "dialog title"
msgid "Autologin Failed"
msgstr "فشل الولوج الآلي"
-#: kmess.cpp:1069
+#: kmess.cpp:1077
msgid "Connection could be down..."
msgstr "ربما ينقطع الاتصال..."
-#: kmess.cpp:1139
+#: kmess.cpp:1147
msgctxt "Status bar message"
msgid "Disconnected"
msgstr "انقطع الاتصال"
-#: kmess.cpp:1478
+#: kmess.cpp:1482
#, kde-format
msgctxt ""
"Paragraph to be added to the text of a message dialog box, but only when KDE "
@@ -1855,7 +1857,7 @@ msgctxt ""
msgid "KMess has searched for it in the following folders:
%1
"
msgstr "بحث خميس عنه في المجلدات التالية:
%1
"
-#: kmess.cpp:1490
+#: kmess.cpp:1494
#, kde-format
msgctxt ""
"Text for a message dialog box; %1 is an explanation about the list of "
@@ -1870,12 +1872,12 @@ msgstr ""
"p>لأنه لم يستطع إيجاد الملف 'kmess.notifyrc' المطلوب، في أي واحد من "
"مجلدات التطبيق.
%1فضلاً تحقَّق من تثبيتك.
"
-#: kmess.cpp:1496
+#: kmess.cpp:1500
msgctxt "Message box title"
msgid "Error With Notifications"
msgstr "خطأ بشأن التنبيهات"
-#: kmess.cpp:1774
+#: kmess.cpp:1778
#, kde-format
msgctxt ""
"Main window caption: switched order to easily distinguish it from chats"
@@ -1884,210 +1886,205 @@ msgstr "خميس - %1"
#. i18n: file: initialview.ui:348
#. i18n: ectx: property (text), widget (QPushButton, connectButton_)
-#: kmessinterface.cpp:160 rc.cpp:326
+#: kmessinterface.cpp:165 rc.cpp:326
msgid "&Connect"
msgstr "ا&تصل"
-#: kmessinterface.cpp:161
+#: kmessinterface.cpp:166
msgid "&Disconnect"
msgstr "ا&قطع الاتصال"
-#: kmessinterface.cpp:162
+#: kmessinterface.cpp:167
msgid "Show My &Profile"
msgstr "أ&ظهر صفحتي الشَّخصية"
-#: kmessinterface.cpp:167
+#: kmessinterface.cpp:172
msgid "Show &Allowed Contacts"
msgstr "أظهر المتراسلين المقبو&لين"
-#: kmessinterface.cpp:168
+#: kmessinterface.cpp:173
msgid "Show &Offline Contacts"
msgstr "أظهر المتراسلين &غير المتصلين"
-#: kmessinterface.cpp:169
+#: kmessinterface.cpp:174
msgid "Show &Removed Contacts"
msgstr "أظهر المتراسلين المُزالي&ن"
-#: kmessinterface.cpp:170
+#: kmessinterface.cpp:175
msgid "Show &History Box"
msgstr "أظهر صندوق ال&تأريخ"
-#: kmessinterface.cpp:171
+#: kmessinterface.cpp:176
msgid "&Show Search Bar"
msgstr "أظهر شريط ال&بحث"
-#: kmessinterface.cpp:172
+#: kmessinterface.cpp:177
msgid "Show &Empty Groups"
msgstr "أظهر الم&جموعات الفارغة"
-#: kmessinterface.cpp:173
+#: kmessinterface.cpp:178
msgid "&Display Pictures Size"
msgstr "&حجم صورة العرض"
-#: kmessinterface.cpp:174
+#: kmessinterface.cpp:179
msgid "&Sort Contacts by"
msgstr "افر&ز المتراسلين حسب"
-#: kmessinterface.cpp:175
+#: kmessinterface.cpp:180
msgid "Show &Transfer Window..."
msgstr "أظهر نا&فذة النقل..."
-#: kmessinterface.cpp:180
+#: kmessinterface.cpp:185
msgid "New &Contact..."
msgstr "مترا&سل جديد..."
-#: kmessinterface.cpp:181
+#: kmessinterface.cpp:186
msgid "New &Group..."
msgstr "مج&موعة جديدة..."
-#: kmessinterface.cpp:182
+#: kmessinterface.cpp:187
msgid "&Export Contact List..."
msgstr "&صدِّر لائحة المتراسلين..."
-#: kmessinterface.cpp:183 kmessview.cpp:691
+#: kmessinterface.cpp:188 kmessview.cpp:708
msgid "Show Chat &History..."
msgstr "أظهر &تأريخ المحادثات..."
-#: kmessinterface.cpp:184
+#: kmessinterface.cpp:189
msgid "New &Account..."
msgstr "&حساب جديد..."
-#: kmessinterface.cpp:185
+#: kmessinterface.cpp:190
msgid "Configure Account..."
msgstr "اضبط الحساب..."
-#: kmessinterface.cpp:186
+#: kmessinterface.cpp:191
msgid "Configure &KMess..."
msgstr "ا&ضبط خميس..."
-#: kmessinterface.cpp:187
+#: kmessinterface.cpp:192
msgid "Show Selection &Menu"
msgstr "أظهر &قائمة الاختيار"
-#: kmessinterface.cpp:190
+#: kmessinterface.cpp:195
msgid "Do Not Display"
msgstr "لا تعرض"
-#: kmessinterface.cpp:191
+#: kmessinterface.cpp:196
msgid "Small"
msgstr "صغير"
-#: kmessinterface.cpp:192
+#: kmessinterface.cpp:197
msgid "Medium"
msgstr "وسط"
-#: kmessinterface.cpp:193
+#: kmessinterface.cpp:198
msgid "Large"
msgstr "كبير"
-#: kmessinterface.cpp:197
+#: kmessinterface.cpp:202
msgid "Group"
msgstr "المجموعة"
-#: kmessinterface.cpp:198
+#: kmessinterface.cpp:203
msgid "Online/Offline"
msgstr "حالة الاتصال (متصل/غير متصل)"
-#: kmessinterface.cpp:199
+#: kmessinterface.cpp:204
msgid "Mixed"
msgstr "خليط"
-#: kmessinterface.cpp:289
+#: kmessinterface.cpp:294
msgid "Show &Network Window..."
msgstr "أظهر نافذة الشب&كة..."
-#: kmessview.cpp:330
+#: kmessview.cpp:341
#, kde-format
msgid "[%1] Logged in with %2"
msgstr "[%1] ولجت بالحساب %2"
-#: kmessview.cpp:374
+#: kmessview.cpp:391
#, kde-format
msgid "[%1] %2 goes online"
msgstr "[%1] اتصل %2"
-#: kmessview.cpp:379
+#: kmessview.cpp:396
#, kde-format
msgid "[%1] %2 goes offline"
msgstr "[%1] فصل %2"
-#: kmessview.cpp:688
+#: kmessview.cpp:705
msgid "Cha&t"
msgstr "حا&دثه"
-#: kmessview.cpp:699
+#: kmessview.cpp:716
msgid "&Remove From Group"
msgstr "أ&زله من المجموعة"
-#: kmessview.cpp:732
+#: kmessview.cpp:749
msgid "&Copy to Group"
msgstr "انس&خه إلى المجموعة"
-#: kmessview.cpp:733
+#: kmessview.cpp:750
msgid "&Move to Group"
msgstr "ان&قله إلى المجموعة"
-#: kmessview.cpp:784
+#: kmessview.cpp:801
msgid "Move Group &Down"
msgstr "حرّك المجموعة إلى الأس&فل"
-#: kmessview.cpp:785
+#: kmessview.cpp:802
msgid "Move Group &Up"
msgstr "حرّك المجموعة إلى الأ&على"
-#: kmessview.cpp:786
+#: kmessview.cpp:803
msgid "Re&move Group"
msgstr "أز&ل المجموعة"
-#: kmessview.cpp:787
+#: kmessview.cpp:804
msgid "Re&name Group"
msgstr "&غيِّر اسم المجموعة"
-#: kmessview.cpp:1237
-msgctxt "Message in list tooltip"
-msgid "This contact does not have you in his or her contact list."
-msgstr "لست موجودًا على لائحة متراسلي هذا الشخص."
-
-#: kmessview.cpp:1255
+#: kmessview.cpp:1273
msgctxt "Contact email label in list tooltip"
msgid "Email address"
msgstr "عنوان البريد"
-#: kmessview.cpp:1262
+#: kmessview.cpp:1280
msgctxt "Contact Live Messenger client label in list tooltip"
msgid "Client"
msgstr "العميل"
-#: kmessview.cpp:1274
+#: kmessview.cpp:1292
msgid "Yes"
msgstr "نعم"
-#: kmessview.cpp:1278
+#: kmessview.cpp:1296
msgid "No"
msgstr "لا"
-#: kmessview.cpp:1281
+#: kmessview.cpp:1299
msgctxt "Contact blocked status label in list tooltip"
msgid "Blocked"
msgstr "محظور"
-#: kmessview.cpp:1303
+#: kmessview.cpp:1321
msgctxt "Contact last presence label in list tooltip"
msgid "Last seen"
msgstr "آخر مشاهدة"
-#: kmessview.cpp:1320
+#: kmessview.cpp:1338
msgctxt "Contact last message label in list tooltip"
msgid "Last message"
msgstr "آخر رسالة"
-#: kmessview.cpp:1330
+#: kmessview.cpp:1348
#, kde-format
msgctxt "Group name in group tooltip"
msgid "Group %1"
msgstr "المجموعة %1"
-#: kmessview.cpp:1338
+#: kmessview.cpp:1356
#, kde-format
msgctxt "Contact counters in normal group tooltip, first part"
msgid "%1 contact, "
@@ -2099,7 +2096,7 @@ msgstr[3] "%1 متراسلين، "
msgstr[4] "%1 متراسلاً، "
msgstr[5] "%1 متراسل، "
-#: kmessview.cpp:1341
+#: kmessview.cpp:1359
#, kde-format
msgctxt "Contact counters in normal group tooltip, second part"
msgid "%1 online"
@@ -2111,7 +2108,7 @@ msgstr[3] "%1 متصلين"
msgstr[4] "%1 متصلاً"
msgstr[5] "%1 متصل"
-#: kmessview.cpp:1347
+#: kmessview.cpp:1365
#, kde-format
msgctxt "Contacts count in special group tooltip"
msgid "%1 contact"
@@ -2123,18 +2120,18 @@ msgstr[3] "%1 متراسلين"
msgstr[4] "%1 متراسلاً"
msgstr[5] "%1 متراسل"
-#: kmessview.cpp:1768
+#: kmessview.cpp:1786
#, fuzzy
msgctxt "Default friendly name tooltip"
msgid "Click here to change your friendly name"
msgstr "انقر هنا لجعل خميس يحفظ كلمة سرِّك"
-#: kmessview.cpp:1828
+#: kmessview.cpp:1846
msgctxt "Default personal message shown in the contact list"
msgid "[i]Click to set a personal message[/i]"
msgstr ""
-#: kmessview.cpp:1829
+#: kmessview.cpp:1847
#, fuzzy
msgctxt "Default personal message tooltip"
msgid ""
@@ -2142,15 +2139,15 @@ msgid ""
"along with your friendly name"
msgstr "أدخل رسالة هنا لتُعرض لمتراسليك: سيشاهدون هذه الرسالة بعد اسمك"
-#: kmessview.cpp:2009
+#: kmessview.cpp:2027
msgid "No chat logs could be found for this contact."
msgstr "لا سجلات محادثات موجودة لهذا المتراسل."
-#: kmessview.cpp:2010 kmessview.cpp:2016
+#: kmessview.cpp:2028 kmessview.cpp:2034
msgid "No chat history found"
msgstr "لا تأريخ محادثات موجود"
-#: kmessview.cpp:2015
+#: kmessview.cpp:2033
msgid ""
"No chat logs could be found for this contact. Note that new chats are not "
"logged; if you want your chats to be logged, you can enable it in your "
@@ -2159,7 +2156,7 @@ msgstr ""
"لا سجلات محادثات موجودة لهذا المتراسل. لاحظ أنَّ المحادثات الجديد لا تُسجَّل، لكن "
"يمكنك إذا أردت تسجيلها أن تفعَّل ذلك من إعدادات الحساب."
-#: kmessview.cpp:2209
+#: kmessview.cpp:2235
#, kde-format
msgid "%1 new email message"
msgid_plural "%1 new email messages"
@@ -2170,6 +2167,16 @@ msgstr[3] "%1 رسائل بريدية جديدة"
msgstr[4] "%1 رسالة بريدية جديدة"
msgstr[5] "%1 رسالة بريدية جديدة"
+#: kmessview.cpp:2254
+#, fuzzy
+msgid "Show contacts what you are listening to (click to disable)"
+msgstr "أظهر للمتراسلين الم&قطوعة التي أستمع إليها"
+
+#: kmessview.cpp:2259
+#, fuzzy
+msgid "Show contacts what you are listening to (click to enable)"
+msgstr "أظهر للمتراسلين الم&قطوعة التي أستمع إليها"
+
#: kmessviewdelegate.cpp:290
#, kde-format
msgctxt ""
@@ -2846,48 +2853,56 @@ msgstr ""
msgid "Marco Mentasti"
msgstr "تهكُّم"
-#: main.cpp:185
+#: main.cpp:183
+msgid "Francesco Nwokeka"
+msgstr ""
+
+#: main.cpp:183
+msgid "Now Listening toggle button above the contact list."
+msgstr ""
+
+#: main.cpp:186
msgid "Inspiration and assorted code"
msgstr "شفرة متجانسة ومُلهِمة"
-#: main.cpp:185
+#: main.cpp:186
msgid "KMerlin (kmerlin.olsd.de)"
msgstr "كمِرلين (kmerlin.olsd.de)"
-#: main.cpp:186
+#: main.cpp:187
msgid "Kopete (kopete.kde.org)"
msgstr "كُبِتي (kopete.kde.org)"
-#: main.cpp:186
+#: main.cpp:187
msgid "Old popup balloons code, initial p2p code, MSN challenge handler"
msgstr "شفرة البالونات المنبثقة القديمة، وشفرة الندِّ للندِّ الأولية، ومُستوثِق MSN"
-#: main.cpp:187
+#: main.cpp:188
msgid "Idle timer code"
msgstr "شفرة مؤقت الخمول"
-#: main.cpp:187
+#: main.cpp:188
msgid "KScreensaver"
msgstr "حافظةشاشةك"
-#: main.cpp:188
+#: main.cpp:189
msgid "BasKet"
msgstr "باسكِت"
-#: main.cpp:188
+#: main.cpp:189
msgid "Close-to-tray icon screenshot code"
msgstr "شفرة الإغلاق إلى أيقونة صينية النظام"
-#: main.cpp:189
+#: main.cpp:190
msgid "Amarok"
msgstr "أمارُك"
-#: main.cpp:189
+#: main.cpp:190
msgid ""
"Custom crash handler implementation, System tray icon overlay implementation"
msgstr "تنفيذ مدبِّر انهيار مخصَّص، بالإضافة إلى تنفيذ تراكب أيقونة صينية النظام"
-#: main.cpp:190
+#: main.cpp:191
msgid ""
"KNotify not giving focus bug fix and KWin focus stealing prevention "
"workaround"
@@ -2895,11 +2910,11 @@ msgstr ""
"إصلاح علَّة اختلال التركيز في مبلِّغك، بالإضافة إلى تحايل منع اختطاف التركيز في "
"نافذةك"
-#: main.cpp:190
+#: main.cpp:191
msgid "Quassel"
msgstr "اكْوَسِل"
-#: main.cpp:193
+#: main.cpp:194
msgid ""
"You are welcome to send bugfixes and patches to the KMess help forum!\n"
"If you feel your name is missing here, please contact us too!"
@@ -2907,33 +2922,33 @@ msgstr ""
"نُرحِّب بإرسالك إصلاحات للعلل أو رُقَع إلى منتديات مساعدة خميس!\n"
"إذا شعرت بأن اسمك مفقود هنا فراسلنا أيضًا رجاءً!"
-#: main.cpp:193
+#: main.cpp:194
msgid "Your name here?"
msgstr "اسمك هنا؟"
-#: main.cpp:196 rc.cpp:1
+#: main.cpp:197 rc.cpp:1
msgctxt "NAME OF TRANSLATORS"
msgid "Your names"
msgstr "محمد عَصَر, عبدالعزيز الشريف, مأمون ديرانية"
-#: main.cpp:197
+#: main.cpp:198
msgctxt "EMAIL OF TRANSLATORS"
msgid "Your email addresses"
msgstr "aser@arabeyes.org, a. a-a.s@hotmail.com, mamoun.diraneyya@gmail.com"
-#: main.cpp:203
+#: main.cpp:204
msgid "Do not show the contact list window initially"
msgstr "لا تظهر نافذة لائحة المتراسلين ابتدائيًا"
-#: main.cpp:204
+#: main.cpp:205
msgid "Autologin with the given email address"
msgstr "ولوج آلي بالبريد المُعطى"
-#: main.cpp:209
+#: main.cpp:210
msgid "Run a debug test (developer build only)"
msgstr "أجرِ اختبارًا تنقيحيًّا (نسخة المطورين فقط)"
-#: main.cpp:211
+#: main.cpp:212
msgid ""
"Connect to the specified server instead of the official Live server.\n"
"Use \"localhost\" or \"127.0.0.1\" to connect to a local KMess Test Server."
@@ -3562,24 +3577,24 @@ msgstr "خطأ في MSN"
msgid "Trying the HTTP fallback..."
msgstr "يجرِّب احتياطيَّ HTTP..."
-#: network/msnnotificationconnection.cpp:1446
+#: network/msnnotificationconnection.cpp:1464
msgid "Authenticating..."
msgstr "يستوثق..."
-#: network/msnnotificationconnection.cpp:1470
+#: network/msnnotificationconnection.cpp:1488
msgid "Authenticated"
msgstr "استوثق"
-#: network/msnnotificationconnection.cpp:1928
+#: network/msnnotificationconnection.cpp:1947
msgid "Connecting..."
msgstr "يتصل..."
-#: network/msnnotificationconnection.cpp:2073
+#: network/msnnotificationconnection.cpp:2092
#, kde-format
msgid "Unknown command received from the server: %1"
msgstr "استُقبِل أمر مجهول من الخادوم: %1"
-#: network/msnnotificationconnection.cpp:2233
+#: network/msnnotificationconnection.cpp:2252
#, kde-format
msgctxt "Time left before server maintenance"
msgid "%1 minute"
@@ -3591,69 +3606,69 @@ msgstr[3] "%1 دقائقٍ"
msgstr[4] "%1 دقيقة"
msgstr[5] "%1 دقيقة"
-#: network/msnnotificationconnection.cpp:2236
+#: network/msnnotificationconnection.cpp:2255
#, kde-format
msgid "Server closes for maintenance in %1!"
msgstr "سيُغلق الخادوم للصيانة في غضون %1!"
-#: network/msnnotificationconnection.cpp:2241
+#: network/msnnotificationconnection.cpp:2260
#, kde-format
msgctxt "Server maintenance dialog box text"
msgid "The Live Messenger server will be going down in %1 for maintenance."
msgstr "سيُغلق خادوم مِرسال لايف بعد %1 للصيانة."
-#: network/msnnotificationconnection.cpp:2442
+#: network/msnnotificationconnection.cpp:2461
#, kde-format
msgid "KMess could not process Offline-IM messages.
Details: %1"
msgstr "تعذَّرت على خميس معالجة الرسائل دون اتصال.
التفاصيل: %1"
-#: network/msnnotificationconnection.cpp:2443
+#: network/msnnotificationconnection.cpp:2462
msgid "SOAP client is no longer valid."
msgstr "عميل SOAP لم يعد صالحًا."
-#: network/msnnotificationconnection.cpp:2721
+#: network/msnnotificationconnection.cpp:2740
msgid "Authentication time limit exceeded"
msgstr "انتهت مهلة الاستيثاق"
-#: network/msnnotificationconnection.cpp:2903
+#: network/msnnotificationconnection.cpp:2922
msgid "Waiting for contact list..."
msgstr "ينتظر قائمة المتراسلين..."
-#: network/msnnotificationconnection.cpp:2949
+#: network/msnnotificationconnection.cpp:2968
#, kde-format
msgctxt "Connection warning: dialog box with message"
msgid "Warning: %1
"
msgstr "تحذير: %1
"
-#: network/msnnotificationconnection.cpp:2950
+#: network/msnnotificationconnection.cpp:2969
msgctxt "Error dialog box title"
msgid "MSN Warning"
msgstr "تحذير من MSN"
-#: network/msnnotificationconnection.cpp:3022
+#: network/msnnotificationconnection.cpp:3041
#, kde-format
msgid "
Internal error reason: %1"
msgstr "
سبب الخطأ الداخلي: %1"
-#: network/msnnotificationconnection.cpp:3083
+#: network/msnnotificationconnection.cpp:3102
msgctxt "Connection error: dialog box"
msgid ""
"Authentication has failed, please verify your account email and password."
"
"
msgstr "فشل الاستيثاق، تحقَّق من فضلك من اسم حسابك وكلمة السر.
"
-#: network/msnnotificationconnection.cpp:3085
+#: network/msnnotificationconnection.cpp:3104
msgctxt "Error dialog box title"
msgid "MSN Error"
msgstr "خطأ في MSN"
-#: network/msnnotificationconnection.cpp:3096
+#: network/msnnotificationconnection.cpp:3115
#, kde-format
msgctxt "Connection error: passive notification message"
msgid "The account %1 has been connected from another location.
"
msgstr "اتصل الحساب %1 من مكان ثانٍ.
"
-#: network/msnnotificationconnection.cpp:3099
+#: network/msnnotificationconnection.cpp:3118
#, kde-format
msgctxt "Connection error: detailed message"
msgid ""
@@ -3663,7 +3678,7 @@ msgstr ""
"لم تعد متصلاً: لقد اتصلت بالحساب %1 من عميل مرسال ثانٍ، أو من مكان "
"ثانٍ.
"
-#: network/msnnotificationconnection.cpp:3111
+#: network/msnnotificationconnection.cpp:3130
msgctxt "Connection error: passive notification message"
msgid ""
"Unable to connect to the Live Messenger service.
Maybe you need to "
@@ -3672,7 +3687,7 @@ msgstr ""
"
عاجز عن الاتصال بخدمة مرسال لايف.
ربما أنت بحاجة لتستوثق قبل أن "
"تستطيع النفاذ إلى الشبكة؟
"
-#: network/msnnotificationconnection.cpp:3114
+#: network/msnnotificationconnection.cpp:3133
#, kde-format
msgctxt "Connection error: detailed message"
msgid ""
@@ -3687,25 +3702,25 @@ msgstr ""
"أن يكون الاستيثاق إلى صفحة وِب أو وسيط مطلوبًا للنفاذ إلى الشبكة.
انقر هنا لزيارة صفحة حالة خدمة المرسال.
"
-#: network/msnnotificationconnection.cpp:3127
+#: network/msnnotificationconnection.cpp:3146
msgid ""
"Unable to resolve the authentication on the client
Maybe you do not "
"have installed qca2 and/or qca2-plugin-ossl?
"
msgstr ""
-#: network/msnnotificationconnection.cpp:3129
+#: network/msnnotificationconnection.cpp:3148
msgid ""
"KMess could not connect to the Live Messenger servers.
You probably "
"need to install qca2 and qca2-plugin-ossl to make KMess work.
It is also "
"possible that the MSN network is unavailable at the moment.
"
msgstr ""
-#: network/msnnotificationconnection.cpp:3144
+#: network/msnnotificationconnection.cpp:3163
msgctxt "Connection error: passive notification message"
msgid "Unable to connect to the Live Messenger service.
"
msgstr "عاجز عن الاتصال بخدمة مرسال لايف.
"
-#: network/msnnotificationconnection.cpp:3146
+#: network/msnnotificationconnection.cpp:3165
#, kde-format
msgctxt "Connection error: detailed message"
msgid ""
@@ -3715,67 +3730,67 @@ msgid ""
"Messenger service status page."
msgstr ""
"تعذَّر على خميس الاتصال بخواديم مرسال لايف.
ربما تكون هناك مشكلة "
-"باتصالك بالإنترنت، أو أن خواديم مرسال لايف غير متاحة مؤقتًا.
انقر هنا لزيارة صفحة حالة خدمة المرسال.
"
+"باتصالك بالإنترنت، أو أن خواديم مرسال لايف غير متاحة مؤقتًا.انقر هنا لزيارة صفحة حالة خدمة المرسال.
"
-#: network/msnnotificationconnection.cpp:3157
+#: network/msnnotificationconnection.cpp:3176
#, kde-format
msgctxt ""
"Connection error (Server-reported user error): passive notification message"
msgid "Error: %1
"
msgstr "خطأ: %1
"
-#: network/msnnotificationconnection.cpp:3159
+#: network/msnnotificationconnection.cpp:3178
#, kde-format
msgctxt "Connection error (Server-reported user error): detailed message"
msgid "The Live Messenger server has reported an error:
%1
"
msgstr "أُبلِغ خادوم مرسال لايف عن خطأ:
%1
"
-#: network/msnnotificationconnection.cpp:3170
+#: network/msnnotificationconnection.cpp:3189
#, kde-format
msgctxt ""
"Connection error (Server-reported server error): passive notification message"
msgid "Messenger Service Error: %1
"
msgstr "خطأ في خدمة المرسال: %1
"
-#: network/msnnotificationconnection.cpp:3172
+#: network/msnnotificationconnection.cpp:3191
#, kde-format
msgctxt "Connection error (Server-reported server error): detailed message"
msgid "The Live Messenger server has reported an error:
%1
"
msgstr "أُبلِغ خادوم مرسال لايف عن خطأ:
%1
"
-#: network/msnnotificationconnection.cpp:3180
+#: network/msnnotificationconnection.cpp:3199
#, kde-format
msgctxt ""
"Connection error (Server-reported client error): passive notification message"
msgid "KMess Error: %1
"
msgstr "خطأ في خميس: %1
"
-#: network/msnnotificationconnection.cpp:3182
+#: network/msnnotificationconnection.cpp:3201
#, kde-format
msgctxt "Connection error (Server-reported client error): detailed message"
msgid "KMess has encountered an internal error:
%1
"
msgstr "صادف خميس خطأ داخليًا:
%1
"
-#: network/msnnotificationconnection.cpp:3193
+#: network/msnnotificationconnection.cpp:3212
msgctxt "Connection error: passive notification message"
msgid "Network connection lost.
"
msgstr "فُقد اتصال الشبكة.
"
-#: network/msnnotificationconnection.cpp:3195
+#: network/msnnotificationconnection.cpp:3214
msgctxt "Connection error: detailed message"
msgid "Connection to the Live Messenger server has been lost.
"
msgstr "فُقد الاتصال بخادوم مرسال لايف.
"
-#: network/msnnotificationconnection.cpp:3251
+#: network/msnnotificationconnection.cpp:3270
#, kde-format
msgctxt "Developer details placed on the network error dialog box"
msgid ""
"Developer info:
Error number: %1
Error string:"
"i> %2
"
msgstr ""
-"معلومات المطور:
رقم الخطأ: %1
جملة الخطأ: %"
-"2
"
+"معلومات المطور:
رقم الخطأ: %1
جملة الخطأ: "
+"%2
"
#: network/msnsocketbase.cpp:135
msgctxt "Dialog box message"
@@ -3817,13 +3832,13 @@ msgstr[5] ""
msgid "The connection to the server was lost"
msgstr "فُقد الاتصال بالخادوم."
-#: network/soap/addressbookservice.cpp:783
+#: network/soap/addressbookservice.cpp:793
#, kde-format
msgctxt "Warning message"
msgid "The specified email address, \"%1\", is not a valid email address!"
msgstr "عنوان البريد المُحدَّد \"%1\" ليس عنوان بريد إلكتروني صالحًا!"
-#: network/soap/addressbookservice.cpp:793
+#: network/soap/addressbookservice.cpp:803
#, kde-format
msgctxt "Error message"
msgid ""
@@ -3831,42 +3846,42 @@ msgid ""
"account!"
msgstr "عنوان البريد المُحدَّد \"%1\" لا ينتمي إلى حسابات مرسال لايف!"
-#: network/soap/addressbookservice.cpp:801
-#: network/soap/addressbookservice.cpp:824
-#: network/soap/httpsoapconnection.cpp:296
+#: network/soap/addressbookservice.cpp:811
+#: network/soap/addressbookservice.cpp:834
+#: network/soap/httpsoapconnection.cpp:297
#, kde-format
msgctxt "Error message (system-generated description)"
msgid "Invalid web service request (%1)"
msgstr "طلب خدمة وِب غير صالح (%1)"
-#: network/soap/httpsoapconnection.cpp:433
+#: network/soap/httpsoapconnection.cpp:434
#, kde-format
msgctxt "Error message (system-generated description)"
msgid "The web service is not accessible (%1)"
msgstr "لا يُمكن النفاذ إلى خدمة الوِب (%1)"
-#: network/soap/httpsoapconnection.cpp:514
+#: network/soap/httpsoapconnection.cpp:518
msgctxt "Error message"
msgid "Too many redirections by web service"
msgstr "إعادات توجيه خدمة الوِب كثيرة جدًا"
-#: network/soap/httpsoapconnection.cpp:558
+#: network/soap/httpsoapconnection.cpp:562
msgctxt "Warning message"
msgid "The Offline Messages web service is currently not available"
msgstr "خدمة وِب الرسائل دون اتصال غير متاحة حاليًا"
-#: network/soap/httpsoapconnection.cpp:564
+#: network/soap/httpsoapconnection.cpp:568
msgctxt "Warning message"
msgid "The Live Messenger web service is experiencing problems"
msgstr "خدمة وِب مرسال لايف تواجه مشكلات"
-#: network/soap/httpsoapconnection.cpp:578
+#: network/soap/httpsoapconnection.cpp:582
#, kde-format
msgctxt "Error message with description (system-generated description)"
msgid "Invalid web service response %1 (%2)"
msgstr "استجابة خدمة وِب غير صالحة %1 (%2)"
-#: network/soap/httpsoapconnection.cpp:617
+#: network/soap/httpsoapconnection.cpp:621
msgctxt "Error message"
msgid "No response from web service"
msgstr "لا استجابة من خدمة الوِب"
@@ -4012,38 +4027,123 @@ msgstr "%1
على الهاتف"
msgid "%1
is out for lunch"
msgstr "%1
خارج للغداء"
+#: notification/macnotification.cpp:61
+msgid "Contact changed status"
+msgstr ""
+
+#: notification/macnotification.cpp:66
+#, fuzzy
+msgid "You received a new e-mail message"
+msgstr "لا رسائل بريدية جديدة"
+
+#: notification/macnotification.cpp:72
+msgid "A contact nudged you!"
+msgstr ""
+
+#: notification/macnotification.cpp:78
+msgid "A contact started a chat with you"
+msgstr ""
+
+#: notification/macnotification.cpp:84
+#, fuzzy
+msgid "A contact messaged you"
+msgstr "لمتراسلي المجموعة نفسها"
+
+#: notification/macnotification.cpp:90
+#, fuzzy
+msgid "A contact came online"
+msgstr "هذا المتراسل ليس متصلاً"
+
+#: notification/macnotification.cpp:96
+#, fuzzy
+msgid "A contact went offline"
+msgstr "هذا المتراسل ليس متصلاً"
+
+#: notification/macnotification.cpp:102
+msgid "A contact changed status"
+msgstr ""
+
+#: notification/macnotification.cpp:107
+#, fuzzy
+msgid "KMess notification"
+msgstr "أيقونة خميس"
+
#: notification/newemailnotification.cpp:92
#, kde-format
msgctxt "%1 is the subject of the mail, %2 is the sender of the mail"
msgid "New email:
'%1'
by '%2'"
msgstr "رسالة بريدية جديدة:
'%1'
من '%2'"
-#: notification/notificationmanager.cpp:114
+#: notification/newsystemtraywidget.cpp:94
+#, fuzzy
+msgid ""
+"Closing the main window will keep KMess running in the system tray."
+"p>
You can open KMess again by clicking on the bird icon, which is now "
+"flashing.
Use 'Quit' from the 'Connect' menu to quit the application.
"
+msgstr ""
+"إغلاق النافذة الرئيسية سيُبقي خميس عاملاً في صينية النظام. استخدم 'أنهِ' من "
+"قائمة 'اتصال' لإنهاء التطبيق."
+
+#: notification/newsystemtraywidget.cpp:108
+#: notification/systemtraywidget.cpp:96 notification/systemtraywidget.cpp:195
+#: notification/systemtraywidget.cpp:205
+msgid "Docking in System Tray"
+msgstr "يرتصف في صينية النظام"
+
+#: notification/newsystemtraywidget.cpp:205
+#, fuzzy, kde-format
+msgctxt ""
+"Tray icon text tooltip when connected, %1 is the friendly name, %2 is the "
+"status"
+msgid "Connected as %1 (%2)"
+msgstr "يتصل بـ%1, عبر المنفذ %2"
+
+#: notification/newsystemtraywidget.cpp:209
+#, fuzzy, kde-format
+msgctxt ""
+"Tray icon HTML tooltip when connected, %1 is the friendly name, %2 is the "
+"status"
+msgid "Connected as:
%1 (%2)
"
+msgstr "
%1 (%2)"
+
+#: notification/newsystemtraywidget.cpp:216
+#, fuzzy
+msgctxt "Tray icon text tooltip when not connected"
+msgid "Not connected"
+msgstr "متصل"
+
+#: notification/newsystemtraywidget.cpp:219
+#, fuzzy
+msgctxt "Tray icon HTML tooltip when not connected"
+msgid "Not connected
"
+msgstr "فُقد اتصال الشبكة.
"
+
+#: notification/notificationmanager.cpp:120
msgctxt "Button text for KDE notification boxes"
msgid "Start Chatting"
msgstr "ابدأ محادثة"
-#: notification/notificationmanager.cpp:118
+#: notification/notificationmanager.cpp:124
msgctxt "Button text for KDE notification boxes"
msgid "Leave a Message"
msgstr "اترك رسالة"
-#: notification/notificationmanager.cpp:122
+#: notification/notificationmanager.cpp:128
msgctxt "Button text for KDE notification boxes"
msgid "View Message"
msgstr "اعرض الرسالة"
-#: notification/notificationmanager.cpp:126
+#: notification/notificationmanager.cpp:132
msgctxt "Button text for KDE notification boxes"
msgid "Details"
msgstr "التفاصيل"
-#: notification/notificationmanager.cpp:130
+#: notification/notificationmanager.cpp:136
msgctxt "Button text for KDE notification boxes"
msgid "Read Email"
msgstr "اقرأ البريد"
-#: notification/notificationmanager.cpp:134
+#: notification/notificationmanager.cpp:140
msgctxt "Button text for KDE notification boxes"
msgid "Hide"
msgstr "أخفِ"
@@ -4056,11 +4156,6 @@ msgstr ""
"إغلاق النافذة الرئيسية سيُبقي خميس عاملاً في صينية النظام. استخدم 'أنهِ' من "
"قائمة 'اتصال' لإنهاء التطبيق."
-#: notification/systemtraywidget.cpp:96 notification/systemtraywidget.cpp:195
-#: notification/systemtraywidget.cpp:205
-msgid "Docking in System Tray"
-msgstr "يرتصف في صينية النظام"
-
#: notification/systemtraywidget.cpp:248
#, fuzzy, kde-format
msgctxt "Tray icon tooltip showing the KMess version"
@@ -4091,21 +4186,21 @@ msgctxt "Tray icon email count, text version"
msgid " - %1 emails"
msgstr "aser@arabeyes.org, a. a-a.s@hotmail.com, mamoun.diraneyya@gmail.com"
-#: settings/accountpage.cpp:81
+#: settings/accountpage.cpp:83
msgid "Browse..."
msgstr "تصفَّح..."
-#: settings/accountpage.cpp:82
+#: settings/accountpage.cpp:84
msgid "Browse and Crop Picture..."
msgstr "تصفَّح واقتطع صورة..."
-#: settings/accountpage.cpp:83
+#: settings/accountpage.cpp:85
msgid "Set Previous Image..."
msgstr "عيِّن الصورة السابقة..."
#. i18n: file: settings/accountpage.ui:133
#. i18n: ectx: property (title), widget (QGroupBox, groupBox_2)
-#: settings/accountpage.cpp:459 rc.cpp:389
+#: settings/accountpage.cpp:466 rc.cpp:389
msgid "Display Picture"
msgstr "صورة العرض"
@@ -6351,6 +6446,10 @@ msgstr ""
"تقريرك، أو ليخبروك عن موعد إنجاز الميزة التي طلبتها.
\n"
"لن يُستخدم عنوان بريدك لأي غرض سوى هذا التقرير.