#######################################################################
#
# $Id: MainWindow.py,v 1.14 2008-04-07 05:09:35 lorenz Exp $
# 
# Copyright (C) 2004-2008 Petr Lorenz
# All rights reserved.
# 
# ##### BEGIN LICENSE BLOCK #####
#
# Version: MPL 1.1 / GPL 2.0 / LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
# 
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
# 
# The Original Code is Petr Lorenz emGine Graphical User Interface (GUI).
# 
# The Initial Developer of the Original Code is Petr Lorenz.
# Portions created by the Initial Developer are Copyright (C) 2004-2008.
# All Rights Reserved.
# 
# Contributor(s): Bruno Biscontini, Rachid Khlifi.
# 
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the  "GPL"), or the
# GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which
# case the provisions of the GPL or the LGPL are applicable instead of those
# above.  If you wish to allow use of your version of this file only under the
# terms of either the GPL or the LGPL and not to allow others to use your
# version of this file under the MPL, indicate your decision by deleting the
# provisions above and replace them with the notice and other provisions
# required by the GPL or LGPL.  If you do not delete the provisions above, a
# recipient may use your version of this file under the terms of any one of the
# MPL License, the GPL or the LGPL.
#
# ##### END LICENSE BLOCK #####
#
#######################################################################
# 
# $Log: MainWindow.py,v $
# Revision 1.14  2008-04-07 05:09:35  lorenz
# Smith diagram integration.
#
# Revision 1.13  2008-03-28 06:25:37  lorenz
# - Perspective/Orthogonal view
# - Top/Bottom/Front/Back/Left/Right views
# - Boundary conditions setup
# - Platform Info
#
# Revision 1.12  2008-02-26 06:07:15  lorenz
# Bugfixes for terminating a simulation on Windows.
#
# Revision 1.11  2008-02-14 05:59:26  lorenz
# Simulation thread improvements - lock, better IPC, termination.
#
# Revision 1.10  2008-02-13 15:28:26  lorenz
# Windows simulation termination implemented.
#
# Revision 1.9  2008-02-08 05:04:57  lorenz
# Unix support for terminating a simulation.
#
# Revision 1.8  2008-02-07 05:45:25  lorenz
# * Fixed 'Simulation Boundary View' check problem
#   when closing a project.
#
# * Fixed Bounding Box problems when moving/editing a geometry.
#
# Revision 1.7  2008-02-04 15:38:53  lorenz
# Simulation boundary menu unchecked when closing a project.
#
# Revision 1.6  2008-02-03 16:33:31  lorenz
# E-Mail contact added.
#
# Revision 1.5  2008-02-01 05:17:13  lorenz
# About text modified.
#
# Revision 1.4  2008-01-30 15:32:03  lorenz
# Copyright and license notice in About dialog corrected.
#
# Revision 1.3  2008-01-30 05:29:04  lorenz
# Application Icon added
#
# Revision 1.2  2008-01-28 16:15:15  lorenz
# Windows related changes (e.g., refreshing).
#
# Revision 1.1.1.1  2008-01-28 06:15:35  lorenz
# Import emGine GUI v. 0.7.1
#
# Revision 1.10  2007-07-02 06:37:18  lorenz
# Clean up of old code.
#
# Revision 1.9  2007-06-28 05:34:28  lorenz
# Checkbutton in 'View->Simulation Boundary' added.
#
# Preliminary support for polygons added.
#
# Revision 1.8  2007-06-22 04:07:19  lorenz
# Calculation of dt (delta t) from first column of TDSignal.
#
# Small changes in the computation of S-Parameters.
#
# Revision 1.7  2007-06-18 03:55:36  lorenz
# Status bar extended
#
# Revision 1.6  2007-06-14 06:31:51  lorenz
# Added emGine settings handling.
# Better handling of GUI state through GUIState class.
#
# Revision 1.5  2007-06-11 06:17:58  lorenz
# Construction plane handling added (during IMS2007, HAWAII + airplane)
#
# Revision 1.4  2007-05-18 16:37:01  lorenz
# Work on 'surrounding space' simbox and
#  'emgine_gui' tag
#
# Revision 1.3  2007-05-14 04:53:51  lorenz
# New code for multiport time-domain signals and S-parameters
#
# Revision 1.2  2007-05-10 16:30:29  lorenz
# Changes in About... menu target WEB location.
#
# Revision 1.1.1.1  2007-05-08 06:22:35  lorenz
# Initial Import
#
#######################################################################

# August 2005 - March 2008

import wx
import wx.grid
import wx.html
import wx.lib.dialogs

import os

from lsBaseDialog1 import lsBaseDialog1

import consts
import Project
import GeometryScene
import Plot2D
import PlotSmith
import Simulation

import webbrowser

from Properties import Properties

## Geometry Objects ##
#import GeometryObject
from GeometryObjectPatch import GeometryObjectPatch
from GeometryObjectBox import GeometryObjectBox
from GeometryObjectCylinder import GeometryObjectCylinder
from GeometryObjectCircle import GeometryObjectCircle
from GeometryObjectPolygon import GeometryObjectPolygon

from GroupGeometryObjects import GroupGeometryObjects

## Materials ##
from Material import Material

from GroupMaterials import GroupMaterials

from Mesh import Mesh
from SurroundingSpace import SurroundingSpace
from GUIState import GUIState
from emGineLog import emGineLog

###########################
# Dialogs
###########################
class SurroundingSpaceDialog(lsBaseDialog1):
  def __init__(self, init_data = None):
    lsBaseDialog1.__init__(self, "Surrounding Space")
    self.create_static_box("Surrounding space definition")

    self.init_data = init_data

    # fill with default values
    xmin = xmax = ymin = ymax = zmin = zmax = "0"

    # set initial values
    if self.init_data:
      if self.init_data[0][0]:
	xmin = self.init_data[0][0]
      if self.init_data[1][0]:
	xmax = self.init_data[1][0]
      if self.init_data[0][1]:
	ymin = self.init_data[0][1]
      if self.init_data[1][1]:
	ymax = self.init_data[1][1]
      if self.init_data[0][2]:
	zmin = self.init_data[0][2]
      if self.init_data[1][2]:
	zmax = self.init_data[1][2]

    entry1 = wx.StaticText(self, -1, "xmin:")
    entry2 = wx.StaticText(self, -1, "xmax:")
    entry3 = wx.StaticText(self, -1, "ymin:")
    entry4 = wx.StaticText(self, -1, "ymax:")
    entry5 = wx.StaticText(self, -1, "zmin:")
    entry6 = wx.StaticText(self, -1, "zmax:")

    entry1_t = wx.TextCtrl(self, -1, str(xmin), size=(80, -1))
    entry2_t = wx.TextCtrl(self, -1, str(xmax), size=(80, -1))
    entry3_t = wx.TextCtrl(self, -1, str(ymin), size=(80, -1))
    entry4_t = wx.TextCtrl(self, -1, str(ymax), size=(80, -1))
    entry5_t = wx.TextCtrl(self, -1, str(zmin), size=(80, -1))
    entry6_t = wx.TextCtrl(self, -1, str(zmax), size=(80, -1))

    # Sizer
    fgs = wx.FlexGridSizer(3, 4, 5, 5)	# rows, cols, hgap, vgap
    fgs.Add(entry1, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry1_t, 0, wx.EXPAND)
    fgs.Add(entry2, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry2_t, 0)#, wx.EXPAND)
    fgs.Add(entry3, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry3_t, 0)#, wx.EXPAND)
    fgs.Add(entry4, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry4_t, 0)#, wx.EXPAND)
    fgs.Add(entry5, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry5_t, 0)#, wx.EXPAND)
    fgs.Add(entry6, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry6_t, 0)#, wx.EXPAND)

    self.set_user_sizer(fgs)
    self.set_data_text_fields([entry1_t, entry2_t, entry3_t, entry4_t, entry5_t, entry6_t])

