tudu-0.10.2/0000755000175000017500000000000013121020352011256 5ustar userusertudu-0.10.2/ChangeLog0000644000175000017500000001060613121017272013042 0ustar useruser0.10.1 * Fixed tmpnam warning * Fixed not null terminated strings 0.10 * Added move task witch shift+up/down * Added mark task as done/undone with space * Fixed segfault on loading schedule 0.9.1 * Added CPPFLAGS to the makefiles * Fixed a segfault adding sched * Fixed the cursor drawing on the editor 0.9 * Added support for double with characters (like some chinese characters) * Added the default options on the man page * Fix a bug with some characters echoing on the editor 0.8.2 * Added configuration variable 'tudu_file' to set the path to the xml file * Improved the category editor * Don't check configuration files when invoked with '-h' and '-v' * Fixed segfault on scroll help page when the resolution is big 0.8.1 * Added arrow keys on date editor * Added support for non-latin keybinding pairs * Fixed wrong plotting while change tudu task position * Fixed category problems (autofill, showonly, ...) * Fixed Makefile problems reported on debian bug #611077 * Removed freeze on moving task 0.8 * Added ./configure script compatible with autotools * Added multiple category support * Added support for non-fix length categories * Added warning color to old scheduled tasks in sched * Added AvPag and RvPag to normal interface * Fixed display when the length of the title equal to the screen * Fixed problems with updating sched when the title changes 0.7 * Added support to multi linear task titles * New pipe windows as separators * Configurable date format as US or european * Configurable tasks with child displayed bold * Warn when disk is full * Fixed install path problems if the DESTDIR didn't end with '/' * Fixed year xml storage with different locales (debian bug #568064) * Fixed problems with external editors and UTF-8 * Fixed collision with some polish characters and control keys * Fixed dead loop when .tudu.xml is empty 0.6.1 * Added confirm question on Q * Configurable beggining to end move * Fixed remaping keys on config file * Show remaped keys on help bar (Patch from Enrique Matias) * Fixed leap year calculus (Patch from Enrique Matias) * Make inline help and man more redeable (Patch from Enrique Matias) * Deactivate Ctrl-c (Patch from Thorbjörn Jemander) 0.6 * Added suppor for international characters * Added help command to display man page * Added hide_percent option in the config file * Added patch from Magnus Müller: scroll to beginning end if end beginning reached * Fixed problems with O and P * Fixed problems at repaint after resize 0.5.1 * Added a simple theme to show when theme don't fit * Added support for up/re page keys on text editor * Fixed tab problems on editors * Fixed problems with text cursor when resize window * Fixed problems with non writable files * Fixed default permisions on lock files * Fixed segfaults when wrong params in cli 0.5 * Added search on titles * Added command interface * Added commands for hide categories * Added autocompletion on category editor * Added home and end keys on the editor * Added lock files for avoid concurrent tudus * Added documentation about all the features in the man page * Editing the title if is empty left arrow destroy the task * Fixed reorder tasks * Fixed english messages (thanks to Michael Leslie) 0.4.1 * Added reorder tasks on the scheluder * Fixed paste as child when task is collapsed * Fixed refresh when sched is deleted 0.4 * Added scheluder for tasks * Added hide done tasks * Added simple visual tree * Added paste as child * Sort by done uses 100% as done * Fixed help dirty close * Added sort after edit priority, category, ... 0.3.2 * Fixed a segfault in i386 editing priorities * Added support for delete priority 0.3.1 * Changed tudurc from /usr/local/share/tudu to /usr/local/etc 0.3 * Added @include to config files * Added theme support in config files * Addeѕ support for resizing term * Added sort by percent done * Added scroll in help screen * Fixed sort errors * Fixed problems with temporal files * Fixed problems with empty tudus 0.2.1 * Fixed bug: saving files in amd64 * Fixed bug: inheritance deadlines * Fixed bug: normal text editor * Fixed bug: category editor 0.2 * Added deadline date. * Added categories. * Added priorities. * Added support for sort the ToDos from different sort methods. * Allowed to edit the text of the ToDos with an external editor. * Fixed some segfaults and bugs. 0.1 * First version. tudu-0.10.2/configure.acr0000644000175000017500000000351013121017273013735 0ustar useruserREQUIRE_ACR_VERSION 0.8.2 PKGNAME tudu VERSION 0.10.2 CONTACT Ruben Pollan ; meskio@sindominio.net YEAR = 2017 ; LANG_CXX! CXXFLAGS += -Wall -O2 ; CPPFLAGS += "" ; SRCS += tudu.cc data.cc editor.cc interface.cc window.cc text.cc parser.cc config.cc date.cc screen.cc sched.cc cmd.cc ; // Detecting curses CHKINC xcurses.h CHKINC ncursesw/curses.h CHKINC ncurses/curses.h CHKINC ncurses.h CHKINC curses.h IF HAVE_XCURSES_H { CURSES_INCLUDE = xcurses.h ; } IF HAVE_NCURSESW_CURSES_H { CURSES_INCLUDE ?= ncursesw/curses.h ; } IF HAVE_NCURSES_CURSES_H { CURSES_INCLUDE ?= ncurses/curses.h ; } IF HAVE_NCURSES_H { CURSES_INCLUDE ?= ncurses.h ; } IF HAVE_CURSES_H { CURSES_INCLUDE ?= curses.h ; } IFNULL CURSES_INCLUDE { DIENOW There is no curses installed! ; } CHKLIB ncursesw CHKLIB ncurses CHKLIB curses IF HAVE_LIB_NCURSESW { LD_CURSES = -lncursesw ; } IF HAVE_LIB_NCURSES { LD_CURSES ?= -lncurses ; } IF HAVE_LIB_CURSES { LD_CURSES ?= -lcurses ; } IFNULL LD_CURSES { DIENOW There is no curses installed! ; } LDFLAGS += $LD_CURSES ; CHECK WIDEC_CURSES < test.c \ echo "#include<$CURSES_INCLUDE>" >> test.c \ echo "int main(){ addwstr(L\"\"); }" >> test.c \ eval \$${COMPILER} ${CXXFLAGS} test.c ${LDFLAGS} >/dev/null 2>&1 \ WIDEC_CURSES=$? \ rm test.c < # @url: http://www.nopcode.org # @repo: git clone https://github.com/radare/acr do_remove() { if [ "${ACR_RMFILES}" ]; then printf "cleaning temporally files... " rm -f ${ACR_RMFILES} echo "done" fi } control_c() { printf "\n\n^C control-c : script execution interrupted.\n" do_remove exit 1 } trap control_c 2 printf "checking for cpp... " if [ "${CROSSBUILD}" = 1 ]; then (exec ${HOST}-${CPP} --help >/dev/null 2>&1) [ $? = 0 ] && CPP="${HOST}-${CPP}" fi (echo "int main(int ac, char **av){return 0;}" | ${CPP} >/dev/null 2>&1) if [ $? = 0 ]; then echo ${CPP}; else echo "ERROR: ${CPP} cannot parse sources"; fi split_host() { S="$" while : ; do ENVWORDS="${ENVWORDS} $1_CPU $1_OS" STR=`eval "echo ${S}$1"` SPLIT_CPU="`echo "$STR" | cut -d - -f 1`" SPLIT_OS="`echo "$STR" | awk -F - '{ if ($2=="unknown"){ if (NF<3) { print $2; } else { print $3; } } else { if ($2=="linux") { print $2; } else if (NF<3) { print $2; } else { print $3; } } }'`" eval "$1_CPU=\"$SPLIT_CPU\"" eval "$1_OS=\"$SPLIT_OS\"" shift [ -z "$1" ] && break done } VPATH=`dirname ${0}` if [ "${VPATH}" = "." ]; then WODIS=current else if [ "${VPATH}" = "${PWD}" ]; then VPATH=. WODIS=current else WODIS=crosspath CURDIR=$PWD cd $VPATH VPATH="${PWD}/" cd $CURDIR fi fi guess_os() { if [ -e "${VPATH}/config.guess" ]; then sh ${VPATH}/config.guess return fi CPU="`uname -m|sed -e 's, ,,g'|cut -d - -f 1`" OS="`uname -s|tr A-Z a-z`" GNU="`uname --help 2>&1 | grep gnu`" [ "${GNU}" ] && OS="${OS}-gnu" [ "${CPU}" = ppc ] && CPU="powerpc" echo "${CPU}-unknown-${OS}" } SEARCHPATH="/usr /usr/local /usr/pkg /sw" : ${PREFIX:=/usr/local} CROSSBUILD=0 BUILD=`guess_os` HOST="${BUILD}" TARGET="${HOST}" SYSCONFDIR="" create_environ() { : ${EPREFIX:="${PREFIX}"} : ${SPREFIX:="${PREFIX}"} : ${BINDIR:="${SPREFIX}/bin"} : ${SBINDIR:="${PREFIX}/sbin"} : ${SYSCONFDIR:="${SPREFIX}/etc"} : ${LIBDIR:="${SPREFIX}/lib"} : ${LIBEXECDIR:="${SPREFIX}/libexec"} : ${INCLUDEDIR:="${SPREFIX}/include"} : ${DATADIR:="${SPREFIX}/share"} : ${INFODIR:="${DATADIR}/info"} : ${MANDIR:="${DATADIR}/man"} : ${DOCDIR:="${DATADIR}/doc/tudu"} : ${LOCALSTATEDIR:="${SPREFIX}/var"} for A in `echo ${PATH} | sed -e 's,:, ,g'` ; do [ -e "$A"/ginstall ] && : ${INSTALL:="$A"/ginstall} && break [ -e "$A"/install ] && : ${INSTALL:="$A"/install} && break done : ${INSTALL_DIR:=${INSTALL} -d} : ${INSTALL_DATA:=${INSTALL} -m 644} : ${INSTALL_SCRIPT:=${INSTALL} -m 755} : ${INSTALL_PROGRAM:=${INSTALL} -m 755} : ${INSTALL_PROGRAM_STRIP:=${INSTALL} -m 755 -s} : ${INSTALL_MAN:=${INSTALL} -m 444} : ${INSTALL_LIB:=${INSTALL} -m 755 -c} PKGNAME='tudu' ; VERSION='0.10.2' ; CONTACT_MAIL="meskio@sindominio.net" ; CONTACT_NAME="Ruben Pollan" ; CONTACT="Ruben Pollan " ; } show_usage() { cat <" echo "" exit 0 } take_environ() { : ${SH:=/bin/sh} : ${CPP:=cpp} : ${CXX:=g++} : ${PREFIX:=/usr/local/} } show_version() { echo "tudu-0.10.2 configuration script done with acr v1.2. The 'Free Software Foundation' message is only for autodetection. Originally written by pancake ." exit 0 } parse_options() { flag=`echo $1| cut -d = -f 1` value=`echo $1| awk 'BEGIN{FS="=";}{print $2}'` flag2=`echo $flag|cut -f2- -d -| sed -e 's,-,_,g' -e 's,^_,,g'|tr '[a-z]' '[A-Z]'` if [ "${TARGET_OS}" = "darwin" ]; then LIBPATH=-Wl,-install_name, else LIBPATH=-Wl,-R fi case $flag in -h|--help|--hel|--h|--he|-help) show_usage ; ;; -V|-version|--version) show_version ; ;; -r|--r|--report) echo "PKGNAME: tudu" echo "VERSION: 0.10.2" echo "LANGS: c++" echo "OPTIONAL: libncursesw" exit 0 ;; --cache-file) # ignored: acr have no cache ;; --build) BUILD="$value"; split_host BUILD ; ;; --host) CROSSBUILD=1 # XXX HOST="$value"; split_host HOST ; ;; --target) TARGET="$value"; split_host TARGET ; ;; --prefix) PREFIX="$value"; ;; --exec-prefix) EPREFIX="$value"; ;; --sandbox|--sprefix) SPREFIX="$value"; ;; --bindir) BINDIR="$value"; ;; --sbindir) SBINDIR="$value"; ;; --libexecdir) LIBEXECDIR="$value"; ;; --docdir) DOCDIR="$value"; ;; --datadir) DATADIR="$value"; ;; --sysconfdir) SYSCONFDIR="$value"; ;; --sharedstatedir) SHAREDSTATEDIR="$value"; ;; --localstatedir) LOCALSTATEDIR="$value"; ;; --libdir) LIBDIR="$value"; ;; --libpath) LDFLAGS="${LDFLAGS} ${LIBPATH}$value"; ;; --includedir) INCLUDEDIR="$value"; CFLAGS="${CFLAGS} -I$value"; ;; --infodir) INFODIR="$value"; ;; --mandir) MANDIR="$value"; ;; *) if [ "$value" ]; then eval "`echo $flag2=$value`" ; else echo ; echo "WARNING: Unknown flag '$flag'." >&2 ; echo ; fi ;; esac } # MAIN # take_environ split_host BUILD HOST TARGET [ -z "$ACRHOOK" ] && ACRHOOK=./configure.hook [ -e "$ACRHOOK" ] && . ${ACRHOOK} while : ; do [ -z "$1" ] && break parse_options "$1" shift done ENVWORDS="MANDIR INFODIR LIBDIR INCLUDEDIR LOCALSTATEDIR SYSCONFDIR DATADIR DOCDIR LIBEXECDIR SBINDIR BINDIR EPREFIX PREFIX SPREFIX TARGET HOST BUILD INSTALL INSTALL_LIB INSTALL_MAN INSTALL_PROGRAM INSTALL_PROGRAM_STRIP INSTALL_DIR INSTALL_SCRIPT INSTALL_DATA HOST_OS HOST_CPU BUILD_OS BUILD_CPU TARGET_OS TARGET_CPU PKGNAME VPATH VERSION CONTACT CONTACT_NAME CONTACT_MAIL YEAR CXX CXXFLAGS LDFLAGS HAVE_LANG_CXX CPP CPPFLAGS SRCS HAVE_XCURSES_H HAVE_NCURSESW_CURSES_H HAVE_NCURSES_CURSES_H HAVE_NCURSES_H HAVE_CURSES_H CURSES_INCLUDE HAVE_LIB_NCURSESW HAVE_LIB_NCURSES HAVE_LIB_CURSES LD_CURSES WIDEC_CURSES HAVE_STRING HAVE_VECTOR HAVE_MAP HAVE_FSTREAM HAVE_LIST HAVE_STACK HAVE_ALGORITHM HAVE_SET HAVE_CTIME HAVE_CSTRING HAVE_CSIGNAL HAVE_CSTDIO HAVE_CSTDLIB HAVE_SYS_TYPES_H HAVE_SYS_WAIT_H HAVE_SYS_STAT_H HAVE_UNISTD_H HAVE_FCNTL_H HAVE_LOCALE HAVE_CWCHAR HAVE_CLOCALE HAVE_CLIMITS HAVE_IOSTREAM HAVE_IOMANIP HAVE_SSTREAM HAVE_CERRNO" create_environ echo "checking build system type... ${BUILD}" echo "checking host system type... ${HOST}" echo "checking target system type... ${TARGET}" [ "${CROSSBUILD}" = 1 ] && echo "using crosscompilation mode." #split_host BUILD HOST TARGET [ -n "${prefix}" ] && PREFIX="${prefix}" echo "checking for working directories... ${WODIS}" echo "using prefix '${PREFIX}'" ACR_RMFILES=" test.c test.cxx a.out a.exe" : YEAR="2017" COMPILER=CXX HAVE_LANG_CXX=1 printf "checking for c++ compiler... " if [ "${CROSSBUILD}" = 1 ]; then (command -v ${HOST}-${CXX} 2>&1 >/dev/null) if [ "$?" = 0 ]; then CXX="${HOST}-${CXX}"; fi fi echo "#include " > test.cxx echo "int main(){ std::cout << 1; return 0;}" >> test.cxx (exec ${CXX} ${CXXFLAGS} ${LDFLAGS} test.cxx -lstdc++ >/dev/null 2>&1) if [ $? = 0 ]; then echo ${CXX}; else HAVE_LANG_CXX=0 echo no echo "ERROR: ${CXX} cannot create executables" >&2 ; do_remove exit 1 fi CXXFLAGS="${CXXFLAGS} -Wall -O2" CPPFLAGS="${CPPFLAGS} " SRCS="${SRCS} tudu.cc data.cc editor.cc interface.cc window.cc text.cc parser.cc config.cc date.cc screen.cc sched.cc cmd.cc" check_include() { VAR=$1 INC=$2 _REQUIRED=$3 printf "checking for $2... " echo > test.c echo "#include <${INC}>" >>test.c echo "int main(int ac, char **av){return 0;}" >>test.c eval \$${COMPILER} ${CFLAGS} ${CPPFLAGS} ${CXXFLAGS} test.c >/dev/null 2>&1 if [ $? = 0 ]; then eval ${VAR}=1 echo yes else eval ${VAR}=0 echo no ; fi } check_include HAVE_XCURSES_H xcurses.h 0 check_include HAVE_NCURSESW_CURSES_H ncursesw/curses.h 0 check_include HAVE_NCURSES_CURSES_H ncurses/curses.h 0 check_include HAVE_NCURSES_H ncurses.h 0 check_include HAVE_CURSES_H curses.h 0 if [ "$HAVE_XCURSES_H" = "1" ]; then CURSES_INCLUDE="xcurses.h"; fi if [ "$HAVE_NCURSESW_CURSES_H" = "1" ]; then [ -z "${CURSES_INCLUDE}" ] && CURSES_INCLUDE="ncursesw/curses.h"; fi if [ "$HAVE_NCURSES_CURSES_H" = "1" ]; then [ -z "${CURSES_INCLUDE}" ] && CURSES_INCLUDE="ncurses/curses.h"; fi if [ "$HAVE_NCURSES_H" = "1" ]; then [ -z "${CURSES_INCLUDE}" ] && CURSES_INCLUDE="ncurses.h"; fi if [ "$HAVE_CURSES_H" = "1" ]; then [ -z "${CURSES_INCLUDE}" ] && CURSES_INCLUDE="curses.h"; fi if [ "$CURSES_INCLUDE" = "" ]; then case "$undefined_variable" in 0|"") echo ; echo "ERROR: There is no curses installed!" >&2 ; echo ; exit 1 ;; esac; fi check_library() { VAR=$1 S="$" _REQUIRED=$3 _CHKLIB_NAME=$2 _CHKLIB_LIBS=$(echo "-l${_CHKLIB_NAME}" | sed 's,+, -l,g') printf "checking for lib${_CHKLIB_NAME} ... " echo "int main(int ac, char **av){return 0;}" > test.c eval ${S}${COMPILER} ${CFLAGS} ${CPPFLAGS} ${CXXFLAGS} ${LDFLAGS} ${_CHKLIB_LIBS} test.c >/dev/null 2>&1 if [ $? = 0 ]; then eval ${VAR}=1 echo yes else eval ${VAR}=0 echo no ; fi } check_library HAVE_LIB_NCURSESW ncursesw 0 check_library HAVE_LIB_NCURSES ncurses 0 check_library HAVE_LIB_CURSES curses 0 if [ "$HAVE_LIB_NCURSESW" = "1" ]; then LD_CURSES="-lncursesw"; fi if [ "$HAVE_LIB_NCURSES" = "1" ]; then [ -z "${LD_CURSES}" ] && LD_CURSES="-lncurses"; fi if [ "$HAVE_LIB_CURSES" = "1" ]; then [ -z "${LD_CURSES}" ] && LD_CURSES="-lcurses"; fi if [ "$LD_CURSES" = "" ]; then case "$undefined_variable" in 0|"") echo ; echo "ERROR: There is no curses installed!" >&2 ; echo ; exit 1 ;; esac; fi LDFLAGS="${LDFLAGS} $LD_CURSES" printf "checking for WIDEC_CURSES... " echo "#define _XOPEN_SOURCE_EXTENDED" > test.c ; echo "#include<$CURSES_INCLUDE>" >> test.c ; echo "int main(){ addwstr(L\"\"); }" >> test.c ; eval \$${COMPILER} ${CXXFLAGS} test.c ${LDFLAGS} >/dev/null 2>&1 ; WIDEC_CURSES=$? ; rm test.c if [ "$WIDEC_CURSES" = 0 ]; then WIDEC_CURSES=1 echo yes else WIDEC_CURSES=0 echo no fi if [ "$WIDEC_CURSES" = "0" ]; then case "$undefined_variable" in 0|"") echo ; echo "ERROR: There is no wide character support on curses!" >&2 ; echo ; exit 1 ;; esac; fi check_include HAVE_STRING string 1 check_include HAVE_VECTOR vector 1 check_include HAVE_MAP map 1 check_include HAVE_FSTREAM fstream 1 check_include HAVE_LIST list 1 check_include HAVE_STACK stack 1 check_include HAVE_ALGORITHM algorithm 1 check_include HAVE_SET set 1 check_include HAVE_CTIME ctime 1 check_include HAVE_CSTRING cstring 1 check_include HAVE_CSIGNAL csignal 1 check_include HAVE_CSTDIO cstdio 1 check_include HAVE_CSTDLIB cstdlib 1 check_include HAVE_SYS_TYPES_H sys/types.h 1 check_include HAVE_SYS_WAIT_H sys/wait.h 1 check_include HAVE_SYS_STAT_H sys/stat.h 1 check_include HAVE_UNISTD_H unistd.h 1 check_include HAVE_FCNTL_H fcntl.h 1 check_include HAVE_LOCALE locale 1 check_include HAVE_CWCHAR cwchar 1 check_include HAVE_CLOCALE clocale 1 check_include HAVE_CLIMITS climits 1 check_include HAVE_IOSTREAM iostream 1 check_include HAVE_IOMANIP iomanip 1 check_include HAVE_SSTREAM sstream 1 check_include HAVE_CERRNO cerrno 1 SEDFLAGS=" -e '" COUNT=0 for A in ${ENVWORDS} ; do [ "${A}" = VPATH ] && continue [ "${A}" = srcdir ] && continue eval "VAR=\$${A}" VAR="`echo ${VAR} | sed -e 's/\,/\\\,/g'`" [ $COUNT = 10 ] && COUNT=0 && SEDFLAGS="${SEDFLAGS}' -e '" COUNT=$(($COUNT+1)) SEDFLAGS="${SEDFLAGS}s,@${A}@,${VAR},g;" done SEDFLAGS="${SEDFLAGS}'" for A in . src data src/defs.h ; do # SUBDIRS if [ -f "${VPATH}/${A}.acr" ]; then SD_TARGET=${A} else if [ -d "${VPATH}/${A}" ]; then SD_TARGET=${A}/Makefile mkdir -p ${A} else echo "ERROR: Cannot find ${VPATH}/${A}.acr" >&2 exit 1 fi fi echo "creating ${SD_TARGET}" mkdir -p $(echo ${A} | sed -e "s,/`basename ${A}`$,,g") cat ${VPATH}/${SD_TARGET}.acr | \ eval sed -e "s,@VPATH@,${VPATH}/${A},g" ${SEDFLAGS} > ${SD_TARGET}.tmp for A in ${ENVWORDS}; do VALUE=`eval echo "$"${A}` if [ "$VALUE" = 0 ]; then ## FALSE MARK="##${A}##" if [ -n "`grep \"${MARK}\" ${SD_TARGET}.tmp`" ]; then mv ${SD_TARGET}.tmp ${SD_TARGET}.tmp2 cat ${SD_TARGET}.tmp2 | MARK=$MARK awk 'BEGIN{a=0;}{if($1==ENVIRON["MARK"]){if(a)a=0;else a=1}else{if(!a)print;}}' > ${SD_TARGET}.tmp fi fi done mv ${SD_TARGET}.tmp ${SD_TARGET} && rm -f ${SD_TARGET}.tmp2 if [ ! $? = 0 ]; then echo Cannot write target file ; control_c ; fi done do_remove tudu-0.10.2/COPYING0000644000175000017500000010451313121017272012324 0ustar useruser GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . tudu-0.10.2/Makefile.acr0000644000175000017500000000140013121017272013464 0ustar useruserVPATH=@VPATH@ PKGNAME=@PKGNAME@ VERSION=@VERSION@ .PHONY: all install uninstall dist clean mrproper distclean all: cd src && ${MAKE} cd data && ${MAKE} install: all cd src && ${MAKE} install cd data && ${MAKE} install clean: cd src && ${MAKE} clean cd data && ${MAKE} clean distclean: mrproper mrproper: clean cd src && ${MAKE} mrproper cd data && ${MAKE} mrproper rm Makefile uninstall: cd src && ${MAKE} uninstall cd data && ${MAKE} uninstall dist: mrproper cd .. && \ cp -r ${PKGNAME} ${PKGNAME}-${VERSION} && \ cd ${PKGNAME}-${VERSION} && \ rm -rf .git .gitignore .vimrc \ rm -rf _*.xml _*.xml.bkp .*.xml_lock \ rm -rf *.c *.jpg *.png \ acr cd .. && \ tar czvf ${PKGNAME}-${VERSION}.tar.gz ${PKGNAME}-${VERSION} && \ echo "dist done" tudu-0.10.2/AUTHORS0000644000175000017500000000004513121017272012334 0ustar useruserRuben Pollan tudu-0.10.2/data/0000755000175000017500000000000013121017273012177 5ustar userusertudu-0.10.2/data/welcome.xml0000644000175000017500000000032513121017273014354 0ustar useruser Welcome to "tudu" "tudu" is a tool to manage "to do" lists. tudu-0.10.2/data/default_theme0000644000175000017500000000011313121017273014723 0ustar useruser[ theme ] row = (help) row = 40%(tree,20|text) row = (,blank) row = (info) tudu-0.10.2/data/Makefile.acr0000644000175000017500000000137213121017273014406 0ustar useruserVPATH=@VPATH@ PKGNAME=@PKGNAME@ VERSION=@VERSION@ INSTALL_DATA=@INSTALL_DATA@ .PHONY: all install uninstall clean mrproper prefix=@PREFIX@ DATADIR?=@DATADIR@ SYSCONFDIR?=@SYSCONFDIR@ MANDIR?=@MANDIR@ all: install: mkdir -p $(DESTDIR)$(DATADIR)/$(PKGNAME) $(INSTALL_DATA) tudu.dtd $(DESTDIR)$(DATADIR)/$(PKGNAME) $(INSTALL_DATA) welcome.xml $(DESTDIR)$(DATADIR)/$(PKGNAME) mkdir -p $(DESTDIR)$(SYSCONFDIR) $(INSTALL_DATA) tudurc $(DESTDIR)$(SYSCONFDIR) mkdir -p $(DESTDIR)$(MANDIR)/man1 $(INSTALL_DATA) tudu.1 $(DESTDIR)$(MANDIR)/man1 clean: mrproper: clean rm Makefile uninstall: rm $(DESTDIR)$(DATADIR)/$(PKGNAME)/tudu.dtd rm $(DESTDIR)$(DATADIR)/$(PKGNAME)/welcome.xml rm $(DESTDIR)$(MANDIR)/man1/tudu.1 rmdir $(DESTDIR)$(DATADIR)/$(PKGNAME) tudu-0.10.2/data/tudu.dtd0000644000175000017500000000071613121017273013661 0ustar useruser tudu-0.10.2/data/tudu.10000644000175000017500000002256613121017273013255 0ustar useruser.\" Copyright (C) 2007-2012 Ruben Pollan Bella .\" Copyright (C) 2010 Enrique Matías Sánchez .\" .\" This file is part of TuDu. .\" .\" TuDu 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; version 3 of the License. .\" .\" TuDu 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 . .\" .TH TuDu 1 "January 09, 2010" Unix "User Manuals" .SH NAME TuDu \- A command-line tool to manage TODO lists hierarchically. .SH SYNOPSIS .PP \fBtudu \fR[\fB-f \fItudu_file\fR] [\fB-c \fIconfig_file\fR] [\fB-v[v]\fR] [\fB-h\fR] .SH DESCRIPTION .PP \fBTuDu\fR is a commandline tool to manage hierarchical TODO lists, so that you can organize everything you have to do in a simple and efficient way. It does not use any database backend, but plain XML files. Every TODO is composed by: .TS tab (>); l l. Status>Currently only two options: Pending and Done. Title>A short sentence summarizing the task. Description text>A longer text providing more details. (Optional) Priority>The urgency of the task. (Optional) Category>A short tag such as @home, @work, @inet. (Optional) Deadline>The latest date the task should be done. (Optional) Scheduled date>The planned date to do the task. (Optional) Subtasks>Every task can have any number of subtasks. (Optional) .TE Tasks can be ordered by any of those fields, and categories can be used to show only some certain kinds of tasks. Tudu also warns when a deadline is approaching, and shows the percentage of the task done so far. .SH OPTIONS .IP "-f \fItudu_file\fP" 10 Load the given tudu file .IP "-c \fIconfig-file\fP" 10 Load specific config file .IP "-v" 10 Display the TuDu version number. .IP "-vv" 10 Display license and copyright information. .IP "-h" 10 Display help. .SH INTERFACE All the key bindings described here are the defaults in tudu. They can be changed in the config file. .IP h Move the cursor one level out in the tree depth. .IP l Move the cursor one level in in the tree depth. .IP j Move the cursor to the next task. .IP k Move the cursor to the previous task. .IP J Move a task one position down. .IP K Move a task one position up. .IP m Mark a task as done. .IP dd Delete a task. .IP dt Remove the deadline of the task. .IP df Remove the priority of the task. .IP dS Remove the scheduled date of the task. .IP p Paste the last deleted task under the current cursor line. .IP P Paste the last deleted task over the current cursor line. .IP V Paste the last deleted task as a subtask of the currently selected task. .IP o Add new task. .IP O Add a new task over the current cursor line. .IP a Edit the title of the task. .IP t Edit the deadline. .IP f Set the priority of the task. .IP C Add or modify the category of the task. .IP e Edit the description text of the task. .IP x Scroll the text window upwards. .IP z Scroll the text window downwards. .IP S Edit the scheduled date of the task. .IP X Scroll the schedule window upwards. .IP Z Scroll the schedule window downwards. .IP c Collapse or expand the children of the current task. .IP M Hide or show tasks marked as done. .IP / Search for a pattern in tasks titles. .IP n Search the next occurrence of last search. .IP N Search the previous occurrence of the last searched tasks. .IP / Search for a pattern in tasks titles. .IP n Search the next occurrence of last search. .IP N Search the previous occurrence of the last search. .IP : Open the command input. See the COMMANDS section. .IP bt Sort by title. .IP bT Sort by title in reverse order. .IP bd Sort by done. .IP bD Sort by done in reverse order. .IP bl Sort by deadline. .IP bL Sort by deadline in reverse order. .IP bp Sort by priority. .IP bP Sort by priority in reverse order. .IP bc Sort by category. .IP bC Sort by category in reverse order. .IP bu Sort by user-defined order. .IP bU Sort by reversed user-defined order. .IP bd Sort by done. .IP bD Sort by done in reverse order. .IP bl Sort by deadline. .IP bL Sort by deadline in reverse order. .IP bp Sort by priority. .IP bP Sort by priority in reverse order. .IP bc Sort by category. .IP bC Sort by category in reverse order. .IP bu Sort by user. .IP bU Sort by user in reverse order. .IP s Save all the changes. .IP ? Display the help. .IP q Quit tudu saving the last changes. .IP Q Quit tudu without saving anything. .SH COMMANDS .IP "hide category1 category2 ... categoryN" Hide one or more categories. .IP "show category1 category2 ... categoryN" Display one or more categories. .IP showall Display all the categories. .IP "showonly category1 category2 ... categoryN" Hide all the categories except the ones given. .IP "help" Display the man page. .SH CONFIG The config file have several sections which start by a name between brackets, like \fB[ general ]\fR. Other config files can be included with the option: .IP "@include = 'path'" .PP The options of each section are: .SS general .IP "collapse = yes|\fBno\fR" Collapse the tasks by default. .IP "hide_done = yes|\fBno\fR" Whether to hide tasks marked as done. .IP "hide_percent = yes|\fBno\fR" Whether to hide the percentage display on each task. .IP "visual_tree = yes|\fBno\fR" Toggle graphical tree. It shows marks, like \fB(+)\fR at the left of the tasks. It is necessary in some shells that can not display bold characters. .IP "bold_parent = \fByes\fR|no" Hilight the parents with children with bold letters. .IP "loop_move = yes|\fBno\fR" Whether to jump to the beginning (or end) when the end (or beginning) is reached. .IP "days_warn = number" How many days before the task is due will the deadline sport a warning remark. By default is 7. .IP "us_dates = yes|\fBno\fR" Use US date format (mm/dd/yyyy), by default it uses dd/mm/yyyy. .IP "old_sched = \fByes\fR|no" Whether display or not past scheduled tasks on the scheduler. In case of yes the scheduled tasks for days already past will be displayed on warn color. .IP "tudu_file = full-path" Location of the tudu xml to be load if no '-f' parameter is given. The path have to be a full path. If is not set ~/.tudu.xml will be use. .IP "sort_order = string" Default order in which tasks will be shown. Tasks are ordered by the 1st letter in the string, then by the 2nd, and so on. The letters mean: .RS .IP t title .IP T reverse title .IP d done .IP D reverse done .IP l deadline .IP L reverse deadline .IP c category .IP C reverse category .IP e percentage done .IP E reverse percentage done .IP u user-defined order .IP U reverse user-defined order .RE .IP "editor = 'path_bin %s'" .SS keys This section defines any key binding on the program. See the example in the default config file. .SS theme Window positions are described by rows; each row with the syntax: .RS row = [height]([width|]window[, [width|]window, ...]) .RE The height and width can be the number of characters or a percentage followed by \fB%\fR. The possible windows are: help, tree, info, blank, vpipe, hpipe text, and schedule. The windows help, vpipe and info don't need to have height, neither hpipe needs to have width, because is predefined as 1. TuDu will try to guess the non given information. Other options for the theme are: .IP "columns = colm1,...,colmN" Columns in tree window. The possible columns are: title, priority, category and deadline. .IP "category_length = numChar" Number of characters to be displayed of the category. .IP "color = color_text, color_background" The default colors for the text and background. If your terminal has support to change colora the colors can be defined as \fB(r, g, b)\fR, where r, g and b are numbers from 0 to 1000, or with the words: black, red, green, yellow, blue, magenta, cyan, white, transparent. .IP "window = color_text, color_background" For each window can be defined it's own colors. The colors of vpipe and hpipe are the same, and defined with the window name \fBpipe\fR. .IP "selected = color_text, color_background" Color for the items under the cursor. .IP "warn = color_text, color_background" Color for the warnings, like the mark of deadline soon or the color of the task scheduled on the past. .SH FILES .PP .IP "~/.tudurc" User configuration file. .IP "/etc/tudurc" Global configuration file. .IP "~/.tudu.xml" User default tudu. .SH NO WARRANTIES 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. .SH SEE ALSO .PP TuDu Home Page: https://code.meskio.net/tudu/ .SH AUTHOR TuDu was written by Rub\['e]n Poll\['a]n Bella . .PP This manual page was written by Rub\['e]n Poll\['a]n Bella and further improved by Enrique Mat\['i]as S\['a]nchez. tudu-0.10.2/data/tudurc0000644000175000017500000001013113121017273013424 0ustar useruser# It is posible to include other config files: # @include = "/home/foobar/.tudu_keys" [ general ] collapse = no # collapse by default hide_done = no # Whether to hide tasks marked as done. hide_percent = no # Whether to hide percentage display on tasks visual_tree = no # Toggle graphical tree. It shows (+) on parent's left side. # Necessary in some shells that can not display bold characters. bold_parent = yes # hilight the parents with children with bold letters loop_move = no # whether to jump to the beginning (or end) # when the end (or beginning) is reached days_warn = 2 # how many days before the task is due # will the deadline sport a warning remark us_dates = no # use US date format (mm/dd/yyyy). # by default it uses dd/mm/yyyy old_sched = yes # display past sched task on the scheduler # Location of the xml file, use the full path # By default ~/.tudu.xml will be use #tudu_file = /home/foobar/.tudu.xml # The default order in which tasks will be shown. # Tasks are ordered by the 1st letter in the string, then by the 2nd, and so on. # l = deadline d = done # p = priority t = title # u = user-defined e = percentage # c = category # By uppercasing the letters the order will be reversed sort_order = lpu # The editor to use to edit the long description texts. # Default is the inline editor. # editor = "/usr/bin/vim %s" # Use the vim editor [ keys ] # All the key definitions for TuDu out = h # out one level in depth in = l # get one level deeper down = j up = k # move todos move_down = J move_up = K delete = dd # delete a todo delDeadline = dt delPriority = df delSched = dS paste = p # paste the last deleted pasteUp = P # paste the last deleted upper than the cursor pasteChild = V # paste the last deleted as child of the task done = m # mark as done addTodo = o addTodoUp = O # add todo upper than the cursor editTitle = a editDeadline = t setPriority = f # add or modify the priority setCategory = C # add or modify the category editText = e editSched = S # add or modify the scheduled date schedUp = X # move a task up on the scheduler schedDown = Z # move a task down on the scheduler upText = x downText = z collapse = c # Collapse or expand a category having children hideDone = M # hide/show done tasks search = / searchNext = n searchPrev = N cmd = : sortByTitle = bt sortRevTitle = bT sortByDone = bd sortRevDone = bD sortByDeadline = bl sortRevDeadline = bL sortByPriority = bp sortRevPriority = bP sortByCategory = bc sortRevCategory = bC sortByUser = bu sortRevUser = bU save = s # save todo help = ? quit = q quitNoSave = Q [ theme ] # Columns of the tree window columns = title,priority,category,deadline # Length of the category to be displayed category_length = 12 # Size of the windows shown, given in number of rows and columns. # Syntax: row = height(width|win, width|win, ...) # 'win' can be empty or be one of these: help, tree, info, blank, text, schedule # 'height' and 'width' can be empty, an absolute value, or a percentage. # The help and info windows don't need to have a height, because is predefined as 1. # TuDu will try to guess the non given information. row = (help) row = 1(blank,vpipe,30|blank) row = 70%(tree,vpipe,30|schedule) # Show the schedule on the right side of screen # row = 70%(tree) # or, alternatively, do not show the schedule. row = (hpipe) row = (text) row = (info) # Colors. The first one is the text color, the second one is the background. # Valid colors: black, red, green, yellow, blue, magenta, cyan, white, transparent # or a color defined like: (r, g, b) # where 'r', 'g' and 'b' are numbers from 0 to 1000. color = white, transparent # Default colors selected = green, transparent warn = red, transparent pipe = white, blue help = white, blue # tree = # info = # text = # schedule = black, blue tudu-0.10.2/data/foo_theme0000644000175000017500000000137113121017273014071 0ustar useruser[ theme ] # windows in screen by rows and columns # sintax: row = height(width|win, width|win, ...) # win can be empty or: help, tree, info, blank, # height can be empty, absolute or percent with % at the end # width can be like height row = (help) row = 1(blank) row = 60%(tree,60|text) row = (,blank) row = (info) # columns of the tree window columns = title,priority,category,deadline # colors the first one is the text color the second the background # valid colors: black, red, green, yellow, blue, magenta, cyan, white, transparent # or a color defined like: (r, g, b) # with r, g and b numbers from 0 to 1000 color = cyan, transparent selected = green, transparent help = (756,200,100), blue tree = magenta, (134,72,890) deadlineMark = red, transparent tudu-0.10.2/CONTRIBUTORS0000644000175000017500000000071713121017272013152 0ustar useruserMichael Leslie - fixed up the English Magnus Müller - scroll to beginning end if end beginning reached patch Enrique Matías - several patches Thorbjörn Jemander - Removed the dangerous ctrl-C evgeny - fixing wrong year in deadline and schedule Ioan Calin Borcoman - Fixed sched load segfault Takeshi Hamasaki - added Ctrl-L support Krzysztof Sawicki - Fixed segfault on load schedule and add extra keybindings Evgenii Sovetkin - Fixed typo in '-f' arg parsing tudu-0.10.2/src/0000755000175000017500000000000013121017272012054 5ustar userusertudu-0.10.2/src/config.h0000644000175000017500000001104513121017272013473 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #ifndef CONFIG_H #define CONFIG_H #include "includes.h" #include "window.h" struct key_action; typedef map key_map; struct key_action { wstring action; key_map subkeys; }; typedef map action_list; #define PRIORITY_LENGTH 1 #define DEADLINE_LENGTH 12 #define HELP_MIN_WIDTH 67 /* information about window position */ #define MAX_THEME_COLS 16 #define MAX_THEME_ROWS 16 #define MAX_THEME_TREECOLS 4 enum window_type { WHELP, WTREE, WTEXT, WINFO, WPRIORITY, WCATEGORY, WDEADLINE, WSCHEDULE, NUM_WINDOWS, WNULL, WBLANK, WVPIPE, WHPIPE }; typedef struct { bool exist[NUM_WINDOWS]; window_coor coor[NUM_WINDOWS]; vector vpipe; vector hpipe; } windows_defs; /* color theme */ enum color_theme { CT_DEFAULT, CT_SELECTED, CT_WARN, CT_HELP, CT_TREE, CT_TEXT, CT_INFO, CT_SCHEDULE, CT_PIPE, NUM_CT }; typedef struct { short int color; short int red; short int green; short int blue; } color_t; class Config { public: Config(); bool load(const char* path); bool getAction(wchar_t key, wstring& action); void clearKeys(); void getActionList(action_list& list); bool getCollapse(); bool& getHideDone(); bool getHidePercent(); bool getVisualTree(); bool getBoldParent(); bool getLoopMove(); bool getOldSched(); int getDaysWarn(); bool useUSDates(); wstring& getTuduFile(); wstring& getSortOrder(); char* getEditor(); int getCategoryLength(); void genWindowCoor(int lines, int cols, windows_defs& coor); void getColorList(color_t* color_list[], short int& length); void getColorPair(short int win, short int& foreground, short int& background); private: typedef struct { window_type window; int width; bool absolute_width; } theme_window; typedef struct { theme_window windows[MAX_THEME_COLS]; int num_windows; int height; bool absolute_height; } theme_row; typedef struct { bool exist; short int foreground; short int background; } color_pair_t; key_map tree_keys; key_map* key_comb; action_list action_keys; bool collapse; bool hide_done; bool hide_percent; bool visual_tree; bool bold_parent; bool loop_move; int days_warn_deadline; bool us_dates; bool old_sched; wstring tudu_file; wstring sort_order; char editor[64]; /* themes */ int row_index; theme_row rows[MAX_THEME_ROWS]; int tree_columns[MAX_THEME_TREECOLS]; int tree_index; int category_length; color_pair_t color_win[NUM_CT]; color_t colors[NUM_CT*2]; short int num_colors; void getOutContextOption(wstring& option, wstring& value); bool isYes(wstring& value); void getGeneralOption(wstring& option, wstring& value); void insertKeyMap(key_map& k, wstring action, wstring keys); void resetTheme(); void getThemeOption(wstring& option, wstring& value); void getThemeRow(wstring& value); void getThemeWindow(wstring fmt, theme_window& w); void getThemeTree(wstring& value); void getThemeCategoryLength(wstring& value); void getThemeColors(wstring& option, wstring& value); short int getThemeColor(wstring color); int getContext(wstring& str); bool genWindowHeights(int lines, int height[]); bool genWindowWidths(int row_index, int cols, windows_defs& coor, int width[]); bool genWindowTree(windows_defs& coor, int height, int x, int y); bool _genWindowCoor(int lines, int cols, windows_defs& coor); }; #endif tudu-0.10.2/src/tudu.cc0000644000175000017500000001556713121017272013362 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #include "includes.h" extern int errno; #include "interface.h" #include "screen.h" #include "data.h" #include "sched.h" #include "parser.h" #include "config.h" #define usage() \ cout << "Usage: " << argv[0] << " [options]" << endl; \ cout << "\t-f file\tload tudu file" << endl; \ cout << "\t-c file\tload specific config file" << endl << endl; \ cout << "\t-v\tshow version" << endl; \ cout << "\t-h\tshow this usage message" << endl << endl; \ cout << "The default config file is in ~/.tudurc" << endl; #define version() \ cout << VERSION_STR << endl; \ cout << "TuDu Copyright (C) 2007-2015 Ruben Pollan Bella " << endl; \ cout << "TuDu comes with ABSOLUTELY NO WARRANTY; for details type `tudu -vv'" << endl; \ cout << "This is free software; you are welcome to redistribute it" << endl; \ cout << "under certain conditions. Type `tudu -vv' for details." << endl; #define copyright() \ cout << VERSION_STR << endl; \ cout << "Copyright (C) 2007-2015 Ruben Pollan Bella " << endl << endl; \ cout << "TuDu is free software; you can redistribute it and/or modify" << endl; \ cout << "it under the terms of the GNU General Public License as published by" << endl; \ cout << "the Free Software Foundation; version 3 of the License." << endl << endl; \ cout << "TuDu is distributed in the hope that it will be useful," << endl; \ cout << "but WITHOUT ANY WARRANTY; without even the implied warranty of" << endl; \ cout << "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the" << endl; \ cout << "GNU General Public License for more details." << endl << endl; \ cout << "You should have received a copy of the GNU General Public License" << endl; \ cout << "along with this program. If not, see ." << endl; /* return true for delete lock file and false for close tudu */ bool lock_ask() { cout << endl << "Lock file found" << endl; cout << endl << "either" << endl; cout << " Another program may be editing the same file." << endl; cout << " If this is the case, be careful not to end up with two" << endl; cout << " different instances of the same file when making changes." << endl; cout << " Quit, or continue with caution." << endl; cout << endl << "or" << endl; cout << " A tudu session for this file crashed." << endl; cout << " \"Edit anyway\" will destroy the lock file." << endl; cout << endl << "[E]dit anyway, [Q]uit:"; string str; cin >> str; if ((str[0] == 'E') || (str[0] == 'e')) return true; else return false; } int main(int argc, char **argv, char *env[]) { int i; char file_rc[128], file_xml[128], file_lock[133]; // Disable Ctrl-C: Otherwise all changes are lost if one slips. struct sigaction ignore_ctrl_c; ignore_ctrl_c.sa_handler = SIG_IGN; ignore_ctrl_c.sa_flags = 0; sigaction(SIGINT, &ignore_ctrl_c, NULL); for (i = 0; strncmp(env[i],"HOME=",5); ++i); Config config; bool configErr = !config.load(CONFIG_FILE); // the error will be displayed after check args strncpy(file_rc,env[i]+5,119); file_rc[119] = '\0'; strncat(file_rc,"/.tudurc", 9); config.load(file_rc); if (config.getTuduFile() == L"") { strncpy(file_xml,env[i]+5,117); file_xml[117] = '\0'; strncat(file_xml,"/.tudu.xml", 10); } else { wcstombs(file_xml, config.getTuduFile().c_str(), 128); } /* * Parse the comand line arguments */ for (i = 1; i < argc; ++i) { if (!strncmp("-f",argv[i],2)) { ++i; if (i < argc) { strncpy(file_xml, argv[i], 127); file_xml[127] = '\0'; } else { usage(); return 0; } } else if (!strncmp("-c",argv[i],2)) { ++i; if (i < argc) { if (argv[i][0] != '/') { int j; for (j = 0; strncmp(env[j],"PWD=",4); ++j); strncpy(file_rc,env[j]+4,99); file_rc[99] = '\0'; strcat(file_rc,"/"); strncat(file_rc,argv[i],27); } else { strncpy(file_rc, argv[i], 127); file_rc[127] = '\0'; } config.load(file_rc); } else { usage(); return 0; } } else if (!strncmp("-vv",argv[i],3)) { copyright(); return 0; } else if (!strncmp("-v",argv[i],2)) { version(); return 0; } else if (!strncmp("--help",argv[i],6) || !strncmp("-h",argv[i],2)) { usage(); return 0; } } if (configErr) { fprintf(stderr, "Err: Global config does not exist. The config should be %s\n", CONFIG_FILE); exit(1); } /* * Check and create the lock file */ strcpy(file_lock,file_xml); for (i = strlen(file_lock); (file_lock[i] != '/') && (i > 0); i--); if (file_lock[i] == '/') i++; if (file_lock[i] != '.') { file_lock[i] = '.'; file_lock[i+1] = '\0'; strcat(file_lock, file_xml+i); } strcat(file_lock,"_lock"); // FIXME: it wont work with NFS int lock; lock = open(file_lock, O_CREAT|O_EXCL, 00666); if (lock == -1) { if (errno == EEXIST) { if (!lock_ask()) exit(1); } /* no rights to write in this folder skip the problem */ else if (errno != EACCES) { fprintf(stderr, "Err: I can not create the lock file %s\n", file_lock); exit(1); } } else { close(lock); } /* * Load data */ ToDo node; iToDo it(node); Sched sched; Parser p(file_xml); if (!p.parse(node,sched)) { Parser welcome(WELCOME_FILE); /* welcome file don't exist */ if (!welcome.parse(node,sched)) { fprintf(stderr, "Err: Welcome file does not exist. It should be %s\n", WELCOME_FILE); unlink(file_lock); exit(1); } } /* * Load end start interface */ Writer w(file_xml,node); Screen screen(config); Cmd cmd; Interface in(screen,it,sched,config,w,cmd); in.main(); /* * Delete lock file */ unlink(file_lock); return 0; } tudu-0.10.2/src/window.cc0000644000175000017500000001015713121017272013676 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #include "window.h" Window::Window(window_coor coor) { win = newwin(coor.lines, coor.cols, coor.y, coor.x); keypad(win, TRUE); } Window::Window(int lines, int cols, int y, int x) { win = newwin(lines, cols, y, x); keypad(win, TRUE); } Window::Window() { int lines, cols; getmaxyx(stdscr, lines, cols); win = newwin(lines, cols, 0, 0); keypad(win, TRUE); } Window::~Window() { delwin(win); } /* int Window::printw(const char *fmt, ...) { wprintw(win, fmt, ...); wrefresh(win); } */ int Window::_addstr(const char *str) { return waddstr(win, str); } int Window::_addstr(const wchar_t *str) { return waddwstr(win, str); } int Window::_addstr(int y, int x, const char *str) { return mvwaddstr(win, y, x, str); } int Window::_addstr(int y, int x, const wchar_t *str) { return mvwaddwstr(win, y, x, str); } int Window::_addstr(const string &str) { return waddstr(win, str.c_str()); } int Window::_addstr(const wstring &str) { return waddwstr(win, str.c_str()); } int Window::_addstr(int y, int x, const string &str) { return mvwaddstr(win, y, x, str.c_str()); } int Window::_addstr(int y, int x, const wstring &str) { return mvwaddwstr(win, y, x, str.c_str()); } int Window::_addstr(const wstring &str, const unsigned int cols) { unsigned int i = 0, c = 0; while (i < str.length()) { const unsigned int width = wcwidth(str[i]); if (width > cols-c) { break; } cchar_t ch; ch.attr = 0; ch.chars[0] = str[i]; ch.chars[1] = L'\0'; wadd_wch(win, &ch); c += wcwidth(str[i]); i++; } while (cols != c) { waddch(win, ' '); c++; } return i; } int Window::_addstr(int y, int x, const wstring &str, const unsigned int cols) { wmove(win, y, x); return _addstr(str, cols); } int Window::_addch(const char ch) { return waddch(win, ch); } int Window::_addch(int y, int x, const char ch) { return mvwaddch(win, y, x, ch); } int Window::_refresh() { return wrefresh(win); } int Window::_redraw() { return redrawwin(win); } int Window::_move(int y, int x) { return wmove(win, y, x); } int Window::_attron(int attrs) { return wattron(win, attrs); } int Window::_attroff(int attrs) { return wattroff(win, attrs); } int Window::_erase() { return werase(win); } int Window::_getch(wint_t& ch) { return wget_wch(win, &ch); } void Window::_getmaxyx(int& y, int& x) { getmaxyx(win, y, x); } int Window::_box() { return box(win, 0, 0); } int Window::_lines() { int lines, cols; getmaxyx(win, lines, cols); return lines; } int Window::_cols() { int lines, cols; getmaxyx(win, lines, cols); return cols; } int Window::_resize(int lines, int columns) { return wresize(win, lines, columns); } int Window::_mv(int y, int x) { return mvwin(win, y, x); } int Window::_vline(chtype ch, int n) { return wvline(win, ch, n); } int Window::_hline(chtype ch, int n) { return whline(win, ch, n); } int Window::_delwin() { return delwin(win); } tudu-0.10.2/src/interface.h0000644000175000017500000000650713121017272014175 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #ifndef INTERFACE_H #define INTERFACE_H #include "includes.h" class Interface; #include "data.h" #include "sched.h" #include "config.h" #include "parser.h" #include "editor.h" #include "screen.h" #include "cmd.h" class Interface { public: Interface(Screen& s, iToDo &t, Sched& sch, Config &c, Writer &w, Cmd &com); ~Interface(); void main(); friend class Cmd; private: Screen &screen; iToDo &cursor; Sched &sched; Config &config; Writer &writer; pToDo copied; wstring sortOrder; wstring search_pattern; Cmd &cmd; /* command interface */ set hidden_categories; int cursor_line; void resizeTerm(); void drawTodo(); void eraseCursor(); /* * calculate the position of the cursor on the screen * so if it was out of the screen it places it inside. * return true if the screen must be redrawn */ bool fitCursor(); void drawCursor(); bool isHide(iToDo& todo); void inherit(); /* update cursor and cursor_line to previous entry on the screen */ bool next(); /* update cursor and cursor_line to next entry on the screen always points to a valid line */ bool prev(); void left(); void right(); void up(); void down(); void prevPage(); void nextPage(); void home(); void end(); void move_up(); void move_down(); void done(); void del(); void delDeadline(); void delPriority(); void delSched(); void paste(); void pasteUp(); void pasteChild(); bool editLine(wstring& str); void editDeadline(); void setPriority(); void setCategory(); void addLine(); void addLineUp(); void modifyLine(); void editText(); void editSched(); void schedUp(); void schedDown(); void upText(); void downText(); void collapse(); void hide_done(); void command_line(); bool _search(); void search(); void search_next(); void search_prev(); void sortByTitle(); void sortByDone(); void sortByDeadline(); void sortByPriority(); void sortByCategory(); void sortByUser(); void sortRevTitle(); void sortRevDone(); void sortRevDeadline(); void sortRevPriority(); void sortRevCategory(); void sortRevUser(); void save(); void help(); }; #endif tudu-0.10.2/src/defs.h.acr0000644000175000017500000000333513121017272013716 0ustar useruser /************************************************************************** * Copyright (C) 2007-2011 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #define VERSION_STR "TuDu @VERSION@ (@YEAR@)" #define SHARE_DIR "@DATADIR@/@PKGNAME@" #define WELCOME_FILE "@DATADIR@/@PKGNAME@/welcome.xml" #define CONFIG_FILE "@SYSCONFDIR@/tudurc" #define PATH_DTD "@DATADIR@/@PKGNAME@/tudu.dtd" #if @HAVE_XCURSES_H@ #define HAVE_XCURSES_H #endif #if @HAVE_NCURSESW_CURSES_H@ #define HAVE_NCURSESW_CURSES_H #endif #if @HAVE_NCURSES_CURSES_H@ #define HAVE_NCURSES_CURSES_H #endif #if @HAVE_CURSES_H@ #define HAVE_CURSES_H #endif tudu-0.10.2/src/includes.h0000644000175000017500000000413213121017272014033 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #ifndef DEFS_H #define DEFS_H #include "defs.h" /* include curses */ #define _XOPEN_SOURCE_EXTENDED #ifdef HAVE_XCURSES_H #include #elif defined(HAVE_NCURSESW_CURSES_H) #include #elif defined(HAVE_NCURSES_CURSES_H) #include #else #include #endif /* system includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #endif tudu-0.10.2/src/config.cc0000644000175000017500000004566713121017272013652 0ustar useruser /************************************************************************* * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 .* *************************************************************************/ #include "config.h" #define DEFAULT_CATEGORY_LENGTH 7 /* * Context in the config file * define with [ keys ] */ enum context_type { C_NULL, C_KEYS, C_GENERAL, C_THEME }; Config::Config(): key_comb(NULL), collapse(false), hide_done(false), hide_percent(false), visual_tree(false), bold_parent(true), loop_move(false), days_warn_deadline(7), us_dates(false), old_sched(true) { category_length = DEFAULT_CATEGORY_LENGTH; } bool Config::load(const char* path) { int context = C_NULL; wifstream file; file.imbue(locale("")); file.open(path); if (!file) return false; tudu_file = L""; sort_order = L""; editor[0] = '\0'; while (!file.eof()) { wstring line, str = L"", option, value; int pos; bool is_definition = false; bool quote = false; getline(file, line); // drop all the spaces for (wstring::iterator i = line.begin(); i != line.end(); i++) { if (L'"' == *i) quote = !quote; else if (quote) str += *i; else if (L'#' == *i) break; //is a coment else if (L'=' == *i) { is_definition = true; str += *i; } else if ((*i != L' ') && (*i != L'\t')) str += *i; } /* * Change of context */ if ((L'[' == str[0]) && (L']' == str[str.length()-1])) { wstring aux = str.substr(1,str.length()-2); context = getContext(aux); continue; } if (!is_definition) continue; //is not a valid line pos = str.find(L"="); option = str.substr(0, pos); value = str.substr(pos+1); if (value.empty()) continue; if ('@' == option[0]) getOutContextOption(option, value); else switch (context) { case C_GENERAL: getGeneralOption(option, value); break; case C_KEYS: insertKeyMap(tree_keys, option, value); action_keys.erase(option); action_keys.insert(pair(option,value)); break; case C_THEME: getThemeOption(option, value); break; } } file.close(); return true; } void Config::getOutContextOption(wstring& option, wstring& value) { if (L"@include" == option) { char path[256]; wcstombs(path, value.c_str(), 256); load(path); } } inline bool Config::isYes(wstring& value) { if (L"yes" == value) return true; return false; } void Config::getGeneralOption(wstring& option, wstring& value) { if (L"collapse" == option) collapse = isYes(value); if (L"hide_done" == option) hide_done = isYes(value); if (L"hide_percent" == option) hide_percent = isYes(value); if (L"visual_tree" == option) visual_tree = isYes(value); if (L"bold_parent" == option) bold_parent = isYes(value); if (L"loop_move" == option) loop_move = isYes(value); if (L"old_sched" == option) old_sched = isYes(value); if (L"days_warn" == option) { char num[5]; wcstombs(num, value.c_str(), 5); days_warn_deadline = atoi(num); } if (L"us_dates" == option) us_dates = isYes(value); if (L"tudu_file" == option) tudu_file = value.c_str(); if (L"sort_order" == option) sort_order = value.c_str(); if (L"editor" == option) wcstombs(editor, value.c_str(), 64); } void Config::insertKeyMap(key_map& k, wstring action, wstring keys) { if ((keys.length() == 1) || (keys[1] == L'#')) { key_action act; act.action = action; k.erase(keys[0]); k.insert(pair(keys[0],act)); } else { if (0 == k.count(keys[0])) { key_action act; act.action = L""; k.insert(pair(keys[0],act)); } insertKeyMap(k[keys[0]].subkeys, action, keys.substr(1)); } } bool Config::getAction(wchar_t key, wstring& action) { if (key_comb) { if (key_comb->count(key) == 1) { key_action& act = (*key_comb)[key]; if (!act.subkeys.empty()) { key_comb = &act.subkeys; } else { key_comb = NULL; } if ( act.action != L"") { action = act.action; return true; } else { action = L""; return false; } } else { key_comb = NULL; } } if (tree_keys.count(key) == 1) { key_action& act = tree_keys[key]; if (!act.subkeys.empty()) { key_comb = &act.subkeys; } if ( act.action != L"") { action = act.action; return true; } } action = L""; return false; } void Config::clearKeys() { key_comb=NULL; } void Config::getActionList(action_list& list) { list = action_keys; } void Config::resetTheme() { row_index = 0; tree_index = 0; num_colors = 0; for (int i=0; i 0) { if ('%' == value[i-1]) { row.absolute_height = false; str = value.substr(0, i-1); } else { row.absolute_height = true; str = value.substr(0, i); } char num[5]; wcstombs(num, str.c_str(), 5); row.height = atoi(num); } else row.height = 0; /* windows */ win = 0; while (i != wstring::npos) { wstring::size_type n; j=i+1; i=value.find(L",", j); if (win == MAX_THEME_COLS) { fprintf(stderr, "Error: too many windows in a row for theme\n"); exit(1); } if (i == wstring::npos) n = value.length()-j-1; else n = i-j; getThemeWindow(value.substr(j,n), row.windows[win]); win++; } row.num_windows = win; row_index++; } void Config::getThemeWindow(wstring fmt, theme_window& w) { wstring::size_type i; if ((i=fmt.find(L"|", 0)) != wstring::npos) { if (fmt[i-1] == L'%') { w.absolute_width = false; char num[5]; wcstombs(num, fmt.substr(0,i-1).c_str(), 5); w.width = atoi(num); } else { w.absolute_width = true; char num[5]; wcstombs(num, fmt.substr(0,i).c_str(), 5); w.width = atoi(num); } fmt = fmt.substr(i+1); } else w.width = 0; if (L"" == fmt) { if (row_index == 0) { fprintf(stderr, "Error: null entry in theme too early\n"); exit(1); } w.window = WNULL; } else if (L"blank" == fmt) w.window = WBLANK; else if (L"vpipe" == fmt) w.window = WVPIPE; else if (L"hpipe" == fmt) w.window = WHPIPE; else if (L"help" == fmt) w.window = WHELP; else if (L"tree" == fmt) w.window = WTREE; else if (L"text" == fmt) w.window = WTEXT; else if (L"schedule" == fmt) w.window = WSCHEDULE; else if (L"info" == fmt) w.window = WINFO; else { fwprintf(stderr, L"Error: unknown window %ls\n", fmt.c_str()); exit(1); } } void Config::getThemeTree(wstring& value) { wstring::size_type i = 0, j = 0; wstring str; tree_index=0; while (i != wstring::npos) { if (tree_index>MAX_THEME_TREECOLS) { fprintf(stderr, "Error: too many cols in a tree for theme\n"); exit(1); } i=value.find(L",", j); str = value.substr(j,i-j); if (L"title" == str) { tree_columns[tree_index] = WTREE; } else if (L"priority" == str) { tree_columns[tree_index] = WPRIORITY; } else if (L"category" == str) { tree_columns[tree_index] = WCATEGORY; } else if (L"deadline" == str) { tree_columns[tree_index] = WDEADLINE; } else { tree_index--; } j=i+1; tree_index++; } } void Config::getThemeCategoryLength(wstring& value) { char num[5]; wcstombs(num, value.c_str(), 5); category_length = atoi(num); } void Config::getThemeColors(wstring& option, wstring& value) { short int color_index; string::size_type i,j; if (L"color" == option) color_index = CT_DEFAULT; else if (L"selected" == option) color_index = CT_SELECTED; else if (L"warn" == option) color_index = CT_WARN; else if (L"pipe" == option) color_index = CT_PIPE; else if (L"help" == option) color_index = CT_HELP; else if (L"tree" == option) color_index = CT_TREE; else if (L"text" == option) color_index = CT_TEXT; else if (L"schedule" == option) color_index = CT_SCHEDULE; else if (L"info" == option) color_index = CT_INFO; else { fwprintf(stderr, L"Error: color theme %ls undefined\n", option.c_str()); exit(1); } j=value.find(L"(", 0); i=value.find(L",", 0); if (j lines) { return false; /* don't fit in screen */ } if (undefined_row != -1) { height[undefined_row] = lines-sum_height; } return true; } bool Config::genWindowWidths(int row_index, int cols, windows_defs& coor, int width[]) { int top_win; int undefined_col = -1; int sum_width = 0; bool undefined_width = false; theme_row& row = rows[row_index]; for (int j=0; j cols) { return false; /* don't fit in screen */ } if (undefined_col != -1) { width[undefined_col] = cols-sum_width; } return true; } bool Config::genWindowTree(windows_defs& coor, int height, int x, int y) { int x_tree; x_tree = x; coor.coor[WTREE].cols--; for (int k=0; k * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #ifndef DATE_H #define DATE_H #include "includes.h" class Date { public: Date(int day = 1, int month = 1, int year = 1900); int& day(int d = 0); int& month(int m = 0); int& year(int y = 0); void setToday(); bool valid(); /* if valid date if year == 1900 is invalid */ bool correct(); /* if this date exist */ int daysLeft(); Date operator-(int days); Date operator+(int days); bool operator<(Date d); bool operator>(Date d); bool operator!=(Date d); bool operator==(Date d); protected: int _day, _month, _year; }; #endif tudu-0.10.2/src/screen.cc0000644000175000017500000005250313121017272013647 0ustar useruser /************************************************************************* * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 .* *************************************************************************/ #include "screen.h" #define COLOR_SELECTED COLOR_PAIR(CT_SELECTED) #define COLOR_WARN COLOR_PAIR(CT_WARN) #define COLOR_HELP COLOR_PAIR(CT_HELP) #define COLOR_TREE COLOR_PAIR(CT_TREE) #define COLOR_TEXT COLOR_PAIR(CT_TEXT) #define COLOR_INFO COLOR_PAIR(CT_INFO) #define COLOR_SCHED COLOR_PAIR(CT_SCHEDULE) #define COLOR_PIPE COLOR_PAIR(CT_PIPE) #define PERCENT_COL (coor.coor[WINFO].cols-7) #define deadline_close(deadline) ((deadline.valid()) && \ (deadline.daysLeft() <= config.getDaysWarn())) #define isCollapse(todo) ((todo.getCollapse()) && (!todo.actCollapse())) Screen::Screen(Config &c): config(c) { /* * Initialize ncurses */ setlocale(LC_ALL, ""); initscr (); if (has_colors()) { start_color(); if (can_change_color()) { color_t* color_list; short int length; config.getColorList(&color_list, length); for (short int i=0; i NUM_CT) { short int foreground, background; use_default_colors(); config.getColorPair(CT_DEFAULT, foreground, background); assume_default_colors(foreground, background); for (short int i=1; i_addch(' '); action_list list; config.getActionList(list); wstring help_bar = L" " + list[L"quit"] + L":quit " + \ list[L"up"] + L":up " + list[L"down"] + L":down " + \ list[L"out"] + L":out " + list[L"in"] + L":in " + \ list[L"done"] + L":done " + list[L"addTodo"] + L":add " + \ list[L"editTitle"] + L":modify"; whelp->_move(0,0); whelp->_addstr(help_bar); whelp->_move(0, c.cols-8); wstring more_help = list[L"help"] + L":help"; whelp->_addstr(more_help); whelp->_refresh(); } void Screen::draw() { int lines, cols; /* get size of windows */ getmaxyx(stdscr, lines, cols); config.genWindowCoor(lines, cols, coor); /* create windows */ wtree = new Window(coor.coor[WTREE]); if (coor.exist[WHELP]) { whelp = new Window(coor.coor[WHELP]); whelp->_attron(COLOR_HELP); draw_helpbar(coor.coor[WHELP]); } else whelp = NULL; if (coor.exist[WPRIORITY]) wpriority = new Window(coor.coor[WPRIORITY]); else wpriority = NULL; if (coor.exist[WCATEGORY]) wcategory = new Window(coor.coor[WCATEGORY]); else wcategory = NULL; if (coor.exist[WDEADLINE]) wdeadline = new Window(coor.coor[WDEADLINE]); else wdeadline = NULL; if (coor.exist[WTEXT]) wtext = new Window(coor.coor[WTEXT]); else wtext = NULL; if (coor.exist[WINFO]) winfo = new Window(coor.coor[WINFO]); else winfo = NULL; if (coor.exist[WSCHEDULE]) wschedule = new Window(coor.coor[WSCHEDULE]); else wschedule = NULL; /* draw pipes */ for (vector::iterator i = coor.vpipe.begin(); i != coor.vpipe.end(); i++) { pipes.push_back(new Window(*i)); pipes.back()->_attron(COLOR_PIPE); pipes.back()->_move(0,0); pipes.back()->_vline('|', i->lines); pipes.back()->_refresh(); } for (vector::iterator i = coor.hpipe.begin(); i != coor.hpipe.end(); i++) { pipes.push_back(new Window(*i)); pipes.back()->_attron(COLOR_PIPE); pipes.back()->_move(0,0); pipes.back()->_hline('-', i->cols); pipes.back()->_refresh(); } } wstring Screen::date2str(Date& date) { wchar_t str[11]; if (config.useUSDates()) { swprintf(str, 11, L"%2d/%2d/%4d", date.month(), date.day(), date.year()); } else { swprintf(str, 11, L"%2d/%2d/%4d", date.day(), date.month(), date.year()); } return wstring(str); } Date Screen::str2date(wstring str) { string date(str.length(), L' '); copy(str.begin(), str.end(), date.begin()); int day, month; int year = atoi(date.substr(6,4).c_str()); if (config.useUSDates()) { month = atoi(date.substr(0,2).c_str()); day = atoi(date.substr(3,2).c_str()); } else { day = atoi(date.substr(0,2).c_str()); month = atoi(date.substr(3,2).c_str()); } Date d(day, month, year); return d; } void Screen::resizeTerm() { int lines, cols; /* get new size of windows */ endwin(); refresh(); getmaxyx(stdscr, lines, cols); config.genWindowCoor(lines, cols, coor); /* * resize windows */ /* clean stdscr */ touchwin(stdscr); refresh(); /* tree */ window_coor c = coor.coor[WTREE]; wtree->_resize(c.lines, c.cols); wtree->_mv(c.y, c.x); wtree->_erase(); /* help */ c = coor.coor[WHELP]; if (coor.exist[WHELP]) { whelp->_resize(c.lines, c.cols); whelp->_mv(c.y, c.x); whelp->_erase(); whelp->_move(0,0); draw_helpbar(c); } /* priority */ c = coor.coor[WPRIORITY]; if (coor.exist[WPRIORITY]) { wpriority->_resize(c.lines, c.cols); wpriority->_mv(c.y, c.x); wpriority->_erase(); } /* category */ c = coor.coor[WCATEGORY]; if (coor.exist[WCATEGORY]) { wcategory->_resize(c.lines, c.cols); wcategory->_mv(c.y, c.x); wcategory->_erase(); } /* deadline */ c = coor.coor[WDEADLINE]; if (coor.exist[WDEADLINE]) { wdeadline->_resize(c.lines, c.cols); wdeadline->_mv(c.y, c.x); wdeadline->_erase(); } /* deadline */ c = coor.coor[WTEXT]; if (coor.exist[WTEXT]) { wtext->_resize(c.lines, c.cols); wtext->_mv(c.y, c.x); wtext->_erase(); } /* info */ c = coor.coor[WINFO]; if (coor.exist[WINFO]) { winfo->_resize(c.lines, c.cols); winfo->_mv(c.y, c.x); winfo->_erase(); } /* schedule */ c = coor.coor[WSCHEDULE]; if (coor.exist[WSCHEDULE]) { wschedule->_resize(c.lines, c.cols); wschedule->_mv(c.y, c.x); wschedule->_erase(); } /* draw pipes */ vector::iterator win = pipes.begin(); for (vector::iterator i = coor.vpipe.begin(); i != coor.vpipe.end(); i++) { (*win)->_resize(i->lines, i->cols); (*win)->_mv(i->y, i->x); (*win)->_erase(); (*win)->_move(0,0); (*win)->_vline('|', i->lines); (*win)->_refresh(); win++; } for (vector::iterator i = coor.hpipe.begin(); i != coor.hpipe.end(); i++) { (*win)->_resize(i->lines, i->cols); (*win)->_mv(i->y, i->x); (*win)->_erase(); (*win)->_move(0,0); (*win)->_hline('-', i->cols); (*win)->_refresh(); win++; } } int Screen::startTitle(int depth) { return depth * 4 + 7; } void Screen::drawTitle(int line, int depth, wstring& title, int startLine) { int lines, cols; wtree->_getmaxyx(lines, cols); const unsigned int title_cols = wcswidth(title.c_str(), string::npos); const unsigned int line_cols = cols-startTitle(depth); const unsigned int title_lines = (title_cols && !(title_cols % line_cols)) ? (title_cols / line_cols)-1 : (title_cols / line_cols); int c = 0; for (unsigned int i = 0; i <= title_lines; i++) { if ((int)(line + i) >= lines) break; if ((int)i < startLine) { for (unsigned int col = 0; col < line_cols; c++) { col += wcwidth(title[c]); } continue; } wstring titleLine = title.substr(c, line_cols); c += wtree->_addstr(line + i, startTitle(depth), titleLine, line_cols); } } void Screen::drawTask(int line, int depth, ToDo& t, bool isCursor) { child_info chinf = t.getChildInfo(); if (isCursor) wtree->_attron(COLOR_SELECTED); else wtree->_attron(COLOR_TREE); wtree->_move(line, 0); /* identation */ for (int i = 0; i < depth; ++i) wtree->_addstr(L" "); if (config.getVisualTree()) if (t.haveChild()) { if ((!t.actCollapse()) && (t.getCollapse())) wtree->_addstr("(+)"); else wtree->_addstr("(-)"); } else wtree->_addstr(" "); else wtree->_addstr(" "); if (t.done()) { wtree->_addstr("[X] "); } else if (!t.haveChild() || config.getHidePercent()) { wtree->_addstr("[ ] "); } else if (100 == chinf.percent) { wtree->_addstr("100 "); } else { char str[8]; sprintf(str, "%2d%% ", chinf.percent); wtree->_addstr(str); } /* add the title split to the length of screen */ if ((t.haveChild()) && (config.getBoldParent())) wtree->_attron(A_BOLD); wstring title = t.getTitle(); drawTitle(line, depth, title); if ((t.haveChild()) && (config.getBoldParent())) wtree->_attroff(A_BOLD); if (isCursor) wtree->_attroff(COLOR_SELECTED); else wtree->_attroff(COLOR_TREE); wtree->_refresh(); /* draw priority */ if (coor.exist[WPRIORITY]) { int priority = t.priority(); if (isCursor) wpriority->_attron(COLOR_SELECTED); else wpriority->_attron(COLOR_TREE); if (priority) { char s[11]; wpriority->_move(line, 0); sprintf(s, "%01d", priority); wpriority->_addstr(s); } if (isCursor) wpriority->_attroff(COLOR_SELECTED); else wpriority->_attroff(COLOR_TREE); wpriority->_refresh(); } /* draw category */ if (coor.exist[WCATEGORY]) { wstring category = t.getCategoriesStr(); if (isCursor) wcategory->_attron(COLOR_SELECTED); else wcategory->_attron(COLOR_TREE); if (!category.empty()) { wcategory->_move(line, 0); wcategory->_addstr(category, config.getCategoryLength()); } if (isCursor) wcategory->_attroff(COLOR_SELECTED); else wcategory->_attroff(COLOR_TREE); wcategory->_refresh(); } /* draw date */ if (coor.exist[WDEADLINE]) { if (isCursor) wdeadline->_attron(COLOR_SELECTED); else wdeadline->_attron(COLOR_TREE); Date& deadline = t.deadline(); if (deadline.valid()) { wdeadline->_move(line, 0); wstring str = date2str(deadline); wdeadline->_addstr(str); } wdeadline->_move(line, 10); if ((!t.done() && deadline_close(deadline)) || (isCollapse(t) && deadline_close(chinf.deadline))) { wdeadline->_attron(COLOR_WARN); wdeadline->_addstr("<-"); wdeadline->_attroff(COLOR_WARN); } else { wdeadline->_addstr(" "); } if (isCursor) wdeadline->_attroff(COLOR_SELECTED); else wdeadline->_attroff(COLOR_TREE); wdeadline->_refresh(); } } void Screen::drawText(Text &t) { if (!coor.exist[WTEXT]) return; wtree->_attron(COLOR_TEXT); wtext->_erase(); t.print(*wtext); wtree->_attroff(COLOR_TEXT); } void Screen::drawSched(Sched &sched, pToDo cursor) { if (!coor.exist[WSCHEDULE]) return; Date today; today.setToday(); sched_l sched_list; if (config.getOldSched()) sched.get(sched_list); else sched.get(today,sched_list); Date last; int line = 0; wschedule->_erase(); wschedule->_move(0,0); for (sched_l::iterator i = sched_list.begin(); (i != sched_list.end()) && (line < coor.coor[WSCHEDULE].lines); i++) { if (today > (*i)->sched()) wschedule->_attron(COLOR_WARN); else wschedule->_attron(COLOR_SCHED); if ((*i)->done()) continue; if ((*i)->sched() != last) { if (line+2 > coor.coor[WSCHEDULE].lines) break; last = (*i)->sched(); wostringstream ss; ss << " " << date2str(last) << endl; wstring str = ss.str(); wschedule->_attron(A_BOLD); wschedule->_addstr(str); wschedule->_attroff(A_BOLD); line++; } if (cursor == (*i)) wschedule->_attron(COLOR_SELECTED); wschedule->_addstr(" "); wstring title = (*i)->getTitle(); int printed_chars = wschedule->_addstr(title, coor.coor[WSCHEDULE].cols-4); if ((int)title.length() == printed_chars) wschedule->_addstr("\n"); line++; } wschedule->_refresh(); } void Screen::scrollUpText(Text& t) { if (!coor.exist[WTEXT]) return; wtree->_attron(COLOR_TEXT); t.scroll_up(*wtext); wtree->_attroff(COLOR_TEXT); } void Screen::scrollDownText(Text& t) { if (!coor.exist[WTEXT]) return; wtree->_attron(COLOR_TEXT); t.scroll_down(*wtext); wtree->_attroff(COLOR_TEXT); } void Screen::deadlineClear(int line) { if (!coor.exist[WDEADLINE]) return; wdeadline->_attron(COLOR_TREE); wdeadline->_move(line, 0); wdeadline->_addstr(" "); wdeadline->_refresh(); wdeadline->_attroff(COLOR_TREE); } void Screen::priorityClear(int line) { if (coor.exist[WPRIORITY]) { wpriority->_attron(COLOR_TREE); wpriority->_move(line, 0); wpriority->_addstr(" "); wpriority->_refresh(); wpriority->_attroff(COLOR_TREE); } } Editor::return_t Screen::editTitle(int line, int depth, bool haveChild, wstring& str, int cursorPos) { Editor::return_t save; wtree->_attron(COLOR_SELECTED); if ((haveChild) && (config.getBoldParent())) wtree->_attron(A_BOLD); titleEditor.getText() = str; if (cursorPos >= 0) titleEditor.cursorPos() = cursorPos; save = titleEditor.edit(*wtree, line, startTitle(depth), coor.coor[WTREE].cols-startTitle(depth)); if (save == Editor::NOT_SAVED) { drawTitle(line, depth, str); for (int i = startTitle(depth) + (str.length()-1 % coor.coor[WTREE].cols); i < coor.coor[WTREE].cols-1; i++) wtree->_addch(' '); wtree->_refresh(); } str = titleEditor.getText(); if ((haveChild) && (config.getBoldParent())) wtree->_attroff(A_BOLD); wtree->_attroff(COLOR_SELECTED); return save; } void Screen::editText(Text& t) { if (!coor.exist[WTEXT]) return; wtree->_attron(COLOR_TEXT); t.edit(*wtext); wtree->_attroff(COLOR_TEXT); } Editor::return_t Screen::editDeadline(int line, Date& deadline, bool done, int cursorPos) { if (!coor.exist[WDEADLINE]) return Editor::NOT_SAVED; Editor::return_t save; wstring date; if (deadline.valid()) { date = date2str(deadline); } else { Date d; d.setToday(); date = date2str(d); } wdeadline->_attron(COLOR_SELECTED); dateEditor.getText() = date; if (cursorPos >= 0) dateEditor.cursorPos() = cursorPos; save = dateEditor.edit(*wdeadline, line, 0); deadline = str2date(dateEditor.getText()); wdeadline->_attroff(COLOR_SELECTED); return save; } Editor::return_t Screen::editSched(Date& s, int cursorPos) { if (!coor.exist[WSCHEDULE]) return Editor::NOT_SAVED; wstring date; Editor::return_t save; wschedule->_attron(COLOR_SCHED); wschedule->_attron(A_BOLD); wschedule->_addstr(coor.coor[WSCHEDULE].lines-1, 0, " Edit schedule: "); wschedule->_attroff(A_BOLD); wschedule->_refresh(); /* if is not valid date use today date */ if (s.valid()) { date = date2str(s); } else { Date d; d.setToday(); date = date2str(d); } /* edit and store */ dateEditor.getText() = date; if (cursorPos >= 0) dateEditor.cursorPos() = cursorPos; save = dateEditor.edit(*wschedule, coor.coor[WSCHEDULE].lines-1, 18); s = str2date(dateEditor.getText()); return save; } Editor::return_t Screen::setPriority(int line, int& priority) { if (!coor.exist[WPRIORITY]) return Editor::NOT_SAVED; wchar_t p[2] = L"N"; if (priority) swprintf(p, 2, L"%01d", priority); Editor::return_t save; wpriority->_attron(COLOR_SELECTED); priorityEditor.getText() = p; save = priorityEditor.edit(*wpriority, line, 0); char num[2]; wcstombs(num, priorityEditor.getText().c_str(), 2); priority = atoi(num); wpriority->_attroff(COLOR_SELECTED); return save; } Editor::return_t Screen::setCategory(int line, wstring& category, int cursorPos) { if (!coor.exist[WCATEGORY]) return Editor::NOT_SAVED; Editor::return_t save; wcategory->_attron(COLOR_SELECTED); categoryEditor.getText() = category; if (cursorPos >= 0) categoryEditor.cursorPos() = cursorPos; save = categoryEditor.edit(*wcategory, line, 0, config.getCategoryLength()); category = categoryEditor.getText(); wcategory->_attroff(COLOR_SELECTED); return save; } void Screen::treeClear() { wtree->_erase(); wtree->_move(0,0); wtree->_refresh(); if (coor.exist[WPRIORITY]) { wpriority->_move(0,0); wpriority->_erase(); wpriority->_refresh(); } if (coor.exist[WCATEGORY]) { wcategory->_erase(); wcategory->_move(0,0); wcategory->_refresh(); } if (coor.exist[WDEADLINE]) { wdeadline->_erase(); wdeadline->_move(0,0); wdeadline->_refresh(); } } int Screen::treeLines() { return wtree->_lines(); } int Screen::taskLines(int depth, ToDo &t) { unsigned int title_cols = wcswidth(t.getTitle().c_str(), string::npos); if (title_cols==(unsigned int)-1) // nonprintable wide character occurs among these characters title_cols=0; int title_lines = (title_cols / (coor.coor[WTREE].cols-startTitle(depth))) + 1; if (title_cols && !(title_cols % (coor.coor[WTREE].cols-startTitle(depth)))) title_lines -= 1; return title_lines; } Editor::return_t Screen::searchText(wstring& pattern, int cursorPos) { if (!coor.exist[WINFO]) return Editor::NOT_SAVED; Editor::return_t save; infoClear(); winfo->_addch(0,0,'/'); searchEditor.getText() = pattern; if (cursorPos >= 0) searchEditor.cursorPos() = cursorPos; save = searchEditor.edit(*winfo, 0, 1, PERCENT_COL-2); pattern = searchEditor.getText(); infoClear(); return save; } Editor::return_t Screen::cmd(wstring& command, int cursorPos) { if (!coor.exist[WINFO]) return Editor::NOT_SAVED; Editor::return_t save; infoClear(); winfo->_addch(0,0,':'); cmdEditor.getText() = command; if (cursorPos >= 0) cmdEditor.cursorPos() = cursorPos; save = cmdEditor.edit(*winfo, 0, 1, PERCENT_COL-2); command = cmdEditor.getText(); infoClear(); return save; } bool Screen::confirmQuit() { infoClear(); winfo->_addstr(0,0,"Close without save? (y/n) "); wint_t ch = 'N'; winfo->_getch(ch); infoClear(); if (('Y' == ch) || ('y' == ch)) return true; else return false; } void Screen::infoMsg(const char str[]) { if (!coor.exist[WINFO]) return; winfo->_attron(COLOR_INFO); infoClear(); winfo->_addstr(0,0,str); winfo->_refresh(); winfo->_attroff(COLOR_INFO); } void Screen::infoClear() { if (!coor.exist[WINFO]) return; winfo->_attron(COLOR_INFO); winfo->_move(0,0); for (int i = 0; i < COLS-15; ++i) { winfo->_addch(' '); } winfo->_refresh(); winfo->_attroff(COLOR_INFO); } void Screen::infoPercent(int percent) { if (!coor.exist[WINFO]) return; winfo->_attron(COLOR_INFO); char str[8]; sprintf(str, "(%3d%%)", percent); winfo->_addstr(0,PERCENT_COL,str); winfo->_refresh(); winfo->_attroff(COLOR_INFO); } #define draw_help() \ do { \ h._erase(); \ h._move(0,0); \ for (int i = cursor; (i<=len) && (i-cursor 0) { --cursor; draw_help(); } break; case KEY_NPAGE: case ' ': cursor += lines; if (cursor > len-lines) { cursor = len + 1 - lines; if (cursor < 0) cursor = 0; } draw_help(); break; case KEY_PPAGE: case 'b': cursor -= lines; if (cursor < 0) cursor = 0; draw_help(); break; case KEY_HOME: case '<': case 'g': cursor = 0; draw_help(); break; case KEY_END: case '>': case 'G': cursor = len + 1 - lines; draw_help(); break; case 'q': close = true; break; default: ; } } if (resized) ungetch(KEY_RESIZE); h._erase(); /* redraw everything, removing the help window */ redrawwin(stdscr); refresh(); wtree->_redraw(); wtree->_refresh(); if (coor.exist[WHELP]) { whelp->_redraw(); whelp->_refresh(); } if (coor.exist[WPRIORITY]) { wpriority->_redraw(); wpriority->_refresh(); } if (coor.exist[WCATEGORY]) { wcategory->_redraw(); wcategory->_refresh(); } if (coor.exist[WDEADLINE]) { wdeadline->_redraw(); wdeadline->_refresh(); } if (coor.exist[WTEXT]) { wtext->_redraw(); wtext->_refresh(); } if (coor.exist[WINFO]) { winfo->_redraw(); winfo->_refresh(); } if (coor.exist[WSCHEDULE]) { wschedule->_redraw(); wschedule->_refresh(); } for (vector::iterator i = pipes.begin(); i != pipes.end(); i++) { (*i)->_redraw(); (*i)->_refresh(); } } tudu-0.10.2/src/data.h0000644000175000017500000000663513121017272013150 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #ifndef DATA_H #define DATA_H #include "includes.h" class ToDo; class iToDo; typedef ToDo* pToDo; typedef list::iterator cursor_t; #include "text.h" #include "date.h" extern set categories; #define NONE_CATEGORY L"NONE" struct child_info { int percent; Date deadline; }; /* * Compare function for sort */ bool cmp(pToDo t1, pToDo t2); class ToDo { public: ToDo(); ~ToDo(); wstring& getTitle(); Text& getText(); Date& deadline(); Date& sched(); int& schedPosition(); bool& done(); int& priority(); set& getCategories(); wstring getCategoriesStr(); void addCategory(const wstring& c); void setCategories(set& c); void setCategoriesStr(wstring& c); bool haveChild(); child_info getChildInfo(); bool& getCollapse(); // real collapse bool& actCollapse(); // if must be collapse now protected: int _order; // unic number that shows the order of the todo wstring title; bool _done; Date _deadline; Date _sched; int sched_position; // position on the sched list, use for sort the list int _priority; set _category; Text text; list childs; bool collapse; //real param bool cursor_in; //if the cursor is inside, use for actCollapse void _sort(); // sort the children with given order friend class iToDo; friend bool cmp(pToDo , pToDo ); }; /* * Iterator for ToDo class */ class iToDo { public: iToDo(ToDo& t); iToDo& operator=(const iToDo& t); bool operator==(const iToDo& t); bool operator!=(const iToDo& t) { return !operator==(t); } bool operator++(); bool operator--(); bool in(); bool out(); void next(); void prev(); ToDo &operator*(); ToDo *operator->(); bool end(); bool begin(); int percentUp(); void addChild(pToDo p); void addChildUp(pToDo p); void del(); int depth(); /* * sort all the todo with given order * t = title * d = done * l = deadline * p = priority * c = category * e = percent * u = user * the same leters in capital are for inverse order */ void sort(wstring order); bool search(wstring& str); bool searchUp(wstring& str); protected: pToDo root; stack::iterator> path; stack parents; cursor_t cursor; }; #endif tudu-0.10.2/src/cmd.h0000644000175000017500000000350113121017272012767 0ustar useruser/************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #ifndef CMD_H #define CMD_H #include "includes.h" class Cmd; #include "interface.h" #include "data.h" /* comands definition with it's params types */ extern map commands; class Cmd { public: Cmd(); void get_interface(Interface *i); bool cmd(wstring command); /* return if should be redraw the screen */ private: Interface *interface; void hide(vector ¶ms); void show(vector ¶ms); void showall(vector ¶ms); void showonly(vector ¶ms); void help(vector ¶ms); }; #endif tudu-0.10.2/src/Makefile.acr0000644000175000017500000000116613121017272014264 0ustar useruserVPATH=@VPATH@ PKGNAME=@PKGNAME@ VERSION=@VERSION@ INSTALL_PROGRAM=@INSTALL_PROGRAM@ .PHONY: all install uninstall clean mrproper CXX=@CXX@ CXXFLAGS=@CXXFLAGS@ CPPFLAGS=@CPPFLAGS@ LDFLAGS=@LDFLAGS@ SRCS=@SRCS@ prefix=@PREFIX@ BINDIR?=@BINDIR@ OBJS=$(SRCS:.cc=.o) all: $(PKGNAME) $(PKGNAME): $(OBJS) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ $(OBJS) $(LDFLAGS) .cc.o: $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c $< install: all mkdir -p $(DESTDIR)$(BINDIR) $(INSTALL_PROGRAM) $(PKGNAME) $(DESTDIR)$(BINDIR) clean: @rm -f $(PKGNAME) $(OBJS) core tags mrproper: clean rm Makefile defs.h uninstall: rm $(DESTDIR)$(BINDIR)/$(PKGNAME) tudu-0.10.2/src/parser.cc0000644000175000017500000002063313121017272013663 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #include "parser.h" Parser::Parser(const char* path) { file.imbue(locale("")); file.open(path); } Parser::~Parser() { file.close(); } bool Parser::parse(ToDo& todo, Sched& sched) { wchar_t ch; bool tag = false, att = false; iToDo iterator(todo); if (!file) return false; //if the file is not open str = L""; collect_text = false; deadline = false; scheduled = false; while (file.get(ch)) { switch (ch) { case L'<': if (tag) return false; tag = true; if (collect_text) { txt = str; str = L""; } else collect_text = true; break; case L'>': if (!tag) return false; tag = false; collect_text = false; if (!att) ptag(iterator,sched); else { patt(iterator); att = false; } str = L""; break; case L'\t': case L' ': if (tag) { if (!att) { ptag(iterator,sched); att = true; str = L""; } else if (str.length()) { patt(iterator); str = L""; } } else if (collect_text) str += ch; break; case L'&': if (collect_text) str += amp(); break; default: if (collect_text) str += ch; } } // in case of empty file create an empty task if (!todo.haveChild()) iterator.addChild(new ToDo()); return true; } wchar_t Parser::amp() { wchar_t ch; wstring str = L""; file.get(ch); while (L';' != ch) { str += ch; file.get(ch); } if (L"amp" == str) return L'&'; if (L"lt" == str) return L'<'; if (L"gt" == str) return L'>'; else return L' '; } void Parser::ptag(iToDo& iterator, Sched& sched) { static bool first_todo = true; if (L"todo" == str) { if (first_todo) first_todo = false; else { iterator.addChild(new ToDo()); iterator.in(); } } if (L"/todo" == str) { iterator.out(); } if (L"title" == str) { collect_text = true; } if (L"/title" == str) { iterator->getTitle() = txt; } if (L"deadline" == str) { deadline = true; } if (L"/deadline" == str) { deadline = false; } if (L"day" == str) { collect_text = true; } if (L"/day" == str) { char num[3]; wcstombs(num, txt.c_str(), 3); int day = atoi(num); if (deadline) { iterator->deadline().day() = day; } else if (scheduled) iterator->sched().day() = day; } if (L"month" == str) { collect_text = true; } if (L"/month" == str) { char num[3]; wcstombs(num, txt.c_str(), 3); int month = atoi(num); if (deadline) { iterator->deadline().month() = month; } else if (scheduled) iterator->sched().month() = month; } if (L"year" == str) { collect_text = true; } if (L"/year" == str) { char num[5]; wcstombs(num, txt.c_str(), 5); int year = atoi(num); if (deadline) { iterator->deadline().year() = year; } else if (scheduled) iterator->sched().year() = year; } if (L"position" == str) { collect_text = true; } if (L"/position" == str) { char num[8]; wcstombs(num, txt.c_str(), 8); iterator->schedPosition() = atoi(num); } if (L"priority" == str) { collect_text = true; } if (L"/priority" == str) { char num[2]; wcstombs(num, txt.c_str(), 2); iterator->priority() = atoi(num); } if (L"category" == str) { collect_text = true; } if (L"/category" == str) { iterator->addCategory(txt); } if (L"text" == str) { collect_text = true; } if (L"/text" == str) { if (L'\n' == txt[0]) txt.erase(0,1); iterator->getText() = txt; } if (L"scheduled" == str) { scheduled = true; } if (L"/scheduled" == str) { if (iterator->sched().valid()) sched.add(&(*iterator)); scheduled = false; } } void Parser::patt(iToDo& iterator) { wstring name, data; int eq_pos = str.find(L"="); name = str.substr(0, eq_pos); eq_pos++; data = str.substr(eq_pos, str.length()-eq_pos); if (L"done" == name) { if (L"\"yes\"" == data) iterator->done() = true; else iterator->done() = false; } else if (L"collapse" == name) { if (L"\"yes\"" == data) iterator->getCollapse() = true; else iterator->getCollapse() = false; } } Writer::Writer(const char* pathToSave, ToDo& t): todo(t) { strncpy(path, pathToSave, 128); path[128] = '\0'; file.imbue(locale("")); } Writer::~Writer() {} bool Writer::save() { file.open(path); file << "" << endl; /* there was an error writing */ if (file.fail()) return false; file << "" << endl; file << "" << endl; i = new iToDo(todo); i->sort(L""); while(--(*i)); _save(); delete i; file << "" << endl; file.close(); return true; } #define putTabs(num) \ for (int j = 0; j < num+1; j++) file << "\t" void Writer::_save() { for (; !((*i).end()); ++(*i)) { putTabs((*i).depth()); file << "done()) file << "yes"; else file << "no"; file << "\" collapse=\""; if ((*i)->getCollapse()) file << "yes"; else file << "no"; file << "\">" << endl; if (L"" != (*i)->getTitle()) { wstring str = (*i)->getTitle(); putTabs((*i).depth()+1); amp(str); file << "" << str << "" << endl; } if ((*i)->deadline().valid()) { Date &date = (*i)->deadline(); putTabs((*i).depth()+1); file << "" << endl; putTabs((*i).depth()+2); file << "" << date.day() << "" << endl; putTabs((*i).depth()+2); file << "" << date.month() << "" << endl; putTabs((*i).depth()+2); char str[10]; /* fixing problem with locales that prints 2,010 */ sprintf(str,"%i",date.year()); file << "" << str << "" << endl; putTabs((*i).depth()+1); file << "" << endl; } if ((*i)->priority()) { putTabs((*i).depth()+1); file << "" << (*i)->priority() << "" << endl; } if (!(*i)->getCategories().empty()) { for (set::iterator it = (*i)->getCategories().begin(); it != (*i)->getCategories().end(); it++) { putTabs((*i).depth()+1); file << "" << *it << "" << endl; } } if ((*i)->getText() != L"") { wstring str = (*i)->getText().getStr(); putTabs((*i).depth()+1); amp(str); file << "" << str; file << "" << endl; } if ((*i)->sched().valid()) { Date &date = (*i)->sched(); putTabs((*i).depth()+1); file << "" << endl; putTabs((*i).depth()+2); file << "" << date.day() << "" << endl; putTabs((*i).depth()+2); file << "" << date.month() << "" << endl; putTabs((*i).depth()+2); char str[10]; /* fixing problem with locales that prints 2,010 */ sprintf(str,"%i",date.year()); file << "" << str << "" << endl; putTabs((*i).depth()+2); file << "" << (*i)->schedPosition() << "" << endl; putTabs((*i).depth()+1); file << "" << endl; } (*i).in(); _save(); (*i).out(); putTabs((*i).depth()); file << "" << endl; } } #define replace(orig, alt) \ { \ index = 0; \ while ((index = str.find(orig,index)) != wstring::npos) \ { \ str.erase(index,1); \ str.insert(index, alt); \ index += 4; \ } \ } while (0) void Writer::amp(wstring& str) { wstring::size_type index; replace(L'&', L"&"); replace(L'<', L"<"); replace(L'>', L">"); } tudu-0.10.2/src/sched.cc0000644000175000017500000000715613121017272013462 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #include "sched.h" /* * when del don't update the position of the neighbours * because when paste it use the last position */ void Sched::add_recursive(pToDo todo) { for (iToDo j(*todo) ; !j.end(); ++j) add_recursive(&(*j)); if (todo->sched().valid()) add(todo); } void Sched::add(pToDo todo) { sched_l::iterator i; for (i = sched.begin(); (i != sched.end()) && ((*i)->sched() < todo->sched()); i++); if (todo->schedPosition() == 0) { if ((i != sched.end()) && ((*i)->sched() == todo->sched())) { for (; ((*i)->sched() == todo->sched()); i++); i--; todo->schedPosition() = (*i)->schedPosition() + 1; i++; } else { todo->schedPosition() = 1; } } else { for (; (i != sched.end()) && ((*i)->sched() == todo->sched()) && ((*i)->schedPosition() < todo->schedPosition()); i++); } sched.insert(i, todo); } void Sched::up(pToDo todo) { sched_l::iterator i,j; for (i = sched.begin(); (i != sched.end()) && ((*i) != todo); i++); j = i; j--; /* if there is a task before swap them */ if ((i != sched.begin()) && ((*i) == todo) && ((*j)->sched() == todo->sched())) { int aux = (*j)->schedPosition(); (*j)->schedPosition() = todo->schedPosition(); todo->schedPosition() = aux; sched.insert(j, todo); j = i; i++; sched.erase(j,i); } } void Sched::down(pToDo todo) { sched_l::iterator i,j; for (i = sched.begin(); (i != sched.end()) && ((*i) != todo); i++); j = i; j++; /* if there is a task before swap them */ if ((j != sched.end()) && ((*i) == todo) && ((*j)->sched() == todo->sched())) { sched.erase(i,j); int aux = (*j)->schedPosition(); (*j)->schedPosition() = todo->schedPosition(); todo->schedPosition() = aux; j++; sched.insert(j, todo); } } void Sched::del(pToDo todo) { sched.remove(todo); } void Sched::del_recursive(pToDo todo) { for (iToDo i(*todo) ; !i.end(); ++i) del_recursive(&(*i)); sched.remove(todo); } int Sched::get(sched_l& list) { sched_l::iterator i; int num_scheds = 0; list.clear(); for (i = sched.begin(); (i != sched.end()); i++) { num_scheds++; list.push_back(*i); } return num_scheds; } int Sched::get(Date& from, sched_l& list) { sched_l::iterator i; int num_scheds = 0; list.clear(); for (i = sched.begin(); (i != sched.end()) && ((*i)->sched() < from); i++); for (; i != sched.end(); i++) { num_scheds++; list.push_back(*i); } return num_scheds; } tudu-0.10.2/src/interface.cc0000644000175000017500000005701513121017272014333 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #include "interface.h" #define isCollapse() ((cursor->getCollapse()) && (!cursor->actCollapse())) Interface::Interface(Screen &s, iToDo &t, Sched& sch, Config &c, Writer &w, Cmd &com) : screen(s), cursor(t), sched(sch), config(c), writer(w), copied(NULL), cmd(com) { cmd.get_interface(this); search_pattern = L""; sortOrder = config.getSortOrder(); cursor.sort(sortOrder); while (prev()); cursor_line = 0; } Interface::~Interface() { delete copied; } void Interface::main() { wint_t key; wstring action; while (cursor.out()); while (--cursor); drawTodo(); while (true) { if (get_wch(&key) == KEY_CODE_YES) { screen.infoClear(); if (KEY_RESIZE == key) resizeTerm(); if (KEY_LEFT == key) left(); if (KEY_RIGHT == key) right(); if (KEY_DOWN == key) down(); if (KEY_UP == key) up(); if (KEY_PPAGE == key) prevPage(); if (KEY_NPAGE == key) nextPage(); if (KEY_HOME == key) home(); if (KEY_END == key) end(); if (KEY_SF == key) move_down(); // shift+down if (KEY_SR == key) move_up(); // shift+up config.clearKeys(); } else if (0xc == key) // Ctrl-L { resizeTerm(); } else if (config.getAction(key, action)) { screen.infoClear(); if (L"quit" == action) { if (writer.save()) break; else screen.infoMsg("File can not be saved"); } if (L"quitNoSave" == action) if (screen.confirmQuit()) break; if (L"out" == action) left(); if (L"in" == action) right(); if (L"down" == action) down(); if (L"up" == action) up(); if (L"move_down" == action) move_down(); if (L"move_up" == action) move_up(); if (L"delete" == action) del(); if (L"delDeadline" == action) delDeadline(); if (L"delPriority" == action) delPriority(); if (L"delSched" == action) delSched(); if (L"paste" == action) paste(); if (L"pasteUp" == action) pasteUp(); if (L"pasteChild" == action) pasteChild(); if (L"done" == action) done(); if (L"addTodo" == action) addLine(); if (L"addTodoUp" == action) addLineUp(); if (L"editTitle" == action) modifyLine(); if (L"editDeadline" == action) editDeadline(); if (L"setPriority" == action) setPriority(); if (L"setCategory" == action) setCategory(); if (L"editText" == action) editText(); if (L"editSched" == action) editSched(); if (L"schedUp" == action) schedUp(); if (L"schedDown" == action) schedDown(); if (L"downText" == action) downText(); if (L"upText" == action) upText(); if (L"collapse" == action) collapse(); if (L"hideDone" == action) hide_done(); if (L"search" == action) search(); if (L"searchNext" == action) search_next(); if (L"searchPrev" == action) search_prev(); if (L"cmd" == action) command_line(); if (L"sortByTitle" == action) sortByTitle(); if (L"sortByDone" == action) sortByDone(); if (L"sortByDeadline" == action) sortByDeadline(); if (L"sortByPriority" == action) sortByPriority(); if (L"sortByCategory" == action) sortByCategory(); if (L"sortByUser" == action) sortByUser(); if (L"sortRevTitle" == action) sortRevTitle(); if (L"sortRevDone" == action) sortRevDone(); if (L"sortRevDeadline" == action) sortRevDeadline(); if (L"sortRevPriority" == action) sortRevPriority(); if (L"sortRevCategory" == action) sortRevCategory(); if (L"sortRevUser" == action) sortRevUser(); if (L"save" == action) save(); if (L"help" == action) help(); } else if (key==' ') done(); } } void Interface::resizeTerm() { screen.resizeTerm(); drawTodo(); } void Interface::drawTodo() { screen.treeClear(); cursor.sort(sortOrder); /* if there is no task to display create a dummy one */ if (isHide(cursor) && !prev() && !next()) { while (cursor.out()); cursor.addChildUp(new ToDo()); inherit(); cursor_line = 0; } /* get the percent done of the whole tree */ iToDo aux = cursor; while (cursor.out()); while (--cursor); screen.infoPercent(cursor.percentUp()); cursor = aux; /* redraw screen */ fitCursor(); int line = cursor_line; while ((cursor_line > 0) && prev()); if (cursor_line < 0) { screen.drawTitle(cursor_line, cursor.depth(), cursor->getTitle(), -cursor_line); next(); } while (cursor_line < screen.treeLines()) { bool isCursor = (cursor == aux); screen.drawTask(cursor_line, cursor.depth(), *cursor, isCursor); if (isCursor) line = cursor_line; if (!next()) break; } cursor = aux; cursor_line = line; screen.drawText(cursor->getText()); screen.drawSched(sched, &(*cursor)); } bool Interface::next() { iToDo oldCursor = cursor; cursor_line += screen.taskLines(cursor.depth(), *cursor); do { if (!cursor.end() && !isCollapse()) cursor.in(); else if (!++cursor) { if (!cursor.out()) { cursor = oldCursor; cursor_line -= screen.taskLines(cursor.depth(), *cursor); return false; } ++cursor; } } while (isHide(cursor)); return true; } bool Interface::prev() { iToDo oldCursor = cursor; do { if (!--cursor) { if (!cursor.out()) { cursor = oldCursor; return false; } } else { while (cursor->haveChild() && !isCollapse()) { cursor.in(); while (++cursor); --cursor; } } } while (isHide(cursor)); cursor_line -= screen.taskLines(cursor.depth(), *cursor); return true; } void Interface::eraseCursor() { screen.drawTask(cursor_line, cursor.depth(), *cursor, false); } bool Interface::fitCursor() { bool needRedraw = false; int treeLines = screen.treeLines(); int taskLines = screen.taskLines(cursor.depth(), *cursor); iToDo task = cursor; /* keep the tree on the screen if it can fit there */ int line = cursor_line; while (prev()); int firstLine = cursor_line; iToDo firstTask = cursor; while (cursor_line < treeLines-5) if (!next()) break; if ((cursor_line < treeLines-5) || (firstLine > 0)) { cursor_line = 0; cursor = firstTask; needRedraw = true; while (cursor != task) next(); } else { cursor_line = line; cursor = task; } /* check if the task is out of the screen scroll */ if (taskLines > treeLines-8) { if (cursor_line + taskLines >= treeLines) { cursor_line = treeLines - taskLines; needRedraw = true; } else if (cursor_line < 0) { cursor_line = 0; needRedraw = true; } } else if (cursor_line + taskLines >= treeLines - 4) { int line = cursor_line; cursor_line = treeLines - taskLines - 4; if (cursor_line < 0) cursor_line = 0; if (cursor_line != line) needRedraw = true; } else if (cursor_line < 4) { int line = cursor_line; while (cursor_line > line - 4) if (!prev()) break; cursor_line = 0; while (task != cursor) next(); if (cursor_line != line) needRedraw = true; } return needRedraw; } void Interface::drawCursor() { if (fitCursor()) { drawTodo(); } else { screen.drawTask(cursor_line, cursor.depth(), *cursor, true); screen.drawText(cursor->getText()); screen.drawSched(sched, &(*cursor)); } } bool Interface::isHide(iToDo& todo) { if (todo.end()) return true; /* if is done */ bool hideDone = (config.getHideDone() && todo->done()); /* if is in hidden category */ bool hideCat = false; set& categories = todo->getCategories(); if (categories.empty() && hidden_categories.count(L"")) hideCat = true; for (set::iterator it = categories.begin(); it != categories.end(); it++) { if (!hidden_categories.count(*it)) { hideCat = false; break; } hideCat = true; } return hideDone || hideCat; } void Interface::inherit() { /* inherit category */ if (cursor.depth()) { iToDo father = cursor; father.out(); cursor->setCategories(father->getCategories()); } else if (hidden_categories.count(L"")) { set::iterator cat; for (cat = categories.begin(); (cat != categories.end()) && hidden_categories.count(*cat); cat++); if (cat != categories.end()) cursor->addCategory(*cat); else cursor->addCategory(NONE_CATEGORY); } } void Interface::left() { iToDo aux = cursor; while (aux.out() && isHide(aux)); if (!isHide(aux)) { eraseCursor(); while (aux != cursor) prev(); cursor->actCollapse() = false; if (cursor->getCollapse()) drawTodo(); else drawCursor(); } else if (isHide(cursor)) { prev(); drawTodo(); } } void Interface::right() { bool need_drawTodo = cursor->getCollapse(); eraseCursor(); cursor->actCollapse() = true; cursor_line += screen.taskLines(cursor.depth(), *cursor); cursor.in(); while (isHide(cursor) && ++cursor); if (cursor.end()) { cursor.addChild(new ToDo()); inherit(); drawTodo(); wstring title; if (editLine(title) && (title != L"")) { /* Use the config collapse */ cursor.out(); cursor->getCollapse() = config.getCollapse(); cursor.in(); } else { del(); } need_drawTodo = false; } if (need_drawTodo) drawTodo(); else drawCursor(); } void Interface::up() { iToDo aux = cursor; if (aux.begin() && config.getLoopMove()) while (++aux); while (--aux && isHide(aux)); if (!isHide(aux)) { eraseCursor(); while (aux != cursor) if (!prev()) break; while (aux != cursor) next(); drawCursor(); } else if (isHide(cursor)) { prev(); drawTodo(); } } void Interface::down() { iToDo aux = cursor; while (++aux) { if (aux.end() && config.getLoopMove()) while (--aux); if (!isHide(aux) || (aux == cursor)) break; } if (!isHide(aux)) { eraseCursor(); while (aux != cursor) if (!next()) break; while (aux != cursor) prev(); drawCursor(); } else if (isHide(cursor)) { prev(); drawTodo(); } } void Interface::prevPage() { int treeLines = screen.treeLines(); while (cursor_line >= 0) if (!prev()) break; iToDo aux = cursor; cursor_line = treeLines - 1; while (cursor_line >= 0) if (!prev()) break; cursor = aux; cursor_line = treeLines - cursor_line; drawTodo(); } void Interface::nextPage() { int treeLines = screen.treeLines(); eraseCursor(); while (cursor_line < treeLines) if (!next()) { drawCursor(); return; } iToDo aux = cursor; cursor_line = 0; while (cursor_line < treeLines) if (!next()) break; cursor = aux; cursor_line = treeLines - cursor_line; drawTodo(); } void Interface::home() { eraseCursor(); while (prev()); drawCursor(); } void Interface::end() { eraseCursor(); while (next()); drawCursor(); } void Interface::move_up() { pToDo t = &(*cursor); cursor.del(); eraseCursor(); --cursor; cursor_line -= screen.taskLines(cursor.depth(), *cursor); cursor.addChildUp(t); drawTodo(); } void Interface::move_down() { iToDo aux = cursor; ++aux; if (aux.end()) return; pToDo t = &(*cursor); cursor.del(); eraseCursor(); aux.addChild(t); while (aux != cursor) next(); drawTodo(); } void Interface::done() { if (cursor->done()) cursor->done() = false; else cursor->done() = true; if (isHide(cursor)) down(); drawTodo(); } void Interface::del() { if (copied) delete copied; copied = &(*cursor); sched.del_recursive(&(*cursor)); cursor.del(); up(); drawTodo(); } void Interface::delDeadline() { cursor->deadline().year() = 1900; if ((string::npos != sortOrder.find('l')) || (string::npos != sortOrder.find('L'))) { drawTodo(); } else { screen.deadlineClear(cursor_line); } } void Interface::delPriority() { cursor->priority() = 0; if ((string::npos != sortOrder.find('p')) || (string::npos != sortOrder.find('P'))) { drawTodo(); } else { screen.priorityClear(cursor_line); } } void Interface::delSched() { sched.del(&(*cursor)); cursor->sched().year() = 1900; screen.drawSched(sched, &(*cursor)); } void Interface::paste() { if (copied) { iToDo aux = cursor; aux.addChild(copied); while (aux != cursor) next(); sched.add_recursive(copied); copied = NULL; drawTodo(); } } void Interface::pasteUp() { if (copied) { cursor.addChildUp(copied); sched.add_recursive(copied); copied = NULL; drawTodo(); } } void Interface::pasteChild() { if (copied) { cursor->actCollapse() = true; cursor_line += screen.taskLines(cursor.depth(), *cursor); cursor.in(); cursor.addChildUp(copied); sched.add_recursive(copied); copied = NULL; drawTodo(); } } bool Interface::editLine(wstring& str) { Editor::return_t save; wstring oldTitle = cursor->getTitle(); str = oldTitle; screen.infoMsg("Editing todo. Press ENTER to save or ESC to abort edit"); save = screen.editTitle(cursor_line, cursor.depth(), cursor->haveChild(), str, str.length()); while ((save == Editor::REDRAW) || (save == Editor::RESIZE)) { cursor->getTitle() = str; if (save == Editor::RESIZE) resizeTerm(); else drawTodo(); save = screen.editTitle(cursor_line, cursor.depth(), cursor->haveChild(), str); } screen.infoClear(); if (save == Editor::NOT_SAVED) { cursor->getTitle() = oldTitle; drawTodo(); } else { cursor->getTitle() = str; if (cursor->sched().valid()) screen.drawSched(sched, &(*cursor)); } return (save == Editor::SAVED); } void Interface::editDeadline() { screen.infoMsg("Editing deadline. Press ENTER to save or ESC to abort edit"); Editor::return_t save; Date date = cursor->deadline(); save = screen.editDeadline(cursor_line, date, cursor->done(), 0); while (save == Editor::RESIZE) { resizeTerm(); save = screen.editDeadline(cursor_line, date, cursor->done()); } if ((save == Editor::SAVED) && date.correct()) cursor->deadline() = date; screen.infoClear(); drawTodo(); } void Interface::setPriority() { screen.infoMsg("Editing priority. Press ENTER to save or ESC to abort edit"); Editor::return_t save; int priority = cursor->priority(); save = screen.setPriority(cursor_line, priority); while (save == Editor::RESIZE) { resizeTerm(); save = screen.setPriority(cursor_line, priority); } if (save == Editor::SAVED) cursor->priority() = priority; screen.infoClear(); drawTodo(); } void Interface::setCategory() { screen.infoMsg("Editing categories. Separate multiple categories with ','. Press ENTER to save or ESC to abort edit"); Editor::return_t save; wstring category = cursor->getCategoriesStr(); save = screen.setCategory(cursor_line, category, category.length()); while (save == Editor::RESIZE) { resizeTerm(); save = screen.setCategory(cursor_line, category); } if (save == Editor::SAVED) cursor->setCategoriesStr(category); screen.infoClear(); drawTodo(); } void Interface::addLine() { iToDo aux = cursor; aux.addChild(new ToDo()); while (aux != cursor) next(); inherit(); drawTodo(); wstring title; if (!editLine(title) || (title == L"")) del(); } void Interface::addLineUp() { cursor.addChildUp(new ToDo()); inherit(); drawTodo(); wstring title; if (!editLine(title) || (title == L"")) del(); } void Interface::modifyLine() { wstring title; editLine(title); } void Interface::editText() { char* editor = config.getEditor(); if (strlen(editor) != 0) { char s[86]; char* argv[32]; int argc; char* res; Text& text = cursor->getText(); /* create a temporal file */ char template_name[]="/tmp/cmguiTuduXXXXXX"; int fout=mkstemp(template_name); close(fout); wofstream ofs(template_name); ofs.imbue(locale("")); ofs << text; ofs.close(); sprintf(s, editor, template_name); argc=0; argv[argc] = strtok(s, " \t"); while ((res = strtok(NULL, " \t")) != NULL) { if (++argc >= 32) break; argv[argc] = res; } argv[argc+1] = NULL; endwin(); switch (fork()) { case 0: execvp(argv[0],argv); break; case -1: screen.infoMsg("I can't create a new process."); break; default: wait(NULL); break; } doupdate(); wifstream ifs(template_name); ifs.imbue(locale("")); ifs >> text; ifs.close(); unlink(template_name); echo(); curs_set(1); screen.drawText(cursor->getText()); noecho(); curs_set(0); } else { screen.infoMsg("Editing text. Press ESC to save"); screen.editText(cursor->getText()); screen.infoClear(); } } void Interface::editSched() { sched.del(&(*cursor)); Editor::return_t save; Date date = cursor->sched(); save = screen.editSched(date, 0); while (save == Editor::RESIZE) { resizeTerm(); save = screen.editSched(date); } if ((save == Editor::SAVED) && date.correct()) cursor->sched() = date; if (cursor->sched().valid()) sched.add(&(*cursor)); screen.drawSched(sched, &(*cursor)); } void Interface::schedUp() { sched.up(&(*cursor)); screen.drawSched(sched, &(*cursor)); } void Interface::schedDown() { sched.down(&(*cursor)); screen.drawSched(sched, &(*cursor)); } void Interface::upText() { screen.scrollUpText(cursor->getText()); } void Interface::downText() { screen.scrollDownText(cursor->getText()); } void Interface::collapse() { cursor->getCollapse() = !cursor->getCollapse(); drawTodo(); } void Interface::hide_done() { config.getHideDone() = !config.getHideDone(); if (isHide(cursor)) up(); if (!config.getHideDone() && cursor->getTitle().empty()) del(); drawTodo(); } bool Interface::_search() { bool res = true; iToDo hit = cursor; if (hit.search(search_pattern)) { iToDo first_hit = hit; /* if is hide search the next one */ while (isHide(hit)) { hit.search(search_pattern); /* if there is only hidden tasks exit */ if (first_hit == hit) { res = false; break; } } } else res = false; if (res) { iToDo aux = cursor; while (aux.out()) aux->actCollapse() = false; aux = hit; while (hit.out()) hit->actCollapse() = true; while (next()) if (cursor == aux) return true; while (cursor != aux) prev(); } return res; } void Interface::command_line() { Editor::return_t save; wstring command(L""); save = screen.cmd(command, 0); while (save == Editor::RESIZE) { resizeTerm(); save = screen.cmd(command); } if (save == Editor::SAVED) { if (cmd.cmd(command)) { if (isHide(cursor)) up(); /* destroy empty with NONE category */ if ((cursor->getCategories().count(NONE_CATEGORY)) && cursor->getTitle().empty()) del(); drawTodo(); } } } void Interface::search() { Editor::return_t save; wstring pattern(L""); save = screen.searchText(pattern, 0); while (save == Editor::RESIZE) { resizeTerm(); save = screen.searchText(pattern); } if (save == Editor::SAVED) { search_pattern = pattern; if (_search()) drawTodo(); else screen.infoMsg("Not found"); } } void Interface::search_next() { if (search_pattern != L"") if (_search()) drawTodo(); else screen.infoMsg("Not found"); else screen.infoMsg("No search pattern"); } void Interface::search_prev() { if (search_pattern != L"") if (_search()) drawTodo(); else screen.infoMsg("Not found"); else screen.infoMsg("No search pattern"); } void Interface::sortByTitle() { sortOrder = L't' + sortOrder; drawTodo(); } void Interface::sortByDone() { sortOrder = L'd' + sortOrder; drawTodo(); } void Interface::sortByDeadline() { sortOrder = L'l' + sortOrder; drawTodo(); } void Interface::sortByPriority() { sortOrder = L'p' + sortOrder; drawTodo(); } void Interface::sortByCategory() { sortOrder = L'c' + sortOrder; drawTodo(); } void Interface::sortByUser() { sortOrder = L'u' + sortOrder; drawTodo(); } void Interface::sortRevTitle() { sortOrder = L'T' + sortOrder; drawTodo(); } void Interface::sortRevDone() { sortOrder = L'D' + sortOrder; drawTodo(); } void Interface::sortRevDeadline() { sortOrder = L'L' + sortOrder; drawTodo(); } void Interface::sortRevPriority() { sortOrder = L'P' + sortOrder; drawTodo(); } void Interface::sortRevCategory() { sortOrder = L'C' + sortOrder; drawTodo(); } void Interface::sortRevUser() { sortOrder = L'U' + sortOrder; drawTodo(); } void Interface::save() { if (writer.save()) { cursor.sort(sortOrder); screen.infoMsg("File saved"); } else { screen.infoMsg("File can not be saved"); } } #define LINES_HELP 44 void Interface::help() { action_list list; config.getActionList(list); wstring str[LINES_HELP]; int i = 0; str[i++] = L" TASK CREATION\n"; str[i++] = L" " + list[L"addTodo"] + L"\tadd a new task below the cursor\n"; str[i++] = L" " + list[L"addTodoUp"] + L"\tadd a new task above the cursor\n"; str[i++] = L" " + list[L"editTitle"] + L"\tedit task's title\n"; str[i++] = L" " + list[L"editText"] + L"\tadd/edit task's long description text\n"; str[i++] = L" " + list[L"setPriority"] + L"\tadd/edit task's priority\n"; str[i++] = L" " + list[L"setCategory"] + L"\tadd/edit task's category\n"; str[i++] = L" " + list[L"editDeadline"] + L"\tadd/edit task's deadline\n"; str[i++] = L" " + list[L"editSched"] + L"\tadd/edit taks's scheduled date\n"; str[i++] = L"\n"; str[i++] = L" NAVIGATION\n"; str[i++] = L" " + list[L"in"] +L"\tgo one level deeper\n"; str[i++] = L" " + list[L"out"] +L"\tgo to the outer lever\n"; str[i++] = L" " + list[L"down"] +L"\tgo down\n"; str[i++] = L" " + list[L"up"] +L"\tgo up\n"; str[i++] = L" " + list[L"collapse"] +L"\tcollapse/expand a task\n"; str[i++] = L" " + list[L"hideDone"] +L"\thide/unhide tasks marked as done\n"; str[i++] = L" " + list[L"move_down"] +L"\tmove a task downwards\n"; str[i++] = L" " + list[L"move_up"] +L"\tmove a task upwards\n"; str[i++] = L" " + list[L"schedUp"] +L"\tmove up the task on the scheduler\n"; str[i++] = L" " + list[L"schedDown"] + L"\tmove down the task on the scheduler\n"; str[i++] = L" " + list[L"downText"] +L"\tscroll text down\n"; str[i++] = L" " + list[L"upText"] +L"\tscroll text up\n"; str[i++] = L" " + list[L"search"] +L"\tsearch on titles\n"; str[i++] = L" " + list[L"searchNext"] +L"\tgo to next search result\n"; str[i++] = L" " + list[L"save"] +L"\tsave changes\n"; str[i++] = L" " + list[L"quit"] +L"\tquit\n"; str[i++] = L" " + list[L"quitNoSave"] +L"\tquit without saving\n"; str[i++] = L"\n"; str[i++] = L" EDITING\n"; str[i++] = L" " + list[L"done"] +L"\tmark/unmark a task as done\n"; str[i++] = L" " + list[L"delete"] +L"\tdelete a task\n"; str[i++] = L" " + list[L"delPriority"] +L"\tdelete task's priority\n"; str[i++] = L" " + list[L"delDeadline"] +L"\tdelete task's deadline\n"; str[i++] = L" " + list[L"delSched"] +L"\tdelete task's scheduled date\n"; str[i++] = L" " + list[L"paste"] +L"\tpaste last deletion below the cursor\n"; str[i++] = L" " + list[L"pasteUp"] +L"\tpaste last deletion above the cursor\n"; str[i++] = L" " + list[L"pasteChild"] +L"\tpaste last deletion as a subtask\n"; str[i++] = L"\n"; str[i++] = L" COMMANDS\n"; str[i++] = L" :help\tshow manual page\n"; str[i++] = L"\n"; str[i++] = L" Please refer to the manual page for more commands, sorting\n"; str[i] = L" by different criteria and category management.\n"; screen.helpPopUp(str, i); } tudu-0.10.2/src/date.cc0000644000175000017500000001222013121017272013275 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #include "date.h" Date::Date(int day, int month, int year): _day(day), _month(month), _year(year) {} int& Date::day(int d) { if (d) _day = d; return _day; } int& Date::month(int m) { if (m) _month = m; return _month; } int& Date::year(int y) { if (y) _year = y; return _year; } void Date::setToday() { time_t t = time(NULL); struct tm* pt = localtime(&t); _day = pt->tm_mday; _month = pt->tm_mon+1; _year = pt->tm_year+1900; } bool Date::valid() { return (1900 != _year); } bool Date::correct() { bool correct; switch (_month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: if ((_day < 1) || (_day > 31)) correct = false; else correct = true; break; case 4: case 6: case 9: case 11: if ((_day < 1) || (_day > 30)) correct = false; else correct = true; break; case 2: /* if leap year */ if ((_year % 4 == 0) && !((_year % 100 == 0) && (_year % 400 != 0))) { if ((_day < 1) || (_day > 29)) correct = false; else correct = true; } else { if ((_day < 1) || (_day > 28)) correct = false; else correct = true; } break; default: correct = false; break; } return correct; } #define SECONDS_IN_A_DAY (60*60*24) int Date::daysLeft() { time_t rawtime; time_t today; struct tm * timeinfo; int daysleft; time(&rawtime); timeinfo = localtime(&rawtime); timeinfo->tm_mday = _day; timeinfo->tm_mon = _month - 1; timeinfo->tm_year = _year - 1900; rawtime = mktime(timeinfo); today = time(NULL); daysleft = difftime(rawtime,today)/SECONDS_IN_A_DAY; return daysleft; } Date Date::operator-(int days) { Date d(_day, _month, _year); d._day -= days; while (d._day <= 0) { d._month--; if (d._month == 0) { d._month = 12; d._year--; } switch (d._month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: d._day += 31; break; case 4: case 6: case 9: case 11: d._day += 30; break; case 2: /* if leap year */ if ((d._year % 4 == 0) && !((d._year % 100 == 0) && (d._year % 400 != 0))) { d._day += 29; } else { d._day += 28; } break; } } return d; } Date Date::operator+(int days) { Date d(_day, _month, _year); bool day_valid = false; d._day += days; do { switch (d._month) { case 1: case 3: case 5: case 7: case 8: case 10: case 12: if (d._day <= 31) day_valid = true; else d._day -= 31; break; case 4: case 6: case 9: case 11: if (d._day <= 30) day_valid = true; else d._day -= 30; break; case 2: /* if leap year */ if ((d._year % 4 == 0) && !((d._year % 100 == 0) && (d._year % 400 != 0))) { if (d._day <= 29) day_valid = true; else d._day -= 29; } else { if (d._day <= 28) day_valid = true; else d._day -= 28; } break; } if (!day_valid) { d._month++; if (d._month == 13) { d._month = 1; d._year++; } } } while (!day_valid); return d; } bool Date::operator<(Date d) { if (_year < d._year) return true; else if (_year > d._year) return false; else if (_month < d._month) return true; else if (_month > d._month) return false; else if (_day < d._day) return true; else return false; } bool Date::operator>(Date d) { if (_year > d._year) return true; else if (_year < d._year) return false; else if (_month > d._month) return true; else if (_month < d._month) return false; else if (_day > d._day) return true; else return false; } bool Date::operator!=(Date d) { if (d._year != _year) return true; else if (d._month != _month) return true; else if (d._day != _day) return true; else return false; } bool Date::operator==(Date d) { if (d._year != _year) return false; else if (d._month != _month) return false; else if (d._day != _day) return false; else return true; } tudu-0.10.2/src/text.h0000644000175000017500000000435513121017272013220 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #ifndef TEXT_H #define TEXT_H #include "includes.h" #include "window.h" class Text { public: Text& operator=(const wstring& str); bool operator!=(const wstring& str); void print(Window& win); void edit(Window& win); wstring getStr(); void scroll_up(Window& win); void scroll_down(Window& win); private: list text; /* list of lines */ int cursor_col; int cursor_y; /* = INT_MIN when is no editing */ list::iterator cursor_line; list::iterator offset; /* line for start to display */ int lines, cols; /* begin=line for start, length=num of screen lines to fit*/ wstring _getStr(list::iterator begin, int length = 0); bool _scroll_up(); bool _scroll_down(); void left(); void right(); void up(); void down(); void backspace(); void supr(); void home(); void end(); void next_page(); void prev_page(); void new_line(); void tab(); }; wostream& operator<<(wostream& os, Text& t); wistream& operator>>(wistream& is, Text& t); #endif tudu-0.10.2/src/editor.cc0000644000175000017500000002752313121017272013662 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #include "editor.h" #include "cmd.h" Editor::Editor() { text = L""; cursor = 0; key = '\0'; } wstring& Editor::getText() { return text; } int& Editor::cursorPos() { return cursor; } Editor::return_t Editor::edit(Window& win, int begin_y, int begin_x, int ncols) { window = &win; y = begin_y; x = begin_x; cols = ncols; exit = false; result = SAVED; curs_set(1); initialize(); while (!exit) { updateText(); if (window->_getch(key) == KEY_CODE_YES) { switch (key) { case KEY_RESIZE: return RESIZE; case KEY_LEFT: left(); break; case KEY_RIGHT: right(); break; case KEY_UP: up(); break; case KEY_DOWN: down(); break; case KEY_HOME: home(); break; case KEY_END: end(); break; case KEY_BACKSPACE: backspace(); break; case KEY_DC: supr(); break; case KEY_ENTER: enter(); break; } } else { switch (key) { case '\e': esc(); break; case '\n': enter(); break; case '\t': tab(); break; default: other(); break; } } } curs_set(0); window->_refresh(); return result; } void Editor::initialize() {} void Editor::updateText() {} void Editor::left() {} void Editor::right() {} void Editor::up() {} void Editor::down() {} void Editor::home() {} void Editor::end() {} void Editor::backspace() {} void Editor::supr() {} void Editor::tab() {} void Editor::other() {} void Editor::esc() { exit = true; result = NOT_SAVED; } void Editor::enter() { exit = true; } /* * Editor mono line */ void LineEditor::updateText() { static int offset = 0; // number of columns needed to display the text on the screen // it only matters for length lower than cols const int text_cols = wcswidth(text.c_str(), cols); int cursor_cols = cursor > offset ? wcswidth(text.substr(offset, cursor-offset).c_str(), cols) : 0; if ((int)cols > text_cols) { offset = 0; } else if (cursor < offset) { offset = cursor; } else while (cursor_cols >= (int)cols) { cursor_cols -= wcwidth(text[offset]); offset++; } window->_move(y, x); window->_addstr(text.substr(offset), cols); window->_move(y, x+cursor_cols); window->_refresh(); } void LineEditor::left() { if (cursor>0) { --cursor; } else if (text.length() == 0) { exit = true; result = NOT_SAVED; } } void LineEditor::right() { if (cursor<(int)text.length()) { ++cursor; } } void LineEditor::home() { cursor = 0; } void LineEditor::end() { cursor = text.length(); } void LineEditor::backspace() { if (cursor>0) text.erase(--cursor, 1); } void LineEditor::supr() { if (cursor<(int)text.length()) text.erase(cursor, 1); } void LineEditor::tab() { text.insert(cursor,1,' '); ++cursor; } void LineEditor::other() { text.insert(cursor,1,key); ++cursor; } /* * Editor for task titles, multilinear */ void TitleEditor::initialize() { const int text_cols = wcswidth(text.c_str(), string::npos); textLines = (text_cols-1) / (int)cols; } void TitleEditor::updateText() { const int text_cols = wcswidth(text.c_str(), string::npos); if (textLines != ((text_cols-1) / (int)cols)) { exit = true; result = REDRAW; return; } int i = 0; bool cursor_found = false; for (int line = 0; line <= textLines; line++) { window->_move(y+line, x); int num_cols = window->_addstr(text.substr(i), cols); // calculate line and col of the cursor if (!cursor_found && ((line == textLines) || (i+num_cols > cursor))) { cursor_line = line; cursor_col = 0; for (int c = i; c < cursor; c++) { cursor_col += wcwidth(text[c]); } cursor_found = true; } i += num_cols; } window->_move(y+cursor_line, x+cursor_col); window->_refresh(); } void TitleEditor::up() { if (cursor_line <= 0) return; for (unsigned int c = 0; c < cols; cursor--) { c += wcwidth(text[cursor]); } } void TitleEditor::down() { if ((int)cursor_line >= textLines) return; for (unsigned int c = 0; c < cols; cursor++) { c += wcwidth(text[cursor]); } if (cursor > (int)text.length()) { cursor = text.length(); } } /* * Editor of Categories */ Editor::return_t CategoryEditor::edit(Window& win, int begin_y, int begin_x, int ncols) { search = categories.end(); return Editor::edit(win, begin_y, begin_x, ncols); } bool CategoryEditor::cmp(unsigned int idx, wstring str) { return text.compare(idx, length, str, 0, length); } void CategoryEditor::tab() /* do completion */ { unsigned int j,i = 0; while ((j = text.find(L",", i)) < (unsigned int)cursor) { i = j+1; } wstring pre(text.substr(0, i)); wstring cat(text.substr(i, j-i)); wstring pos; if (j < text.length()) { pos = text.substr(j); } else { j = text.length(); } /* if it is no the first time */ if ((cursor == (int)j) && (search != categories.end()) && (cat == *search)) { search++; if ((search != categories.end()) && (!cmp(i, *search))) { text = pre + *search + pos; cursor = i+search->length(); } else { text = pre + cat.substr(0, length) + pos; search = first; cursor = i+length; } } /* if it is the first time */ else { length = j-i; for (search = categories.begin(); (search != categories.end()) && (cmp(i, *search)); search++); if ((search != categories.end()) && (!cmp(i, *search))) { text = pre + *search + pos; first = search; cursor = i+search->length(); } } } /* * Editor with history, used on search */ void HistoryEditor::initialize() { shown = history.begin(); LineEditor::initialize(); } void HistoryEditor::up() { if (shown != history.end()) { text = *shown; cursor = text.length(); shown++; } } void HistoryEditor::down() { if (shown != history.begin()) { shown--; text = *shown; cursor = text.length(); } } void HistoryEditor::enter() { exit = true; history.push_front(text); } void HistoryEditor::backspace() { if (text.length() == 0) { exit = true; result = NOT_SAVED; return; } LineEditor::backspace(); } /* * Command editor */ void CmdEditor::initialize() { /* initialize if is new command, * in other case we expect it to be already initialized */ if (text == L"") { search = categories.end(); com_search = commands.end(); param = 0; } HistoryEditor::initialize(); } bool CmdEditor::cmp(wstring str) { return text.compare(0, length, str, 0, length); } void CmdEditor::tab() /* do completion */ { vector params; size_t begin, end; wstring rest_params = L""; /* Get the command and params in text */ for (begin = 0, end = text.find(' ', 0); (wstring::npos != end) && (cursor > (int)end); begin = end+1, end = text.find(' ', begin)) { params.push_back(text.substr(begin, end-begin)); } if (wstring::npos != end) { params.push_back(text.substr(begin, end-begin)); rest_params = text.substr(end+1); } else { params.push_back(text.substr(begin)); } /* if is completing the command */ if (params.size() == 1) { command_completion(params[0]); } /* if is completing the param */ else { if (commands[params[0]] == L"category") category_completion(params.back(), params.size()-1); } /* regenerate the text string */ text = L""; for (vector::iterator p = params.begin(); p != params.end(); p++) { text += *p + L" "; } cursor = text.length()-1; if (rest_params.empty()) text.erase(text.length()-1, 1); else text += rest_params; param = params.size()-1; } void CmdEditor::command_completion(wstring& com) { /* if it is not the first time */ if ((param == 0) && (com_search != commands.end()) && (com == com_search->first)) { com_search++; if ((com_search != commands.end()) && (!cmp(com_search->first))) { com = com_search->first; cursor = com.length(); } else { com = com.substr(0, length); com_search = com_first; cursor = length; } } /* if it is the first time */ else { length = com.length(); //TODO: try upper_bound for (com_search = commands.begin(); (com_search != commands.end()) && (cmp(com_search->first)); com_search++); if ((com_search != commands.end()) && (!cmp(com_search->first))) { com = com_search->first; com_first = com_search; cursor = com.length(); } } } #define param_cmp(str) cat.compare(0, length, str, 0, length) void CmdEditor::category_completion(wstring& cat, int num_param) { /* if it is no the first time */ if ((param == num_param) && (search != categories.end()) && (cat == *search)) { search++; if ((search != categories.end()) && (!param_cmp(*search))) { cat = *search; } else { cat = cat.substr(0, length); search = first; } } /* if it is the first time */ else { length = cat.length(); for (search = categories.begin(); (search != categories.end()) && (param_cmp(*search)); search++); if ((search != categories.end()) && (!param_cmp(*search))) { cat = *search; first = search; } } } /* * Editor of dates */ Editor::return_t DateEditor::edit(Window& win, int begin_y, int begin_x) { return Editor::edit(win, begin_y, begin_x, 11); } void DateEditor::updateText() { if (cursor >= (int) cols) cursor = cols-1; window->_addstr(y, x, text); window->_move(y, x+cursor); window->_refresh(); } void DateEditor::left() { if (cursor>0) --cursor; if ((2==cursor) || (5==cursor)) --cursor; } void DateEditor::right() { if (cursor<9) ++cursor; if ((2==cursor) || (5==cursor)) ++cursor; } void DateEditor::up() { if ((text[cursor] < '0') || (text[cursor] > '9')) text[cursor] = '0'; if (text[cursor] < '9') text[cursor]++; } void DateEditor::down() { if ((text[cursor] > '0') && (text[cursor] <= '9')) text[cursor]--; } void DateEditor::home() { cursor = 0; } void DateEditor::end() { cursor = 9; } void DateEditor::other() { /* if is a number */ if ((key >= 48) && (key <= 57)) { text[cursor] = key; if (cursor<9) ++cursor; if ((2==cursor) || (5==cursor)) ++cursor; } } /* * Editor of priorities */ Editor::return_t PriorityEditor::edit(Window& win, int begin_y, int begin_x) { return Editor::edit(win, begin_y, begin_x, 1); } void PriorityEditor::updateText() { cursor = 0; window->_addstr(y, x, text); window->_move(y, x); window->_refresh(); } void PriorityEditor::up() { if ((text != L"N") && (text[cursor] > 49)) { text[cursor]--; } else { text = L"1"; } } void PriorityEditor::down() { if ((text != L"N") && (text[cursor] < 53)) { text[cursor]++; } else { text = L"5"; } } void PriorityEditor::backspace() { text = L"N"; } void PriorityEditor::supr() { text = L"N"; } void PriorityEditor::other() { /* if is a number between 1 and 5 */ if ((key >= 49) && (key <= 53)) { text[cursor] = key; } } tudu-0.10.2/src/text.cc0000644000175000017500000002220613121017272013351 0ustar useruser /************************************************************************* * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 .* *************************************************************************/ #include "text.h" #define cursor_x (cursor_col % cols) #define rows_in_line(line) ((line->length() / cols) + 1) Text& Text::operator=(const wstring& str) { unsigned int i = 0, size; /* build a list with each line of the text in an entry */ text.clear(); while (i < str.length()) { for (size = 0; (i+size < str.length()) && ('\n' != str[i+size]); ++size); text.push_back(str.substr(i, size)); i += size+1; } if (text.empty()) /* if is empty it makes a sigfault at edit */ text.push_back(L""); /* set up the cursor */ cursor_col = 0; cursor_y = INT_MIN; cursor_line = text.begin(); offset = text.begin(); return *this; } bool Text::operator!=(const wstring& str) { return (str != getStr()); } void Text::print(Window& win) { lines = win._lines(); cols = win._cols(); wstring str = _getStr(offset, lines); win._erase(); win._addstr(0,0,str); win._refresh(); } void Text::edit(Window& win) { bool resized = false; /* calculate the cursor_y */ cursor_y = 0; for (list::iterator i = offset; i != cursor_line; ++i) cursor_y += rows_in_line(i); cursor_y += cursor_col / cols; lines = win._lines(); cols = win._cols(); win._move(cursor_y, cursor_x); curs_set(1); win._refresh(); /* editor loop */ wint_t key = '\e'; bool isKeyCode = (win._getch(key) == KEY_CODE_YES); while ('\e' != key) { if (isKeyCode) { switch (key) { case KEY_RESIZE: resized = true; break; case KEY_LEFT: left(); break; case KEY_RIGHT: right(); break; case KEY_DOWN: down(); break; case KEY_UP: up(); break; case KEY_HOME: home(); break; case KEY_END: end(); break; case KEY_NPAGE: next_page(); break; case KEY_PPAGE: prev_page(); break; case KEY_BACKSPACE: backspace(); break; case KEY_DC: supr(); break; case KEY_ENTER: new_line(); break; } } else { switch (key) { case '\n': new_line(); break; case '\t': tab(); break; default: cursor_line->insert(cursor_col,1,key); ++cursor_col; if (0 == cursor_x) ++cursor_y; break; } } /* print the text, place cursor, ... */ wstring str = _getStr(offset, lines); win._erase(); win._addstr(0,0,str); win._move(cursor_y, cursor_x); win._refresh(); isKeyCode = (win._getch(key) == KEY_CODE_YES); } curs_set(0); print(win); cursor_y = INT_MIN; if (resized) ungetch(KEY_RESIZE); return; } wstring Text::getStr() { wstring s = L""; for (list::iterator i = text.begin(); i != text.end(); ++i) { s += *i; s += L'\n'; } return s; } wstring Text::_getStr(list::iterator begin, int length) { int rows = 0; wstring s = L""; list::iterator i = begin; if (text.end() == begin) return s; for (;i != text.end(); ++i) { if (length) { int rows_line = rows_in_line(i); if (rows+rows_line > length) { for (int row = 0; row < length-rows; ++row) { s += i->substr(row*cols, cols); } s += '\n'; break; } rows += rows_line; } s += *i; s += '\n'; if ((length) && (rows == length)) break; } s.erase(s.length()-1); /* del the last '\n' */ return s; } void Text::scroll_up(Window& win) { lines = win._lines(); cols = win._cols(); _scroll_up(); print(win); } void Text::scroll_down(Window& win) { lines = win._lines(); cols = win._cols(); _scroll_down(); print(win); } bool Text::_scroll_up() { if (text.begin() != offset) { --offset; /* update cursor_y if is editing */ if (cursor_y != INT_MIN) { cursor_y += rows_in_line(offset); while (cursor_y >= lines) { cursor_y -= rows_in_line(cursor_line); --cursor_line; if ((int)cursor_line->length() < cursor_col) cursor_col = cursor_line->length(); } } /* if is not in edit mode scroll also the cursor */ else { --cursor_line; if ((int)cursor_line->length() < cursor_col) cursor_col = cursor_line->length(); } return true; } else return false; } bool Text::_scroll_down() { ++offset; if (text.end() != offset) { --offset; /* update cursor_y if is editing */ if (cursor_y != INT_MIN) { cursor_y -= rows_in_line(offset); if (cursor_y < 0) { cursor_y = 0; ++cursor_line; if (cursor_x < (int)cursor_line->length()) cursor_col = cursor_x; else cursor_col = cursor_line->length(); } } /* if is not in edit mode scroll also the cursor */ else { ++cursor_line; if (cursor_line == text.end()) { --cursor_line; } else { if (cursor_x < (int)cursor_line->length()) cursor_col = cursor_x; else cursor_col = cursor_line->length(); } } ++offset; return true; } else { --offset; return false; } } void Text::left() { if (cursor_col>0) { if (0 == cursor_x) --cursor_y; --cursor_col; } else if (cursor_line != text.begin()) { --cursor_y; --cursor_line; cursor_col = cursor_line->length(); } if (cursor_y < 0) _scroll_up(); } void Text::right() { if (cursor_col < (int)cursor_line->length()) { ++cursor_col; if (0 == cursor_x) ++cursor_y; } else if (cursor_line != --text.end()) { cursor_col = 0; ++cursor_y; ++cursor_line; } if (cursor_y >= lines) _scroll_down(); } #define last_line() ((int)rows_in_line(cursor_line)-1 == cursor_col / cols) void Text::down() { if (last_line()) { if (cursor_line != --text.end()) { ++cursor_y; ++cursor_line; cursor_col = cursor_x; } } else { ++cursor_y; cursor_col += cols; } if (cursor_col > (int)cursor_line->length()) { cursor_col = cursor_line->length(); } if (cursor_y >= lines) _scroll_down(); } void Text::up() { if ((cursor_col >= cols) || (cursor_line != text.begin())) { --cursor_y; if (cursor_col < cols) { --cursor_line; if (cursor_x < (int)cursor_line->length() % cols) cursor_col = cursor_x + (rows_in_line(cursor_line)-1) * cols; else cursor_col = cursor_line->length(); } else { cursor_col -= cols; } if (cursor_y < 0) _scroll_up(); } } void Text::backspace() { if (cursor_col > 0) { if (0 == cursor_x) --cursor_y; if (cursor_y < 0) _scroll_up(); --cursor_col; cursor_line->erase(cursor_col, 1); } else if (cursor_line != text.begin()) /* delete line break */ { list::iterator i = cursor_line; --cursor_y; --cursor_line; cursor_col = cursor_line->length(); if (cursor_y < 0) _scroll_up(); *cursor_line += *i; text.erase(i); } } void Text::supr() { if ((cursor_col == (int)cursor_line->length()) && (cursor_line != --text.end())) { list::iterator i = cursor_line; ++i; *cursor_line += *i; text.erase(i); } else { cursor_line->erase(cursor_col, 1); } if (cursor_y >= lines) _scroll_down(); } void Text::home() { for (int i = 0; i < cursor_col/cols; --cursor_y, ++i); cursor_col = 0; if (cursor_y >= lines) _scroll_down(); } void Text::end() { for (int i = 0; i < ((int)cursor_line->length()-cursor_col)/cols; ++cursor_y, ++i); cursor_col = cursor_line->length(); if (cursor_y >= lines) _scroll_down(); } void Text::next_page() { int line_count = rows_in_line(offset); while ((line_count < lines) && (_scroll_down())) { line_count += rows_in_line(offset); } } void Text::prev_page() { int line_count = rows_in_line(offset); while ((line_count < lines) && (_scroll_up())) { line_count += rows_in_line(offset); } } void Text::new_line() { list::iterator i = cursor_line; ++i; text.insert(i, cursor_line->substr(cursor_col)); cursor_line->erase(cursor_col); ++cursor_y; ++cursor_line; cursor_col = 0; if (cursor_y >= lines) _scroll_down(); } #define TAB_SPACES 4 void Text::tab() { cursor_line->insert(cursor_col,TAB_SPACES,' '); cursor_col+=TAB_SPACES; if (TAB_SPACES > cursor_x) ++cursor_y; } wostream& operator<<(wostream& os, Text& t) { os << t.getStr(); return os; } wistream& operator>>(wistream& is, Text& t) { wstring str; wchar_t c; while (is.get(c)) str += c; t = str; return is; } tudu-0.10.2/src/editor.h0000644000175000017500000000744113121017272013521 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #ifndef EDITOR_H #define EDITOR_H #include "includes.h" #include "data.h" #include "window.h" class Editor { public: /* return values for the editor */ enum return_t { NOT_SAVED = 0, SAVED, /* In case of changes that need to redraw or resize the screen. * After update the screen the function edit should be call again. */ RESIZE, REDRAW }; Editor(); wstring& getText(); int& cursorPos(); return_t edit(Window& win, int begin_y, int begin_x, int ncols); protected: Window *window; int y; int x; unsigned int cols; wstring text; int cursor; wint_t key; bool exit; return_t result; virtual void initialize(); virtual void updateText(); virtual void left(); virtual void right(); virtual void up(); virtual void down(); virtual void home(); virtual void end(); virtual void backspace(); virtual void supr(); virtual void tab(); virtual void other(); virtual void enter(); virtual void esc(); }; class LineEditor: public Editor { protected: void updateText(); void left(); void right(); void home(); void end(); void backspace(); void supr(); void tab(); void other(); }; class TitleEditor: public LineEditor { protected: int textLines; int cursor_col; int cursor_line; void initialize(); void updateText(); void up(); void down(); }; class CategoryEditor: public LineEditor { public: return_t edit(Window& win, int begin_y, int begin_x, int ncols); protected: set::iterator search; set::iterator first; int length; bool cmp(unsigned int idx, wstring str); void tab(); }; class HistoryEditor: public LineEditor { protected: list history; list::iterator shown; void initialize(); void up(); void down(); void enter(); void backspace(); }; class CmdEditor: public HistoryEditor { protected: map::iterator com_search; map::iterator com_first; set::iterator search; set::iterator first; int length; int param; void initialize(); bool cmp(wstring str); void tab(); void command_completion(wstring& com); void category_completion(wstring& cat, int num_param); }; class DateEditor: public Editor { public: return_t edit(Window& win, int begin_y, int begin_x); protected: void updateText(); void left(); void right(); void up(); void down(); void home(); void end(); void other(); }; class PriorityEditor: public Editor { public: return_t edit(Window& win, int begin_y, int begin_x); protected: void updateText(); void up(); void down(); void backspace(); void supr(); void other(); }; #endif tudu-0.10.2/src/window.h0000644000175000017500000000461413121017272013541 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #ifndef WINDOW_H #define WINDOW_H #include "includes.h" typedef struct { int y, x; int lines, cols; } window_coor; class Window { public: Window(window_coor coor); Window(int lines, int cols, int y, int x); Window(); ~Window(); int _addstr(const char *str); int _addstr(const wchar_t *str); int _addstr(const string &str); int _addstr(const wstring &str); int _addstr(int y, int x, const char *str); int _addstr(int y, int x, const wchar_t *str); int _addstr(int y, int x, const string &str); int _addstr(int y, int x, const wstring &str); int _addstr(const wstring &str, const unsigned int cols); int _addstr(int y, int x, const wstring &str, unsigned int cols); int _addch(const char ch); int _addch(int y, int x, const char ch); int _refresh(); int _redraw(); int _move(int y, int x); int _attron(int attrs); int _attroff(int attrs); int _erase(); int _getch(wint_t& ch); void _getmaxyx(int& y, int& x); int _box(); int _lines(); int _cols(); int _resize(int lines, int columns); int _mv(int y, int x); int _vline(chtype ch, int n); int _hline(chtype ch, int n); int _delwin(); protected: WINDOW *win; }; #endif tudu-0.10.2/src/sched.h0000644000175000017500000000323613121017272013317 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #ifndef SCHEDULE_H #define SCHEDULE_H #include "includes.h" #include "data.h" #include "date.h" typedef list sched_l; class Sched { public: void add(pToDo todo); void add_recursive(pToDo todo); void up(pToDo todo); void down(pToDo todo); void del(pToDo todo); void del_recursive(pToDo todo); int get(sched_l& list); int get(Date& from, sched_l& list); private: sched_l sched; }; #endif tudu-0.10.2/src/cmd.cc0000644000175000017500000000723713121017272013137 0ustar useruser/************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #include "cmd.h" map commands; Cmd::Cmd() { /* initialize commands */ commands[L"hide"] = L"category"; commands[L"show"] = L"category"; commands[L"showall"] = L"category"; commands[L"showonly"] = L"category"; commands[L"help"] = L""; } void Cmd::get_interface(Interface *i) { interface = i; } bool Cmd::cmd(wstring command) { vector params; wstring com; size_t begin, end; /* Get the command and params in text */ for (begin = 0, end = command.find(' ', 0); wstring::npos != end; begin = end+1, end = command.find(' ', begin)) { if (begin == 0) com = command.substr(begin, end-begin); else params.push_back(command.substr(begin, end-begin)); } if (com == L"") com = command.substr(begin); else params.push_back(command.substr(begin)); /* Exec the command */ if (L"show" == com) { show(params); return true; } else if (L"hide" == com) { hide(params); return true; } else if (L"showall" == com) { showall(params); return true; } else if (L"showonly" == com) { showonly(params); return true; } else if (L"help" == com) { help(params); return true; } else return false; } void Cmd::hide(vector ¶ms) { for (vector::iterator p = params.begin(); p != params.end(); p++) { if (*p != NONE_CATEGORY) interface->hidden_categories.insert(*p); } } void Cmd::show(vector ¶ms) { for (vector::iterator p = params.begin(); p != params.end(); p++) { interface->hidden_categories.erase(*p); } } void Cmd::showall(vector ¶ms) { interface->hidden_categories.clear(); } void Cmd::showonly(vector ¶ms) { /* add all the categories to the hidden list */ interface->hidden_categories.insert(L""); for (set::iterator c = categories.begin(); c != categories.end(); c++) { interface->hidden_categories.insert(*c); } /* remove the shown categories */ for (vector::iterator p = params.begin(); p != params.end(); p++) { interface->hidden_categories.erase(*p); } interface->hidden_categories.erase(NONE_CATEGORY); } void Cmd::help(vector ¶ms) { char* argv[3]; char argv0[] = "man"; char argv1[] = "tudu"; argv[0] = argv0; argv[1] = argv1; argv[2] = NULL; endwin(); switch (fork()) { case 0: execvp(argv[0],argv); break; case -1: interface->screen.infoMsg("I can't create a new process."); break; default: wait(NULL); break; } doupdate(); } tudu-0.10.2/src/screen.h0000644000175000017500000000626313121017272013513 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #ifndef SCREEN_H #define SCREEN_H #include "includes.h" #include "window.h" #include "text.h" #include "data.h" #include "config.h" #include "editor.h" #include "sched.h" class Screen { public: Screen(Config& c); ~Screen(); void resizeTerm(); void drawTask(int line, int depth, ToDo& t, bool isCursor=false); void drawTitle(int line, int depth, wstring& title, int startLine=0); void drawText(Text &t); void drawSched(Sched &sched, pToDo cursor = NULL); void scrollUpText(Text &t); void scrollDownText(Text &t); void deadlineClear(int line); void priorityClear(int line); Editor::return_t editTitle(int line, int depth, bool haveChild, wstring& str, int cursorPos = -1); void editText(Text& t); Editor::return_t editDeadline(int line, Date& deadline, bool done, int cursorPos = -1); Editor::return_t editSched(Date& s, int cursorPos = -1); Editor::return_t setPriority(int line, int& priority); Editor::return_t setCategory(int line, wstring& category, int cursorPos = -1); void treeClear(); int treeLines(); /* number of lines the task needs on the screen */ int taskLines(int depth, ToDo &t); Editor::return_t searchText(wstring& pattern, int cursorPos = -1); Editor::return_t cmd(wstring& command, int cursorPos = -1); bool confirmQuit(); void infoMsg(const char str[]); void infoClear(); void infoPercent(int percent); void helpPopUp(wstring str[], int len); private: Window *whelp; Window *wtree; Window *wpriority; Window *wcategory; Window *wdeadline; Window *wtext; Window *winfo; Window *wschedule; vector pipes; Config &config; TitleEditor titleEditor; CategoryEditor categoryEditor; DateEditor dateEditor; PriorityEditor priorityEditor; HistoryEditor searchEditor; CmdEditor cmdEditor; windows_defs coor; void draw_helpbar(window_coor c); void draw(); wstring date2str(Date& date); Date str2date(wstring str); /* col where the title text starts */ int startTitle(int depth); }; #endif tudu-0.10.2/src/parser.h0000644000175000017500000000363213121017272013525 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #ifndef PARSER_H #define PARSER_H #include "includes.h" #include "data.h" #include "sched.h" #include "text.h" class Parser { public: Parser(const char* path); ~Parser(); bool parse(ToDo& todo, Sched& sched); private: wifstream file; wstring str; wstring txt; bool collect_text; bool deadline; bool scheduled; void ptag(iToDo& iterator, Sched& sched); void patt(iToDo& iterator); wchar_t amp(); }; class Writer { public: Writer(const char* pathToSave, ToDo& t); ~Writer(); bool save(); /* return if was succesfull */ private: wofstream file; ToDo& todo; iToDo* i; char path[128]; void _save(); void amp(wstring& str); }; #endif tudu-0.10.2/src/data.cc0000644000175000017500000002375213121017272013305 0ustar useruser /************************************************************************** * Copyright (C) 2007-2015 Ruben Pollan Bella * * * * This file is part of TuDu. * * * * TuDu 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; version 3 of the License. * * * * TuDu 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 . * **************************************************************************/ #include "data.h" set categories; ToDo::ToDo() { collapse = false; cursor_in = false; title = L""; text = L""; _done = false; _priority = 0; sched_position = 0; } ToDo::~ToDo() { list::iterator it; for (it = childs.begin(); it != childs.end(); it++) { delete (*it); } } wstring& ToDo::getTitle() { return title; } Text& ToDo::getText() { return text; } Date& ToDo::deadline() { return _deadline; } Date& ToDo::sched() { return _sched; } int& ToDo::schedPosition() { return sched_position; } bool& ToDo::done() { return _done; } int& ToDo::priority() { return _priority; } set& ToDo::getCategories() { return _category; } wstring ToDo::getCategoriesStr() { wstring cat(L""); for (set::iterator it = _category.begin(); it != _category.end(); it++) { cat += (*it); if (it != --(_category.end())) cat += L','; } return cat; } void ToDo::addCategory(const wstring& c) { _category.insert(c); if (c != NONE_CATEGORY) categories.insert(c); } void ToDo::setCategories(set& c) { _category = c; for (set::iterator it = c.begin(); it != c.end(); it++) if (*it != NONE_CATEGORY) categories.insert(*it); } void ToDo::setCategoriesStr(wstring& c) { _category.clear(); if (c.empty()) return; size_t posEnd, posStart = 0; while ((posEnd = c.find(L',', posStart)) != wstring::npos) { addCategory(c.substr(posStart, posEnd-posStart)); posStart = posEnd+1; } addCategory(c.substr(posStart)); } bool ToDo::haveChild() { return !childs.empty(); } child_info ToDo::getChildInfo() { child_info chinf; if (!haveChild()) { chinf.percent = _done? 100: 0; if (!_done) chinf.deadline = _deadline; } else { iToDo i(*this); int sum_percent = 0, j; child_info aux; if (!_done) chinf.deadline = _deadline; for (j = 0; !(i.end()); ++i, ++j) { aux = i->getChildInfo(); sum_percent += aux.percent; if (aux.deadline.valid() && ((aux.deadline < chinf.deadline) || !chinf.deadline.valid())) chinf.deadline = aux.deadline; } chinf.percent = sum_percent/j; } return chinf; } bool& ToDo::getCollapse() { return collapse; } bool& ToDo::actCollapse() { return cursor_in; } wstring cmpOrder; bool cmp(pToDo t1, pToDo t2) { bool res = true; bool out = false; child_info chinf1, chinf2; chinf1 = t1->getChildInfo(); chinf2 = t2->getChildInfo(); for (int i = 0; i<16 && !out; i++) { switch (cmpOrder[i]) { /* Title */ case 't': if (t1->title != t2->title) { res = (t1->title < t2->title); out = true; } break; case 'T': if (t1->title != t2->title) { res = (t1->title > t2->title); out = true; } break; /* Done */ case 'd': if (t1->_done != t2->_done) { res = t2->_done; out = true; } else if (!t1->_done && (chinf1.percent == 100)) { res = false; out = true; } else if (!t2->_done && (chinf2.percent == 100)) { res = true; out = true; } break; case 'D': if (t1->_done != t2->_done) { res = t1->_done; out = true; } else if (!t1->_done && (chinf1.percent == 100)) { res = true; out = true; } else if (!t2->_done && (chinf2.percent == 100)) { res = false; out = true; } break; /* Deadline */ case 'l': if (chinf1.deadline != chinf2.deadline) { if (chinf1.deadline.valid()) res = (chinf1.deadline < chinf2.deadline); else res = false; out = true; } break; case 'L': if (chinf1.deadline != chinf2.deadline) { res = (chinf1.deadline > chinf2.deadline); out = true; } break; /* Priority */ case 'p': if (t1->_priority != t2->_priority) { int p1, p2; p1 = t1->_priority; p2 = t2->_priority; if (!p1) p1 = 6; if (!p2) p2 = 6; res=(p1 < p2); out = true; } break; case 'P': if (t1->_priority != t2->_priority) { res=(t1->_priority > t2->_priority); out = true; } break; /* Category */ case 'c': if (t1->_category != t2->_category) { if (t1->_category.empty()) res = false; else if (t2->_category.empty()) res = true; else res = (t1->getCategoriesStr()getCategoriesStr()); out = true; } break; case 'C': if (t1->_category != t2->_category) { if (t1->_category.empty()) res = true; else if (t2->_category.empty()) res = false; else res = (t1->getCategoriesStr()>t2->getCategoriesStr()); out = true; } break; /* Percent */ case 'e': if (chinf1.percent != chinf2.percent) { res = (chinf1.percent < chinf2.percent); out = true; } break; case 'E': if (chinf1.percent != chinf2.percent) { res = (chinf1.percent > chinf2.percent); out = true; } break; /* User */ case 'u': if (t1->_order != t2->_order) { res = (t1->_order < t2->_order); out = true; } break; case 'U': if (t1->_order != t2->_order) { res = (t1->_order > t2->_order); out = true; } break; } } return res; } void ToDo::_sort() { childs.sort(cmp); for (cursor_t i = childs.begin(); i != childs.end(); i++) { (*i)->_sort(); } } #define parent parents.top() iToDo::iToDo(ToDo& t) { root = &t; cursor = t.childs.begin(); parents.push(&t); } iToDo& iToDo::operator=(const iToDo& t) { path = t.path; parents = t.parents; cursor = t.cursor; return *this; } bool iToDo::operator==(const iToDo& t) { return (*t.cursor) == (*cursor); } bool iToDo::operator++() { if (!end()) { ++cursor; return true; } else { return false; } } bool iToDo::operator--() { if (!begin()) { --cursor; return true; } else { return false; } } bool iToDo::in() { if (!end()) { parents.push(*cursor); path.push(cursor); cursor = (*cursor)->childs.begin(); return true; } else { return false; } } bool iToDo::out() { if (!path.empty()) { cursor = path.top(); path.pop(); parents.pop(); return true; } else { return false; } } void iToDo::next() { in(); /* if there is no childs */ if (end()) { /* while is the end of the childs go to the parent and move forward */ while (end() && !path.empty()) { out(); operator++(); } /* if is the last task continue from the beginning */ if (end() && path.empty()) cursor = parent->childs.begin(); } } void iToDo::prev() { /* if is not the first child move up and go as deep as possible */ if (!begin()) { operator--(); while ((*cursor)->haveChild()) { in(); while (operator++()); operator--(); } } /* if is the first child go to the parent */ else { if (!out()) { cursor = parent->childs.end(); cursor--; while ((*cursor)->haveChild()) { in(); while (operator++()); operator--(); } } } } ToDo &iToDo::operator*() { if (!end()) return *(*cursor); else { return *(parent); } } ToDo *iToDo::operator->() { if (!end()) return *cursor; else { return parent; } } bool iToDo::end() { return ((parent->childs.end() == cursor) && (parent->childs.end()-- == cursor)); } bool iToDo::begin() { return (parent->childs.begin() == cursor); } int iToDo::percentUp() { return parent->getChildInfo().percent; } void iToDo::addChild(pToDo p) { if (!end()) { p->_order = (*cursor)->_order+1; ++cursor; for (cursor_t c = cursor; c != parent->childs.end(); c++) (*c)->_order++; } else { if (!begin()) { --cursor; p->_order = (*cursor)->_order+1; ++cursor; } else { p->_order = 0; } } cursor = parent->childs.insert(cursor, p); } void iToDo::addChildUp(pToDo p) { if (end() && begin()) { p->_order = 0; } else { p->_order = (*cursor)->_order; for (cursor_t c = cursor; c != parent->childs.end(); c++) (*c)->_order++; } cursor = parent->childs.insert(cursor, p); } void iToDo::del() { cursor = parent->childs.erase(cursor); /* if is the last task create an empty one */ if (end() && begin() && path.empty()) { addChild(new ToDo()); } } int iToDo::depth() { return path.size(); } void iToDo::sort(wstring order) { cmpOrder = order; if (cmpOrder.find(L'u') == wstring::npos) cmpOrder += L'u'; root->_sort(); } bool iToDo::search(wstring& str) { pToDo begin = *cursor; while (1) { next(); /* if the title contains str */ if ((*cursor)->title.find(str, 0) != wstring::npos) return true; /* if is the same as the beginning */ if (*cursor == begin) return false; } } bool iToDo::searchUp(wstring& str) { pToDo begin = *cursor; while (1) { prev(); /* if the title contains str */ if ((*cursor)->title.find(str, 0) != wstring::npos) return true; /* if is the same as the beginning */ if (*cursor == begin) return false; } } tudu-0.10.2/README0000644000175000017500000000224713121017272012152 0ustar useruserInstall ======= TuDu needs ncurses library with wide characters (in some systems is known as ncursesw) for work. You will need to install it for compile it. For compiling the program execute: $ ./configure $ make For installing the program execute (as root): # make install Usage ===== Usage: tudu [options] -f file load tudu file -c file load specific config file -v show version -h show this usage message The default config file is in ~/.tudurc The file tudurc in the source code is an example of config file. Notes ===== * Since version 0.8 the theme config deadlineMark now is call warn, because is not use just for the deadline is also use for the past sched. * Some environments (like Konsole of KDE3) don't show well the tasks that have childs. The normal way to show them is because they are bold, but in some shells the bold characters are indistinguishable of the normal ones. For that cases (or others) there is the posibility of show "(+)", for the collapsed tasks, and "(-)", for the expanded tasks, at the left of them. This option is activated on the config file by the option: [ general ] visual_tree = yes tudu-0.10.2/todo.xml0000644000175000017500000001216013121017272012754 0ustar useruser tmpnam warning interface.cc:770:15: warning: ignoring return value of ‘char* tmpnam(char*)’, declared with attribute warn_unused_result [-Wunused-result] interface.cc:773:17: warning: ignoring return value of ‘char* tmpnam(char*)’, declared with attribute warn_unused_result [-Wunused-result] split README for the package?? I would suggest to split installation information out of the README file and into README.install since that isn't useful for users of the binary packages. hyphen-used-as-minus-sign http://lintian.debian.org/tags/hyphen-used-as-minus-sign.html data/tudu.1:227 dangerous usage of char[] > [src/tudu.cc:96]: (error) Dangerous usage of 'file_rc' (strncpy doesn't always null-terminate it). > [src/tudu.cc:101]: (error) Dangerous usage of 'file_xml' (strncpy doesn't always null-terminate it). bfbtest > bfbtester: > > Several crashes like this: > > *** Crash </.../tudu-0.9.1/debian/tudu/usr/bin/tudu> *** > args: [10240] > envs: LANG=[10235] > Signal: 6 ( Aborted ) > Core? Yes Maybe the same than: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=716408 show category on the tudurc I use the commmand :showonly cat1 cat2 to see only this two categories. This works very fine. Is it possible to add this in .tudurc? Because i use the same .tudu.xml for home and office. And i want only to see office categories on my laptop and only home categories on the privat pc. command line interface for sort order or show info while press b one task two places cli interface cooerent editor and title import and export more filters (by project, keyword, date) more states for a task (undone, done, waiting, maybe, ...) dates in human format option for entering dates in "human" format like "2d", which will result in deadline date=today+2 days; 3w, 3m and so on. optional navigating throw tree with only "j" and "k" option for navigating through tree with only "j" and "k", so when cursor stands on a level 0 with with sub level, pressing j will lead to changing a cursor position to 0-1, then 0-2 and so on, probably the depth level of such behavior should be adjustable through config file time accounting How about a feature to log when I had spent time on it in the past, which is sporadic for my long long list of todo's. Such log can be amusing when looking back a few years down the road -- why did I spent that amount of time doing that !? Taskwarrior has some thoughts on it http://taskwarrior.org/boards/6/topics/79 Una de las prestaciones que no he encontrado en otros programas de gestión de tareas es sobre la duración de las tareas, poder decir el tiempo estimado que requiero para cada tarea, y que me avise si me saturo. En la versión en papel que empecé a usar (sin continuidad) solía poner la duración estimada de la tarea, pero claro el papel no me hacía la suma. Lo más interesante que encontré fuen en Lightning ó Mozilla Sunbird, donde en la agenda-calendario te marca los días en los que tienes tareas pendientes creo recordar. Además se puede poner el % que has realizado, y no recuerdo si también la duración estimada de cada tarea, pero cada dato se trata por separado, no se usa para facilitar la gestión del tiempo que es necesario reservar para las tareas. Es decir, sabiendo que para dentro de 2 días tengo que hacer 5 tareas que me llevaran Xi.%i tiempo en total, puedo saber si me va a dar tiempo ó no. En Lightning tienes la agenda, gestionas que no se solapen las citas, pero si en los huecos ocupados tienes tiempo justo para las tareas pendientes también debería ser razón para no poner una cita nueva. Pues eso, que podría ser una feature para TuDu que te avise de que el día tiene 24 horas (ó útiles para hacer tareas menos). deadline and scheduler with hour Add hour and minuts to the deadline date