diff --git a/.gitignore b/.gitignore index 8d709c1..cfe59ac 100644 --- a/.gitignore +++ b/.gitignore @@ -1,43 +1,45 @@ *.lo *.o .deps/ .libs/ /aclocal.m4 /autom4te.cache /config.h.in /config.h /config.log /config.status /configure /Makefile.in autom4te.cache/ assuan/Makefile.in assuan/Makefile curses/Makefile.in curses/Makefile doc/Makefile.in doc/Makefile doc/pinentry.info doc/stamp-vti doc/version.texi fltk/Makefile.in fltk/Makefile gtk+-2/Makefile.in gtk+-2/Makefile gnome3/Makefile.in gnome3/Makefile pinentry/Makefile.in pinentry/Makefile qt/Makefile.in qt/Makefile +tqt/Makefile.in +tqt/Makefile secmem/Makefile.in secmem/Makefile w32/Makefile.in w32/Makefile tty/Makefile.in tty/Makefile /qt/pinentryconfirm.moc /qt/pinentrydialog.moc /qt/qsecurelineedit.moc /m4/Makefile.in /emacs/Makefile.in diff --git a/Makefile.am b/Makefile.am index e11b009..8c8b8e5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,123 +1,130 @@ # Makefile.am # Copyright (C) 2002, 2012, 2015 g10 Code GmbH # # This file is part of PINENTRY. # # PINENTRY is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PINENTRY 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 General Public License # along with this program; if not, see . # SPDX-License-Identifier: GPL-2.0+ ## Process this file with automake to produce Makefile.in ACLOCAL_AMFLAGS = -I m4 DISTCHECK_CONFIGURE_FLAGS = --disable-pinentry-qt --enable-pinentry-emacs GITLOG_TO_CHANGELOG=gitlog-to-changelog EXTRA_DIST = autogen.sh autogen.rc README.GIT ChangeLog-old \ build-aux/gitlog-to-changelog \ build-aux/git-log-fix build-aux/git-log-footer if BUILD_PINENTRY_CURSES pinentry_curses = curses else pinentry_curses = endif if BUILD_PINENTRY_TTY pinentry_tty = tty else pinentry_tty = endif if BUILD_PINENTRY_EMACS pinentry_emacs = emacs else pinentry_emacs = endif if BUILD_PINENTRY_GTK_2 pinentry_gtk_2 = gtk+-2 else pinentry_gtk_2 = endif if BUILD_PINENTRY_GNOME_3 pinentry_gnome_3 = gnome3 else pinentry_gnome_3 = endif if BUILD_PINENTRY_QT pinentry_qt = qt else pinentry_qt = endif +if BUILD_PINENTRY_TQT +pinentry_tqt = tqt +else +pinentry_tqt = +endif + if BUILD_PINENTRY_W32 pinentry_w32 = w32 else pinentry_w32 = endif if BUILD_PINENTRY_FLTK pinentry_fltk = fltk else pinentry_fltk = endif SUBDIRS = m4 secmem pinentry ${pinentry_curses} ${pinentry_tty} \ ${pinentry_emacs} ${pinentry_gtk_2} ${pinentry_gnome_3} \ - ${pinentry_qt} ${pinentry_w32} ${pinentry_fltk} doc + ${pinentry_qt} ${pinentry_tqt} ${pinentry_w32} \ + ${pinentry_fltk} doc install-exec-local: @list='$(bin_PROGRAMS)'; for p in $$list; do \ echo " $(SETCAP) cap_ipc_lock+p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ $(SETCAP) cap_ipc_lock+p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'` || true; \ done (cd $(DESTDIR)$(bindir); \ rm -f pinentry; \ $(LN_S) $(PINENTRY_DEFAULT)$(EXEEXT) pinentry) dist-hook: gen-ChangeLog echo "$(VERSION)" > $(distdir)/VERSION distcheck-hook: set -e; ( \ pref="#+macro: pinentry_" ;\ reldate="$$(date -u +%Y-%m-%d)" ;\ echo "$${pref}ver $(PACKAGE_VERSION)" ;\ echo "$${pref}date $${reldate}" ;\ list='$(DIST_ARCHIVES)'; for i in $$list; do \ case "$$i" in *.tar.bz2) \ echo "$${pref}size $$(wc -c <$$i|awk '{print int($$1/1024)}')k" ;\ echo "$${pref}sha1 $$(sha1sum <$$i|cut -d' ' -f1)" ;\ echo "$${pref}sha2 $$(sha256sum <$$i|cut -d' ' -f1)" ;;\ esac;\ done ) | tee $(distdir).swdb gen_start_date = 2012-08-08T00:00:00 .PHONY: gen-ChangeLog gen-ChangeLog: if test -d $(top_srcdir)/.git; then \ (cd $(top_srcdir) && \ $(GITLOG_TO_CHANGELOG) --append-dot --tear-off \ --amend=build-aux/git-log-fix \ --since=$(gen_start_date) ) > $(distdir)/cl-t; \ cat $(top_srcdir)/build-aux/git-log-footer >> $(distdir)/cl-t;\ rm -f $(distdir)/ChangeLog; \ mv $(distdir)/cl-t $(distdir)/ChangeLog; \ fi diff --git a/NEWS b/NEWS index 5534d4d..b1976c3 100644 --- a/NEWS +++ b/NEWS @@ -1,363 +1,365 @@ Noteworthy changes in version 1.0.1 (unreleased) ------------------------------------------------ * A FLTK1.3-based pinentry has been contributed. + * A TQt3-based pinentry has been contributed. + * New option --ttyalert for pinentry-curses to alert the user. * Don't show "save passphrase" checkbox if secret service is unavailable. Noteworthy changes in version 1.0.0 (2016-11-22) ------------------------------------------------ * Qt pinentry now supports repeat mode in one dialog. * Qt and GTK pinentries now make it possible to show the entered value. * Qt pinentry now only grabs the keyboard if an entry field is focused. * Fixed foreground handling in pinentry-qt if compiled with Qt5 for Windows. * Fixed potential crash in Qt qualitybar calculation. * GTK keyboard grabbing is now a bit more robust. The cursor is changed to a big dot as a visual indication that a pinentry has popped up and is waiting for input. * The GNOME pinentry now falls back to curses if it can't use the GCR system prompter or a screenlock is active. * Fixed error output for cached passwords. * A show/hide passphrase button or checkbox is now available with some pinentry flavors. * Improved diagnostics and error codes. Noteworthy changes in version 0.9.7 (2015-12-07) ------------------------------------------------ * Fix regressions in the Qt pinentry. * Fix minor problems pinnetyr-tty. * New option --invisible-char. Noteworthy changes in version 0.9.6 (2015-09-10) ------------------------------------------------ * Many improvements for the dump tty pinentry. * Use the standard GTK+-2 text entry widget instead of our outdated and back-then-it-was-more-secure text widget. * Use the standard Qt text widget. * Allow for building a static Qt variant. * Fix regression in w32 pinentry. Noteworthy changes in version 0.9.5 (2015-07-01) ------------------------------------------------ * Replaced the internal Assuan and gpg-error code by the standard libassuan and libgpg-error libraries. * Add a new Emacs pinentry and use as fallback for GUI programs. * gnome3: The use-password-manager checkbox does now work. * Gtk: Improved fallback to curses feature. * curses: Recognize DEL as backspace. Noteworthy changes in version 0.9.4 (2015-06-05) ------------------------------------------------ * Fix regression in GTK+ and curses pinentries. Noteworthy changes in version 0.9.3 (2015-06-01) ------------------------------------------------ * Improved documentation * New pinentry-gnome3 * More improvements for pinentry-tty. * Fixes for pinentry-curses including support for Ctrl-W, Ctrl-U, Ctrl-H, Ctrl-L, and Alt-Backspace * New Assuan command to request clearing an external cache. * Fixed problems linking to ncursesw. * All kind of other minor fixes. Noteworthy changes in version 0.9.2 (2015-05-11) ------------------------------------------------ * Support for saving the passphrase with libsecret. * Escape key works in the Gtk+ pinentry. * Improvements for pinentry-tty. * Minor cleanups for the native Windows pinentry. Noteworthy changes in version 0.9.1 (2015-03-18) ------------------------------------------------ * Fixed build problems for systems without ncurses. * Reworked the option parser to allow building on systems without getopt_long. * Fixed Qt4 build problems. Noteworthy changes in version 0.9.0 (2014-10-26) ------------------------------------------------ * New command SETREPEAT. Currently only supported for Gtk+-2. * Gtk+-2: Pasting using the mouse is now supported. * curses: Check that it is actually connected to a tty. * Removed the old qt-3 and gtk+-1 pinentries. Noteworthy changes in version 0.8.4 (2014-09-18) ------------------------------------------------ * New pinentry-tty version for dumb terminals. * Qt4: New option to enable pasting the passphrase from clipboard * Qt4: Improved accessiblity * Qt4: Raise confirm message windows into foreground * Qt4 (Windows): Improve the way pinentry-qt raises itself in the foreground. * Improved the build system. Noteworthy changes in version 0.8.3 (2013-04-26) ------------------------------------------------ * Build fixes for newer mingw32 toolchains. * Add SETTIMEOUT command for the gtk+-2 pinentry. Noteworthy changes in version 0.8.2 (2012-08-08) ------------------------------------------------ * New SETTIMEOUT command for the qt4 pinentry. * Wide character support for the curses pinentry. * Various bug fixes. Noteworthy changes in version 0.8.1 (2010-12-16) ------------------------------------------------ * The W32 pinentry now supports WindowsCE. * The GTK pinentry now always sticks to the top and properly grabs the keyboard. * The protocol options default-cancel and default-ok now work for the pinentry-gtk2 and pinentry-qt (that is QT3). Noteworthy changes in version 0.8.0 (2010-03-03) ------------------------------------------------ * Beautified the qt4 pinentry * Minor enhancements. Noteworthy changes in version 0.7.6 (2009-06-19) ------------------------------------------------ * Make Gtk+-2 pinentry transient to the root window. * Add Qt4 pinentry. * Add native W32 pinentry. * Fix utf-8 problem in Qt pinentries. * Return GPG_ERR_CANCELED if during a "CONFIRM" command the user closed the window. * Add quality bar. Noteworthy changes in version 0.7.5 (2008-02-15) ------------------------------------------------ * Fix cross compilation for Gtk+-2 pinentry. * New Assuan command GETINFO with subcommands "version" and "pid". Noteworthy changes in version 0.7.4 (2007-11-29) ------------------------------------------------ * Pinentry-gtk-2 and pinentry-qt now support a simple passphrase quality indicator. Noteworthy changes in version 0.7.3 (2007-07-06) ------------------------------------------------ * New command MESSAGE and --one-button compatibility option to CONFIRM. * New Assuan option touch-file to set a file which will be touched after ncurses does not need the display anymore. * New option --colors=FG,BG,SO to set the colors for the curses pinentry. * Pinentry-w32 does now basically work. It needs some finishing though. For example the buttons should resize themself according to the size of the text. Noteworthy changes in version 0.7.2 (2005-01-27) ------------------------------------------------ * Remove bug in configure script that would use installed version of Qt even if another path was explicitely specified with QTDIR. * Honor the rpath setting for Qt. * Add GTK+-2 pinentry. * Install a symbolic link under the name "pinentry" that defaults to pinentry-gtk, pinentry-qt, pinentry-gtk-2, or pinentry-curses, in that order. Noteworthy changes in version 0.7.1 (2004-04-21) ------------------------------------------------ * Removed unneeded Assuan cruft. * Fixes for *BSD. Noteworthy changes in version 0.7.0 (2003-12-23) ------------------------------------------------ * Make UTF8 description (prompt, error message, button texts) work. * Make sure that secmem_term is called before program termination. * Make assuan in Gtk and Curses pinentry use secure memory for storage. * Fixed a bug that would occur if a canceled GETPIN was immediately followed by a CONFIRM. * Disabled undo/redo in Qt pinentry. * Print diagnostics for locale problems and return a new error code in that case. Noteworthy changes in version 0.6.8 (2003-02-07) ------------------------------------------------ * Bug fix in pinentry-qt. Noteworthy changes in version 0.6.7 (2002-11-20) ------------------------------------------------ * Workaround for a bug in the curses version which led to an infinite loop. Noteworthy changes in version 0.6.6 (2002-11-09) ------------------------------------------------ * Fixed handling of DISPLAY and --display for the sake of the curses fallback. * UTF-8 conversion does now work for the GTK+ and CURSES version. Noteworthy changes in version 0.6.5 (2002-09-30) ------------------------------------------------ * Handle Assuan options in the qt version. Noteworthy changes in version 0.6.4 (2002-08-19) ------------------------------------------------ * Handle CONFIRM command in the qt version. Noteworthy changes in version 0.6.3 (2002-06-26) ------------------------------------------------ * Minor bug fixes to the qt version. Noteworthy changes in version 0.6.2 (2002-05-13) ------------------------------------------------ * Error texts can now be percent-escaped. * The Curses pinentry supports multi-line error texts. * The GTK+ and Qt pinentry can fall back to curses if no display is available. Noteworthy changes in version 0.6.1 (2002-04-25) ------------------------------------------------ * The Curses pinentry supports user-provided button texts via the new SETOK and SETCANCEL commands. * The Curses pinentry supports setting the desired character set locale with --lc-ctype and correctly translates the UTF-8 strings into that. Noteworthy changes in version 0.6.0 (2002-04-05) ------------------------------------------------ * Merged all pinentry frontends into a single module. * There is now a Curses frontend. * The curses pinentry supports --ttyname and --ttytype options to set the desired input/output terminal and its type. Noteworthy changes in version 0.5.1 (2002-02-18) ------------------------------------------------ * CONFIRM command works Noteworthy changes in version 0.5.0 (2002-01-04) ------------------------------------------------ * Window layout is somewhat nicer * percent escape sequences do now work for SETDESC and SETERROR diff --git a/configure.ac b/configure.ac index 3de0882..86cf98b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,718 +1,760 @@ # configure.ac # Copyright (C) 1999 Robert Bihlmeyer # Copyright (C) 2001, 2002, 2003, 2004, 2007, 2015, 2016 g10 Code GmbH # # This file is part of PINENTRY. # # PINENTRY is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PINENTRY 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 General Public License # along with this program; if not, see . # SPDX-License-Identifier: GPL-2.0+ # (Process this file with autoconf to produce a configure script.) AC_PREREQ(2.69) min_automake_version="1.14" # To build a release you need to create a tag with the version number # (git tag -s pinentry-n.m.k) and run "./autogen.sh --force". Please # bump the version number immediately after the release, do another # commit, and a push so that the git magic is able to work. m4_define(mym4_version, [1.0.1]) # Below is m4 magic to extract and compute the git revision number, # the decimalized short revision number, a beta version string and a # flag indicating a development version (mym4_isgit). Note that the # m4 processing is done by autoconf and not during the configure run. m4_define([mym4_revision], m4_esyscmd([git branch -v 2>/dev/null \ | awk '/^\* / {printf "%s",$3}'])) m4_define([mym4_revision_dec], m4_esyscmd_s([echo $((0x$(echo ]mym4_revision[|head -c 4)))])) m4_define([mym4_betastring], m4_esyscmd_s([git describe --match 'pinentry-[0-9].[0-9].*[0-9]' \ --long| awk -F- '$3!=0{print"-beta"$3}'])) m4_define([mym4_isgit],m4_if(mym4_betastring,[],[no],[yes])) m4_define([mym4_full_version],[mym4_version[]mym4_betastring]) AC_INIT([pinentry],[mym4_full_version], [https://bugs.gnupg.org]) AC_CONFIG_AUX_DIR([build-aux]) AM_CONFIG_HEADER(config.h) AC_CONFIG_SRCDIR(pinentry/pinentry.h) AM_INIT_AUTOMAKE([serial-tests dist-bzip2 no-dist-gzip]) AC_GNU_SOURCE AM_MAINTAINER_MODE AC_CANONICAL_HOST AH_TOP([ #ifndef PINENTRY_CONFIG_H_INCLUDED #define PINENTRY_CONFIG_H_INCLUDED /* Enable gpg-error's strerror macro under W32CE. */ #define GPG_ERR_ENABLE_ERRNO_MACROS 1 ]) AH_BOTTOM([ #endif /*PINENTRY_CONFIG_H_INCLUDED*/ ]) dnl Checks for programs. AC_PROG_MAKE_SET AM_SANITY_CHECK missing_dir=`cd $ac_aux_dir && pwd` AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_PROG_RANLIB # We need to check for cplusplus here because we may not do the test # for Qt and autoconf does does not allow that. AC_PROG_CXX AC_PROG_LN_S PKG_PROG_PKG_CONFIG AC_CHECK_TOOL(WINDRES, windres, :) AC_CHECK_PROGS(GITLOG_TO_CHANGELOG, gitlog-to-changelog, [build-aux/gitlog-to-changelog]) have_dosish_system=no have_w32_system=no have_w32ce_system=no case "${host}" in *-mingw32*) AC_DEFINE(USE_ONLY_8DOT3,1, [Set this to limit filenames to the 8.3 format]) have_dosish_system=yes have_w32_system=yes case "${host}" in *-mingw32ce*) have_w32ce_system=yes ;; *) AC_DEFINE(HAVE_DRIVE_LETTERS,1, [Defined if the OS supports drive letters.]) ;; esac ;; i?86-emx-os2 | i?86-*-os2*emx ) # OS/2 with the EMX environment AC_DEFINE(HAVE_DRIVE_LETTERS) have_dosish_system=yes ;; i?86-*-msdosdjgpp*) # DOS with the DJGPP environment AC_DEFINE(HAVE_DRIVE_LETTERS) have_dosish_system=yes ;; esac if test "$have_dosish_system" = yes; then AC_DEFINE(HAVE_DOSISH_SYSTEM,1, [Defined if we run on some of the PCDOS like systems (DOS, Windoze. OS/2) with special properties like no file modes]) fi AM_CONDITIONAL(HAVE_DOSISH_SYSTEM, test "$have_dosish_system" = yes) if test "$have_w32_system" = yes; then AC_DEFINE(HAVE_W32_SYSTEM,1, [Defined if we run on a W32 API based system]) if test "$have_w32ce_system" = yes; then AC_DEFINE(HAVE_W32CE_SYSTEM,1,[Defined if we run on WindowsCE]) fi fi AM_CONDITIONAL(HAVE_W32_SYSTEM, test "$have_w32_system" = yes) AM_CONDITIONAL(HAVE_W32CE_SYSTEM, test "$have_w32ce_system" = yes) dnl Checks for compiler features. if test "$GCC" = yes; then # Check whether gcc does not emit a diagnositc for unknown -Wno-* # options. This is the case for gcc >= 4.6 AC_MSG_CHECKING([if gcc ignores unknown -Wno-* options]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6 ) #kickerror #endif]],[])],[_gcc_silent_wno=yes],[_gcc_silent_wno=no]) AC_MSG_RESULT($_gcc_silent_wno) if test "$USE_MAINTAINER_MODE" = "yes"; then CFLAGS="$CFLAGS -Wall -Wcast-align -Wshadow -Wstrict-prototypes" CFLAGS="$CFLAGS -Wformat -Wno-format-y2k -Wformat-security" if test x"$_gcc_silent_wno" = xyes ; then _gcc_warn=yes else AC_MSG_CHECKING([if gcc supports -Wno-missing-field-initializers]) _gcc_cflags_save=$CFLAGS CFLAGS="-Wno-missing-field-initializers" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])], [_gcc_warn=yes],[_gcc_warn=no]) AC_MSG_RESULT($_gcc_warn) CFLAGS=$_gcc_cflags_save; fi if test x"$_gcc_warn" = xyes ; then CFLAGS="$CFLAGS -W -Wno-sign-compare -Wno-missing-field-initializers" fi AC_MSG_CHECKING([if gcc supports -Wdeclaration-after-statement]) _gcc_cflags_save=$CFLAGS CFLAGS="-Wdeclaration-after-statement" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],_gcc_warn=yes,_gcc_warn=no) AC_MSG_RESULT($_gcc_warn) CFLAGS=$_gcc_cflags_save; if test x"$_gcc_warn" = xyes ; then CFLAGS="$CFLAGS -Wdeclaration-after-statement" fi else # Not in maintainer mode: Use standard warnings. CFLAGS="$CFLAGS -Wall" fi CPPFLAGS="$CPPFLAGS -Wall" if test x"$_gcc_silent_wno" = xyes ; then _gcc_warn=yes else AC_MSG_CHECKING([if gcc supports -Wno-pointer-sign]) _gcc_cflags_save=$CFLAGS CFLAGS="-Wno-pointer-sign" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],[_gcc_warn=yes],[_gcc_warn=no]) AC_MSG_RESULT($_gcc_warn) CFLAGS=$_gcc_cflags_save; fi if test x"$_gcc_warn" = xyes ; then CFLAGS="$CFLAGS -Wno-pointer-sign" fi AC_MSG_CHECKING([if gcc supports -Wpointer-arith]) _gcc_cflags_save=$CFLAGS CFLAGS="-Wpointer-arith" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],[])],_gcc_warn=yes,_gcc_warn=no) AC_MSG_RESULT($_gcc_warn) CFLAGS=$_gcc_cflags_save; if test x"$_gcc_warn" = xyes ; then CFLAGS="$CFLAGS -Wpointer-arith" fi fi # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS(string.h unistd.h langinfo.h termio.h locale.h utime.h wchar.h) dnl Checks for library functions. AC_CHECK_FUNCS(seteuid stpcpy mmap) GNUPG_CHECK_MLOCK dnl Checks for standard types. AC_TYPE_UINT32_T # Common libraries and cflags. COMMON_CFLAGS= COMMON_LIBS= AC_SUBST(COMMON_CFLAGS) AC_SUBST(COMMON_LIBS) dnl Checks for libgpg-error # # libgpg-error is a library with error codes shared between GnuPG # related projects. # NEED_GPG_ERROR_VERSION=1.16 have_gpg_error=no AM_PATH_GPG_ERROR("$NEED_GPG_ERROR_VERSION", have_gpg_error=yes,have_gpg_error=no) COMMON_CFLAGS="$GPG_ERROR_CFLAGS $COMMON_CFLAGS" COMMON_LIBS="$GPG_ERROR_LIBS $COMMON_LIBS" AC_DEFINE_UNQUOTED(GPG_ERR_ENABLE_GETTEXT_MACROS, 1, [Under Windows we use the gettext code from libgpg-error]) AC_DEFINE_UNQUOTED(GPG_ERR_ENABLE_ERRNO_MACROS, 1, [Under WindowsCE we use the strerror replacement from libgpg-error.]) dnl Checks for libassuan. # # libassuan is used for IPC # NEED_LIBASSUAN_API=2 NEED_LIBASSUAN_VERSION=2.1.0 have_libassuan=no AM_PATH_LIBASSUAN("$NEED_LIBASSUAN_API:$NEED_LIBASSUAN_VERSION", have_libassuan=yes,have_libassuan=no) if test "$have_libassuan" = "yes"; then AC_DEFINE_UNQUOTED(GNUPG_LIBASSUAN_VERSION, "$libassuan_version", [version of the libassuan library]) fi COMMON_CFLAGS="$LIBASSUAN_CFLAGS $COMMON_CFLAGS" COMMON_LIBS="$LIBASSUAN_LIBS $COMMON_LIBS" dnl Checks for libsecmem. GNUPG_CHECK_TYPEDEF(byte, HAVE_BYTE_TYPEDEF) GNUPG_CHECK_TYPEDEF(ulong, HAVE_ULONG_TYPEDEF) dnl Check for libcap AC_ARG_WITH([libcap], AC_HELP_STRING([--without-libcap], [Disable support for capabilities library])) if test "x$with_libcap" != "xno"; then AC_PATH_PROG(SETCAP, setcap, :, "$PATH:/sbin:/usr/sbin") AC_CHECK_LIB(cap, cap_set_proc, [ AC_DEFINE(USE_CAPABILITIES,1,[The capabilities support library is installed]) LIBCAP=-lcap ]) fi AC_SUBST(LIBCAP) dnl dnl Check for curses pinentry program. dnl AC_ARG_ENABLE(pinentry-curses, AC_HELP_STRING([--enable-pinentry-curses], [build curses pinentry]), pinentry_curses=$enableval, pinentry_curses=maybe) AC_ARG_ENABLE(fallback-curses, AC_HELP_STRING([--enable-fallback-curses], [include curses fallback]), fallback_curses=$enableval, fallback_curses=maybe) dnl dnl Checks for curses libraries. Deal correctly with $pinentry_curses = maybe dnl and $fallback_curses = maybe. dnl if test "$pinentry_curses" != "no" -o "$fallback_curses" != "no"; then IU_LIB_CURSES fi if test "$LIBCURSES"; then if test "$pinentry_curses" != "no"; then pinentry_curses=yes fi if test "$fallback_curses" != "no"; then fallback_curses=yes AC_DEFINE(FALLBACK_CURSES, 1, [The GUI pinentries should fall back to curses if X is not available.]) fi else if test "$pinentry_curses" = "yes" -o "$fallback_curses" = "yes"; then AC_MSG_ERROR([[ *** *** The curses library is required. The latest version of *** ncurses is always available from ftp://ftp.gnu.org/gnu/ncurses/. ***]]) fi pinentry_curses=no fallback_curses=no fi AM_CONDITIONAL(BUILD_LIBPINENTRY_CURSES, test "$pinentry_curses" = "yes" -o "$fallback_curses" = "yes") AM_CONDITIONAL(BUILD_PINENTRY_CURSES, test "$pinentry_curses" = "yes") AM_CONDITIONAL(FALLBACK_CURSES, test "$fallback_curses" = "yes") if test "$pinentry_curses" = "yes"; then AC_DEFINE(PINENTRY_CURSES, 1, [The Curses version of Pinentry is to be build]) fi dnl dnl Check for tty pinentry program. dnl AC_ARG_ENABLE(pinentry-tty, AC_HELP_STRING([--enable-pinentry-tty], [build tty pinentry]), pinentry_tty=$enableval, pinentry_tty=maybe) AM_CONDITIONAL(BUILD_PINENTRY_TTY, test "$pinentry_tty" = "yes") if test "$pinentry_tty" = "yes"; then AC_DEFINE(PINENTRY_TTY, 1, [The TTY version of Pinentry is to be build]) fi dnl dnl Additional checks pinentry Curses. dnl if test "$pinentry_curses" = "yes" \ -o "$fallback_curses" = "yes" ; then AM_ICONV if test "$am_cv_func_iconv" != "yes"; then AC_MSG_ERROR([[ *** *** The iconv function is required. You can specify its location *** using the --with-libiconv-prefix=PREFIX option to configure. ***]]) fi fi dnl dnl Check for emacs pinentry program. dnl AC_ARG_ENABLE(pinentry-emacs, AC_HELP_STRING([--enable-pinentry-emacs], [build emacs pinentry]), pinentry_emacs=$enableval, pinentry_emacs=no) AC_ARG_ENABLE(inside-emacs, AC_HELP_STRING([--enable-inside-emacs], [include emacs hack]), inside_emacs=$enableval, inside_emacs=maybe) if test "$pinentry_emacs" != "no" -o "$inside_emacs" != "no"; then AC_MSG_CHECKING([if Unix domain socket is supported]) AC_TRY_COMPILE([ #include #include ], [int s = socket (AF_UNIX, SOCK_STREAM, 0);], [_unixsock_works=yes], [_unixsock_works=no]) AC_MSG_RESULT($_unixsock_works) if test "$_unixsock_works" = "yes"; then if test "$pinentry_emacs" != "no"; then pinentry_emacs=yes fi if test "$inside_emacs" != "no"; then inside_emacs=yes AC_DEFINE(INSIDE_EMACS, 1, [The GUI pinentries should respect INSIDE_EMACS envvar.]) fi else if test "$pinentry_emacs" = "yes" -o "$inside_emacs" = "yes"; then AC_MSG_ERROR([[ *** *** Support for Unix domain sockets is required. ***]]) fi pinentry_emacs=no inside_emacs=no fi fi AM_CONDITIONAL(BUILD_LIBPINENTRY_EMACS, test "$pinentry_emacs" = "yes" -o "$inside_emacs" = "yes") AM_CONDITIONAL(BUILD_PINENTRY_EMACS, test "$pinentry_emacs" = "yes") AM_CONDITIONAL(INSIDE_EMACS, test "$inside_emacs" = "yes") if test "$pinentry_emacs" = "yes"; then AC_DEFINE(PINENTRY_EMACS, 1, [The Emacs version of Pinentry is to be build]) fi dnl dnl Check for GTK+-2 / GNOME3 pinentry programs. dnl AC_ARG_ENABLE(pinentry-gtk2, AC_HELP_STRING([--enable-pinentry-gtk2], [build GTK+-2 pinentry]), pinentry_gtk_2=$enableval, pinentry_gtk_2=maybe) AC_ARG_ENABLE(pinentry-gnome3, AC_HELP_STRING([--enable-pinentry-gnome3], [build GNOME 3 pinentry]), pinentry_gnome_3=$enableval, pinentry_gnome_3=maybe) dnl check if the module gtk+-2.0 exists if test "$pinentry_gtk_2" != "no"; then PKG_CHECK_MODULES( GTK2, [gtk+-2.0 >= 2.4.0], [ test "$pinentry_gtk_2" != "no" && pinentry_gtk_2=yes test "$pinentry_gnome_3" != "no" && pinentry_gnome_3=yes ], [ AC_MSG_WARN([pkg-config could not find the module gtk+-2.0]) pinentry_gtk_2=no ] ) fi AM_CONDITIONAL(BUILD_PINENTRY_GTK_2, test "$pinentry_gtk_2" = "yes") if test "$pinentry_gnome_3" != "no"; then PKG_CHECK_MODULES( GNOME3, [gcr-3,gcr-base-3], [ pinentry_gnome_3=yes AC_DEFINE(GCR_API_SUBJECT_TO_CHANGE, 1, [Nod nod]) ], [ AC_MSG_WARN([pkg-config could not find the module gcr-3,gcr-base-3]) pinentry_gnome_3=no ] ) fi AM_CONDITIONAL(BUILD_PINENTRY_GNOME_3, test "$pinentry_gnome_3" = "yes") dnl dnl Check for libsecret. dnl AC_ARG_ENABLE(libsecret, AC_HELP_STRING([--enable-libsecret], [optionally cache passphrases using libsecret]), libsecret=$enableval, libsecret=maybe) dnl check if the module libsecret exists if test "$libsecret" != "no"; then PKG_CHECK_MODULES( LIBSECRET, [libsecret-1], [libsecret=yes], [ AC_MSG_WARN([pkg-config could not find the module libsecret-1]) libsecret=no ] ) fi AM_CONDITIONAL(BUILD_WITH_LIBSECRET, test "$libsecret" = "yes") if test "$libsecret" = "yes"; then AC_DEFINE(HAVE_LIBSECRET, 1, [The pinentries should optionally cache the passphrase using libsecret.]) COMMON_CFLAGS="$LIBSECRET_CFLAGS $COMMON_CFLAGS" COMMON_LIBS="$LIBSECRET_LIBS $COMMON_LIBS" fi dnl dnl Check for Qt pinentry program. dnl AC_ARG_ENABLE(pinentry-qt, AC_HELP_STRING([--enable-pinentry-qt], [build qt pinentry]), pinentry_qt=$enableval, pinentry_qt=maybe) dnl dnl Checks for qt libraries. Deal correctly with $pinentry_qt = maybe. dnl Tries to find Qt5, falls back on Qt4 dnl if test "$pinentry_qt" != "no"; then FIND_QT if test "$have_qt4_libs" != "yes" -a "$have_qt5_libs" != "yes"; then if test "$pinentry_qt" = "yes"; then AC_MSG_ERROR([[ *** *** Qt4 (QtCore, QtGui) or Qt5 (Qt5Core, Qt5Gui, Qt5Widgets) is required. ***]]) else pinentry_qt=no fi fi fi AC_SUBST(PINENTRY_QT_CFLAGS) AC_SUBST(PINENTRY_QT_LIBS) AC_SUBST(MOC) dnl If we have come so far, qt pinentry can be build. if test "$pinentry_qt" != "no"; then pinentry_qt=yes fi AM_CONDITIONAL(BUILD_PINENTRY_QT, test "$pinentry_qt" = "yes") if test "$pinentry_qt" = "yes"; then AC_DEFINE(PINENTRY_QT, 1, [The qt version of Pinentry is to be build]) if test "$have_qt4_libs" = "yes"; then pinentry_qt_lib_version="(Qt4)" else pinentry_qt_lib_version="(Qt5)" fi fi +dnl +dnl Check for TQt pinentry program. +dnl +AC_ARG_ENABLE(pinentry-tqt, + AC_HELP_STRING([--enable-pinentry-tqt], [build tqt pinentry]), + pinentry_tqt=$enableval, pinentry_tqt=no) + +if test "$pinentry_tqt" != "no"; then + + if test "$pinentry_qt" = "yes"; then + AC_MSG_ERROR([[ + *** + *** Building both Qt and TQt pinentries is not supported. + *** Use --disable-pinentry-qt if you want the TQt pinentry. + ***]]) + fi + + PKG_CHECK_MODULES(PINENTRY_TQT, tqt, + have_tqt_libs=yes, + [PKG_CHECK_MODULES(PINENTRY_TQT, tqt-mt, + have_tqt_libs=yes, have_tqt_libs=no)]) + + if test "$have_tqt_libs" = "yes"; then + AC_CHECK_TOOL([TQT_MOC], tqmoc, "no") + fi + + if test "$have_tqt_libs" = "yes" -a "$TQT_MOC" != "no"; then + pinentry_tqt=yes + else + AC_MSG_WARN([TQt is not found]) + pinentry_tqt=no + fi + +fi +AM_CONDITIONAL(BUILD_PINENTRY_TQT, test "$pinentry_tqt" = "yes") + # # Check whether we should build the W32 pinentry. This is actually # the simplest check as we do this only for that platform. # pinentry_w32=no test $have_w32_system = yes && pinentry_w32=yes AM_CONDITIONAL(BUILD_PINENTRY_W32, test "$pinentry_w32" = "yes") dnl dnl Check for FLTK pinentry program. dnl AC_ARG_ENABLE(pinentry-fltk, AC_HELP_STRING([--enable-pinentry-fltk], [build FLTK 1.3 pinentry]), pinentry_fltk=$enableval, pinentry_fltk=maybe) dnl check for fltk-config if test "$pinentry_fltk" != "no"; then AC_PATH_PROG(FLTK_CONFIG, fltk-config, no) if test x"${FLTK_CONFIG}" = xno ; then AC_MSG_WARN([fltk-config is not found]) pinentry_fltk=no fi fi dnl check for FLTK libraries and set flags if test "$pinentry_fltk" != "no"; then AC_MSG_CHECKING([for FLTK 1.3]) FLTK_VERSION=`${FLTK_CONFIG} --api-version` if test ${FLTK_VERSION} != "1.3" ; then AC_MSG_RESULT([no]) AC_MSG_WARN([FLTK 1.3 not found (available $FLTK_VERSION)]) pinentry_fltk=no else AC_MSG_RESULT([yes]) FLTKCFLAGS=`${FLTK_CONFIG} --cflags` FLTKCXXFLAGS=`${FLTK_CONFIG} --cxxflags` FLTKLIBS=`${FLTK_CONFIG} --ldflags` AC_SUBST(FLTKCFLAGS) AC_SUBST(FLTKCXXFLAGS) AC_SUBST(FLTKLIBS) pinentry_fltk=yes fi fi AM_CONDITIONAL(BUILD_PINENTRY_FLTK, test "$pinentry_fltk" = "yes") # Figure out the default pinentry. We are very conservative here. # Please change the order only after verifying that the preferred # pinentry really is better (more feature-complete and more secure). if test "$pinentry_gtk_2" = "yes"; then PINENTRY_DEFAULT=pinentry-gtk-2 else if test "$pinentry_qt" = "yes"; then PINENTRY_DEFAULT=pinentry-qt else if test "$pinentry_gnome_3" = "yes"; then PINENTRY_DEFAULT=pinentry-gnome3 else if test "$pinentry_curses" = "yes"; then PINENTRY_DEFAULT=pinentry-curses else if test "$pinentry_tty" = "yes"; then PINENTRY_DEFAULT=pinentry-tty else if test "$pinentry_w32" = "yes"; then PINENTRY_DEFAULT=pinentry-w32 else if test "$pinentry_fltk" = "yes"; then PINENTRY_DEFAULT=pinentry-fltk else - AC_MSG_ERROR([[No pinentry enabled.]]) + if test "$pinentry_tqt" = "yes"; then + PINENTRY_DEFAULT=pinentry-tqt + else + AC_MSG_ERROR([[No pinentry enabled.]]) + fi fi fi fi fi fi fi fi AC_SUBST(PINENTRY_DEFAULT) # # Print errors here so that they are visible all # together and the user can acquire them all together. # die=no if test "$have_gpg_error" = "no"; then die=yes AC_MSG_NOTICE([[ *** *** You need libgpg-error to build this program. ** This library is for example available at *** ftp://ftp.gnupg.org/gcrypt/libgpg-error *** (at least version $NEED_GPG_ERROR_VERSION is required.) ***]]) fi if test "$have_libassuan" = "no"; then die=yes AC_MSG_NOTICE([[ *** *** You need libassuan to build this program. *** This library is for example available at *** ftp://ftp.gnupg.org/gcrypt/libassuan/ *** (at least version $NEED_LIBASSUAN_VERSION (API $NEED_LIBASSUAN_API) is required). ***]]) fi if test "$die" = "yes"; then AC_MSG_ERROR([[ *** *** Required libraries not found. Please consult the above messages *** and install them before running configure again. ***]]) fi # # To avoid double inclusion of config.h which might happen at some # places, we add the usual double inclusion protection at the top of # config.h. # AH_TOP([ #ifndef GNUPG_CONFIG_H_INCLUDED #define GNUPG_CONFIG_H_INCLUDED ]) # # Stuff which goes at the bottom of config.h. # AH_BOTTOM([ #ifdef GPG_ERR_SOURCE_DEFAULT # error GPG_ERR_SOURCE_DEFAULT already defined #endif #define GPG_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_PINENTRY #endif /*GNUPG_CONFIG_H_INCLUDED*/ ]) AC_CONFIG_FILES([ m4/Makefile secmem/Makefile pinentry/Makefile curses/Makefile tty/Makefile emacs/Makefile gtk+-2/Makefile gnome3/Makefile qt/Makefile +tqt/Makefile w32/Makefile fltk/Makefile doc/Makefile Makefile ]) AC_OUTPUT AC_MSG_NOTICE([ Pinentry v${VERSION} has been configured as follows: Revision: mym4_revision (mym4_revision_dec) Platform: $host Curses Pinentry ..: $pinentry_curses TTY Pinentry .....: $pinentry_tty Emacs Pinentry ...: $pinentry_emacs GTK+-2 Pinentry ..: $pinentry_gtk_2 GNOME 3 Pinentry .: $pinentry_gnome_3 Qt Pinentry ......: $pinentry_qt $pinentry_qt_lib_version + TQt Pinentry .....: $pinentry_tqt W32 Pinentry .....: $pinentry_w32 FLTK Pinentry ....: $pinentry_fltk Fallback to Curses: $fallback_curses Emacs integration : $inside_emacs libsecret ........: $libsecret Default Pinentry .: $PINENTRY_DEFAULT ]) diff --git a/tqt/Makefile.am b/tqt/Makefile.am new file mode 100644 index 0000000..9171b0f --- /dev/null +++ b/tqt/Makefile.am @@ -0,0 +1,58 @@ +# Makefile.am +# Copyright (C) 2002 g10 Code GmbH, Klarälvdalens Datakonsult AB +# Copyright (C) 2008, 2015 g10 Code GmbH +# +# This file is part of PINENTRY. +# +# PINENTRY is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# PINENTRY 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 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 + +## Process this file with automake to produce Makefile.in + +bin_PROGRAMS = pinentry-tqt + + +if FALLBACK_CURSES +ncurses_include = $(NCURSES_INCLUDE) +libcurses = ../pinentry/libpinentry-curses.a $(LIBCURSES) $(LIBICONV) +else +ncurses_include = +libcurses = +endif + + +AM_CPPFLAGS = $(COMMON_CFLAGS) \ + -I$(top_srcdir) -I$(top_srcdir)/secmem \ + $(ncurses_include) -I$(top_srcdir)/pinentry +AM_CXXFLAGS = $(PINENTRY_TQT_CFLAGS) +pinentry_tqt_LDADD = \ + ../pinentry/libpinentry.a $(top_builddir)/secmem/libsecmem.a \ + $(COMMON_LIBS) $(PINENTRY_TQT_LIBS) $(libcurses) $(LIBCAP) + +BUILT_SOURCES = \ + secqlineedit.moc pinentrydialog.moc + +CLEANFILES = \ + secqlineedit.moc pinentrydialog.moc + +pinentry_tqt_SOURCES = pinentrydialog.h pinentrydialog.cpp \ + main.cpp secqinternal_p.h secqinternal.cpp \ + secqlineedit.h secqlineedit.cpp \ + secqstring.h secqstring.cpp + +nodist_pinentry_tqt_SOURCES = \ + secqlineedit.moc pinentrydialog.moc + +.h.moc: + $(TQT_MOC) `test -f '$<' || echo '$(srcdir)/'`$< -o $@ diff --git a/tqt/main.cpp b/tqt/main.cpp new file mode 100644 index 0000000..3f7efb4 --- /dev/null +++ b/tqt/main.cpp @@ -0,0 +1,241 @@ +/* main.cpp - Secure KDE dialog for PIN entry. + Copyright (C) 2002 Klarälvdalens Datakonsult AB + Copyright (C) 2003 g10 Code GmbH + Written by Steffen Hansen . + Modified by Marcus Brinkmann . + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 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 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 */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include "secqstring.h" + +#include "pinentrydialog.h" + +#include "pinentry.h" + +#ifdef FALLBACK_CURSES +#include +#endif + +static TQString escape_accel( const TQString & s ) { + + TQString result; + result.reserve( 2 * s.length()); + + bool afterUnderscore = false; + + for ( unsigned int i = 0, end = s.length() ; i != end ; ++i ) { + const TQChar ch = s[i]; + if ( ch == TQChar ( '_' ) ) + { + if ( afterUnderscore ) // escaped _ + { + result += TQChar ( '_' ); + afterUnderscore = false; + } + else // accel + { + afterUnderscore = true; + } + } + else + { + if ( afterUnderscore || // accel + ch == TQChar ( '&' ) ) // escape & from being interpreted by TQt + result += TQChar ( '&' ); + result += ch; + afterUnderscore = false; + } + } + + if ( afterUnderscore ) + // trailing single underscore: shouldn't happen, but deal with it robustly: + result += TQChar ( '_' ); + + return result; +} + + +/* Hack for creating a TQWidget with a "foreign" window ID */ +class ForeignWidget : public TQWidget +{ +public: + ForeignWidget( WId wid ) : TQWidget( 0 ) + { + TQWidget::destroy(); + create( wid, false, false ); + } + + ~ForeignWidget() + { + destroy( false, false ); + } +}; + +static int +qt_cmd_handler (pinentry_t pe) +{ + TQWidget *parent = 0; + + int want_pass = !!pe->pin; + + if (want_pass) + { + /* FIXME: Add parent window ID to pinentry and GTK. */ + if (pe->parent_wid) + parent = new ForeignWidget (pe->parent_wid); + + PinEntryDialog pinentry (parent, NULL, true, !!pe->quality_bar); + + pinentry.setPinentryInfo (pe); + pinentry.setPrompt (TQString::fromUtf8 (pe->prompt)); + pinentry.setDescription (TQString::fromUtf8 (pe->description)); + /* If we reuse the same dialog window. */ +#if 0 + pinentry.setText (SecTQString::null); +#endif + + if (pe->ok) + pinentry.setOkText (escape_accel (TQString::fromUtf8 (pe->ok))); + else if (pe->default_ok) + pinentry.setOkText (escape_accel (TQString::fromUtf8 (pe->default_ok))); + + if (pe->cancel) + pinentry.setCancelText (escape_accel (TQString::fromUtf8 (pe->cancel))); + else if (pe->default_cancel) + pinentry.setCancelText + (escape_accel (TQString::fromUtf8 (pe->default_cancel))); + + if (pe->error) + pinentry.setError (TQString::fromUtf8 (pe->error)); + if (pe->quality_bar) + pinentry.setQualityBar (TQString::fromUtf8 (pe->quality_bar)); + if (pe->quality_bar_tt) + pinentry.setQualityBarTT (TQString::fromUtf8 (pe->quality_bar_tt)); + + bool ret = pinentry.exec (); + if (!ret) + return -1; + + char *pin = (char *) pinentry.text().utf8(); + if (!pin) + return -1; + + int len = strlen (pin); + if (len >= 0) + { + pinentry_setbufferlen (pe, len + 1); + if (pe->pin) + { + strcpy (pe->pin, pin); + ::secmem_free (pin); + return len; + } + } + ::secmem_free (pin); + return -1; + } + else + { + TQString desc = TQString::fromUtf8 (pe->description? pe->description : ""); + TQString ok = escape_accel + (TQString::fromUtf8 (pe->ok ? pe->ok : + pe->default_ok ? pe->default_ok : "_OK")); + TQString can = escape_accel + (TQString::fromUtf8 (pe->cancel ? pe->cancel : + pe->default_cancel? pe->default_cancel: "_Cancel")); + bool ret; + + ret = TQMessageBox::information (parent, "", desc, ok, can ); + + return !ret; + } +} + +pinentry_cmd_handler_t pinentry_cmd_handler = qt_cmd_handler; + +int +main (int argc, char *argv[]) +{ + pinentry_init ("pinentry-tqt"); + +#ifdef FALLBACK_CURSES + if (!pinentry_have_display (argc, argv)) + pinentry_cmd_handler = curses_cmd_handler; + else +#endif + { + /* TQt does only understand -display but not --display; thus we + are fixing that here. The code is pretty simply and may get + confused if an argument is called "--display". */ + char **new_argv, *p; + size_t n; + int i, done; + + for (n=0,i=0; i < argc; i++) + n += strlen (argv[i])+1; + n++; + new_argv = (char**)calloc (argc+1, sizeof *new_argv); + if (new_argv) + *new_argv = (char*)malloc (n); + if (!new_argv || !*new_argv) + { + fprintf (stderr, "pinentry-tqt: can't fixup argument list: %s\n", + strerror (errno)); + exit (EXIT_FAILURE); + + } + for (done=0,p=*new_argv,i=0; i < argc; i++) + if (!done && !strcmp (argv[i], "--display")) + { + new_argv[i] = (char*)"-display"; + done = 1; + } + else + { + new_argv[i] = strcpy (p, argv[i]); + p += strlen (argv[i]) + 1; + } + + /* We use a modal dialog window, so we don't need the application + window anymore. */ + i = argc; + new TQApplication (i, new_argv); + } + + + /* Consumes all arguments. */ + pinentry_parse_opts (argc, argv); +// if (pinentry_parse_opts (argc, argv)) +// { +// printf ("pinentry-tqt (pinentry) " VERSION "\n"); +// exit (EXIT_SUCCESS); +// } + + if (pinentry_loop ()) + return 1; + + return 0; +} diff --git a/tqt/pinentrydialog.cpp b/tqt/pinentrydialog.cpp new file mode 100644 index 0000000..2eae54d --- /dev/null +++ b/tqt/pinentrydialog.cpp @@ -0,0 +1,234 @@ +/* pinentrydialog.cpp - A secure KDE dialog for PIN entry. + Copyright (C) 2002 Klarälvdalens Datakonsult AB + Copyright (C) 2007 g10 Code GmbH + Written by Steffen Hansen . + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 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 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 +#include +#include +#include +#include +#include + +#include "secqlineedit.h" + +#include "pinentrydialog.h" +#include "pinentry.h" + +PinEntryDialog::PinEntryDialog( TQWidget* parent, const char* name, + bool modal, bool enable_quality_bar ) + : TQDialog( parent, name, modal, TQt::WStyle_StaysOnTop ), _grabbed( false ) +{ + TQBoxLayout* top = new TQVBoxLayout( this, 6 ); + TQBoxLayout* upperLayout = new TQHBoxLayout( top ); + + _icon = new TQLabel( this ); + _icon->setPixmap( TQMessageBox::standardIcon( TQMessageBox::Information ) ); + upperLayout->addWidget( _icon ); + + TQBoxLayout* labelLayout = new TQVBoxLayout( upperLayout ); + + _error = new TQLabel( this ); + labelLayout->addWidget( _error ); + + _desc = new TQLabel( this ); + labelLayout->addWidget( _desc ); + + TQGridLayout* grid = new TQGridLayout( labelLayout ); + + _prompt = new TQLabel( this ); + _prompt->setAlignment( TQt::AlignRight | TQt::AlignVCenter ); + grid->addWidget( _prompt, 0, 0 ); + _edit = new SecTQLineEdit( this ); + _edit->setMaxLength( 256 ); + _edit->setEchoMode( SecTQLineEdit::Password ); + grid->addWidget( _edit, 0, 1 ); + + if (enable_quality_bar) + { + _quality_bar_label = new TQLabel( this ); + _quality_bar_label->setAlignment( TQt::AlignRight | TQt::AlignVCenter ); + grid->addWidget ( _quality_bar_label, 1, 0 ); + _quality_bar = new TQProgressBar( this ); + _quality_bar->setCenterIndicator( true ); + grid->addWidget( _quality_bar, 1, 1 ); + _have_quality_bar = true; + } + else + _have_quality_bar = false; + + TQBoxLayout* l = new TQHBoxLayout( top ); + + _ok = new TQPushButton( tr("OK"), this ); + _cancel = new TQPushButton( tr("Cancel"), this ); + + l->addWidget( _ok ); + l->addStretch(); + l->addWidget( _cancel ); + + _ok->setDefault(true); + + connect( _ok, SIGNAL( clicked() ), + this, SIGNAL( accepted() ) ); + connect( _cancel, SIGNAL( clicked() ), + this, SIGNAL( rejected() ) ); + connect( _edit, SIGNAL( textModified(const SecTQString&) ), + this, SLOT( updateQuality(const SecTQString&) ) ); + connect (this, SIGNAL (accepted ()), + this, SLOT (accept ())); + connect (this, SIGNAL (rejected ()), + this, SLOT (reject ())); + _edit->setFocus(); +} + +void PinEntryDialog::paintEvent( TQPaintEvent* ev ) +{ + // Grab keyboard when widget is mapped to screen + // It might be a little weird to do it here, but it works! + if( !_grabbed ) { + _edit->grabKeyboard(); + _grabbed = true; + } + TQDialog::paintEvent( ev ); +} + +void PinEntryDialog::hideEvent( TQHideEvent* ev ) +{ + _edit->releaseKeyboard(); + _grabbed = false; + TQDialog::hideEvent( ev ); +} + +void PinEntryDialog::keyPressEvent( TQKeyEvent* e ) +{ + if ( e->state() == 0 && e->key() == Key_Escape ) { + emit rejected(); + return; + } + TQDialog::keyPressEvent( e ); +} + + +void PinEntryDialog::updateQuality( const SecTQString & txt ) +{ + char *pin; + int length; + int percent; + TQPalette pal; + + if (!_have_quality_bar || !_pinentry_info) + return; + pin = (char*)txt.utf8(); + length = strlen (pin); + percent = length? pinentry_inq_quality (_pinentry_info, pin, length) : 0; + ::secmem_free (pin); + if (!length) + { + _quality_bar->reset (); + } + else + { + pal = _quality_bar->palette (); + if (percent < 0) + { + pal.setColor (TQColorGroup::Highlight, TQColor("red")); + percent = -percent; + } + else + { + pal.setColor (TQColorGroup::Highlight, TQColor("green")); + } + _quality_bar->setPalette (pal); + _quality_bar->setProgress (percent); + } +} + + +void PinEntryDialog::setDescription( const TQString& txt ) +{ + _desc->setText( txt ); + _icon->setPixmap( TQMessageBox::standardIcon( TQMessageBox::Information ) ); + setError( TQString::null ); +} + +TQString PinEntryDialog::description() const +{ + return _desc->text(); +} + +void PinEntryDialog::setError( const TQString& txt ) +{ + if ( !txt.isNull() ) + _icon->setPixmap( TQMessageBox::standardIcon( TQMessageBox::Critical ) ); + _error->setText( txt ); +} + +TQString PinEntryDialog::error() const +{ + return _error->text(); +} + +void PinEntryDialog::setText( const SecTQString& txt ) +{ + _edit->setText( txt ); +} + +SecTQString PinEntryDialog::text() const +{ + return _edit->text(); +} + +void PinEntryDialog::setPrompt( const TQString& txt ) +{ + _prompt->setText( txt ); +} + +TQString PinEntryDialog::prompt() const +{ + return _prompt->text(); +} + +void PinEntryDialog::setOkText( const TQString& txt ) +{ + _ok->setText( txt ); +} + +void PinEntryDialog::setCancelText( const TQString& txt ) +{ + _cancel->setText( txt ); +} + +void PinEntryDialog::setQualityBar( const TQString& txt ) +{ + if (_have_quality_bar) + _quality_bar_label->setText( txt ); +} + +void PinEntryDialog::setQualityBarTT( const TQString& txt ) +{ + if (_have_quality_bar) + TQToolTip::add ( _quality_bar, txt ); +} + +void PinEntryDialog::setPinentryInfo (pinentry_t peinfo ) +{ + _pinentry_info = peinfo; +} + +#include "pinentrydialog.moc" diff --git a/tqt/pinentrydialog.h b/tqt/pinentrydialog.h new file mode 100644 index 0000000..4d69a28 --- /dev/null +++ b/tqt/pinentrydialog.h @@ -0,0 +1,92 @@ +/* pinentrydialog.h - A secure KDE dialog for PIN entry. + Copyright (C) 2002 Klarälvdalens Datakonsult AB + Written by Steffen Hansen . + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 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 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 __PINENTRYDIALOG_H__ +#define __PINENTRYDIALOG_H__ + +#include +#include "pinentry.h" + +class TQLabel; +class TQPushButton; +class TQProgressBar; +class SecTQLineEdit; +class SecTQString; + +class PinEntryDialog : public TQDialog { + TQ_OBJECT + + TQ_PROPERTY( TQString description READ description WRITE setDescription ) + TQ_PROPERTY( TQString error READ error WRITE setError ) + // TQ_PROPERTY( SecTQString text READ text WRITE setText ) + TQ_PROPERTY( TQString prompt READ prompt WRITE setPrompt ) +public: + friend class PinEntryController; // TODO: remove when assuan lets me use TQt eventloop. + PinEntryDialog( TQWidget* parent = 0, const char* name = 0, + bool modal = false, bool enable_quality_bar = false ); + + void setDescription( const TQString& ); + TQString description() const; + + void setError( const TQString& ); + TQString error() const; + + void setText( const SecTQString& ); + SecTQString text() const; + + void setPrompt( const TQString& ); + TQString prompt() const; + + void setOkText( const TQString& ); + void setCancelText( const TQString& ); + + void setQualityBar( const TQString& ); + void setQualityBarTT( const TQString& ); + + void setPinentryInfo (pinentry_t); + +public slots: + void updateQuality(const SecTQString &); + +signals: + void accepted(); + void rejected(); + +protected: + virtual void keyPressEvent( TQKeyEvent *e ); + virtual void hideEvent( TQHideEvent* ); + virtual void paintEvent( TQPaintEvent* ); + +private: + TQLabel* _icon; + TQLabel* _desc; + TQLabel* _error; + TQLabel* _prompt; + TQLabel* _quality_bar_label; + TQProgressBar* _quality_bar; + SecTQLineEdit* _edit; + TQPushButton* _ok; + TQPushButton* _cancel; + bool _grabbed; + bool _have_quality_bar; + pinentry_t _pinentry_info; +}; + + +#endif // __PINENTRYDIALOG_H__ diff --git a/tqt/secqinternal.cpp b/tqt/secqinternal.cpp new file mode 100644 index 0000000..a1113a8 --- /dev/null +++ b/tqt/secqinternal.cpp @@ -0,0 +1,635 @@ +/**************************************************************************** +** $Id$ +** +** Implementation of some internal classes +** +** Created : 010427 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.TQPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition +** licenses may use this file in accordance with the TQt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about TQt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for TQPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "secqinternal_p.h" +#include "ntqwidget.h" +#include "ntqpixmap.h" +#include "ntqpainter.h" +#include "ntqcleanuphandler.h" + +static TQPixmap* qdb_shared_pixmap = 0; +static TQPixmap *qdb_force_pixmap = 0; +static SecTQSharedDoubleBuffer* qdb_owner = 0; + +static TQCleanupHandler qdb_pixmap_cleanup; + +#ifdef Q_WS_MACX +bool SecTQSharedDoubleBuffer::dblbufr = FALSE; +#else +bool SecTQSharedDoubleBuffer::dblbufr = TRUE; +#endif + + +/* + hardLimitWidth/Height: if >= 0, the maximum number of pixels that + get double buffered. + + sharedLimitWidth/Height: if >= 0, the maximum number of pixels the + shared double buffer can keep. + + For x with sharedLimitSize < x <= hardLimitSize, temporary buffers + are constructed. + */ +static const int hardLimitWidth = -1; +static const int hardLimitHeight = -1; +#if defined( Q_WS_QWS ) || defined( Q_WS_MAC9 ) +// Small in TQt/Embedded / Mac9 - 5K on 32bpp +static const int sharedLimitWidth = 64; +static const int sharedLimitHeight = 20; +#else +// 240K on 32bpp +static const int sharedLimitWidth = 640; +static const int sharedLimitHeight = 100; +#endif + +// ******************************************************************* +// SecTQSharedDoubleBufferCleaner declaration and implementation +// ******************************************************************* + +/* \internal + This class is responsible for cleaning up the pixmaps created by the + SecTQSharedDoubleBuffer class. When SecTQSharedDoubleBuffer creates a + pixmap larger than the shared limits, this class deletes it after a + specified amount of time. + + When the large pixmap is created/used, you must call start(). If the + large pixmap is ever deleted, you must call stop(). The start() + method always restarts the timer, so if the large pixmap is + constantly in use, the timer will never fire, and the pixmap will + not be constantly created and destroyed. +*/ + +static const int shared_double_buffer_cleanup_timeout = 30000; // 30 seconds + +// declaration + +class SecTQSharedDoubleBufferCleaner : public TQObject +{ +public: + SecTQSharedDoubleBufferCleaner( void ); + + void start( void ); + void stop( void ); + + void doCleanup( void ); + + bool event( TQEvent *e ); + +private: + int timer_id; +}; + +// implementation + +/* \internal + Creates a SecTQSharedDoubleBufferCleaner object. The timer is not + started when creating the object. +*/ +SecTQSharedDoubleBufferCleaner::SecTQSharedDoubleBufferCleaner( void ) + : TQObject( 0, "internal shared double buffer cleanup object" ), + timer_id( -1 ) +{ +} + +/* \internal + Starts the cleanup timer. Any previously running timer is stopped. +*/ +void SecTQSharedDoubleBufferCleaner::start( void ) +{ + stop(); + timer_id = startTimer( shared_double_buffer_cleanup_timeout ); +} + +/* \internal + Stops the cleanup timer, if it is running. +*/ +void SecTQSharedDoubleBufferCleaner::stop( void ) +{ + if ( timer_id != -1 ) + killTimer( timer_id ); + timer_id = -1; +} + +/* \internal + */ +void SecTQSharedDoubleBufferCleaner::doCleanup( void ) +{ + qdb_pixmap_cleanup.remove( &qdb_force_pixmap ); + delete qdb_force_pixmap; + qdb_force_pixmap = 0; +} + +/* \internal + Event handler reimplementation. Calls doCleanup() when the timer + fires. +*/ +bool SecTQSharedDoubleBufferCleaner::event( TQEvent *e ) +{ + if ( e->type() != TQEvent::Timer ) + return FALSE; + + TQTimerEvent *event = (TQTimerEvent *) e; + if ( event->timerId() == timer_id ) { + doCleanup(); + stop(); + } +#ifdef QT_CHECK_STATE + else { + tqWarning( "SecTQSharedDoubleBufferCleaner::event: invalid timer event received." ); + return FALSE; + } +#endif // QT_CHECK_STATE + + return TRUE; +} + +// static instance +static SecTQSharedDoubleBufferCleaner *static_cleaner = 0; +TQSingleCleanupHandler cleanup_static_cleaner; + +inline static SecTQSharedDoubleBufferCleaner *staticCleaner() +{ + if ( ! static_cleaner ) { + static_cleaner = new SecTQSharedDoubleBufferCleaner(); + cleanup_static_cleaner.set( &static_cleaner ); + } + return static_cleaner; +} + + +// ******************************************************************* +// SecTQSharedDoubleBuffer implementation +// ******************************************************************* + +/* \internal + \enum DoubleBufferFlags + + \value InitBG initialize the background of the double buffer. + + \value Force disable shared buffer size limits. + + \value Default InitBG and Force are used by default. +*/ + +/* \internal + \enum DoubleBufferState + + \value Active indicates that the buffer may be used. + + \value BufferActive indicates that painting with painter() will be + double buffered. + + \value ExternalPainter indicates that painter() will return a + painter that was not created by SecTQSharedDoubleBuffer. +*/ + +/* \internal + \class SecTQSharedDoubleBuffer + + This class provides a single, reusable double buffer. This class + is used internally by TQt widgets that need double buffering, which + prevents each individual widget form creating a double buffering + pixmap. + + Using a single pixmap double buffer and sharing it across all + widgets is nicer on window system resources. +*/ + +/* \internal + Creates a SecTQSharedDoubleBuffer with flags \f. + + \sa DoubleBufferFlags +*/ +SecTQSharedDoubleBuffer::SecTQSharedDoubleBuffer( DBFlags f ) + : wid( 0 ), rx( 0 ), ry( 0 ), rw( 0 ), rh( 0 ), flags( f ), state( 0 ), + p( 0 ), external_p( 0 ), pix( 0 ) +{ +} + +/* \internal + Creates a SecTQSharedDoubleBuffer with flags \f. The \a widget, \a x, + \a y, \a w and \a h arguments are passed to begin(). + + \sa DoubleBufferFlags begin() +*/ +SecTQSharedDoubleBuffer::SecTQSharedDoubleBuffer( TQWidget* widget, + int x, int y, int w, int h, + DBFlags f ) + : wid( 0 ), rx( 0 ), ry( 0 ), rw( 0 ), rh( 0 ), flags( f ), state( 0 ), + p( 0 ), external_p( 0 ), pix( 0 ) +{ + begin( widget, x, y, w, h ); +} + +/* \internal + Creates a SecTQSharedDoubleBuffer with flags \f. The \a painter, \a x, + \a y, \a w and \a h arguments are passed to begin(). + + \sa DoubleBufferFlags begin() +*/ +SecTQSharedDoubleBuffer::SecTQSharedDoubleBuffer( TQPainter* painter, + int x, int y, int w, int h, + DBFlags f) + : wid( 0 ), rx( 0 ), ry( 0 ), rw( 0 ), rh( 0 ), flags( f ), state( 0 ), + p( 0 ), external_p( 0 ), pix( 0 ) +{ + begin( painter, x, y, w, h ); +} + +/* \internal + Creates a SecTQSharedDoubleBuffer with flags \f. The \a widget and + \a r arguments are passed to begin(). + + \sa DoubleBufferFlags begin() +*/ +SecTQSharedDoubleBuffer::SecTQSharedDoubleBuffer( TQWidget *widget, const TQRect &r, DBFlags f ) + : wid( 0 ), rx( 0 ), ry( 0 ), rw( 0 ), rh( 0 ), flags( f ), state( 0 ), + p( 0 ), external_p( 0 ), pix( 0 ) +{ + begin( widget, r ); +} + +/* \internal + Creates a SecTQSharedDoubleBuffer with flags \f. The \a painter and + \a r arguments are passed to begin(). + + \sa DoubleBufferFlags begin() +*/ +SecTQSharedDoubleBuffer::SecTQSharedDoubleBuffer( TQPainter *painter, const TQRect &r, DBFlags f ) + : wid( 0 ), rx( 0 ), ry( 0 ), rw( 0 ), rh( 0 ), flags( f ), state( 0 ), + p( 0 ), external_p( 0 ), pix( 0 ) +{ + begin( painter, r ); +} + +/* \internal + Destructs the SecTQSharedDoubleBuffer and calls end() if the buffer is + active. + + \sa isActive() end() +*/ +SecTQSharedDoubleBuffer::~SecTQSharedDoubleBuffer() +{ + if ( isActive() ) + end(); +} + +/* \internal + Starts double buffered painting in the area specified by \a x, + \a y, \a w and \a h on \a painter. Painting should be done using the + TQPainter returned by SecTQSharedDoubleBuffer::painter(). + + The double buffered area will be updated when calling end(). + + \sa painter() isActive() end() +*/ +bool SecTQSharedDoubleBuffer::begin( TQPainter* painter, int x, int y, int w, int h ) +{ + if ( isActive() ) { +#if defined(QT_CHECK_STATE) + tqWarning( "SecTQSharedDoubleBuffer::begin: Buffer is already active." + "\n\tYou must end() the buffer before a second begin()" ); +#endif // QT_CHECK_STATE + return FALSE; + } + + external_p = painter; + + if ( painter->device()->devType() == TQInternal::Widget ) + return begin( (TQWidget *) painter->device(), x, y, w, h ); + + state = Active; + + rx = x; + ry = y; + rw = w; + rh = h; + + if ( ( pix = getPixmap() ) ) { +#ifdef Q_WS_X11 + if ( painter->device()->x11Screen() != pix->x11Screen() ) + pix->x11SetScreen( painter->device()->x11Screen() ); + TQPixmap::x11SetDefaultScreen( pix->x11Screen() ); +#endif // Q_WS_X11 + + state |= BufferActive; + p = new TQPainter( pix ); + if ( p->isActive() ) { + p->setPen( external_p->pen() ); + p->setBackgroundColor( external_p->backgroundColor() ); + p->setFont( external_p->font() ); + } + } else { + state |= ExternalPainter; + p = external_p; + } + + return TRUE; +} + +/* \internal + + + Starts double buffered painting in the area specified by \a x, + \a y, \a w and \a h on \a widget. Painting should be done using the + TQPainter returned by SecTQSharedDoubleBuffer::painter(). + + The double buffered area will be updated when calling end(). + + \sa painter() isActive() end() +*/ +bool SecTQSharedDoubleBuffer::begin( TQWidget* widget, int x, int y, int w, int h ) +{ + if ( isActive() ) { +#if defined(QT_CHECK_STATE) + tqWarning( "SecTQSharedDoubleBuffer::begin: Buffer is already active." + "\n\tYou must end() the buffer before a second begin()" ); +#endif // QT_CHECK_STATE + return FALSE; + } + + state = Active; + + wid = widget; + rx = x; + ry = y; + rw = w <= 0 ? wid->width() : w; + rh = h <= 0 ? wid->height() : h; + + if ( ( pix = getPixmap() ) ) { +#ifdef Q_WS_X11 + if ( wid->x11Screen() != pix->x11Screen() ) + pix->x11SetScreen( wid->x11Screen() ); + TQPixmap::x11SetDefaultScreen( pix->x11Screen() ); +#endif // Q_WS_X11 + + state |= BufferActive; + if ( flags & InitBG ) { + pix->fill( wid, rx, ry ); + } + p = new TQPainter( pix, wid ); + // newly created painters should be translated to the origin + // of the widget, so that paint methods can draw onto the double + // buffered painter in widget coordinates. + p->setBrushOrigin( -rx, -ry ); + p->translate( -rx, -ry ); + } else { + if ( external_p ) { + state |= ExternalPainter; + p = external_p; + } else { + p = new TQPainter( wid ); + } + + if ( flags & InitBG ) { + wid->erase( rx, ry, rw, rh ); + } + } + return TRUE; +} + +/* \internal + Ends double buffered painting. The contents of the shared double + buffer pixmap are drawn onto the destination by calling flush(), + and ownership of the shared double buffer pixmap is released. + + \sa begin() flush() +*/ +bool SecTQSharedDoubleBuffer::end() +{ + if ( ! isActive() ) { +#if defined(QT_CHECK_STATE) + tqWarning( "SecTQSharedDoubleBuffer::end: Buffer is not active." + "\n\tYou must call begin() before calling end()." ); +#endif // QT_CHECK_STATE + return FALSE; + } + + if ( ! ( state & ExternalPainter ) ) { + p->end(); + delete p; + } + + flush(); + + if ( pix ) { + releasePixmap(); + } + + wid = 0; + rx = ry = rw = rh = 0; + // do not reset flags! + state = 0; + + p = external_p = 0; + pix = 0; + + return TRUE; +} + +/* \internal + Paints the contents of the shared double buffer pixmap onto the + destination. The destination is determined from the arguments + based to begin(). + + Note: You should not need to call this function, since it is called + from end(). + + \sa begin() end() +*/ +void SecTQSharedDoubleBuffer::flush() +{ + if ( ! isActive() || ! ( state & BufferActive ) ) + return; + + if ( external_p ) + external_p->drawPixmap( rx, ry, *pix, 0, 0, rw, rh ); + else if ( wid && wid->isVisible() ) + bitBlt( wid, rx, ry, pix, 0, 0, rw, rh ); +} + +/* \internal + Atquire ownership of the shared double buffer pixmap, subject to the + following conditions: + + \list 1 + \i double buffering is enabled globally. + \i the shared double buffer pixmap is not in use. + \i the size specified in begin() is valid, and within limits. + \endlist + + If all of these conditions are met, then this SecTQSharedDoubleBuffer + object becomes the owner of the shared double buffer pixmap. The + shared double buffer pixmap is resize if necessary, and this + function returns a pointer to the pixmap. Ownership must later be + relinquished by calling releasePixmap(). + + If none of the above conditions are met, this function returns + zero. + + \sa releasePixmap() +*/ +TQPixmap *SecTQSharedDoubleBuffer::getPixmap() +{ + if ( isDisabled() ) { + // double buffering disabled globally + return 0; + } + + if ( qdb_owner ) { + // shared pixmap already in use + return 0; + } + + if ( rw <= 0 || rh <= 0 || + ( hardLimitWidth > 0 && rw >= hardLimitWidth ) || + ( hardLimitHeight > 0 && rh >= hardLimitHeight ) ) { + // invalid size, or hard limit reached + return 0; + } + + if ( rw >= sharedLimitWidth || rh >= sharedLimitHeight ) { + if ( flags & Force ) { + rw = TQMIN(rw, 8000); + rh = TQMIN(rh, 8000); + // need to create a big pixmap and start the cleaner + if ( ! qdb_force_pixmap ) { + qdb_force_pixmap = new TQPixmap( rw, rh ); + qdb_pixmap_cleanup.add( &qdb_force_pixmap ); + } else if ( qdb_force_pixmap->width () < rw || + qdb_force_pixmap->height() < rh ) { + qdb_force_pixmap->resize( rw, rh ); + } + qdb_owner = this; + staticCleaner()->start(); + return qdb_force_pixmap; + } + + // size is outside shared limit + return 0; + } + + if ( ! qdb_shared_pixmap ) { + qdb_shared_pixmap = new TQPixmap( rw, rh ); + qdb_pixmap_cleanup.add( &qdb_shared_pixmap ); + } else if ( qdb_shared_pixmap->width() < rw || + qdb_shared_pixmap->height() < rh ) { + qdb_shared_pixmap->resize( rw, rh ); + } + qdb_owner = this; + return qdb_shared_pixmap; +} + +/* \internal + Releases ownership of the shared double buffer pixmap. + + \sa getPixmap() +*/ +void SecTQSharedDoubleBuffer::releasePixmap() +{ + if ( qdb_owner != this ) { + // sanity check + +#ifdef QT_CHECK_STATE + tqWarning( "SecTQSharedDoubleBuffer::releasePixmap: internal error." + "\n\t%p does not own shared pixmap, %p does.", + (void*)this, (void*)qdb_owner ); +#endif // QT_CHECK_STATE + + return; + } + + qdb_owner = 0; +} + +/* \internal + \fn bool SecTQSharedDoubleBuffer::isDisabled() + + Returns TRUE is double buffering is disabled globally, FALSE otherwise. +*/ + +/* \internal + \fn void SecTQSharedDoubleBuffer::setDisabled( bool off ) + + Disables global double buffering \a off is TRUE, otherwise global + double buffering is enabled. +*/ + +/* \internal + Deletes the shared double buffer pixmap. You should not need to + call this function, since it is called from the TQApplication + destructor. +*/ +void SecTQSharedDoubleBuffer::cleanup() +{ + qdb_pixmap_cleanup.remove( &qdb_shared_pixmap ); + qdb_pixmap_cleanup.remove( &qdb_force_pixmap ); + delete qdb_shared_pixmap; + delete qdb_force_pixmap; + qdb_shared_pixmap = 0; + qdb_force_pixmap = 0; + qdb_owner = 0; +} + +/* \internal + \fn bool SecTQSharedDoubleBuffer::begin( TQWidget *widget, const TQRect &r ) + \overload +*/ + +/* \internal + \fn bool SecTQSharedDoubleBuffer::begin( TQPainter *painter, const TQRect &r ) + \overload +*/ + +/* \internal + \fn TQPainter *SecTQSharedDoubleBuffer::painter() const + + Returns the active painter on the double buffered area, + or zero if double buffered painting is not active. +*/ + +/* \internal + \fn bool SecTQSharedDoubleBuffer::isActive() const + + Returns TRUE if double buffered painting is active, FALSE otherwise. +*/ + +/* \internal + \fn bool SecTQSharedDoubleBuffer::isBuffered() const + + Returns TRUE if painting is double buffered, FALSE otherwise. +*/ diff --git a/tqt/secqinternal_p.h b/tqt/secqinternal_p.h new file mode 100644 index 0000000..35d2b0d --- /dev/null +++ b/tqt/secqinternal_p.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** $Id$ +** +** Definition of some shared interal classes +** +** Created : 010427 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.TQPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition +** licenses may use this file in accordance with the TQt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about TQt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for TQPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef SECTQINTERNAL_P_H +#define SECTQINTERNAL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the TQt API. It exists for the convenience +// of a number of TQt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// +// +#ifndef QT_H +#include "ntqnamespace.h" +#include "ntqrect.h" +#include "ntqptrlist.h" +#include "ntqcstring.h" +#include "ntqiodevice.h" +#endif // QT_H + +class TQWidget; +class TQPainter; +class TQPixmap; + +class Q_EXPORT SecTQSharedDoubleBuffer +{ +public: + enum DoubleBufferFlags { + NoFlags = 0x00, + InitBG = 0x01, + Force = 0x02, + Default = InitBG | Force + }; + typedef uint DBFlags; + + SecTQSharedDoubleBuffer( DBFlags f = Default ); + SecTQSharedDoubleBuffer( TQWidget* widget, + int x = 0, int y = 0, int w = -1, int h = -1, + DBFlags f = Default ); + SecTQSharedDoubleBuffer( TQPainter* painter, + int x = 0, int y = 0, int w = -1, int h = -1, + DBFlags f = Default ); + SecTQSharedDoubleBuffer( TQWidget *widget, const TQRect &r, DBFlags f = Default ); + SecTQSharedDoubleBuffer( TQPainter *painter, const TQRect &r, DBFlags f = Default ); + ~SecTQSharedDoubleBuffer(); + + bool begin( TQWidget* widget, int x = 0, int y = 0, int w = -1, int h = -1 ); + bool begin( TQPainter* painter, int x = 0, int y = 0, int w = -1, int h = -1); + bool begin( TQWidget* widget, const TQRect &r ); + bool begin( TQPainter* painter, const TQRect &r ); + bool end(); + + TQPainter* painter() const; + + bool isActive() const; + bool isBuffered() const; + void flush(); + + static bool isDisabled() { return !dblbufr; } + static void setDisabled( bool off ) { dblbufr = !off; } + + static void cleanup(); + +private: + enum DoubleBufferState { + Active = 0x0100, + BufferActive = 0x0200, + ExternalPainter = 0x0400 + }; + typedef uint DBState; + + TQPixmap *getPixmap(); + void releasePixmap(); + + TQWidget *wid; + int rx, ry, rw, rh; + DBFlags flags; + DBState state; + + TQPainter *p, *external_p; + TQPixmap *pix; + + static bool dblbufr; +}; + +inline bool SecTQSharedDoubleBuffer::begin( TQWidget* widget, const TQRect &r ) +{ return begin( widget, r.x(), r.y(), r.width(), r.height() ); } + +inline bool SecTQSharedDoubleBuffer::begin( TQPainter *painter, const TQRect &r ) +{ return begin( painter, r.x(), r.y(), r.width(), r.height() ); } + +inline TQPainter* SecTQSharedDoubleBuffer::painter() const +{ return p; } + +inline bool SecTQSharedDoubleBuffer::isActive() const +{ return ( state & Active ); } + +inline bool SecTQSharedDoubleBuffer::isBuffered() const +{ return ( state & BufferActive ); } + +#endif // SECTQINTERNAL_P_H diff --git a/tqt/secqlineedit.cpp b/tqt/secqlineedit.cpp new file mode 100644 index 0000000..ecf6010 --- /dev/null +++ b/tqt/secqlineedit.cpp @@ -0,0 +1,1955 @@ +/* secqlineedit.cpp - Secure version of TQLineEdit. + Copyright (C) 1992-2002 Trolltech AS. All rights reserved. + Copyright (C) 2003 g10 Code GmbH + + The license of the original qlineedit.cpp file from which this file + is derived can be found below. Modified by Marcus Brinkmann + . All modifications are licensed as follows, so + that the intersection of the two licenses is then the GNU General + Public License version 2. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 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 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 */ + + +/* Undo/Redo is disabled, because it uses unsecure memory for the + history buffer. */ +#define SECURE_NO_UNDO 1 + + +/********************************************************************** +** $Id$ +** +** Implementation of SecTQLineEdit widget class +** +** Created : 941011 +** +** Copyright (C) 1992-2002 Trolltech AS. All rights reserved. +** +** This file is part of the widgets module of the TQt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.TQPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition +** licenses may use this file in accordance with the TQt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about TQt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for TQPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "secqlineedit.h" +#include "ntqpainter.h" +#include "ntqdrawutil.h" +#include "ntqfontmetrics.h" +#include "ntqpixmap.h" +#include "ntqclipboard.h" +#include "ntqapplication.h" +#include "ntqtimer.h" +#include "ntqpopupmenu.h" +#include "ntqstringlist.h" +#include "ntqguardedptr.h" +#include "ntqstyle.h" +#include "ntqwhatsthis.h" +#include "secqinternal_p.h" +#include "private/qtextlayout_p.h" +#include "ntqvaluevector.h" +#if defined(QT_ACCESSIBILITY_SUPPORT) +#include "ntqaccessible.h" +#endif + +#ifndef QT_NO_ACCEL +#include "ntqkeysequence.h" +#define ACCEL_KEY(k) "\t" + TQString(TQKeySequence( TQt::CTRL | TQt::Key_ ## k )) +#else +#define ACCEL_KEY(k) "\t" + TQString("Ctrl+" #k) +#endif + +#define innerMargin 1 + +struct SecTQLineEditPrivate : public TQt +{ + SecTQLineEditPrivate( SecTQLineEdit *q ) + : q(q), cursor(0), cursorTimer(0), tripleClickTimer(0), frame(1), + cursorVisible(0), separator(0), readOnly(0), modified(0), + direction(TQChar::DirON), alignment(0), + echoMode(0), textDirty(0), selDirty(0), + ascent(0), maxLength(32767), menuId(0), + hscroll(0), + undoState(0), selstart(0), selend(0), + imstart(0), imend(0), imselstart(0), imselend(0) + {} + void init( const SecTQString&); + + SecTQLineEdit *q; + SecTQString text; + int cursor; + int cursorTimer; + TQPoint tripleClick; + int tripleClickTimer; + uint frame : 1; + uint cursorVisible : 1; + uint separator : 1; + uint readOnly : 1; + uint modified : 1; + uint direction : 5; + uint alignment : 3; + uint echoMode : 2; + uint textDirty : 1; + uint selDirty : 1; + int ascent; + int maxLength; + int menuId; + int hscroll; + + void finishChange( int validateFromState = -1, bool setModified = TRUE ); + + void setCursorVisible( bool visible ); + + + // undo/redo handling + enum CommandType { Separator, Insert, Remove, Delete, RemoveSelection, DeleteSelection }; + struct Command { + inline Command(){} + inline Command( CommandType type, int pos, TQChar c ) + :type(type),c(c),pos(pos){} + uint type : 4; + TQChar c; + int pos; + }; + int undoState; + TQValueVector history; +#ifndef SECURE_NO_UNDO + void addCommand( const Command& cmd ); +#endif /* SECURE_NO_UNDO */ + + void insert( const SecTQString& s ); + void del( bool wasBackspace = FALSE ); + void remove( int pos ); + + inline void separate() { separator = TRUE; } +#ifndef SECURE_NO_UNDO + inline void undo( int until = -1 ) { + if ( !isUndoAvailable() ) + return; + deselect(); + while ( undoState && undoState > until ) { + Command& cmd = history[--undoState]; + switch ( cmd.type ) { + case Insert: + text.remove( cmd.pos, 1); + cursor = cmd.pos; + break; + case Remove: + case RemoveSelection: + text.insert( cmd.pos, cmd.c ); + cursor = cmd.pos + 1; + break; + case Delete: + case DeleteSelection: + text.insert( cmd.pos, cmd.c ); + cursor = cmd.pos; + break; + case Separator: + continue; + } + if ( until < 0 && undoState ) { + Command& next = history[undoState-1]; + if ( next.type != cmd.type && next.type < RemoveSelection + && !( cmd.type >= RemoveSelection && next.type != Separator ) ) + break; + } + } + modified = ( undoState != 0 ); + textDirty = TRUE; + } + inline void redo() { + if ( !isRedoAvailable() ) + return; + deselect(); + while ( undoState < (int)history.size() ) { + Command& cmd = history[undoState++]; + switch ( cmd.type ) { + case Insert: + text.insert( cmd.pos, cmd.c ); + cursor = cmd.pos + 1; + break; + case Remove: + case Delete: + case RemoveSelection: + case DeleteSelection: + text.remove( cmd.pos, 1 ); + cursor = cmd.pos; + break; + case Separator: + continue; + } + if ( undoState < (int)history.size() ) { + Command& next = history[undoState]; + if ( next.type != cmd.type && cmd.type < RemoveSelection + && !( next.type >= RemoveSelection && cmd.type != Separator ) ) + break; + } + } + textDirty = TRUE; + } +#endif /* SECURE_NO_UNDO */ + inline bool isUndoAvailable() const { return !readOnly && undoState; } + inline bool isRedoAvailable() const { return !readOnly && undoState < (int)history.size(); } + + + // bidi + inline bool isRightToLeft() const { return direction==TQChar::DirON?text.isRightToLeft():(direction==TQChar::DirR); } + + // selection + int selstart, selend; + inline bool allSelected() const { return !text.isEmpty() && selstart == 0 && selend == (int)text.length(); } + inline bool hasSelectedText() const { return !text.isEmpty() && selend > selstart; } + inline void deselect() { selDirty |= (selend > selstart); selstart = selend = 0; } + void removeSelectedText(); +#ifndef QT_NO_CLIPBOARD + void copy( bool clipboard = TRUE ) const; +#endif + inline bool inSelection( int x ) const + { if ( selstart >= selend ) return FALSE; + int pos = xToPos( x, TQTextItem::OnCharacters ); return pos >= selstart && pos < selend; } + + // input methods + int imstart, imend, imselstart, imselend; + + // complex text layout + TQTextLayout textLayout; + void updateTextLayout(); + void moveCursor( int pos, bool mark = FALSE ); + void setText( const SecTQString& txt ); + int xToPos( int x, TQTextItem::CursorPosition = TQTextItem::BetweenCharacters ) const; + inline int visualAlignment() const { return alignment ? alignment : int( isRightToLeft() ? AlignRight : AlignLeft ); } + TQRect cursorRect() const; + void updateMicroFocusHint(); + +}; + + +/*! + \class SecTQLineEdit + \brief The SecTQLineEdit widget is a one-line text editor. + + \ingroup basic + \mainclass + + A line edit allows the user to enter and edit a single line of + plain text with a useful collection of editing functions, + including undo and redo, cut and paste, + + By changing the echoMode() of a line edit, it can also be used as + a "write-only" field, for inputs such as passwords. + + The length of the text can be constrained to maxLength(). + + A related class is TQTextEdit which allows multi-line, rich-text + editing. + + You can change the text with setText() or insert(). The text is + retrieved with text(); the displayed text (which may be different, + see \l{EchoMode}) is retrieved with displayText(). Text can be + selected with setSelection() or selectAll(), and the selection can + be cut(), copy()ied and paste()d. The text can be aligned with + setAlignment(). + + When the text changes the textChanged() signal is emitted; when + the Return or Enter key is pressed the returnPressed() signal is + emitted. + + When the text changes the textModified() signal is emitted in all + cases. + + By default, SecTQLineEdits have a frame as specified by the Windows + and Motif style guides; you can turn it off by calling + setFrame(FALSE). + + The default key bindings are described below. + \target desc + \table + \header \i Keypress \i Action + \row \i Left Arrow \i Moves the cursor one character to the left. + \row \i Shift+Left Arrow \i Moves and selects text one character to the left. + \row \i Right Arrow \i Moves the cursor one character to the right. + \row \i Shift+Right Arrow \i Moves and selects text one character to the right. + \row \i Home \i Moves the cursor to the beginning of the line. + \row \i End \i Moves the cursor to the end of the line. + \row \i Backspace \i Deletes the character to the left of the cursor. + \row \i Ctrl+Backspace \i Deletes the word to the left of the cursor. + \row \i Delete \i Deletes the character to the right of the cursor. + \row \i Ctrl+Delete \i Deletes the word to the right of the cursor. + \row \i Ctrl+A \i Moves the cursor to the beginning of the line. + \row \i Ctrl+B \i Moves the cursor one character to the left. + \row \i Ctrl+C \i Copies the selected text to the clipboard. + (Windows also supports Ctrl+Insert for this operation.) + \row \i Ctrl+D \i Deletes the character to the right of the cursor. + \row \i Ctrl+E \i Moves the cursor to the end of the line. + \row \i Ctrl+F \i Moves the cursor one character to the right. + \row \i Ctrl+H \i Deletes the character to the left of the cursor. + \row \i Ctrl+K \i Deletes to the end of the line. + \row \i Ctrl+V \i Pastes the clipboard text into line edit. + (Windows also supports Shift+Insert for this operation.) + \row \i Ctrl+X \i Deletes the selected text and copies it to the clipboard. + (Windows also supports Shift+Delete for this operation.) + \row \i Ctrl+Z \i Undoes the last operation. + \row \i Ctrl+Y \i Redoes the last undone operation. + \endtable + + Any other key sequence that represents a valid character, will + cause the character to be inserted into the line edit. + + + + \sa TQTextEdit TQLabel TQComboBox + \link guibooks.html#fowler GUI Design Handbook: Field, Entry\endlink +*/ + + +/*! + \fn void SecTQLineEdit::textChanged( const SecTQString& ) + + This signal is emitted whenever the text changes. The argument is + the new text. +*/ + +/*! + \fn void SecTQLineEdit::selectionChanged() + + This signal is emitted whenever the selection changes. + + \sa hasSelectedText(), selectedText() +*/ + +/*! + \fn void SecTQLineEdit::lostFocus() + + This signal is emitted when the line edit has lost focus. + + \sa hasFocus(), TQWidget::focusInEvent(), TQWidget::focusOutEvent() +*/ + + + +/*! + Constructs a line edit with no text. + + The maximum text length is set to 32767 characters. + + The \a parent and \a name arguments are sent to the TQWidget constructor. + + \sa setText(), setMaxLength() +*/ + +SecTQLineEdit::SecTQLineEdit( TQWidget* parent, const char* name ) + : TQFrame( parent, name, WNoAutoErase ), d(new SecTQLineEditPrivate( this )) +{ + d->init( SecTQString::null ); +} + +/*! + Constructs a line edit containing the text \a contents. + + The cursor position is set to the end of the line and the maximum + text length to 32767 characters. + + The \a parent and \a name arguments are sent to the TQWidget + constructor. + + \sa text(), setMaxLength() +*/ + +SecTQLineEdit::SecTQLineEdit( const SecTQString& contents, TQWidget* parent, const char* name ) + : TQFrame( parent, name, WNoAutoErase ), d(new SecTQLineEditPrivate( this )) +{ + d->init( contents ); +} + +/*! + Destroys the line edit. +*/ + +SecTQLineEdit::~SecTQLineEdit() +{ + delete d; +} + + +/*! + \property SecTQLineEdit::text + \brief the line edit's text + + Setting this property clears the selection, clears the undo/redo + history, moves the cursor to the end of the line and resets the + \c modified property to FALSE. + + The text is truncated to maxLength() length. + + \sa insert() +*/ +SecTQString SecTQLineEdit::text() const +{ + return ( d->text.isNull() ? SecTQString ("") : d->text ); +} + +void SecTQLineEdit::setText( const SecTQString& text) +{ + resetInputContext(); + d->setText( text ); + d->modified = FALSE; + d->finishChange( -1, FALSE ); +} + + +/*! + \property SecTQLineEdit::displayText + \brief the displayed text + + If \c EchoMode is \c Normal this returns the same as text(); if + \c EchoMode is \c Password it returns a string of asterisks + text().length() characters long, e.g. "******"; if \c EchoMode is + \c NoEcho returns an empty string, "". + + \sa setEchoMode() text() EchoMode +*/ + +TQString SecTQLineEdit::displayText() const +{ + if ( d->echoMode == NoEcho ) + return TQString::fromLatin1(""); + + TQChar pwd_char = TQChar (style().styleHint( TQStyle::SH_LineEdit_PasswordCharacter, this)); + TQString res; + res.fill (pwd_char, d->text.length ()); + return res; +} + + +/*! + \property SecTQLineEdit::maxLength + \brief the maximum permitted length of the text + + If the text is too long, it is truncated at the limit. + + If truncation occurs any selected text will be unselected, the + cursor position is set to 0 and the first part of the string is + shown. +*/ + +int SecTQLineEdit::maxLength() const +{ + return d->maxLength; +} + +void SecTQLineEdit::setMaxLength( int maxLength ) +{ + d->maxLength = maxLength; + setText( d->text ); +} + + + +/*! + \property SecTQLineEdit::frame + \brief whether the line edit draws itself with a frame + + If enabled (the default) the line edit draws itself inside a + two-pixel frame, otherwise the line edit draws itself without any + frame. +*/ +bool SecTQLineEdit::frame() const +{ + return frameShape() != NoFrame; +} + + +void SecTQLineEdit::setFrame( bool enable ) +{ + setFrameStyle( enable ? ( LineEditPanel | Sunken ) : NoFrame ); +} + + +/*! + \enum SecTQLineEdit::EchoMode + + This enum type describes how a line edit should display its + contents. + + \value Normal Display characters as they are entered. This is the + default. + \value NoEcho Do not display anything. This may be appropriate + for passwords where even the length of the + password should be kept secret. + \value Password Display asterisks instead of the characters + actually entered. + + \sa setEchoMode() echoMode() +*/ + + +/*! + \property SecTQLineEdit::echoMode + \brief the line edit's echo mode + + The initial setting is \c Normal, but SecTQLineEdit also supports \c + NoEcho and \c Password modes. + + The widget's display and the ability to copy the text is affected + by this setting. + + \sa EchoMode displayText() +*/ + +SecTQLineEdit::EchoMode SecTQLineEdit::echoMode() const +{ + return (EchoMode) d->echoMode; +} + +void SecTQLineEdit::setEchoMode( EchoMode mode ) +{ + d->echoMode = mode; + d->updateTextLayout(); + update(); +} + + + +/*! + Returns a recommended size for the widget. + + The width returned, in pixels, is usually enough for about 15 to + 20 characters. +*/ + +TQSize SecTQLineEdit::sizeHint() const +{ + constPolish(); + TQFontMetrics fm( font() ); + int h = TQMAX(fm.lineSpacing(), 14) + 2*innerMargin; + int w = fm.width( 'x' ) * 17; // "some" + int m = frameWidth() * 2; + return (style().sizeFromContents(TQStyle::CT_LineEdit, this, + TQSize( w + m, h + m ). + expandedTo(TQApplication::globalStrut()))); +} + + +/*! + Returns a minimum size for the line edit. + + The width returned is enough for at least one character. +*/ + +TQSize SecTQLineEdit::minimumSizeHint() const +{ + constPolish(); + TQFontMetrics fm = fontMetrics(); + int h = fm.height() + TQMAX( 2*innerMargin, fm.leading() ); + int w = fm.maxWidth(); + int m = frameWidth() * 2; + return TQSize( w + m, h + m ); +} + + +/*! + \property SecTQLineEdit::cursorPosition + \brief the current cursor position for this line edit + + Setting the cursor position causes a repaint when appropriate. +*/ + +int SecTQLineEdit::cursorPosition() const +{ + return d->cursor; +} + + +void SecTQLineEdit::setCursorPosition( int pos ) +{ + if ( pos <= (int) d->text.length() ) + d->moveCursor( pos ); +} + + +/*! + \property SecTQLineEdit::alignment + \brief the alignment of the line edit + + Possible Values are \c TQt::AlignAuto, \c TQt::AlignLeft, \c + TQt::AlignRight and \c TQt::AlignHCenter. + + Attempting to set the alignment to an illegal flag combination + does nothing. + + \sa TQt::AlignmentFlags +*/ + +int SecTQLineEdit::alignment() const +{ + return d->alignment; +} + +void SecTQLineEdit::setAlignment( int flag ) +{ + d->alignment = flag & 0x7; + update(); +} + + +/*! + \obsolete + \fn void SecTQLineEdit::cursorRight( bool, int ) + + Use cursorForward() instead. + + \sa cursorForward() +*/ + +/*! + \obsolete + \fn void SecTQLineEdit::cursorLeft( bool, int ) + For compatibilty with older applications only. Use cursorBackward() + instead. + \sa cursorBackward() +*/ + +/*! + Moves the cursor forward \a steps characters. If \a mark is TRUE + each character moved over is added to the selection; if \a mark is + FALSE the selection is cleared. + + \sa cursorBackward() +*/ + +void SecTQLineEdit::cursorForward( bool mark, int steps ) +{ + int cursor = d->cursor; + if ( steps > 0 ) { + while( steps-- ) + cursor = d->textLayout.nextCursorPosition( cursor ); + } else if ( steps < 0 ) { + while ( steps++ ) + cursor = d->textLayout.previousCursorPosition( cursor ); + } + d->moveCursor( cursor, mark ); +} + + +/*! + Moves the cursor back \a steps characters. If \a mark is TRUE each + character moved over is added to the selection; if \a mark is + FALSE the selection is cleared. + + \sa cursorForward() +*/ +void SecTQLineEdit::cursorBackward( bool mark, int steps ) +{ + cursorForward( mark, -steps ); +} + +/*! + Moves the cursor one word forward. If \a mark is TRUE, the word is + also selected. + + \sa cursorWordBackward() +*/ +void SecTQLineEdit::cursorWordForward( bool mark ) +{ + d->moveCursor( d->textLayout.nextCursorPosition(d->cursor, TQTextLayout::SkipWords), mark ); +} + +/*! + Moves the cursor one word backward. If \a mark is TRUE, the word + is also selected. + + \sa cursorWordForward() +*/ + +void SecTQLineEdit::cursorWordBackward( bool mark ) +{ + d->moveCursor( d->textLayout.previousCursorPosition(d->cursor, TQTextLayout::SkipWords), mark ); +} + + +/*! + If no text is selected, deletes the character to the left of the + text cursor and moves the cursor one position to the left. If any + text is selected, the cursor is moved to the beginning of the + selected text and the selected text is deleted. + + \sa del() +*/ +void SecTQLineEdit::backspace() +{ + int priorState = d->undoState; + if ( d->hasSelectedText() ) { + d->removeSelectedText(); + } else if ( d->cursor ) { + --d->cursor; + d->del( TRUE ); + } + d->finishChange( priorState ); +} + +/*! + If no text is selected, deletes the character to the right of the + text cursor. If any text is selected, the cursor is moved to the + beginning of the selected text and the selected text is deleted. + + \sa backspace() +*/ + +void SecTQLineEdit::del() +{ + int priorState = d->undoState; + if ( d->hasSelectedText() ) { + d->removeSelectedText(); + } else { + int n = d->textLayout.nextCursorPosition( d->cursor ) - d->cursor; + while ( n-- ) + d->del(); + } + d->finishChange( priorState ); +} + +/*! + Moves the text cursor to the beginning of the line unless it is + already there. If \a mark is TRUE, text is selected towards the + first position; otherwise, any selected text is unselected if the + cursor is moved. + + \sa end() +*/ + +void SecTQLineEdit::home( bool mark ) +{ + d->moveCursor( 0, mark ); +} + +/*! + Moves the text cursor to the end of the line unless it is already + there. If \a mark is TRUE, text is selected towards the last + position; otherwise, any selected text is unselected if the cursor + is moved. + + \sa home() +*/ + +void SecTQLineEdit::end( bool mark ) +{ + d->moveCursor( d->text.length(), mark ); +} + + +/*! + \property SecTQLineEdit::modified + \brief whether the line edit's contents has been modified by the user + + The modified flag is never read by SecTQLineEdit; it has a default value + of FALSE and is changed to TRUE whenever the user changes the line + edit's contents. + + This is useful for things that need to provide a default value but + do not start out knowing what the default should be (perhaps it + depends on other fields on the form). Start the line edit without + the best default, and when the default is known, if modified() + returns FALSE (the user hasn't entered any text), insert the + default value. + + Calling clearModified() or setText() resets the modified flag to + FALSE. +*/ + +bool SecTQLineEdit::isModified() const +{ + return d->modified; +} + +/*! + Resets the modified flag to FALSE. + + \sa isModified() +*/ +void SecTQLineEdit::clearModified() +{ + d->modified = FALSE; + d->history.clear(); + d->undoState = 0; +} + +/*! + \obsolete + \property SecTQLineEdit::edited + \brief whether the line edit has been edited. Use modified instead. +*/ +bool SecTQLineEdit::edited() const { return d->modified; } +void SecTQLineEdit::setEdited( bool on ) { d->modified = on; } + +/*! + \obsolete + \property SecTQLineEdit::hasMarkedText + \brief whether part of the text has been selected by the user. Use hasSelectedText instead. +*/ + +/*! + \property SecTQLineEdit::hasSelectedText + \brief whether there is any text selected + + hasSelectedText() returns TRUE if some or all of the text has been + selected by the user; otherwise returns FALSE. + + \sa selectedText() +*/ + + +bool SecTQLineEdit::hasSelectedText() const +{ + return d->hasSelectedText(); +} + +/*! + \obsolete + \property SecTQLineEdit::markedText + \brief the text selected by the user. Use selectedText instead. +*/ + +/*! + \property SecTQLineEdit::selectedText + \brief the selected text + + If there is no selected text this property's value is + TQString::null. + + \sa hasSelectedText() +*/ + +SecTQString SecTQLineEdit::selectedText() const +{ + if ( d->hasSelectedText() ) + return d->text.mid( d->selstart, d->selend - d->selstart ); + return SecTQString::null; +} + +/*! + selectionStart() returns the index of the first selected character in the + line edit or -1 if no text is selected. + + \sa selectedText() +*/ + +int SecTQLineEdit::selectionStart() const +{ + return d->hasSelectedText() ? d->selstart : -1; +} + + +/*! + Selects text from position \a start and for \a length characters. + + \sa deselect() selectAll() +*/ + +void SecTQLineEdit::setSelection( int start, int length ) +{ + if ( start < 0 || start > (int)d->text.length() || length < 0 ) { + d->selstart = d->selend = 0; + } else { + d->selstart = start; + d->selend = TQMIN( start + length, (int)d->text.length() ); + d->cursor = d->selend; + } + update(); +} + + +/*! + \property SecTQLineEdit::undoAvailable + \brief whether undo is available +*/ + +bool SecTQLineEdit::isUndoAvailable() const +{ + return d->isUndoAvailable(); +} + +/*! + \property SecTQLineEdit::redoAvailable + \brief whether redo is available +*/ + +bool SecTQLineEdit::isRedoAvailable() const +{ + return d->isRedoAvailable(); +} + +/*! + Selects all the text (i.e. highlights it) and moves the cursor to + the end. This is useful when a default value has been inserted + because if the user types before clicking on the widget, the + selected text will be deleted. + + \sa setSelection() deselect() +*/ + +void SecTQLineEdit::selectAll() +{ + d->selstart = d->selend = d->cursor = 0; + d->moveCursor( d->text.length(), TRUE ); +} + +/*! + Deselects any selected text. + + \sa setSelection() selectAll() +*/ + +void SecTQLineEdit::deselect() +{ + d->deselect(); + d->finishChange(); +} + + +/*! + Deletes any selected text, inserts \a newText and sets it as the + new contents of the line edit. +*/ +void SecTQLineEdit::insert( const SecTQString &newText ) +{ +// q->resetInputContext(); //#### FIX ME IN QT + int priorState = d->undoState; + d->removeSelectedText(); + d->insert( newText ); + d->finishChange( priorState ); +} + +/*! + Clears the contents of the line edit. +*/ +void SecTQLineEdit::clear() +{ + int priorState = d->undoState; + resetInputContext(); + d->selstart = 0; + d->selend = d->text.length(); + d->removeSelectedText(); + d->separate(); + d->finishChange( priorState ); +} + +/*! + Undoes the last operation if undo is \link + SecTQLineEdit::undoAvailable available\endlink. Deselects any current + selection, and updates the selection start to the current cursor + position. +*/ +void SecTQLineEdit::undo() +{ +#ifndef SECURE_NO_UNDO + resetInputContext(); + d->undo(); + d->finishChange( -1, FALSE ); +#endif +} + +/*! + Redoes the last operation if redo is \link + SecTQLineEdit::redoAvailable available\endlink. +*/ +void SecTQLineEdit::redo() +{ +#ifndef SECURE_NO_UNDO + resetInputContext(); + d->redo(); + d->finishChange(); +#endif +} + + +/*! + \property SecTQLineEdit::readOnly + \brief whether the line edit is read only. + + In read-only mode, the user can still copy the text to the + clipboard (if echoMode() is \c Normal), but cannot edit it. + + SecTQLineEdit does not show a cursor in read-only mode. + + \sa setEnabled() +*/ + +bool SecTQLineEdit::isReadOnly() const +{ + return d->readOnly; +} + +void SecTQLineEdit::setReadOnly( bool enable ) +{ + d->readOnly = enable; +#ifndef QT_NO_CURSOR + setCursor( enable ? arrowCursor : ibeamCursor ); +#endif + update(); +} + + +#ifndef QT_NO_CLIPBOARD +/*! + Copies the selected text to the clipboard and deletes it, if there + is any, and if echoMode() is \c Normal. + + \sa copy() paste() setValidator() +*/ + +void SecTQLineEdit::cut() +{ + if ( hasSelectedText() ) { + copy(); + del(); + } +} + + +/*! + Copies the selected text to the clipboard, if there is any, and if + echoMode() is \c Normal. + + \sa cut() paste() +*/ + +void SecTQLineEdit::copy() const +{ + d->copy(); +} + +/*! + Inserts the clipboard's text at the cursor position, deleting any + selected text, providing the line edit is not \link + SecTQLineEdit::readOnly read-only\endlink. + + \sa copy() cut() +*/ + +void SecTQLineEdit::paste() +{ + d->removeSelectedText(); + insert( TQApplication::clipboard()->text( TQClipboard::Clipboard ) ); +} + +void SecTQLineEditPrivate::copy( bool clipboard ) const +{ +#ifndef SECURE + TQString t = q->selectedText(); + if ( !t.isEmpty() && echoMode == SecTQLineEdit::Normal ) { + q->disconnect( TQApplication::clipboard(), SIGNAL(selectionChanged()), q, 0); + TQApplication::clipboard()->setText( t, clipboard ? TQClipboard::Clipboard : TQClipboard::Selection ); + q->connect( TQApplication::clipboard(), SIGNAL(selectionChanged()), + q, SLOT(clipboardChanged()) ); + } +#endif +} + +#endif // !QT_NO_CLIPBOARD + +/*!\reimp +*/ + +void SecTQLineEdit::resizeEvent( TQResizeEvent *e ) +{ + TQFrame::resizeEvent( e ); +} + +/*! \reimp +*/ +bool SecTQLineEdit::event( TQEvent * e ) +{ + if ( e->type() == TQEvent::AccelOverride && !d->readOnly ) { + TQKeyEvent* ke = (TQKeyEvent*) e; + if ( ke->state() == NoButton || ke->state() == ShiftButton + || ke->state() == Keypad ) { + if ( ke->key() < Key_Escape ) { + ke->accept(); + } else if ( ke->state() == NoButton + || ke->state() == ShiftButton ) { + switch ( ke->key() ) { + case Key_Delete: + case Key_Home: + case Key_End: + case Key_Backspace: + case Key_Left: + case Key_Right: + ke->accept(); + default: + break; + } + } + } else if ( ke->state() & ControlButton ) { + switch ( ke->key() ) { +// Those are too frequently used for application functionality +/* case Key_A: + case Key_B: + case Key_D: + case Key_E: + case Key_F: + case Key_H: + case Key_K: +*/ + case Key_C: + case Key_V: + case Key_X: + case Key_Y: + case Key_Z: + case Key_Left: + case Key_Right: +#if defined (Q_WS_WIN) + case Key_Insert: + case Key_Delete: +#endif + ke->accept(); + default: + break; + } + } + } else if ( e->type() == TQEvent::Timer ) { + // should be timerEvent, is here for binary compatibility + int timerId = ((TQTimerEvent*)e)->timerId(); + if ( timerId == d->cursorTimer ) { + if(!hasSelectedText() || style().styleHint( TQStyle::SH_BlinkCursorWhenTextSelected )) + d->setCursorVisible( !d->cursorVisible ); + } else if ( timerId == d->tripleClickTimer ) { + killTimer( d->tripleClickTimer ); + d->tripleClickTimer = 0; + } + } + return TQWidget::event( e ); +} + +/*! \reimp +*/ +void SecTQLineEdit::mousePressEvent( TQMouseEvent* e ) +{ + if ( e->button() == RightButton ) + return; + if ( d->tripleClickTimer && ( e->pos() - d->tripleClick ).manhattanLength() < + TQApplication::startDragDistance() ) { + selectAll(); + return; + } + bool mark = e->state() & ShiftButton; + int cursor = d->xToPos( e->pos().x() ); + d->moveCursor( cursor, mark ); +} + +/*! \reimp +*/ +void SecTQLineEdit::mouseMoveEvent( TQMouseEvent * e ) +{ + +#ifndef QT_NO_CURSOR + if ( ( e->state() & MouseButtonMask ) == 0 ) { + if ( !d->readOnly ) + setCursor( ( d->inSelection( e->pos().x() ) ? arrowCursor : ibeamCursor ) ); + } +#endif + + if ( e->state() & LeftButton ) { + d->moveCursor( d->xToPos( e->pos().x() ), TRUE ); + } +} + +/*! \reimp +*/ +void SecTQLineEdit::mouseReleaseEvent( TQMouseEvent* e ) +{ +#ifndef QT_NO_CLIPBOARD + if (TQApplication::clipboard()->supportsSelection() ) { + if ( e->button() == LeftButton ) { + d->copy( FALSE ); + } else if ( !d->readOnly && e->button() == MidButton ) { + d->deselect(); + insert( TQApplication::clipboard()->text( TQClipboard::Selection ) ); + } + } +#endif +} + +/*! \reimp +*/ +void SecTQLineEdit::mouseDoubleClickEvent( TQMouseEvent* e ) +{ + if ( e->button() == TQt::LeftButton ) { + deselect(); + d->cursor = d->xToPos( e->pos().x() ); + d->cursor = d->textLayout.previousCursorPosition( d->cursor, TQTextLayout::SkipWords ); + // ## text layout should support end of words. + int end = d->textLayout.nextCursorPosition( d->cursor, TQTextLayout::SkipWords ); + while ( end > d->cursor && d->text[end-1].isSpace() ) + --end; + d->moveCursor( end, TRUE ); + d->tripleClickTimer = startTimer( TQApplication::doubleClickInterval() ); + d->tripleClick = e->pos(); + } +} + +/*! + \fn void SecTQLineEdit::returnPressed() + + This signal is emitted when the Return or Enter key is pressed. +*/ + +/*! + Converts key press event \a e into a line edit action. + + If Return or Enter is pressed the signal returnPressed() is + emitted. + + The default key bindings are listed in the \link #desc detailed + description.\endlink +*/ + +void SecTQLineEdit::keyPressEvent( TQKeyEvent * e ) +{ + d->setCursorVisible( TRUE ); + if ( e->key() == Key_Enter || e->key() == Key_Return ) { + emit returnPressed(); + e->ignore(); + return; + } + if ( !d->readOnly ) { + TQString t = e->text(); + if ( !t.isEmpty() && (!e->ascii() || e->ascii()>=32) && + e->key() != Key_Delete && + e->key() != Key_Backspace ) { +#ifdef Q_WS_X11 + extern bool tqt_hebrew_keyboard_hack; + if ( tqt_hebrew_keyboard_hack ) { + // the X11 keyboard layout is broken and does not reverse + // braces correctly. This is a hack to get halfway correct + // behaviour + if ( d->isRightToLeft() ) { + TQChar *c = (TQChar *)t.unicode(); + int l = t.length(); + while( l-- ) { + if ( c->mirrored() ) + *c = c->mirroredChar(); + c++; + } + } + } +#endif + insert( t ); + return; + } + } + bool unknown = FALSE; + if ( e->state() & ControlButton ) { + switch ( e->key() ) { + case Key_A: +#if defined(Q_WS_X11) + home( e->state() & ShiftButton ); +#else + selectAll(); +#endif + break; + case Key_B: + cursorForward( e->state() & ShiftButton, -1 ); + break; +#ifndef QT_NO_CLIPBOARD + case Key_C: + copy(); + break; +#endif + case Key_D: + if ( !d->readOnly ) { + del(); + } + break; + case Key_E: + end( e->state() & ShiftButton ); + break; + case Key_F: + cursorForward( e->state() & ShiftButton, 1 ); + break; + case Key_H: + if ( !d->readOnly ) { + backspace(); + } + break; + case Key_K: + if ( !d->readOnly ) { + int priorState = d->undoState; + d->deselect(); + while ( d->cursor < (int) d->text.length() ) + d->del(); + d->finishChange( priorState ); + } + break; +#if defined(Q_WS_X11) + case Key_U: + if ( !d->readOnly ) + clear(); + break; +#endif +#ifndef QT_NO_CLIPBOARD + case Key_V: + if ( !d->readOnly ) + paste(); + break; + case Key_X: + if ( !d->readOnly && d->hasSelectedText() && echoMode() == Normal ) { + copy(); + del(); + } + break; +#if defined (Q_WS_WIN) + case Key_Insert: + copy(); + break; +#endif +#endif + case Key_Delete: + if ( !d->readOnly ) { + cursorWordForward( TRUE ); + del(); + } + break; + case Key_Backspace: + if ( !d->readOnly ) { + cursorWordBackward( TRUE ); + del(); + } + break; + case Key_Right: + case Key_Left: + if ( d->isRightToLeft() == (e->key() == Key_Right) ) { + if ( echoMode() == Normal ) + cursorWordBackward( e->state() & ShiftButton ); + else + home( e->state() & ShiftButton ); + } else { + if ( echoMode() == Normal ) + cursorWordForward( e->state() & ShiftButton ); + else + end( e->state() & ShiftButton ); + } + break; + case Key_Z: + if ( !d->readOnly ) { + if(e->state() & ShiftButton) + redo(); + else + undo(); + } + break; + case Key_Y: + if ( !d->readOnly ) + redo(); + break; + default: + unknown = TRUE; + } + } else { // ### check for *no* modifier + switch ( e->key() ) { + case Key_Shift: + // ### TODO + break; + case Key_Left: + case Key_Right: { + int step = (d->isRightToLeft() == (e->key() == Key_Right)) ? -1 : 1; + cursorForward( e->state() & ShiftButton, step ); + } + break; + case Key_Backspace: + if ( !d->readOnly ) { + backspace(); + } + break; + case Key_Home: +#ifdef Q_WS_MACX + case Key_Up: +#endif + home( e->state() & ShiftButton ); + break; + case Key_End: +#ifdef Q_WS_MACX + case Key_Down: +#endif + end( e->state() & ShiftButton ); + break; + case Key_Delete: + if ( !d->readOnly ) { +#if defined (Q_WS_WIN) + if ( e->state() & ShiftButton ) { + cut(); + break; + } +#endif + del(); + } + break; +#if defined (Q_WS_WIN) + case Key_Insert: + if ( !d->readOnly && e->state() & ShiftButton ) + paste(); + else + unknown = TRUE; + break; +#endif + case Key_F14: // Undo key on Sun keyboards + if ( !d->readOnly ) + undo(); + break; +#ifndef QT_NO_CLIPBOARD + case Key_F16: // Copy key on Sun keyboards + copy(); + break; + case Key_F18: // Paste key on Sun keyboards + if ( !d->readOnly ) + paste(); + break; + case Key_F20: // Cut key on Sun keyboards + if ( !d->readOnly && hasSelectedText() && echoMode() == Normal ) { + copy(); + del(); + } + break; +#endif + default: + unknown = TRUE; + } + } + if ( e->key() == Key_Direction_L ) + d->direction = TQChar::DirL; + else if ( e->key() == Key_Direction_R ) + d->direction = TQChar::DirR; + + if ( unknown ) + e->ignore(); +} + +/*! \reimp + */ +void SecTQLineEdit::imStartEvent( TQIMEvent *e ) +{ + if ( d->readOnly ) { + e->ignore(); + return; + } + d->removeSelectedText(); + d->updateMicroFocusHint(); + d->imstart = d->imend = d->imselstart = d->imselend = d->cursor; +} + +/*! \reimp + */ +void SecTQLineEdit::imComposeEvent( TQIMEvent *e ) +{ + if ( d->readOnly ) { + e->ignore(); + } else { + d->text.replace( d->imstart, d->imend - d->imstart, e->text() ); + d->imend = d->imstart + e->text().length(); + d->imselstart = d->imstart + e->cursorPos(); + d->imselend = d->imselstart + e->selectionLength(); + d->cursor = e->selectionLength() ? d->imend : d->imselend; + d->updateTextLayout(); + update(); + } +} + +/*! \reimp + */ +void SecTQLineEdit::imEndEvent( TQIMEvent *e ) +{ + if ( d->readOnly ) { + e->ignore(); + } else { + d->text.remove( d->imstart, d->imend - d->imstart ); + d->cursor = d->imselstart = d->imselend = d->imend = d->imstart; + d->textDirty = TRUE; + insert( e->text() ); + } +} + +/*!\reimp +*/ + +void SecTQLineEdit::focusInEvent( TQFocusEvent* e ) +{ + if ( e->reason() == TQFocusEvent::Tab || + e->reason() == TQFocusEvent::Backtab || + e->reason() == TQFocusEvent::Shortcut ) + selectAll(); + if ( !d->cursorTimer ) { + int cft = TQApplication::cursorFlashTime(); + d->cursorTimer = cft ? startTimer( cft/2 ) : -1; + } + d->updateMicroFocusHint(); +} + +/*!\reimp +*/ + +void SecTQLineEdit::focusOutEvent( TQFocusEvent* e ) +{ + if ( e->reason() != TQFocusEvent::ActiveWindow && + e->reason() != TQFocusEvent::Popup ) + deselect(); + d->setCursorVisible( FALSE ); + if ( d->cursorTimer > 0 ) + killTimer( d->cursorTimer ); + d->cursorTimer = 0; + emit lostFocus(); +} + +/*!\reimp +*/ +void SecTQLineEdit::drawContents( TQPainter *p ) +{ + const TQColorGroup& cg = colorGroup(); + TQRect cr = contentsRect(); + TQFontMetrics fm = fontMetrics(); + TQRect lineRect( cr.x() + innerMargin, cr.y() + (cr.height() - fm.height() + 1) / 2, + cr.width() - 2*innerMargin, fm.height() ); + TQBrush bg = TQBrush( paletteBackgroundColor() ); + if ( paletteBackgroundPixmap() ) + bg = TQBrush( cg.background(), *paletteBackgroundPixmap() ); + else if ( !isEnabled() ) + bg = cg.brush( TQColorGroup::Background ); + p->save(); + p->setClipRegion( TQRegion(cr) - lineRect ); + p->fillRect( cr, bg ); + p->restore(); + SecTQSharedDoubleBuffer buffer( p, lineRect.x(), lineRect.y(), + lineRect.width(), lineRect.height(), + hasFocus() ? SecTQSharedDoubleBuffer::Force : 0 ); + p = buffer.painter(); + p->fillRect( lineRect, bg ); + + // locate cursor position + int cix = 0; + TQTextItem ci = d->textLayout.findItem( d->cursor ); + if ( ci.isValid() ) { + if ( d->cursor != (int)d->text.length() && d->cursor == ci.from() + ci.length() + && ci.isRightToLeft() != d->isRightToLeft() ) + ci = d->textLayout.findItem( d->cursor + 1 ); + cix = ci.x() + ci.cursorToX( d->cursor - ci.from() ); + } + + // horizontal scrolling + int minLB = TQMAX( 0, -fm.minLeftBearing() ); + int minRB = TQMAX( 0, -fm.minRightBearing() ); + int widthUsed = d->textLayout.widthUsed() + 1 + minRB; + if ( (minLB + widthUsed) <= lineRect.width() ) { + switch ( d->visualAlignment() ) { + case AlignRight: + d->hscroll = widthUsed - lineRect.width(); + break; + case AlignHCenter: + d->hscroll = ( widthUsed - lineRect.width() ) / 2; + break; + default: + d->hscroll = 0; + break; + } + d->hscroll -= minLB; + } else if ( cix - d->hscroll >= lineRect.width() ) { + d->hscroll = cix - lineRect.width() + 1; + } else if ( cix - d->hscroll < 0 ) { + d->hscroll = cix; + } else if ( widthUsed - d->hscroll < lineRect.width() ) { + d->hscroll = widthUsed - lineRect.width() + 1; + } + // the y offset is there to keep the baseline constant in case we have script changes in the text. + TQPoint topLeft = lineRect.topLeft() - TQPoint(d->hscroll, d->ascent-fm.ascent()); + + // draw text, selections and cursors + p->setPen( cg.text() ); + bool supressCursor = d->readOnly, hasRightToLeft = d->isRightToLeft(); + int textflags = 0; + if ( font().underline() ) + textflags |= TQt::Underline; + if ( font().strikeOut() ) + textflags |= TQt::StrikeOut; + if ( font().overline() ) + textflags |= TQt::Overline; + + for ( int i = 0; i < d->textLayout.numItems(); i++ ) { + TQTextItem ti = d->textLayout.itemAt( i ); + hasRightToLeft |= ti.isRightToLeft(); + int tix = topLeft.x() + ti.x(); + int first = ti.from(); + int last = ti.from() + ti.length() - 1; + + // text and selection + if ( d->selstart < d->selend && (last >= d->selstart && first < d->selend ) ) { + TQRect highlight = TQRect( TQPoint( tix + ti.cursorToX( TQMAX( d->selstart - first, 0 ) ), + lineRect.top() ), + TQPoint( tix + ti.cursorToX( TQMIN( d->selend - first, last - first + 1 ) ) - 1, + lineRect.bottom() ) ).normalize(); + p->save(); + p->setClipRegion( TQRegion( lineRect ) - highlight, TQPainter::CoordPainter ); + p->drawTextItem( topLeft, ti, textflags ); + p->setClipRect( lineRect & highlight, TQPainter::CoordPainter ); + p->fillRect( highlight, cg.highlight() ); + p->setPen( cg.highlightedText() ); + p->drawTextItem( topLeft, ti, textflags ); + p->restore(); + } else { + p->drawTextItem( topLeft, ti, textflags ); + } + + // input method edit area + if ( d->imstart < d->imend && (last >= d->imstart && first < d->imend ) ) { + TQRect highlight = TQRect( TQPoint( tix + ti.cursorToX( TQMAX( d->imstart - first, 0 ) ), lineRect.top() ), + TQPoint( tix + ti.cursorToX( TQMIN( d->imend - first, last - first + 1 ) )-1, lineRect.bottom() ) ).normalize(); + p->save(); + p->setClipRect( lineRect & highlight, TQPainter::CoordPainter ); + + int h1, s1, v1, h2, s2, v2; + cg.color( TQColorGroup::Base ).hsv( &h1, &s1, &v1 ); + cg.color( TQColorGroup::Background ).hsv( &h2, &s2, &v2 ); + TQColor imCol; + imCol.setHsv( h1, s1, ( v1 + v2 ) / 2 ); + p->fillRect( highlight, imCol ); + p->drawTextItem( topLeft, ti, textflags ); + p->restore(); + } + + // input method selection + if ( d->imselstart < d->imselend && (last >= d->imselstart && first < d->imselend ) ) { + TQRect highlight = TQRect( TQPoint( tix + ti.cursorToX( TQMAX( d->imselstart - first, 0 ) ), lineRect.top() ), + TQPoint( tix + ti.cursorToX( TQMIN( d->imselend - first, last - first + 1 ) )-1, lineRect.bottom() ) ).normalize(); + p->save(); + p->setClipRect( lineRect & highlight, TQPainter::CoordPainter ); + p->fillRect( highlight, cg.text() ); + p->setPen( paletteBackgroundColor() ); + p->drawTextItem( topLeft, ti, textflags ); + p->restore(); + } + } + + // draw cursor + if ( d->cursorVisible && !supressCursor ) { + TQPoint from( topLeft.x() + cix, lineRect.top() ); + TQPoint to = from + TQPoint( 0, lineRect.height() ); + p->drawLine( from, to ); + if ( hasRightToLeft ) { + to = from + TQPoint( (ci.isRightToLeft()?-2:2), 2 ); + p->drawLine( from, to ); + from.ry() += 4; + p->drawLine( from, to ); + } + } + buffer.end(); +} + + +enum { IdUndo, IdRedo, IdSep1, IdCut, IdCopy, IdPaste, IdClear, IdSep2, IdSelectAll }; + + +/*! \reimp */ +void SecTQLineEdit::windowActivationChange( bool b ) +{ + //### remove me with WHighlightSelection attribute + if ( palette().active() != palette().inactive() ) + update(); + TQWidget::windowActivationChange( b ); +} + +/*! \reimp */ + +void SecTQLineEdit::setPalette( const TQPalette & p ) +{ + //### remove me with WHighlightSelection attribute + TQWidget::setPalette( p ); + update(); +} + +/*! + \obsolete + \fn void SecTQLineEdit::repaintArea( int from, int to ) + Repaints all characters from \a from to \a to. If cursorPos is + between from and to, ensures that cursorPos is visible. +*/ + +/*! \reimp + */ +void SecTQLineEdit::setFont( const TQFont & f ) +{ + TQWidget::setFont( f ); + d->updateTextLayout(); +} + + +void SecTQLineEdit::clipboardChanged() +{ +} + +void SecTQLineEditPrivate::init( const SecTQString& txt ) +{ +#ifndef QT_NO_CURSOR + q->setCursor( readOnly ? arrowCursor : ibeamCursor ); +#endif + q->setFocusPolicy( TQWidget::StrongFocus ); + q->setInputMethodEnabled( TRUE ); + // Specifies that this widget can use more, but is able to survive on + // less, horizontal space; and is fixed vertically. + q->setSizePolicy( TQSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Fixed ) ); + q->setBackgroundMode( PaletteBase ); + q->setKeyCompression( TRUE ); + q->setMouseTracking( TRUE ); + q->setAcceptDrops( TRUE ); + q->setFrame( TRUE ); + text = txt; + updateTextLayout(); + cursor = text.length(); +} + +void SecTQLineEditPrivate::updateTextLayout() +{ + // replace all non-printable characters with spaces (to avoid + // drawing boxes when using fonts that don't have glyphs for such + // characters) + const TQString &displayText = q->displayText(); + TQString str(displayText.unicode(), displayText.length()); + TQChar* uc = (TQChar*)str.unicode(); + for (int i = 0; i < (int)str.length(); ++i) { + if (! uc[i].isPrint()) + uc[i] = TQChar(0x0020); + } + textLayout.setText( str, q->font() ); + // ### want to do textLayout.setRightToLeft( text.isRightToLeft() ); + textLayout.beginLayout( TQTextLayout::SingleLine ); + textLayout.beginLine( INT_MAX ); + while ( !textLayout.atEnd() ) + textLayout.addCurrentItem(); + ascent = 0; + textLayout.endLine(0, 0, TQt::AlignLeft, &ascent); +} + +int SecTQLineEditPrivate::xToPos( int x, TQTextItem::CursorPosition betweenOrOn ) const +{ + x-= q->contentsRect().x() - hscroll + innerMargin; + for ( int i = 0; i < textLayout.numItems(); ++i ) { + TQTextItem ti = textLayout.itemAt( i ); + TQRect tir = ti.rect(); + if ( x >= tir.left() && x <= tir.right() ) + return ti.xToCursor( x - tir.x(), betweenOrOn ) + ti.from(); + } + return x < 0 ? 0 : text.length(); +} + + +TQRect SecTQLineEditPrivate::cursorRect() const +{ + TQRect cr = q->contentsRect(); + int cix = cr.x() - hscroll + innerMargin; + TQTextItem ci = textLayout.findItem( cursor ); + if ( ci.isValid() ) { + if ( cursor != (int)text.length() && cursor == ci.from() + ci.length() + && ci.isRightToLeft() != isRightToLeft() ) + ci = textLayout.findItem( cursor + 1 ); + cix += ci.x() + ci.cursorToX( cursor - ci.from() ); + } + int ch = q->fontMetrics().height(); + return TQRect( cix-4, cr.y() + ( cr.height() - ch + 1) / 2, 8, ch + 1 ); +} + +void SecTQLineEditPrivate::updateMicroFocusHint() +{ + if ( q->hasFocus() ) { + TQRect r = cursorRect(); + q->setMicroFocusHint( r.x(), r.y(), r.width(), r.height() ); + } +} + +void SecTQLineEditPrivate::moveCursor( int pos, bool mark ) +{ + if ( pos != cursor ) + separate(); + bool fullUpdate = mark || hasSelectedText(); + if ( mark ) { + int anchor; + if ( selend > selstart && cursor == selstart ) + anchor = selend; + else if ( selend > selstart && cursor == selend ) + anchor = selstart; + else + anchor = cursor; + selstart = TQMIN( anchor, pos ); + selend = TQMAX( anchor, pos ); + } else { + selstart = selend = 0; + } + if ( fullUpdate ) { + cursor = pos; + q->update(); + } else { + setCursorVisible( FALSE ); + cursor = pos; + setCursorVisible( TRUE ); + } + updateMicroFocusHint(); + if ( mark ) { + if( !q->style().styleHint( TQStyle::SH_BlinkCursorWhenTextSelected )) + setCursorVisible( FALSE ); + emit q->selectionChanged(); + } +} + +void SecTQLineEditPrivate::finishChange( int validateFromState, bool setModified ) +{ + bool lineDirty = selDirty; + if ( textDirty ) { + if ( validateFromState >= 0 ) { +#ifndef SECURE_NO_UNDO + undo( validateFromState ); +#endif /* SECURE_NO_UNDO */ + history.resize( undoState ); + textDirty = setModified = FALSE; + } + updateTextLayout(); + updateMicroFocusHint(); + lineDirty |= textDirty; + if ( setModified ) + modified = TRUE; + if ( textDirty ) { + textDirty = FALSE; + emit q->textChanged( text ); + } + emit q->textModified( text ); +#if defined(QT_ACCESSIBILITY_SUPPORT) + TQAccessible::updateAccessibility( q, 0, TQAccessible::ValueChanged ); +#endif + } + if ( selDirty ) { + selDirty = FALSE; + emit q->selectionChanged(); + } + if ( lineDirty || !setModified ) + q->update(); +} + +void SecTQLineEditPrivate::setText( const SecTQString& txt ) +{ + deselect(); + SecTQString oldText = text; + text = txt.isEmpty() ? SecTQString ("") : txt.left( maxLength ); + history.clear(); + undoState = 0; + cursor = text.length(); + textDirty = 1; // Err on safe side. +} + + +void SecTQLineEditPrivate::setCursorVisible( bool visible ) +{ + if ( (bool)cursorVisible == visible ) + return; + if ( cursorTimer ) + cursorVisible = visible; + TQRect r = cursorRect(); + if ( !q->contentsRect().contains( r ) ) + q->update(); + else + q->update( r ); +} + +#ifndef SECURE_NO_UNDO + +void SecTQLineEditPrivate::addCommand( const Command& cmd ) +{ + if ( separator && undoState && history[undoState-1].type != Separator ) { + history.resize( undoState + 2 ); + history[undoState++] = Command( Separator, 0, 0 ); + } else { + history.resize( undoState + 1); + } + separator = FALSE; + history[ undoState++ ] = cmd; +} +#endif /* SECURE_NO_UNDO */ + +void SecTQLineEditPrivate::insert( const SecTQString& s ) +{ + int remaining = maxLength - text.length(); + text.insert( cursor, s.left(remaining) ); + for ( int i = 0; i < (int) s.left(remaining).length(); ++i ) + { +#ifndef SECURE_NO_UNDO + addCommand( Command( Insert, cursor, s.at(i) ) ); +#endif /* SECURE_NO_UNDO */ + cursor++; + } + textDirty = TRUE; +} + +void SecTQLineEditPrivate::del( bool wasBackspace ) +{ + if ( cursor < (int) text.length() ) { +#ifndef SECURE_NO_UNDO + addCommand ( Command( (CommandType)(wasBackspace?Remove:Delete), cursor, text.at(cursor) ) ); +#endif /* SECURE_NO_UNDO */ + text.remove( cursor, 1 ); + textDirty = TRUE; + } +} + +void SecTQLineEditPrivate::removeSelectedText() +{ + if ( selstart < selend && selend <= (int) text.length() ) { + separate(); +#ifndef SECURE_NO_UNDO + int i ; + if ( selstart <= cursor && cursor < selend ) { + // cursor is within the selection. Split up the commands + // to be able to restore the correct cursor position + for ( i = cursor; i >= selstart; --i ) + addCommand ( Command( DeleteSelection, i, text.at(i) ) ); + for ( i = selend - 1; i > cursor; --i ) + addCommand ( Command( DeleteSelection, i - cursor + selstart - 1, text.at(i) ) ); + } else { + for ( i = selend-1; i >= selstart; --i ) + addCommand ( Command( RemoveSelection, i, text.at(i) ) ); + } +#endif /* SECURE_NO_UNDO */ + text.remove( selstart, selend - selstart ); + if ( cursor > selstart ) + cursor -= TQMIN( cursor, selend ) - selstart; + deselect(); + textDirty = TRUE; + } +} + +#include "secqlineedit.moc" diff --git a/tqt/secqlineedit.h b/tqt/secqlineedit.h new file mode 100644 index 0000000..9b396ed --- /dev/null +++ b/tqt/secqlineedit.h @@ -0,0 +1,227 @@ +/* secntqlineedit.h - Secure version of TQLineEdit. + Copyright (C) 1992-2002 Trolltech AS. All rights reserved. + Copyright (C) 2003 g10 Code GmbH + + The license of the original ntqlineedit.h file from which this file + is derived can be found below. Modified by Marcus Brinkmann + . All modifications are licensed as follows, so + that the intersection of the two licenses is then the GNU General + Public License version 2. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 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 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 "secqstring.h" + +/* This disables some insecure code. */ +#define SECURE 1 + +/********************************************************************** +** $Id$ +** +** Definition of SecTQLineEdit widget class +** +** Created : 941011 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the widgets module of the TQt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.TQPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition +** licenses may use this file in accordance with the TQt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about TQt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for TQPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef SECTQLINEEDIT_H +#define SECTQLINEEDIT_H + +struct SecTQLineEditPrivate; + +class TQPopupMenu; + +#ifndef QT_H +#include "ntqframe.h" +#include "ntqstring.h" +#endif // QT_H + +class TQTextParagraph; +class TQTextCursor; + +class Q_EXPORT SecTQLineEdit : public TQFrame +{ + TQ_OBJECT + TQ_ENUMS( EchoMode ) + // TQ_PROPERTY( SecTQString text READ text WRITE setText ) + TQ_PROPERTY( int maxLength READ maxLength WRITE setMaxLength ) + TQ_PROPERTY( bool frame READ frame WRITE setFrame ) + TQ_PROPERTY( EchoMode echoMode READ echoMode WRITE setEchoMode ) + TQ_PROPERTY( TQString displayText READ displayText ) + TQ_PROPERTY( int cursorPosition READ cursorPosition WRITE setCursorPosition ) + TQ_PROPERTY( Alignment alignment READ alignment WRITE setAlignment ) + TQ_PROPERTY( bool edited READ edited WRITE setEdited DESIGNABLE false ) + TQ_PROPERTY( bool modified READ isModified ) + TQ_PROPERTY( bool hasSelectedText READ hasSelectedText ) + // TQ_PROPERTY( SecTQString markedText READ markedText DESIGNABLE false ) + // TQ_PROPERTY( SecTQString selectedText READ selectedText ) + TQ_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly ) + TQ_PROPERTY( bool undoAvailable READ isUndoAvailable ) + TQ_PROPERTY( bool redoAvailable READ isRedoAvailable ) + +public: + SecTQLineEdit( TQWidget* parent, const char* name=0 ); + SecTQLineEdit( const SecTQString &, TQWidget* parent, const char* name=0 ); + SecTQLineEdit( const SecTQString &, const TQString &, TQWidget* parent, const char* name=0 ); + ~SecTQLineEdit(); + + SecTQString text() const; + + TQString displayText() const; + + int maxLength() const; + + bool frame() const; + + enum EchoMode { Normal, NoEcho, Password }; + EchoMode echoMode() const; + + bool isReadOnly() const; + + TQSize sizeHint() const; + TQSize minimumSizeHint() const; + + int cursorPosition() const; + bool validateAndSet( const SecTQString &, int, int, int ); // obsolete + + int alignment() const; + +#ifndef QT_NO_COMPAT + void cursorLeft( bool mark, int steps = 1 ) { cursorForward( mark, -steps ); } + void cursorRight( bool mark, int steps = 1 ) { cursorForward( mark, steps ); } +#endif + void cursorForward( bool mark, int steps = 1 ); + void cursorBackward( bool mark, int steps = 1 ); + void cursorWordForward( bool mark ); + void cursorWordBackward( bool mark ); + void backspace(); + void del(); + void home( bool mark ); + void end( bool mark ); + + bool isModified() const; + void clearModified(); + + bool edited() const; // obsolete, use isModified() + void setEdited( bool ); // obsolete, use clearModified() + + bool hasSelectedText() const; + SecTQString selectedText() const; + int selectionStart() const; + + bool isUndoAvailable() const; + bool isRedoAvailable() const; + +#ifndef QT_NO_COMPAT + bool hasMarkedText() const { return hasSelectedText(); } + SecTQString markedText() const { return selectedText(); } +#endif + +public slots: + virtual void setText( const SecTQString &); + virtual void selectAll(); + virtual void deselect(); + virtual void insert( const SecTQString &); + virtual void clear(); + virtual void undo(); + virtual void redo(); + virtual void setMaxLength( int ); + virtual void setFrame( bool ); + virtual void setEchoMode( EchoMode ); + virtual void setReadOnly( bool ); + virtual void setFont( const TQFont & ); + virtual void setPalette( const TQPalette & ); + virtual void setSelection( int, int ); + virtual void setCursorPosition( int ); + virtual void setAlignment( int flag ); +#ifndef QT_NO_CLIPBOARD + virtual void cut(); + virtual void copy() const; + virtual void paste(); +#endif + +signals: + void textChanged( const SecTQString &); + void textModified( const SecTQString &); + void returnPressed(); + void lostFocus(); + void selectionChanged(); + +protected: + bool event( TQEvent * ); + void mousePressEvent( TQMouseEvent * ); + void mouseMoveEvent( TQMouseEvent * ); + void mouseReleaseEvent( TQMouseEvent * ); + void mouseDoubleClickEvent( TQMouseEvent * ); + void keyPressEvent( TQKeyEvent * ); + void imStartEvent( TQIMEvent * ); + void imComposeEvent( TQIMEvent * ); + void imEndEvent( TQIMEvent * ); + void focusInEvent( TQFocusEvent * ); + void focusOutEvent( TQFocusEvent * ); + void resizeEvent( TQResizeEvent * ); + void drawContents( TQPainter * ); + void windowActivationChange( bool ); +#ifndef QT_NO_COMPAT + void repaintArea( int, int ) { update(); } +#endif + +private slots: + void clipboardChanged(); + +public: + TQChar passwordChar() const; // obsolete internal + +private: + friend struct SecTQLineEditPrivate; + SecTQLineEditPrivate * d; + +private: // Disabled copy constructor and operator= +#if defined(TQ_DISABLE_COPY) + SecTQLineEdit( const SecTQLineEdit & ); + SecTQLineEdit &operator=( const SecTQLineEdit & ); +#endif +}; + +#endif // SECTQLINEEDIT_H diff --git a/tqt/secqstring.cpp b/tqt/secqstring.cpp new file mode 100644 index 0000000..4070169 --- /dev/null +++ b/tqt/secqstring.cpp @@ -0,0 +1,939 @@ +/* secqstring.cpp - Secure version of TQString. + Copyright (C) 1992-2002 Trolltech AS. All rights reserved. + Copyright (C) 2003 g10 Code GmbH + + The license of the original qstring.cpp file from which this file + is derived can be found below. Modified by Marcus Brinkmann + . All modifications are licensed as follows, so + that the intersection of the two licenses is then the GNU General + Public License version 2. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 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 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 */ + +/**************************************************************************** +** $Id$ +** +** Implementation of the SecTQString class and related Unicode functions +** +** Created : 920722 +** +** Copyright (C) 1992-2002 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the TQt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.TQPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition +** licenses may use this file in accordance with the TQt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about TQt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for TQPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +// Don't define it while compiling this module, or USERS of TQt will +// not be able to link. + +#include "secqstring.h" + +static uint computeNewMax( uint len ) +{ + uint newMax = 4; + while ( newMax < len ) + newMax *= 2; + // try to save some memory + if ( newMax >= 1024 * 1024 && len <= newMax - (newMax >> 2) ) + newMax -= newMax >> 2; + return newMax; +} + +// These macros are used for efficient allocation of TQChar strings. +// IMPORTANT! If you change these, make sure you also change the +// "delete unicode" statement in ~SecTQStringData() in SecTQString.h correspondingly! + +#define QT_ALLOC_SECTQCHAR_VEC(N) (TQChar*) ::secmem_malloc (sizeof(TQChar) * (N)) +#define QT_DELETE_SECTQCHAR_VEC(P) ::secmem_free (P) + + +/***************************************************************************** + SecTQString member functions + *****************************************************************************/ + +/*! + \class SecTQString SecTQString.h + \reentrant + + \brief The SecTQString class provides an abstraction of Unicode text + and the classic C '\0'-terminated char array. + + \ingroup tools + \ingroup shared + \ingroup text + \mainclass + + SecTQString uses \link shclass.html implicit sharing\endlink, which + makes it very efficient and easy to use. + + In all of the SecTQString methods that take \c {const char *} + parameters, the \c {const char *} is interpreted as a classic + C-style '\0'-terminated ASCII string. It is legal for the \c + {const char *} parameter to be 0. If the \c {const char *} is not + '\0'-terminated, the results are undefined. Functions that copy + classic C strings into a SecTQString will not copy the terminating + '\0' character. The TQChar array of the SecTQString (as returned by + unicode()) is generally not terminated by a '\0'. If you need to + pass a SecTQString to a function that requires a C '\0'-terminated + string use latin1(). + + \keyword SecTQString::null + A SecTQString that has not been assigned to anything is \e null, i.e. + both the length and data pointer is 0. A SecTQString that references + the empty string ("", a single '\0' char) is \e empty. Both null + and empty SecTQStrings are legal parameters to the methods. Assigning + \c{(const char *) 0} to SecTQString gives a null SecTQString. For + convenience, \c SecTQString::null is a null SecTQString. When sorting, + empty strings come first, followed by non-empty strings, followed + by null strings. We recommend using \c{if ( !str.isNull() )} to + check for a non-null string rather than \c{if ( !str )}; see \l + operator!() for an explanation. + + Note that if you find that you are mixing usage of \l TQCString, + SecTQString, and \l TQByteArray, this causes lots of unnecessary + copying and might indicate that the true nature of the data you + are dealing with is uncertain. If the data is '\0'-terminated 8-bit + data, use \l TQCString; if it is unterminated (i.e. contains '\0's) + 8-bit data, use \l TQByteArray; if it is text, use SecTQString. + + Lists of strings are handled by the SecTQStringList class. You can + split a string into a list of strings using SecTQStringList::split(), + and join a list of strings into a single string with an optional + separator using SecTQStringList::join(). You can obtain a list of + strings from a string list that contain a particular substring or + that match a particular \link ntqregexp.html regex\endlink using + SecTQStringList::grep(). + + Note for C programmers + + Due to C++'s type system and the fact that SecTQString is implicitly + shared, SecTQStrings may be treated like ints or other simple base + types. For example: + + \code + SecTQString boolToString( bool b ) + { + SecTQString result; + if ( b ) + result = "True"; + else + result = "False"; + return result; + } + \endcode + + The variable, result, is an auto variable allocated on the stack. + When return is called, because we're returning by value, The copy + constructor is called and a copy of the string is returned. (No + actual copying takes place thanks to the implicit sharing, see + below.) + + Throughout TQt's source code you will encounter SecTQString usages like + this: + \code + SecTQString func( const SecTQString& input ) + { + SecTQString output = input; + // process output + return output; + } + \endcode + + The 'copying' of input to output is almost as fast as copying a + pointer because behind the scenes copying is achieved by + incrementing a reference count. SecTQString (like all TQt's implicitly + shared classes) operates on a copy-on-write basis, only copying if + an instance is actually changed. + + If you wish to create a deep copy of a SecTQString without losing any + Unicode information then you should use TQDeepCopy. + + \sa TQChar TQCString TQByteArray SecTQConstString +*/ + +Q_EXPORT SecTQStringData *SecTQString::shared_null = 0; +QT_STATIC_CONST_IMPL SecTQString SecTQString::null; +QT_STATIC_CONST_IMPL TQChar TQChar::null; +QT_STATIC_CONST_IMPL TQChar TQChar::replacement((ushort)0xfffd); +QT_STATIC_CONST_IMPL TQChar TQChar::byteOrderMark((ushort)0xfeff); +QT_STATIC_CONST_IMPL TQChar TQChar::byteOrderSwapped((ushort)0xfffe); +QT_STATIC_CONST_IMPL TQChar TQChar::nbsp((ushort)0x00a0); + +SecTQStringData* SecTQString::makeSharedNull() +{ + SecTQString::shared_null = new SecTQStringData; +#if defined( Q_OS_MAC ) + SecTQString *that = const_cast(&SecTQString::null); + that->d = SecTQString::shared_null; +#endif + return SecTQString::shared_null; +} + +/*! + \fn SecTQString::SecTQString() + + Constructs a null string, i.e. both the length and data pointer + are 0. + + \sa isNull() +*/ + +/*! + Constructs a string of length one, containing the character \a ch. +*/ +SecTQString::SecTQString( TQChar ch ) +{ + d = new SecTQStringData( QT_ALLOC_SECTQCHAR_VEC( 1 ), 1, 1 ); + d->unicode[0] = ch; +} + +/*! + Constructs an implicitly shared copy of \a s. This is very fast + since it only involves incrementing a reference count. +*/ +SecTQString::SecTQString( const SecTQString &s ) : + d(s.d) +{ + d->ref(); +} + + +SecTQString::SecTQString( int size, bool /*dummy*/ ) +{ + if ( size ) { + int l = size; + TQChar* uc = QT_ALLOC_SECTQCHAR_VEC( l ); + d = new SecTQStringData( uc, 0, l ); + } else { + d = shared_null ? shared_null : (shared_null=new SecTQStringData); + d->ref(); + } +} + + +/* Deep copy of STR. */ +SecTQString::SecTQString( const TQString &str ) +{ + const TQChar *unicode = str.unicode (); + uint length = str.length (); + + if ( !unicode && !length ) { + d = shared_null ? shared_null : makeSharedNull(); + d->ref(); + } else { + TQChar* uc = QT_ALLOC_SECTQCHAR_VEC( length ); + if ( unicode ) + memcpy(uc, unicode, length*sizeof(TQChar)); + d = new SecTQStringData(uc,unicode ? length : 0,length); + } +} + + +/*! + Constructs a string that is a deep copy of the first \a length + characters in the TQChar array. + + If \a unicode and \a length are 0, then a null string is created. + + If only \a unicode is 0, the string is empty but has \a length + characters of space preallocated: SecTQString expands automatically + anyway, but this may speed up some cases a little. We recommend + using the plain constructor and setLength() for this purpose since + it will result in more readable code. + + \sa isNull() setLength() +*/ + +SecTQString::SecTQString( const TQChar* unicode, uint length ) +{ + if ( !unicode && !length ) { + d = shared_null ? shared_null : makeSharedNull(); + d->ref(); + } else { + TQChar* uc = QT_ALLOC_SECTQCHAR_VEC( length ); + if ( unicode ) + memcpy(uc, unicode, length*sizeof(TQChar)); + d = new SecTQStringData(uc,unicode ? length : 0,length); + } +} + +/*! + \fn SecTQString::~SecTQString() + + Destroys the string and frees the string's data if this is the + last reference to the string. +*/ + + +/*! + Deallocates any space reserved solely by this SecTQString. + + If the string does not share its data with another SecTQString + instance, nothing happens; otherwise the function creates a new, + unique copy of this string. This function is called whenever the + string is modified. +*/ + +void SecTQString::real_detach() +{ + setLength( length() ); +} + +void SecTQString::deref() +{ + if ( d && d->deref() ) { + if ( d != shared_null ) + delete d; + d = 0; + } +} + +void SecTQStringData::deleteSelf() +{ + delete this; +} + +/*! + \fn SecTQString& SecTQString::operator=( TQChar c ) + + Sets the string to contain just the single character \a c. +*/ + + +/*! + \overload + + Assigns a shallow copy of \a s to this string and returns a + reference to this string. This is very fast because the string + isn't actually copied. +*/ +SecTQString &SecTQString::operator=( const SecTQString &s ) +{ + s.d->ref(); + deref(); + d = s.d; + return *this; +} + + +/*! + \fn bool SecTQString::isNull() const + + Returns TRUE if the string is null; otherwise returns FALSE. A + null string is always empty. + + \code + SecTQString a; // a.unicode() == 0, a.length() == 0 + a.isNull(); // TRUE, because a.unicode() == 0 + a.isEmpty(); // TRUE, because a.length() == 0 + \endcode + + \sa isEmpty(), length() +*/ + +/*! + \fn bool SecTQString::isEmpty() const + + Returns TRUE if the string is empty, i.e. if length() == 0; + otherwise returns FALSE. Null strings are also empty. + + \code + SecTQString a( "" ); + a.isEmpty(); // TRUE + a.isNull(); // FALSE + + SecTQString b; + b.isEmpty(); // TRUE + b.isNull(); // TRUE + \endcode + + \sa isNull(), length() +*/ + +/*! + \fn uint SecTQString::length() const + + Returns the length of the string. + + Null strings and empty strings have zero length. + + \sa isNull(), isEmpty() +*/ + +/*! + If \a newLen is less than the length of the string, then the + string is truncated at position \a newLen. Otherwise nothing + happens. + + \code + SecTQString s = "truncate me"; + s.truncate( 5 ); // s == "trunc" + \endcode + + \sa setLength() +*/ + +void SecTQString::truncate( uint newLen ) +{ + if ( newLen < d->len ) + setLength( newLen ); +} + +/*! + Ensures that at least \a newLen characters are allocated to the + string, and sets the length of the string to \a newLen. Any new + space allocated contains arbitrary data. + + \sa reserve(), truncate() +*/ +void SecTQString::setLength( uint newLen ) +{ + if ( d->count != 1 || newLen > d->maxl || + ( newLen * 4 < d->maxl && d->maxl > 4 ) ) { + // detach, grow or shrink + uint newMax = computeNewMax( newLen ); + TQChar* nd = QT_ALLOC_SECTQCHAR_VEC( newMax ); + if ( nd ) { + uint len = TQMIN( d->len, newLen ); + memcpy( nd, d->unicode, sizeof(TQChar) * len ); + deref(); + d = new SecTQStringData( nd, newLen, newMax ); + } + } else { + d->len = newLen; + } +} + + +/*! + \internal + + Like setLength, but doesn't shrink the allocated memory. +*/ +void SecTQString::grow( uint newLen ) +{ + if ( d->count != 1 || newLen > d->maxl ) { + setLength( newLen ); + } else { + d->len = newLen; + } +} + + +/*! + Returns a substring that contains the \a len leftmost characters + of the string. + + The whole string is returned if \a len exceeds the length of the + string. + + \code + SecTQString s = "Pineapple"; + SecTQString t = s.left( 4 ); // t == "Pine" + \endcode + + \sa right(), mid(), isEmpty() +*/ + +SecTQString SecTQString::left( uint len ) const +{ + if ( isEmpty() ) { + return SecTQString(); + } else if ( len == 0 ) { // ## just for 1.x compat: + return SecTQString (""); + } else if ( len >= length() ) { + return *this; + } else { + SecTQString s( len, TRUE ); + memcpy( s.d->unicode, d->unicode, len * sizeof(TQChar) ); + s.d->len = len; + return s; + } +} + +/*! + Returns a string that contains the \a len rightmost characters of + the string. + + If \a len is greater than the length of the string then the whole + string is returned. + + \code + SecTQString string( "Pineapple" ); + SecTQString t = string.right( 5 ); // t == "apple" + \endcode + + \sa left(), mid(), isEmpty() +*/ + +SecTQString SecTQString::right( uint len ) const +{ + if ( isEmpty() ) { + return SecTQString(); + } else if ( len == 0 ) { // ## just for 1.x compat: + return SecTQString (""); + } else { + uint l = length(); + if ( len >= l ) + return *this; + SecTQString s( len, TRUE ); + memcpy( s.d->unicode, d->unicode+(l-len), len*sizeof(TQChar) ); + s.d->len = len; + return s; + } +} + +/*! + Returns a string that contains the \a len characters of this + string, starting at position \a index. + + Returns a null string if the string is empty or \a index is out of + range. Returns the whole string from \a index if \a index + \a len + exceeds the length of the string. + + \code + SecTQString s( "Five pineapples" ); + SecTQString t = s.mid( 5, 4 ); // t == "pine" + \endcode + + \sa left(), right() +*/ + +SecTQString SecTQString::mid( uint index, uint len ) const +{ + uint slen = length(); + if ( isEmpty() || index >= slen ) { + return SecTQString(); + } else if ( len == 0 ) { // ## just for 1.x compat: + return SecTQString (""); + } else { + if ( len > slen-index ) + len = slen - index; + if ( index == 0 && len == slen ) + return *this; + register const TQChar *p = unicode()+index; + SecTQString s( len, TRUE ); + memcpy( s.d->unicode, p, len * sizeof(TQChar) ); + s.d->len = len; + return s; + } +} + +/*! + Inserts \a s into the string at position \a index. + + If \a index is beyond the end of the string, the string is + extended with spaces to length \a index and \a s is then appended + and returns a reference to the string. + + \code + SecTQString string( "I like fish" ); + str = string.insert( 2, "don't " ); + // str == "I don't like fish" + \endcode + + \sa remove(), replace() +*/ + +SecTQString &SecTQString::insert( uint index, const SecTQString &s ) +{ + // the sub function takes care of &s == this case. + return insert( index, s.unicode(), s.length() ); +} + +/*! + \overload + + Inserts the first \a len characters in \a s into the string at + position \a index and returns a reference to the string. +*/ + +SecTQString &SecTQString::insert( uint index, const TQChar* s, uint len ) +{ + if ( len == 0 ) + return *this; + uint olen = length(); + int nlen = olen + len; + + if ( s >= d->unicode && (uint)(s - d->unicode) < d->maxl ) { + // Part of me - take a copy. + TQChar *tmp = QT_ALLOC_SECTQCHAR_VEC( len ); + memcpy(tmp,s,len*sizeof(TQChar)); + insert(index,tmp,len); + QT_DELETE_SECTQCHAR_VEC( tmp ); + return *this; + } + + if ( index >= olen ) { // insert after end of string + grow( len + index ); + int n = index - olen; + TQChar* uc = d->unicode+olen; + while (n--) + *uc++ = ' '; + memcpy( d->unicode+index, s, sizeof(TQChar)*len ); + } else { // normal insert + grow( nlen ); + memmove( d->unicode + index + len, unicode() + index, + sizeof(TQChar) * (olen - index) ); + memcpy( d->unicode + index, s, sizeof(TQChar) * len ); + } + return *this; +} + +/*! + Removes \a len characters from the string starting at position \a + index, and returns a reference to the string. + + If \a index is beyond the length of the string, nothing happens. + If \a index is within the string, but \a index + \a len is beyond + the end of the string, the string is truncated at position \a + index. + + \code + SecTQString string( "Montreal" ); + string.remove( 1, 4 ); // string == "Meal" + \endcode + + \sa insert(), replace() +*/ + +SecTQString &SecTQString::remove( uint index, uint len ) +{ + uint olen = length(); + if ( index >= olen ) { + // range problems + } else if ( index + len >= olen ) { // index ok + setLength( index ); + } else if ( len != 0 ) { + real_detach(); + memmove( d->unicode+index, d->unicode+index+len, + sizeof(TQChar)*(olen-index-len) ); + setLength( olen-len ); + } + return *this; +} + + +/*! + \overload + + Replaces \a len characters with \a slen characters of TQChar data + from \a s, starting at position \a index, and returns a reference + to the string. + + \sa insert(), remove() +*/ + +SecTQString &SecTQString::replace( uint index, uint len, const TQChar* s, uint slen ) +{ + real_detach(); + if ( len == slen && index + len <= length() ) { + // Optimized common case: replace without size change + memcpy( d->unicode+index, s, len * sizeof(TQChar) ); + } else if ( s >= d->unicode && (uint)(s - d->unicode) < d->maxl ) { + // Part of me - take a copy. + TQChar *tmp = QT_ALLOC_SECTQCHAR_VEC( slen ); + memcpy( tmp, s, slen * sizeof(TQChar) ); + replace( index, len, tmp, slen ); + QT_DELETE_SECTQCHAR_VEC( tmp ); + } else { + remove( index, len ); + insert( index, s, slen ); + } + return *this; +} + + +/*! + Replaces \a len characters from the string with \a s, starting at + position \a index, and returns a reference to the string. + + If \a index is beyond the length of the string, nothing is deleted + and \a s is appended at the end of the string. If \a index is + valid, but \a index + \a len is beyond the end of the string, + the string is truncated at position \a index, then \a s is + appended at the end. + + \code + TQString string( "Say yes!" ); + string = string.replace( 4, 3, "NO" ); + // string == "Say NO!" + \endcode + + \sa insert(), remove() +*/ + +SecTQString &SecTQString::replace( uint index, uint len, const SecTQString &s ) +{ + return replace( index, len, s.unicode(), s.length() ); +} + + +/*! + Appends \a str to the string and returns a reference to the string. +*/ +SecTQString& SecTQString::operator+=( const SecTQString &str ) +{ + uint len1 = length(); + uint len2 = str.length(); + if ( len2 ) { + if ( isEmpty() ) { + operator=( str ); + } else { + grow( len1+len2 ); + memcpy( d->unicode+len1, str.unicode(), sizeof(TQChar)*len2 ); + } + } else if ( isNull() && !str.isNull() ) { // ## just for 1.x compat: + *this = SecTQString (""); + } + return *this; +} + + +/*! + Returns the string encoded in UTF-8 format. + + See TQTextCodec for more diverse coding/decoding of Unicode strings. + + \sa fromUtf8(), ascii(), latin1(), local8Bit() +*/ +uchar *SecTQString::utf8() const +{ + int l = length(); + int rlen = l*3+1; + uchar* rstr = (uchar*) ::secmem_malloc (rlen); + uchar* cursor = rstr; + const TQChar *ch = d->unicode; + for (int i=0; i < l; i++) { + uint u = ch->unicode(); + if ( u < 0x80 ) { + *cursor++ = (uchar)u; + } else { + if ( u < 0x0800 ) { + *cursor++ = 0xc0 | ((uchar) (u >> 6)); + } else { + if (u >= 0xd800 && u < 0xdc00 && i < l-1) { + unsigned short low = ch[1].unicode(); + if (low >= 0xdc00 && low < 0xe000) { + ++ch; + ++i; + u = (u - 0xd800)*0x400 + (low - 0xdc00) + 0x10000; + } + } + if (u > 0xffff) { + // if people are working in utf8, but strings are encoded in eg. latin1, the resulting + // name might be invalid utf8. This and the corresponding code in fromUtf8 takes care + // we can handle this without loosing information. This can happen with latin filenames + // and a utf8 locale under Unix. + if (u > 0x10fe00 && u < 0x10ff00) { + *cursor++ = (u - 0x10fe00); + ++ch; + continue; + } else { + *cursor++ = 0xf0 | ((uchar) (u >> 18)); + *cursor++ = 0x80 | ( ((uchar) (u >> 12)) & 0x3f); + } + } else { + *cursor++ = 0xe0 | ((uchar) (u >> 12)); + } + *cursor++ = 0x80 | ( ((uchar) (u >> 6)) & 0x3f); + } + *cursor++ = 0x80 | ((uchar) (u&0x3f)); + } + ++ch; + } + /* FIXME: secmem_realloc doesn't release extra memory. */ + *cursor = '\0'; + return rstr; +} + + +/*! + \fn TQChar SecTQString::at( uint ) const + + Returns the character at index \a i, or 0 if \a i is beyond the + length of the string. + + \code + const SecTQString string( "abcdefgh" ); + TQChar ch = string.at( 4 ); + // ch == 'e' + \endcode + + If the SecTQString is not const (i.e. const SecTQString) or const& (i.e. + const SecTQString &), then the non-const overload of at() will be used + instead. +*/ + +/*! + \fn TQChar SecTQString::constref(uint i) const + + Returns the TQChar at index \a i by value. + + Equivalent to at(\a i). + + \sa ref() +*/ + +/*! + \fn TQChar& SecTQString::ref(uint i) + + Returns the TQChar at index \a i by reference, expanding the string + with TQChar::null if necessary. The resulting reference can be + assigned to, or otherwise used immediately, but becomes invalid + once furher modifications are made to the string. + + \code + SecTQString string("ABCDEF"); + TQChar ch = string.ref( 3 ); // ch == 'D' + \endcode + + \sa constref() +*/ + +/*! + \fn TQChar SecTQString::operator[]( int ) const + + Returns the character at index \a i, or TQChar::null if \a i is + beyond the length of the string. + + If the SecTQString is not const (i.e., const SecTQString) or const\& + (i.e., const SecTQString\&), then the non-const overload of operator[] + will be used instead. +*/ + +/*! + \fn TQCharRef SecTQString::operator[]( int ) + + \overload + + The function returns a reference to the character at index \a i. + The resulting reference can then be assigned to, or used + immediately, but it will become invalid once further modifications + are made to the original string. + + If \a i is beyond the length of the string then the string is + expanded with TQChar::nulls, so that the TQCharRef references a + valid (null) character in the string. + + The TQCharRef internal class can be used much like a constant + TQChar, but if you assign to it, you change the original string + (which will detach itself because of SecTQString's copy-on-write + semantics). You will get compilation errors if you try to use the + result as anything but a TQChar. +*/ + +/*! + \fn TQCharRef SecTQString::at( uint i ) + + \overload + + The function returns a reference to the character at index \a i. + The resulting reference can then be assigned to, or used + immediately, but it will become invalid once further modifications + are made to the original string. + + If \a i is beyond the length of the string then the string is + expanded with TQChar::null. +*/ + +/* + Internal chunk of code to handle the + uncommon cases of at() above. +*/ +void SecTQString::subat( uint i ) +{ + uint olen = d->len; + if ( i >= olen ) { + setLength( i+1 ); // i is index; i+1 is needed length + for ( uint j=olen; j<=i; j++ ) + d->unicode[j] = TQChar::null; + } else { + // Just be sure to detach + real_detach(); + } +} + + +/*! \internal + */ +bool SecTQString::isRightToLeft() const +{ + int len = length(); + TQChar *p = d->unicode; + while ( len-- ) { + switch( (*p).direction () ) + { + case TQChar::DirL: + case TQChar::DirLRO: + case TQChar::DirLRE: + return FALSE; + case TQChar::DirR: + case TQChar::DirAL: + case TQChar::DirRLO: + case TQChar::DirRLE: + return TRUE; + default: + break; + } + ++p; + } + return FALSE; +} + + +/*! + \fn const SecTQString operator+( const SecTQString &s1, const SecTQString &s2 ) + + \relates SecTQString + + Returns a string which is the result of concatenating the string + \a s1 and the string \a s2. + + Equivalent to \a {s1}.append(\a s2). +*/ + + +/*! \fn void SecTQString::detach() + If the string does not share its data with another SecTQString instance, + nothing happens; otherwise the function creates a new, unique copy of + this string. This function is called whenever the string is modified. The + implicit sharing mechanism is implemented this way. +*/ diff --git a/tqt/secqstring.h b/tqt/secqstring.h new file mode 100644 index 0000000..fa309df --- /dev/null +++ b/tqt/secqstring.h @@ -0,0 +1,307 @@ +/* secntqstring.h - Secure version of TQString. + Copyright (C) 1992-2002 Trolltech AS. All rights reserved. + Copyright (C) 2003 g10 Code GmbH + + The license of the original ntqstring.h file from which this file is + derived can be found below. Modified by Marcus Brinkmann + . All modifications are licensed as follows, so + that the intersection of the two licenses is then the GNU General + Public License version 2. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 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 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 */ + +/**************************************************************************** +** $Id$ +** +** Definition of the SecTQString class, and related Unicode functions. +** +** Created : 920609 +** +** Copyright (C) 1992-2002 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the TQt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.TQPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid TQt Enterprise Edition or TQt Professional Edition +** licenses may use this file in accordance with the TQt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about TQt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for TQPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef SECTQSTRING_H +#define SECTQSTRING_H + +extern "C" +{ +#include "memory.h" +} + +/* We need the original qchar and qstring for transparent conversion + from TQChar to TQChar and TQString to SecTQString (but not the other + way round). */ +#include + +#ifndef QT_H +#include "ntqcstring.h" +#endif // QT_H + + +/***************************************************************************** + SecTQString class + *****************************************************************************/ + +class SecTQString; +class SecTQCharRef; +template class TQDeepCopy; +#include +// internal +struct Q_EXPORT SecTQStringData : public TQShared { + SecTQStringData() : + TQShared(), unicode(0), len(0), maxl(0) { ref(); } + SecTQStringData(TQChar *u, uint l, uint m) : + TQShared(), unicode(u), len(l), maxl(m) { } + ~SecTQStringData() { if ( unicode ) ::secmem_free ((char*) unicode); } + + void deleteSelf(); + TQChar *unicode; +#ifdef Q_OS_MAC9 + uint len; +#else + uint len : 30; +#endif +#ifdef Q_OS_MAC9 + uint maxl; +#else + uint maxl : 30; +#endif +}; + + +class Q_EXPORT SecTQString +{ +public: + SecTQString(); // make null string + SecTQString( TQChar ); // one-char string + SecTQString( const SecTQString & ); // impl-shared copy + /* We need a way to convert a TQString to a SecTQString ("importing" + it). Having no conversion for the other way prevents + accidential bugs where the secure string is copied to insecure + memory. */ + SecTQString( const TQString & ); // deep copy + SecTQString( const TQChar* unicode, uint length ); // deep copy + ~SecTQString(); + + SecTQString &operator=( const SecTQString & ); // impl-shared copy + + QT_STATIC_CONST SecTQString null; + + bool isNull() const; + bool isEmpty() const; + uint length() const; + void truncate( uint pos ); + + SecTQString left( uint len ) const; + SecTQString right( uint len ) const; + SecTQString mid( uint index, uint len=0xffffffff) const; + + + SecTQString &insert( uint index, const SecTQString & ); + SecTQString &insert( uint index, const TQChar*, uint len ); + SecTQString &remove( uint index, uint len ); + SecTQString &replace( uint index, uint len, const SecTQString & ); + SecTQString &replace( uint index, uint len, const TQChar*, uint clen ); + + SecTQString &operator+=( const SecTQString &str ); + + TQChar at( uint i ) const + { return i < d->len ? d->unicode[i] : TQChar::null; } + TQChar operator[]( int i ) const { return at((uint)i); } + SecTQCharRef at( uint i ); + SecTQCharRef operator[]( int i ); + + TQChar constref(uint i) const + { return at(i); } + TQChar& ref(uint i) + { // Optimized for easy-inlining by simple compilers. + if ( d->count != 1 || i >= d->len ) + subat( i ); + return d->unicode[i]; + } + + const TQChar* unicode() const { return d->unicode; } + + uchar* utf8() const; + + void setLength( uint newLength ); + + bool isRightToLeft() const; + + +private: + SecTQString( int size, bool /* dummy */ ); // allocate size incl. \0 + + void deref(); + void real_detach(); + void subat( uint ); + + void grow( uint newLength ); + + SecTQStringData *d; + static SecTQStringData* shared_null; + static SecTQStringData* makeSharedNull(); + + friend class SecTQConstString; + friend class TQTextStream; + SecTQString( SecTQStringData* dd, bool /* dummy */ ) : d(dd) { } + + // needed for TQDeepCopy + void detach(); + friend class TQDeepCopy; +}; + +class Q_EXPORT SecTQCharRef { + friend class SecTQString; + SecTQString& s; + uint p; + SecTQCharRef(SecTQString* str, uint pos) : s(*str), p(pos) { } + +public: + // most TQChar operations repeated here + + // all this is not documented: We just say "like TQChar" and let it be. +#ifndef Q_QDOC + ushort unicode() const { return s.constref(p).unicode(); } + + // An operator= for each TQChar cast constructors + SecTQCharRef operator=(char c ) { s.ref(p)=c; return *this; } + SecTQCharRef operator=(uchar c ) { s.ref(p)=c; return *this; } + SecTQCharRef operator=(TQChar c ) { s.ref(p)=c; return *this; } + SecTQCharRef operator=(const SecTQCharRef& c ) { s.ref(p)=c.unicode(); return *this; } + SecTQCharRef operator=(ushort rc ) { s.ref(p)=rc; return *this; } + SecTQCharRef operator=(short rc ) { s.ref(p)=rc; return *this; } + SecTQCharRef operator=(uint rc ) { s.ref(p)=rc; return *this; } + SecTQCharRef operator=(int rc ) { s.ref(p)=rc; return *this; } + + operator TQChar () const { return s.constref(p); } + + // each function... + bool isNull() const { return unicode()==0; } + bool isPrint() const { return s.constref(p).isPrint(); } + bool isPunct() const { return s.constref(p).isPunct(); } + bool isSpace() const { return s.constref(p).isSpace(); } + bool isMark() const { return s.constref(p).isMark(); } + bool isLetter() const { return s.constref(p).isLetter(); } + bool isNumber() const { return s.constref(p).isNumber(); } + bool isLetterOrNumber() { return s.constref(p).isLetterOrNumber(); } + bool isDigit() const { return s.constref(p).isDigit(); } + + int digitValue() const { return s.constref(p).digitValue(); } + TQChar lower() const { return s.constref(p).lower(); } + TQChar upper() const { return s.constref(p).upper(); } + + TQChar::Category category() const { return s.constref(p).category(); } + TQChar::Direction direction() const { return s.constref(p).direction(); } + TQChar::Joining joining() const { return s.constref(p).joining(); } + bool mirrored() const { return s.constref(p).mirrored(); } + TQChar mirroredChar() const { return s.constref(p).mirroredChar(); } + // const SecTQString &decomposition() const { return s.constref(p).decomposition(); } + TQChar::Decomposition decompositionTag() const { return s.constref(p).decompositionTag(); } + unsigned char combiningClass() const { return s.constref(p).combiningClass(); } + + // Not the non-const ones of these. + uchar cell() const { return s.constref(p).cell(); } + uchar row() const { return s.constref(p).row(); } +#endif +}; + +inline SecTQCharRef SecTQString::at( uint i ) { return SecTQCharRef(this,i); } +inline SecTQCharRef SecTQString::operator[]( int i ) { return at((uint)i); } + +class Q_EXPORT SecTQConstString : private SecTQString { +public: + SecTQConstString( const TQChar* unicode, uint length ); + ~SecTQConstString(); + const SecTQString& string() const { return *this; } +}; + + +/***************************************************************************** + SecTQString inline functions + *****************************************************************************/ + +// These two move code into makeSharedNull() and deletesData() +// to improve cache-coherence (and reduce code bloat), while +// keeping the common cases fast. +// +// No safe way to pre-init shared_null on ALL compilers/linkers. +inline SecTQString::SecTQString() : + d(shared_null ? shared_null : makeSharedNull()) +{ + d->ref(); +} +// +inline SecTQString::~SecTQString() +{ + if ( d->deref() ) { + if ( d != shared_null ) + d->deleteSelf(); + } +} + +// needed for TQDeepCopy +inline void SecTQString::detach() +{ real_detach(); } + +inline bool SecTQString::isNull() const +{ return unicode() == 0; } + +inline uint SecTQString::length() const +{ return d->len; } + +inline bool SecTQString::isEmpty() const +{ return length() == 0; } + +/***************************************************************************** + SecTQString non-member operators + *****************************************************************************/ + +Q_EXPORT inline const SecTQString operator+( const SecTQString &s1, const SecTQString &s2 ) +{ + SecTQString tmp( s1 ); + tmp += s2; + return tmp; +} + +#endif // SECTQSTRING_H