diff --git a/debian/changelog b/debian/changelog index 85e4313..5a91780 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,11 +1,12 @@ -simbuto (0.1.1) UNRELEASED; urgency=medium +simbuto (0.1.1) unstable; urgency=medium * add command-line options (help, verbose, debug) * add version info to about dialog * fix crash on events that start after the plotrange * F5 now refreshes the graph as well as Ctrl-R + * add start and end plot date selector calendars - -- Yann Büchau Thu, 05 Jan 2017 14:38:08 +0100 + -- Yann Büchau Sun, 08 Jan 2017 22:08:43 +0100 simbuto (0.1) unstable; urgency=medium diff --git a/usr/lib/simbuto/python/simbuto/gui.py b/usr/lib/simbuto/python/simbuto/gui.py index a5a86d6..20bac5a 100644 --- a/usr/lib/simbuto/python/simbuto/gui.py +++ b/usr/lib/simbuto/python/simbuto/gui.py @@ -1,4 +1,14 @@ #!/usr/bin/env python3 +# system modules +import logging +import os +import configparser +import signal +import datetime +import hashlib +import contextlib + +# external modules import gi gi.require_version('Gtk','3.0') from gi.repository import Gtk @@ -6,11 +16,8 @@ from gi.repository import Gdk from gi.repository import GLib from gi.repository import Pango -import logging -import os -import configparser -import signal -import hashlib + +# internal modules from . import signalmanager from . import config from . import VERSION @@ -106,12 +113,82 @@ def budget_needs_saving(self): @property def current_editor_content(self): - textview = self.builder.get_object("editor_textview") + textview = self("editor_textview") tb = textview.get_buffer() # get the underlying buffer start, end = tb.get_bounds() content = tb.get_text(start, end, True) return content + @property + def selected_start_date(self): + """ The selected start date. You may set this to a datetime.datetime + object. + Returns: + date (datetime.datetime): The start date + """ + year,month,day = self.object("dateregion_start_calendar").get_date() + date = datetime.datetime(year = year, month = month + 1, day = day) + return date + + @selected_start_date.setter + def selected_start_date(self, newdate): + try: + year,month,day = newdate.year, newdate.month - 1, newdate.day + except AttributeError: + raise TypeError("selected_start_date needs to be set to object of " + "datetime.datetime") + self("dateregion_start_calendar").select_month( + month=month,year=year) + self("dateregion_start_calendar").select_day(day = day) + + @property + def selected_end_date(self): + """ The selected end date. You may set this to a datetime.datetime + object. + Returns: + date (datetime.datetime): The end date + """ + year,month,day = self.object("dateregion_end_calendar").get_date() + date = datetime.datetime(year = year, month = month + 1, day = day) + return date + + @selected_end_date.setter + def selected_end_date(self, newdate): + try: + year,month,day = newdate.year, newdate.month - 1, newdate.day + except AttributeError: + raise TypeError("selected_end_date needs to be set to object of " + "datetime.datetime") + self("dateregion_end_calendar").select_month( + month=month,year=year) + self("dateregion_end_calendar").select_day(day = day) + + @property + def calendar_setting_in_progress(self): + """ This is an internal property to prevent recursion in the calendar + date setting. It is always boolean. When you set it, it is converted to + bool. + """ + if hasattr(self,"_calendar_setting_in_progress"): + return bool(self._calendar_setting_in_progress) + else: + return False + + @calendar_setting_in_progress.setter + def calendar_setting_in_progress(self, value): + self._calendar_setting_in_progress = bool(value) + + ######################## + ### Context managers ### + ######################## + @contextlib.contextmanager + def no_calendar_recursion(self): + old = self.calendar_setting_in_progress # old value + self.calendar_setting_in_progress = True # lock + try: + yield + finally: + self.calendar_setting_in_progress = old # unlock ############### ### Methods ### @@ -137,6 +214,15 @@ def install_glib_handler(sig): # add a unix signal handler install_glib_handler, sig, # add a handler for this signal priority = GLib.PRIORITY_HIGH ) + # get an object from the builder + def object(self, name): + try: + self.builder + except AttributeError: # builder not yet loaded + self.load_builder() + obj = self.builder.get_object(name) + return obj + # build the gui def load_builder(self): # get a GTK builder @@ -165,6 +251,8 @@ def setup_gui(self): "ResetStatus": self.reset_statusbar, "UpdateStatus": self.update_statusbar_from_widget, "UpdateGraphFromEditor": self.update_graph_from_editor, + "RegionDaySelected": self.region_day_selected, + "ResetDate": self.reset_dateregion, } self.builder.connect_signals(self.handlers) @@ -184,14 +272,16 @@ def setup_gui(self): "tooltip":_("Quit Simbuto")}, "app.about": {"label":_("About"),"short":_("About"), "tooltip":_("Display information on Simbuto")}, + "app.reset": {"label":_("Date Reset"),"short":_("Date Reset"), + "tooltip":_("Reset the selected date region")}, } # set the label for each action for action, labels in self.actions.items(): - self.builder.get_object(action).set_label( # the label + self(action).set_label( # the label self.actions.get(action,{}).get("label")) - self.builder.get_object(action).set_short_label( # the short label + self(action).set_short_label( # the short label self.actions.get(action,{}).get("short")) - self.builder.get_object(action).set_tooltip( # the tooltip + self(action).set_tooltip( # the tooltip self.actions.get(action,{}).get("tooltip")) # create a simbuto file filter @@ -200,21 +290,21 @@ def setup_gui(self): self.simbuto_filefilter.add_mime_type("application/x-simbuto") # main window - window = self.builder.get_object("main_applicationwindow") + window = self("main_applicationwindow") self.update_window_title_filename() window.set_icon_from_file(self.config.get('gui-general','icon')) # the menu # the window accelgroup - accelgroup = self.builder.get_object("window_accelgroup") + accelgroup = self("window_accelgroup") # define accelerators accels = { - self.builder.get_object("new_menuitem"): "n", - self.builder.get_object("open_menuitem"): "o", - self.builder.get_object("save_menuitem"): "s", - self.builder.get_object("saveas_menuitem"): "s", - self.builder.get_object("quit_menuitem"): "q", - self.builder.get_object("refresh_menuitem"):["F5","r"], + self("new_menuitem"): "n", + self("open_menuitem"): "o", + self("save_menuitem"): "s", + self("saveas_menuitem"): "s", + self("quit_menuitem"): "q", + self("refresh_menuitem"):["F5","r"], } # add the accelerators for item, accelstrs in accels.items(): @@ -233,22 +323,32 @@ def setup_gui(self): } # set the label for each menuitem for name, label in menuitems.items(): - self.builder.get_object(name).set_label(label) + self(name).set_label(label) # editor - editorheading = self.builder.get_object("editor_heading_label") + editorheading = self("editor_heading_label") editorheading.set_text(_("Budget editor")) - editor_textview = self.builder.get_object("editor_textview") # the tv + editor_textview = self("editor_textview") # the tv monofont = Pango.FontDescription("monospace") # a monospace font editor_textview.modify_font(monofont) # set the editor to monospace # graph - plotheading = self.builder.get_object("plot_heading_label") + plotheading = self("plot_heading_label") plotheading.set_text(_("Budget graph")) # statusbar self.reset_statusbar() # initially reset statusbar + # calendar + # translate + + # pretend the start date was selected and let automatic range selection + # do the rest + self("dateregion_expander_label").set_text(_("Date range")) + self("dateregion_start_calendar_label").set_text(_("start date")) + self("dateregion_end_calendar_label").set_text(_("end date")) + self.reset_dateregion() # reset dateregion + window.show_all() def get_current_editor_content(self): @@ -263,7 +363,7 @@ def new_budget(self,*args): self.empty_editor() def update_window_title_filename(self): - window = self.builder.get_object("main_applicationwindow") + window = self("main_applicationwindow") try: basename = os.path.basename(self.currently_edited_file) except: basename = _("unsaved budget") window.set_title("{} - {}".format(_("Simbuto"), basename)) @@ -271,13 +371,13 @@ def update_window_title_filename(self): def empty_editor(self): self.logger.debug(_("emptying editor")) # get the textview - textview = self.builder.get_object("editor_textview") + textview = self("editor_textview") textbuffer = textview.get_buffer() # get the underlying buffer textbuffer.set_text("") # empty the text self.currently_edited_file = None # no file edited currently def reset_statusbar(self, *args): - statuslabel = self.builder.get_object("status_label") + statuslabel = self("status_label") statuslabel.set_text(_("Simbuto - a simple budgeting tool")) def update_statusbar_from_widget(self, widget): @@ -289,7 +389,7 @@ def update_statusbar_from_widget(self, widget): self.actions.get(widget_action,{}).get("tooltip")) def update_statusbar(self, text = None): - statuslabel = self.builder.get_object("status_label") + statuslabel = self("status_label") # if None, use default if isinstance(text, str): newtext = text else: newtext = _("Simbuto - a simple budgeting tool") @@ -297,7 +397,7 @@ def update_statusbar(self, text = None): statuslabel.set_text(newtext) def update_graph_from_editor(self, *args): - rect = self.builder.get_object("plot_image").get_allocation() + rect = self("plot_image").get_allocation() width = rect.width height = rect.height try: @@ -308,8 +408,12 @@ def update_graph_from_editor(self, *args): filename = os.path.join(config.personal_simbuto_dotfolder(), "plots",name) success = self.signalmanager.emit_signal("create-graph-from-text", - filename=filename, text = self.current_editor_content, - width = width, height = height) + filename=filename, # to this file + text = self.current_editor_content, # this text + width = width, height = height, # these dimensions + start = self.selected_start_date, # this start date + end = self.selected_end_date, # this end date + ) if success[0]: self.logger.debug(_("The graph file was obviously " "sucessfully updated.")) @@ -323,8 +427,45 @@ def update_graph_from_editor(self, *args): return True def update_graph_from_file(self, filename): - self.builder.get_object("plot_image").set_from_file(filename) + self("plot_image").set_from_file(filename) + def reset_dateregion(self,*args): + """ Reset the selected dateregion + """ + self.selected_start_date = datetime.datetime.now() + self.selected_end_date = datetime.datetime.now() + \ + datetime.timedelta(365) + + def region_day_selected(self,calendar): + self.logger.debug(_("Date region was changed.")) + if self.calendar_setting_in_progress: + self.logger.debug(_("To prevent recursion I won't react to this.")) + return # we don't want recursion + with self.no_calendar_recursion(): + # get selected start dates + start_date = self.selected_start_date + self.logger.debug(_("start date is now {}").format(start_date)) + end_date = self.selected_end_date + self.logger.debug(_("end date is now {}").format(end_date)) + if start_date >= end_date: # bullshit selected + self.logger.debug(_("End date before start date selected.")) + # start date was selected + if calendar == self("dateregion_start_calendar"): + # set end date to one year later + self.logger.debug(_("Setting end date to one year after " + "start date")) + self.selected_end_date = start_date+datetime.timedelta(365) + # end date was selected + elif calendar == self("dateregion_end_calendar"): + self.logger.debug(_("Setting start date to one month " + "before end date")) + # set start date to one month earlier + self.selected_start_date = end_date - datetime.timedelta(30) + else: + self.logger.warning(_("Somehow a date was selected from an " + "unknown calendar. This should not have happened.")) + # update the graph + self.update_graph_from_editor() ############### ### Dialogs ### @@ -333,7 +474,7 @@ def open_file_dialog(self, *args): # create a dialog dialog = Gtk.FileChooserDialog( _("Please choose a file"), # title - self.builder.get_object("main_applicationwindow"), # parent + self("main_applicationwindow"), # parent Gtk.FileChooserAction.OPEN, # Action # Buttons (obviously not possible with glade!?) (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, @@ -360,7 +501,7 @@ def saveas_dialog(self, *args): # create a dialog dialog = Gtk.FileChooserDialog( _("Please select a saving destination"), # title - self.builder.get_object("main_applicationwindow"), # parent + self("main_applicationwindow"), # parent Gtk.FileChooserAction.SAVE, # Action # Buttons (obviously not possible with glade!?) (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, @@ -385,14 +526,14 @@ def saveas_dialog(self, *args): def show_notyetimplemented_dialog(self, *args): # get the dialog - dialog = self.builder.get_object("notyetimplemented_dialog") + dialog = self("notyetimplemented_dialog") dialog.set_markup(_("This feature is currently not implemented.")) dialog.run() # run the dialog dialog.hide() # only hide it, because destroying prevents re-opening def wanttosave_dialog(self): # get the info dialog - dialog = self.builder.get_object("wanttosave_dialog") + dialog = self("wanttosave_dialog") dialog.set_markup(_("Do you want to save your current budget?")) response = dialog.run() # run the dialog if response == Gtk.ResponseType.YES: @@ -404,7 +545,7 @@ def wanttosave_dialog(self): def show_info_dialog(self, *args): # get the info dialog - infodialog = self.builder.get_object("info_dialog") + infodialog = self("info_dialog") # comment infodialog.set_comments(_("a simple budgeting tool")) # version @@ -437,7 +578,7 @@ def save_current_budget_to_file(self, filename = None): if res == [True]: self.logger.info(_("Budget saved to '{}'").format(filename)) self.currently_edited_file = filename # update currently edited file - self.builder.get_object("app.refresh").activate() # refresh + self("app.refresh").activate() # refresh self.update_statusbar(_("Budget saved to '{}'").format(filename)) else: self.logger.info(_("Budget could NOT be saved to '{}'!").format( @@ -459,13 +600,13 @@ def fill_editor_from_file(self, filename): text = res[0] if text is not None: # get the textview - textview = self.builder.get_object("editor_textview") + textview = self("editor_textview") textbuffer = textview.get_buffer() # get the underlying buffer textbuffer.set_text(text) # empty the text self.logger.debug(_("editor was filled with contents of file '{}'" ).format(filename)) self.currently_edited_file = filename # set currently edited file - self.builder.get_object("app.refresh").activate() # refresh + self("app.refresh").activate() # refresh else: # didn't work, empty editor self.logger.warning(_("Reading from file '{}' didn't work!").format( filename)) @@ -482,6 +623,11 @@ def run(self): self.mainloop.run() self.logger.debug(_("GLib main loop ended.")) + def __call__(self, objname): + """ When called, return the object like the builder + """ + return self.object(objname) + # quit the gui def quit(self, *args): self.logger.debug(_("Received quitting signal.")) diff --git a/usr/lib/simbuto/python/simbuto/manager.py b/usr/lib/simbuto/python/simbuto/manager.py index 0445e41..e84f95c 100644 --- a/usr/lib/simbuto/python/simbuto/manager.py +++ b/usr/lib/simbuto/python/simbuto/manager.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import logging import hashlib +import datetime from rpy2.rinterface import RRuntimeError from rpy2.robjects import r as R # be able to talk to R from . import signalmanager @@ -102,14 +103,35 @@ def md5sum_of_file(self, filename): ### Plotting ### ################ def create_png_graph_from_text(self, text, filename, - width = 600, height = 400): + width = 600, height = 400, + start = datetime.datetime.now(), + end = datetime.datetime.now() + datetime.timedelta(365) ): + """ Create a png graph from simbuto csv-like text + Args: + text (str): the csv-like simbuto budget + filename (path): the output png file path + width, height [Optional(int)]: width and height of the png file. + Defaults to 600x400px. + start [Optional(datetime.datetime)]: the start day of the budget + calculation and plotting. Defaults to the current day. + end [Optional(datetime.datetime)]: the end time of the budget + calculation and plotting. Defaults to the current day plus one + year. + Returns: + success (bool): True if graph png file was created, False otherwise + """ + start_date = R("as.Date('{}-{}-{}')".format( + start.year,start.month,start.day)) + end_date = R("as.Date('{}-{}-{}')".format( + end.year,end.month,end.day)) try: # append newline if not text.endswith("\n"): text += "\n" # create the budget from text budget_frame = R.read_budget_from_text(text = text) # create the timeseries from the budget - timeseries_frame = R.timeseries_from_budget(budget = budget_frame) + timeseries_frame = R.timeseries_from_budget(budget = budget_frame, + start = start_date, end = end_date) # plot to png R.plot_budget_timeseries_to_png(filename=filename, timeseries = timeseries_frame, width = width, height = height) diff --git a/usr/lib/simbuto/r/simbuto-functions.R b/usr/lib/simbuto/r/simbuto-functions.R index a4f2ccc..021a893 100755 --- a/usr/lib/simbuto/r/simbuto-functions.R +++ b/usr/lib/simbuto/r/simbuto-functions.R @@ -38,6 +38,7 @@ timeseries_from_budget <- function(budget, start = Sys.Date(), end = Sys.Date() # cat("from=",fact.start," to=",fact.end," by=",interval," length.out=",number.occurences,"\n") + occurences <- c() if(fact.start < fact.end) { if(is.numeric(number.occurences)){ occurences <- seq.Date(from = fact.start, to = fact.end, length.out = number.occurences) @@ -59,7 +60,7 @@ timeseries_from_budget <- function(budget, start = Sys.Date(), end = Sys.Date() plot_budget_timeseries <- function(timeseries) { # base plot plot(timeseries,type="n",xaxt="n",yaxt="n" - ,ylab="",xlab="",main=paste(timeseries$day[2]," - ",timeseries$day[length(timeseries$day)])) + ,ylab="",xlab="",main=paste(timeseries$day[1]," - ",timeseries$day[length(timeseries$day)])) axismoney <- axis(side = 2,las=1) axisdates <- axis.Date(side = 1, x = timeseries$day) diff --git a/usr/share/simbuto/gui/simbuto.glade b/usr/share/simbuto/gui/simbuto.glade index ca1f0f5..a22e844 100644 --- a/usr/share/simbuto/gui/simbuto.glade +++ b/usr/share/simbuto/gui/simbuto.glade @@ -19,10 +19,14 @@ - gtk-apply + gtk-refresh dialog-ok + + gtk-media-rewind + + gtk-save @@ -227,7 +231,22 @@ False True True - gtk-apply + gtk-refresh + + + False + True + + + + + app.reset + True + False + True + Date reset + True + gtk-media-rewind False @@ -337,6 +356,145 @@ 0 + + + True + False + + + True + True + True + 5 + True + + + True + False + + + True + False + vertical + + + True + False + Start + + + False + True + 0 + + + + + True + True + 2017 + 8 + + + + False + True + 1 + + + + + True + False + 0 + + + + + True + False + vertical + + + False + False + 5 + 1 + + + + + True + False + vertical + + + True + False + End + + + False + True + 0 + + + + + True + True + 2017 + 8 + + + + False + True + 1 + + + + + True + False + 2 + + + + + + + True + False + From - To + + + + + True + False + 0 + + + + + False + True + 1 + + + + + True + False + + + False + True + 5 + 2 + + 300 @@ -348,7 +506,7 @@ True True - 1 + 3 diff --git a/usr/share/simbuto/lang/de/LC_MESSAGES/simbuto.po b/usr/share/simbuto/lang/de/LC_MESSAGES/simbuto.po index d98106a..0bbb9ab 100644 --- a/usr/share/simbuto/lang/de/LC_MESSAGES/simbuto.po +++ b/usr/share/simbuto/lang/de/LC_MESSAGES/simbuto.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-01-08 19:43+0100\n" -"PO-Revision-Date: 2017-01-08 14:44+0100\n" +"POT-Creation-Date: 2017-01-08 22:05+0100\n" +"PO-Revision-Date: 2017-01-08 22:06+0100\n" "Last-Translator: \n" "Language-Team: \n" "Language: de\n" @@ -18,253 +18,309 @@ msgstr "" "X-Generator: Poedit 1.8.7.1\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: usr/lib/simbuto/python/simbuto/gui.py:78 +#: usr/lib/simbuto/python/simbuto/gui.py:85 msgid "" "The current buffer is empty and no file is specified. No saving necessary." msgstr "" "Der Editor ist leer und keine Datei wurde angegeben. Speichern ist nicht " "notwendig." -#: usr/lib/simbuto/python/simbuto/gui.py:86 +#: usr/lib/simbuto/python/simbuto/gui.py:93 msgid "Nonexistant or no file specified. Saving necessary!" msgstr "" "Nichtexistente oder gar keine Datei angegeben. Speichern ist notwendig!" -#: usr/lib/simbuto/python/simbuto/gui.py:93 -#: usr/lib/simbuto/python/simbuto/manager.py:92 +#: usr/lib/simbuto/python/simbuto/gui.py:100 +#: usr/lib/simbuto/python/simbuto/manager.py:93 msgid "md5sum of file '{}' is '{}'" msgstr "md5-Summe der Datei '{}' is '{}'" -#: usr/lib/simbuto/python/simbuto/gui.py:98 +#: usr/lib/simbuto/python/simbuto/gui.py:105 msgid "md5sum of editor content is '{}'" msgstr "md5-Summe des Editorinhalts ist '{}'" -#: usr/lib/simbuto/python/simbuto/gui.py:102 +#: usr/lib/simbuto/python/simbuto/gui.py:109 msgid "The current budget would need saving." msgstr "Das aktuelle Budget müsste gespeichert werden." -#: usr/lib/simbuto/python/simbuto/gui.py:104 +#: usr/lib/simbuto/python/simbuto/gui.py:111 msgid "The current budget doesn't need saving." msgstr "Das aktuelle Budget muss nicht gespeichert werden." -#: usr/lib/simbuto/python/simbuto/gui.py:173 +#: usr/lib/simbuto/python/simbuto/gui.py:261 msgid "New Budget" msgstr "Neues Budget" -#: usr/lib/simbuto/python/simbuto/gui.py:173 +#: usr/lib/simbuto/python/simbuto/gui.py:261 msgid "New" msgstr "Neu" -#: usr/lib/simbuto/python/simbuto/gui.py:174 +#: usr/lib/simbuto/python/simbuto/gui.py:262 msgid "Create a new budget" msgstr "Ein neues Budget erstellen" -#: usr/lib/simbuto/python/simbuto/gui.py:175 +#: usr/lib/simbuto/python/simbuto/gui.py:263 msgid "Open Budget" msgstr "Öffne Budget" -#: usr/lib/simbuto/python/simbuto/gui.py:175 +#: usr/lib/simbuto/python/simbuto/gui.py:263 msgid "Open" msgstr "Öffnen" -#: usr/lib/simbuto/python/simbuto/gui.py:176 +#: usr/lib/simbuto/python/simbuto/gui.py:264 msgid "Open an existing budget file" msgstr "Eine existierende Budget-Datei öffnen" -#: usr/lib/simbuto/python/simbuto/gui.py:177 +#: usr/lib/simbuto/python/simbuto/gui.py:265 msgid "Save Budget" msgstr "Budget speichern" -#: usr/lib/simbuto/python/simbuto/gui.py:177 +#: usr/lib/simbuto/python/simbuto/gui.py:265 msgid "Save" msgstr "Speichern" -#: usr/lib/simbuto/python/simbuto/gui.py:178 +#: usr/lib/simbuto/python/simbuto/gui.py:266 msgid "Save this budget" msgstr "Dieses Budget speichern" -#: usr/lib/simbuto/python/simbuto/gui.py:179 +#: usr/lib/simbuto/python/simbuto/gui.py:267 msgid "Save As" msgstr "Speichern unter" -#: usr/lib/simbuto/python/simbuto/gui.py:180 +#: usr/lib/simbuto/python/simbuto/gui.py:268 msgid "Save this budget to another file" msgstr "Dieses Budget anderswo speichern" -#: usr/lib/simbuto/python/simbuto/gui.py:181 +#: usr/lib/simbuto/python/simbuto/gui.py:269 msgid "Refresh Graph" msgstr "Graph aktualisieren" -#: usr/lib/simbuto/python/simbuto/gui.py:181 +#: usr/lib/simbuto/python/simbuto/gui.py:269 msgid "Refresh" msgstr "Aktualisieren" -#: usr/lib/simbuto/python/simbuto/gui.py:182 +#: usr/lib/simbuto/python/simbuto/gui.py:270 msgid "Refresh the budget graph" msgstr "den Budget-Graph aktualisieren" -#: usr/lib/simbuto/python/simbuto/gui.py:183 +#: usr/lib/simbuto/python/simbuto/gui.py:271 msgid "Quit" msgstr "Beenden" -#: usr/lib/simbuto/python/simbuto/gui.py:184 +#: usr/lib/simbuto/python/simbuto/gui.py:272 msgid "Quit Simbuto" msgstr "Simbuto beenden" -#: usr/lib/simbuto/python/simbuto/gui.py:185 +#: usr/lib/simbuto/python/simbuto/gui.py:273 msgid "About" msgstr "Über" -#: usr/lib/simbuto/python/simbuto/gui.py:186 +#: usr/lib/simbuto/python/simbuto/gui.py:274 msgid "Display information on Simbuto" msgstr "Informationen über Simbuto anzeigen" -#: usr/lib/simbuto/python/simbuto/gui.py:199 +#: usr/lib/simbuto/python/simbuto/gui.py:275 +msgid "Date Reset" +msgstr "Datum zurücksetzen" + +#: usr/lib/simbuto/python/simbuto/gui.py:276 +msgid "Reset the selected date region" +msgstr "Setze den ausgewählten Datumsbereich zurück" + +#: usr/lib/simbuto/python/simbuto/gui.py:289 msgid "Simbuto budget files" msgstr "Simbuto Budget-Dateien" -#: usr/lib/simbuto/python/simbuto/gui.py:230 +#: usr/lib/simbuto/python/simbuto/gui.py:320 msgid "_File" msgstr "_Datei" -#: usr/lib/simbuto/python/simbuto/gui.py:231 +#: usr/lib/simbuto/python/simbuto/gui.py:321 msgid "_Help" msgstr "_Hilfe" -#: usr/lib/simbuto/python/simbuto/gui.py:232 +#: usr/lib/simbuto/python/simbuto/gui.py:322 msgid "_Budget" msgstr "_Budget" -#: usr/lib/simbuto/python/simbuto/gui.py:240 +#: usr/lib/simbuto/python/simbuto/gui.py:330 msgid "Budget editor" msgstr "Budget Editor" -#: usr/lib/simbuto/python/simbuto/gui.py:247 +#: usr/lib/simbuto/python/simbuto/gui.py:337 msgid "Budget graph" msgstr "Budget Graph" -#: usr/lib/simbuto/python/simbuto/gui.py:268 +#: usr/lib/simbuto/python/simbuto/gui.py:347 +msgid "Date range" +msgstr "Datumsbereich" + +#: usr/lib/simbuto/python/simbuto/gui.py:348 +msgid "start date" +msgstr "Startdatum" + +#: usr/lib/simbuto/python/simbuto/gui.py:349 +msgid "end date" +msgstr "Enddatum" + +#: usr/lib/simbuto/python/simbuto/gui.py:368 msgid "unsaved budget" msgstr "ungespeichertes Budget" -#: usr/lib/simbuto/python/simbuto/gui.py:269 usr/bin/simbuto:36 +#: usr/lib/simbuto/python/simbuto/gui.py:369 usr/bin/simbuto:36 msgid "Simbuto" msgstr "Simbuto" -#: usr/lib/simbuto/python/simbuto/gui.py:272 +#: usr/lib/simbuto/python/simbuto/gui.py:372 msgid "emptying editor" msgstr "leere den Budget-Editor" -#: usr/lib/simbuto/python/simbuto/gui.py:281 -#: usr/lib/simbuto/python/simbuto/gui.py:295 +#: usr/lib/simbuto/python/simbuto/gui.py:381 +#: usr/lib/simbuto/python/simbuto/gui.py:395 msgid "Simbuto - a simple budgeting tool" msgstr "Simbuto - ein einfaches Werkzeug zur Kostenplanung" -#: usr/lib/simbuto/python/simbuto/gui.py:306 +#: usr/lib/simbuto/python/simbuto/gui.py:406 msgid "unnamed-budget" msgstr "unbenanntes-Budget" -#: usr/lib/simbuto/python/simbuto/gui.py:314 +#: usr/lib/simbuto/python/simbuto/gui.py:418 msgid "The graph file was obviously sucessfully updated." msgstr "Die Graph-Bildatei wurde erfolgreich aktualisiert." -#: usr/lib/simbuto/python/simbuto/gui.py:317 +#: usr/lib/simbuto/python/simbuto/gui.py:421 msgid "Graph updated" msgstr "Graph aktualisiert" -#: usr/lib/simbuto/python/simbuto/gui.py:319 +#: usr/lib/simbuto/python/simbuto/gui.py:423 msgid "There was a problem updating the graph." msgstr "Es gab ein Problem beim Aktualisieren des Graphen." -#: usr/lib/simbuto/python/simbuto/gui.py:320 +#: usr/lib/simbuto/python/simbuto/gui.py:424 msgid "" "[WARNING] There was a problem updating the graph. Please check the input!" msgstr "" "[WARNUNG] Es gab ein Problem beim Aktualisieren des Graphen. Bitte Eingabe " "überprüfen!" -#: usr/lib/simbuto/python/simbuto/gui.py:335 +#: usr/lib/simbuto/python/simbuto/gui.py:440 +msgid "Date region was changed." +msgstr "Datumsbereich wurde geändert." + +#: usr/lib/simbuto/python/simbuto/gui.py:442 +msgid "To prevent recursion I won't react to this." +msgstr "Um Rekursion zu verhindern, wird nicht darauf reagiert." + +#: usr/lib/simbuto/python/simbuto/gui.py:447 +msgid "start date is now {}" +msgstr "Startdatum ist jetzt {}" + +#: usr/lib/simbuto/python/simbuto/gui.py:449 +msgid "end date is now {}" +msgstr "Enddatum ist jetzt {}" + +#: usr/lib/simbuto/python/simbuto/gui.py:451 +msgid "End date before start date selected." +msgstr "Enddatum vor Startdatum ausgewählt" + +#: usr/lib/simbuto/python/simbuto/gui.py:455 +msgid "Setting end date to one year after start date" +msgstr "Setze Enddatum auf ein Jahr vor dem Startdatum" + +#: usr/lib/simbuto/python/simbuto/gui.py:460 +msgid "Setting start date to one month before end date" +msgstr "Setze Startdatum auf einen Monat vor dem Enddatum" + +#: usr/lib/simbuto/python/simbuto/gui.py:465 +msgid "" +"Somehow a date was selected from an unknown calendar. This should not have " +"happened." +msgstr "" +"Irgendwie wurde ein Datum von einem unbekannten Kalender ausgewählt. Das " +"hätte nicht passieren sollen." + +#: usr/lib/simbuto/python/simbuto/gui.py:476 msgid "Please choose a file" msgstr "Bitte eine Datei auswählen" -#: usr/lib/simbuto/python/simbuto/gui.py:349 -#: usr/lib/simbuto/python/simbuto/gui.py:376 +#: usr/lib/simbuto/python/simbuto/gui.py:490 +#: usr/lib/simbuto/python/simbuto/gui.py:517 msgid "File '{}' selected" msgstr "Datei '{}' ausgewählt" -#: usr/lib/simbuto/python/simbuto/gui.py:353 -#: usr/lib/simbuto/python/simbuto/gui.py:380 +#: usr/lib/simbuto/python/simbuto/gui.py:494 +#: usr/lib/simbuto/python/simbuto/gui.py:521 msgid "File selection cancelled" msgstr "Dateiauswahl abgebrochen" -#: usr/lib/simbuto/python/simbuto/gui.py:355 -#: usr/lib/simbuto/python/simbuto/gui.py:382 +#: usr/lib/simbuto/python/simbuto/gui.py:496 +#: usr/lib/simbuto/python/simbuto/gui.py:523 msgid "File selection dialog was closed" msgstr "Dateiauswahldialog wurde geschlossen" -#: usr/lib/simbuto/python/simbuto/gui.py:362 +#: usr/lib/simbuto/python/simbuto/gui.py:503 msgid "Please select a saving destination" msgstr "Bitte einen Speicherort auswählen" -#: usr/lib/simbuto/python/simbuto/gui.py:389 +#: usr/lib/simbuto/python/simbuto/gui.py:530 msgid "This feature is currently not implemented." msgstr "Diese Funktionalität ist momentan noch nicht implementiert." -#: usr/lib/simbuto/python/simbuto/gui.py:396 +#: usr/lib/simbuto/python/simbuto/gui.py:537 msgid "Do you want to save your current budget?" msgstr "Das aktuelle Budget speichern?" -#: usr/lib/simbuto/python/simbuto/gui.py:399 +#: usr/lib/simbuto/python/simbuto/gui.py:540 msgid "The user wants to save the budget to file." msgstr "Der Benutzer möchte das aktuelle Budget speichern." -#: usr/lib/simbuto/python/simbuto/gui.py:402 +#: usr/lib/simbuto/python/simbuto/gui.py:543 msgid "The user does NOT want to save the budget." msgstr "Das Benutzer möchte das aktuelle Budget NICHT speichern." -#: usr/lib/simbuto/python/simbuto/gui.py:409 +#: usr/lib/simbuto/python/simbuto/gui.py:550 msgid "a simple budgeting tool" msgstr "ein einfaches Werkzeug zur Kostenplanung" -#: usr/lib/simbuto/python/simbuto/gui.py:432 +#: usr/lib/simbuto/python/simbuto/gui.py:573 msgid "Saving the current budget to the file '{}'..." msgstr "Speichere das aktuelle Budget in die Datei '{}'..." -#: usr/lib/simbuto/python/simbuto/gui.py:438 -#: usr/lib/simbuto/python/simbuto/gui.py:441 +#: usr/lib/simbuto/python/simbuto/gui.py:579 +#: usr/lib/simbuto/python/simbuto/gui.py:582 msgid "Budget saved to '{}'" msgstr "Budget wurde nach '{}' gespeichert" -#: usr/lib/simbuto/python/simbuto/gui.py:443 +#: usr/lib/simbuto/python/simbuto/gui.py:584 msgid "Budget could NOT be saved to '{}'!" msgstr "Budget Konnte NICHT nach '{}' gespeichert werden!" -#: usr/lib/simbuto/python/simbuto/gui.py:445 +#: usr/lib/simbuto/python/simbuto/gui.py:586 msgid "[WARNING] Budget could not be saved to '{}'!" msgstr "[WARNUNG] Budget konnte NICHT nach '{}' gespeichert werden!" -#: usr/lib/simbuto/python/simbuto/gui.py:456 +#: usr/lib/simbuto/python/simbuto/gui.py:597 msgid "read file '{}' into editor...." msgstr "lese Datei '{}' in den Editor ein..." -#: usr/lib/simbuto/python/simbuto/gui.py:465 +#: usr/lib/simbuto/python/simbuto/gui.py:606 msgid "editor was filled with contents of file '{}'" msgstr "Der Editor wurde mit den Inhalten der Datei '{}' gefüllt" -#: usr/lib/simbuto/python/simbuto/gui.py:470 -#: usr/lib/simbuto/python/simbuto/manager.py:55 +#: usr/lib/simbuto/python/simbuto/gui.py:611 +#: usr/lib/simbuto/python/simbuto/manager.py:56 msgid "Reading from file '{}' didn't work!" msgstr "Lesen von der Datei '{}' hat nicht funktioniert!" -#: usr/lib/simbuto/python/simbuto/gui.py:481 +#: usr/lib/simbuto/python/simbuto/gui.py:622 msgid "Starting GLib main loop..." msgstr "starte GLib Hautpschleife..." -#: usr/lib/simbuto/python/simbuto/gui.py:483 +#: usr/lib/simbuto/python/simbuto/gui.py:624 msgid "GLib main loop ended." msgstr "GLib Hauptschleife beendet." -#: usr/lib/simbuto/python/simbuto/gui.py:487 +#: usr/lib/simbuto/python/simbuto/gui.py:633 msgid "Received quitting signal." msgstr "Anhaltesignal erhalten." @@ -308,27 +364,27 @@ msgstr "Führe Aktion '{}' mit Daten '{}' aus" msgid "Attempt to emit unregistered signal '{}'" msgstr "Versuch, unregistriertes Signal '{}' zu emittieren" -#: usr/lib/simbuto/python/simbuto/manager.py:50 +#: usr/lib/simbuto/python/simbuto/manager.py:51 msgid "Read {} characters from file '{}'" msgstr "Lese {} Zeichen von Datei '{}'" -#: usr/lib/simbuto/python/simbuto/manager.py:66 +#: usr/lib/simbuto/python/simbuto/manager.py:67 msgid "Saving {} characters to file '{}'..." msgstr "Speichere {} Zeichen in die Datei '{}'..." -#: usr/lib/simbuto/python/simbuto/manager.py:71 +#: usr/lib/simbuto/python/simbuto/manager.py:72 msgid "Saved {} characters to file '{}'" msgstr "{} Zeichen wurden in die Datei '{}' gespeichert" -#: usr/lib/simbuto/python/simbuto/manager.py:76 +#: usr/lib/simbuto/python/simbuto/manager.py:77 msgid "Saving {} characters to file '{}' didn't work!" msgstr "Speichern von {} Zeichen in die Datei '{}' hat nicht funktioniert!" -#: usr/lib/simbuto/python/simbuto/manager.py:96 +#: usr/lib/simbuto/python/simbuto/manager.py:97 msgid "Calculating md5sum of file '{}' didn't work!" msgstr "Berechnen der md5-Summe für die Datei '{}' hat nicht funktioniert!" -#: usr/lib/simbuto/python/simbuto/manager.py:118 +#: usr/lib/simbuto/python/simbuto/manager.py:140 msgid "R could not read from text" msgstr "R konnte den Text nicht einlesen." @@ -488,9 +544,6 @@ msgstr "über die Kommandozeile wurde keine zu öffnende Datei angegeben" #~ msgid "giving the device another {} seconds of warmup time..." #~ msgstr "warte noch {} Sekunden, bis das Gerät bereit ist..." -#~ msgid "opened data file" -#~ msgstr "Aufzeichnungsdatei geöffnet" - #~ msgid "opened {} for data logging." #~ msgstr "Datei {} zur Datenaufzeichnung geöffnet."