From e54e881eeef211302821ec67791d690737d117e3 Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Mon, 31 Aug 2015 03:24:19 +0200 Subject: [PATCH] Initial import of DeforaOS Notes This is forked from DeforaOS Todo. --- .gitignore | 10 + COPYING | 25 ++ data/deforaos-notes.desktop | 10 + data/project.conf | 4 + po/.gitignore | 2 + po/POTFILES | 4 + po/es.po | 122 ++++++ po/fr.po | 122 ++++++ po/gettext.sh | 210 ++++++++++ po/project.conf | 19 + project.conf | 6 + src/.gitignore | 1 + src/main.c | 116 ++++++ src/note.c | 202 ++++++++++ src/note.h | 61 +++ src/noteedit.c | 163 ++++++++ src/noteedit.h | 47 +++ src/notes.c | 783 ++++++++++++++++++++++++++++++++++++ src/notes.h | 71 ++++ src/project.conf | 29 ++ src/window.c | 321 +++++++++++++++ src/window.h | 45 +++ tools/notes.c | 125 ++++++ tools/project.conf | 13 + 24 files changed, 2511 insertions(+) create mode 100644 .gitignore create mode 100644 COPYING create mode 100644 data/deforaos-notes.desktop create mode 100644 data/project.conf create mode 100644 po/.gitignore create mode 100644 po/POTFILES create mode 100644 po/es.po create mode 100644 po/fr.po create mode 100755 po/gettext.sh create mode 100644 po/project.conf create mode 100644 project.conf create mode 100644 src/.gitignore create mode 100644 src/main.c create mode 100644 src/note.c create mode 100644 src/note.h create mode 100644 src/noteedit.c create mode 100644 src/noteedit.h create mode 100644 src/notes.c create mode 100644 src/notes.h create mode 100644 src/project.conf create mode 100644 src/window.c create mode 100644 src/window.h create mode 100644 tools/notes.c create mode 100644 tools/project.conf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..29bf531 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +Makefile +/config.h +/config.sh +*~ +*.a +*.dll +*.dylib +*.o +*.so +*.so.* diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..3f2efae --- /dev/null +++ b/COPYING @@ -0,0 +1,25 @@ +Copyright (c) 2009-2015, Pierre Pronchery +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/data/deforaos-notes.desktop b/data/deforaos-notes.desktop new file mode 100644 index 0000000..a65ce83 --- /dev/null +++ b/data/deforaos-notes.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Name=DeforaOS Notes +GenericName=Notes +Comment=Keep a list of notes +TryExec=notes +Exec=notes +#Icon= +Type=Application +Categories=Office;GTK; +StartupNotify=true diff --git a/data/project.conf b/data/project.conf new file mode 100644 index 0000000..4d95de6 --- /dev/null +++ b/data/project.conf @@ -0,0 +1,4 @@ +dist=Makefile,deforaos-notes.desktop + +[deforaos-notes.desktop] +install=$(PREFIX)/share/applications diff --git a/po/.gitignore b/po/.gitignore new file mode 100644 index 0000000..ec762cb --- /dev/null +++ b/po/.gitignore @@ -0,0 +1,2 @@ +/Notes.pot +/*.mo diff --git a/po/POTFILES b/po/POTFILES new file mode 100644 index 0000000..44b87e0 --- /dev/null +++ b/po/POTFILES @@ -0,0 +1,4 @@ +../src/main.c +../src/noteedit.c +../src/notes.c +../src/window.c diff --git a/po/es.po b/po/es.po new file mode 100644 index 0000000..40fde47 --- /dev/null +++ b/po/es.po @@ -0,0 +1,122 @@ +# $Id$ +# Copyright (c) 2015 Pierre Pronchery +# This file is distributed under the same license as the Notes package. +# +msgid "" +msgstr "" +"Project-Id-Version: Notes 0.0.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-08-31 03:17+0200\n" +"PO-Revision-Date: 2015-04-21 00:54+0200\n" +"Last-Translator: Ana Carolina Rocha \n" +"Language-Team: Spanish\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../src/main.c:90 +#, c-format +msgid "Usage: %s\n" +msgstr "Usage: %s\n" + +#: ../src/noteedit.c:76 +msgid "Edit note: " +msgstr "Editar nota: " + +#: ../src/noteedit.c:86 +msgid "Title:" +msgstr "Título:" + +#: ../src/noteedit.c:95 +msgid "Description:" +msgstr "Descripción:" + +#: ../src/notes.c:113 +msgid "Title" +msgstr "Título" + +#: ../src/notes.c:128 ../src/notes.c:363 +msgid "New note" +msgstr "Nueva nota" + +#: ../src/notes.c:129 +msgid "Edit note" +msgstr "Editar nota" + +#: ../src/notes.c:133 ../src/notes.c:136 +msgid "Select all" +msgstr "Seleccionar todo" + +#: ../src/notes.c:139 +msgid "Delete note" +msgstr "Eliminar nota" + +#: ../src/notes.c:143 +msgid "Preferences" +msgstr "Preferencias" + +#: ../src/notes.c:281 +msgid "Notes for the DeforaOS desktop" +msgstr "Administrador de notas para el escritorio de DeforaOS" + +#: ../src/notes.c:287 +msgid "translator-credits" +msgstr "Ana Carolina Rocha " + +#: ../src/notes.c:317 ../src/notes.c:322 +msgid "Error" +msgstr "Error" + +#: ../src/notes.c:392 +msgid "Are you sure you want to delete the selected note(s)?" +msgstr "Está seguro que desea eliminar la(s) nota(s) seleccionada(s)?" + +#: ../src/notes.c:597 ../src/notes.c:602 +msgid "Question" +msgstr "Pregunta" + +#: ../src/window.c:102 +msgid "_New" +msgstr "_Nuevo" + +#: ../src/window.c:104 ../src/window.c:143 +msgid "_Edit" +msgstr "_Editar" + +#: ../src/window.c:107 +msgid "_Close" +msgstr "_Cerrar" + +#: ../src/window.c:113 +msgid "Select _All" +msgstr "Seleccionar _todo" + +#: ../src/window.c:121 +msgid "_Delete" +msgstr "_Eliminar tarea" + +#: ../src/window.c:124 +msgid "_Preferences" +msgstr "_Preferencias" + +#: ../src/window.c:130 +msgid "_Contents" +msgstr "_Contenidos" + +#: ../src/window.c:132 +msgid "_About" +msgstr "Acerca _de" + +#: ../src/window.c:142 +msgid "_File" +msgstr "_Archivo" + +#: ../src/window.c:144 +msgid "_Help" +msgstr "_Ayuda" + +#: ../src/window.c:179 +msgid "Notes" +msgstr "Notas" diff --git a/po/fr.po b/po/fr.po new file mode 100644 index 0000000..675bdf0 --- /dev/null +++ b/po/fr.po @@ -0,0 +1,122 @@ +# $Id$ +# Copyright (c) 2015 Pierre Pronchery +# This file is distributed under the same license as the Notes package. +# +msgid "" +msgstr "" +"Project-Id-Version: Notes 0.0.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-08-31 03:17+0200\n" +"PO-Revision-Date: 2010-04-23 14:35+0200\n" +"Last-Translator: Pierre Pronchery \n" +"Language-Team: French\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: ../src/main.c:90 +#, c-format +msgid "Usage: %s\n" +msgstr "Usage: %s\n" + +#: ../src/noteedit.c:76 +msgid "Edit note: " +msgstr "Modifier la note : " + +#: ../src/noteedit.c:86 +msgid "Title:" +msgstr "Titre:" + +#: ../src/noteedit.c:95 +msgid "Description:" +msgstr "Description:" + +#: ../src/notes.c:113 +msgid "Title" +msgstr "Titre" + +#: ../src/notes.c:128 ../src/notes.c:363 +msgid "New note" +msgstr "Nouvelle note" + +#: ../src/notes.c:129 +msgid "Edit note" +msgstr "Modifier la note" + +#: ../src/notes.c:133 ../src/notes.c:136 +msgid "Select all" +msgstr "Sélectionner tout" + +#: ../src/notes.c:139 +msgid "Delete note" +msgstr "Supprimer la note" + +#: ../src/notes.c:143 +msgid "Preferences" +msgstr "Préférences" + +#: ../src/notes.c:281 +msgid "Notes for the DeforaOS desktop" +msgstr "Gestionnaire de notes pour l'environnement DeforaOS" + +#: ../src/notes.c:287 +msgid "translator-credits" +msgstr "Pierre Pronchery " + +#: ../src/notes.c:317 ../src/notes.c:322 +msgid "Error" +msgstr "Erreur" + +#: ../src/notes.c:392 +msgid "Are you sure you want to delete the selected note(s)?" +msgstr "Voulez-vous vraiment supprimer la sélection?" + +#: ../src/notes.c:597 ../src/notes.c:602 +msgid "Question" +msgstr "Question" + +#: ../src/window.c:102 +msgid "_New" +msgstr "_Nouvelle tâche" + +#: ../src/window.c:104 ../src/window.c:143 +msgid "_Edit" +msgstr "É_dition" + +#: ../src/window.c:107 +msgid "_Close" +msgstr "_Fermer" + +#: ../src/window.c:113 +msgid "Select _All" +msgstr "Sélectionner _tout" + +#: ../src/window.c:121 +msgid "_Delete" +msgstr "_Supprimer" + +#: ../src/window.c:124 +msgid "_Preferences" +msgstr "_Préférences" + +#: ../src/window.c:130 +msgid "_Contents" +msgstr "_Sommaire" + +#: ../src/window.c:132 +msgid "_About" +msgstr "À _propos" + +#: ../src/window.c:142 +msgid "_File" +msgstr "_Fichier" + +#: ../src/window.c:144 +msgid "_Help" +msgstr "_Aide" + +#: ../src/window.c:179 +msgid "Notes" +msgstr "Notes" diff --git a/po/gettext.sh b/po/gettext.sh new file mode 100755 index 0000000..bf53b2b --- /dev/null +++ b/po/gettext.sh @@ -0,0 +1,210 @@ +#!/bin/sh +#$Id$ +#Copyright (c) 2010-2015 Pierre Pronchery +# +#Redistribution and use in source and binary forms, with or without +#modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +#DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +#FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +#DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +#SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +#CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +#OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +#OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +#variables +PREFIX="/usr/local" +[ -f "../config.sh" ] && . "../config.sh" +LOCALEDIR="$PREFIX/share/locale" +POTFILES="POTFILES" +PROGNAME="gettext.sh" +#executables +DEBUG="_debug" +INSTALL="install -m 0644" +MKDIR="mkdir -p" +MSGFMT="msgfmt" +MSGINIT="msginit" +MSGMERGE="msgmerge" +RM="rm -f" +XGETTEXT="xgettext --force-po" + + +#functions +#debug +_debug() +{ + echo "$@" 1>&2 + "$@" +} + + +#error +_error() +{ + echo "$PROGNAME: $@" 1>&2 + return 2 +} + + +#usage +_usage() +{ + echo "Usage: $PROGNAME [-c|-i|-u][-P prefix] target..." 1>&2 + return 1 +} + + +#gettext_mo +_gettext_mo() +{ + package="$1" + lang="$2" + potfile="$3" + pofile="$4" + mofile="$5" + + _gettext_po "$package" "$lang" "$potfile" "$pofile" || return 1 + $DEBUG $MSGFMT -c -v -o "$mofile" "$pofile" || return 1 +} + + +#gettext_po +_gettext_po() +{ + package="$1" + lang="$2" + potfile="$3" + pofile="$4" + + if [ -f "$pofile" ]; then + $DEBUG $MSGMERGE -U "$pofile" "$potfile" || return 1 + else + $DEBUG $MSGINIT -l "$lang" -o "$pofile" -i "$potfile" \ + || return 1 + fi +} + + +#gettext_pot +_gettext_pot() +{ + package="$1" + potfile="$2" + + $DEBUG $XGETTEXT -d "$package" -o "$potfile" --keyword="_" \ + --keyword="N_" -f "$POTFILES" || return 1 +} + + +#main +clean=0 +install=0 +uninstall=0 +while getopts "ciuP:" name; do + case "$name" in + c) + clean=1 + ;; + i) + uninstall=0 + install=1 + ;; + u) + install=0 + uninstall=1 + ;; + P) + PREFIX="$OPTARG" + ;; + ?) + _usage + exit $? + ;; + esac +done +shift $(($OPTIND - 1)) +if [ $# -eq 0 ]; then + _usage + exit $? +fi + +#check the variables +if [ -z "$PACKAGE" ]; then + _error "The PACKAGE variable needs to be set" + exit $? +fi + +LOCALEDIR="$PREFIX/share/locale" +while [ $# -gt 0 ]; do + target="$1" + source="${target#$OBJDIR}" + lang="${source%%.mo}" + lang="${lang%%.po}" + shift + + #clean + [ "$clean" -ne 0 ] && continue + + #uninstall + if [ "$uninstall" -eq 1 ]; then + $DEBUG $RM "$LOCALEDIR/$lang/LC_MESSAGES/$PACKAGE.mo" \ + || exit 2 + continue + fi + + #install + if [ "$install" -eq 1 ]; then + $DEBUG $MKDIR "$LOCALEDIR/$lang/LC_MESSAGES" || exit 2 + $DEBUG $INSTALL "$target" \ + "$LOCALEDIR/$lang/LC_MESSAGES/$PACKAGE.mo" \ + || exit 2 + continue + fi + + #create + case "$target" in + *.mo) + #XXX may not match + if [ -n "$OBJDIR" ]; then + potfile="$OBJDIR/$PACKAGE.pot" + else + potfile="$PACKAGE.pot" + fi + mofile="$target" + pofile="${source%%.mo}.po" + _gettext_mo "$PACKAGE" "$lang" "$potfile" "$pofile" \ + "$mofile" || exit 2 + ;; + *.po) + #XXX may not match + if [ -n "$OBJDIR" ]; then + potfile="$OBJDIR/$PACKAGE.pot" + else + potfile="$PACKAGE.pot" + fi + pofile="$target" + _gettext_po "$PACKAGE" "$lang" "$potfile" "$pofile" \ + || exit 2 + ;; + *.pot) + package="${source%%.pot}" + potfile="$target" + _gettext_pot "$package" "$potfile" || exit 2 + ;; + *) + exit 2 + ;; + esac +done diff --git a/po/project.conf b/po/project.conf new file mode 100644 index 0000000..3b9db83 --- /dev/null +++ b/po/project.conf @@ -0,0 +1,19 @@ +targets=Notes.pot,es.mo,fr.mo +dist=Makefile,gettext.sh,POTFILES,es.po,fr.po + +[Notes.pot] +type=script +script=./gettext.sh +depends=POTFILES + +[es.mo] +type=script +script=./gettext.sh +install= +depends=$(OBJDIR)Notes.pot,es.po + +[fr.mo] +type=script +script=./gettext.sh +install= +depends=$(OBJDIR)Notes.pot,fr.po diff --git a/project.conf b/project.conf new file mode 100644 index 0000000..d1d7dcc --- /dev/null +++ b/project.conf @@ -0,0 +1,6 @@ +package=Notes +version=0.0.0 +config=h,sh + +subdirs=data,po,src,tools +dist=Makefile,COPYING,config.h,config.sh diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..f7e4b7e --- /dev/null +++ b/src/.gitignore @@ -0,0 +1 @@ +/notes diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..4998504 --- /dev/null +++ b/src/main.c @@ -0,0 +1,116 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Notes */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#include +#include +#include +#include +#include +#include +#include "window.h" +#include "../config.h" +#define _(string) gettext(string) + +/* constants */ +#ifndef PROGNAME +# define PROGNAME "notes" +#endif +#ifndef PREFIX +# define PREFIX "/usr/local" +#endif +#ifndef DATADIR +# define DATADIR PREFIX "/share" +#endif +#ifndef LOCALEDIR +# define LOCALEDIR DATADIR "/locale" +#endif + + +/* private */ +/* prototypes */ +static int _notes(void); + +static int _error(char const * message, int ret); +static int _usage(void); + + +/* functions */ +/* notes */ +static int _notes(void) +{ + NotesWindow * notes; + + if((notes = noteswindow_new()) == NULL) + return error_print(PACKAGE); + gtk_main(); + noteswindow_delete(notes); + return 0; +} + + +/* error */ +static int _error(char const * message, int ret) +{ + fputs(PROGNAME ": ", stderr); + perror(message); + return ret; +} + + +/* usage */ +static int _usage(void) +{ + fprintf(stderr, _("Usage: %s\n"), PROGNAME); + return 1; +} + + +/* public */ +/* functions */ +/* main */ +int main(int argc, char * argv[]) +{ + int o; + + if(setlocale(LC_ALL, "") == NULL) + _error("setlocale", 1); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + gtk_init(&argc, &argv); + while((o = getopt(argc, argv, "")) != -1) + switch(o) + { + default: + return _usage(); + } + if(optind != argc) + return _usage(); + return (_notes() == 0) ? 0 : 2; +} diff --git a/src/note.c b/src/note.c new file mode 100644 index 0000000..9b1dfb3 --- /dev/null +++ b/src/note.c @@ -0,0 +1,202 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Notes */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#include +#include +#include +#include +#include +#include "note.h" + + +/* Note */ +/* private */ +/* types */ +struct _Note +{ + Config * config; + + /* internal */ + char * filename; + String * description; +}; + + +/* public */ +/* functions */ +/* note_new */ +Note * note_new(void) +{ + Note * note; + + if((note = object_new(sizeof(*note))) == NULL) + return NULL; + note->config = config_new(); + note->filename = NULL; + note->description = NULL; + if(note->config == NULL) + { + note_delete(note); + return NULL; + } + return note; +} + + +/* note_new_from_file */ +Note * note_new_from_file(char const * filename) +{ + Note * note; + + if((note = note_new()) == NULL) + return NULL; + if(note_set_filename(note, filename) != 0 + || note_load(note) != 0) + { + note_delete(note); + return NULL; + } + return note; +} + + +/* note_delete */ +void note_delete(Note * note) +{ + string_delete(note->description); + free(note->filename); + if(note->config != NULL) + config_delete(note->config); + object_delete(note); +} + + +/* accessors */ +/* note_get_description */ +char const * note_get_description(Note * note) +{ + String const * p; + String * q; + + if(note->description != NULL) + return note->description; + if((p = config_get(note->config, NULL, "description")) == NULL) + return ""; + if((q = string_new_replace(p, "\\n", "\n")) == NULL + || string_replace(&q, "\\\\", "\\") != 0) + return NULL; + note->description = q; + return note->description; +} + + +/* note_get_filename */ +char const * note_get_filename(Note * note) +{ + return note->filename; +} + + +/* note_get_title */ +char const * note_get_title(Note * note) +{ + char const * ret; + + if((ret = config_get(note->config, NULL, "title")) == NULL) + return ""; + return ret; +} + + +/* note_set_description */ +int note_set_description(Note * note, char const * description) +{ + String * d; + + if((d = string_new_replace(description, "\\", "\\\\")) == NULL) + return -1; + if(string_replace(&d, "\n", "\\n") != 0 + || config_set(note->config, NULL, "description", d) + != 0) + { + string_delete(d); + return -1; + } + string_delete(note->description); + note->description = d; + return 0; +} + + +/* note_set_filename */ +int note_set_filename(Note * note, char const * filename) +{ + char * p; + + if((p = strdup(filename)) == NULL) + return -1; /* XXX set error */ + free(note->filename); + note->filename = p; + return 0; +} + + +/* note_set_title */ +int note_set_title(Note * note, char const * title) +{ + return config_set(note->config, NULL, "title", title); +} + + +/* useful */ +/* note_load */ +int note_load(Note * note) +{ + config_reset(note->config); + return config_load(note->config, note->filename); +} + + +/* note_save */ +int note_save(Note * note) +{ + if(note->filename == NULL) + return -1; /* XXX set error */ + return config_save(note->config, note->filename); +} + + +/* note_unlink */ +int note_unlink(Note * note) +{ + if(note->filename == NULL) + return -1; /* XXX set error */ + return unlink(note->filename); +} diff --git a/src/note.h b/src/note.h new file mode 100644 index 0000000..944d457 --- /dev/null +++ b/src/note.h @@ -0,0 +1,61 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Notes */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#ifndef NOTES_NOTE_H +# define NOTES_NOTE_H + + +/* Note */ +/* types */ +typedef struct _Note Note; + + +/* functions */ +Note * note_new(void); +Note * note_new_from_file(char const * filename); +void note_delete(Note * note); + + +/* accessors */ +char const * note_get_description(Note * note); +char const * note_get_filename(Note * note); +char const * note_get_title(Note * note); + +int note_set_description(Note * note, char const * description); +int note_set_filename(Note * note, char const * filename); +int note_set_title(Note * note, char const * title); + + +/* useful */ +int note_load(Note * note); +int note_save(Note * note); +int note_unlink(Note * note); + +#endif /* !NOTES_NOTE_H */ diff --git a/src/noteedit.c b/src/noteedit.c new file mode 100644 index 0000000..280230d --- /dev/null +++ b/src/noteedit.c @@ -0,0 +1,163 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Notes */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#include +#include +#include +#include "noteedit.h" +#define _(string) gettext(string) + + +/* NoteEdit */ +/* private */ +/* types */ +struct _NoteEdit +{ + Notes * notes; + Note * note; + + /* widgets */ + GtkWidget * window; + GtkWidget * title; + GtkWidget * description; +}; + + +/* public */ +/* functions */ +/* note_new */ +static void _on_noteedit_cancel(gpointer data); +static void _on_noteedit_ok(gpointer data); + +NoteEdit * noteedit_new(Notes * notes, Note * note) +{ + NoteEdit * noteedit; + char buf[80]; + GtkSizeGroup * group; + GtkWidget * vbox; + GtkWidget * hbox; + GtkWidget * widget; + GtkWidget * bbox; + GtkWidget * scrolled; + char const * description; + + if((noteedit = malloc(sizeof(*noteedit))) == NULL) + return NULL; + noteedit->notes = notes; + noteedit->note = note; + noteedit->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + snprintf(buf, sizeof(buf), "%s%s", _("Edit note: "), note_get_title( + note)); + gtk_window_set_default_size(GTK_WINDOW(noteedit->window), 300, 400); + gtk_window_set_title(GTK_WINDOW(noteedit->window), buf); + g_signal_connect_swapped(noteedit->window, "delete-event", G_CALLBACK( + _on_noteedit_cancel), noteedit); + group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + vbox = gtk_vbox_new(FALSE, 4); + /* title */ + hbox = gtk_hbox_new(FALSE, 4); + widget = gtk_label_new(_("Title:")); + gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5); + gtk_size_group_add_widget(group, widget); + gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); + noteedit->title = gtk_entry_new(); + gtk_entry_set_text(GTK_ENTRY(noteedit->title), note_get_title(note)); + gtk_box_pack_start(GTK_BOX(hbox), noteedit->title, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); + /* description */ + widget = gtk_label_new(_("Description:")); + gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5); + gtk_size_group_add_widget(group, widget); + gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0); + scrolled = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), + GTK_SHADOW_IN); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + noteedit->description = gtk_text_view_new(); + if((description = note_get_description(note)) != NULL) + gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW( + noteedit->description)), + description, -1); + gtk_container_add(GTK_CONTAINER(scrolled), noteedit->description); + gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 0); + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); + gtk_box_set_spacing(GTK_BOX(bbox), 4); + widget = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + g_signal_connect_swapped(widget, "clicked", G_CALLBACK( + _on_noteedit_cancel), noteedit); + gtk_container_add(GTK_CONTAINER(bbox), widget); + widget = gtk_button_new_from_stock(GTK_STOCK_OK); + g_signal_connect_swapped(widget, "clicked", G_CALLBACK(_on_noteedit_ok), + noteedit); + gtk_container_add(GTK_CONTAINER(bbox), widget); + gtk_box_pack_end(GTK_BOX(vbox), bbox, FALSE, TRUE, 0); + gtk_container_set_border_width(GTK_CONTAINER(noteedit->window), 4); + gtk_container_add(GTK_CONTAINER(noteedit->window), vbox); + gtk_widget_show_all(noteedit->window); + return noteedit; +} + +static void _on_noteedit_cancel(gpointer data) +{ + NoteEdit * noteedit = data; + + noteedit_delete(noteedit); +} + +static void _on_noteedit_ok(gpointer data) +{ + NoteEdit * noteedit = data; + GtkTextBuffer * tbuf; + GtkTextIter start; + GtkTextIter end; + gchar * description; + + note_set_title(noteedit->note, gtk_entry_get_text(GTK_ENTRY( + noteedit->title))); + tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(noteedit->description)); + gtk_text_buffer_get_start_iter(tbuf, &start); + gtk_text_buffer_get_end_iter(tbuf, &end); + description = gtk_text_buffer_get_text(tbuf, &start, &end, FALSE); + note_set_description(noteedit->note, description); + g_free(description); + note_save(noteedit->note); + notes_note_reload_all(noteedit->notes); /* XXX violent solution */ + _on_noteedit_cancel(noteedit); +} + + +/* noteedit_delete */ +void noteedit_delete(NoteEdit * noteedit) +{ + gtk_widget_destroy(noteedit->window); + free(noteedit); +} diff --git a/src/noteedit.h b/src/noteedit.h new file mode 100644 index 0000000..46c6278 --- /dev/null +++ b/src/noteedit.h @@ -0,0 +1,47 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Notes */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#ifndef NOTES_NOTEEDIT_H +# define NOTES_NOTEEDIT_H + +# include "note.h" +# include "notes.h" + + +/* NoteEdit */ +/* types */ +typedef struct _NoteEdit NoteEdit; + + +/* functions */ +NoteEdit * noteedit_new(Notes * notes, Note * note); +void noteedit_delete(NoteEdit * noteedit); + +#endif /* !NOTES_NOTEEDIT_H */ diff --git a/src/notes.c b/src/notes.c new file mode 100644 index 0000000..e81bdea --- /dev/null +++ b/src/notes.c @@ -0,0 +1,783 @@ +/* $Id$ */ +static char _copyright[] = +"Copyright © 2015 Pierre Pronchery "; +/* This file is part of DeforaOS Desktop Notes */ +static char const _license[] = "All rights reserved.\n" +"\n" +"Redistribution and use in source and binary forms, with or without\n" +"modification, are permitted provided that the following conditions are\n" +"met:\n" +"\n" +"1. Redistributions of source code must retain the above copyright\n" +" notice, this list of conditions and the following disclaimer.\n" +"\n" +"2. Redistributions in binary form must reproduce the above copyright\n" +" notice, this list of conditions and the following disclaimer in the\n" +" documentation and/or other materials provided with the distribution.\n" +"\n" +"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS\n" +"IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\n" +"TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\n" +"PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n" +"HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n" +"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED\n" +"TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n" +"PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n" +"LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n" +"NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n" +"SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."; +/* TODO: + * - add a clear/apply button (allocate a temporary object) */ + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "noteedit.h" +#include "notes.h" +#include "../config.h" +#define _(string) gettext(string) +#define N_(string) (string) + + +/* Notes */ +/* private */ +/* types */ +typedef enum _NotesColumn +{ + ND_COL_NOTE, ND_COL_TITLE, ND_COL_CATEGORY +} NotesColumn; +#define ND_COL_LAST ND_COL_CATEGORY +#define ND_COL_COUNT (ND_COL_LAST + 1) + +struct _Notes +{ + GtkWidget * window; + GtkWidget * widget; + GtkWidget * scrolled; + GtkListStore * store; + GtkListStore * priorities; + GtkTreeModel * filter; + GtkTreeModel * filter_sort; + GtkWidget * view; + GtkTreeViewColumn * columns[ND_COL_COUNT]; + GtkWidget * about; +}; + + +/* prototypes */ +static int _notes_confirm(GtkWidget * window, char const * message); +static gboolean _notes_get_iter(Notes * notes, GtkTreeIter * iter, + GtkTreePath * path); +static char * _notes_note_get_directory(void); +static char * _notes_note_get_filename(char const * filename); +static char * _notes_note_get_new_filename(void); +static void _notes_note_save(Notes * notes, GtkTreeIter * iter); + +/* callbacks */ +/* toolbar */ +static void _notes_on_new(gpointer data); +static void _notes_on_edit(gpointer data); +static void _notes_on_select_all(gpointer data); +static void _notes_on_delete(gpointer data); +#ifdef EMBEDDED +static void _notes_on_preferences(gpointer data); +#endif + +/* view */ +static void _notes_on_note_activated(gpointer data); +static void _notes_on_note_cursor_changed(gpointer data); +static void _notes_on_note_title_edited(GtkCellRendererText * renderer, + gchar * path, gchar * title, gpointer data); + + +/* constants */ +static const struct +{ + int col; + char const * title; + int sort; + GCallback callback; +} _notes_columns[] = +{ + { ND_COL_TITLE, N_("Title"), ND_COL_TITLE, G_CALLBACK( + _notes_on_note_title_edited) }, + { 0, NULL, 0, NULL } +}; + + +static char const * _authors[] = +{ + "Pierre Pronchery ", + NULL +}; + +/* toolbar */ +static DesktopToolbar _toolbar[] = +{ + { N_("New note"), G_CALLBACK(_notes_on_new), GTK_STOCK_NEW, 0, 0, NULL }, + { N_("Edit note"), G_CALLBACK(_notes_on_edit), GTK_STOCK_EDIT, 0, 0, + NULL }, + { "", NULL, NULL, 0, 0, NULL }, +#if GTK_CHECK_VERSION(2, 10, 0) + { N_("Select all"), G_CALLBACK(_notes_on_select_all), + GTK_STOCK_SELECT_ALL, 0, 0, NULL }, +#else + { N_("Select all"), G_CALLBACK(_notes_on_select_all), "edit-select-all", + 0, 0, NULL }, +#endif + { N_("Delete note"), G_CALLBACK(_notes_on_delete), GTK_STOCK_DELETE, 0, + 0, NULL }, +#ifdef EMBEDDED + { "", NULL, NULL, 0, 0, NULL }, + { N_("Preferences"), G_CALLBACK(_notes_on_preferences), + GTK_STOCK_PREFERENCES, 0, 0, NULL }, +#endif + { "", NULL, NULL, 0, 0, NULL }, + { NULL, NULL, NULL, 0, 0, NULL } +}; + + +/* public */ +/* functions */ +/* notes_new */ +static void _new_view(Notes * notes); +static gboolean _new_idle(gpointer data); + +Notes * notes_new(GtkWidget * window, GtkAccelGroup * group) +{ + Notes * notes; + GtkWidget * vbox; + GtkWidget * widget; + + if((notes = object_new(sizeof(*notes))) == NULL) + return NULL; + /* main window */ + notes->window = window; + vbox = gtk_vbox_new(FALSE, 0); + notes->widget = vbox; + /* toolbar */ + widget = desktop_toolbar_create(_toolbar, notes, group); + gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0); + /* view */ + notes->scrolled = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(notes->scrolled), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + _new_view(notes); + gtk_box_pack_start(GTK_BOX(vbox), notes->scrolled, TRUE, TRUE, 0); + notes->about = NULL; + g_idle_add(_new_idle, notes); + return notes; +} + +static void _new_view(Notes * notes) +{ + size_t i; + GtkTreeSelection * sel; + GtkCellRenderer * renderer; + GtkTreeViewColumn * column; + + notes->store = gtk_list_store_new(ND_COL_COUNT, + G_TYPE_POINTER, /* note */ + G_TYPE_STRING, /* title */ + G_TYPE_STRING); /* category */ + /* XXX get rid of filter? */ + notes->filter = gtk_tree_model_filter_new(GTK_TREE_MODEL(notes->store), + NULL); + notes->filter_sort = gtk_tree_model_sort_new_with_model(notes->filter); + notes->view = gtk_tree_view_new_with_model(GTK_TREE_MODEL( + notes->filter_sort)); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(notes->view), TRUE); + if((sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(notes->view))) + != NULL) + gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE); + g_signal_connect_swapped(notes->view, "cursor-changed", G_CALLBACK( + _notes_on_note_cursor_changed), notes); + g_signal_connect_swapped(notes->view, "row-activated", G_CALLBACK( + _notes_on_note_activated), notes); + /* columns */ + memset(¬es->columns, 0, sizeof(notes->columns)); + for(i = 0; _notes_columns[i].title != NULL; i++) + { + renderer = gtk_cell_renderer_text_new(); + if(_notes_columns[i].callback != NULL) + { + g_object_set(G_OBJECT(renderer), "editable", TRUE, + "ellipsize", PANGO_ELLIPSIZE_END, NULL); + g_signal_connect(renderer, "edited", G_CALLBACK( + _notes_columns[i].callback), + notes); + } + column = gtk_tree_view_column_new_with_attributes( + _(_notes_columns[i].title), renderer, "text", + _notes_columns[i].col, NULL); + notes->columns[_notes_columns[i].col] = column; +#if GTK_CHECK_VERSION(2, 4, 0) + gtk_tree_view_column_set_expand(column, TRUE); +#endif + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_column_set_sort_column_id(column, + _notes_columns[i].sort); + gtk_tree_view_append_column(GTK_TREE_VIEW(notes->view), column); + } + gtk_tree_view_column_set_sort_column_id(column, ND_COL_TITLE); + gtk_container_add(GTK_CONTAINER(notes->scrolled), notes->view); + gtk_tree_view_append_column(GTK_TREE_VIEW(notes->view), column); +} + +static gboolean _new_idle(gpointer data) +{ + Notes * notes = data; + + notes_note_reload_all(notes); + return FALSE; +} + + +/* notes_delete */ +void notes_delete(Notes * notes) +{ + notes_note_save_all(notes); + notes_note_remove_all(notes); + free(notes); + object_delete(notes); +} + + +/* accessors */ +/* notes_get_widget */ +GtkWidget * notes_get_widget(Notes * notes) +{ + return notes->widget; +} + + +/* useful */ +/* notes_about */ +static gboolean _about_on_closex(gpointer data); + +void notes_about(Notes * notes) +{ + if(notes->about != NULL) + { + gtk_widget_show(notes->about); + return; + } + notes->about = desktop_about_dialog_new(); + gtk_window_set_transient_for(GTK_WINDOW(notes->about), + GTK_WINDOW(notes->window)); + desktop_about_dialog_set_authors(notes->about, _authors); + desktop_about_dialog_set_comments(notes->about, + _("Notes for the DeforaOS desktop")); + desktop_about_dialog_set_copyright(notes->about, _copyright); + desktop_about_dialog_set_logo_icon_name(notes->about, "notes"); + desktop_about_dialog_set_license(notes->about, _license); + desktop_about_dialog_set_program_name(notes->about, PACKAGE); + desktop_about_dialog_set_translator_credits(notes->about, + _("translator-credits")); + desktop_about_dialog_set_version(notes->about, VERSION); + desktop_about_dialog_set_website(notes->about, "http://www.defora.org/"); + g_signal_connect_swapped(notes->about, "delete-event", G_CALLBACK( + _about_on_closex), notes); + gtk_widget_show(notes->about); +} + +static gboolean _about_on_closex(gpointer data) +{ + Notes * notes = data; + + gtk_widget_hide(notes->about); + return TRUE; +} + + +/* notes_error */ +static int _error_text(char const * message, int ret); + +int notes_error(Notes * notes, char const * message, int ret) +{ + GtkWidget * dialog; + + if(notes == NULL) + return _error_text(message, ret); + dialog = gtk_message_dialog_new(GTK_WINDOW(notes->window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", +#if GTK_CHECK_VERSION(2, 8, 0) + _("Error")); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), + "%s", +#endif + message); + gtk_window_set_title(GTK_WINDOW(dialog), _("Error")); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + return ret; +} + +static int _error_text(char const * message, int ret) +{ + fputs(PACKAGE ": ", stderr); + fputs(message, stderr); + fputc('\n', stderr); + return ret; +} + + +/* notes_show_preferences */ +void notes_show_preferences(Notes * notes, gboolean show) +{ + /* FIXME implement */ +} + + +/* notes */ +/* notes_note_add */ +Note * notes_note_add(Notes * notes, Note * note) +{ + GtkTreeIter iter; + char * filename; + + if(note == NULL) + { + if((note = note_new()) == NULL) + return NULL; + if((filename = _notes_note_get_new_filename()) == NULL) + { + notes_error(notes, error_get(), 0); + note_delete(note); + return NULL; + } + note_set_filename(note, filename); + free(filename); + note_set_title(note, _("New note")); + note_save(note); + } + gtk_list_store_insert(notes->store, &iter, 0); + gtk_list_store_set(notes->store, &iter, ND_COL_NOTE, note, + ND_COL_TITLE, note_get_title(note), -1); + return note; +} + + +/* notes_note_delete_selected */ +static void _note_delete_selected_foreach(GtkTreeRowReference * reference, + Notes * notes); + +void notes_note_delete_selected(Notes * notes) +{ + GtkTreeSelection * treesel; + GList * selected; + GtkTreeModel * model = GTK_TREE_MODEL(notes->store); + GtkTreeRowReference * reference; + GList * s; + GtkTreePath * path; + + if((treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(notes->view))) + == NULL) + return; + if((selected = gtk_tree_selection_get_selected_rows(treesel, NULL)) + == NULL) + return; + if(_notes_confirm(notes->window, _("Are you sure you want to delete the" + " selected note(s)?")) != 0) + return; + for(s = g_list_first(selected); s != NULL; s = g_list_next(s)) + { + if((path = s->data) == NULL) + continue; + reference = gtk_tree_row_reference_new(model, path); + s->data = reference; + gtk_tree_path_free(path); + } + g_list_foreach(selected, (GFunc)_note_delete_selected_foreach, notes); + g_list_free(selected); +} + +static void _note_delete_selected_foreach(GtkTreeRowReference * reference, + Notes * notes) +{ + GtkTreeModel * model = GTK_TREE_MODEL(notes->store); + GtkTreePath * path; + GtkTreeIter iter; + Note * note; + + if(reference == NULL) + return; + if((path = gtk_tree_row_reference_get_path(reference)) == NULL) + return; + if(_notes_get_iter(notes, &iter, path) == TRUE) + { + gtk_tree_model_get(model, &iter, ND_COL_NOTE, ¬e, -1); + note_unlink(note); + note_delete(note); + } + gtk_list_store_remove(notes->store, &iter); + gtk_tree_path_free(path); +} + + +/* notes_note_cursor_changed */ +void notes_note_cursor_changed(Notes * notes) +{ + GtkTreeModel * model = GTK_TREE_MODEL(notes->store); + GtkTreePath * path = NULL; + GtkTreeViewColumn * column = NULL; + GtkTreeIter iter; + Note * note = NULL; + gint id = -1; + + gtk_tree_view_get_cursor(GTK_TREE_VIEW(notes->view), &path, &column); + if(path == NULL) + return; + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, ND_COL_NOTE, ¬e, -1); + if(column != NULL) + id = gtk_tree_view_column_get_sort_column_id(column); + gtk_tree_path_free(path); +} + + +/* notes_note_edit */ +void notes_note_edit(Notes * notes) +{ + GtkTreeSelection * treesel; + GList * selected; + GtkTreeModel * model = GTK_TREE_MODEL(notes->store); + GList * s; + GtkTreePath * path; + GtkTreeIter iter; + Note * note; + + if((treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(notes->view))) + == NULL) + return; + if((selected = gtk_tree_selection_get_selected_rows(treesel, NULL)) + == NULL) + return; + for(s = g_list_first(selected); s != NULL; s = g_list_next(s)) + { + if((path = s->data) == NULL) + continue; + if(_notes_get_iter(notes, &iter, path) != TRUE) + continue; + gtk_tree_model_get(model, &iter, ND_COL_NOTE, ¬e, -1); + if(note != NULL) + noteedit_new(notes, note); + } + g_list_free(selected); +} + + +/* notes_note_reload_all */ +int notes_note_reload_all(Notes * notes) +{ + int ret = 0; + char * filename; + DIR * dir; + struct dirent * de; + Note * note; + + if((filename = _notes_note_get_directory()) == NULL) + return notes_error(notes, error_get(), 1); + if((dir = opendir(filename)) == NULL) + { + if(errno != ENOENT) + { + error_set("%s: %s", filename, strerror(errno)); + ret = notes_error(notes, error_get(), 1); + } + } + else + { + notes_note_remove_all(notes); + while((de = readdir(dir)) != NULL) + { + if(strncmp(de->d_name, "note.", 5) != 0) + continue; + free(filename); + if((filename = _notes_note_get_filename(de->d_name)) + == NULL) + continue; /* XXX report error */ + if((note = note_new_from_file(filename)) == NULL) + { + notes_error(NULL, error_get(), 1); + continue; + } + if(notes_note_add(notes, note) == NULL) + { + note_delete(note); + continue; /* XXX report error */ + } + } + } + free(filename); + return ret; +} + + +/* notes_note_remove_all */ +void notes_note_remove_all(Notes * notes) +{ + GtkTreeModel * model = GTK_TREE_MODEL(notes->store); + GtkTreeIter iter; + gboolean valid; + Note * note; + + valid = gtk_tree_model_get_iter_first(model, &iter); + for(; valid == TRUE; valid = gtk_tree_model_iter_next(model, &iter)) + { + gtk_tree_model_get(model, &iter, ND_COL_NOTE, ¬e, -1); + note_delete(note); + } + gtk_list_store_clear(notes->store); +} + + +/* notes_note_save_all */ +void notes_note_save_all(Notes * notes) +{ + GtkTreeModel * model = GTK_TREE_MODEL(notes->store); + GtkTreeIter iter; + gboolean valid; + + valid = gtk_tree_model_get_iter_first(model, &iter); + for(; valid == TRUE; valid = gtk_tree_model_iter_next(model, &iter)) + _notes_note_save(notes, &iter); +} + + +/* notes_note_select_all */ +void notes_note_select_all(Notes * notes) +{ + GtkTreeSelection * sel; + + sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(notes->view)); + gtk_tree_selection_select_all(sel); +} + + +/* notes_note_set_title */ +void notes_note_set_title(Notes * notes, GtkTreePath * path, char const * title) +{ + GtkTreeModel * model = GTK_TREE_MODEL(notes->store); + GtkTreeIter iter; + Note * note; + + _notes_get_iter(notes, &iter, path); + gtk_tree_model_get(model, &iter, ND_COL_NOTE, ¬e, -1); + note_set_title(note, title); + gtk_list_store_set(notes->store, &iter, ND_COL_TITLE, title, -1); + note_save(note); +} + + +/* private */ +/* functions */ +/* notes_confirm */ +static int _notes_confirm(GtkWidget * window, char const * message) +{ + GtkWidget * dialog; + int res; + + dialog = gtk_message_dialog_new(GTK_WINDOW(window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "%s", +#if GTK_CHECK_VERSION(2, 8, 0) + _("Question")); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), + "%s", +#endif + message); + gtk_window_set_title(GTK_WINDOW(dialog), _("Question")); + res = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + if(res == GTK_RESPONSE_YES) + return 0; + return 1; +} + + +/* notes_get_iter */ +static gboolean _notes_get_iter(Notes * notes, GtkTreeIter * iter, + GtkTreePath * path) +{ + GtkTreeIter p; + + if(gtk_tree_model_get_iter(GTK_TREE_MODEL(notes->filter_sort), iter, + path) == FALSE) + return FALSE; + gtk_tree_model_sort_convert_iter_to_child_iter(GTK_TREE_MODEL_SORT( + notes->filter_sort), &p, iter); + gtk_tree_model_filter_convert_iter_to_child_iter(GTK_TREE_MODEL_FILTER( + notes->filter), iter, &p); + return TRUE; +} + + +/* notes_note_get_directory */ +static char * _notes_note_get_directory(void) +{ + char const * homedir; + size_t len; + char const directory[] = ".notes"; + char * filename; + + if((homedir = getenv("HOME")) == NULL) + homedir = g_get_home_dir(); + len = strlen(homedir) + 1 + sizeof(directory); + if((filename = malloc(len)) == NULL) + return NULL; + snprintf(filename, len, "%s/%s", homedir, directory); + return filename; +} + + +/* notes_note_get_filename */ +static char * _notes_note_get_filename(char const * filenam) +{ + char const * homedir; + int len; + char const directory[] = ".notes"; + char * pathname; + + if((homedir = getenv("HOME")) == NULL) + homedir = g_get_home_dir(); + len = strlen(homedir) + 1 + sizeof(directory) + 1 + strlen(filenam) + 1; + if((pathname = malloc(len)) == NULL) + return NULL; + snprintf(pathname, len, "%s/%s/%s", homedir, directory, filenam); + return pathname; +} + + +/* notes_note_get_new_filename */ +static char * _notes_note_get_new_filename(void) +{ + char const * homedir; + int len; + char const directory[] = ".notes"; + char template[] = "note.XXXXXX"; + char * filename; + int fd; + + if((homedir = getenv("HOME")) == NULL) + homedir = g_get_home_dir(); + len = strlen(homedir) + 1 + sizeof(directory) + 1 + sizeof(template); + if((filename = malloc(len)) == NULL) + return NULL; + snprintf(filename, len, "%s/%s", homedir, directory); + if((mkdir(filename, 0777) != 0 && errno != EEXIST) + || snprintf(filename, len, "%s/%s/%s", homedir, + directory, template) >= len + || (fd = mkstemp(filename)) < 0) + { + error_set("%s: %s", filename, strerror(errno)); + free(filename); + return NULL; + } + close(fd); + return filename; +} + + +/* notes_note_save */ +static void _notes_note_save(Notes * notes, GtkTreeIter * iter) +{ + GtkTreeModel * model = GTK_TREE_MODEL(notes->store); + Note * note; + + gtk_tree_model_get(model, iter, ND_COL_NOTE, ¬e, -1); + note_save(note); +} + + +/* callbacks */ +/* toolbar */ +/* notes_on_delete */ +static void _notes_on_delete(gpointer data) +{ + Notes * notes = data; + + notes_note_delete_selected(notes); +} + + +/* notes_on_edit */ +static void _notes_on_edit(gpointer data) +{ + Notes * notes = data; + + notes_note_edit(notes); +} + + +/* notes_on_new */ +static void _notes_on_new(gpointer data) +{ + Notes * notes = data; + + notes_note_add(notes, NULL); +} + + +#ifdef EMBEDDED +/* notes_on_preferences */ +static void _notes_on_preferences(gpointer data) +{ + Notes * notes = data; + + notes_show_preferences(notes, TRUE); +} +#endif + + +/* notes_on_select_all */ +static void _notes_on_select_all(gpointer data) +{ + Notes * notes = data; + + notes_note_select_all(notes); +} + + +/* view */ +/* notes_on_note_activated */ +static void _notes_on_note_activated(gpointer data) +{ + Notes * notes = data; + + notes_note_edit(notes); +} + + +/* notes_on_note_cursor_changed */ +static void _notes_on_note_cursor_changed(gpointer data) +{ + Notes * notes = data; + + notes_note_cursor_changed(notes); +} + + +/* notes_on_note_title_edited */ +static void _notes_on_note_title_edited(GtkCellRendererText * renderer, + gchar * path, gchar * title, gpointer data) +{ + Notes * notes = data; + GtkTreePath * treepath; + + treepath = gtk_tree_path_new_from_string(path); + notes_note_set_title(notes, treepath, title); + gtk_tree_path_free(treepath); +} diff --git a/src/notes.h b/src/notes.h new file mode 100644 index 0000000..0588616 --- /dev/null +++ b/src/notes.h @@ -0,0 +1,71 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Notes */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#ifndef NOTES_NOTES_H +# define NOTES_NOTES_H + +# include "note.h" +# include + + +/* Notes */ +/* types */ +typedef struct _Notes Notes; + + +/* functions */ +Notes * notes_new(GtkWidget * window, GtkAccelGroup * group); +void notes_delete(Notes * notes); + +/* accessors */ +GtkWidget * notes_get_widget(Notes * notes); + +/* useful */ +void notes_about(Notes * notes); +int notes_error(Notes * notes, char const * message, int ret); + +void notes_show_preferences(Notes * notes, gboolean show); + +/* notes */ +Note * notes_note_add(Notes * notes, Note * note); +void notes_note_delete_selected(Notes * notes); +void notes_note_remove_all(Notes * notes); + +/* accessors */ +void notes_note_set_title(Notes * notes, GtkTreePath * path, + char const * title); + +void notes_note_cursor_changed(Notes * notes); +void notes_note_edit(Notes * notes); +int notes_note_reload_all(Notes * notes); +void notes_note_save_all(Notes * notes); +void notes_note_select_all(Notes * notes); + +#endif /* !NOTES_NOTES_H */ diff --git a/src/project.conf b/src/project.conf new file mode 100644 index 0000000..f3462bd --- /dev/null +++ b/src/project.conf @@ -0,0 +1,29 @@ +targets=notes +#cppflags=-D EMBEDDED +cflags_force=`pkg-config --cflags libDesktop` +cflags=-W -Wall -g -O2 -pedantic -fPIE -D_FORTIFY_SOURCE=2 -fstack-protector-all +ldflags_force=`pkg-config --libs libDesktop` -lintl +ldflags=-Wl,-pie +dist=Makefile,note.h,noteedit.h,notes.h,window.h + +[notes] +type=binary +sources=note.c,noteedit.c,notes.c,window.c,main.c +install=$(BINDIR) + +[main.c] +depends=note.h,notes.h,../config.h + +[note.c] +depends=note.h +cflags=-fPIC + +[noteedit.c] +cflags=-fPIC + +[notes.c] +depends=note.h,notes.h,../config.h +cflags=-fPIC + +[window.c] +depends=notes.h,window.h diff --git a/src/window.c b/src/window.c new file mode 100644 index 0000000..a356f86 --- /dev/null +++ b/src/window.c @@ -0,0 +1,321 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Notes */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#include +#include +#include +#include +#include +#include "notes.h" +#include "window.h" +#include "../config.h" +#define _(string) gettext(string) +#define N_(string) (string) + +#ifndef PROGNAME +# define PROGNAME "notes" +#endif + + +/* NotesWindow */ +/* private */ +/* types */ +struct _NotesWindow +{ + Notes * notes; + + /* widgets */ + GtkWidget * window; + GtkWidget * statusbar; +}; + + +/* prototypes */ +/* callbacks */ +static void _noteswindow_on_close(gpointer data); +static gboolean _noteswindow_on_closex(gpointer data); +static void _noteswindow_on_edit(gpointer data); +static void _noteswindow_on_new(gpointer data); +static void _noteswindow_on_preferences(gpointer data); + +#ifndef EMBEDDED +/* menus */ +/* file menu */ +static void _noteswindow_on_file_new(gpointer data); +static void _noteswindow_on_file_edit(gpointer data); +static void _noteswindow_on_file_close(gpointer data); + +/* edit menu */ +static void _noteswindow_on_edit_select_all(gpointer data); +static void _noteswindow_on_edit_delete(gpointer data); +static void _noteswindow_on_edit_preferences(gpointer data); + +/* help menu */ +static void _noteswindow_on_help_about(gpointer data); +#endif + +/* constants */ +/* accelerators */ +static const DesktopAccel _notes_accel[] = +{ +#ifdef EMBEDDED + { G_CALLBACK(_noteswindow_on_close), GDK_CONTROL_MASK, GDK_KEY_W }, + { G_CALLBACK(_noteswindow_on_edit), GDK_CONTROL_MASK, GDK_KEY_E }, + { G_CALLBACK(_noteswindow_on_new), GDK_CONTROL_MASK, GDK_KEY_N }, + { G_CALLBACK(_noteswindow_on_preferences), GDK_CONTROL_MASK, GDK_KEY_P }, +#endif + { NULL, 0, 0 } +}; + +#ifndef EMBEDDED +/* menubar */ +static const DesktopMenu _file_menu[] = +{ + { N_("_New"), G_CALLBACK(_noteswindow_on_file_new), GTK_STOCK_NEW, + GDK_CONTROL_MASK, GDK_KEY_N }, + { N_("_Edit"), G_CALLBACK(_noteswindow_on_file_edit), GTK_STOCK_EDIT, + GDK_CONTROL_MASK, GDK_KEY_E }, + { "", NULL, NULL, 0, 0 }, + { N_("_Close"), G_CALLBACK(_noteswindow_on_file_close), GTK_STOCK_CLOSE, + GDK_CONTROL_MASK, GDK_KEY_W }, + { NULL, NULL, NULL, 0, 0 } +}; +static const DesktopMenu _edit_menu[] = +{ + { N_("Select _All"), G_CALLBACK(_noteswindow_on_edit_select_all), +#if GTK_CHECK_VERSION(2, 10, 0) + GTK_STOCK_SELECT_ALL, +#else + "edit-select-all", +#endif + GDK_CONTROL_MASK, GDK_KEY_A }, + { "", NULL, NULL, 0, 0 }, + { N_("_Delete"), G_CALLBACK(_noteswindow_on_edit_delete), + GTK_STOCK_DELETE, 0, 0 }, + { "", NULL, NULL, 0, 0 }, + { N_("_Preferences"), G_CALLBACK(_noteswindow_on_edit_preferences), + GTK_STOCK_PREFERENCES, GDK_CONTROL_MASK, GDK_KEY_P }, + { NULL, NULL, NULL, 0, 0 } +}; +static const DesktopMenu _help_menu[] = +{ + { N_("_About"), G_CALLBACK(_noteswindow_on_help_about), +#if GTK_CHECK_VERSION(2, 6, 0) + GTK_STOCK_ABOUT, 0, 0 }, +#else + NULL, 0, 0 }, +#endif + { NULL, NULL, NULL, 0, 0 } +}; +static const DesktopMenubar _menubar[] = +{ + { N_("_File"), _file_menu }, + { N_("_Edit"), _edit_menu }, + { N_("_Help"), _help_menu }, + { NULL, NULL }, +}; +#endif + + +/* public */ +/* functions */ +/* noteswindow_new */ +NotesWindow * noteswindow_new(void) +{ + NotesWindow * notes; + GtkAccelGroup * group; + GtkWidget * vbox; + GtkWidget * widget; + + if((notes = malloc(sizeof(*notes))) == NULL) + return NULL; + notes->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + group = gtk_accel_group_new(); + notes->notes = notes_new(notes->window, group); + /* check for errors */ + if(notes->notes == NULL) + { + noteswindow_delete(notes); + g_object_unref(group); + return NULL; + } + desktop_accel_create(_notes_accel, notes, group); + gtk_window_add_accel_group(GTK_WINDOW(notes->window), group); + g_object_unref(group); + gtk_window_set_default_size(GTK_WINDOW(notes->window), 640, 480); +#if GTK_CHECK_VERSION(2, 6, 0) + gtk_window_set_icon_name(GTK_WINDOW(notes->window), "notes"); +#endif + gtk_window_set_title(GTK_WINDOW(notes->window), _("Notes")); + g_signal_connect_swapped(notes->window, "delete-event", G_CALLBACK( + _noteswindow_on_closex), notes); + vbox = gtk_vbox_new(FALSE, 0); +#ifndef EMBEDDED + /* menubar */ + widget = desktop_menubar_create(_menubar, notes, group); + gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0); +#endif + widget = notes_get_widget(notes->notes); + gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0); + /* statusbar */ + notes->statusbar = gtk_statusbar_new(); + gtk_box_pack_start(GTK_BOX(vbox), notes->statusbar, FALSE, TRUE, 0); + gtk_container_add(GTK_CONTAINER(notes->window), vbox); + gtk_widget_show_all(notes->window); + return notes; +} + + +/* noteswindow_delete */ +void noteswindow_delete(NotesWindow * notes) +{ + if(notes->notes != NULL) + notes_delete(notes->notes); + gtk_widget_destroy(notes->window); + free(notes); +} + + +/* private */ +/* functions */ +/* callbacks */ +/* noteswindow_on_close */ +static void _noteswindow_on_close(gpointer data) +{ + NotesWindow * notes = data; + + _noteswindow_on_closex(notes); +} + + +/* noteswindow_on_closex */ +static gboolean _noteswindow_on_closex(gpointer data) +{ + NotesWindow * notes = data; + + gtk_widget_hide(notes->window); + gtk_main_quit(); + return TRUE; +} + + +/* noteswindow_on_edit */ +static void _noteswindow_on_edit(gpointer data) +{ + NotesWindow * notes = data; + + notes_note_edit(notes->notes); +} + + +/* noteswindow_on_new */ +static void _noteswindow_on_new(gpointer data) +{ + NotesWindow * notes = data; + + notes_note_add(notes->notes, NULL); +} + + +/* noteswindow_on_preferences */ +static void _noteswindow_on_preferences(gpointer data) +{ + NotesWindow * notes = data; + + notes_show_preferences(notes->notes, TRUE); +} + + +#ifndef EMBEDDED +/* file menu */ +/* noteswindow_on_file_close */ +static void _noteswindow_on_file_close(gpointer data) +{ + NotesWindow * notes = data; + + _noteswindow_on_close(notes); +} + + +/* noteswindow_on_file_edit */ +static void _noteswindow_on_file_edit(gpointer data) +{ + NotesWindow * notes = data; + + _noteswindow_on_edit(notes); +} + + +/* noteswindow_on_file_new */ +static void _noteswindow_on_file_new(gpointer data) +{ + NotesWindow * notes = data; + + _noteswindow_on_new(notes); +} + + +/* edit menu */ +/* noteswindow_on_edit_delete */ +static void _noteswindow_on_edit_delete(gpointer data) +{ + NotesWindow * notes = data; + + notes_note_delete_selected(notes->notes); +} + + +/* noteswindow_on_edit_preferences */ +static void _noteswindow_on_edit_preferences(gpointer data) +{ + NotesWindow * notes = data; + + _noteswindow_on_preferences(notes); +} + + +/* noteswindow_on_edit_select_all */ +static void _noteswindow_on_edit_select_all(gpointer data) +{ + NotesWindow * notes = data; + + notes_note_select_all(notes->notes); +} + + +/* help menu */ +/* noteswindow_on_help_about */ +static void _noteswindow_on_help_about(gpointer data) +{ + NotesWindow * notes = data; + + notes_about(notes->notes); +} +#endif diff --git a/src/window.h b/src/window.h new file mode 100644 index 0000000..d48be9c --- /dev/null +++ b/src/window.h @@ -0,0 +1,45 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Notes */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#ifndef NOTES_WINDOW_H +# define NOTES_WINDOW_H + + +/* NotesWindow */ +/* public */ +/* types */ +typedef struct _NotesWindow NotesWindow; + + +/* functions */ +NotesWindow * noteswindow_new(void); +void noteswindow_delete(NotesWindow * notes); + +#endif /* !NOTES_WINDOW_H */ diff --git a/tools/notes.c b/tools/notes.c new file mode 100644 index 0000000..43f44f1 --- /dev/null +++ b/tools/notes.c @@ -0,0 +1,125 @@ +/* $Id$ */ +/* Copyright (c) 2015 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Notes */ +/* All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + + + +#define EMBEDDED +#include +#include + +#include "../src/note.c" +#include "../src/noteedit.c" +#include "../src/notes.c" + + +/* Mailing-lists */ +/* private */ +/* types */ +typedef struct _MailerPlugin NotesPlugin; + +struct _MailerPlugin +{ + MailerPluginHelper * helper; + + Notes * notes; + + /* widgets */ + GtkWidget * widget; + GtkWidget * view; +}; + + +/* protected */ +/* prototypes */ +/* plug-in */ +static MailerPlugin * _notes_init(MailerPluginHelper * helper); +static void _notes_destroy(NotesPlugin * notes); +static GtkWidget * _notes_get_widget(NotesPlugin * notes); + + +/* public */ +/* variables */ +/* plug-in */ +MailerPluginDefinition plugin = +{ + "Notes", + "notes", + NULL, + _notes_init, + _notes_destroy, + _notes_get_widget, + NULL +}; + + +/* protected */ +/* functions */ +/* plug-in */ +/* notes_init */ +static MailerPlugin * _notes_init(MailerPluginHelper * helper) +{ + NotesPlugin * notes; + GtkWidget * widget; + size_t i; + + if((notes = malloc(sizeof(*notes))) == NULL) + return NULL; + if((notes->notes = notes_new(NULL, NULL)) == NULL) + { + _notes_destroy(notes); + return NULL; + } + notes->helper = helper; + notes->widget = gtk_vbox_new(FALSE, 4); + widget = notes_get_widget(notes->notes); + gtk_box_pack_start(GTK_BOX(notes->widget), widget, TRUE, TRUE, 0); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(notes->notes->view), + FALSE); + for(i = 0; i < ND_COL_COUNT; i++) + if(notes->notes->columns[i] != NULL && i != ND_COL_TITLE) + gtk_tree_view_column_set_visible(notes->notes->columns[i], + FALSE); + gtk_widget_show_all(notes->widget); + return notes; +} + + +/* notes_destroy */ +static void _notes_destroy(NotesPlugin * notes) +{ + if(notes->notes != NULL) + notes_delete(notes->notes); + free(notes); +} + + +/* notes_get_widget */ +static GtkWidget * _notes_get_widget(NotesPlugin * notes) +{ + return notes->widget; +} diff --git a/tools/project.conf b/tools/project.conf new file mode 100644 index 0000000..643c8de --- /dev/null +++ b/tools/project.conf @@ -0,0 +1,13 @@ +targets=notes +cflags_force=`pkg-config --cflags libDesktop Mailer` +cflags=-W -Wall -g -O2 -pedantic -fPIC -D_FORTIFY_SOURCE=2 -fstack-protector-all +ldflags_force=`pkg-config --libs libDesktop` +dist=Makefile + +[notes] +type=plugin +sources=notes.c +install=$(LIBDIR)/Mailer/plugins + +[notes.c] +depends=../src/note.c,../src/noteedit.c,../src/notes.c