## Filename : charter_info.py
## Author(s) : Geoffroy Andrieux
## Created : 03/2010
## Revision :
## Source :
##
## Copyright 2012 - 2020 IRISA/IRSET
##
## This library is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published
## by the Free Software Foundation; either version 2.1 of the License, or
## any later version.
##
## This library is distributed in the hope that it will be useful, but
## WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF
## MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. The software and
## documentation provided here under is on an "as is" basis, and IRISA has
## no obligations to provide maintenance, support, updates, enhancements
## or modifications.
## In no event shall IRISA be liable to any party for direct, indirect,
## special, incidental or consequential damages, including lost profits,
## arising out of the use of this software and its documentation, even if
## IRISA have been advised of the possibility of such damage. See
## the GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this library; if not, write to the Free Software Foundation,
## Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
##
## The original code contained here was initially developed by:
##
## Geoffroy Andrieux.
## IRISA
## Symbiose team
## IRISA Campus de Beaulieu
## 35042 RENNES Cedex, FRANCE
##
##
## Contributor(s): Michel Le Borgne, Nolwenn Le Meur
##
"""
Widget for displaying information on the elements of the model
CharterInfo: Contains 3 classes inheriting from :class:`Info`:
:class:`ModelInfo`
:class:`NodeInfo`
:class:`TransInfo`
"""
from __future__ import print_function
import gtk
import pkg_resources
import json
from utils.text_page import TextEditConfig, TextPage
from cadbiom import commons as cm
[docs]class CharterInfo(gtk.Frame):
"""Windows for displaying information on the elements of the model
Contains 3 classes whose role is to update in real time the fields in the GUI
about the currently selected transition, model or node.
.. seealso::
:class:`ModelInfo`
:class:`NodeInfo`
:class:`TransInfo`
This class is directly linked to the observers of the :class:`ChartControler`
thanks to the signal `current_change`.
"""
def __init__(self, frame):
self.frame = frame
self.controler = None
self.fact_window = None
self.model_info = ModelInfo(self)
self.node_info = NodeInfo(self)
self.trans_info = TransInfo(self)
self.current_info = self.model_info
[docs] def set_controler(self, new_controler):
"""Associate a controler in a MVC pattern
.. note:: attach current_change signal to the given controller.
:param new_controler: New ChartControler
:type new_controler: <ChartControler>
"""
if self.controler:
self.controler.detach("current_change", self)
self.controler = new_controler
self.controler.attach("current_change", self)
[docs] def display(self):
"""
Show all
"""
chi = self.frame.get_child()
if chi:
self.frame.remove(chi)
self.frame.add(self.current_info.frame)
self.frame.show()
[docs] def switch_to(self, new_info):
"""
callback when info change
"""
if self.current_info is not None:
self.current_info.warn_change()
self.current_info = new_info
self.display()
[docs] def update(self, node, transition):
"""
Used if registered as an observer
"""
if node is None and transition is None:
self.model_info.update(self.controler)
self.switch_to(self.model_info)
elif transition is None:
if node.is_top_node():
# Update ModelInfo
self.model_info.update(self.controler)
self.switch_to(self.model_info)
else:
# Update NodeInfo
self.node_info.update(node)
self.switch_to(self.node_info)
else:
# Update TransInfo
self.trans_info.update(transition)
self.switch_to(self.trans_info)
[docs] def enter_callback(self, widget, entry):
"""
return the entry
"""
entry_text = entry.get_text()
print("Entry contents: %s\n" % entry_text)
[docs] def has_transition(self):
"""
As it says
"""
return self.current_info.has_transition()
[docs]class Info(object):
"""Abstract class
Implementing a "notes window" for metadata of transitions and nodes
Used by::
:class:`ModelInfo`
:class:`NodeInfo`
:class:`TransInfo`
"""
[docs] def warn_change(self):
"""Called when ChartInfo is updated (Ex: save notes)"""
pass
[docs] def has_transition(self):
"""Return the current transition"""
pass
[docs] def update(self, controler):
"""Used when registered as an observer"""
pass
[docs] def display_note_window(self, title, note_text):
"""Display a window with the given text content
Used to display notes from the selected transitions or nodes.
.. seealso: :class:`NodeInfo`, :class:`TransInfo`.
:param title: Title of the window
:param note_text: Text content to display
:type title: <str>
:type note_text: <str>
"""
self.note_window = gtk.Window(gtk.WINDOW_TOPLEVEL)
# TEST: Do not save the notes
# self.note_window.connect("destroy", self.save_note)
self.note_window.set_title("notes: " + title)
self.note_window.set_position(gtk.WIN_POS_CENTER)
self.note_window.set_keep_above(True)
self.note_window.set_default_size(600, 300)
self.note_window.connect("key_press_event", self.on_escape)
# Favicon
favicon = pkg_resources.resource_filename(
__name__,
"images/favicon.ico"
)
self.note_window.set_icon_from_file(favicon)
ed_conf = TextEditConfig()
self.note_text_page = TextPage(None, ed_conf)
# TEST: Not editable
self.note_text_page.write.set_editable(False)
# Handle JSON data
try:
parsed = json.loads(note_text)
note = json.dumps(parsed, indent=2, sort_keys=True)
except ValueError:
note = note_text
self.note_text_page.set_text(note)
self.note_window.add(self.note_text_page)
self.note_window.show_all()
[docs] def on_escape(self, widget, event):
"""On ESC key_press_event, destroy this window."""
if gtk.gdk.keyval_name(event.keyval) == "Escape":
self.note_window.destroy()
[docs] def save_note(self, widget):
"""Save the current text modified in display_note_window"""
raise NotImplementedError("Abstract method")
[docs]class ModelInfo(Info):
"""Object used as a model - store information for CharterInfo"""
def __init__(self, cin):
template = pkg_resources.resource_filename(
__name__, "chart_glade/model_info.glade"
)
self.page = gtk.glade.XML(template)
wid = self.page.get_widget("model_frame")
self.frame = wid.get_child()
wid.remove(self.frame)
self.info = cin
self.name = self.page.get_widget("model_entry")
self.name.connect("changed", self.set_model)
self.name.set_editable(True)
self.nb_nodes = self.page.get_widget("node_entry")
self.nb_nodes.set_editable(False)
self.nb_nodes.set_sensitive(False)
self.nb_trans = self.page.get_widget("trans_entry")
self.nb_trans.set_editable(False)
self.nb_trans.set_sensitive(False)
[docs] def set_model(self, widget):
"""Called when the name of the model has been modified by a user
- set the name of the model,
- then notify the model.
"""
self.model.name = self.name.get_text()
self.model.notify()
[docs] def update(self, controler):
"""
when used as an observer
"""
self.model = controler.model
self.name.set_text(controler.model.name)
nodes = str(len(self.model.simple_node_dict.keys()))
trans = str(len(self.model.transition_list))
self.nb_nodes.set_text(nodes)
self.nb_trans.set_text(trans)
[docs]class NodeInfo(Info):
"""A component of CharterInfo used for nodes
.. TODO:: Display node notes; move notes code from TransInfo to Info
"""
def __init__(self, cin):
template = pkg_resources.resource_filename(
__name__, "chart_glade/node_info.glade"
)
self.page = gtk.glade.XML(template)
wid = self.page.get_widget("node_frame")
self.frame = wid.get_child()
wid.remove(self.frame)
self.info = cin
self.name = self.page.get_widget("node_entry")
self.name.connect("changed", self.set_node)
# Button
self.show_notes_button = self.page.get_widget("button_metadata")
self.show_notes_button.connect("clicked", self.set_note)
[docs] def set_node(self, widget):
"""Called when the node has been modified by a user
- set the node settings,
- then notify the model.
"""
self.node.set_name(self.name.get_text())
self.node.model.notify()
[docs] def update(self, node):
"""
Used when registered as an observer
"""
if node:
self.node = node
self.name.set_text(node.name)
[docs] def set_note(self, widget):
"""Associate a text note to a node
Use the method of the parent class :class:`Info` to display the note.
"""
self.display_note_window(self.node.name, self.node.note)
[docs]class TransInfo(Info):
"""A component of CharterInfo used for transitions"""
def __init__(self, cin):
template = pkg_resources.resource_filename(
__name__, "chart_glade/trans_info.glade"
)
self.page = gtk.glade.XML(template)
wid = self.page.get_widget("trans_frame")
self.frame = wid.get_child()
wid.remove(self.frame)
self.info = cin # owner
self.note_window = None
# Text entries
self.name = self.page.get_widget("trans_entry")
self.name.set_editable(False)
self.evt = self.page.get_widget("evt_entry")
self.cond = self.page.get_widget("cond_entry")
# Buttons
self.show_notes_button = self.page.get_widget("button_metadata")
# Attached to Charter.on_display_states via clicked event
self.show_influencing_nodes_button = self.page.get_widget(
"button_influencing_nodes"
)
# Tooltips
self.tooltips = gtk.Tooltips()
self.tooltips.set_tip(self.show_notes_button, "Show the transition metadata")
self.tooltips.set_tip(
self.show_influencing_nodes_button,
"Show the nodes influencing this transition",
)
self.tooltips.enable()
self.tooltips.set_delay(cm.TOOLTIPS_DELAY)
# User can change all the entries
self.name.connect("changed", self.set_trans)
self.evt.connect("changed", self.set_trans)
self.cond.connect("changed", self.set_trans)
self.show_notes_button.connect("clicked", self.set_note)
[docs] def set_trans(self, widget):
"""Called when the transition has been modified by a user
(and after TransInfo update)
- set the transition settings,
- then notify the model.
"""
if self.lock:
return
self.trans.set_name(self.name.get_text())
self.trans.set_event(self.evt.get_text())
self.trans.set_condition(self.cond.get_text())
self.trans.ori.model.notify()
[docs] def warn_change(self):
"""
As it says
"""
# TEST: Do not save the notes
# self.save_note(None)
pass
[docs] def update(self, trans):
"""
When registered as an observer
"""
if trans:
self.lock = True
self.trans = trans # for fact association management
self.name.set_text(trans.ori.name + "->" + trans.ext.name)
self.evt.set_text(trans.event)
self.cond.set_text(trans.condition)
self.lock = False
[docs] def has_transition(self):
"""
As it says
"""
return self.trans
[docs] def set_note(self, widget):
"""Associate a text note to a transition
Use the method of the parent class :class:`Info` to display the note.
"""
self.display_note_window(
self.trans.ori.name + "->" + self.trans.ext.name, self.trans.note
)
[docs] def save_note(self, widget):
"""
register the note (deactivated for now)
"""
if self.note_window:
text = self.note_text_page.get_text()
self.trans.note = text
self.trans.ori.model.modified = True
self.note_window.destroy()
self.note_window = None