text: # $Id: GenericDialog.py,v 1.4 2006/07/02 13:08:53 marcusva Exp $
  #
  # Copyright (c) 2004-2006, Marcus von Appen
  # All rights reserved.
  # Redistribution and use in source and binary forms, with or without
  # modification, are permitted provided that the following conditions are met:
  #
  #  * Redistributions of source code must retain the above copyright notice,
  #    this list of conditions and the following disclaimer.
  #  * Redistributions in binary form must reproduce the above copyright notice,
  #    this list of conditions and the following disclaimer in the documentation
  #    and/or other materials provided with the distribution.
  #
  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  # POSSIBILITY OF SUCH DAMAGE.
  
  """An universal dialog window class with additional buttons."""
  
  from DialogWindow import DialogWindow
  from Frame import VFrame, HFrame
  from Button import Button
  from Constants import *
  
  class GenericDialog (DialogWindow):
      """GenericDialog (title, buttons, results) -> GenericDialog
  
      A generic dialog window, which supports result values.
  
      The GenericDialog widget class is suitable to create dialog windows
      which need to check for certain dialog results in an easy
      way. Specific result values can be bound to the buttons of the
      dialog and will be emitted upon clicking the buttons.
  
      The creation of the GenericDialog is a bit different from other
      widgets. Besides the title, it receives two lists for the buttons to
      display and the results they have to send. Both lists need to have
      the same length.
  
      dialog = GenericDialog ('Test', [Button ('OK'), Button ('Cancel')],
                              [DLGRESULT_OK, DLGRESULT_CANCEL])
  
      The index of the result values need to match the index of the
      button, that should emit them. Of course the buttons can be changed
      at runtime programmatically with the set_buttons() method, which is
      similar to the constructor.
  
      dialog.set_buttons ([Button ('Close'), Button ('ClickMe')],
                          [DLGRESULT_CLOSE, DLGRESULT_USER])
  
      The result values to set must match a valid value from the
      DLGRESULT_TYPES tuple.
  
      Given the above set_buttons() example, a callback for the
      SIG_DIALOGRESPONSE signal will receive either the DLGRESULT_CLOSE or
      DLGRESULT_USER value upon which certain actions can take place.
  
      def dialog_callback (result, dialog):
          if result == DLGRESULT_CLOSE:
              dialog.destroy ()
          elif result == DLGRESULT_USER:
              ...
  
      mydialog.connect_signal (SIG_DIALOGRESPONSE, dialog_callback, mydialog)
      
      The GenericDialog is separated in several frames, to which user
      content can be added. The main frame, which holds anything else, can
      be accessed through the 'main' attribute. While it is possible to
      change most of its attributes without unwanted side effects, its
      children should not be modifed or deleted to prevent misbehaviour of
      the dialog.
  
      dialog.main.spacing = 10
      
      The second frame, which is usually the most interesting is the
      content frame, packed into the main frame. It can be accessed
      through the 'content' attribute and should (only) be used to add own
      widgets. Those can be deleted and modified, too.
  
      label = Label ('Label on the dialog')
      dialog.content.add_child (label)
      dialog.content.add_child (Button ('Button after label'))
      dialog.content.remove_child (label)
  
      Default action (invoked by activate()):
      See the DialogWindow class.
      
      Mnemonic action (invoked by activate_mnemonic()):
      See the DialogWindow class.
  
      Signals:
      SIG_DIALOGRESPONSE - Invoked, when an attached button is pressed.
      """
      def __init__ (self, title, buttons, results):
          DialogWindow.__init__ (self, title)
          
          # The main frame holds the whole content for the window.
          # The basic design idea of the dialog looks like:
          # +----------------------+
          # | Title caption        |
          # +----------------------+
          # | main frame           |
          # | ++++++++++++++++++++ |
          # | +                  + |
          # | +    with          + |
          # | +                  + |
          # | +   user content   + |
          # | +                  + |
          # | +------------------+ |
          # | +  Action frame    + |
          # | ++++++++++++++++++++ |
          # +----------------------+
          self.padding = 5
          
          self._mainframe = VFrame ()
          self._mainframe.border = BORDER_NONE
          self._mainframe.spacing = 5
          self._mainframe.padding = 0
  
          self._contentframe = VFrame ()
          self._contentframe.border = BORDER_NONE
          self._contentframe.spacing = 0
          self._contentframe.padding = 0
          self._mainframe.add_child (self._contentframe)
  
          # Buttons will be placed in the action frame.
          self._actionframe = HFrame ()
          self._actionframe.border = BORDER_NONE
          self._actionframe.padding = 0
          self._mainframe.add_child (self._actionframe)
  
          self.set_buttons (buttons, results)
  
          self._signals[SIG_DIALOGRESPONSE] = []
          self.set_child (self._mainframe)
  
      def set_buttons (self, buttons, results):
          """G.set_buttons (buttons. results) -> None
  
          Sets the buttons for the dialog and their wanted result values.
          """
          for widget in self._actionframe.children:
              widget.destroy ()
  
          for i in xrange (len (buttons)):
              if not isinstance (buttons[i], Button):
                  raise TypeError ("All elements in buttons must inherit "
                                   "from Button")
              if results[i] not in DLGRESULT_TYPES:
                  raise TypeError ("All elements in results must be values "
                                   "of DLGRESULT_TYPES")
              buttons[i].connect_signal (SIG_CLICKED, self._button_clicked,
                                         results[i])
              self._actionframe.add_child (buttons[i])
          self.dirty = True
  
      def _button_clicked (self, result):
          """G._button_clicked (...) -> None
  
          Callback for the buttons in the action frame.
  
          The _button_clicked method will run the SIG_DIALOGRESPONSE
          signal handlers with the passed result. 
          """
          self.run_signal_handlers (SIG_DIALOGRESPONSE, result)
  
      content = property (lambda self: self._contentframe,
                          doc = "The content frame to add widgets to.")
      main = property (lambda self: self._mainframe,
                       doc = "The main frame of the dialog.")
  