diff --git a/ChangeLog b/ChangeLog index 633bd7639..a4156086a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2007-11-25 Benny Malengier + * src/gen/lib/notetype.py: type report, citation + * src/plugins/NarrativeWeb.py: new selection of home note & home media + * src/GrampsWidgets.py: NoteEntry, MediaEntry + I intend to change the other note selectors likewise next. + 2007-11-25 Douglas S. Blank * src/gen/lib/date.py: refer to Config values via Config.get() * src/gen/lib/test/date_test.py: set Config values before testing diff --git a/src/GrampsWidgets.py b/src/GrampsWidgets.py index 92f7f2c0b..5822f0667 100644 --- a/src/GrampsWidgets.py +++ b/src/GrampsWidgets.py @@ -742,19 +742,20 @@ class ObjEntry: to select the object. This is the base class to create a real entry """ - def __init__(self, dbstate, uistate, track, obj, set_val, - get_val, add_del, share): + def __init__(self, dbstate, uistate, track, label, set_val, + get_val, add_edt, share): '''Pass the dbstate and uistate and present track. - obj is a gtk.Label that shows the persent value + label is a gtk.Label that shows the persent value set_val is function that is called when handle changes, use it to update the calling module get_val is function that is called to obtain handle from calling module - add_del is the gtk.Button with add or delete value - share is the gtk.Button to call the object selector + share is the gtk.Button to call the object selector or del connect + add_edt is the gtk.Button with add or edit value. Pass None if + this button should not be present. ''' - self.obj = obj - self.add_del = add_del + self.label = label + self.add_edt = add_edt self.share = share self.dbstate = dbstate self.db = dbstate.db @@ -769,29 +770,39 @@ class ObjEntry: #set the object specific code self._init_object() - if get_val(): + #check if valid object: + handle = self.get_val() + if handle: + obj = self.get_from_handle(handle) + if not obj: + #invalid val, set it to None + self.set_val(None) + if self.get_val(): self.set_button(True) - p = self.get_from_handle(self.get_val()) - name = self.get_label(p) + obj = self.get_from_handle(self.get_val()) + name = self.get_label(obj) else: name = u"" self.set_button(False) if self.db.readonly: - self.add_del.set_sensitive(False) + if self.add_edt is not None: + self.add_edt.set_sensitive(False) self.share.set_sensitive(False) else: - self.add_del.set_sensitive(True) + if self.add_edt is not None: + self.add_edt.set_sensitive(True) self.share.set_sensitive(True) - self.add_del.connect('clicked', self.add_del_clicked) + if self.add_edt is not None: + self.add_edt.connect('clicked', self.add_edt_clicked) self.share.connect('clicked', self.share_clicked) if not self.db.readonly and not name: - obj.set_text(self.EMPTY_TEXT) - obj.set_use_markup(True) + self.label.set_text(self.EMPTY_TEXT) + self.label.set_use_markup(True) else: - obj.set_text(name) + self.label.set_text(name) def _init_dnd(self): '''inheriting objects must set this @@ -817,15 +828,14 @@ class ObjEntry: def after_edit(self, obj): name = self.get_label(obj) - self.obj.set_text(name) + self.label.set_text(name) - def add_del_clicked(self, obj): - ''' if value, delete, if no value, call editor + def add_edt_clicked(self, obj): + ''' if value, edit, if no value, call editor on new object ''' if self.get_val(): - self.set_val(None) - self.obj.set_text(u'') - self.set_button(False) + obj = self.get_from_handle(self.get_val()) + self.call_editor(obj) else: self.call_editor() @@ -848,15 +858,16 @@ class ObjEntry: def obj_added(self, data): ''' callback from adding an object to the entry''' self.set_val(data.handle) - self.obj.set_text(self.get_label(data)) + self.label.set_text(self.get_label(data)) self.set_button(True) def share_clicked(self, obj): - ''' if value, edit object, in no value, select existing object + ''' if value, delete connect, in no value, select existing object ''' if self.get_val(): - obj = self.get_from_handle(self.get_val()) - self.call_editor(obj) + self.set_val(None) + self.label.set_text(self.EMPTY_TEXT) + self.set_button(False) else: select = self.call_selector() obj = select.run() @@ -864,10 +875,13 @@ class ObjEntry: self.obj_added(obj) def set_button(self, use_add): - ''' This sets the correct image to the two buttons + ''' This sets the correct image to the two buttons. + If False: select icon and add icon + If True: remove icon and edit icon ''' - for i in self.add_del.get_children(): - self.add_del.remove(i) + if self.add_edt is not None: + for i in self.add_edt.get_children(): + self.add_edt.remove(i) for i in self.share.get_children(): self.share.remove(i) @@ -875,24 +889,26 @@ class ObjEntry: image = gtk.Image() image.set_from_stock(gtk.STOCK_REMOVE, gtk.ICON_SIZE_BUTTON) image.show() - self.add_del.add(image) - image = gtk.Image() - image.set_from_stock(gtk.STOCK_EDIT, gtk.ICON_SIZE_BUTTON) - image.show() self.share.add(image) - self.tooltips.set_tip(self.share, self.EDIT_STR) - self.tooltips.set_tip(self.add_del, self.DEL_STR) + self.tooltips.set_tip(self.share, self.DEL_STR) + if self.add_edt is not None: + image = gtk.Image() + image.set_from_stock(gtk.STOCK_EDIT, gtk.ICON_SIZE_BUTTON) + image.show() + self.add_edt.add(image) + self.tooltips.set_tip(self.add_edt, self.EDIT_STR) else: - image = gtk.Image() - image.set_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_BUTTON) - image.show() - self.add_del.add(image) image = gtk.Image() image.set_from_stock(gtk.STOCK_INDEX, gtk.ICON_SIZE_BUTTON) image.show() self.share.add(image) self.tooltips.set_tip(self.share, self.SHARE_STR) - self.tooltips.set_tip(self.add_del, self.ADD_STR) + if self.add_edt is not None: + image = gtk.Image() + image.set_from_stock(gtk.STOCK_ADD, gtk.ICON_SIZE_BUTTON) + image.show() + self.add_edt.add(image) + self.tooltips.set_tip(self.add_edt, self.ADD_STR) class PlaceEntry(ObjEntry): """ @@ -906,17 +922,17 @@ class PlaceEntry(ObjEntry): ADD_STR = _('Add a new place') DEL_STR = _('Remove place') - def __init__(self, dbstate, uistate, track, obj, set_val, - get_val, add_del, share): - ObjEntry.__init__(self, dbstate, uistate, track, obj, set_val, - get_val, add_del, share) + def __init__(self, dbstate, uistate, track, label, set_val, + get_val, add_edt, share): + ObjEntry.__init__(self, dbstate, uistate, track, label, set_val, + get_val, add_edt, share) def _init_dnd(self): '''connect drag and drop of places ''' - self.obj.drag_dest_set(gtk.DEST_DEFAULT_ALL, [DdTargets.PLACE_LINK.target()], + self.label.drag_dest_set(gtk.DEST_DEFAULT_ALL, [DdTargets.PLACE_LINK.target()], gtk.gdk.ACTION_COPY) - self.obj.connect('drag_data_received', self.drag_data_received) + self.label.connect('drag_data_received', self.drag_data_received) def get_from_handle(self, handle): ''' return the object given the hande @@ -947,6 +963,59 @@ class PlaceEntry(ObjEntry): cls = selector_factory('Place') return cls(self.dbstate, self.uistate, self.track) +class MediaEntry(ObjEntry): + """ + Handles the selection of a existing or new media. Supports Drag and Drop + to select a media object. + """ + EMPTY_TEXT = "%s" % _('To select a media object, use drag-and-drop ' + 'or use the buttons') + EDIT_STR = _('Edit media object') + SHARE_STR = _('Select an existing media object') + ADD_STR = _('Add a new media object') + DEL_STR = _('Remove media object') + + def __init__(self, dbstate, uistate, track, label, set_val, + get_val, add_edt, share): + ObjEntry.__init__(self, dbstate, uistate, track, label, set_val, + get_val, add_edt, share) + + def _init_dnd(self): + '''connect drag and drop of places + ''' + self.label.drag_dest_set(gtk.DEST_DEFAULT_ALL, [DdTargets.MEDIAOBJ.target()], + gtk.gdk.ACTION_COPY) + self.label.connect('drag_data_received', self.drag_data_received) + + def get_from_handle(self, handle): + ''' return the object given the hande + ''' + return self.db.get_object_from_handle(handle) + + def get_label(self, object): + return "%s [%s]" % (object.get_description(), object.gramps_id) + + def call_editor(self, obj=None): + from Editors import EditMedia + + if obj is None: + from gen.lib import MediaObject + object = MediaObject() + func = self.obj_added + else: + object = obj + func = self.after_edit + try: + EditMedia(self.dbstate, self.uistate, self.track, + object, func) + except WindowActiveError: + pass + + def call_selector(self): + from Selectors import selector_factory + cls = selector_factory('MediaObject') + return cls(self.dbstate, self.uistate, self.track) + class NoteEntry(ObjEntry): """ Handles the selection of a existing or new Note. Supports Drag and Drop @@ -959,17 +1028,28 @@ class NoteEntry(ObjEntry): ADD_STR = _('Add a new note') DEL_STR = _('Remove note') - def __init__(self, dbstate, uistate, track, obj, set_val, - get_val, add_del, share): - ObjEntry.__init__(self, dbstate, uistate, track, obj, set_val, - get_val, add_del, share) + def __init__(self, dbstate, uistate, track, label, set_val, + get_val, add_edt, share): + ObjEntry.__init__(self, dbstate, uistate, track, label, set_val, + get_val, add_edt, share) + self.notetype = None + + def set_notetype(self, type): + ''' set a notetype to use in new notes + ''' + self.notetype = type + + def get_notetype(self): + ''' return the set notetype + ''' + return self.notetype def _init_dnd(self): '''connect drag and drop of places ''' - self.obj.drag_dest_set(gtk.DEST_DEFAULT_ALL, [DdTargets.NOTE_LINK.target()], + self.label.drag_dest_set(gtk.DEST_DEFAULT_ALL, [DdTargets.NOTE_LINK.target()], gtk.gdk.ACTION_COPY) - self.obj.connect('drag_data_received', self.drag_data_received) + self.label.connect('drag_data_received', self.drag_data_received) def get_from_handle(self, handle): ''' return the object given the hande @@ -977,27 +1057,27 @@ class NoteEntry(ObjEntry): return self.db.get_note_from_handle(handle) def get_label(self, note): - note = " ".join(note.get(markup=False).split()) - if len(note) > 35: - txt = note[:35]+"..." + txt = " ".join(note.get(markup=False).split()) + if len(txt) > 35: + txt = txt[:35]+"..." else: - txt = note - return "%s [%s]" % (txt, p.gramps_id) + txt = txt + return "%s [%s]" % (txt, note.gramps_id) def call_editor(self, obj=None): from Editors import EditNote if obj is None: - from gen.lib import Note, Notetype + from gen.lib import Note note = Note() - note.set_type(NoteType.REPORT) + note.set_type(self.get_notetype()) func = self.obj_added else: note = obj func = self.after_edit try: EditNote(self.dbstate, self.uistate, self.track, - note, func) + note, func) except WindowActiveError: pass diff --git a/src/gen/lib/notetype.py b/src/gen/lib/notetype.py index 64b5b99ff..11ae58097 100644 --- a/src/gen/lib/notetype.py +++ b/src/gen/lib/notetype.py @@ -67,18 +67,22 @@ class NoteType(GrampsType): PERSONNAME = 20 # other common types SOURCE_TEXT = 21 # this is used for verbatim source text in SourceRef + CITATION = 22 + REPORT_TEXT = 23 # this is used for notes used for reports _CUSTOM = CUSTOM _DEFAULT = GENERAL _DATAMAPREAL = [ - (UNKNOWN, _("Unknown"), "Unknown"), - (CUSTOM, _("Custom"), "Custom"), - (GENERAL, _("General"), "General"), - (RESEARCH, _("Research"), "Research"), - (TRANSCRIPT, _("Transcript"), "Transcript"), + (UNKNOWN, _("Unknown"), "Unknown"), + (CUSTOM, _("Custom"), "Custom"), + (GENERAL, _("General"), "General"), + (RESEARCH, _("Research"), "Research"), + (TRANSCRIPT, _("Transcript"), "Transcript"), (SOURCE_TEXT, _("Source text"), "Source text"), + (CITATION, _('Citation'), "Citation"), + (REPORT_TEXT, _("Report"), "Report"), ] _DATAMAPIGNORE = [ diff --git a/src/plugins/NarrativeWeb.py b/src/plugins/NarrativeWeb.py index ae5c6e7bf..e8c9522d9 100644 --- a/src/plugins/NarrativeWeb.py +++ b/src/plugins/NarrativeWeb.py @@ -80,6 +80,7 @@ import Utils import ThumbNails import ImgManip import GrampsLocale +import GrampsWidgets import Mime from QuestionDialog import ErrorDialog, WarningDialog from BasicUtils import name_displayer as _nd @@ -174,7 +175,8 @@ class BasePage: self.photo_list = photo_list self.usegraph = options.handler.options_dict['NWEBgraph'] self.graphgens = options.handler.options_dict['NWEBgraphgens'] - self.use_home = self.options.handler.options_dict['NWEBhomenote'] != "" + self.use_home = self.options.handler.options_dict['NWEBhomenote'] != "" or \ + self.options.handler.options_dict['NWEBhomepic'] != "" self.page_title = "" self.warn_dir = True @@ -1398,20 +1400,21 @@ class HomePage(BasePage): BasePage.__init__(self, title, options, archive, media_list, "") note_id = options.handler.options_dict['NWEBhomenote'] + pic_id = options.handler.options_dict['NWEBhomepic'] of = self.create_file("index") author = get_researcher().get_name() self.display_header(of,db,_('Home'),author) of.write('