class NewProjectDialog(lsBaseDialog1):
  def __init__(self): #, units_length_dict, units_frequency_dict, units_time_dict):
    lsBaseDialog1.__init__(self, "New Project")
    self.create_static_box("Project Definition")

    choice_1_list = ['m', 'cm', 'mm', 'um', 'nm', 'mil']
    choice_2_list = ['Hz', 'kHz', 'MHz', 'GHz', 'THz']
    choice_3_list = ['s', 'ms', 'us', 'ns']

    entry1 = wx.StaticText(self, -1, "Project name:")
    entry2 = wx.StaticText(self, -1, "Length units:")
    entry3 = wx.StaticText(self, -1, "Frequency units:")
    entry4 = wx.StaticText(self, -1, "Time units:")

    entry1_t = wx.TextCtrl(self, -1, "", size=(150, -1))
    choice1 = wx.Choice(self, -1, (80, -1), choices = choice_1_list)
    choice2 = wx.Choice(self, -1, (80, -1), choices = choice_2_list)
    choice3 = wx.Choice(self, -1, (80, -1), choices = choice_3_list)
    choice1.SetSelection(2)
    choice2.SetSelection(3)
    choice3.SetSelection(0)

    # Sizer
    fgs = wx.FlexGridSizer(4, 2, 10, 5)	# rows, cols, hgap, vgap
    fgs.Add(entry1, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry1_t, 0, wx.EXPAND)

    fgs.Add(entry2, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(choice1, 0)

    fgs.Add(entry3, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(choice2, 0)

    fgs.Add(entry4, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(choice3, 0)

    self.set_user_sizer(fgs)
    self.set_data_text_fields([entry1_t])
    self.set_data_items([choice1, choice2, choice3])
    self.set_items_lists([choice_1_list, choice_2_list, choice_3_list])

##############################################################
### class GeometryChangeMaterialDialog(tkSimpleDialog.Dialog):
###   def __init__(self, master, matl, title):
###     self.matl = matl
###     tkSimpleDialog.Dialog.__init__(self, master, title)
###     
###   def body(self, master):
###     print self.matl  
###     Label(master, text="Choose Material:... ").grid(row = 0, sticky = W)
###     self.listbox = Listbox(master)
###     for item in self.matl:
###         self.listbox.insert(END,item)
###     #self.listbox.insert(END,self.material_list)
###     self.listbox.grid(row = 1, sticky = W)
###     return self.listbox	    #initial focus
###    
###   def apply(self):
###     self.result = self.listbox.get(ACTIVE)  

class ExcitationVoltagePortDialog(lsBaseDialog1):
  def __init__(self):
    lsBaseDialog1.__init__(self, "Voltage Port")
    self.create_static_box("Voltage port definition")

    entry1 = wx.StaticText(self, -1, "Port name:")
    entry2 = wx.StaticText(self, -1, "x1:")
    entry3 = wx.StaticText(self, -1, "y1:")
    entry4 = wx.StaticText(self, -1, "z1:")
    entry5 = wx.StaticText(self, -1, "x2:")
    entry6 = wx.StaticText(self, -1, "y2:")
    entry7 = wx.StaticText(self, -1, "z2:")

    entry1_t = wx.TextCtrl(self, -1, "Voltage", size=(80, -1))
    entry2_t = wx.TextCtrl(self, -1, "0.0", size=(80, -1))
    entry3_t = wx.TextCtrl(self, -1, "0.0", size=(80, -1))
    entry4_t = wx.TextCtrl(self, -1, "0.0", size=(80, -1))
    entry5_t = wx.TextCtrl(self, -1, "0.0", size=(80, -1))
    entry6_t = wx.TextCtrl(self, -1, "0.0", size=(80, -1))
    entry7_t = wx.TextCtrl(self, -1, "0.0", size=(80, -1))

    # Sizer
    fgs = wx.FlexGridSizer(3, 6, 5, 5)	# rows, cols, hgap, vgap
    fgs.Add(entry1, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry1_t, 0, wx.EXPAND)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add(entry2, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry2_t, 0)#, wx.EXPAND)
    fgs.Add(entry3, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry3_t, 0)#, wx.EXPAND)
    fgs.Add(entry4, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry4_t, 0)#, wx.EXPAND)
    fgs.Add(entry5, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry5_t, 0)#, wx.EXPAND)
    fgs.Add(entry6, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry6_t, 0)#, wx.EXPAND)
    fgs.Add(entry7, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry7_t, 0)#, wx.EXPAND)

    self.set_user_sizer(fgs)
    self.set_data_text_fields([entry1_t, entry2_t, entry3_t, entry4_t, entry5_t, entry6_t, entry7_t])

class MaterialDialog(lsBaseDialog1):
  def __init__(self, material = None):
    lsBaseDialog1.__init__(self, "Define material")
    self.create_static_box("Material definition")

    name_t = "New_Material"
    epsr_t = "1.0"
    mur_t = "1.0"
    sigmae_t = "0.0"
    tande_t = "0.0"

    entry1 = wx.StaticText(self, -1, "Material name:")
    entry2 = wx.StaticText(self, -1, "Relative permittivity (eps_r):")
    entry3 = wx.StaticText(self, -1, "Relative permeability (mu_r):")
    entry4 = wx.StaticText(self, -1, "Conductivity [S/m]:")
    entry5 = wx.StaticText(self, -1, "Dielectric loss (tan delta_e):")

    style_ = wx.TE_READONLY
    entry1_t = wx.TextCtrl(self, -1, name_t, size=(120, -1))
    entry2_t = wx.TextCtrl(self, -1, epsr_t, size=(120, -1))
    entry3_t = wx.TextCtrl(self, -1, mur_t, size=(120, -1), style = style_)
    entry4_t = wx.TextCtrl(self, -1, sigmae_t, size=(120, -1), style = style_)
    entry5_t = wx.TextCtrl(self, -1, tande_t, size=(120, -1), style = style_)

    self.set_name_entry(entry1_t)

    entry3_t.SetBackgroundColour("gray")
    entry4_t.SetBackgroundColour("gray")
    entry5_t.SetBackgroundColour("gray")

    # Sizer
    fgs = wx.FlexGridSizer(5, 2, 5, 5)	# rows, cols, hgap, vgap
    fgs.Add(entry1, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry1_t, 0, wx.EXPAND)
    fgs.Add(entry2, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry2_t, 0)#, wx.EXPAND)
    fgs.Add(entry3, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry3_t, 0)#, wx.EXPAND)
    fgs.Add(entry4, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry4_t, 0)#, wx.EXPAND)
    fgs.Add(entry5, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry5_t, 0)#, wx.EXPAND)
    #fgs.Add(entry6, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    #fgs.Add(entry6_t, 0)#, wx.EXPAND)
    #fgs.Add(entry7, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    #fgs.Add(entry7_t, 0)#, wx.EXPAND)

    self.set_user_sizer(fgs)
    self.set_data_text_fields([entry1_t, entry2_t, entry3_t, entry4_t, entry5_t]) #, entry6_t, entry7_t])

class BoundaryConditionsDialog(lsBaseDialog1):
  def __init__(self, init_bc = None):
    lsBaseDialog1.__init__(self, "Boundary conditions")
    self.create_static_box("Boundary conditions setup")

    choice_list = ["Electric: PEC (E_t = 0)", "Magnetic: PMC (H_t = 0)", "Absorbing: Open"]
    choice_inds = [consts.XML_BC_TYPE_PEC, consts.XML_BC_TYPE_PMC, consts.XML_BC_TYPE_ABSORBING]
    choice_dict = {choice_inds[0] : 0, choice_inds[1] : 1, choice_inds[2] : 2}

    entry1 = wx.StaticText(self, -1, "xmin:")
    entry2 = wx.StaticText(self, -1, "xmax:")
    entry3 = wx.StaticText(self, -1, "ymin:")
    entry4 = wx.StaticText(self, -1, "ymax:")
    entry5 = wx.StaticText(self, -1, "zmin:")
    entry6 = wx.StaticText(self, -1, "zmax:")

    choice1 = wx.Choice(self, -1, (80, -1), choices = choice_list)
    choice2 = wx.Choice(self, -1, (80, -1), choices = choice_list)
    choice3 = wx.Choice(self, -1, (80, -1), choices = choice_list)
    choice4 = wx.Choice(self, -1, (80, -1), choices = choice_list)
    choice5 = wx.Choice(self, -1, (80, -1), choices = choice_list)
    choice6 = wx.Choice(self, -1, (80, -1), choices = choice_list)

    bcs_select = list()

    default_selection = 2
    for i in range(6):
      bcs_select.append(default_selection)

    if init_bc:
      for i in range(6):
	bcs_select[i] = choice_dict[init_bc[i]]

    choice1.SetSelection(bcs_select[0])
    choice2.SetSelection(bcs_select[1])
    choice3.SetSelection(bcs_select[2])
    choice4.SetSelection(bcs_select[3])
    choice5.SetSelection(bcs_select[4])
    choice6.SetSelection(bcs_select[5])

    # Sizer
    fgs = wx.FlexGridSizer(3, 5, 20, 10)	# rows, cols, hgap, vgap
    fgs.Add(entry1, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(choice1, 0)
    fgs.Add((15,0), 1)
    fgs.Add(entry2, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(choice2, 0)

    fgs.Add(entry3, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(choice3, 0)
    fgs.Add((15,0), 1)
    fgs.Add(entry4, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(choice4, 0)

    fgs.Add(entry5, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(choice5, 0)
    fgs.Add((15,0), 1)
    fgs.Add(entry6, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(choice6, 0)

    self.set_user_sizer(fgs)
    self.set_data_items([choice1, choice2, choice3, choice4, choice5, choice6])
    #self.set_items_lists([choice_list, choice_list, choice_list, choice_list, choice_list, choice_list]) 
    self.set_items_lists([choice_inds, choice_inds, choice_inds, choice_inds, choice_inds, choice_inds]) 

class SolverSetupDialog(lsBaseDialog1):    
  def __init__(self, solver_list, freq_verb):
    lsBaseDialog1.__init__(self, "Setup the solver")
    self.create_static_box("Solver setup")

    self.solver_list = solver_list

    entry1 = wx.StaticText(self, -1, "Number of time steps:")
    entry2 = wx.StaticText(self, -1, "Frequency (min) [%s]:" %(freq_verb))
    entry3 = wx.StaticText(self, -1, "Frequency (max) [%s]:" %(freq_verb))
    entry4 = wx.StaticText(self, -1, "Spatial resolution (cells per wavelength):")
    entry5 = wx.StaticText(self, -1, "Boundary distance (cells):")

    entry1_t = wx.TextCtrl(self, -1, str(self.solver_list[0]), size=(80, -1))
    entry2_t = wx.TextCtrl(self, -1, str(self.solver_list[1]), size=(80, -1))
    entry3_t = wx.TextCtrl(self, -1, str(self.solver_list[2]), size=(80, -1))
    entry4_t = wx.TextCtrl(self, -1, str(self.solver_list[3]), size=(80, -1))
    entry5_t = wx.TextCtrl(self, -1, str(self.solver_list[4]), size=(80, -1))

    # Sizer
    fgs = wx.FlexGridSizer(5, 2, 5, 5)	# rows, cols, hgap, vgap
    fgs.Add(entry1, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry1_t, 0, wx.EXPAND)
    fgs.Add(entry2, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry2_t, 0)#, wx.EXPAND)
    fgs.Add(entry3, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry3_t, 0)#, wx.EXPAND)
    fgs.Add(entry4, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry4_t, 0)#, wx.EXPAND)
    fgs.Add(entry5, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry5_t, 0)#, wx.EXPAND)

    self.set_user_sizer(fgs)
    self.set_data_text_fields([entry1_t, entry2_t, entry3_t, entry4_t, entry5_t])

  def apply(self):
    self.result = (self.number_time_steps.get(), self.freq_min.get(), self.freq_max.get(), self.spatial_res.get(), self.bdist.get())



### class BoundaryAddDialog(tkSimpleDialog.Dialog):    
###   def body(self, master):
###     Label(master, text = "Boundary name: ").grid(row = 0, sticky = W)
###     self.name = Entry(master)
###     self.name.grid(row = 0, column = 1)
### 
###     Label(master, text = "Boundary typ (MAG,PEC,ABC): ").grid(row = 1, sticky = W)
###     self.typ = Entry(master)
###     self.typ.grid(row = 1, column = 1)
### 
###     Label(master, text = "Reflexion factor (ref): ").grid(row = 2, sticky = W)
###     self.ref = Entry(master)
###     self.ref.grid(row = 2, column = 1)
### 
### #    Label(master, text = "Conductivity [S/m]: ").grid(row = 3, sticky = W)
### #    self.cond = Entry(master)
### #    self.cond.grid(row = 3, column = 1)
### 
### #    Label(master, text = "Dielectric losses (tan delta): ").grid(row = 4, sticky = W)
### #    self.tand = Entry(master)
### #    self.tand.grid(row = 4, column = 1)
### 
###     # Predefined values
###     self.typ.insert(0, "ABC")
###     self.ref.insert(0, "0")
### #    self.cond.insert(0, "0")
### #    self.tand.insert(0, "0")
### 
###   def apply(self):
###     self.result = (self.name.get(), self.typ.get(), self.ref.get())


#########
## geometric objects dialogs
#########

class GeometryPatchDialog(lsBaseDialog1):
  def __init__(self, geom_object = None):
    lsBaseDialog1.__init__(self, "Patch geometry")
    self.create_static_box("Patch definition")

    name_t = "Patch"
    x1_t = "0.0"
    y1_t = "0.0"
    length_x_t = "0.0"
    length_y_t = "0.0"
    z_t = "0.0"
    if geom_object:
      name_t = geom_object.get_name()
      p1 = geom_object.p1
      p2 = geom_object.p2
      x1_t = str(p1[0])
      y1_t = str(p1[1])
      z_t = str(p1[2])
      length_x_t = str(p2[0] - p1[0])
      length_y_t = str(p2[1] - p1[1])


    entry1 = wx.StaticText(self, -1, "Name:")
    entry2 = wx.StaticText(self, -1, "x1:")
    entry3 = wx.StaticText(self, -1, "y1:")
    entry4 = wx.StaticText(self, -1, "Length x:")
    entry5 = wx.StaticText(self, -1, "Length y:")
    entry6 = wx.StaticText(self, -1, "z:")

    entry1_t = wx.TextCtrl(self, -1, name_t, size=(125, -1))
    entry2_t = wx.TextCtrl(self, -1, x1_t, size=(80, -1))
    entry3_t = wx.TextCtrl(self, -1, y1_t, size=(80, -1))
    entry4_t = wx.TextCtrl(self, -1, length_x_t, size=(80, -1))
    entry5_t = wx.TextCtrl(self, -1, length_y_t, size=(80, -1))
    entry6_t = wx.TextCtrl(self, -1, z_t, size=(80, -1))

    self.set_name_entry(entry1_t)

    # Sizer
    fgs = wx.FlexGridSizer(4, 4, 5, 5)	# rows, cols, hgap, vgap
    fgs.Add(entry1, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry1_t, 0, wx.EXPAND)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add(entry2, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry2_t, 0)#, wx.EXPAND)
    fgs.Add(entry3, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry3_t, 0)#, wx.EXPAND)
    fgs.Add(entry4, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry4_t, 0)#, wx.EXPAND)
    fgs.Add(entry5, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry5_t, 0)#, wx.EXPAND)
    fgs.Add(entry6, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry6_t, 0)#, wx.EXPAND)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)

    self.set_user_sizer(fgs)
    self.set_data_text_fields([entry1_t, entry2_t, entry3_t, entry4_t, entry5_t, entry6_t])


class GeometryCircleDialog(lsBaseDialog1):
  def __init__(self, geom_object = None):
    lsBaseDialog1.__init__(self, "Circle geometry")
    self.create_static_box("Circle definition")

    name_t = "Circle"
    x1_t = "0.0"
    y1_t = "0.0"
    radius_t = "0.0"
    z_t = "0.0"
    if geom_object:
      name_t = geom_object.get_name()
      p1 = geom_object.p1
      x1_t = str(p1[0])
      y1_t = str(p1[1])
      z_t = str(p1[2])
      radius_t = str(geom_object.radius)

    entry1 = wx.StaticText(self, -1, "Name:")
    entry2 = wx.StaticText(self, -1, "x1:")
    entry3 = wx.StaticText(self, -1, "y1:")
    entry4 = wx.StaticText(self, -1, "Radius:")
    entry5 = wx.StaticText(self, -1, "z:")

    entry1_t = wx.TextCtrl(self, -1, name_t, size=(125, -1))
    entry2_t = wx.TextCtrl(self, -1, x1_t, size=(80, -1))
    entry3_t = wx.TextCtrl(self, -1, y1_t, size=(80, -1))
    entry4_t = wx.TextCtrl(self, -1, radius_t, size=(80, -1))
    entry5_t = wx.TextCtrl(self, -1, z_t, size=(80, -1))

    self.set_name_entry(entry1_t)

    # Sizer
    fgs = wx.FlexGridSizer(4, 4, 5, 5)	# rows, cols, hgap, vgap
    fgs.Add(entry1, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry1_t, 0, wx.EXPAND)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add(entry2, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry2_t, 0)#, wx.EXPAND)
    fgs.Add(entry3, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry3_t, 0)#, wx.EXPAND)
    fgs.Add(entry4, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry4_t, 0)#, wx.EXPAND)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add(entry5, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry5_t, 0)#, wx.EXPAND)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)

    self.set_user_sizer(fgs)
    self.set_data_text_fields([entry1_t, entry2_t, entry3_t, entry4_t, entry5_t])


class GeometryPolygonDialog(lsBaseDialog1):
  def __init__(self, geom_object = None):
    lsBaseDialog1.__init__(self, "Polygon geometry")
    self.create_static_box("Polygon definition")

    grid = wx.grid.Grid(self)
    grid.CreateGrid(30, 2)
    grid.SetColLabelValue(0, "x")
    grid.SetColLabelValue(1, "y")

    name_t = "Polygon"
    z_t = "0.0"
    if geom_object:
      name_t = geom_object.get_name()
      pts = geom_object.points
      z_t = str(pts[0][2])
      for row in range(len(pts)):
	grid.SetCellValue(row, 0, str(pts[row][0]))
	grid.SetCellValue(row, 1, str(pts[row][1]))

    entry1 = wx.StaticText(self, -1, "Name:")
    entry1_t = wx.TextCtrl(self, -1, name_t)
    self.set_name_entry(entry1_t)

    entry2 = wx.StaticText(self, -1, "z-level:")
    entry2_t = wx.TextCtrl(self, -1, z_t)

    sizer = wx.BoxSizer(wx.VERTICAL)
    sizer_h = wx.BoxSizer(wx.HORIZONTAL)
    sizer_h2 = wx.BoxSizer(wx.HORIZONTAL)

    sizer_h.Add(entry1, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL) 
    sizer_h.Add((5,5), 0, wx.EXPAND)
    sizer_h.Add(entry1_t, 0, wx.ALIGN_RIGHT)

    fgs = wx.FlexGridSizer(1, 2, 5, 5)
    fgs.Add(entry2, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry2_t, 0, wx.ALIGN_RIGHT)

    sizer_h2.Add(grid, 0, wx.EXPAND)
    sizer_h2.Add((20,20), 0, wx.EXPAND)
    sizer_h2.Add(fgs, 0, wx.EXPAND)

    sizer.Add(sizer_h, 0, wx.EXPAND)
    sizer.Add((20,20), 0, wx.EXPAND)
    sizer.Add(sizer_h2, 0, wx.EXPAND)

    self.set_user_sizer(sizer)
    self.set_data_text_fields([entry1_t, entry2_t])
    self.set_data_grid_plain([grid])


class GeometryBoxDialog(lsBaseDialog1):
  def __init__(self, geom_object = None):
    lsBaseDialog1.__init__(self, "Box geometry")
    self.create_static_box("Box definition")

    name_t = "Box"
    x1_t = "0.0"
    y1_t = "0.0"
    z1_t = "0.0"
    length_x_t = "0.0"
    length_y_t = "0.0"
    length_z_t = "0.0"
    if geom_object:
      name_t = geom_object.get_name()
      p1 = geom_object.p1
      p2 = geom_object.p2
      x1_t = str(p1[0])
      y1_t = str(p1[1])
      z1_t = str(p1[2])
      length_x_t = str(p2[0] - p1[0])
      length_y_t = str(p2[1] - p1[1])
      length_z_t = str(p2[2] - p1[2])

    entry1 = wx.StaticText(self, -1, "Name:")
    entry2 = wx.StaticText(self, -1, "x1:")
    entry3 = wx.StaticText(self, -1, "y1:")
    entry4 = wx.StaticText(self, -1, "z1:")
    entry5 = wx.StaticText(self, -1, "Length x:")
    entry6 = wx.StaticText(self, -1, "Length y:")
    entry7 = wx.StaticText(self, -1, "Length z:")

    entry1_t = wx.TextCtrl(self, -1, name_t, size=(100, -1))
    entry2_t = wx.TextCtrl(self, -1, x1_t, size=(100, -1))
    entry3_t = wx.TextCtrl(self, -1, y1_t, size=(100, -1))
    entry4_t = wx.TextCtrl(self, -1, z1_t, size=(100, -1))
    entry5_t = wx.TextCtrl(self, -1, length_x_t, size=(100, -1))
    entry6_t = wx.TextCtrl(self, -1, length_y_t, size=(100, -1))
    entry7_t = wx.TextCtrl(self, -1, length_z_t, size=(100, -1))

    self.set_name_entry(entry1_t)

    # Sizer
    fgs = wx.FlexGridSizer(4, 6, 5, 5)	# rows, cols, hgap, vgap
    fgs.Add(entry1, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry1_t, 0, wx.EXPAND)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add(entry2, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry2_t, 0)#, wx.EXPAND)
    fgs.Add(entry3, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry3_t, 0)#, wx.EXPAND)
    fgs.Add(entry4, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry4_t, 0)#, wx.EXPAND)
    fgs.Add(entry5, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry5_t, 0)#, wx.EXPAND)
    fgs.Add(entry6, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry6_t, 0)#, wx.EXPAND)
    fgs.Add(entry7, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry7_t, 0)#, wx.EXPAND)

    self.set_user_sizer(fgs)
    self.set_data_text_fields([entry1_t, entry2_t, entry3_t, entry4_t, entry5_t, entry6_t, entry7_t])


class GeometryCylinderDialog(lsBaseDialog1):
  def __init__(self, geom_object = None):
    lsBaseDialog1.__init__(self, "Cylinder geometry")
    self.create_static_box("Cylinder definition")

    name_t = "Cylinder"
    x1_t = "0.0"
    y1_t = "0.0"
    z1_t = "0.0"
    radius_t = "0.0"
    height_z_t = "0.0"
    if geom_object:
      name_t = geom_object.get_name()
      p1 = geom_object.center
      x1_t = str(p1[0])
      y1_t = str(p1[1])
      z1_t = str(p1[2])
      radius_t = str(geom_object.radius)
      height_z_t = str(geom_object.height)

    entry1 = wx.StaticText(self, -1, "Name:")
    entry2 = wx.StaticText(self, -1, "x1:")
    entry3 = wx.StaticText(self, -1, "y1:")
    entry4 = wx.StaticText(self, -1, "z1:")
    entry5 = wx.StaticText(self, -1, "Radius:")
    entry6 = wx.StaticText(self, -1, "Height z:")

    entry1_t = wx.TextCtrl(self, -1, name_t, size=(80, -1))
    entry2_t = wx.TextCtrl(self, -1, x1_t, size=(80, -1))
    entry3_t = wx.TextCtrl(self, -1, y1_t, size=(80, -1))
    entry4_t = wx.TextCtrl(self, -1, z1_t, size=(80, -1))
    entry5_t = wx.TextCtrl(self, -1, radius_t, size=(80, -1))
    entry6_t = wx.TextCtrl(self, -1, height_z_t, size=(80, -1))

    self.set_name_entry(entry1_t)

    # Sizer
    fgs = wx.FlexGridSizer(4, 6, 5, 5)	# rows, cols, hgap, vgap
    fgs.Add(entry1, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry1_t, 0, wx.EXPAND)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add(entry2, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry2_t, 0)#, wx.EXPAND)
    fgs.Add(entry3, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry3_t, 0)#, wx.EXPAND)
    fgs.Add(entry4, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry4_t, 0)#, wx.EXPAND)
    fgs.Add(entry5, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry5_t, 0)#, wx.EXPAND)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)
    fgs.Add(entry6, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)
    fgs.Add(entry6_t, 0)#, wx.EXPAND)
    fgs.Add((0,0), 1)
    fgs.Add((0,0), 1)

    self.set_user_sizer(fgs)
    self.set_data_text_fields([entry1_t, entry2_t, entry3_t, entry4_t, entry5_t, entry6_t])


### class GeometryMacroModelRectangularCoilDialog(tkSimpleDialog.Dialog):
###   def body(self, master):
###     Label(master, text = "Name: ").grid(row = 0)
###     self.name = Entry(master)
###     self.name.grid(row = 0, column = 1)
###     #self.name.insert(0, name)
### 
###     Label(master, text = "x1: ").grid(row = 2, column = 0)
###     self.x1 = Entry(master)
###     self.x1.grid(row = 2, column = 1)
###     Label(master, text = "y1: ").grid(row = 2, column = 2)
###     self.y1 = Entry(master)
###     self.y1.grid(row = 2, column = 3)
###     Label(master, text = "z1: ").grid(row = 2, column = 4)
###     self.z1 = Entry(master)
###     self.z1.grid(row = 2, column = 5)
### 
###     Label(master, text = "Radius: ").grid(row = 4, column = 0)
###     self.radius = Entry(master)
###     self.radius.grid(row = 4, column = 1)
### 
###     Label(master, text = "Height z: ").grid(row = 4, column = 2)
###     self.height_z = Entry(master)
###     self.height_z.grid(row = 4, column = 3)
### 
###     self.name.insert(0, "Cylinder")
###     self.x1.insert(0, "0.0")
###     self.y1.insert(0, "0.0")
###     self.z1.insert(0, "0.0")
###     self.radius.insert(0, "0.0")
###     self.height_z.insert(0, "0.0")
### 
###     #Label(master, text = "Length y: ").grid(row = 4, column = 2)
###     #self.length_y = Entry(master)
###     #self.length_y.grid(row = 4, column = 3)
###     #Label(master, text = "Length z: ").grid(row = 4, column = 4)
###     #self.length_z = Entry(master)
###     #self.length_z.grid(row = 4, column = 5)
### 
###     return self.name    #initial focus for this field
### 
###   def apply(self):
###     self.result = (self.name.get(), self.x1.get(), self.y1.get(), self.z1.get(), self.radius.get(), self.height_z.get())

class emGineGUIAboutDialog(wx.Dialog):
  text = '''
<html>
<body bgcolor="#dddddd">
<center>
<p><b>''' + consts.MW_TITLE + '''</b></p>

<p><b>emGine GUI</b> is licensed under the MPL/GPL/LGPL tri-license. A copy of the
licenses can be found in COPYING.MPL, COPYING.GPL and COPYING.LGPL files.</p>

<p><b>tlmGine</b> - the electromagnetic simulation engine - is licensed free (in binary format) for
non-commercial and educational purposes. 
<u>Any commercial usage of the electromagnetic simulation engine is prohibited.</u></p>

<p>All software distributed under these licenses is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the licenses for the
specific language governing rights and limitations under the licenses.</p>

<p>Contact: <i>emgine@petr-lorenz.com</i><br />
<i>Copyright (C) 2004-2008 Petr Lorenz, All rights reserved.</i>
</p>
</center>
</body>
</html>'''

  def __init__(self, parent):
    wx.Dialog.__init__(self, parent, -1, 'About emGine', size = (440, 400))

    html = wx.html.HtmlWindow(self)
    html.SetPage(self.text)
    button = wx.Button(self, wx.ID_OK, "OK")

    sizer = wx.BoxSizer(wx.VERTICAL)
    sizer.Add(html, 1, wx.EXPAND | wx.ALL, 5)
    sizer.Add(button, 0, wx.ALIGN_CENTER | wx.ALL, 5)

    self.SetSizer(sizer)
    self.Layout()

#
# Dummy node emulating XML node
#
class DummyNode:
  def __init__(self, name):
    self.nodeName = name
    self.attributes = {}

  def getAttribute(self, attr_name):
    return self.attributes[attr_name]

  def setAttribute(self, attr_name, value):
    self.attributes[attr_name] = value

########################
# Misc functions
########################
def format_int_number(number):
  l = list(str(number))
  c = len(l)

  while c > 3:
    c -= 3
    l.insert(c, ",")

  return ''.join(l)


########################
# The main window layout
########################
class MainWindow(wx.App):
  def __init__(self, redirect = False, filename = None):
    wx.App.__init__(self, redirect, filename)

    self.app_path = os.getcwd()

    ### Start a blank project
    self.start_blank()
    ########################################################

  def OnInit(self):
    # Set-up properties
    self.properties = Properties()
    self.properties.load()

    # Splash window
    image = wx.Image("emGineGUI/Graphics/emGineSplash.bmp", wx.BITMAP_TYPE_BMP)
    bmp = image.ConvertToBitmap()
    wx.SplashScreen(bmp, wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT, 3000, None, -1)
    wx.Yield()

    # Create the master window (frame)
    frame = wx.Frame(None, -1, "%s" %(consts.MW_TITLE), size = (800, 600), style = wx.DEFAULT_FRAME_STYLE | wx.MAXIMIZE)

    icon = wx.EmptyIcon()
    icon.CopyFromBitmap(wx.Bitmap("emGineGUI/Icons/emGine_32_32.png", wx.BITMAP_TYPE_PNG))
    frame.SetIcon(icon)

    ###############
    ## Status bar
    ###############
    self.statusbar = frame.CreateStatusBar(number = 6)
    self.statusbar.SetStatusWidths([-7,-1,-1,-1,-1,-4])
    self.statbar_pos_length = 1
    self.statbar_pos_frequency = 2
    self.statbar_pos_time = 3
    self.statbar_pos_dl = 4
    self.statbar_pos_ncells = 5


    ###############
    ## Tool bar
    ###############
    self.toolbar = toolbar = frame.CreateToolBar()

    bitmap_file_new = wx.ArtProvider_GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, (16, 16))
    toolbar_new_project = toolbar.AddSimpleTool(wx.NewId(), bitmap_file_new, "New Project", "Create new project")
    self.Bind(wx.EVT_MENU, self.file_new_project, toolbar_new_project)

    bitmap_file_open = wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, (16, 16))
    toolbar_open_project = toolbar.AddSimpleTool(wx.NewId(), bitmap_file_open, "Open Project", "Open existing project")
    self.Bind(wx.EVT_TOOL, self.file_open_project, toolbar_open_project)

    bitmap_file_save = wx.ArtProvider_GetBitmap(wx.ART_FILE_SAVE, wx.ART_OTHER, (16, 16))
    new_id = self.toolbar_save_id = wx.NewId()
    toolbar_save = toolbar.AddSimpleTool(new_id, bitmap_file_save, "Save Project", "Save project")
    self.Bind(wx.EVT_TOOL, self.file_save_project, toolbar_save)

    bitmap_file_save_as = wx.ArtProvider_GetBitmap(wx.ART_FILE_SAVE_AS, wx.ART_OTHER, (16, 16))
    new_id = self.toolbar_save_as_id = wx.NewId()
    toolbar_save_as = toolbar.AddSimpleTool(new_id, bitmap_file_save_as, "Save Project As", "Save project as")
    self.Bind(wx.EVT_TOOL, self.file_save_project_as, toolbar_save_as)

    toolbar.AddSeparator()

    bitmap_file_print = wx.ArtProvider_GetBitmap(wx.ART_PRINT, wx.ART_OTHER, (16, 16))
    new_id = self.toolbar_print_id = wx.NewId()
    toolbar_print = toolbar.AddSimpleTool(new_id, bitmap_file_print, "Print Working Space", "Print")

    toolbar.AddSeparator()

    self.bitmap_patch = bitmap_patch = wx.Bitmap("emGineGUI/Icons/patch_16_16.png", wx.BITMAP_TYPE_PNG)
    new_id = self.toolbar_patch_id = wx.NewId()
    toolbar_patch = toolbar.AddSimpleTool(new_id, bitmap_patch, "Create a Patch", "Create a patch geometry")
    self.Bind(wx.EVT_TOOL, self.geometry_patch, toolbar_patch)

    self.bitmap_circle = bitmap_circle = wx.Bitmap("emGineGUI/Icons/circle_16_16.png", wx.BITMAP_TYPE_PNG)
    new_id = self.toolbar_circle_id = wx.NewId()
    toolbar_circle = toolbar.AddSimpleTool(new_id, bitmap_circle, "Create a Circle", "Create a circle geometry")

    self.Bind(wx.EVT_TOOL, self.geometry_circle, toolbar_circle)

    self.bitmap_polygon = bitmap_polygon = wx.Bitmap("emGineGUI/Icons/polygon_16_16.png", wx.BITMAP_TYPE_PNG)
    new_id = self.toolbar_polygon_id = wx.NewId()
    toolbar_polygon = toolbar.AddSimpleTool(new_id, bitmap_polygon, "Create a Polygon", "Create a polygon geometry")
    self.Bind(wx.EVT_TOOL, self.geometry_polygon, toolbar_polygon)

    toolbar.AddSeparator()

    self.bitmap_box = bitmap_box = wx.Bitmap("emGineGUI/Icons/box_16_16.png", wx.BITMAP_TYPE_PNG)
    new_id = self.toolbar_box_id = wx.NewId()
    toolbar_box = toolbar.AddSimpleTool(new_id, bitmap_box, "Create a Box", "Create a box geometry")
    self.Bind(wx.EVT_TOOL, self.geometry_box, toolbar_box)

    self.bitmap_cylinder = bitmap_cylinder = wx.Bitmap("emGineGUI/Icons/cylinder_16_16.png", wx.BITMAP_TYPE_PNG)
    new_id = self.toolbar_cylinder_id = wx.NewId()
    toolbar_cylinder = toolbar.AddSimpleTool(new_id, bitmap_cylinder, "Create a Cylinder", "Create a cylinder geometry")
    self.Bind(wx.EVT_TOOL, self.geometry_cylinder, toolbar_cylinder)

    toolbar.AddSeparator()

    bitmap_simulate = wx.Bitmap("emGineGUI/Icons/simulate_16_16.png", wx.BITMAP_TYPE_PNG)
    new_id = self.toolbar_simulate_id = wx.NewId()
    toolbar_simulate = toolbar.AddSimpleTool(new_id, bitmap_simulate, "Simulate !", "Run the EM simulation")
    self.Bind(wx.EVT_TOOL, self.solver_simulate, toolbar_simulate)

    toolbar.AddSeparator()

    toolbar.Realize()

    #########
    ## Menu
    #########
    self.menu_bar = menu_bar = wx.MenuBar()

    # File #
    filem = self.filem = wx.Menu()

    filem_item = wx.MenuItem(filem, -1, "&New Project...\tCtrl+N", "Create new project")
    filem_item.SetBitmap(bitmap_file_new)
    filem_new_project = filem.AppendItem(filem_item)
    self.Bind(wx.EVT_MENU, self.file_new_project, filem_new_project)

    filem_item = wx.MenuItem(filem, -1, "&Open Project...\tCtrl+O", "Open existing project")
    filem_item.SetBitmap(bitmap_file_open)
    filem_open_project = filem.AppendItem(filem_item)
    self.Bind(wx.EVT_MENU, self.file_open_project, filem_open_project)

    new_id = self.mnu_save_project_id = wx.NewId()
    filem_save_project = filem.Append(new_id, "&Save Project\tCtrl+S", "Save opened project")
    self.Bind(wx.EVT_MENU, self.file_save_project, filem_save_project)

    new_id = self.mnu_save_project_as_id = wx.NewId()
    filem_save_project_as = filem.Append(new_id, "Save Project &as...", "Save project under new file")
    self.Bind(wx.EVT_MENU, self.file_save_project_as, filem_save_project_as)

    new_id = self.mnu_close_project_id = wx.NewId()
    filem_close_project = filem.Append(new_id, "&Close Project\tCtrl+W", "Close the opened project")
    self.Bind(wx.EVT_MENU, self.file_close_project, filem_close_project)

    filem.AppendSeparator()

    new_id = self.mnu_print_id = wx.NewId()
    filem_item = wx.MenuItem(filem, new_id, "&Print...\tCtrl+P", "Print working space")
    filem_item.SetBitmap(bitmap_file_print)
    filem_print = filem.AppendItem(filem_item)
    #self.Bind(wx.EVT_MENU, self.file_print, filem_print)

    filem.AppendSeparator()

    new_id = self.mnu_export_data_id = wx.NewId()
    filem_export_data = filem.Append(new_id, "Export Data...", "Export data")
    self.Bind(wx.EVT_MENU, self.dummy, filem_export_data)

    new_id = self.mnu_export_geometry_id = wx.NewId()
    filem_export_geometry = filem.Append(new_id, "Export Geometry...", "Export geometry")
    self.Bind(wx.EVT_MENU, self.dummy, filem_export_geometry)

    filem.AppendSeparator()

    new_id = self.mnu_platform_info_id = wx.NewId()
    filem_platform_info = filem.Append(new_id, "Platform &Info...\tShift+I", "Platform information")
    self.Bind(wx.EVT_MENU, self.file_platform_info, filem_platform_info)

    filem.AppendSeparator()

    filem_exit = filem.Append(-1, "E&xit\tCtrl+X", "Exit emGine GUI")
    self.Bind(wx.EVT_MENU, self.quit_app, filem_exit)

    menu_bar.Append(filem, "&File")

    # Edit #
    editm = self.editm = wx.Menu()

    new_id = self.mnu_copy_id = wx.NewId()
    editm.Append(new_id, "Copy\tCtrl+C", "Copy to clipboard")

    new_id = self.mnu_paste_id = wx.NewId()
    editm.Append(new_id, "Paste\tCtrl+V", "Paste from clipboard")

    editm.AppendSeparator()

    new_id = self.mnu_rename_id = wx.NewId()
    editm.Append(new_id, "Rename", "Rename")

    new_id = self.mnu_delete_id = wx.NewId()
    editm_delete = editm.Append(new_id, "Delete\tDel", "Delete the selected object")
    self.Bind(wx.EVT_MENU, self.edit_delete, editm_delete)

    editm.AppendSeparator()

    new_id = self.mnu_units_id = wx.NewId()
    editm.Append(new_id, "Units...", "Set units")

    editm.AppendSeparator()

    new_id = self.mnu_preferences_id = wx.NewId()
    editm.Append(new_id, "Preferences...", "Change preferences")

    menu_bar.Append(editm, "&Edit")

    # View #
    viewm = self.viewm = wx.Menu()

    new_id = self.mnu_zoom_fit_id = wx.NewId() 
    viewm.Append(new_id, "Zoom to fit (r)", "Fit the view")

    viewm.AppendSeparator()

    new_id = self.mnu_view_top_id = wx.NewId()
    viewm_top = viewm.Append(new_id, "Top\tCtrl+1", "Top view")
    self.Bind(wx.EVT_MENU, self.view_top, viewm_top)

    new_id = self.mnu_view_bottom_id = wx.NewId()
    viewm_bottom = viewm.Append(new_id, "Bottom\tCtrl+2", "Bottom view")
    self.Bind(wx.EVT_MENU, self.view_bottom, viewm_bottom)

    new_id = self.mnu_view_front_id = wx.NewId()
    viewm_front = viewm.Append(new_id, "Front\tCtrl+3", "Front view")
    self.Bind(wx.EVT_MENU, self.view_front, viewm_front)

    new_id = self.mnu_view_back_id = wx.NewId()
    viewm_back = viewm.Append(new_id, "Back\tCtrl+4", "Back view")
    self.Bind(wx.EVT_MENU, self.view_back, viewm_back)

    new_id = self.mnu_view_left_id = wx.NewId()
    viewm_left = viewm.Append(new_id, "Left\tCtrl+5", "Left view")
    self.Bind(wx.EVT_MENU, self.view_left, viewm_left)

    new_id = self.mnu_view_right_id = wx.NewId()
    viewm_right = viewm.Append(new_id, "Right\tCtrl+6", "Right view")
    self.Bind(wx.EVT_MENU, self.view_right, viewm_right)

    viewm.AppendSeparator()

    new_id = self.mnu_wireframe_id = wx.NewId()
    viewm.Append(new_id, "Wireframe (w)", "Wireframe mode")

    new_id = self.mnu_shaded_id = wx.NewId()
    viewm.Append(new_id, "Shaded (s)", "Shaded mode")

    viewm.AppendSeparator()

    new_id = self.mnu_perspective_id = wx.NewId()
    viewm_perspective = viewm.Append(new_id, "Perspective\tCtrl+A", "Switch between perspective and orthogonal view", wx.ITEM_CHECK)
    self.Bind(wx.EVT_MENU, self.view_perspective, viewm_perspective)
    self.viewm.Check(self.mnu_perspective_id, True)	# check

    viewm.AppendSeparator()

    new_id = self.mnu_simulation_boundary_id = wx.NewId()
    viewm_simulation_boundary = viewm.Append(new_id, "Simulation Boundary\tCtrl+B", "View simulation boundary", wx.ITEM_CHECK)
    self.Bind(wx.EVT_MENU, self.view_simulation_boundary, viewm_simulation_boundary)

    menu_bar.Append(viewm, "&View")

    # Material #
    materialm = self.materialm = wx.Menu()

    new_id = self.mnu_new_material_id = wx.NewId()
    materialm_add = materialm.Append(new_id, "New Material...", "Add a new material")
    self.Bind(wx.EVT_MENU, self.material_add, materialm_add)

    new_id = self.mnu_material_modify = wx.NewId()
    materialm.Append(new_id, "Modify...", "Modify material")

    #materialm.AppendSeparator()
    #materialm.Append(-1, "Surrounding Space...", "Change material of surrounding space")

    menu_bar.Append(materialm, "&Material")

    # Geometry #
    geometrym = self.geometrym = wx.Menu()

    new_id = self.mnu_geometry_patch_id = wx.NewId()
    geometrym_item = wx.MenuItem(geometrym, new_id, "Patch...", "Create a patch")
    geometrym_item.SetBitmap(bitmap_patch)
    geometrym_patch = geometrym.AppendItem(geometrym_item)
    self.Bind(wx.EVT_MENU, self.geometry_patch, geometrym_patch)

    new_id = self.mnu_geometry_circle_id = wx.NewId()
    geometrym_item = wx.MenuItem(geometrym, new_id, "Circle...", "Create a circle")
    geometrym_item.SetBitmap(bitmap_circle)
    geometrym_circle = geometrym.AppendItem(geometrym_item)
    self.Bind(wx.EVT_MENU, self.geometry_circle, geometrym_circle)

    #geometrym.Append(-1, "Triangle...", "Create triangle")
    #geometrym.Append(-1, "Ring...", "Create ring")

    new_id = self.mnu_geometry_polygon_id = wx.NewId()
    geometrym_item = wx.MenuItem(geometrym, new_id, "Polygon...", "Create a polygon")
    geometrym_item.SetBitmap(bitmap_polygon)
    geometrym_polygon = geometrym.AppendItem(geometrym_item)
    self.Bind(wx.EVT_MENU, self.geometry_polygon, geometrym_polygon)

    geometrym.AppendSeparator()

    new_id = self.mnu_geometry_box_id = wx.NewId()
    geometrym_item = wx.MenuItem(geometrym, new_id, "Box...", "Create a box")
    geometrym_item.SetBitmap(bitmap_box)
    geometrym_box = geometrym.AppendItem(geometrym_item)
    self.Bind(wx.EVT_MENU, self.geometry_box, geometrym_box)

    new_id = self.mnu_geometry_cylinder_id = wx.NewId()
    geometrym_item = wx.MenuItem(geometrym, new_id, "Cylinder...", "Create a cylinder")
    geometrym_item.SetBitmap(bitmap_cylinder)
    geometrym_cylinder = geometrym.AppendItem(geometrym_item)
    self.Bind(wx.EVT_MENU, self.geometry_cylinder, geometrym_cylinder)

    #geometrym.Append(-1, "Sphere...", "Create a sphere")
    #geometrym.Append(-1, "Cone...", "Create a cone")
    #geometrym.Append(-1, "Torus...", "Create a torus")

    ### # Submenu: Macro Model #
    ### macromodelm = self.macromodelm = Menu(geometrym)
    ### geometrym.add_cascade(label="Macro Model", underline = 0, menu = macromodelm) 
    ### macromodelm.add_command(label="Rectangular Coil...", command = self.geometry_macro_model_rectangular_coil, state = DISABLED)

    #geometrym.AppendSeparator()
    #geometrym.Append(-1, "Import...", "Import geometry")

    geometrym.AppendSeparator()
    new_id = self.mnu_geometry_change_material_id = wx.NewId()
    geometrym_change_material = geometrym.Append(new_id, "Change Material...", "Change material for selected geometry")
    self.Bind(wx.EVT_MENU, self.geometry_change_material, geometrym_change_material)

    menu_bar.Append(geometrym, "&Geometry")

    # Transform #
    transformm = self.transformm = wx.Menu()
    new_id = self.mnu_transform_translate_id = wx.NewId()
    transformm.Append(new_id, "Translate...", "Translate")

    new_id = self.mnu_transform_rotate_id = wx.NewId()
    transformm.Append(new_id, "Rotate...", "Rotate")

    new_id = self.mnu_transform_scale_id = wx.NewId()
    transformm.Append(new_id, "Scale...", "Scale")

    menu_bar.Append(transformm, "&Transform")

    # Excitation #
    excitationm = self.excitationm = wx.Menu()

    new_id = self.mnu_excitation_voltage_port_id = wx.NewId()
    excitationm_voltage_port = excitationm.Append(new_id, "&Voltage Port...\tShift+V", "Create discrete voltage port excitation")
    self.Bind(wx.EVT_MENU, self.excitation_voltage_port, excitationm_voltage_port)

    new_id = self.mnu_excitation_modal_port_id = wx.NewId()
    excitationm.Append(new_id, "&Modal Port...\tShift+M", "Create modal excitation")

    new_id = self.mnu_excitation_plane_wave_port_id = wx.NewId()
    excitationm_plane_wave_port = excitationm.Append(new_id, "Plane &Wave Port...\tShift+W", "Create plane wave (TEM) port excitation")
    self.Bind(wx.EVT_MENU, self.excitation_plane_wave_port, excitationm_plane_wave_port)

    excitationm.AppendSeparator()
    new_id = self.mnu_excitation_modify_id = wx.NewId()
    excitationm.Append(new_id, "Modify", "Modify excitation")

    menu_bar.Append(excitationm, "E&xcitation")

    # Simulation #
    simulationm = self.simulationm = wx.Menu()

    #simulationm.add_command(label="Parameters...", command = self.dummy, state = DISABLED)
    new_id = self.mnu_simulation_surrounding_space_id = wx.NewId()
    simulationm_surrounding_space = simulationm.Append(new_id, "&Surrounding Space...\tShift+U", "Setup surrounding space")
    self.Bind(wx.EVT_MENU, self.simulation_surrounding_space, simulationm_surrounding_space)

    new_id = self.mnu_simulation_boundary_conditions_id = wx.NewId()
    simulationm_boundary_conditions = simulationm.Append(new_id, "&Boundary Conditions...\tShift+B", "Setup boundary conditions")
    self.Bind(wx.EVT_MENU, self.simulation_boundary_conditions, simulationm_boundary_conditions)

    menu_bar.Append(simulationm, "&Simulation")

    # Solver #
    solverm = self.solverm = wx.Menu()

    new_id = self.mnu_solver_setup_id = wx.NewId()
    solverm_setup = solverm.Append(new_id, "S&etup...\tShift+S", "Setup the solver")
    self.Bind(wx.EVT_MENU, self.solver_setup, solverm_setup)

    new_id = self.mnu_solver_calculate_mesh_id = wx.NewId()
    solverm_calculate_mesh = solverm.Append(new_id, "&Calculate Mesh \tCtrl+M", "Calculate mesh for the simulation")
    self.Bind(wx.EVT_MENU, self.solver_calculate_mesh, solverm_calculate_mesh)

    solverm.AppendSeparator()

    new_id = self.mnu_solver_simulate_id = wx.NewId()

    solverm_item = wx.MenuItem(solverm, new_id, "&Simulate !\tCtrl+R", "Run the EM simulation")
    solverm_item.SetBitmap(bitmap_simulate)
    solverm_simulate = solverm.AppendItem(solverm_item)
    self.Bind(wx.EVT_MENU, self.solver_simulate, solverm_simulate)

    menu_bar.Append(solverm, "S&olver")

    # Help #
    helpm = self.helpm = wx.Menu()
    helpm_about = helpm.Append(-1, "About...", "This is emGine GUI. Copyright (C) 2004-2008 Petr Lorenz. All rights reserved.")
    self.Bind(wx.EVT_MENU, self.help_about, helpm_about)
    menu_bar.Append(helpm, "&Help")

    frame.SetMenuBar(menu_bar)


    #
    # Splitter 2 - for TOP and BOTTOM frames
    #
    sty = wx.BORDER_SIMPLE
    splitter2 = wx.SplitterWindow(frame, -1)

    # Notebook1
    self.notebook1 = notebook1 = wx.Notebook(splitter2, -1, style = wx.NB_BOTTOM) # wx.NB_LEFT)

    # Log window
    #self.log_widget = wx.TextCtrl(splitter2, -1, style = wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL | wx.TE_RICH2)
    self.log_widget = wx.TextCtrl(notebook1, -1, style = wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL | wx.TE_RICH2)
    #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log_widget)) 

    self.log_widget_simulation = wx.TextCtrl(notebook1, -1, style = wx.TE_MULTILINE | wx.TE_READONLY | wx.HSCROLL | wx.TE_RICH2)

    # List of parameters
    self.list_parameters = wx.ListCtrl(notebook1, -1, style = wx.LC_REPORT | wx.LC_HRULES | wx.LC_VRULES | wx.BORDER_SUNKEN)
    self.list_parameters.InsertColumn(0, "Name")
    self.list_parameters.InsertColumn(1, "Value / Expression")
    self.list_parameters.InsertColumn(2, "Description")

    self.list_parameters.SetColumnWidth(0, 250)
    self.list_parameters.SetColumnWidth(1, 350) #wx.LIST_AUTOSIZE_USEHEADER)
    self.list_parameters.SetColumnWidth(2, 350) #wx.LIST_AUTOSIZE_USEHEADER)

    # Add pages to the notebook
    notebook1.AddPage(self.log_widget, "Information")
    notebook1.AddPage(self.list_parameters, "Parameters")
    notebook1.AddPage(self.log_widget_simulation, "Simulation Log")

    ###############################
    ## Tree frame + Working frame
    ###############################
    #sty = wx.BORDER_SUNKEN
    sty = wx.BORDER_SIMPLE
    #splitter = wx.SplitterWindow(frame, -1)
    splitter = wx.SplitterWindow(splitter2, -1)
    self.tree_frame = tree_frame = wx.Window(splitter, style = sty)
    self.work_frame = work_frame = wx.Window(splitter, style = sty)
    tree_frame.SetBackgroundColour('White')
    work_frame.SetBackgroundColour('White')

    splitter2.SetMinimumPaneSize(20)
    #splitter2.SplitHorizontally(splitter, self.log_widget, -110)
    splitter2.SplitHorizontally(splitter, notebook1, -160)

    splitter.SetMinimumPaneSize(20)
    splitter.SplitVertically(tree_frame, work_frame, 200)

    splitter2.Bind(wx.EVT_SIZE, self.OnSize_splitter)

    ##
    ## Tree
    ##

    isz = (16, 16)
    il = wx.ImageList(isz[0], isz[1])
    self.tree_fldridx = fldridx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, isz))
    self.tree_fldropenidx = fldropenidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, isz))
    self.tree_boxidx = il.Add(self.bitmap_box)
    self.tree_cylinderidx = il.Add(self.bitmap_cylinder)
    self.tree_patchidx = il.Add(self.bitmap_patch)
    self.tree_circleidx = il.Add(self.bitmap_circle)
    self.tree_polygonidx = il.Add(self.bitmap_polygon)

    #tree_style = wx.TR_HIDE_ROOT | wx.TR_HAS_BUTTONS
    #if self.simulation.platform["name"] == 'WIN32':	# workaround for WIN32
    tree_style = wx.TR_HIDE_ROOT | wx.TR_LINES_AT_ROOT | wx.TR_HAS_BUTTONS
    self.tree = tree = wx.TreeCtrl(tree_frame, wx.NewId(), style = tree_style)
    self.tree.SetImageList(il)
    self.il = il		# this ensures the image list is not removed from memory

    troot = tree.AddRoot("emGine_GUI")	# XXX: Can I get this one?

    self.Bind(wx.EVT_TREE_SEL_CHANGED, self.tree_on_click, self.tree)
    self.tree.Bind(wx.EVT_LEFT_DCLICK, self.tree_on_left_dclick)

    ## geometry scene
    self.geometry_scene = GeometryScene.GeometryScene(work_frame)

    ## 2D plotting
    self.plot2D = Plot2D.Plot2D(work_frame)

    ## Smith Chart plotting
    self.plot_smith = PlotSmith.PlotSmith(work_frame)

    ## scale frame windows
    tree_frame.Bind(wx.EVT_SIZE, self.OnSize_tree_frame)
    work_frame.Bind(wx.EVT_SIZE, self.OnSize_work_frame)
    work_frame.Bind(wx.EVT_ENTER_WINDOW, self.change_cursor_work_frame)

    ## Q & D refresh
    self.OnSize_tree_frame(None)
    self.OnSize_work_frame(None)

    ### Show frame and return True to start the application
    frame.Show(True)
    self.SetTopWindow(frame)
    self.frame = frame
    return True

  def OnSize_tree_frame(self, evt):
    w, h = self.tree_frame.GetClientSizeTuple()
    self.tree.SetDimensions(0, 0, w, h)
    if evt:
      evt.Skip()

  def OnSize_work_frame(self, evt):
    w, h = self.work_frame.GetClientSizeTuple()
    self.geometry_scene.set_dimensions(0, 0, w, h)
    self.plot2D.set_dimensions(0, 0, w, h)
    self.plot_smith.set_dimensions(0, 0, w, h)
    if evt:
      evt.Skip()

  def OnSize_splitter(self, evt):
    splitter = evt.GetEventObject()
    size = splitter.GetSize()
    splitter.SetSashPosition(size.height - 160, False)
    evt.Skip()

  #### def OnInit_trash(self):
  ####   self.geometry_scene = GeometryScene.GeometryScene(work_frame)
  ####   self.plot2D = Plot2D.Plot2D(work_frame)

  ####   #####
  ####   ## Status bars
  ####   statbar_frame = self.statbar_frame = Frame(master)
  ####   statbar_frame.pack(side = LEFT, expand = YES, fill = X)
  ####   statbar_frame.columnconfigure(0, weight = 15, pad = 0)
  ####   statbar_frame.columnconfigure(1, weight = 1, pad = 0)
  ####   statbar_frame.columnconfigure(2, weight = 1, pad = 0)
  ####   statbar_frame.columnconfigure(3, weight = 1, pad = 0)
  ####   statbar_frame.columnconfigure(4, weight = 1, pad = 0)

  ####   self.statbar = Label(statbar_frame, text = "", bd = 1, relief = SUNKEN, anchor = W)
  ####   self.statbar.grid(row = 0, column = 0, sticky = W + E)
  ####   #self.statbar.pack(side = LEFT, fill = X)
  ####   #self.statbar.pack(side = BOTTOM, fill = X)

  ####   self.statbar2 = Label(statbar_frame, text = " Number of cells: ", bd = 1, relief = SUNKEN, anchor = W)
  ####   self.statbar2.grid(row = 0, column = 1, sticky = W + E)

  ####   self.statbar3 = Label(statbar_frame, text = " dl: ", bd = 1, relief = SUNKEN, anchor = W)
  ####   self.statbar3.grid(row = 0, column = 2, sticky = W + E, ipadx = 10)

  ####   self.statbar4 = Label(statbar_frame, text = " mm ", bd = 1, relief = SUNKEN, anchor = W)
  ####   self.statbar4.grid(row = 0, column = 3, sticky = W + E)

  ####   self.statbar5 = Label(statbar_frame, text = " GHz ", bd = 1, relief = SUNKEN, anchor = W)
  ####   self.statbar5.grid(row = 0, column = 4, sticky = W + E)
  ####   #print statbar_frame.grid_slaves()

  def get_time_units(self):
    time_verb = self.global_units['time']
    time_units = self.units_time_dict[time_verb]
    return (time_units, time_verb)

  def get_freq_units(self):
    freq_verb = self.global_units['frequency']
    freq_units = self.units_frequency_dict[freq_verb]
    return (freq_units, freq_verb)


  ###----------------------------------
  ### read_emm_materials
  ###
  ### Read materials from the EMM file
  ### and store them in the appropriate
  ### GroupMaterials structure
  ###----------------------------------
  def read_emm_materials(self):
    prj_materials = self.prj.get_all_materials()
    print "**** read_emm_materials ****"
    for mat_entry in prj_materials:
      material = Material()
      material.set_data_from_emm(mat_entry)
      self.materials.add(material)
    print self.materials.get_info()
    for entry in self.materials.get_list():
      print "--"
      print entry.get_info()
      print "--"

  ###----------------------------------
  ### read_emm_geometries
  ###
  ### Read geometries from the EMM file
  ### and store them in the appropriate
  ### GroupGeometryObjects structure
  ###----------------------------------
  def read_emm_geometries(self):
    return
    ### XXX: TODO: This routine should read and build all the geometries
    prj_geometries = self.prj.get_all_geometries()
    print "**** read_emm_geometries ****"
    for geom in prj_geometries:
      material_name = geom[consts.XML_ATTR_GEOMETRY_MATERIAL]
      geom_name = geom[consts.XML_ATTR_NAME]
      #geom_object = 
      mat = None
      if material_name:
	mat = self.materials.get_object_by_name(material_name)
      else:
	mat = self.materials.get_object_by_name(consts.EMGINE_DEFAULT_MATERIAL)

      if mat:
	print "Geometry " + geom_name + " is associated with material:\n"
	print mat.get_info()


  ###----------------------------------
  ### read_all_emm_data 
  ###
  ### Initialize all internal data
  ### structures with data from EMM
  ### file
  ###----------------------------------
  def read_all_emm_data(self):
    self.read_emm_materials()
    self.read_emm_geometries()

  ###--------------------------------------
  ### start_blank
  ###
  ### Description:
  ###     Initialize class' variables and
  ###     start a blank project
  ###--------------------------------------
  def start_blank(self):
    os.chdir(self.app_path)	# start from the top-level app directory

    ########################################################
    # initialize class' variables; also default values
    self.state = consts.STATE_INITIALIZED	# TODO: how can constants be defined?
    self.prj = Project.Project()	# initialize project
    self.log_device = emGineLog(self.log_widget)
    self.log_device_simulation = emGineLog(self.log_widget_simulation)
    self.simulation = Simulation.Simulation(self.log_device_simulation)	
    self.reference_simulation = Simulation.Simulation(self.log_device_simulation, '_ref')	
    self.clicked_node = None

    # Groups of objects
    self.geometries = GroupGeometryObjects()
    self.materials = GroupMaterials()

    self.results = ''
    self.ref_results = None
    self.mesh = Mesh()
    self.surrounding_space = None
    self.settings = {}			###< settings of the GUI
    self.guistate = GUIState()
    self.global_units = {'length' : '', 'frequency' : '', 'time' : ''} 	###< default units

    # Units
    self.units_length_dict = {'m':1, 'cm':1e-2, 'mm':1e-3, 'um':1e-6, 'nm':1e-9}
    self.units_frequency_dict = {'Hz':1, 'kHz':1e3, 'MHz':1e6, 'GHz':1e9, 'THz':1e12}
    self.units_time_dict = {'s':1, 'ms':1e-3, 'us':1e-6, 'ns':1e-9}
    
    self.inv_units_length_dict = dict([[v,k] for k,v in self.units_length_dict.items()])
    self.inv_units_frequency_dict = dict([[v,k] for k,v in self.units_frequency_dict.items()])
    self.inv_units_time_dict = dict([[v,k] for k,v in self.units_time_dict.items()])

    # Frame title
    self.frame_title = "%s" %(consts.MW_TITLE)

    # default wildcard
    self.wildcard = "Electromagnetic Model Files (*.emm)|*.emm|All Files (*.*)|*.*|All Files Unix (*)|*"

    ## Set defaults at start
    self.set_state_initialized()
    self.refresh_title_bar()
    self.refresh_status_bar()

    ## initialize the geometry scene and create an empty one
    self.geometry_scene.set_to_initial_state()
    self.construction_planes_redraw()

    ## initialize the tree to a default state 
    tree = self.tree
    troot = tree.GetRootItem()

    # first delete existing tree entries
    (item, cookie) = tree.GetFirstChild(troot)
    items = list()
    while item:
      items.append(item)
      (item, cookie) = tree.GetNextChild(troot, cookie)
    for item in items:
      tree.Delete(item)

    # now create default tree entries
    self.titem_materials = tree_item_materials = tree.AppendItem(troot, "Materials")
    self.titem_geometry = tree_item_geometry = tree.AppendItem(troot, "Geometry")
    self.titem_excitation = tree_item_excitation = tree.AppendItem(troot, "Excitation")
    self.titem_results = tree_item_results = tree.AppendItem(troot, "Results")
    # default data for the tree items
    for item_id in [troot, tree_item_materials, tree_item_geometry, tree_item_excitation, tree_item_results]:
      self.tree.SetItemPyData(item_id, None)
      self.tree.SetItemImage(item_id, self.tree_fldridx, wx.TreeItemIcon_Normal)
      self.tree.SetItemImage(item_id, self.tree_fldropenidx, wx.TreeItemIcon_Expanded)

    ## initialize default status bar
    self.statusbar.SetStatusText('', self.statbar_pos_length)
    self.statusbar.SetStatusText('', self.statbar_pos_frequency)
    self.statusbar.SetStatusText('', self.statbar_pos_time)
    self.statusbar.SetStatusText("dl: ", self.statbar_pos_dl)
    self.statusbar.SetStatusText("Number of cells: ", self.statbar_pos_ncells)

  def change_cursor_work_frame(self, evt):
    self.work_frame.SetCursor(wx.StockCursor(wx.CURSOR_CROSS))

  ###--------------------
  ### state_enable
  ###--------------------
  def state_enable(self, widgets):
    for widget in widgets:
      widget.config(state = NORMAL)

  ###--------------------
  ### state_disable
  ###--------------------
  def state_disable(self, widgets):
    for widget in widgets:
      widget.config(state = DISABLED)

  ###-----------------------
  ### refresh_all
  ###-----------------------
  def refresh_all(self):
    self.set_state(self.state)	# refresh with the current state
    self.show_tree()
    self.refresh_simulation_boundary_view()
    self.refresh_title_bar()
    self.refresh_status_bar()

  ###---------------------------
  ### refresh_with_new_material
  ###---------------------------
  def refresh_with_new_material(self):
    self.show_tree()
    self.refresh_title_bar()

  ###----------------------------
  ### refresh_with_new_geometry
  ###----------------------------
  def refresh_with_new_geometry(self):
    self.show_tree()
    self.refresh_mesh()
    self.construction_planes_redraw()
    self.refresh_simulation_boundary_view()
    self.refresh_title_bar()

  ###------------------------------------
  ### refresh_simulation_boundary_view
  ###------------------------------------
  def refresh_simulation_boundary_view(self):
    # redraw simulation boundary
    if self.guistate.show_simulation_boundary:
      self.hide_simulation_boundary()
      self.view_simulation_boundary()

  ###--------------
  ### refresh_mesh
  ###--------------
  def refresh_mesh(self):
    self.mesh.clear_all()
    #print "** Mesh::bbox : ", self.mesh.get_bbox()
    #print "*** Discretization points:", self.geometries.get_discretization_points()
    self.mesh.add_points(self.geometries.get_discretization_points())
    #print "** Mesh::bbox : ", self.mesh.get_bbox()
    self.mesh.set_simbox(self.surrounding_space.get_simbox())

  ###----------------------------------------
  ### refresh_status_bar
  ###----------------------------------------
  def refresh_status_bar(self):
    self.refresh_units()
    self.statusbar.SetStatusText(self.global_units['length'], self.statbar_pos_length)
    self.statusbar.SetStatusText(self.global_units['frequency'], self.statbar_pos_frequency)
    self.statusbar.SetStatusText(self.global_units['time'], self.statbar_pos_time)

  ###-------------------
  ### refresh_title_bar
  ###-------------------
  def refresh_title_bar(self):
    title = self.frame_title

    prj_name = self.prj.get_project_name()
    if prj_name != '':
      fname = self.prj.get_file_name()
      if self.prj.modified():
	fname = fname + " *"
      title = fname +  " (" + prj_name + ") - " + title

    self.frame.SetTitle(title)

  ###--------------------------
  ### refresh_units
  ###
  ### Description:
  ###     Refresh global units
  ###--------------------------
  def refresh_units(self):
    prj_units = self.prj.get_units()
    if not prj_units:
      return

    prj_length = prj_units[consts.XML_TAG_UNITS_LENGTH]
    prj_frequency = prj_units[consts.XML_TAG_UNITS_FREQUENCY]
    prj_time = prj_units[consts.XML_TAG_UNITS_TIME]

    self.global_units['length'] = self.inv_units_length_dict[prj_length]
    self.global_units['frequency'] = self.inv_units_frequency_dict[prj_frequency]
    self.global_units['time'] = self.inv_units_time_dict[prj_time]

  ###----------------------------------------------------
  ### set_state_initialized
  ###
  ### Description: set the state of the GUI just after
  ###              starting it
  ###----------------------------------------------------
  ### FIXME: this routine should be a part of set_state ?
  def set_state_initialized(self, mode = False):
    if mode == False:
      self.geometrym_disable_all()
    else:
      self.geometrym_disable_all(True)
      self.geometrym_disable_default()

    menu_bar = self.menu_bar

    # disable entries which make no sense if project not opened
    for id in [self.toolbar_save_id, self.toolbar_save_as_id]:
      self.toolbar.EnableTool(id, mode)

    for id in [self.toolbar_print_id]:
      self.toolbar.EnableTool(id, False)

    for id in [self.mnu_save_project_id, self.mnu_save_project_as_id, self.mnu_close_project_id]: 
      menu_bar.Enable(id, mode)

    for id in [self.mnu_print_id]: 
      menu_bar.Enable(id, False)

    for id in [self.mnu_delete_id]:
      menu_bar.Enable(id, mode)

    for id in [self.mnu_simulation_boundary_id, self.mnu_view_top_id, self.mnu_view_bottom_id, self.mnu_view_front_id, self.mnu_view_back_id, self.mnu_view_left_id, self.mnu_view_right_id, self.mnu_perspective_id]:
      menu_bar.Enable(id, mode)

    for id in [self.mnu_new_material_id]:
      menu_bar.Enable(id, mode)

    for id in [self.mnu_excitation_voltage_port_id]:
      menu_bar.Enable(id, mode)

    for id in [self.mnu_simulation_surrounding_space_id, self.mnu_simulation_boundary_conditions_id]:
      menu_bar.Enable(id, mode)

    # Solver
    for id in [self.toolbar_simulate_id]:
      self.toolbar.EnableTool(id, mode)

    for id in [self.mnu_solver_setup_id, self.mnu_solver_calculate_mesh_id, self.mnu_solver_simulate_id]:
      menu_bar.Enable(id, mode)

    # disable non-yet-working menus
    self.transformm_disable_all()

    for id in [self.mnu_copy_id, self.mnu_paste_id, self.mnu_rename_id, self.mnu_units_id, self.mnu_preferences_id]:
      menu_bar.Enable(id, False)

    for id in [self.mnu_zoom_fit_id, self.mnu_wireframe_id, self.mnu_shaded_id]:
      menu_bar.Enable(id, False)

    menu_bar.Enable(self.mnu_excitation_plane_wave_port_id, False)

    menu_bar.Enable(self.mnu_export_data_id, False)
    menu_bar.Enable(self.mnu_export_geometry_id, False)

    menu_bar.Enable(self.mnu_material_modify, False)

    menu_bar.Enable(self.mnu_excitation_modal_port_id, False)
    menu_bar.Enable(self.mnu_excitation_modify_id, False)

  ###---------------------------------------------------
  ### set_state_opened_project
  ###
  ### Description: set the state of the GUI default to
  ###              an opened project
  ###---------------------------------------------------
  def set_state_opened_project(self):
    self.set_state_initialized(True)


  ###----------------------------------------
  ### set_state
  ###
  ### if new_state == None, then refreshing
  ###----------------------------------------
  def set_state(self, new_state, state_data = None):
    old_state = self.state
    self.state = new_state
    print "MainWindow::state = ", self.state, "; old_state = ", old_state

    # default actions
    self.plot2D.hide()
    self.plot_smith.hide()
    self.geometry_scene.show()

    # disable the widgets, which are most of the time disabled
    self.geometrym_disable_default()
    self.menu_bar.Enable(self.mnu_geometry_change_material_id, False)

    self.excitationm_disable_all()
    self.resultsm_disable_all()

    # Highlight again all objects
    if (new_state != old_state) and ((old_state == consts.STATE_TREE_CLICKED_GEOMETRY_NODE) or (old_state == consts.STATE_TREE_CLICKED_EXCITATION_NODE)):
      self.geometry_scene.highlight_object(None)

    self.log_device.clear()

    # enable the widgets which should be enabled for the given state
    if new_state == consts.STATE_PROJECT_CHANGED:
      prj_state = self.prj.state
      if prj_state == consts.PRJ_STATE_OPENED or prj_state == consts.PRJ_STATE_NEW:
	None
	### #self.state_enable([self.butt_gen])     # XXX: delete this line!
	### self.filem.entryconfig(3, state = NORMAL)		#Save Project
	### self.filem.entryconfig(4, state = NORMAL)		#Save Project as...
	### self.filem.entryconfig(5, state = DISABLED)		#Close Project
	### self.statbar.config(text = "Working project: %s" %(self.prj.fname))
      elif prj_state == consts.PRJ_STATE_INITIALIZED:
	None
	### #self.state_disable([self.butt_gen, self.butt_view_sx, self.butt_view_sy, self.butt_view_sz]) #XXX: delete this line!
	### self.filem.entryconfig(3, state = DISABLED)		#Save Project
	### self.filem.entryconfig(4, state = DISABLED)		#Save Project as...
	### self.filem.entryconfig(5, state = DISABLED)		#Close Project
	### self.statbar.config(text = "")
      elif prj_state == consts.PRJ_STATE_SAVED:
	None
	### self.statbar.config(text = "Project saved under: %s" %(self.prj.fname))

    elif new_state == consts.STATE_TREE_CLICKED_GEOMETRY_NODE:
      object_name = self.clicked_node.getAttribute(consts.XML_ATTR_NAME)
      self.geometry_scene.highlight_geometry(object_name)
      #self.menu_bar.Enable(self.mnu_geometry_change_material_id, True)
      self.menu_bar.Enable(self.mnu_geometry_change_material_id, False)

      go = self.geometries.get_name(object_name)
      self.log_device.write(go.get_info())

    elif new_state == consts.STATE_TREE_CLICKED_EXCITATION_NODE:
      object_name = self.clicked_node.getAttribute(consts.XML_ATTR_NAME)
      self.geometry_scene.highlight_excitation(object_name)

    elif new_state == consts.STATE_TREE_CLICKED_MATERIAL:
      mat_name = self.clicked_node.getAttribute(consts.XML_ATTR_NAME)
      mat_obj = self.materials.get_object_by_name(mat_name)
      self.log_device.write(mat_obj.get_info())

    elif new_state == consts.STATE_TREE_CLICKED_PROJECT:	# Remove
      None	# Remove
    elif new_state == consts.STATE_TREE_CLICKED_FOLDER:	# Remove
      None	# Remove
    elif new_state == consts.STATE_TREE_CLICKED_SFOLDER:	# Remove
      None	# Remove
    elif new_state == consts.STATE_TREE_CLICKED_SIMULATION:	# Remove
      None	# Remove

    elif new_state == consts.STATE_TREE_CLICKED_GEOMETRY:
      self.geometrym_enable_all()

    elif new_state == consts.STATE_TREE_CLICKED_EXCITATION:
      self.excitationm_enable_all()

    elif new_state == consts.STATE_TREE_CLICKED_RESULTS2D:
      self.geometry_scene.hide()
      self.resultsm_enable_all()

      #fname = self.clicked_node.childNodes[0].nodeValue
      #res = self.results.get_object_by_name(self.clicked_node.getAttribute("name"))

      ## FIXME: Following code is VERY specific, e.g., taking
      ##        first or second list entry !!!!
      nname = self.clicked_node.getAttribute("name")

      (time_units, time_verb) = self.get_time_units()
      (freq_units, freq_verb) = self.get_freq_units()

      if (nname == 'z11'):
        res = self.results["zparams"][0]
        #self.plot2D.plot_data(res.impedance.get_xlist(), res.impedance.get_real_ylist())
	xdata = res.impedance.get_xarray()/freq_units
	real_part = res.impedance.get_real_ylist()
	imag_part = res.impedance.get_imag_ylist()
        self.plot2D.plot_data(xdata, real_part, 'Frequency [%s]' %(freq_verb), 'Re/Im{z11} [Ohm]')
	self.plot2D.hold_on()
        self.plot2D.plot_data(xdata, imag_part) #, 'Frequency [Hz]', 'Im{z11} [Ohm]')
	self.plot2D.hold_off()
	#print res.impedance.get_real_ylist()
      elif (nname == 's11'):
        res = self.results["sparams"][0]
        data = res.get_data()
	print "len(xlist) = ", len(data.get_xlist()), "; len(ylist) = ", len(data.get_ylist())
        self.plot2D.plot_data(data.get_xarray()/freq_units, data.get_20abs_dB_ylist(0), 'Frequency [%s]' %(freq_verb), 'dB(|s11|) [dB]')
      elif (nname == 's21'):
        res = self.results["sparams"][0]
        data = res.get_data()
        self.plot2D.plot_data(data.get_xarray()/freq_units, data.get_20abs_dB_ylist(1), 'Frequency [%s]' %(freq_verb), 'dB(|s21|) [dB]')
      elif (nname == 'TDSignal1'):
	res = self.results["tdsignals"][0]
	data = res.get_data()
	self.plot2D.plot_data(data.get_xarray()/time_units, data.get_yarray(), 'Time [%s]' %(time_verb), 'Wave amplitude [V]')
      elif (nname == 'TDSignal1_2'):
	res = self.results["tdsignals"][1]
	data = res.get_data()
	self.plot2D.plot_data(data.get_xarray()/time_units, data.get_yarray(), 'Time [%s]' %(time_verb), 'Wave amplitude [V]')
      elif (nname == 'TDSignal2'):
	res = self.results["tdsignals"][2]
	data = res.get_data()
	self.plot2D.plot_data(data.get_xarray()/time_units, data.get_yarray(), 'Time [%s]' %(time_verb), 'Wave amplitude [V]')
      elif (nname == 'TDSignal2_2'):
	res = self.results["tdsignals"][3]
	data = res.get_data()
	self.plot2D.plot_data(data.get_xarray()/time_units, data.get_yarray(), 'Time [%s]' %(time_verb), 'Wave amplitude [V]')
      else:
	print "** Warning! Unknown Result!"


      #self.plot2D.plot_ascii_file(fname)
      self.plot2D.show()

    elif new_state == consts.STATE_TREE_CLICKED_RESULTS2D_ALL_TDSIGNALS:
      self.geometry_scene.hide()
      self.resultsm_enable_all()

      (time_units, time_verb) = self.get_time_units()

      res_names = list()
      for res in self.results["tdsignals"]:
	data = res.get_data()
	res_names.append(res.names[0])
	self.plot2D.plot_data(data.get_xarray()/time_units, data.get_yarray(), 'Time [%s]' %(time_verb), 'Wave amplitude [V]')
	self.plot2D.hold_on()
      self.plot2D.set_legend(res_names)

      self.plot2D.hold_off()
      self.plot2D.show()

    elif new_state == consts.STATE_TREE_CLICKED_RESULTS2D_ALL_SPARAMETERS:
      self.geometry_scene.hide()
      self.resultsm_enable_all()

      (freq_units, freq_verb) = self.get_freq_units()

      for res in self.results["sparams"]:
	data = res.get_data()
	for i in range(data.get_ylen()):
	  self.plot2D.plot_data(data.get_xarray()/freq_units, data.get_20abs_dB_ylist(i), 'Frequency [%s]' %(freq_verb), 'S [dB]')
	  self.plot2D.hold_on()
	self.plot2D.set_legend(res.names)

      self.plot2D.hold_off()
      self.plot2D.show()

    elif new_state == consts.STATE_TREE_CLICKED_PLOT_ALL_SMITH:
      self.geometry_scene.hide()
      self.resultsm_enable_all()

      (freq_units, freq_verb) = self.get_freq_units()

      # TODO: just s11 is plotted for now
      for res in self.results["sparams"]:
	data = res.get_data()
	#for i in range(data.get_ylen()):
	for i in (0,):
	  self.plot_smith.plot_data(data.get_real_ylist(i), data.get_imag_ylist(i), data.get_xarray()/freq_units, 's11')
	  #self.plot_smith.hold_on()
	self.plot_smith.set_legend("Smith Chart - s11 plot")

      self.plot_smith.hold_off()
      self.plot_smith.show()

  ###--------------------
  ### tree_on_click
  ###--------------------
  def tree_on_click(self, evt):
    item = evt.GetItem()
    node_name = self.tree.GetItemText(item)
    node_data = self.tree.GetItemPyData(item)
    print "tree_on_click:", node_name, "; data:", node_data
    if node_data:
      node_data_name = None

      if isinstance(node_data, str):
	node_data_name = node_data
      else:
	node = node_data
	#print "tree_on_click: ;%s;" %(node.nodeName)
	self.clicked_node = node
	print self.clicked_node

	node_data_name = node.nodeName

      if node_data_name == consts.PRJ_TAG_PROJECT:		#XXX: why does 'is' not work???
        self.set_state(consts.STATE_TREE_CLICKED_PROJECT)

      elif node_data_name == consts.PRJ_TAG_FOLDER:		
        self.set_state(consts.STATE_TREE_CLICKED_FOLDER)

      elif node_data_name == consts.PRJ_TAG_SFOLDER:		
        self.set_state(consts.STATE_TREE_CLICKED_SFOLDER)

      elif node_data_name == consts.PRJ_TAG_SIMULATION:		
        self.set_state(consts.STATE_TREE_CLICKED_SIMULATION)

      elif node_data_name == consts.XML_TAG_GEOMETRY:
        self.set_state(consts.STATE_TREE_CLICKED_GEOMETRY)

      elif node_data_name in consts.XML_GEOMETRY_GROUP:
        self.set_state(consts.STATE_TREE_CLICKED_GEOMETRY_NODE)

      elif node_data_name == consts.XML_TAG_MATERIAL:
        self.set_state(consts.STATE_TREE_CLICKED_MATERIAL)

      elif node_data_name == consts.XML_TAG_EXCITATION:
        self.set_state(consts.STATE_TREE_CLICKED_EXCITATION)

      elif node_data_name in consts.XML_EXCITATION_GROUP:
        self.set_state(consts.STATE_TREE_CLICKED_EXCITATION_NODE)

      elif node_data_name in consts.XML_RESULTS2D_GROUP:
        self.set_state(consts.STATE_TREE_CLICKED_RESULTS2D)

      elif node_data_name == "all_S_smith":
	self.set_state(consts.STATE_TREE_CLICKED_PLOT_ALL_SMITH)

      elif node_data_name == "all_TD_signals":
	self.set_state(consts.STATE_TREE_CLICKED_RESULTS2D_ALL_TDSIGNALS)

      elif node_data_name == "all_S_parameters":
	self.set_state(consts.STATE_TREE_CLICKED_RESULTS2D_ALL_SPARAMETERS)

      else:
	self.set_state(consts.STATE_NONE)      # for states without definition need

    else:
      self.clicked_node = None
      self.set_state(consts.STATE_NONE)      # for states without definition need

  def tree_on_left_dclick(self, evt):
    pos = evt.GetPosition()
    item, flags = self.tree.HitTest(pos)
    item_data = self.tree.GetItemPyData(item)
    #print "tree_on_left_dclick: ", item_text

    parent = self.tree.GetItemParent(item)
    if parent.IsOk():
      if item_data == 'geometry_definition':
	self.geometry_edit_definition(self.tree.GetItemPyData(parent))

    evt.Skip()

  ###-----------------------------
  ### tree_init_with_project_data
  ###-----------------------------
  def tree_init_with_project_data(self):
    # set the items for base tree nodes
    self.tree.SetItemPyData(self.titem_materials, self.prj.get_node(consts.XML_TAG_MATERIALS))
    self.tree.SetItemPyData(self.titem_geometry, self.prj.get_node(consts.XML_TAG_GEOMETRY))
    self.tree.SetItemPyData(self.titem_excitation, self.prj.get_node(consts.XML_TAG_EXCITATION))
    #self.tree.SetItemPyData(self.titem_results, self.prj.get_node(consts.XML_TAG_RESULTS))

  ###-------------------
  ### get_tree_children
  ###-------------------
  def get_tree_children(self, parent):
    result = {}
    (item, cookie) = self.tree.GetFirstChild(parent)
    while item:
      result[self.tree.GetItemText(item)] = item
      (item, cookie) = self.tree.GetNextChild(parent, cookie)
    return result

  ###-------------------------
  ### tree_update_node_level1
  ###-------------------------
  def tree_update_node_level1(self, item, prj_data):
    # build lists of already contained items
    node_dict = self.get_tree_children(item)
    node_names = node_dict.keys()

    prj_data_names = list()
    for entry in prj_data:
      entry_name = entry[consts.XML_ATTR_NAME]
      prj_data_names.append(entry_name)
      if entry_name not in node_names:
	new_item = self.tree.AppendItem(item, entry_name)
	self.tree.SetItemPyData(new_item, entry[consts.GUI_XML_NODE])
      else:
	old_node = node_dict[entry_name]
	if self.tree.GetItemPyData(old_node) != entry[consts.GUI_XML_NODE]:
	  self.tree.SetItemPyData(old_node, entry[consts.GUI_XML_NODE])

    # delete old geometry items
    for old_entry in node_names:
      if old_entry not in prj_data_names:
	#print "deleting entry",  old_entry
	self.tree.Delete(node_dict[old_entry])

  ###-------------------------
  ### tree_update_node_result
  ###-------------------------
  def tree_update_node_result(self, item, res_data, xml_type):
    # build lists of already contained items
    node_dict = self.get_tree_children(item)
    node_names = node_dict.keys()

    #print ">>> res_data:", res_data
    res_data_names = list()
    if isinstance(res_data, list):
      for res in res_data:
	res_data_names.append(res.get_names()[0])
    else:
      res_data_names = res_data.get_names()

    for entry_name in res_data_names:
      if entry_name not in node_names:
	node = DummyNode(xml_type)
	node.setAttribute(consts.XML_ATTR_NAME, entry_name)
	new_item = self.tree.AppendItem(item, entry_name)
	self.tree.SetItemPyData(new_item, node)

    # delete old geometry items
    for old_entry in node_names:
      if old_entry not in res_data_names:
	#print "deleting entry",  old_entry
	self.tree.Delete(node_dict[old_entry])

  ###-------------------------
  ### tree_update_geometries
  ###-------------------------
  def tree_update_geometries(self):
    prj_geometries = self.prj.get_all_geometries()
    self.tree_update_node_level1(self.titem_geometry, prj_geometries)

    node_dict = self.get_tree_children(self.titem_geometry)
    node_names = node_dict.keys()
    print str(node_dict)
    for item in node_dict.values():
      (child, cookie) = self.tree.GetFirstChild(item)
      if not child:
	new_item = self.tree.AppendItem(item, "Definition")
	self.tree.SetItemPyData(new_item, "geometry_definition")

	data = self.tree.GetItemPyData(item)
	idx = None
	node_name = data.nodeName
	if node_name == consts.XML_TAG_CUBE:
	  idx = self.tree_boxidx
	elif node_name == consts.XML_TAG_CYLINDER:
	  idx = self.tree_cylinderidx
	elif node_name == consts.XML_TAG_PATCH:
	  idx = self.tree_patchidx
	elif node_name == consts.XML_TAG_CIRCLE:
	  idx = self.tree_circleidx
	elif node_name == consts.XML_TAG_POLYGON2D:
	  idx = self.tree_polygonidx

	if idx: 
	  self.tree.SetItemImage(new_item, idx, wx.TreeItemIcon_Normal) 
	  self.tree.SetItemImage(new_item, idx, wx.TreeItemIcon_Expanded) 



  ###----------------------
  ### tree_update_results
  ###----------------------
  def tree_update_results(self):
    # delete old entries

    nodes = self.get_tree_children(self.titem_results)
    if len(nodes) == 0:		# create sub-results nodes only if not already existing
      self.titem_results_tdsignals = self.tree.AppendItem(self.titem_results, "Time-Domain Signals")
      self.titem_results_sparams = self.tree.AppendItem(self.titem_results, "S-Parameters")
      self.titem_results_smith = self.tree.AppendItem(self.titem_results, "Smith Chart")
      self.titem_results_zparams = self.tree.AppendItem(self.titem_results, "Z-Parameters")
      for item_id in [self.titem_results_tdsignals, self.titem_results_sparams, self.titem_results_smith, self.titem_results_zparams]:
	self.tree.SetItemImage(item_id, self.tree_fldridx, wx.TreeItemIcon_Normal)
	self.tree.SetItemImage(item_id, self.tree_fldropenidx, wx.TreeItemIcon_Expanded)

      # create data for Time-Domain Signals
      self.tree.SetItemPyData(self.titem_results_tdsignals, "all_TD_signals")
      self.tree.SetItemPyData(self.titem_results_sparams, "all_S_parameters")
      self.tree.SetItemPyData(self.titem_results_smith, "all_S_smith")

    ## prj_results = self.prj.get_all_results()
    ## print ">>> prj_results:", prj_results
    ## tdsignals = list()
    ## sparams = list()
    ## zparams = list()
    ## for result in prj_results:
    ##   res_type = result[consts.XML_TAG_RESULTS]
    ##   if res_type == consts.XML_TAG_TDSIGNAL:
    ##     tdsignals.append(result)
    ##   elif res_type == consts.XML_TAG_SPARAMETERS:
    ##     sparams.append(result)
    ##   elif res_type == consts.XML_TAG_ZPARAMETERS:
    ##     zparams.append(result)
    ##
    ## self.tree_update_node_level1(self.titem_results_tdsignals, tdsignals)
    ## self.tree_update_node_level1(self.titem_results_sparams, sparams)
    ## self.tree_update_node_level1(self.titem_results_zparams, zparams)

    results = self.simulation.get_results()
    #tdsignals = results["tdsignals"][0]
    sparams = results["sparams"][0]
    zparams = results["zparams"][0]

    self.tree_update_node_result(self.titem_results_tdsignals, results["tdsignals"], consts.XML_TAG_TDSIGNAL)
    self.tree_update_node_result(self.titem_results_sparams, sparams, consts.XML_TAG_SPARAMETERS)
    self.tree_update_node_result(self.titem_results_zparams, zparams, consts.XML_TAG_ZPARAMETERS)

  ###-------------------------------------------
  ### show_tree
  ###
  ### Description: show and refresh the tree
  ###-------------------------------------------
  def show_tree(self):
    #
    # TODO: when refreshing the tree, do not collapse, but stay in the current state
    #
    prj = self.prj

    ### Refresh the tree ###

    ## Materials ##
    prj_materials = prj.get_all_materials()
    self.tree_update_node_level1(self.titem_materials, prj_materials)

    ## Geometries ##
    self.tree_update_geometries()

    ## Excitations ##
    prj_excitations = prj.get_all_excitations()
    self.tree_update_node_level1(self.titem_excitation, prj_excitations)

    ## Results ##
    if self.simulation.have_results:
      self.tree_update_results()

    self.tree.Refresh(True)

  ###--------------------
  ### delete_tree
  ###--------------------
  def delete_tree(self):
    print "** Warning! delete_tree not implemented!"

  ###--------------------
  ### delete_tree_old XXX: DELETE this routine XXX
  ###--------------------
  def delete_tree_old(self):
    self.tree_node.destroy()
    self.tree_canvas.destroy()		#destroy the canvas; TODO: is it OK so?

    # recreate the canvas
    ## tree_canvas = self.tree_canvas = ScrolledCanvas(self.tree_frame)
    ## tree_canvas.config(bg = 'white')
    ## tree_canvas.pack()

    #tree_canvas = self.tree_canvas = ScrolledCanvas(tree_frame, bg = "white")
    tree_canvas = self.tree_canvas = Canvas(self.tree_frame, bg = "white")
    #tree_canvas.config(bg = 'white')
    #tree_canvas.frame.pack(expand = 1)
    tree_canvas.pack(expand = 1)

  ###############
  #### PATCH ####
  ###############

  ###---------------------------------------
  ### get_new_patch
  ###
  ### Generate new patch geometry
  ###
  ### FIXME: This should be a constructor
  ###        method of GeometryObjectPatch
  ###---------------------------------------
  def get_new_patch(self, patchdef):
    if isinstance(patchdef, dict):
      name = patchdef[consts.XML_ATTR_NAME]
      material_name = patchdef[consts.XML_ATTR_GEOMETRY_MATERIAL]
      x1 = float(patchdef[consts.XML_TAG_X1])
      y1 = float(patchdef[consts.XML_TAG_Y1])
      x2 = x1 + float(patchdef[consts.XML_TAG_LENGTH_X])
      y2 = y1 + float(patchdef[consts.XML_TAG_LENGTH_Y])
      z = float(patchdef[consts.XML_TAG_Z1])
    else:
      name = patchdef[0]
      x1 = float(patchdef[1])
      y1 = float(patchdef[2])
      x2 = x1 + float(patchdef[3])
      y2 = y1 + float(patchdef[4])
      z = float(patchdef[5])
      material_name = str(patchdef[-1])		# last entry is the material name

    p1 = [x1, y1, z]
    p2 = [x2, y2, z]
    material = self.materials.get_material_by_name(material_name)
    new_patch = GeometryObjectPatch(name, p1, p2, material)
    return new_patch

  #### ###----------------------------------
  #### ### add_patch
  #### ###
  #### ### add a patch geometry to the GUI
  #### ###----------------------------------
  #### def add_patch(self, patchdef):

  ###----------------
  ### edit_patch
  ###----------------
  def edit_patch(self, patchdef, old_patch = None):
    new_patch = self.get_new_patch(patchdef)
    print self.geometries.get_info()
    if not old_patch:
      #self.add_patch(patchdef)
      self.geometries.add(new_patch)
    else:
      self.geometries.replace_object(old_patch, new_patch)
      self.geometry_scene.delete_geometry(old_patch.name)

    self.geometry_scene.add_patch(new_patch)
    print self.geometries.get_info()

  ################
  #### CIRCLE ####
  ################

  def get_new_circle(self, circledef):
    if isinstance(circledef, dict):
      name = circledef[consts.XML_ATTR_NAME]
      material_name = circledef[consts.XML_ATTR_GEOMETRY_MATERIAL]
      x = float(circledef[consts.XML_TAG_X1])
      y = float(circledef[consts.XML_TAG_Y1])
      z = float(circledef[consts.XML_TAG_Z1])
      radius = float(circledef[consts.XML_TAG_RADIUS])
    else:
      name = circledef[0]
      x = float(circledef[1])
      y = float(circledef[2])
      radius = float(circledef[3])
      z = float(circledef[4])
      material_name = str(circledef[-1])		# last entry is the material name

    p1 = [x, y, z]
    material = self.materials.get_material_by_name(material_name)
    new_circle = GeometryObjectCircle(name, p1, radius, material)
    return new_circle

  #### ###----------------------------------
  #### ### add_circle
  #### ###
  #### ### add a circle geometry to the GUI
  #### ###----------------------------------
  #### def add_circle(self, circledef):

  def edit_circle(self, circledef, old_circle_go = None):
    new_circle_go = self.get_new_circle(circledef)
    if not old_circle_go:
      self.geometries.add(new_circle_go)
    else:
      self.geometries.replace_object(old_circle_go, new_circle_go)
      self.geometry_scene.delete_geometry(old_circle_go.name)
    self.geometry_scene.add_circle(new_circle_go)

  #################
  #### POLYGON ####
  #################

  ###----------------------------------
  ### get_new_polygon
  ###
  ### generate a polygon geometry 
  ###----------------------------------
  def get_new_polygon(self, polygondef): #points, level, normal = 'z'):
    if isinstance(polygondef, dict):
      name = polygondef[consts.XML_ATTR_NAME]
      material_name = polygondef[consts.XML_ATTR_GEOMETRY_MATERIAL]
      level = polygondef[consts.XML_TAG_LEVEL]
      normal = polygondef[consts.XML_TAG_NORMAL]
      points2d = polygondef[consts.XML_TAG_POINTS]
    else:
      points2d = polygondef[0]
      data = polygondef[1]
      normal_v = polygondef[2]

      name = data[0]
      level = float(data[1])

      normal = [0,0,1]	# default normal in z
      if normal_v == 'x':
	normal = [1,0,0]
      elif normal_v == 'y':
	normal = [0,1,0]

      material_name = str(polygondef[-1])		# last entry is the material name

    points = list()
    if normal == [0,0,1]:
      for point in points2d:
	points.append([point[0], point[1], level])
    elif normal == [0,1,0]:
      for point in points2d:
	points.append([point[1], level, point[0]])
    elif normal == [1,0,0]:
      for point in points2d:
	points.append([level, point[0], point[1]])

    #print "Adding polygon ", name, " with:", points, normal
    material = self.materials.get_material_by_name(material_name)
    new_polygon = GeometryObjectPolygon(name, points, normal, material)
    return new_polygon

  ###--------------
  ### edit_polygon
  ###--------------
  def edit_polygon(self, polygondef, old_polygon_go = None):
    new_polygon_go = self.get_new_polygon(polygondef)
    if not old_polygon_go:
      self.geometries.add(new_polygon_go)
    else:
      self.geometries.replace_object(old_polygon_go, new_polygon_go)
      self.geometry_scene.delete_geometry(old_polygon_go.name)
    self.geometry_scene.add_polygon(new_polygon_go)

  #############
  #### BOX ####
  #############

  def get_new_box(self, boxdef):
    if isinstance(boxdef, dict):
      name = boxdef[consts.XML_ATTR_NAME]
      material_name = boxdef[consts.XML_ATTR_GEOMETRY_MATERIAL]
      x1 = float(boxdef[consts.XML_TAG_X1])
      y1 = float(boxdef[consts.XML_TAG_Y1])
      z1 = float(boxdef[consts.XML_TAG_Z1])

      x2 = x1 + float(boxdef[consts.XML_TAG_LENGTH_X])
      y2 = y1 + float(boxdef[consts.XML_TAG_LENGTH_Y])
      z2 = z1 + float(boxdef[consts.XML_TAG_LENGTH_Z])
    else:
      name = boxdef[0]
      x1 = float(boxdef[1])
      y1 = float(boxdef[2])
      z1 = float(boxdef[3])

      x2 = x1 + float(boxdef[4])
      y2 = y1 + float(boxdef[5])
      z2 = z1 + float(boxdef[6])
      material_name = str(boxdef[-1])		# last entry is the material name

    p1 = [x1, y1, z1]
    p2 = [x2, y2, z2]
    material = self.materials.get_material_by_name(material_name)
    new_box = GeometryObjectBox(name, p1, p2, material)
    return new_box

  ###----------------------------------
  ### edit_box
  ###
  ### edit a box geometry to the GUI
  ###----------------------------------
  def edit_box(self, boxdef, old_box_go = None):
    new_box_go = self.get_new_box(boxdef)
    if not old_box_go:
      self.geometries.add(new_box_go)
    else:
      self.geometries.replace_object(old_box_go, new_box_go)
      self.geometry_scene.delete_geometry(old_box_go.name)
    self.geometry_scene.add_box(new_box_go)

  ##################
  #### CYLINDER ####
  ##################

  ###------------------------------------
  ### get_new_cylinder
  ###
  ### get a cylinder geometry
  ###------------------------------------
  def get_new_cylinder(self, cyldef):
    if isinstance(cyldef, dict):
      name = cyldef[consts.XML_ATTR_NAME]
      material_name = cyldef[consts.XML_ATTR_GEOMETRY_MATERIAL]
      x1 = float(cyldef[consts.XML_TAG_X1])
      y1 = float(cyldef[consts.XML_TAG_Y1])
      z1 = float(cyldef[consts.XML_TAG_Z1])
      radius = float(cyldef[consts.XML_TAG_RADIUS])
      height = float(cyldef[consts.XML_TAG_HEIGHT])
    else:
      name = cyldef[0]
      material_name = str(cyldef[-1])		# last entry is the material name
      x1 = float(cyldef[1])
      y1 = float(cyldef[2])
      z1 = float(cyldef[3])

      radius = float(cyldef[4])
      height = float(cyldef[5])


    p1 = [x1, y1, z1]
    material = self.materials.get_material_by_name(material_name)
    new_cylinder = GeometryObjectCylinder(name, p1, radius, height, material)
    return new_cylinder

  def edit_cylinder(self, cyldef, old_cylinder_go = None):
    new_cylinder_go = self.get_new_cylinder(cyldef)
    if not old_cylinder_go:
      self.geometries.add(new_cylinder_go)
    else:
      self.geometries.replace_object(old_cylinder_go, new_cylinder_go)
      self.geometry_scene.delete_geometry(old_cylinder_go.name)
    self.geometry_scene.add_cylinder(new_cylinder_go)


  ###------------------------------------------
  ### open_project_from_file
  ###
  ### Description:
  ###     Open a project from the file given
  ###     by filename
  ###------------------------------------------
  def open_project_from_file(self, prjfname):
    self.prj.open_working_file(prjfname)

    # initialize all data structures from EMM file (database)
    self.read_all_emm_data()

    # initialize the tree
    self.tree_init_with_project_data()

    # Re-draw geometries
    self.set_state(consts.STATE_PROJECT_CHANGED)
    self.geometry_redraw_all()

    # Re-load and re-calculate simulation results
    results = self.prj.get_results()
    ref_results = None
    ref_results_sim = self.prj.get_ref_results()

    print "MainWindow::open_working_file - results:"
    print results
    print "MainWindow::open_working_file - ref_results:"
    print ref_results

    number_of_ports = len(self.prj.get_all_excitations())
    self.simulation.set_number_of_ports(number_of_ports)
    #self.reference_simulation.set_number_of_ports(number_of_ports)

    if number_of_ports == 2:            # FIXME: implement more sophisticated
                                        #        system to find out if deembedding is
					#        needed !
      self.reference_simulation.deembedding_turn_on()
      self.simulation.deembedding_turn_on()

    if results:
      if ref_results_sim:
	ref_results = self.reference_simulation.recalculate_results(ref_results_sim, is_reference = True)

      self.simulation.recalculate_results(results, reference_results = ref_results)
      self.results = self.simulation.results
      self.ref_results = ref_results

    # Re-load surrounding space
    self.surrounding_space = self.prj.get_surrounding_space()
    self.mesh.set_simbox(self.surrounding_space.get_simbox())
    self.settings = self.prj.get_emginegui_settings()
    print self.settings

    # draw construction plane
    self.construction_planes_redraw()

    # redraw the tree and title bar
    self.show_tree()
    self.refresh_title_bar()
    self.refresh_status_bar()

    # set the state of the GUI to opened project
    self.set_state_opened_project()

  ### Redraw construction planes
  def construction_planes_redraw(self):
    self.mesh.add_points(self.geometries.get_discretization_points())
    simbox = self.mesh.get_bbox()

    # default simbox if no simbox found
    #print simbox
    if ( simbox == ((None, None, None), (None, None, None)) ):
      simbox = ((-5, -5, 0), (5, 5, 0))

    bbox2D = ((simbox[0][0], simbox[0][1]), (simbox[1][0], simbox[1][1]))
    self.geometry_scene.draw_construction_plane_xy(bbox2D)
    #self.work_frame.grid()

  ### Calculate discretization step dl for uniform mesh.
  ### dl is returned in units of the project
  def calculate_uniform_dl(self):
    prj_units = self.prj.get_units()

    units_length = prj_units[consts.XML_TAG_UNITS_LENGTH]

    mesh = self.mesh
    mesh.add_points(self.geometries.get_discretization_points())
    min_dl = mesh.get_min_dl()

    dl = self.simulation.dl/units_length	# simulation has dl in meters
    if min_dl != None:
      if (min_dl < dl):
	print "!! Warning !! Objects with finer details than mesh resolution detected !!!"
	dl = min_dl/2			# at least two cells per detail
    else:
      print "!! Warning !! Mesh does not return correct dl!"

    return dl


  ##########################################################################################
  ###--------------------
  ### edit_delete
  ###--------------------
  def edit_delete(self, evt):
    state = self.state
    if (state == consts.STATE_TREE_CLICKED_GEOMETRY_NODE) | (state == consts.STATE_TREE_CLICKED_EXCITATION_NODE):
      if self.delete_object_ask(evt) == wx.ID_YES:
	print "Deleting object: ", self.clicked_node
	
	object_name = self.clicked_node.getAttribute(consts.XML_ATTR_NAME)

	if (self.state == consts.STATE_TREE_CLICKED_GEOMETRY_NODE):
	  self.prj.delete_geometry_node(self.clicked_node)
	  self.geometry_scene.delete_geometry(object_name)
	  self.geometries.remove(object_name)
	elif (self.state == consts.STATE_TREE_CLICKED_MATERIAL):
	  dialog = wx.MessageDialog(self.frame, "Materials cannot be deleted in this version!", "emGine limitation", wx.OK | wx.ICON_EXCLAMATION)
	  dialog.ShowModal()
	  dialog.Destroy()
	  #self.prj.delete_material_node(self.clicked_node)
	elif (self.state == consts.STATE_TREE_CLICKED_EXCITATION_NODE):
	  self.prj.delete_excitation_node(self.clicked_node)
	  self.geometry_scene.delete_excitation(object_name)
	else:
	  dialog = wx.MessageDialog(self.frame, "This object cannot be deleted!", "emGine limitation", wx.OK | wx.ICON_EXCLAMATION)
	  dialog.ShowModal()
	  dialog.Destroy()
	  return

	# refresh
	self.show_tree()
	self.refresh_mesh()
	self.refresh_simulation_boundary_view()
	self.construction_planes_redraw()
	self.refresh_title_bar()
    else:
      if (self.state == consts.STATE_TREE_CLICKED_MATERIAL):
	dialog = wx.MessageDialog(self.frame, "Sorry, materials cannot be deleted in this version!", "emGine limitation", wx.OK | wx.ICON_EXCLAMATION)
	dialog.ShowModal()
	dialog.Destroy()
	#self.prj.delete_material_node(self.clicked_node)
      else:
	wx.MessageBox("Sorry, this object cannot be deleted!", "emGine limitation")
	#dialog = wx.MessageDialog(self.frame, "Sorry, this object cannot be deleted!", "emGine limitation", wx.OK | wx.ICON_EXCLAMATION)
	#dialog.ShowModal()
	#dialog.Destroy()


  ##########################################################################################

  ###-----------
  ### view_top
  ###-----------
  def view_top(self, evt):
    self.geometry_scene.set_view_top()

  ###-------------
  ### view_bottom
  ###-------------
  def view_bottom(self, evt):
    self.geometry_scene.set_view_bottom()

  ###-------------
  ### view_front
  ###-------------
  def view_front(self, evt):
    self.geometry_scene.set_view_front()

  ###-------------
  ### view_back
  ###-------------
  def view_back(self, evt):
    self.geometry_scene.set_view_back()

  ###-------------
  ### view_left
  ###-------------
  def view_left(self, evt):
    self.geometry_scene.set_view_left()

  ###-------------
  ### view_right
  ###-------------
  def view_right(self, evt):
    self.geometry_scene.set_view_right()

  ###-------------------
  ### view_perspective
  ###-------------------
  def view_perspective(self, evt):
    if self.guistate.perspective_view == True:
      self.viewm.Check(self.mnu_perspective_id, False)	# check
      self.geometry_scene.set_orthogonal_projection()
      self.guistate.perspective_view = False
    else:
      self.viewm.Check(self.mnu_perspective_id, True)	# check
      self.geometry_scene.set_perspective_projection()
      self.guistate.perspective_view = True

  ###---------------------------
  ### view_simulation_boundary
  ###---------------------------
  def view_simulation_boundary(self, evt = None):
    #mesh = Mesh()
    if self.guistate.show_simulation_boundary == False:		# boundary not shown up to now
      mesh = self.mesh
      mesh.add_points(self.geometries.get_discretization_points())
      self.geometry_scene.show_simulation_boundary(mesh.get_bbox())
      self.guistate.show_simulation_boundary = True
    else:							# hide simulation boundary
      self.hide_simulation_boundary()

  def hide_simulation_boundary(self):
    #print "hiding simulation boundary"
    if self.guistate.show_simulation_boundary:
      self.viewm.Check(self.mnu_simulation_boundary_id, False)	# uncheck always
      self.geometry_scene.hide_simulation_boundary()
      self.guistate.show_simulation_boundary = False

  def save_project(self, fname):
    print "Saving file " + fname
    self.prj.save(fname)
    self.refresh_title_bar()

  ###------------------------------------------
  ### project_not_saved_ask
  ###
  ### Description:
  ### ask the user if OK to perform
  ### an action if the project is not saved
  ###------------------------------------------
  def project_not_saved_ask(self, evt):
    dialog = wx.MessageDialog(self.frame, "Project was modified, do you want to save it first?", "Save changes", wx.YES_NO | wx.CANCEL | wx.ICON_EXCLAMATION)
    ret_val = dialog.ShowModal()
    if ret_val == wx.ID_YES:
      self.file_save_project(evt)
    dialog.Destroy()

    return ret_val

  ###---------------------------------------
  ### delete_object_ask
  ###
  ### Description:
  ###          ask the user if OK to delete
  ###          the selected object
  ###---------------------------------------
  def delete_object_ask(self, evt):
    dialog = wx.MessageDialog(self.frame, "Delete permanently the selected object?", "Delete object", wx.YES_NO | wx.ICON_QUESTION)
    ret_val = dialog.ShowModal()
    dialog.Destroy()

    return ret_val




  #############################################################################
  ### FILE callbacks
  #############################################################################

  ###--------------------
  ### file_new_project
  ###--------------------
  def file_new_project(self, evt):
    # first test if an opened project was modified
    if self.prj.modified():
      ret_dialog = self.project_not_saved_ask(evt)
      if ret_dialog == wx.ID_CANCEL:
	return

    # ask the user to define a new project
    dialog = NewProjectDialog() #self.units_length_dict, self.units_frequency_dict, self.units_time_dict)
    if dialog.ShowModal() == wx.ID_OK:
      # close an opened project first
      if self.prj.state != consts.PRJ_STATE_INITIALIZED:
	self.file_close_project(evt)

      res_raw = dialog.get_data()
      dialog_result = [res_raw[0], self.units_length_dict[res_raw[1]], self.units_frequency_dict[res_raw[2]], self.units_time_dict[res_raw[3]]]

      self.global_units['length'] = res_raw[1]
      self.global_units['frequency'] = res_raw[2]
      self.global_units['time'] = res_raw[3]

      #print dialog_result

      self.prj.new(dialog_result)
      self.read_all_emm_data()
      self.tree_init_with_project_data()
      self.show_tree()
      self.refresh_status_bar()
      self.refresh_title_bar()
      self.set_state_opened_project()
      self.set_state(consts.STATE_PROJECT_CHANGED)
    dialog.Destroy()

  ###--------------------
  ### file_open_project
  ###--------------------
  def file_open_project(self, evt):
    #print ">> CWD: " + os.getcwd()

    # first test if an opened project was modified
    if self.prj.modified():
      ret_dialog = self.project_not_saved_ask(evt)
      if ret_dialog == wx.ID_CANCEL:
	return

    # ask the user to choose a project to open
    dialog = wx.FileDialog(None, "Open a project", wildcard = self.wildcard , style = wx.OPEN) #, style = wx.CHANGE_DIR)
    if dialog.ShowModal() == wx.ID_OK:
      # close an opened project first
      if self.prj.state != consts.PRJ_STATE_INITIALIZED:
	self.file_close_project(evt)

      #print ">> CWD: " + os.getcwd()
      prjfname = dialog.GetPath()
      self.open_project_from_file(prjfname)
    dialog.Destroy()

  ###--------------------
  ### file_save_project
  ###--------------------
  def file_save_project(self, evt):
    ### TODO: check for 'Noname.emm' no file name ??
    if self.prj.fname == consts.PRJ_DEFAULT_FNAME:
      self.file_save_project_as(evt)
    else:
      self.save_project(self.prj.fname)
  
  ###--------------------
  ### file_save_project_as
  ###--------------------
  def file_save_project_as(self, evt):
    fname = self.prj.get_file_name()
    dialog = wx.FileDialog(None, "Save project as...", defaultFile = fname, wildcard = self.wildcard, style = wx.SAVE | wx.OVERWRITE_PROMPT)

    if dialog.ShowModal() == wx.ID_OK:
      fname = dialog.GetPath()
      self.save_project(fname)
    dialog.Destroy()


    #### ## TODO: check for file overwrite!
    #### if not fname:
    ####   fname = tkFileDialog.asksaveasfilename()
    ####   if not fname:
    ####     return
    ####   self.prj.fname = fname


    ##f = open(fname, "w")
    ##self.prj.dom.writexml(f, indent = "  ")
    ###f.write(self.prj.dom.toprettyxml("  "))
    ##f.close()
    ##self.set_state(consts.STATE_PROJECT_CHANGED)


  ###--------------------
  ### file_close_project
  ###--------------------
  def file_close_project(self, evt):
    if self.prj.modified():
      ret_dialog = self.project_not_saved_ask(evt)
      if ret_dialog == wx.ID_CANCEL:
	return

    ### close the project
    self.prj.close()

    ### hide the simulation boundary
    self.hide_simulation_boundary()

    ### start a new blank UI
    self.start_blank()

    #### self.delete_tree()
    #### self.set_state(consts.STATE_PROJECT_CHANGED)
    #### self.work_frame.grid_remove()

  ###---------------------
  ### file_platform_info
  ###---------------------
  def file_platform_info(self, evt):
    msg = "** Platform Information **\n\n"
    msg += self.simulation.get_platform_info()
    dialog = wx.lib.dialogs.ScrolledMessageDialog(self.frame, msg, "Platform information")
    dialog.ShowModal()
    dialog.Destroy()

  ###----------------------
  ### geometry_edit_patch
  ###----------------------
  def geometry_edit_patch(self, patch_go = None):
    dialog_result = None
    dialog = GeometryPatchDialog(patch_go)
    dialog.set_materials(self.materials)
    dialog.set_material_list([consts.EMGINE_MATERIAL_PEC])

    geometries_names = self.geometries.get_list_of_names()
    if patch_go:
      geometries_names.remove(patch_go.name)
    dialog.turn_on_unique_name_checking(geometries_names)

    if dialog.ShowModal() == wx.ID_OK:
      dialog_result = dialog.get_data()
    dialog.Destroy()

    if dialog_result:
      if not patch_go:
	#print "Adding patch"
	self.prj.add_geometry_patch(dialog_result)
      else:
	self.prj.replace_geometry_patch(dialog_result, patch_go.name)

      self.edit_patch(dialog_result, patch_go)
      self.refresh_with_new_geometry()

  ###----------------------
  ### geometry_edit_circle
  ###----------------------
  def geometry_edit_circle(self, circle_go = None):
    dialog_result = None
    dialog = GeometryCircleDialog(circle_go)
    dialog.set_materials(self.materials)
    dialog.set_material_list([consts.EMGINE_MATERIAL_PEC])

    geometries_names = self.geometries.get_list_of_names()
    if circle_go:
      geometries_names.remove(circle_go.name)
    dialog.turn_on_unique_name_checking(geometries_names)

    if dialog.ShowModal() == wx.ID_OK:
      dialog_result = dialog.get_data()
    dialog.Destroy()

    if dialog_result:
      if not circle_go:
	self.prj.add_geometry_circle(dialog_result)
      else:
	self.prj.replace_geometry_circle(dialog_result, circle_go.name)

      self.edit_circle(dialog_result, circle_go)
      self.refresh_with_new_geometry()

  ###-----------------------
  ### geometry_edit_polygon
  ###-----------------------
  def geometry_edit_polygon(self, polygon_go = None):
    dialog_result = None
    dialog = GeometryPolygonDialog(polygon_go)
    dialog.set_materials(self.materials)
    dialog.set_material_list([consts.EMGINE_MATERIAL_PEC])

    geometries_names = self.geometries.get_list_of_names()
    if polygon_go:
      geometries_names.remove(polygon_go.name)
    dialog.turn_on_unique_name_checking(geometries_names)

    if dialog.ShowModal() == wx.ID_OK:
      data_grid = dialog.get_data_grid()[0]
      data_text = dialog.get_data()

      # create the list of points given by the user
      points = list()
      for entry in data_grid:
	if len(entry) == 2:
	  points.append([float(entry[0]), float(entry[1])])

      if (len(points) >= 3):
	# polygon must have at least three points
	polygon_def = [points, data_text, 'z']
	if not polygon_go:
	  self.prj.add_geometry_polygon(polygon_def)
	else:
	  self.prj.replace_geometry_polygon(polygon_def, polygon_go.name)

	self.edit_polygon(polygon_def, polygon_go)
	self.refresh_with_new_geometry()
    dialog.Destroy()

  ###-------------------
  ### geometry_edit_box
  ###-------------------
  def geometry_edit_box(self, box_go = None):
    dialog_result = None
    dialog = GeometryBoxDialog(box_go)
    dialog.set_materials(self.materials)

    geometries_names = self.geometries.get_list_of_names()
    if box_go:
      geometries_names.remove(box_go.name)
      dialog.set_selected_material(box_go.material)
    dialog.turn_on_unique_name_checking(geometries_names)

    if dialog.ShowModal() == wx.ID_OK:
      dialog_result = dialog.get_data()
    dialog.Destroy()

    if dialog_result:
      if not box_go:
	self.prj.add_geometry_box(dialog_result)
      else:
	self.prj.replace_geometry_box(dialog_result, box_go.name)

      self.edit_box(dialog_result, box_go)
      self.refresh_with_new_geometry()

  ###------------------------
  ### geometry_edit_cylinder
  ###------------------------
  def geometry_edit_cylinder(self, cylinder_go = None):
    dialog = GeometryCylinderDialog(cylinder_go)
    dialog.set_materials(self.materials)
    dialog.set_material_list([consts.EMGINE_MATERIAL_PEC])

    geometries_names = self.geometries.get_list_of_names()
    if cylinder_go:
      geometries_names.remove(cylinder_go.name)
    dialog.turn_on_unique_name_checking(geometries_names)

    if dialog.ShowModal() == wx.ID_OK:
      dialog_result = dialog.get_data()
      if not cylinder_go:
	self.prj.add_geometry_cylinder(dialog_result)
      else:
	self.prj.replace_geometry_cylinder(dialog_result, cylinder_go.name)

      self.edit_cylinder(dialog_result, cylinder_go)
      self.refresh_with_new_geometry()
    dialog.Destroy()

  #############################################################################
  ### GEOMETRY callbacks
  #############################################################################

  ###--------------------
  ### geometry_patch
  ###--------------------
  def geometry_patch(self, evt):
    self.geometry_edit_patch()

  ###--------------------
  ### geometry_circle
  ###--------------------
  def geometry_circle(self, evt):
    self.geometry_edit_circle()

  ###--------------------
  ### geometry_polygon
  ###--------------------
  def geometry_polygon(self, evt):
    self.geometry_edit_polygon()

  ###--------------------
  ### geometry_box
  ###--------------------
  def geometry_box(self, evt):
    self.geometry_edit_box()

  ###--------------------
  ### geometry_cylinder
  ###--------------------
  def geometry_cylinder(self, evt):
    self.geometry_edit_cylinder()

  ###----------------------------------------
  ### geometry_macro_model_rectangular_coil
  ###----------------------------------------
  def geometry_macro_model_rectangular_coil(self):
    dialog = GeometryMacroModelRectangularCoilDialog(self.master, "Rectangular Coil...")
    if not dialog.result:
      return
    print "Adding rectangular coil"


  ###---------------------------
  ### geometry_change_material
  ###---------------------------
  def geometry_change_material(self, evt):
    print "Changing material..."  
    mats = self.prj.get_all_materials()
    matl = list()
    for mat in mats:
      matl.append(mat['name'])

    dlg = wx.SingleChoiceDialog(self.frame, "Select material for the geometry", "Change Material", matl, wx.CHOICEDLG_STYLE)
    if dlg.ShowModal() == wx.ID_OK:
      None
    dlg.Destroy()

    ## dialog = GeometryChangeMaterialDialog(self.master, matl, "Change Material...")
    ## if not dialog.result:
    ##   return 
    ## self.clicked_node.setAttribute(consts.XML_ATTR_GEOMETRY_MATERIAL, dialog.result)
    ## self.show_tree()

  ###---------------------------
  ### geometry_edit_definition
  ###---------------------------
  def geometry_edit_definition(self, geometry):
    name = geometry.getAttribute(consts.XML_ATTR_NAME)
    go = self.geometries.get_name(name)
    print "** Editing geometry (%s): " %(name)

    go_type = go.get_class_type()
    if go_type == "GeometryObjectPatch":
      self.geometry_edit_patch(go)
    elif go_type == "GeometryObjectPolygon":
      self.geometry_edit_polygon(go)
    elif go_type == "GeometryObjectCircle":
      self.geometry_edit_circle(go)
    elif go_type == "GeometryObjectBox":
      self.geometry_edit_box(go)
    elif go_type == "GeometryObjectCylinder":
      self.geometry_edit_cylinder(go)



  ###---------------------
  ### geometry_redraw_all
  ###---------------------
  def geometry_redraw_all(self):
    # redraw geometry objects
    gobjects = self.prj.get_all_geometries()
    for gobject in gobjects:
      object_type = gobject[consts.XML_TAG_GEOMETRY]
      if object_type == consts.XML_TAG_PATCH:
        self.edit_patch(gobject)
      elif object_type == consts.XML_TAG_CUBE:
        self.edit_box(gobject)
      elif object_type == consts.XML_TAG_CYLINDER:
	self.edit_cylinder(gobject)
      elif object_type == consts.XML_TAG_CIRCLE:
	self.edit_circle(gobject)
      elif object_type == consts.XML_TAG_POLYGON2D:
	#print gobject
	self.edit_polygon(gobject)

    # redraw excitations
    excitations = self.prj.get_all_excitations()
    for excit in excitations:
      excit_type = excit[consts.XML_TAG_EXCITATION]
      if excit_type == consts.XML_TAG_VOLTAGE_PORT:
	#print "Adding voltage port!"
	self.geometry_scene.add_voltage_port(excit)
      else:
	print "** Warning! Unknown excitation type (" + excit_type + ")! Not considered."


  #############################################################################
  ### MATERIAL methods
  #############################################################################

  def material_edit(self, material = None):
    dialog = MaterialDialog(material)
    dialog.turn_on_unique_name_checking(self.materials.get_list_of_names())

    if dialog.ShowModal() == wx.ID_OK:
      dialog_result = dialog.get_data()
      if not material:
	material = Material()
	material.set_data_from_dialog(dialog_result)
	self.materials.add(material)

	self.prj.add_material(dialog_result)
      else:
	None	# XXX : implement replacing material (in future)

      self.refresh_with_new_material()
    dialog.Destroy()


  #############################################################################
  ### MATERIAL callbacks
  #############################################################################

  ###--------------------
  ### material_add
  ###--------------------
  def material_add(self, evt):
    self.material_edit()

  #############################################################################
  ### BOUNDARY callbacks
  #############################################################################

  ###--------------------
  ### boundary_add
  ###--------------------
  def boundary_add(self):
    dialog = BoundaryAddDialog(self.master, "Add Bondary...")
    if not dialog.result:
      return
    print "Adding boundary "
    self.prj.add_boundary(self.clicked_node, dialog.result)

    self.show_tree()
    self.geometry_scene.add_boundary(dialog.result) 

  #############################################################################
  ### SOLVER callbacks
  #############################################################################

  ###--------------------
  ### solver_setup
  ###--------------------
  def solver_setup(self, evt):
    solver_list = self.simulation.get_solver_setup()
    
    (freq_units, freq_verb) = self.get_freq_units()

    solver_list[1] = float(solver_list[1])/freq_units	# fmin in user units
    solver_list[2] = float(solver_list[2])/freq_units	# fmax in user units

    dialog = SolverSetupDialog(solver_list, freq_verb)
    if dialog.ShowModal() == wx.ID_OK:
      dialog_result = dialog.get_data()

      timesteps = int(dialog_result[0])
      fmin = float(dialog_result[1])*freq_units		# fmin in Hz
      fmax = float(dialog_result[2])*freq_units		# fmax in Hz
      #spatial_res = float(dialog_result[3])
      #bdist = int(dialog_result[4])

      if (fmin > fmax):
	dummy = fmin
	fmin = fmax
	fmax = dummy

      self.prj.set_signal_fmin_fmax('', fmin, fmax)
      self.prj.set_solver_number_of_time_steps('', timesteps)

      #self.simulation.set_spatial_resolution(spatial_res)
      #self.simulation.set_boundary_distance(bdist)
      self.simulation.set_solver_setup(dialog_result)
      self.simulation.set_fmin_fmax(fmin, fmax)
      self.simulation.update_results()

      self.refresh_all()

    dialog.Destroy()

  ###-----------------------
  ### solver_calculate_mesh
  ###-----------------------
  def solver_calculate_mesh(self, evt=None):
    print "Computing mesh..."
    dl = self.calculate_uniform_dl()

    # compute number of cells; TODO: this code is a quick hack for uniform mesh
    bbox = self.mesh.get_bbox()
    dx = bbox[1][0] - bbox[0][0]
    dy = bbox[1][1] - bbox[0][1]
    dz = bbox[1][2] - bbox[0][2]

    # FIXME: rounding here does not result always in an accurate result
    n_cells = int((dx/dl)*(dy/dl)*(dz/dl))	

    print " Number of cells: " + str(n_cells)
    print " dl: " + str(dl)
    print " nx = " + str(int(dx/dl))
    print " ny = " + str(int(dy/dl))
    print " nz = " + str(int(dz/dl))

    self.statusbar.SetStatusText("dl: " + str(dl), self.statbar_pos_dl)
    self.statusbar.SetStatusText("Number of cells: " + format_int_number(n_cells), self.statbar_pos_ncells)

    if (n_cells > consts.EMGINE_LARGE_NUMBER_OF_CELLS):
      dialog = wx.MessageDialog(self.frame, "Please be careful! Your number of cells is too LARGE : %s cells" %(format_int_number(n_cells)), "emGine limitation", wx.OK | wx.ICON_EXCLAMATION)
      dialog.ShowModal()
      dialog.Destroy()


  ###--------------------
  ### solver_simulate
  ###--------------------
  def solver_simulate(self, evt):
    #print self.geometries.bbox

    self.notebook1.SetSelection(2)		# Select Simulation LOG Page in Notebook
    self.log_device_simulation.clear()

    # show to the user the actual number of cells and dl
    self.solver_calculate_mesh()	# FIXME: computation of dl is done twice, once inside solver_calculate_mesh and once here (see code below); this can be optimized

    dl = self.calculate_uniform_dl()
    mesh = self.mesh
    prj_units = self.prj.get_units()
    units_length = prj_units[consts.XML_TAG_UNITS_LENGTH]
    mesh.set_dl(dl*units_length)

    self.prj.set_tlm_mesh(mesh, self.simulation.bdist)

    # Set number of ports
    # TODO: is the code below efficient ?
    number_of_ports = len(self.prj.get_all_excitations())
    if (number_of_ports > 2):
      # TODO: Show an error window
      #print "** Error! This version supports a maximum of two ports!\n";
      dialog = wx.MessageDialog(self.frame, "This version supports a maximum of two ports!", "emGine limitation", wx.OK | wx.ICON_EXCLAMATION)
      dialog.ShowModal()
      dialog.Destroy()
      return None

    self.simulation.set_number_of_ports(number_of_ports)

    # save the project before starting the simulation
    self.prj.save()                     # TODO: ask the user, if OK to save the file

    # Start the simulation
    sim_results = None
    ref_results = None

    if number_of_ports == 1:
      sim_results = self.simulation.simulate(self.prj.fname)

    elif number_of_ports == 2:          # FIXME: implement more sophisticated
                                        #        system to find out if deembedding is
					#        needed !
      print "Simulating 2-port structure with AUTOMATIC DEEMBEDDING!"
      self.reference_simulation.deembedding_turn_on()
      self.simulation.deembedding_turn_on()

      ####
      ## Reference simulation
      ####
      self.log_device_simulation.write("INFO: Running reference simulation.\n")

      # create reference mesh as a copy of the
      # original mesh with reduced bounding box
      mesh_ref = Mesh()
      simbox = mesh.get_bbox()
      mesh_ref.set_simbox(simbox)
      mesh_ref.set_dl(mesh.get_dl())
      mesh_ref.set_simbox_xmax(simbox[0][0] + dl * consts.EMGINE_DEEMBEDDING_CELLS) # use dl in units_length

      self.prj.set_tlm_mesh(mesh_ref, 0.0)
      self.prj.save()                     # TODO: ask the user, if OK to save the file
      ref_results_sim = self.reference_simulation.simulate(self.prj.fname)

      # show reference simulation progress dialog
      #pg_dlg = wx.ProgressDialog("Reference Simulation", "Reference simulation progress", maximum = 100, parent = self.frame, style = wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME | wx.PD_REMAINING_TIME | wx.PD_AUTO_HIDE) # | wx.PD_SMOOTH
      pg_dlg = wx.ProgressDialog("Reference Simulation", "Reference simulation progress", maximum = 100, parent = self.frame, style = wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME | wx.PD_REMAINING_TIME | wx.PD_AUTO_HIDE) # | wx.PD_SMOOTH
      pg_dlg.Update(0)

      simulation_running = True
      while simulation_running:
	# print self.log_device_simulation.progress
	# print "status1: ", self.log_device_simulation.status1
	wx.MilliSleep(200)

	pg_dlg.Update(self.log_device_simulation.progress)
	# cont_simulation = pg_dlg.Update(self.log_device_simulation.progress)
	# if not cont_simulation:
	#   simulation_running = False

	if self.log_device_simulation.status1 == consts.EMGINE_SIMULATION_FINISHED:
	  simulation_running = False

      # self.log_device_simulation.status1 = consts.EMGINE_SIMULATION_EXIT_THREAD # green light to exit thread
      pg_dlg.Destroy()

      # update reference results
      ref_results = self.reference_simulation.recalculate_results(ref_results_sim, is_reference = True) #results)

      self.log_device_simulation.write("\n")

      ####
      ## Actual simulation
      ####
      self.log_device_simulation.write("INFO: Running simulation of the complete structure.\n")
      self.prj.set_tlm_mesh(mesh, self.simulation.bdist)
      self.prj.save()                     
      sim_results = self.simulation.simulate(self.prj.fname)

    # show simulation progress dialog
    pg_dlg = wx.ProgressDialog("Simulation", "Simulation progress", maximum = 100, parent = self.frame, style = wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME | wx.PD_ESTIMATED_TIME | wx.PD_REMAINING_TIME)
    pg_dlg.Update(0)

    simulation_running = True
    while simulation_running:
      #print self.log_device_simulation.progress
      wx.Sleep(1)

      upd_val = pg_dlg.Update(self.log_device_simulation.progress)
      # wxPython 2.6 and 2.8 return different objects, bool and tuple, resp.
      if isinstance(upd_val, tuple):
	(cont_simulation, skip_) = upd_val
      else:
	cont_simulation = upd_val

      #print "cont_simulation: ", cont_simulation
      if not cont_simulation:
	simulation_running = False

	# send a terminate message to the simulation thread and wait to finish
	self.log_device_simulation.status1_lock.acquire()
	if self.log_device_simulation.status1 != consts.EMGINE_SIMULATION_FINISHED:
	  self.log_device_simulation.status1 = consts.EMGINE_SIMULATION_TERMINATE
	self.log_device_simulation.status1_lock.release()

	pg_dlg.Update(self.log_device_simulation.progress, "Terminating simulation, please wait...")
	while self.log_device_simulation.status1 != consts.EMGINE_SIMULATION_FINISHED:
	  # print "Waiting..."
	  # print self.log_device_simulation.status1
	  wx.MilliSleep(200)

      if self.log_device_simulation.status1 == consts.EMGINE_SIMULATION_FINISHED:
	simulation_running = False
	if (self.properties.simulation_dialog_keep_open):
	  pg_dlg.Update(100, "Simulation finished.")	# 100 % of simulation done

    #self.log_device_simulation.status1 = consts.EMGINE_SIMULATION_EXIT_THREAD # green light to exit thread
    pg_dlg.Destroy()

    # update results
    self.simulation.recalculate_results(sim_results, reference_results = ref_results)

    self.prj.update_results(self.simulation.results, ref_results)
    self.results = self.simulation.results
    self.ref_results = ref_results
    self.refresh_all()

  #############################################################################
  ### SIMULATION callbacks
  #############################################################################

  ###-------------------------------
  ### simulation_surrounding_space
  ###-------------------------------
  def simulation_surrounding_space(self, evt):
    dialog = SurroundingSpaceDialog(self.surrounding_space.get_simbox())
    dialog.set_materials(self.materials)
    dialog.set_material_list([consts.EMGINE_MATERIAL_FREE_SPACE])

    if dialog.ShowModal() == wx.ID_OK:
      dialog_result = dialog.get_data()
      xmin = float(dialog_result[0])
      xmax = float(dialog_result[1])
      ymin = float(dialog_result[2])
      ymax = float(dialog_result[3])
      zmin = float(dialog_result[4])
      zmax = float(dialog_result[5])

      self.surrounding_space.set_simbox([[xmin, ymin, zmin], [xmax, ymax, zmax]])

      self.mesh.set_simbox_xmin(xmin)
      self.mesh.set_simbox_xmax(xmax)
      self.mesh.set_simbox_ymin(ymin)
      self.mesh.set_simbox_ymax(ymax)
      self.mesh.set_simbox_zmin(zmin)
      self.mesh.set_simbox_zmax(zmax)
      self.prj.set_emgine_surrounding_space(self.mesh.simbox)
      self.prj.set_tlm_mesh(self.mesh, float(0))

      # redraw simulation boundary
      self.refresh_simulation_boundary_view()
    dialog.Destroy()

  ###---------------------------------
  ### simulation_boundary_conditions
  ###---------------------------------
  def simulation_boundary_conditions(self, evt):
    bcs = self.prj.get_boundary_conditions()
    dialog = BoundaryConditionsDialog(bcs)
    if dialog.ShowModal() == wx.ID_OK:
      res_raw = dialog.get_data()
      self.prj.set_boundary_conditions(res_raw)

      # refreshing
      self.refresh_title_bar()
      self.refresh_status_bar()
    dialog.Destroy()

  #############################################################################
  ### EXCITATION callbacks
  #############################################################################

  ###--------------------------
  ### excitation_voltage_port
  ###--------------------------
  def excitation_voltage_port(self, evt):
    dialog = ExcitationVoltagePortDialog()
    if dialog.ShowModal() == wx.ID_OK:
      print "Adding excitation port"
      dialog_result = dialog.get_data()
      self.prj.add_excitation_voltage_port(self.clicked_node, dialog_result)
      self.show_tree()
      self.geometry_scene.add_voltage_port(dialog_result)
    dialog.Destroy()

  ###-----------------------------
  ### excitation_plane_wave_port
  ###-----------------------------
  def excitation_plane_wave_port(self, evt):
    None

  #############################################################################
  ### HELP callbacks
  #############################################################################

  ###--------------------------
  ### help_about
  ###--------------------------
  def help_about(self, evt):
    #webbrowser.open("http://www.lorenz-solutions.com")
    dialog = emGineGUIAboutDialog(self.frame)
    dialog.ShowModal()
    dialog.Destroy()


  ###----------------------
  ### geometrym_disable_all
  ###----------------------
  def geometrym_disable_all(self, enabled = False):
    for id in [self.toolbar_patch_id, self.toolbar_circle_id, self.toolbar_polygon_id, self.toolbar_box_id, self.toolbar_cylinder_id]:
      self.toolbar.EnableTool(id, enabled)

    for id in [self.mnu_geometry_patch_id, self.mnu_geometry_circle_id, self.mnu_geometry_polygon_id, self.mnu_geometry_box_id, self.mnu_geometry_cylinder_id]:
      self.menu_bar.Enable(id, enabled)

    for id in [self.mnu_geometry_change_material_id]:
      #self.menu_bar.Enable(id, enabled)
      self.menu_bar.Enable(id, False)

  ###---------------------------
  ### geometrym_disable_default
  ###---------------------------
  def geometrym_disable_default(self, enabled = False):
    for id in [self.mnu_geometry_change_material_id]:
      self.menu_bar.Enable(id, enabled)

  ###----------------------
  ### geometrym_enable_all
  ###----------------------
  def geometrym_enable_all(self):
    self.geometrym_disable_all(True)

  ###------------------------
  ### transformm_disable_all
  ###------------------------
  def transformm_disable_all(self, enabled = False):
    for id in [self.mnu_transform_translate_id, self.mnu_transform_rotate_id, self.mnu_transform_scale_id]:
      self.menu_bar.Enable(id, enabled)

  ###------------------------
  ### transformm_enable_all
  ###------------------------
  def transformm_enable_all(self, enabled = False):
    self.transformm_disable_all(True)

  ###--------------------------
  ### excitationm_disable_all
  ###--------------------------
  def excitationm_disable_all(self):
    None
    ### self.excitationm.entryconfig(1, state = DISABLED)
    ##self.excitationm.entryconfig(3, state = DISABLED)

  ###--------------------------
  ### excitationm_enable_all
  ###--------------------------
  def excitationm_enable_all(self):
    None
    #self.excitationm.entryconfig(1, state = NORMAL)
    #self.excitationm.entryconfig(3, state = NORMAL)

  ###--------------------------
  ### resultsm_enable_all
  ###--------------------------
  def resultsm_enable_all(self):
    None
    ### self.filem.entryconfig(7, state = NORMAL)		# File->Export Data...

  ###--------------------------
  ### resultsm_disable_all
  ###--------------------------
  def resultsm_disable_all(self):
    None
    ### self.filem.entryconfig(7, state = DISABLED)		# File->Export Data...

  ###--------------------
  ### quit_app
  ###--------------------
  def quit_app(self, evt):
    quit = True
    if self.prj.modified():
      ret_dialog = self.project_not_saved_ask(evt)
      if ret_dialog == wx.ID_CANCEL:
	quit = False

    if quit:
      self.frame.Close(True)

  ###--------------------
  ### dummy
  ###--------------------
  def dummy(self, evt):
    print "Dummy Callback"