%s

\n' % _('Home')) - if note_id: - obj = db.get_object_from_handle(note_id) + if pic_id: + obj = db.get_object_from_handle(pic_id) mime_type = obj.get_mime_type() if mime_type and mime_type.startswith("image"): try: (newpath,thumb_path) = self.copy_media(obj,False) - self.store_file(archive,self.html_dir,obj.get_path(), + self.store_file(archive, self.html_dir, obj.get_path(), newpath) of.write('
\n') of.write('' % obj.get_description()) of.write('
\n') except (IOError,OSError),msg: - WarningDialog(_("Could not add photo to page"),str(msg)) + WarningDialog(_("Could not add photo to page"), str(msg)) - notelist = obj.get_note_list() - if notelist: - note_obj = db.get_note_from_handle(notelist[0]) - text = note_obj.get(markup=True) - if note_obj.get_format(): - of.write('
\n%s\n
\n' % text) - else: - of.write('

') - of.write('

'.join(text.split('\n'))) - of.write('

') + if note_id: + note_obj = db.get_note_from_handle(note_id) + text = note_obj.get(markup=True) + if note_obj.get_format(): + of.write('
\n%s\n
\n' % text) + else: + of.write('

') + of.write('

'.join(text.split('\n'))) + of.write('

') self.display_footer(of,db) self.close_file(of) @@ -2359,6 +2361,7 @@ class WebReport(Report): NWEBencoding NWEBintronote NWEBhomenote + NWEBhomepic NWEBnoid NWEBlinkhome NWEBshowbirth @@ -2415,7 +2418,8 @@ class WebReport(Report): self.user_footer = options.handler.options_dict['NWEBfooter'] self.use_archive = options.handler.options_dict['NWEBarchive'] self.use_intro = options.handler.options_dict['NWEBintronote'] != u"" - self.use_home = options.handler.options_dict['NWEBhomenote'] != u"" + self.use_home = options.handler.options_dict['NWEBhomenote'] != u"" or\ + options.handler.options_dict['NWEBhomepic'] != u"" def write_report(self): if not self.use_archive: @@ -2702,12 +2706,13 @@ class WebReportOptions(ReportOptions): 'NWEBcss' : 'main0.css', 'NWEBintronote' : '', 'NWEBhomenote' : '', + 'NWEBhomepic' : '', } self.options_help = { } - def add_user_options(self,dialog): + def add_user_options(self, dialog): priv_msg = _("Do not include records marked private") living_msg = _("Living People") death_msg = _("Years from death to consider living") @@ -2851,12 +2856,14 @@ class WebReportOptions(ReportOptions): media_list = [['','']] html_list = [['','']] + #Page Generation tab if self.db: cursor = self.db.get_media_cursor() data = cursor.first() while data: (handle, value) = data if not value[3]: + #no mime type html_list.append([value[4],handle]) media_list.append([value[4],handle]) @@ -2865,14 +2872,29 @@ class WebReportOptions(ReportOptions): media_list.sort(lambda x, y: locale.strcoll(x[0], y[0])) html_list.sort(lambda x, y: locale.strcoll(x[0], y[0])) - self.home_note = mk_combobox(media_list,self.options_dict['NWEBhomenote']) + self.home_nt_box, self.home_nt_label, self.home_nt_share_btn \ + = mk_object_entry() + self.home_note = GrampsWidgets.NoteEntry(dialog.dbstate, + dialog.uistate, dialog.track, + self.home_nt_label, + self.set_home_nt_val, self.get_home_nt_val, + None, self.home_nt_share_btn) + self.home_pic_box, self.home_pic_label, self.home_pic_share_btn \ + = mk_object_entry() + self.home_pic = GrampsWidgets.MediaEntry(dialog.dbstate, + dialog.uistate, dialog.track, + self.home_pic_label, + self.set_home_pic_val, self.get_home_pic_val, + None, self.home_pic_share_btn) self.intro_note = mk_combobox(media_list,self.options_dict['NWEBintronote']) self.contact = mk_combobox(media_list,self.options_dict['NWEBcontact']) self.header = mk_combobox(html_list,self.options_dict['NWEBheader']) self.footer = mk_combobox(html_list,self.options_dict['NWEBfooter']) - dialog.add_frame_option(title,_('Home Media/Note ID'), - self.home_note) + dialog.add_frame_option(title,_('Home Page note'), + self.home_nt_box) + dialog.add_frame_option(title,_('Home Page image'), + self.home_pic_box) dialog.add_frame_option(title,_('Introduction Media/Note ID'), self.intro_note) dialog.add_frame_option(title,contact_msg,self.contact) @@ -2895,7 +2917,41 @@ class WebReportOptions(ReportOptions): dialog.add_frame_option(title,None,self.showparents) dialog.add_frame_option(title,None,self.showhalfsiblings) - def parse_user_options(self,dialog): + def set_home_nt_val(self, val): + ''' store the note handle in options + ''' + if val is None: + self.options_dict['NWEBhomenote'] = u'' + else: + self.options_dict['NWEBhomenote'] = unicode(val) + + def get_home_nt_val(self): + ''' obtain note handle + ''' + val = self.options_dict['NWEBhomenote'] + if val == "": + return None + else: + return val + + def set_home_pic_val(self, val): + ''' store the media handle in options + ''' + if val is None: + self.options_dict['NWEBhomepic'] = u'' + else: + self.options_dict['NWEBhomepic'] = unicode(val) + + def get_home_pic_val(self): + ''' obtain note handle + ''' + val = self.options_dict['NWEBhomepic'] + if val == "": + return None + else: + return val + + def parse_user_options(self, dialog): """Parse the privacy options frame of the dialog. Save the user selected choices for later use.""" @@ -2918,7 +2974,6 @@ class WebReportOptions(ReportOptions): self.options_dict['NWEBdownload'] = int(self.inc_download.get_active()) self.options_dict['NWEBtitle'] = unicode(self.title.get_text()) self.options_dict['NWEBintronote'] = unicode(self.intro_note.get_handle()) - self.options_dict['NWEBhomenote'] = unicode(self.home_note.get_handle()) self.options_dict['NWEBgraph'] = int(self.inc_graph.get_active()) index = self.graph_gens.get_active() @@ -2959,25 +3014,30 @@ class WebReportDialog(ReportDialog): HELP_TOPIC = "rep-web" - def __init__(self,dbstate,uistate,person): + def __init__(self, dbstate, uistate, person): self.database = dbstate.db self.person = person name = "navwebpage" translated_name = _("Generate Web Site") self.options = WebReportOptions(name,self.database) self.category = CATEGORY_WEB - ReportDialog.__init__(self,dbstate,uistate,person,self.options, - name,translated_name) + ReportDialog.__init__(self, dbstate, uistate, person, self.options, + name, translated_name) self.style_name = None while True: response = self.window.run() if response == gtk.RESPONSE_OK: + self.close() self.make_report() break - elif response != gtk.RESPONSE_HELP: + elif (response == gtk.RESPONSE_DELETE_EVENT or + response == gtk.RESPONSE_CANCEL): + # the buttons generating this already call close via connect break - self.close() + + def on_cancel(self, *obj): + self.close(*obj) def setup_style_frame(self): """The style frame is not used in this dialog.""" @@ -3129,6 +3189,7 @@ class EmptyDoc: def init(self): pass + #------------------------------------------------------------------------- # # GrampsNoteComboBox @@ -3181,6 +3242,16 @@ def mk_combobox(media_list,select_value): widget.set_sensitive(False) return widget +def mk_object_entry(): + ''' return a vbox widget with fields for object selection + ''' + box = gtk.HBox() + label = gtk.Label() + button_sel = gtk.Button() + box.pack_start(label) + box.pack_start(button_sel, expand=False, fill=False) + return (box, label, button_sel) + #------------------------------------------------------------------------- # #