예제 #1
0
파일: dListBox.py 프로젝트: xfxf/dabo
class dListBox(dcm.dControlItemMixin, wx.ListBox):
    """Creates a listbox, allowing the user to choose one or more items."""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 *args,
                 **kwargs):
        self._baseClass = dListBox
        self._choices = []

        preClass = wx.PreListBox
        dcm.dControlItemMixin.__init__(self,
                                       preClass,
                                       parent,
                                       properties=properties,
                                       attProperties=attProperties,
                                       *args,
                                       **kwargs)

    def _initEvents(self):
        super(dListBox, self)._initEvents()
        self.Bind(wx.EVT_LISTBOX, self._onWxHit)

    def clearSelections(self):
        for elem in self.GetSelections():
            self.SetSelection(elem, False)

    def selectAll(self):
        if self.MultipleSelect:
            for ii in xrange(self.Count):
                self.SetSelection(ii)

    def unselectAll(self):
        self.clearSelections()

    def invertSelections(self):
        """Switch all the items from False to True, and vice-versa."""
        for ii in xrange(self.Count):
            if self.IsSelected(ii):
                self.Deselect(ii)
            else:
                self.SetSelection(ii)

    def _getMultipleSelect(self):
        return self._hasWindowStyleFlag(wx.LB_EXTENDED)

    def _setMultipleSelect(self, val):
        if bool(val):
            self._delWindowStyleFlag(wx.LB_SINGLE)
            self._addWindowStyleFlag(wx.LB_EXTENDED)
        else:
            self._delWindowStyleFlag(wx.LB_EXTENDED)
            self._addWindowStyleFlag(wx.LB_SINGLE)

    MultipleSelect = property(
        _getMultipleSelect, _setMultipleSelect, None,
        _("Can multiple items be selected at once?  (bool)"))

    DynamicMultipleSelect = makeDynamicProperty(MultipleSelect)
예제 #2
0
파일: alignmentMixin.py 프로젝트: xfxf/dabo
class AlignmentMixin(object):
    def _getAlignment(self):
        if self._hasWindowStyleFlag(wx.ALIGN_RIGHT):
            return "Right"
        elif self._hasWindowStyleFlag(wx.ALIGN_CENTRE):
            return "Center"
        else:
            return "Left"

    def _setAlignment(self, value):
        # Note: Alignment must be set before object created.
        self._delWindowStyleFlag(wx.ALIGN_LEFT)
        self._delWindowStyleFlag(wx.ALIGN_CENTRE)
        self._delWindowStyleFlag(wx.ALIGN_RIGHT)
        value = ustr(value).lower()

        if value == "left":
            self._addWindowStyleFlag(wx.ALIGN_LEFT)
        elif value == "center":
            self._addWindowStyleFlag(wx.ALIGN_CENTRE)
        elif value == "right":
            self._addWindowStyleFlag(wx.ALIGN_RIGHT)
        else:
            raise ValueError("The only possible values are "
                             "'Left', 'Center', and 'Right'.")

    Alignment = property(
        _getAlignment, _setAlignment, None,
        _("""Specifies the alignment of the text. (str)
			Left (default)
			Center
			Right"""))

    DynamicAlignment = makeDynamicProperty(Alignment)
예제 #3
0
class dPageFrameNoTabs(dPanel):
	"""
	Creates a pageframe with no tabs or other way for the user to select a
	page. Your code will have to programatically set the page.
	"""
	def __init__(self, *args, **kwargs):
		self._pageClass = dPage
		self._pageSizerClass = dabo.ui.dSizer
		self._activePage = None
		self._pages = []
		super(dPageFrameNoTabs, self).__init__(*args, **kwargs)
		self._baseClass = dPageFrameNoTabs


	def _afterInit(self):
		if self.Sizer is None:
			self.Sizer = dabo.ui.dSizer()
		super(dPageFrameNoTabs, self)._afterInit()


	def appendPage(self, pgCls=None, makeActive=False):
		"""
		Creates a new page, which should be a subclass of dPage. If makeActive
		is True, the page is displayed; otherwise, it is added without changing
		the SelectedPage.
		"""
		return self.insertPage(self.PageCount, pgCls=pgCls, makeActive=makeActive)


	def insertPage(self, pos, pgCls=None, makeActive=False, ignoreOverride=False):
		"""
		Inserts the page into the pageframe at the specified position,
		and makes it the active (displayed) page if makeActive is True.
		"""
		# Allow subclasses to potentially override this behavior. This will
		# enable them to handle page creation in their own way. If overridden,
		# the method will return the new page.
		ret = None
		if not ignoreOverride:
			ret = self._insertPageOverride(pos, pgCls, makeActive)
		if ret:
			return ret
		if pgCls is None:
			pgCls = self.PageClass
		if self.Sizer is None:
			self.Sizer = dabo.ui.dSizer()
		if isinstance(pgCls, dPage):
			pg = pgCls
		else:
			# See if the 'pgCls' is either some XML or the path of an XML file
			if isinstance(pgCls, basestring):
				xml = pgCls
				from dabo.lib.DesignerClassConverter import DesignerClassConverter
				conv = DesignerClassConverter()
				pgCls = conv.classFromText(xml)
			pg = pgCls(self)
		self.Sizer.insert(pos, pg, 1, "x")
		self._pages.insert(pos, pg)
		self.layout()
		if makeActive or (self.PageCount == 1):
			self.showPage(pg)
		else:
			self.showPage(self.SelectedPage)
		return self.Pages[pos]
	def _insertPageOverride(self, pos, pgCls, makeActive): pass


	def removePage(self, pgOrPos, delPage=True):
		"""
		Removes the specified page. You can specify a page by either
		passing the page itself, or a position. If delPage is True (default),
		the page is released, and None is returned. If delPage is
		False, the page is returned.
		"""
		if isinstance(pgOrPos, int):
			pg = self.Pages[pgOrPos]
		else:
			pg = pgOrPos
		self._pages.remove(pg)
		if delPage:
			pg.release()
			ret = None
		else:
			self.Sizer.remove(pg)
			ret = pg
		return ret


	def layout(self):
		"""Wrap the wx version of the call, if possible."""
		for pg in self.Pages:
			try:
				pg.layout()
			except AttributeError:
				# could be that the page is a single control, not a container
				pass
		super(dPageFrameNoTabs, self).layout()


	def showPage(self, pg):
		ap = self._activePage
		if isinstance(pg, int):
			pg = self.Pages[pg]
		newPage = (pg is not ap)
		if pg in self.Pages:
			if newPage:
				if ap:
					dabo.ui.callAfter(ap.raiseEvent, dEvents.PageLeave)
					apNum = self.getPageNumber(ap)
				else:
					apNum = -1
				dabo.ui.callAfter(pg.raiseEvent, dEvents.PageEnter)
				dabo.ui.callAfter(self.raiseEvent, dEvents.PageChanged,
						oldPageNum=apNum, newPageNum=self.getPageNumber(pg))
			self._activePage = pg
			for ch in self.Pages:
				self.Sizer.Show(ch, (ch is pg))
			self.layout()
			pg.setFocus()
		else:
			raise AttributeError(_("Attempt to show non-member page"))


	def nextPage(self):
		"""
		Selects the next page. If the last page is selected,
		it will select the first page.
		"""
		self.cyclePages(1)


	def priorPage(self):
		"""
		Selects the previous page. If the first page is selected,
		it will select the last page.
		"""
		self.cyclePages(-1)


	def cyclePages(self, num):
		"""
		Moves through the pages by the specified amount, wrapping
		around the ends. Negative values move to previous pages; positive
		move through the next pages.
		"""
		self.SelectedPageNumber = (self.SelectedPageNumber + num) % self.PageCount


	def getPageNumber(self, pg):
		"""Given a page, returns its position."""
		try:
			ret = self.Pages.index(pg)
		except ValueError:
			ret = None
		return ret


	#------------------------------------
	# The following methods don't do anything except
	# make this class compatible with dPage classes, which
	# expect their parent to have these methods.
	#------------------------------------
	def getPageImage(self, pg):
		return None


	def setPageImage(self, pg, img):
		pass


	def GetPageText(self, pg):
		return ""


	def SetPageText(self, pg, txt):
		pass


	#------------------------------------
	def _getPageClass(self):
		return self._pageClass

	def _setPageClass(self, val):
		if isinstance(val, basestring):
			from dabo.lib.DesignerClassConverter import DesignerClassConverter
			conv = DesignerClassConverter()
			self._pageClass = conv.classFromText(val)
		elif issubclass(val, (dPage, dPanel)):
			self._pageClass = val


	def _getPageCount(self):
		return len(self._pages)

	def _setPageCount(self, val):
		diff = (val - len(self._pages))
		if diff > 0:
			# Need to add pages
			while diff:
				self.appendPage()
				diff -= 1
		elif diff < 0:
			currPg = self.SelectedPageNumber
			pagesToKill = self._pages[val:]
			self._pages = self._pages[:val]
			# Need to add the check if the page exists since it
			# may have already been released.
			[pg.release() for pg in pagesToKill if pg]
			# Make sure the page we were on isn't one of the deleted pages.
			# If so, switch to the last page.
			newPg = min(currPg, val-1)
			self.SelectedPage = newPg


	def _getPages(self):
		return self._pages


	def _getPageSizerClass(self):
		return self._pageSizerClass

	def _setPageSizerClass(self, val):
		if self._constructed():
			self._pageSizerClass = val
		else:
			self._properties["PageSizerClass"] = val


	def _getSelectedPage(self):
		try:
			return self._activePage
		except AttributeError:
			return None

	def _setSelectedPage(self, pg):
		self.showPage(pg)


	def _getSelectedPageNumber(self):
		return self.getPageNumber(self._activePage)

	def _setSelectedPageNumber(self, val):
		pg = self.Pages[val]
		self.showPage(pg)


	PageClass = property(_getPageClass, _setPageClass, None,
			_("The default class used when adding new pages.  (dPage)") )

	PageCount = property(_getPageCount, _setPageCount, None,
			_("Returns the number of pages in this pageframe  (int)") )

	Pages = property(_getPages, None, None,
			_("List of all the pages.   (list)") )

	PageSizerClass = property(_getPageSizerClass, _setPageSizerClass, None,
			_("""Default sizer class for pages added automatically to this control. Set
			this to None to prevent sizers from being automatically added to child
			pages. (dSizer or None)"""))

	SelectedPage = property(_getSelectedPage, _setSelectedPage, None,
			_("Returns a reference to the currently displayed page  (dPage | dPanel)") )

	SelectedPageNumber = property(_getSelectedPageNumber, _setSelectedPageNumber, None,
			_("Returns a reference to the index of the currently displayed page  (int)") )


	DynamicPageClass = makeDynamicProperty(PageClass)
	DynamicPageCount = makeDynamicProperty(PageCount)
	DynamicSelectedPage = makeDynamicProperty(SelectedPage)
	DynamicSelectedPageNumber = makeDynamicProperty(SelectedPageNumber)
예제 #4
0
파일: dComboBox.py 프로젝트: xfxf/dabo
class dComboBox(dcm.dControlItemMixin, wx.ComboBox):
    """
	Creates a combobox, which combines a dropdown list with a textbox.

	The user can choose an item in the dropdown, or enter freeform text.
	"""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 *args,
                 **kwargs):
        self._baseClass = dComboBox
        self._choices = []
        self._userVal = False
        # Used to force the case of entered text
        self._forceCase = None
        self._inForceCase = False
        self._textLength = None
        # Flag for appending items when the user presses 'Enter'
        self._appendOnEnter = False
        # Holds the text to be appended
        self._textToAppend = ""

        preClass = wx.PreComboBox
        dcm.dControlItemMixin.__init__(self,
                                       preClass,
                                       parent,
                                       properties=properties,
                                       attProperties=attProperties,
                                       *args,
                                       **kwargs)

    def _preInitUI(self, kwargs):
        style = kwargs.get("style", 0)
        style |= wx.PROCESS_ENTER
        kwargs["style"] = style
        return kwargs

    def _initEvents(self):
        super(dComboBox, self)._initEvents()
        self.Bind(wx.EVT_COMBOBOX, self.__onComboBox)
        # 		self.Bind(wx.EVT_TEXT_ENTER, self.__onTextBox)
        self.Bind(wx.EVT_KEY_DOWN, self.__onWxKeyDown)

    def __onComboBox(self, evt):
        self._userVal = False
        evt.Skip()
        self._onWxHit(evt)

    def __onWxKeyDown(self, evt):
        """
		We need to capture the Enter/Return key in order to implement
		the AppendOnEnter behavior. However, under Windows this leads to
		navigation issues, so we also need to capture when Tab is pressed,
		and handle the navigation ourselves.
		"""
        # Shorthand for easy reference
        dk = dabo.ui.dKeys
        # Don't call the native Skip() if Tab is pressed; we'll handle it ourselves.
        callSkip = True
        enter_codes = (dk.key_Return, dk.key_Numpad_enter)
        keyCode = evt.GetKeyCode()
        if keyCode in enter_codes:
            self._userVal = True
            if self.AppendOnEnter:
                txt = self.GetValue()
                if txt not in self.Choices:
                    self._textToAppend = txt
                    if self.beforeAppendOnEnter() is not False:
                        if self._textToAppend:
                            self.appendItem(self._textToAppend, select=True)
                            self.afterAppendOnEnter()
            self.raiseEvent(dEvents.Hit, evt)
        elif keyCode == dk.key_Tab:
            forward = not evt.ShiftDown()
            self.Navigate(forward)
            callSkip = False
        if callSkip:
            evt.Skip()

    def __onKeyChar(self, evt):
        """This handles KeyChar events when ForceCase is set to a non-empty value."""
        if not self:
            # The control is being destroyed
            return
        keyCode = evt.keyCode
        if keyCode >= dKeys.key_Space:
            dabo.ui.callAfter(self._checkForceCase)
            dabo.ui.callAfter(self._checkTextLength)

    def _checkTextLength(self):
        """
		If the TextLength property is set, checks the current value of the control
		and truncates it if too long
		"""
        if not self:
            # The control is being destroyed
            return
        if not isinstance(self.GetValue(), basestring):
            #Don't bother if it isn't a string type
            return
        length = self.TextLength
        if not length:
            return
        val = self.GetValue()
        if len(val) > length:
            dabo.ui.beep()
            ip = self.GetInsertionPoint()
            self.SetValue(val[:length])
            self.SetInsertionPoint(ip)

    def _checkForceCase(self):
        """
		If the ForceCase property is set, casts the current value of the control
		to the specified case.
		"""
        if not self:
            # The control is being destroyed
            return
        if not isinstance(self.GetValue(), basestring):
            # Don't bother if it isn't a string type
            return
        case = self.ForceCase
        if not case:
            return
        ip = self.GetInsertionPoint()
        if case == "upper":
            self.SetValue(self.GetValue().upper())
        elif case == "lower":
            self.SetValue(self.GetValue().lower())
        elif case == "title":
            self.SetValue(self.GetValue().title())
        self.SetInsertionPoint(ip)

    def beforeAppendOnEnter(self):
        """
		Hook method that is called when user-defined text is entered
		into the combo box and Enter is pressed (when self.AppendOnEnter
		is True). This gives the programmer the ability to interact with such
		events, and optionally prevent them from happening. Returning
		False will prevent the append from happening.

		The text value to be appended is stored in self._textToAppend. You
		may modify this value (e.g., force to upper case), or delete it entirely
		(e.g., filter out obscenities and such). If you set self._textToAppend
		to an empty string, nothing will be appended. So this 'before' hook
		gives you two opportunities to prevent the append: return a non-
		empty value, or clear out self._textToAppend.
		"""
        pass

    def afterAppendOnEnter(self):
        """
		Hook method that provides a means to interact with the newly-
		changed list of items after a new item has been added by the user
		pressing Enter, but before control returns to the program.
		"""
        pass

    # Property get/set/del methods follow. Scroll to bottom to see the property
    # definitions themselves.
    def _getAppendOnEnter(self):
        return self._appendOnEnter

    def _setAppendOnEnter(self, val):
        if self._constructed():
            self._appendOnEnter = val
        else:
            self._properties["AppendOnEnter"] = val

    def _getForceCase(self):
        return self._forceCase

    def _setForceCase(self, val):
        if self._constructed():
            if val is None:
                valKey = None
            else:
                valKey = val[0].upper()
            self._forceCase = {
                "U": "upper",
                "L": "lower",
                "T": "title",
                None: None,
                "None": None
            }.get(valKey)
            self._checkForceCase()
            self.unbindEvent(dEvents.KeyChar, self.__onKeyChar)
            if self._forceCase or self._textLength:
                self.bindEvent(dEvents.KeyChar, self.__onKeyChar)
        else:
            self._properties["ForceCase"] = val

    def _getTextLength(self):
        return self._textLength

    def _setTextLength(self, val):
        if self._constructed():
            if val == None:
                self._textLength = None
            else:
                val = int(val)
                if val < 1:
                    raise ValueError('TextLength must be a positve Integer')
                self._textLength = val
            self._checkTextLength()

            self.unbindEvent(dEvents.KeyChar, self.__onKeyChar)
            if self._forceCase or self._textLength:
                self.bindEvent(dEvents.KeyChar, self.__onKeyChar)
        else:
            self._properties["TextLength"] = val

    def _getUserValue(self):
        if self._userVal:
            return self.GetValue()
        else:
            return self.GetStringSelection()

    def _setUserValue(self, value):
        if self._constructed():
            self.SetValue(value)
            # don't call _afterValueChanged(), because value tracks the item in the list,
            # not the displayed value. User code can query UserValue and then decide to
            # add it to the list, if appropriate.
        else:
            self._properties["UserValue"] = value

    AppendOnEnter = property(
        _getAppendOnEnter, _setAppendOnEnter, None,
        _("""Flag to determine if user-entered text is appended when they
			press 'Enter'  (bool)"""))

    ForceCase = property(
        _getForceCase, _setForceCase, None,
        _("""Determines if we change the case of entered text. Possible values are:

				============ =====================
				None or ""   No changes made (default)
				"Upper"      FORCE TO UPPER CASE
				"Lower"      Force to lower case
				"Title"      Force To Title Case
				============ =====================

			These can be abbreviated to "u", "l" or "t"  (str)"""))

    TextLength = property(
        _getTextLength, _setTextLength, None,
        _("""The maximum length the entered text can be. (int)"""))

    UserValue = property(
        _getUserValue, _setUserValue, None,
        _("""Specifies the text displayed in the textbox portion of the ComboBox.

			String. Read-write at runtime.

			UserValue can differ from StringValue, which would mean that the user
			has typed in arbitrary text. Unlike StringValue, PositionValue, and
			KeyValue, setting UserValue does not change the currently selected item
			in the list portion of the ComboBox."""))

    DynamicUserValue = makeDynamicProperty(UserValue)
예제 #5
0
파일: dGauge.py 프로젝트: xfxf/dabo
class dGauge(cm.dControlMixin, wx.Gauge):
    """Creates a gauge, which can be used as a progress bar."""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 *args,
                 **kwargs):
        self._baseClass = dGauge
        preClass = wx.PreGauge
        cm.dControlMixin.__init__(self,
                                  preClass,
                                  parent,
                                  properties=properties,
                                  attProperties=attProperties,
                                  *args,
                                  **kwargs)

    def _initEvents(self):
        super(dGauge, self)._initEvents()

    # Property get/set/del methods follow. Scroll to bottom to see the property
    # definitions themselves.
    def _getPercentage(self):
        return round(100 * (float(self.Value) / self.Range), 2)

    def _setPercentage(self, val):
        if self._constructed():
            self.Value = round(self.Range * (val / 100.0))
        else:
            self._properties["Percentage"] = val

    def _getOrientation(self):
        if self.IsVertical():
            return "Vertical"
        else:
            return "Horizontal"

    def _setOrientation(self, value):
        self._delWindowStyleFlag(wx.GA_HORIZONTAL)
        self._delWindowStyleFlag(wx.GA_VERTICAL)
        if value.lower()[:1] == "h":
            self._addWindowStyleFlag(wx.GA_HORIZONTAL)
        else:
            self._addWindowStyleFlag(wx.GA_VERTICAL)

    def _getRange(self):
        return self.GetRange()

    def _setRange(self, value):
        if self._constructed():
            self.SetRange(value)
        else:
            self._properties["Range"] = value

    def _getValue(self):
        return self.GetValue()

    def _setValue(self, value):
        if self._constructed():
            self.SetValue(value)
        else:
            self._properties["Value"] = value

    # Property definitions:
    Percentage = property(
        _getPercentage, _setPercentage, None,
        _("""Alternate way of setting/getting the Value, using percentage
			of the Range.  (float)"""))

    Orientation = property(
        _getOrientation, _setOrientation, None,
        _("Specifies whether the gauge is displayed as Horizontal or Vertical.  (str)"
          ))

    Range = property(_getRange, _setRange, None,
                     _("Specifies the maximum value for the gauge.  (int)"))

    Value = property(
        _getValue, _setValue, None,
        _("Specifies the state of the gauge, relative to max value."))

    DynamicOrientation = makeDynamicProperty(Orientation)
    DynamicRange = makeDynamicProperty(Range)
    DynamicValue = makeDynamicProperty(Value)
예제 #6
0
class dDialog(fm.dFormMixin, wx.Dialog):
    """
	Creates a dialog, which is a lightweight form.

	Dialogs are like forms, but typically are modal and are requesting a very
	specific piece of information from the user, and/or offering specific
	information to the user.
	"""
    def __init__(self, parent=None, properties=None, *args, **kwargs):
        self._baseClass = dDialog
        self._modal = True
        self._centered = True
        self._fit = True
        self._borderless = self._extractKey((properties, kwargs), "Borderless",
                                            False)

        if self._borderless:
            defaultStyle = wx.STAY_ON_TOP
        else:
            defaultStyle = wx.DEFAULT_DIALOG_STYLE
        try:
            kwargs["style"] = kwargs["style"] | defaultStyle
        except KeyError:
            kwargs["style"] = defaultStyle

        preClass = wx.PreDialog
        fm.dFormMixin.__init__(self,
                               preClass,
                               parent,
                               properties=properties,
                               *args,
                               **kwargs)

        # Hook method, so that we add the buttons last
        self._addControls()

        # Needed starting with wx 2.7, for the first control to have the focus:
        self.setFocus()

    def getBizobj(self, *args, **kwargs):
        ## self.Form resolves to the containing dialog, making calls to 'self.Form.getBizobj()'
        ## fail since the dialog knows nothing about bizobjs. Let's be helpful and pass the
        ## request up to the form:
        return self.Form.getBizobj(*args, **kwargs)

    def EndModal(self, *args, **kwargs):
        self.saveSizeAndPosition()
        self.hide()
        if self.Modal:
            try:
                super(dDialog, self).EndModal(*args, **kwargs)
            except wx._core.PyAssertionError:
                # The modal hack is causing problems in some edge cases.
                pass

    def _afterInit(self):
        self.MenuBarClass = None
        self.Sizer = dabo.ui.dSizer("V")
        super(dDialog, self)._afterInit()

    def ShowModal(self):
        self.restoreSizeAndPositionIfNeeded()
        # updates were potentially suppressed while the dialog
        # wasn't visible, so update now.
        self.update()
        return super(dDialog, self).ShowModal()

    def showModal(self):
        """Show the dialog modally."""
        ## pkm: We had to override this, because the default in dPemMixin doesn't
        ##      actually result in a modal dialog.
        self.Modal = True
        self.show()

    def showModeless(self):
        """Show the dialog non-modally."""
        self.Modal = False
        self.show()

    def _afterShow(self):
        if self.AutoSize:
            self.Fit()
        if self.Centered:
            self.Centre()

    def show(self):
        # Call _afterShow() once immediately, and then once after the dialog is visible, which
        # will correct minor mistakes such as the height of wordwrapped labels not being
        # accounted for. If we only called it after the dialog was already shown, then we
        # risk the dialog being too jumpy.
        self._afterShow()
        dabo.ui.callAfter(self._afterShow)
        if self.Modal:
            ret = self.ShowModal()
            return {
                wx.ID_OK: kons.DLG_OK,
                wx.ID_CANCEL: kons.DLG_CANCEL
            }.get(ret, ret)
        return self.Show(True)

    def _addControls(self):
        """
		Any controls that need to be added to the dialog
		can be added in this method in framework classes, or
		in addControls() in instances.
		"""
        self.beforeAddControls()
        self.addControls()
        self.afterAddControls()

    def beforeAddControls(self):
        """This is a hook, called at the appropriate time by the framework."""
        pass

    def afterAddControls(self):
        """This is a hook, called at the appropriate time by the framework."""
        pass

    def addControls(self):
        """
		Add your custom controls to the dialog.

		This is a hook, called at the appropriate time by the framework.
		"""
        pass

    def release(self):
        """
		Need to augment this to make sure the dialog
		is removed from the app's forms collection.
		"""
        if self.Application is not None:
            self.Application.uiForms.remove(self)
        super(dDialog, self).release()

    def _controlGotFocus(self, ctrl):
        # Placeholder until we unify dForm and dDialog
        pass

    def _getAutoSize(self):
        return self._fit

    def _setAutoSize(self, val):
        self._fit = val

    def _getBorderless(self):
        return self._borderless

    def _setBorderless(self, val):
        if self._constructed():
            raise ValueError(
                _("Cannot set the Borderless property once the dialog is created."
                  ))
        else:
            self._properties["Borderless"] = val

    def _getCaption(self):
        return self.GetTitle()

    def _setCaption(self, val):
        if self._constructed():
            self.SetTitle(val)
        else:
            self._properties["Caption"] = val

    def _getCentered(self):
        return self._centered

    def _setCentered(self, val):
        self._centered = val

    def _getModal(self):
        return self._modal

    def _setModal(self, val):
        self._modal = val

    def _getShowStat(self):
        # Dialogs cannot have status bars.
        return False

    _showStatusBar = property(_getShowStat)

    AutoSize = property(
        _getAutoSize, _setAutoSize, None,
        _("When True, the dialog resizes to fit the added controls.  (bool)"))

    Borderless = property(
        _getBorderless, _setBorderless, None,
        _("""Must be passed at construction time. When set to True, the dialog displays
			without a title bar or borders  (bool)"""))

    Caption = property(
        _getCaption, _setCaption, None,
        _("The text that appears in the dialog's title bar  (str)"))

    Centered = property(
        _getCentered, _setCentered, None,
        _("Determines if the dialog is displayed centered on the screen.  (bool)"
          ))

    Modal = property(
        _getModal, _setModal, None,
        _("Determines if the dialog is shown modal (default) or modeless.  (bool)"
          ))

    DynamicAutoSize = makeDynamicProperty(AutoSize)
    DynamicCaption = makeDynamicProperty(Caption)
    DynamicCentered = makeDynamicProperty(Centered)
예제 #7
0
파일: dDockForm.py 프로젝트: xfxf/dabo
class dDockPanel(dabo.ui.dPanel):
	def __init__(self, parent, properties=None, attProperties=None, *args, **kwargs):
		nmU = self._extractKey((properties, kwargs), "Name", "")
		nb = self._extractKey((properties, kwargs), "NameBase", "")
		nmL = self._extractKey((properties, kwargs), "name", "")
		kwargs["NameBase"] = [txt for txt in (nmU, nb, nmL, "dDockPanel") if txt][0]
		pcapUp = self._extractKey(kwargs, "Caption", "")
		pcap = self._extractKey(kwargs, "caption", "")
		ptype = self._extractKey(kwargs, "typ", "")
		if pcapUp:
			kwargs["Caption"] = pcapUp
		else:
			kwargs["Caption"] = pcap
		self._paramType = ptype
		self._toolbar = self._extractKey(kwargs, "Toolbar", False)

		# Initialize attributes that underly properties
		self._bottomDockable = True
		self._leftDockable = True
		self._rightDockable = True
		self._topDockable = True
		self._floatable = True
		self._floatingPosition = (0, 0)
		self._floatingSize = (100, 100)
		self._gripperPosition = "Left"
		self._destroyOnClose = False
		self._movable = True
		self._resizable = True
		self._showBorder = True
		self._showCaption = True
		self._showCloseButton = True
		self._showGripper = False
		self._showMaximizeButton = False
		self._showMinimizeButton = False
		self._showPinButton = True
		super(dDockPanel, self).__init__(parent, properties=properties,
				attProperties=attProperties, *args, **kwargs)
		if self.Floating:
			self._floatingPosition = self.GetParent().GetPosition().Get()
			self._floatingSize = self.GetParent().GetSize().Get()


	def _uniqueNameForParent(self, name, parent=None):
		"""
		We need to check the AUI manager's PaneInfo name value, too, as that has to be unique
		there as well as the form.
		"""
		changed = True
		try:
			mgr = parent._mgr
		except AttributeError:
			mgr = self._Manager
		while changed:
			i = 0
			auiOK = False
			while not auiOK:
				auiOK = True
				candidate = name
				if i:
					candidate = "%s%s" % (name, i)
				mtch = [pi.name for pi in mgr.GetAllPanes()
						if pi.name == candidate]
				if mtch:
					auiOK = False
					i += 1
			changed = changed and (candidate != name)
			name = candidate

			candidate = super(dDockPanel, self)._uniqueNameForParent(name, parent)
			changed = changed and (candidate != name)
			name = candidate
		return name


	def float(self):
		"""Float the panel if it isn't already floating."""
		if self.Floating or not self.Floatable:
			return
		self._PaneInfo.Float()
		self._updateAUI()


	def dock(self, side=None):
		"""
		Dock the panel. If side is specified, it is docked on that side of the
		form. If no side is specified, it is docked in its default location.
		"""
		if self.Docked or not self.Dockable:
			return
		inf = self._PaneInfo
		if side is not None:
			s = side[0].lower()
			func = {"l": inf.Left, "r": inf.Right, "t": inf.Top, "b": inf.Bottom}.get(s, None)
			if func:
				func()
			else:
				dabo.log.error(_("Invalid dock position: '%s'.") % side)
		inf.Dock()
		self._updateAUI()


	def _beforeSetProperties(self, props):
		"""
		Some properties of Floating panels cannot be set at the usual
		point in the process, since the panel will still be docked, and you
		can't change dimensions/location of a docked panel. So extract
		them now, and then set them afterwards.
		"""
		self._propDelayDict = {}
		props2Delay = ("Bottom", "BottomDockable", "Caption", "DestroyOnClose", "Dockable", "Docked",
				"DockSide", "Floatable", "Floating", "FloatingBottom", "FloatingHeight", "FloatingLeft",
				"FloatingPosition", "FloatingRight", "FloatingSize", "FloatingTop", "FloatingWidth", "GripperPosition",
				"Height", "Left", "LeftDockable", "Movable", "Resizable", "Right", "RightDockable", "ShowBorder",
				"ShowCaption", "ShowCloseButton", "ShowGripper", "ShowMaximizeButton", "ShowMinimizeButton",
				"ShowPinButton", "Top", "TopDockable", "Visible", "Width")
		for delayed in props2Delay:
			val = self._extractKey(props, delayed, None)
			if val is not None:
				self._propDelayDict[delayed] = val
		return super(dDockPanel, self)._beforeSetProperties(props)


	def _afterSetProperties(self):
		nm = self.Name
		frm = self.Form
		self._Manager.addPane(self, name=nm,
				typ=self._paramType, caption=self._propDelayDict.get("Caption", "dDockPanel"))
		del self._paramType
		self._PaneInfo.MinSize((50,50))
		if self._propDelayDict:
			self.setProperties(self._propDelayDict)
		del self._propDelayDict


	def getState(self):
		"""Returns the local name and a string that can be used to restore the state of this pane."""
		inf = self._Manager.SavePaneInfo(self._PaneInfo)
		try:
			infPairs = (qq.split("=") for qq in inf.split(";"))
			nm = dict(infPairs)["name"]
		except KeyError:
			# For some reason a name was not returned
			return ""
		return (nm, inf.replace("name=%s;" % nm, ""))


	def _updateAUI(self):
		frm = self.Form
		if frm is not None:
			frm._refreshState()
		else:
			try:
				self._Manager.runUpdate()
			except AttributeError:
				pass


	def __getPosition(self):
		if self.Floating:
			obj = self.GetParent()
		else:
			obj = self
		return obj.GetPosition().Get()


	def __getSize(self):
		if self.Floating:
			obj = self.GetParent()
		else:
			obj = self
		return obj.GetSize().Get()


	# Property get/set/del methods follow. Scroll to bottom to see the property
	# definitions themselves.
	def _getBottom(self):
		return self.__getPosition()[1] + self.__getSize()[1]

	def _setBottom(self, val):
		if self._constructed():
			if self.Floating:
				self.FloatingBottom = val
			else:
				dabo.log.error(_("Cannot set the position of a docked panel"))
		else:
			self._properties["Bottom"] = val


	def _getBottomDockable(self):
		return self._bottomDockable

	def _setBottomDockable(self, val):
		if self._constructed():
			self._PaneInfo.BottomDockable(val)
			self._updateAUI()
		else:
			self._properties["BottomDockable"] = val

	def _getCaption(self):
		try:
			return self._caption
		except AttributeError:
			self._caption = ""
			return self._caption

	def _setCaption(self, val):
		if self._constructed():
			self._caption = val
			self._PaneInfo.Caption(val)
			self._updateAUI()
		else:
			self._properties["Caption"] = val


	def _getDestroyOnClose(self):
		return self._destroyOnClose

	def _setDestroyOnClose(self, val):
		if self._constructed():
			self._destroyOnClose = val
			self._PaneInfo.DestroyOnClose(val)
			self._updateAUI()
		else:
			self._properties["DestroyOnClose"] = val


	def _getDockable(self):
		return self._bottomDockable or self._leftDockable or self._rightDockable or self._topDockable

	def _setDockable(self, val):
		if self._constructed():
			self._dockable = self._bottomDockable = self._leftDockable = self._rightDockable = self._topDockable = val
			self._PaneInfo.Dockable(val)
			if self.Docked:
				self.Docked = val
			self._updateAUI()
		else:
			self._properties["Dockable"] = val


	def _getDocked(self):
		return self._PaneInfo.IsDocked()

	def _setDocked(self, val):
		if self._constructed():
			curr = self._PaneInfo.IsDocked()
			chg = False
			if val and not curr:
				self._PaneInfo.Dock()
				chg = True
			elif not val and curr:
				self._PaneInfo.Float()
				chg = True
			if chg:
				self._updateAUI()
		else:
			self._properties["Docked"] = val


	def _getDockSide(self):
		return {1: "Top", 2: "Right", 3: "Bottom", 4: "Left"}[self._PaneInfo.dock_direction]

	def _setDockSide(self, val):
		if self._constructed():
			vUp = val[0].upper()
			self._PaneInfo.dock_direction = {"T": 1, "R": 2, "B": 3, "L": 4}[vUp]
			self._updateAUI()
		else:
			self._properties["DockSide"] = val


	def _getFloatable(self):
		return self._floatable

	def _setFloatable(self, val):
		if self._constructed():
			self._floatable = val
			self._PaneInfo.Floatable(val)
			self._updateAUI()
		else:
			self._properties["Floatable"] = val


	def _getFloating(self):
		return self._PaneInfo.IsFloating()

	def _setFloating(self, val):
		if self._constructed():
			curr = self._PaneInfo.IsFloating()
			chg = False
			if val and not curr:
				self._PaneInfo.Float()
				chg = True
			elif not val and curr:
				self._PaneInfo.Dock()
				chg = True
			if chg:
				self._updateAUI()
		else:
			self._properties["Floating"] = val


	def _getFloatingBottom(self):
		return self.FloatingPosition[1] + self.FloatingSize[1]

	def _setFloatingBottom(self, val):
		if self._constructed():
			ht = self.FloatingSize[1]
			self._floatingPosition = (self.FloatingPosition[0], val - ht)
			self._PaneInfo.FloatingPosition(self._floatingPosition)
			self.Form._refreshState(0)
		else:
			self._properties["FloatingBottom"] = val


	def _getFloatingHeight(self):
		return self.FloatingSize[1]

	def _setFloatingHeight(self, val):
		if self._constructed():
			self._floatingSize = (self.FloatingSize[0], val)
			if self._PaneInfo.IsFloating():
				self.GetParent().SetSize(self._floatingSize)
			else:
				self._PaneInfo.FloatingSize(self._floatingSize)
			self.Form._refreshState(0)
		else:
			self._properties["FloatingHeight"] = val


	def _getFloatingLeft(self):
		return self.FloatingPosition[0]

	def _setFloatingLeft(self, val):
		if self._constructed():
			self._floatingPosition = (val, self.FloatingPosition[1])
			self._PaneInfo.FloatingPosition(self._floatingPosition)
			self.Form._refreshState(0)
		else:
			self._properties["FloatingLeft"] = val


	def _getFloatingPosition(self):
		return self._PaneInfo.floating_pos.Get()

	def _setFloatingPosition(self, val):
		if self._constructed():
			self._PaneInfo.FloatingPosition(val)
			self.Form._refreshState(0)
		else:
			self._properties["FloatingPosition"] = val


	def _getFloatingRight(self):
		return self.FloatingPosition[0] + self.FloatingSize[0]

	def _setFloatingRight(self, val):
		if self._constructed():
			wd = self.FloatingSize[0]
			self._floatingPosition = (val - wd, self.FloatingPosition[1])
			self._PaneInfo.FloatingPosition(self._floatingPosition)
			self.Form._refreshState(0)
		else:
			self._properties["FloatingRight"] = val


	def _getFloatingSize(self):
		return self._PaneInfo.floating_size.Get()

	def _setFloatingSize(self, val):
		if self._constructed():
			self._PaneInfo.FloatingSize(val)
			self.Form._refreshState(0)
		else:
			self._properties["FloatingSize"] = val


	def _getFloatingTop(self):
		return self.FloatingPosition[1]

	def _setFloatingTop(self, val):
		if self._constructed():
			self._floatingPosition = (self.FloatingPosition[0], val)
			self._PaneInfo.FloatingPosition(self._floatingPosition)
			self.Form._refreshState(0)
		else:
			self._properties["FloatingTop"] = val


	def _getFloatingWidth(self):
		return self.FloatingSize[0]

	def _setFloatingWidth(self, val):
		if self._constructed():
			self._floatingSize = (val, self.FloatingSize[1])
			if self._PaneInfo.IsFloating():
				self.GetParent().SetSize(self._floatingSize)
			else:
				self._PaneInfo.FloatingSize(self._floatingSize)
			self.Form._refreshState(0)
		else:
			self._properties["FloatingWidth"] = val


	def _getGripperPosition(self):
		return self._gripperPosition

	def _setGripperPosition(self, val):
		if self._constructed():
			val = val[0].lower()
			if not val in ("l", "t"):
				raise ValueError(_("Only valid GripperPosition values are 'Top' or 'Left'."))
			self._gripperPosition = {"l": "Left", "t": "Top"}[val]
			self._PaneInfo.GripperTop(val == "t")
			self._updateAUI()
		else:
			self._properties["GripperPosition"] = val


	def _getHeight(self):
		return self.__getSize()[1]

	def _setHeight(self, val):
		if self._constructed():
			if self.Floating:
				self.FloatingHeight = val
			else:
				dabo.log.error(_("Cannot set the Size of a docked panel"))
		else:
			self._properties["Height"] = val


	def _getLeft(self):
		return self.__getPosition()[0]

	def _setLeft(self, val):
		if self._constructed():
			if self.Floating:
				self.FloatingLeft = val
			else:
				dabo.log.error(_("Cannot set the position of a docked panel"))
		else:
			self._properties["Left"] = val


	def _getLeftDockable(self):
		return self._leftDockable

	def _setLeftDockable(self, val):
		if self._constructed():
			self._PaneInfo.LeftDockable(val)
			self._updateAUI()
		else:
			self._properties["LeftDockable"] = val


	def _getManager(self):
		try:
			mgr = self._mgr
		except AttributeError:
			mgr = self._mgr = self.Form._mgr
		return mgr


	def _getMovable(self):
		return self._movable

	def _setMovable(self, val):
		if self._constructed():
			self._movable = val
			self._PaneInfo.Movable(val)
			self._updateAUI()
		else:
			self._properties["Movable"] = val


	def _getPaneInfo(self):
		try:
			mgr = self._mgr
		except AttributeError:
			mgr = self._mgr = self.Form._mgr
		return mgr.GetPane(self)


	def _getResizable(self):
		return self._resizable

	def _setResizable(self, val):
		if self._constructed():
			self._resizable = val
			self._PaneInfo.Resizable(val)
			self._updateAUI()
		else:
			self._properties["Resizable"] = val


	def _getRight(self):
		return self.__getPosition()[0] + self.__getSize()[0]

	def _setRight(self, val):
		if self._constructed():
			if self.Floating:
				self.FloatingRight = val
			else:
				dabo.log.error(_("Cannot set the position of a docked panel"))
		else:
			self._properties["Right"] = val


	def _getRightDockable(self):
		return self._rightDockable

	def _setRightDockable(self, val):
		if self._constructed():
			self._PaneInfo.RightDockable(val)
			self._updateAUI()
		else:
			self._properties["RightDockable"] = val


	def _getShowBorder(self):
		return self._showBorder

	def _setShowBorder(self, val):
		if self._constructed():
			self._showBorder = val
			self._PaneInfo.PaneBorder(val)
			self._updateAUI()
		else:
			self._properties["ShowBorder"] = val


	def _getShowCaption(self):
		return self._showCaption

	def _setShowCaption(self, val):
		if self._constructed():
			self._showCaption = val
			self._PaneInfo.CaptionVisible(val)
			self._updateAUI()
		else:
			self._properties["ShowCaption"] = val


	def _getShowCloseButton(self):
		return self._showCloseButton

	def _setShowCloseButton(self, val):
		if self._constructed():
			self._showCloseButton = val
			self._PaneInfo.CloseButton(val)
			self.Form._refreshState(0)
			self.Form.lockDisplay()
			self.Docked = not self.Docked
			dabo.ui.setAfterInterval(100, self, "Docked", not self.Docked)
			dabo.ui.callAfterInterval(150, self.Form.unlockDisplay)
		else:
			self._properties["ShowCloseButton"] = val


	def _getShowGripper(self):
		return self._showGripper

	def _setShowGripper(self, val):
		if self._constructed():
			if val == self._showGripper:
				return
			self._showGripper = val
			self._PaneInfo.Gripper(val)
			self._updateAUI()
		else:
			self._properties["ShowGripper"] = val


	def _getShowMaximizeButton(self):
		return self._showMaximizeButton

	def _setShowMaximizeButton(self, val):
		if self._constructed():
			self._showMaximizeButton = val
			self._PaneInfo.MaximizeButton(val)
			self._updateAUI()
		else:
			self._properties["ShowMaximizeButton"] = val


	def _getShowMinimizeButton(self):
		return self._showMinimizeButton

	def _setShowMinimizeButton(self, val):
		if self._constructed():
			self._showMinimizeButton = val
			self._PaneInfo.MinimizeButton(val)
			self._updateAUI()
		else:
			self._properties["ShowMinimizeButton"] = val


	def _getShowPinButton(self):
		return self._showPinButton

	def _setShowPinButton(self, val):
		if self._constructed():
			self._showPinButton = val
			self._PaneInfo.PinButton(val)
			self._updateAUI()
		else:
			self._properties["ShowPinButton"] = val



	def _getToolbar(self):
		return self._toolbar


	def _getTop(self):
		return self.__getPosition()[1]

	def _setTop(self, val):
		if self._constructed():
			if self.Floating:
				self.FloatingTop = val
			else:
				dabo.log.error(_("Cannot set the position of a docked panel"))
		else:
			self._properties["Top"] = val


	def _getTopDockable(self):
		return self._topDockable

	def _setTopDockable(self, val):
		if self._constructed():
			self._PaneInfo.TopDockable(val)
			self._updateAUI()
		else:
			self._properties["TopDockable"] = val


	def _getVisible(self):
		return self._PaneInfo.IsShown()

	def _setVisible(self, val):
		if self._constructed():
			self._PaneInfo.Show(val)
			self._updateAUI()
		else:
			self._properties["Visible"] = val


	def _getWidth(self):
		return self.__getSize()[0]

	def _setWidth(self, val):
		if self._constructed():
			if self.Floating:
				self.FloatingWidth = val
			else:
				dabo.log.error(_("Cannot set the Size of a docked panel"))
		else:
			self._properties["Width"] = val


	Bottom = property(_getBottom, _setBottom, None,
			_("Position in pixels of the bottom side of the panel. Read-only when docked; read-write when floating  (int)"))

	BottomDockable = property(_getBottomDockable, _setBottomDockable, None,
			_("Can the panel be docked to the bottom edge of the form? Default=True  (bool)"))

	Caption = property(_getCaption, _setCaption, None,
			_("Text that appears in the title bar  (str)"))

	DestroyOnClose = property(_getDestroyOnClose, _setDestroyOnClose, None,
			_("When the panel's Close button is clicked, does the panel get destroyed (True) or just hidden (False, default)  (bool)"))

	Dockable = property(_getDockable, _setDockable, None,
			_("Can the panel be docked to the form? Default=True  (bool)"))

	Docked = property(_getDocked, _setDocked, None,
			_("Determines whether the pane is floating (False) or docked (True)  (bool)"))

	DockSide = property(_getDockSide, _setDockSide, None,
			_("""Side of the form that the panel is either currently docked to,
			or would be if dock() were to be called. Possible values are
			'Left', 'Right', 'Top' and 'Bottom'.  (str)"""))

	Floatable = property(_getFloatable, _setFloatable, None,
			_("Can the panel be undocked from the form and float independently? Default=True  (bool)"))

	Floating = property(_getFloating, _setFloating, None,
			_("Determines whether the pane is floating (True) or docked (False)  (bool)"))

	FloatingBottom = property(_getFloatingBottom, _setFloatingBottom, None,
			_("Bottom coordinate of the panel when floating  (int)"))

	FloatingHeight = property(_getFloatingHeight, _setFloatingHeight, None,
			_("Height of the panel when floating  (int)"))

	FloatingLeft = property(_getFloatingLeft, _setFloatingLeft, None,
			_("Left coordinate of the panel when floating  (int)"))

	FloatingPosition = property(_getFloatingPosition, _setFloatingPosition, None,
			_("Position of the panel when floating  (2-tuple of ints)"))

	FloatingRight = property(_getFloatingRight, _setFloatingRight, None,
			_("Right coordinate of the panel when floating  (int)"))

	FloatingSize = property(_getFloatingSize, _setFloatingSize, None,
			_("Size of the panel when floating  (2-tuple of ints)"))

	FloatingTop = property(_getFloatingTop, _setFloatingTop, None,
			_("Top coordinate of the panel when floating  (int)"))

	FloatingWidth = property(_getFloatingWidth, _setFloatingWidth, None,
			_("Width of the panel when floating  (int)"))

	GripperPosition = property(_getGripperPosition, _setGripperPosition, None,
			_("If a gripper is shown, is it on the Top or Left side? Default = 'Left'  ('Top' or 'Left')"))

	Height = property(_getHeight, _setHeight, None,
			_("Position in pixels of the height of the panel. Read-only when docked; read-write when floating  (int)"))

	Left = property(_getLeft, _setLeft, None,
			_("Position in pixels of the left side of the panel. Read-only when docked; read-write when floating  (int)"))

	LeftDockable = property(_getLeftDockable, _setLeftDockable, None,
			_("Can the panel be docked to the left edge of the form? Default=True  (bool)"))

	_Manager = property(_getManager, None, None,
			_("Reference to the AUI manager (for internal use only).  (_dDockManager)"))

	Movable = property(_getMovable, _setMovable, None,
			_("Can the panel be moved (True, default), or is it in a fixed position (False).  (bool)"))

	_PaneInfo = property(_getPaneInfo, None, None,
			_("Reference to the AUI PaneInfo object (for internal use only).  (wx.aui.PaneInfo)"))

	Resizable = property(_getResizable, _setResizable, None,
			_("Can the panel be resized? Default=True  (bool)"))

	Right = property(_getRight, _setRight, None,
			_("Position in pixels of the right side of the panel. Read-only when docked; read-write when floating  (int)"))

	RightDockable = property(_getRightDockable, _setRightDockable, None,
			_("Can the panel be docked to the right edge of the form? Default=True  (bool)"))

	ShowBorder = property(_getShowBorder, _setShowBorder, None,
			_("Should the panel's border be shown when floating?  (bool)"))

	ShowCaption = property(_getShowCaption, _setShowCaption, None,
			_("Should the panel's Caption be shown when it is docked? Default=True  (bool)"))

	ShowCloseButton = property(_getShowCloseButton, _setShowCloseButton, None,
			_("Does the panel display a close button when floating? Default=True  (bool)"))

	ShowGripper = property(_getShowGripper, _setShowGripper, None,
			_("Does the panel display a draggable gripper? Default=False  (bool)"))

	ShowMaximizeButton = property(_getShowMaximizeButton, _setShowMaximizeButton, None,
			_("Does the panel display a maximize button when floating? Default=False  (bool)"))

	ShowMinimizeButton = property(_getShowMinimizeButton, _setShowMinimizeButton, None,
			_("Does the panel display a minimize button when floating? Default=False  (bool)"))

	ShowPinButton = property(_getShowPinButton, _setShowPinButton, None,
			_("Does the panel display a pin button when floating? Default=False  (bool)"))

	Toolbar = property(_getToolbar, None, None,
			_("Returns True if this is a Toolbar pane. Default=False  (bool)"))

	Top = property(_getTop, _setTop, None,
			_("Position in pixels of the top side of the panel. Read-only when docked; read-write when floating  (int)"))

	TopDockable = property(_getTopDockable, _setTopDockable, None,
			_("Can the panel be docked to the top edge of the form? Default=True  (bool)"))

	Visible = property(_getVisible, _setVisible, None,
			_("Is the panel shown?  (bool)"))

	Width = property(_getWidth, _setWidth, None,
			_("Position in pixels of the width of the panel. Read-only when docked; read-write when floating  (int)"))


	DynamicCaption = makeDynamicProperty(Caption)
예제 #8
0
파일: dTreeView.py 프로젝트: xfxf/dabo
class dTreeView(dcm.dControlMixin, wx.TreeCtrl):
    """Creates a treeview, which allows display of hierarchical data."""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 *args,
                 **kwargs):
        self._baseClass = dTreeView

        # Dictionary for tracking images by key value
        self.__imageList = {}
        self.nodes = []
        self._rootNode = None
        # Class to use for creating nodes
        self._nodeClass = dNode
        # Default size for images added to the tree.
        self._imageSize = (16, 16)
        # Do we set tooltips from the nodes?
        self._useNodeToolTips = False
        # Store the default ToolTipText while UseNodeToolTips is True
        self._storedToolTipText = None

        style = self._extractKey((properties, attProperties, kwargs), "style",
                                 0) | wx.TR_HAS_VARIABLE_ROW_HEIGHT
        # Default to showing buttons
        val = self._extractKey(attProperties, "ShowButtons", None)
        if val is not None:
            val = (val == "True")
        else:
            val = self._extractKey((properties, kwargs), "ShowButtons", True)
        if val:
            style = style | wx.TR_HAS_BUTTONS

        # Default to showing lines
        val = self._extractKey(attProperties, "ShowLines", None)
        if val is not None:
            val = (val == "True")
        else:
            val = self._extractKey((properties, kwargs), "ShowLines", True)
        if not val:
            style = style | wx.TR_NO_LINES

        # Default to showing root node
        val = self._extractKey(attProperties, "ShowRootNode", None)
        if val is not None:
            val = (val == "True")
        else:
            val = self._extractKey((properties, kwargs), "ShowRootNode", True)
        if not val:
            style = style | wx.TR_HIDE_ROOT

        # Default to showing root node lines
        val = self._extractKey(attProperties, "ShowRootNodeLines", None)
        if val is not None:
            val = (val == "True")
        else:
            val = self._extractKey((properties, kwargs), "ShowRootNodeLines",
                                   True)
        if val:
            style = style | wx.TR_LINES_AT_ROOT

        preClass = wx.PreTreeCtrl
        dcm.dControlMixin.__init__(self,
                                   preClass,
                                   parent,
                                   properties=properties,
                                   attProperties=attProperties,
                                   style=style,
                                   *args,
                                   **kwargs)

    def _initEvents(self):
        super(dTreeView, self)._initEvents()
        self.Bind(wx.EVT_LEFT_UP, self._onWxHit)
        self.Bind(wx.EVT_KEY_UP, self.__onKeyUp)
        self.Bind(wx.EVT_TREE_SEL_CHANGED, self.__onTreeSel)
        self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.__onTreeItemCollapse)
        self.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.__onTreeItemExpand)
        self.Bind(wx.EVT_TREE_ITEM_MENU, self.__onTreeItemContextMenu)
        self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.__onTreeBeginDrag)
        self.Bind(wx.EVT_TREE_END_DRAG, self.__onTreeEndDrag)
        self.Bind(wx.EVT_MOTION, self.__onTreeMouseMove)

    def __onTreeItemContextMenu(self, evt):
        self.raiseEvent(dEvents.TreeItemContextMenu, evt)

    def __onTreeBeginDrag(self, evt):
        if self._allowDrag(evt):
            evt.Allow()
        # We need to select the item being dragged
        # so we don't try to drag an old selected item
        self.SelectItem(evt.GetItem())
        evt.Skip()
        self.raiseEvent(dEvents.TreeBeginDrag, evt)

    def __onTreeEndDrag(self, evt):
        evt.Skip()
        # We need to select only our destination node
        if self.MultipleSelect:
            self.UnselectAll()
        self.SelectItem(evt.GetItem())
        self.raiseEvent(dEvents.TreeEndDrag, evt)

    def _allowDrag(self, evt):
        nd = self.find(evt.GetItem())
        return self.allowDrag(nd)

    def allowDrag(self, node):
        # Override in subclasses in needed.
        return True

    def _getInitPropertiesList(self):
        original = list(super(dTreeView, self)._getInitPropertiesList())
        original.remove("MultipleSelect")
        return tuple(original)

    def clear(self, clearImageList=False):
        self.DeleteAllItems()
        self.nodes = []
        if clearImageList:
            il = self.GetImageList()
            if il:
                il.RemoveAll()
            self.__imageList = {}

    def refreshDisplay(self):
        """
		Changing some node appearance properties requires that the tree be
		collapsed and re-opened in order to update any sizing issues.
		"""
        self.lockDisplay()
        sel = self.Selection
        ndExp = ((nd, nd.Expanded) for nd in self.nodes
                 if ((not nd.IsRootNode) or self.ShowRootNode))
        self.collapseAll()
        for nd, exp in ndExp:
            nd.Expanded = exp
        self.Selection = sel
        self.unlockDisplay()

    def getRootNode(self):
        return self._rootNode

    def setRootNode(self, txt):
        itemID = self.AddRoot(txt)
        ret = self._rootNode = self.NodeClass(self, itemID, None)
        if self.ShowRootNode:
            self.SetItemFont(ret.itemID, self.GetFont())
        self.nodes.append(ret)
        return ret

    def appendNode(self, node, txt):
        if node is None:
            # Get the root node
            ndid = self.GetRootItem()
        else:
            ndid = node.itemID
        itemID = self.AppendItem(ndid, txt)
        ret = self.NodeClass(self, itemID, node)
        self.SetItemFont(ret.itemID, self.GetFont())
        self.nodes.append(ret)
        return ret

    def removeNode(self, node):
        self.Delete(node.itemID)
        for n in node.Descendents:
            self.nodes.remove(n)
        self.nodes.remove(node)

    def expand(self, node):
        self.Expand(node.itemID)

    def collapse(self, node):
        self.Collapse(node.itemID)

    def expandAll(self):
        nds = self.nodes
        if not self.ShowRootNode:
            nds = [nd for nd in self.nodes if not nd.IsRootNode]
        for n in nds:
            self.expand(n)

    def collapseAll(self):
        nds = self.nodes
        if not self.ShowRootNode:
            nds = [nd for nd in self.nodes if not nd.IsRootNode]
        for n in nds:
            self.collapse(n)

    def expandBranch(self, nd):
        """Expands the specified node, as well as any of its child nodes."""
        self.ExpandAllChildren(nd.itemID)

    def collapseBranch(self, nd):
        """Collapses the specified node, as well as any of its child nodes."""
        self.CollapseAllChildren(nd.itemID)

    def showNode(self, node):
        self.EnsureVisible(node.itemID)

    # Image-handling function
    def addImage(self, img, key=None):
        """
		Adds the passed image to the control's ImageList, and maintains
		a reference to it that is retrievable via the key value.
		"""
        # Default image size
        wd, ht = self.ImageSize
        il = self.GetImageList()
        if not il:
            il = wx.ImageList(wd, ht, initialCount=0)
            self.AssignImageList(il)
        else:
            if il.GetImageCount():
                wd, ht = il.GetSize(0)
        if key is None:
            key = ustr(img)
        if isinstance(img, basestring):
            img = dabo.ui.strToBmp(img, width=wd, height=ht)
        idx = il.Add(img)
        self.__imageList[key] = idx

    def setNodeImg(self, node, imgKey, which="normal"):
        """
		Sets the specified node's image to the image corresponding to the
		specified key. May also optionally pass the index of the image in the
		image list rather than the key, which is the state of the node.

		Valid states are:

			'normal'
			'expanded'
			'selected'
			'selectedexpanded'

		"""
        whichdict = {
            "normal": wx.TreeItemIcon_Normal,
            "expanded": wx.TreeItemIcon_Expanded,
            "selected": wx.TreeItemIcon_Selected,
            "selectedexpanded": wx.TreeItemIcon_SelectedExpanded
        }
        if which.lower() not in whichdict:
            raise ValueError(_("Invalid Node State: %s") % which)
        if isinstance(imgKey, int):
            imgIdx = imgKey
        else:
            imgIdx = self.__imageList[imgKey]
        self.SetItemImage(node.itemID, imgIdx, whichdict[which.lower()])

    def getNodeImg(self, node, which="normal"):
        """
		Returns the index of the specified node's image in the
		current image list, or -1 if no image is set for the node.
		Which is the state of the node.

		Valid states are:

			'normal'
			'expanded'
			'selected'
			'selectedexpanded'

		"""
        whichdict = {
            "normal": wx.TreeItemIcon_Normal,
            "expanded": wx.TreeItemIcon_Expanded,
            "selected": wx.TreeItemIcon_Selected,
            "selectedexpanded": wx.TreeItemIcon_SelectedExpanded
        }
        if which.lower() not in whichdict:
            raise ValueError(_("Invalid Node State: %s") % which)
        return self.GetItemImage(node.itemID, whichdict[which.lower()])

    def nodeForObject(self, obj):
        """Given an object, returns the corresponding node."""
        try:
            return [nd for nd in self.nodes if nd._object is obj][0]
        except IndexError:
            return None

    def getParentNode(self, node):
        """
		Returns the node that is the parent of the given node, or
		None if the node is the root.
		"""
        parentID = self.GetItemParent(node.itemID)
        ret = self.find(parentID)
        if ret:
            if isinstance(ret, list):
                ret = ret[0]
        else:
            ret = None
        return ret

    def getChildren(self, node):
        """Returns a list of all nodes that are child nodes of this node."""
        ret = [n for n in self.nodes if n.parent == node]
        return ret

    def getDescendents(self, node):
        """Returns a list of all nodes that are direct descendents of this node."""
        ret = []
        for n in self.nodes:
            par = n.parent
            while par:
                if par == node:
                    ret.append(n)
                    break
                else:
                    par = par.parent
        return ret

    def getSiblings(self, node):
        """
		Returns a list of all nodes at the same level as the specified
		node. The specified node is included in the list.
		"""
        ret = [n for n in self.nodes if n.parent == node.parent]
        return ret

    def find(self, srch, top=None):
        """
		Searches the nodes collection for all nodes that match
		whose text matches the passed search value (if a text value
		was passed). If a wxPython TreeItemID object is passed, returns
		a list nodes matching that itemID value. If a specific node is passed
		in the top property, the search is limited to descendents of that
		node.
		Returns a list of matching nodes.
		"""
        ret = []
        if top is None:
            nodes = self.nodes
        else:
            nodes = top.Descendents
        if isinstance(srch, basestring):
            ret = [n for n in nodes if n.Caption == srch]
        elif isinstance(srch, wx.TreeItemId):
            ret = [n for n in nodes if n.itemID == srch]
        return ret

    def findPattern(self, srchPat, top=None):
        """
		Allows for regexp pattern matching in order to find matching
		nodes using less than exact matches. If a specific node is passed
		in the top property, the search is limited to descendents of that
		node.
		Returns a list of matching nodes.
		"""
        ret = []
        if top is None:
            nodes = self.nodes
        else:
            nodes = top.Descendents
        if isinstance(srchPat, basestring):
            ret = [n for n in nodes if re.match(srchPat, n.Caption)]
        return ret

    # These related functions all use self._getRelative().
    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    def nextSibling(self, nd=None):
        """Returns the next sibling node, or None if there are no more"""
        return self._getRelative(nd, self.GetNextSibling)

    def priorSibling(self, nd=None):
        """Returns the prior sibling node, or None if there are no more"""
        return self._getRelative(nd, self.GetPrevSibling)

    def nextNode(self, nd=None):
        """
		If the current node has children, returns the first child node. If
		it has no children, returns the next sibling. If there are no next
		siblings, returns the next sibling of the parent node. If the parent
		node has no more siblings, returns the next sibling of the grand-
		parent node, etc. Returns None if we are at the absolute bottom
		of the flattened tree structure. Sometimes referred to as 'flatdown'
		navigation.
		"""
        if not isinstance(nd, dNode):
            nd = self.nodeForObject(nd)
        if nd is None:
            nd = self.Selection
            if isinstance(nd, list):
                if nd:
                    nd = nd[0]
                else:
                    # Empty list
                    return None
        try:
            ret = self.getChildren(nd)[0]
        except IndexError:
            ret = None
        if ret is None:
            ret = self._getRelative(nd, self.GetNextSibling)
            while ret is None:
                # No more siblings. Go up the tree, getting the next
                # sibling of each parent until we either find one, or
                # we reach the top.
                nd = self.getParentNode(nd)
                if nd is None:
                    break
                ret = self._getRelative(nd, self.GetNextSibling)
        return ret

    def priorNode(self, nd=None):
        """
		Returns last child of the prior sibling node. If there
		are no prior siblings, returns the parent. Sometimes
		referred to as 'flatup' navigation.
		"""
        if not isinstance(nd, dNode):
            nd = self.nodeForObject(nd)
        if nd is None:
            nd = self.Selection
            if isinstance(nd, list):
                if nd:
                    nd = nd[0]
                else:
                    # Empty list
                    return None
        ret = self._getRelative(nd, self.GetPrevSibling)
        if ret is None:
            try:
                ret = self.getParentNode(nd)
            except wx.PyAssertionError:
                pass
        else:
            # Find the last child of the last child of the last child...
            nd = ret
            kids = self.getChildren(nd)
            while kids:
                nd = kids[-1]
                kids = self.getChildren(nd)
            ret = nd
        return ret

    def _getRelative(self, nd, func):
        """
		Used by nextNode(), nextSibling(), priorNode() and
		priorSibling() methods for relative movement.
		"""
        if nd is None:
            nd = self.Selection
        if isinstance(nd, list):
            if nd:
                nd = nd[0]
            else:
                # Empty list
                return None
        try:
            itemID = func(nd.itemID)
            ret = [nod for nod in self.nodes if nod.itemID == itemID][0]
        except IndexError:
            ret = None
        return ret

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    def makeDirTree(self,
                    dirPath,
                    wildcard=None,
                    ignored=None,
                    showHidden=False,
                    expand=False):
        """
		Make this dTreeView show a filesystem directory hierarchy. You
		can specify a wildcard pattern: e.g., "\*py" will only include files
		ending in 'py'. You can also pass a list of wildcards, and files
		matching any of these will be included in the tree. If no wildcard
		is specified, all files will be included.

		You can also specify file patterns to ignore in the 'ignored' parameter.
		This can be a single string of a file pattern, or a list of such patterns.
		Any file matching any of these patterns will not be included in the tree.

		By default, hidden files (i.e., those beginning with a period) are ignored.
		You can optionally show them by passing True in the showHidden
		parameter.

		The tree defaults to fully collapsed; you can change it to fully
		expanded by passing True in the 'expand' parameter.

		Warning: Don't use this for huge hierarchies, as it blocks while
		filling the complete tree, instead of only filling the nodes as
		they are opened.
		"""
        self.clear(clearImageList=True)
        # Add the standard images for a directory tree
        self.addImage("folder", "folder")
        self.addImage("folderopen", "folderopen")
        self.addImage("normalfile", "file")
        self.addImage("executablefile", "executablefile")

        # Add any trailing slash character
        self._pathNode = {}

        # Define the function to be passed to os.path.walk
        def addNode(arg, currDir, fNames):
            wildcards, ignored, showHid = arg
            prnt, nm = os.path.split(currDir)
            if not showHid and nm.startswith("."):
                return
            try:
                nd = self._pathNode[currDir] = self._pathNode[
                    prnt].appendChild(nm)
            except (KeyError, AttributeError):
                # If this is the first entry, we need to set the root
                if not self._pathNode:
                    nd = self._pathNode[currDir] = self.setRootNode(nm)
                else:
                    # parent wasn't added, because it was hidden
                    return
            self.setNodeImg(nd, "folder", "normal")
            self.setNodeImg(nd, "folderopen", "expanded")
            nd.ToolTipText = nd._filePath = currDir
            acceptedNames = ignoredNames = None
            if wildcards is not None:
                acceptedNames = []
                for wc in wildcards:
                    acceptedNames += glob.glob(
                        os.path.join(currDir, wc.lower()))
                    acceptedNames += glob.glob(
                        os.path.join(currDir, wc.upper()))
            if ignored is not None:
                ignoredNames = []
                for ig in ignored:
                    ignoredNames += glob.glob(os.path.join(
                        currDir, ig.lower()))
                    ignoredNames += glob.glob(os.path.join(
                        currDir, ig.upper()))
            for f in fNames:
                fullName = os.path.join(currDir, f)
                if os.path.isdir(fullName):
                    # it will be added as a directory
                    continue
                if not showHid and f.startswith("."):
                    continue
                if acceptedNames is not None:
                    if fullName not in acceptedNames:
                        continue
                if ignoredNames is not None:
                    if fullName in ignoredNames:
                        continue
                kid = nd.appendChild(f)
                kid._filePath = fullName
                self.setNodeImg(kid, "file", "normal")
                kid.ToolTipText = fullName

        def sortNode(arg, currDir, fNames):
            if currDir in self._pathNode:
                self.SortChildren(self._pathNode[currDir].itemID)

        if wildcard and not isinstance(wildcard, (list, tuple)):
            # single string passed
            wildcard = [wildcard]
        if ignored and not isinstance(ignored, (list, tuple)):
            # single string passed
            ignored = [ignored]
        arg = (wildcard, ignored, showHidden)
        os.path.walk(dirPath, addNode, arg)
        os.path.walk(dirPath, sortNode, None)
        if expand:
            self.expandAll()

    def _setAbsoluteFontZoom(self, newZoom):
        self._currFontZoom = newZoom
        for node in self.nodes:
            origFontSize = node._origFontSize = getattr(
                node, "_origFontSize", node.FontSize)
            fontSize = origFontSize + newZoom
            if fontSize > 1:
                node.FontSize = fontSize

        if self.Form is not None:
            dabo.ui.callAfterInterval(200, self.Form.layout)

    def treeFromStructure(self, stru, topNode=None):
        """
		Given a sequence of items with a standard format,
		this will construct a tree structure and append it to
		the specified 'topNode'. If 'topNode' is None, the tree
		will be cleared, and a new structure containing only the
		passed info will be created. The info should be passed
		as a sequence of either lists or tuples, with the first
		element being the text to be displayed, and, if there are
		to be child nodes, the second being the child node
		information. If there are no children for that node, either
		do not include the second element, or set it to None.
		If there are child nodes, the child information will be
		recursively parsed.
		"""
        addRoot = (topNode is None)
        if addRoot:
            self.DeleteAllItems()
        if isinstance(stru[0], basestring):
            # We're at the end of the recursion. Just append the node
            self.appendNode(topNode, stru[0])
        else:
            for nodes in stru:
                txt = nodes[0]
                if addRoot:
                    nd = self.setRootNode(txt)
                    addRoot = False
                else:
                    nd = self.appendNode(topNode, txt)
                try:
                    kids = nodes[1]
                except IndexError:
                    kids = None
                if kids:
                    self.treeFromStructure(kids, nd)

    def addDummyData(self):
        """For testing purposes!"""
        root = ["This is the root"]
        kid1 = ["First Child"]
        kid2 = ["Second Child"]
        kid3 = ["Third Child"]
        gk1 = ["Grandkid #1"]
        gk2 = ["Grandkid #2"]
        gk3 = ["Grandkid #3"]
        ggk1 = ["Great-Grandkid #1"]
        root.append([kid1, kid2, kid3])
        kid2.append([gk1, gk2, gk3])
        gk2.append(ggk1)
        self.treeFromStructure([root])
        ### NOTE: This will also work
        # 		self.DeleteAllItems()
        # 		r = self.setRootNode("This is the root")
        # 		c1 = r.appendChild("First Child")
        # 		c2 = r.appendChild("Second Child")
        # 		c3 = r.appendChild("Third Child")
        # 		c21 = c2.appendChild("Grandkid #1")
        # 		c22 = c2.appendChild("Grandkid #2")
        # 		c23 = c2.appendChild("Grandkid #3")
        # 		c221 = c22.appendChild("Great-Grandkid #1")

    def getNodeForID(self, idval):
        """Given a wx item ID, returns the corresponding node, or None."""
        try:
            ret = [nd for nd in self.nodes if nd.itemID == idval][0]
        except IndexError:
            ret = None
        return ret

    def getNodeUnderMouse(self, includeSpace=False, includeButton=True):
        """
		Returns the node directly under the mouse, or None if the mouse is not
		over a node. If 'includeSpace' is True, the empty space to the right of the node
		is counted as part of the node. Likewise, if 'includeButton' is True, the
		area for the expanding/collapsing button is considered part of the node.
		Otherwise, it is considered to not be over any node.
		"""
        # The following wxPython constants are available:
        # 	wx.TREE_HITTEST_ABOVE: Above the client area.
        # 	wx.TREE_HITTEST_BELOW: Below the client area.
        # 	wx.TREE_HITTEST_NOWHERE: In the client area but below the last item.
        # 	wx.TREE_HITTEST_ONITEMBUTTON: On the button associated with an item.
        # 	wx.TREE_HITTEST_ONITEMICON: On the bitmap associated with an item.
        # 	wx.TREE_HITTEST_ONITEMINDENT: In the indentation associated with an item.
        # 	wx.TREE_HITTEST_ONITEMLABEL: On the label (string) associated with an item.
        # 	wx.TREE_HITTEST_ONITEMRIGHT: In the area to the right of an item.
        # 	wx.TREE_HITTEST_ONITEMSTATEICON: On the state icon for a tree view item that is in a user-defined state.
        # 	wx.TREE_HITTEST_TOLEFT: To the right of the client area.
        # 	wx.TREE_HITTEST_TORIGHT: To the left of the client area.
        ret = None
        mp = self.getMousePosition()
        idval, flag = self.HitTest(mp)
        overFlags = (wx.TREE_HITTEST_ONITEMICON | wx.TREE_HITTEST_ONITEMINDENT
                     | wx.TREE_HITTEST_ONITEMLABEL)
        if includeSpace:
            overFlags = overFlags | wx.TREE_HITTEST_ONITEMRIGHT
        if includeButton:
            overFlags = overFlags | wx.TREE_HITTEST_ONITEMBUTTON
        if idval and (flag & overFlags):
            ret = self.getNodeForID(idval)
        return ret

    def getBaseNodeClass(cls):
        return dNode

    getBaseNodeClass = classmethod(getBaseNodeClass)

    # Event-handling code
    def __onTreeSel(self, evt):
        self.raiseEvent(dEvents.TreeSelection, evt)

    def __onKeyUp(self, evt):
        evt.Skip()
        if evt.GetKeyCode() in (316, 317, 318, 319):
            self._onWxHit(evt)

    def __onTreeItemCollapse(self, evt):
        self.raiseEvent(dEvents.TreeItemCollapse, evt)

    def __onTreeItemExpand(self, evt):
        self.raiseEvent(dEvents.TreeItemExpand, evt)

    def __onTreeMouseMove(self, evt):
        if self._useNodeToolTips:
            nd = self.getNodeUnderMouse()
            if nd:
                if nd.ToolTipText:
                    self.ToolTipText = nd.ToolTipText
                else:
                    self.ToolTipText = nd.Caption
            else:
                if self._storedToolTipText is not None:
                    self.ToolTipText = self._storedToolTipText
                else:
                    self.ToolTipText = ""

    def _getBaseNodes(self):
        if self.ShowRootNode:
            return [self._rootNode]
        else:
            return [
                nd for nd in self.nodes
                if nd.parent is not None and nd.parent.IsRootNode
            ]

    def _getEditable(self):
        return self._hasWindowStyleFlag(wx.TR_EDIT_LABELS)

    def _setEditable(self, val):
        self._delWindowStyleFlag(wx.TR_EDIT_LABELS)
        if val:
            self._addWindowStyleFlag(wx.TR_EDIT_LABELS)

    def _getImageSize(self):
        return self._imageSize

    def _setImageSize(self, val):
        if self._constructed():
            self._imageSize = val
        else:
            self._properties["ImageSize"] = val

    def _getMultipleSelect(self):
        return self._hasWindowStyleFlag(wx.TR_MULTIPLE)

    def _setMultipleSelect(self, val):
        self._delWindowStyleFlag(wx.TR_MULTIPLE)
        self._delWindowStyleFlag(wx.TR_EXTENDED)
        self._delWindowStyleFlag(wx.TR_SINGLE)
        if val:
            self._addWindowStyleFlag(wx.TR_MULTIPLE)
            self._addWindowStyleFlag(wx.TR_EXTENDED)
        else:
            if self._constructed():
                self.lockDisplay()
                sel = self.Selection
                self.UnselectAll()
                self._addWindowStyleFlag(wx.TR_SINGLE)
                self.Selection = sel
                self.unlockDisplay()
            else:
                self._addWindowStyleFlag(wx.TR_SINGLE)

    def _getNodeClass(self):
        return self._nodeClass

    def _setNodeClass(self, val):
        if self._constructed():
            self._nodeClass = val
        else:
            self._properties["NodeClass"] = val

    def _getSelection(self):
        if self.MultipleSelect:
            ids = self.GetSelections()
            ret = [node for node in self.nodes if node.itemID in ids]
        else:
            itemID = self.GetSelection()
            if itemID:
                try:
                    ret = [n for n in self.nodes if n.itemID == itemID][0]
                except IndexError:
                    ret = None
            else:
                ret = None
        return ret

    def _setSelection(self, node):
        if self._constructed():
            self.UnselectAll()
            if not node:
                return
            if isinstance(node, (list, tuple)):
                if self.MultipleSelect:
                    for itm in node:
                        self.SelectItem(itm.itemID, True)
                else:
                    if len(node) > 1:
                        dabo.log.error(
                            _("Attempting to select multiple nodes when MultipleSelect is False"
                              ))
                    self.SelectItem(node[0].itemID)
            else:
                self.SelectItem(node.itemID)
        else:
            self._properties["Selection"] = node

    def _getShowButtons(self):
        return self._hasWindowStyleFlag(wx.TR_HAS_BUTTONS)

    def _setShowButtons(self, val):
        if val:
            self._delWindowStyleFlag(wx.TR_NO_BUTTONS)
            self._addWindowStyleFlag(wx.TR_HAS_BUTTONS)
        else:
            self._delWindowStyleFlag(wx.TR_HAS_BUTTONS)
            self._addWindowStyleFlag(wx.TR_NO_BUTTONS)
        if self._constructed():
            try:
                self.refresh()
            except AttributeError:
                # Control may not be constructed yet
                pass

    def _getShowLines(self):
        return not self._hasWindowStyleFlag(wx.TR_NO_LINES)

    def _setShowLines(self, val):
        self._delWindowStyleFlag(wx.TR_NO_LINES)
        if not val:
            self._addWindowStyleFlag(wx.TR_NO_LINES)
        if self._constructed():
            try:
                self.refresh()
            except AttributeError:
                # Control may not be constructed yet
                pass

    def _getShowRootNode(self):
        return not self._hasWindowStyleFlag(wx.TR_HIDE_ROOT)

    def _setShowRootNode(self, val):
        self._delWindowStyleFlag(wx.TR_HIDE_ROOT)
        if not val:
            self._addWindowStyleFlag(wx.TR_HIDE_ROOT)
        if self._constructed():
            try:
                self.refresh()
            except AttributeError:
                # Control may not be constructed yet
                pass

    def _getShowRootNodeLines(self):
        return self._hasWindowStyleFlag(wx.TR_LINES_AT_ROOT)

    def _setShowRootNodeLines(self, val):
        self._delWindowStyleFlag(wx.TR_LINES_AT_ROOT)
        if val:
            self._addWindowStyleFlag(wx.TR_LINES_AT_ROOT)
        if self._constructed():
            try:
                self.refresh()
            except AttributeError:
                # Control may not be constructed yet
                pass

    def _getUseNodeToolTips(self):
        return self._useNodeToolTips

    def _setUseNodeToolTips(self, val):
        if self._constructed():
            if val:
                self._storedToolTipText = self.ToolTipText
            else:
                if self._storedToolTipText is not None:
                    self.ToolTipText = self._storedToolTipText
            self._useNodeToolTips = val
        else:
            self._properties["UseNodeToolTips"] = val

    BaseNodes = property(
        _getBaseNodes, None, None,
        _("""Returns the root node if ShowRootNode is True; otherwise,
			returns all the nodes who are not children of other nodes
			(read-only) (list of nodes)"""))

    Editable = property(
        _getEditable, _setEditable, None,
        _("""Specifies whether the tree labels can be edited by the user."""))

    ImageSize = property(
        _getImageSize, _setImageSize, None,
        _("Size of images added to the tree. Default=(15, 15)  (2-tuple of int)"
          ))

    MultipleSelect = property(
        _getMultipleSelect, _setMultipleSelect, None,
        _("""Specifies whether more than one node may be selected at once."""))

    NodeClass = property(_getNodeClass, _setNodeClass, None,
                         _("Class to use when creating nodes  (dNode)"))

    Selection = property(
        _getSelection, _setSelection, None,
        _("""Specifies which node or nodes are selected.

		If MultipleSelect is False, the currently selected node is specified. If MultipleSelect
		is True, a list of selected nodes is specified."""))

    ShowButtons = property(
        _getShowButtons, _setShowButtons, None,
        _("""Specifies whether +/- indicators are show at the left of parent nodes."""
          ))

    ShowLines = property(
        _getShowLines, _setShowLines, None,
        _("Specifies whether lines are drawn between nodes.  (bool)"))

    ShowRootNode = property(
        _getShowRootNode, _setShowRootNode, None,
        _("""Specifies whether the root node is included in the treeview.

		There can be only one root node, so if you want several root nodes you can
		fake it by setting ShowRootNode to False. Now, your top child nodes have
		the visual indication of being sibling root nodes."""))

    ShowRootNodeLines = property(
        _getShowRootNodeLines, _setShowRootNodeLines, None,
        _("""Specifies whether vertical lines are shown between root siblings."""
          ))

    UseNodeToolTips = property(
        _getUseNodeToolTips, _setUseNodeToolTips, None,
        _("""When True, the ToolTipText displayed is taken from the node.
			Default=False  (bool)"""))

    DynamicEditable = makeDynamicProperty(Editable)
    DynamicMultipleSelect = makeDynamicProperty(MultipleSelect)
    DynamicSelection = makeDynamicProperty(Selection)
    DynamicShowButtons = makeDynamicProperty(ShowButtons)
    DynamicShowLines = makeDynamicProperty(ShowLines)
    DynamicShowRootNode = makeDynamicProperty(ShowRootNode)
    DynamicShowRootNodeLines = makeDynamicProperty(ShowRootNodeLines)
예제 #9
0
class dSplitter(cm.dControlMixin, wx.SplitterWindow):
	"""
	Main class for handling split windows. It will contain two
	panels (subclass of SplitterPanelMixin), each of which can further
	split itself in two.
	"""
	def __init__(self, parent, properties=None, attProperties=None, *args, **kwargs):
		self._baseClass = dSplitter
		unsplitAtt = self._extractKey((kwargs, properties, attProperties), "CanUnsplit", "True")
		self._canUnsplit = unsplitAtt.upper()[0] == "T"
		baseStyle = wx.SP_3D | wx.SP_LIVE_UPDATE
		if self._canUnsplit:
			baseStyle = baseStyle | wx.SP_PERMIT_UNSPLIT
		style = self._extractKey((kwargs, properties, attProperties), "style", baseStyle)
		self._createPanes = self._extractKey(attProperties, "createPanes", None)
		if self._createPanes is not None:
			self._createPanes = (self._createPanes == "True")
		else:
			self._createPanes = self._extractKey((kwargs, properties), "createPanes", False)
		self._createSizers = self._extractKey(attProperties, "createSizers", None)
		if self._createSizers is not None:
			self._createSizers = (self._createSizers == "True")
		else:
			self._createSizers = self._extractKey((kwargs, properties), "createSizers", False)
		self._splitOnInit = self._extractKey(attProperties, "splitOnInit", None)
		if self._splitOnInit is not None:
			self._splitOnInit = (self._splitOnInit == "True")
		else:
			self._splitOnInit = self._extractKey((kwargs, properties), "splitOnInit", self._createPanes)
		# Default to a decent minimum panel size if none is specified
		mp = self._extractKey(attProperties, "MinimumPanelSize", None)
		if mp is not None:
			mp = int(mp)
		else:
			mp = self._extractKey((kwargs, properties, attProperties), "MinimumPanelSize", 20)
		kwargs["MinimumPanelSize"] = mp

		# Default to vertical split
		self._orientation = self._extractKey((kwargs, properties, attProperties), "Orientation", "v")
		self._sashPos = 100
		self._sashPercent = 1
		self._p1 = self._p2 = None
		# Default to not showing the context menus on the panels
		self._showPanelSplitMenu = False

		preClass = wx.PreSplitterWindow
		cm.dControlMixin.__init__(self, preClass, parent, properties=properties,
				attProperties=attProperties, style=style, *args, **kwargs)


	def _initEvents(self):
		super(dSplitter, self)._initEvents()
		self.Bind(wx.EVT_SPLITTER_DCLICK, self._onSashDClick)
		self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self._onSashPos)


	def _afterInit(self):
		# Create the panes
		if self._createPanes:
			self.createPanes()
		if self._splitOnInit:
			self.split()
		super(dSplitter, self)._afterInit()


	def _makeSplitterPanelClass(self, cls):
		mixin = SplitterPanelMixin
		if hasattr(self.Form, "isDesignerForm"):
			mixin = self.Application.getControlClass(mixin)
		# See if the class already is mixed in with the SplitterPanelMixin
		if isinstance(cls, mixin):
			ret = cls
		else:
			class MixedSplitterPanel(cls, mixin):
				def __init__(self, parent, *args, **kwargs):
					cls.__init__(self, parent, *args, **kwargs)
					mixin.__init__(self, parent, *args, **kwargs)
			ret = MixedSplitterPanel
		return ret


	def createPanes(self, cls=None, pane=None, force=False):
		if cls is None:
			cls = self.PanelClass
		spCls = self._makeSplitterPanelClass(cls)
		if pane is None:
			p1 = p2 = True
		else:
			p1 = (pane == 1)
			p2 = (pane == 2)
		if p1 and (force or self.Panel1 is None):
			self.Panel1 = spCls(self)
			if self._createSizers:
				self.Panel1.Sizer = dabo.ui.dSizer()
		if p2 and (force or self.Panel2 is None):
			self.Panel2 = spCls(self)
			if self._createSizers:
				self.Panel2.Sizer = dabo.ui.dSizer()


	def initialize(self, pnl):
		self.Initialize(pnl)


	def layout(self):
		if not self:
			return
		self.Panel1.layout()
		self.Panel2.layout()


	def _onSashDClick(self, evt):
		"""
		Handle the double-clicking of the sash. This will call
		the user-customizable onSashDClick() method.
		"""
		## Vetoing the event now will give user code the opportunity to not do the
		## default of removing the sash, by calling evt.stop().
		evt.Veto()
		# Update the internal sash position attribute.
		self._getSashPosition()
		# Raise a dEvent for other code to bind to,
		self.raiseEvent(dEvents.SashDoubleClick, evt)


	def _onSashPos(self, evt):
		"""Fires when the sash position is changed."""
		evt.Skip()
		# Update the internal sash position attribute.
		self._getSashPosition()
		sz = {"V": self.Width, "H": self.Height}[self.Orientation[0]] * 1.0
		if sz:
			pct = float(self.SashPosition) / sz
			self._sashPercent = max(0, min(1, pct))
			self.SetSashGravity(self._sashPercent)
		# Raise a dEvent for other code to bind to,
		self.raiseEvent(dEvents.SashPositionChanged, evt)


	def split(self, dir_=None):
		if self.IsSplit():
			return
		if self.Panel1 is None or self.Panel2 is None:
			# No panels, so we can't split! Create them.
			self.createPanes()

		if dir_:
			self.Orientation = dir_
		# Get the position
		pos = self.SashPosition
		if self.Orientation == "Horizontal":
			self.SplitHorizontally(self.Panel1, self.Panel2, pos)
		else:
			self.SplitVertically(self.Panel1, self.Panel2, pos)
		self.layout()


	def unsplit(self, win=None):
		if self.IsSplit():
			# Save the sash position
			self._getSashPosition()
			self.Unsplit(win)
			self.layout()


	def canRemove(self, pnl):
		ret = self.IsSplit()
		if not ret:
			# Make sure that there is at least one level of splitting somewhere
			obj = pnl
			while obj.Parent and not ret:
				obj = obj.Parent
				if isinstance(obj, dSplitter):
					ret = self.IsSplit()
		return ret


	def remove(self, pnl):
		if self.IsSplit():
			self.unsplit(pnl)
		else:
			# If the parent of this is a SplitterPanelMixin, tell it to hide
			prnt = self.Parent
			if isinstance(prnt, SplitterPanelMixin):
				prnt.remove()
			else:
				self.Destroy()


	def toggleSplit(self):
		"""Flips the split status of the control."""
		if self.IsSplit():
			self.unsplit()
		else:
			self.split()


	def _getCanUnsplit(self):
		return self._canUnsplit


	def _getMinPanelSize(self):
		return self.GetMinimumPaneSize()

	def _setMinPanelSize(self, val):
		if self._constructed():
			self.SetMinimumPaneSize(val)
		else:
			self._properties["MinimumPanelSize"] = val


	def _getOrientation(self):
		if self._orientation[0].lower() == "v":
			return "Vertical"
		else:
			return "Horizontal"

	def _setOrientation(self, val):
		if self._constructed():
			orient = val.lower()[0]
			if orient in ("h", "v"):
				self._orientation = {"h": "Horizontal", "v": "Vertical"}[orient]
				if self.IsSplit():
					self.lockDisplay()
					self.unsplit()
					self.split()
					self.unlockDisplay()
			else:
				raise ValueError("Orientation can only be 'Horizontal' or 'Vertical'")
		else:
			self._properties["Orientation"] = val


	def _getPanel1(self):
		return self._p1

	def _setPanel1(self, pnl):
		if self._constructed():
			old = self._p1
			if self.IsSplit():
				if self.Orientation == "Vertical":
					self.SplitVertically(pnl, self._p2)
				else:
					self.SplitHorizontally(pnl, self._p2)
			else:
				self.Initialize(pnl)
			self._p1 = pnl
			try:
				old.Destroy()
			except AttributeError:
				pass
		else:
			self._properties["Panel1"] = pnl


	def _getPanel2(self):
		return self._p2

	def _setPanel2(self, pnl):
		if self._constructed():
			old = self._p2
			self._p2 = pnl
			if self.IsSplit():
				self.ReplaceWindow(self.GetWindow2(), pnl)
			try:
				old.Destroy()
			except AttributeError:
				pass
		else:
			self._properties["Panel2"] = pnl


	def _getPanelClass(self):
		try:
			ret = self._panelClass
		except AttributeError:
			ret = self._panelClass = dabo.ui.dPanel
		return ret

	def _setPanelClass(self, val):
		self._panelClass = val


	def _getSashPercent(self):
		pos = self._getSashPosition()
		sz = {"V": self.Width, "H": self.Height}[self.Orientation[0]]
		if sz:
			ret = 100 * (float(pos) / float(sz))
		else:
			ret = 0
		return ret

	def _setSashPercent(self, val):
		if self._constructed():
			if 0 <= val <= 100:
				sz = {"V": self.Width, "H": self.Height}[self.Orientation[0]]
				pct = val / 100.0
				self._setSashPosition(sz * pct)
				self.SetSashGravity(pct)
		else:
			self._properties["SashPercent"] = val


	def _getSashPosition(self):
		if self.IsSplit():
			self._sashPos = self.GetSashPosition()
		return self._sashPos

	def _setSashPosition(self, val):
		if self._constructed():
			self.SetSashPosition(val)
			# Set the internal prop from the wx Prop
			self._sashPos = self.GetSashPosition()
		else:
			self._properties["SashPosition"] = val


	def _getShowPanelSplitMenu(self):
		return self._showPanelSplitMenu

	def _setShowPanelSplitMenu(self, val):
		if self._constructed():
			self._showPanelSplitMenu = val
			try:
				self.Panel1.ShowSplitMenu = val
			except AttributeError:
				pass
			try:
				self.Panel2.ShowSplitMenu = val
			except AttributeError:
				pass
		else:
			self._properties["ShowPanelSplitMenu"] = val


	def _getSplit(self):
		return self.IsSplit()

	def _setSplit(self, val):
		if val:
			self.split()
		else:
			self.unsplit()


	CanUnsplit = property(_getCanUnsplit, None, None,
			_("""Can the control be unsplit (i.e., only the first pane visible),
			even with a non-zero MinimumPanelSize? Can only be set when the control
			is created; read-only afterwards. Default=True  (bool)"""))

	MinimumPanelSize = property(_getMinPanelSize, _setMinPanelSize, None,
			_("Controls the minimum width/height of the panels.  (int)"))

	Orientation = property(_getOrientation, _setOrientation, None,
			_("Determines if the window splits Horizontally or Vertically.  (string)"))

	Panel1 = property(_getPanel1, _setPanel1, None,
			_("Returns the Top/Left panel.  (dPanel)"))

	Panel2 = property(_getPanel2, _setPanel2, None,
			_("Returns the Bottom/Right panel.  (dPanel)"))

	PanelClass = property(_getPanelClass, _setPanelClass, None,
			_("""Class used for creating panels. If the class does not descend from
			SplitterPanelMixin, that class will be mixed-into the class specified here.
			This must be set before the panels are created; setting it afterward has
			no effect unless you destroy the panels and re-create them.
			Default=dPanel  (dPanel)"""))

	SashPercent = property(_getSashPercent, _setSashPercent, None,
			_("Percentage of the split window given to Panel1. Range=0-100  (float)"))

	SashPosition = property(_getSashPosition, _setSashPosition, None,
			_("Position of the sash when the window is split.  (int)"))

	ShowPanelSplitMenu = property(_getShowPanelSplitMenu, _setShowPanelSplitMenu, None,
			_("""Determines if the default context menu for split/unsplit is enabled
			for the panels (default=False)  (bool)"""))

	Split = property(_getSplit, _setSplit, None,
			_("Returns the split status of the control  (bool)"))


	DynamicMinimumPanelSize = makeDynamicProperty(MinimumPanelSize)
	DynamicOrientation = makeDynamicProperty(Orientation)
	DynamicPanel1 = makeDynamicProperty(Panel1)
	DynamicPanel2 = makeDynamicProperty(Panel2)
	DynamicSashPosition = makeDynamicProperty(SashPosition)
	DynamicSplit = makeDynamicProperty(Split)
예제 #10
0
class dDatePicker(dcm.dDataControlMixin, wx.DatePickerCtrl):
    """
	Creates a DatePicker control.
	Control purpose is to maintain Date field types, but it can
	be used for Timestamp data field types too.
	It's behavior is similar to dDateTextBox control.
	"""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 *args,
                 **kwargs):
        self._invalidBackColor = "Yellow"
        self._valueMode = "d"
        self._timePart = [0, 0, 0, 0]
        self._lastWasNone = True
        self._baseClass = dDatePicker
        preClass = wx.PreDatePickerCtrl
        pickerMode = self._extractKey((properties, attProperties, kwargs),
                                      "PickerMode", "Dropdown")[:1].lower()
        if pickerMode not in "ds":
            pickerMode = "d"
        kwargs["style"] = kwargs.get("style", 0) | \
          {"d": wx.DP_DROPDOWN, "s": wx.DP_SPIN}[pickerMode]
        if self._extractKey((properties, attProperties, kwargs),
                            "AllowNullDate", False):
            kwargs["style"] |= wx.DP_ALLOWNONE
        if self._extractKey((properties, attProperties, kwargs),
                            "ForceShowCentury", False):
            kwargs["style"] |= wx.DP_SHOWCENTURY
        dcm.dDataControlMixin.__init__(self, preClass, parent, properties,
                                       attProperties, *args, **kwargs)
        self._bindKeys()

        if self.AllowNullDate:
            self.SetValue(
                None
            )  # Need this for the datetime not to display the current date when Null.

    def _initEvents(self):
        super(dDatePicker, self)._initEvents()
        self.Bind(wx.EVT_DATE_CHANGED, self._onWxHit)

    def _onWxHit(self, evt):
        self._userChanged = True
        self._lastWasNone = False
        self.flushValue()
        super(dDatePicker, self)._onWxHit(evt)

    def dayInterval(self, days):
        """Adjusts the date by the given number of days; negative
		values move backwards.
		"""
        self.Value += datetime.timedelta(days)

    def monthInterval(self, months):
        """Adjusts the date by the given number of months; negative
		values move backwards.
		"""
        val = self.Value
        mn = val.month + months
        yr = val.year
        dy = val.day
        while mn < 1:
            yr -= 1
            mn += 12
        while mn > 12:
            yr += 1
            mn -= 12
        # May still be an invalid day for the selected month
        ok = False
        while not ok:
            try:
                val = val.replace(year=yr, month=mn, day=dy)
                ok = True
            except ValueError:
                dy -= 1
        self.Value = val

    def setCurrentDate(self):
        if self._valueMode == "d":
            val = datetime.date.today()
        else:
            val = datetime.datetime.now()
        self.Value = val

    def setToMonthDay(self, day):
        val = self.Value
        if isinstance(day, basestring):
            if day[:1].lower() == "f":
                val = val.replace(day=1)
            elif day[:1].lower() == "l":
                mn = val.month
                td = datetime.timedelta(1)
                while mn == val.month:
                    val += td
                # We're now at the first of the next month. Go back one.
                val -= td
        else:
            val = val.replace(day=day)
        self.Value = val

    def setToYearDay(self, day):
        val = self.Value
        if isinstance(day, basestring):
            if day[:1].lower() == "f":
                val = val.replace(month=1, day=1)
            elif day[:1].lower() == "l":
                val = val.replace(month=12, day=31)
        self.Value = val

    def _processKey(self, evt):
        key = evt.EventData["keyCode"]
        if key == 43:  # +
            self.dayInterval(1)
        elif key == 45:  # -
            self.dayInterval(-1)
        elif key == 116:  # T
            self.setCurrentDate()
        elif key == 91:  # [
            self.monthInterval(-1)
        elif key == 93:  # ]
            self.monthInterval(1)
        elif key == 109:  # m
            self.setToMonthDay("First")
        elif key == 104:  # h
            self.setToMonthDay("Last")
        elif key == 121:  # y
            self.setToYearDay("First")
        elif key == 114:  # r
            self.setToYearDay("Last")
        elif key == 100:  # d
            self._setCustomDate()
        elif key in (dabo.ui.dKeys.key_Delete, dabo.ui.dKeys.key_Back):
            self.Value = None
        else:
            print key

    def _setCustomDate(self):
        days = dabo.ui.getInt(message=_("Day shift:"),
                              caption=_("Reschedule day"),
                              Min=-365,
                              Max=365)
        if days:
            self.dayInterval(days)

    def _bindKeys(self):
        # It seems that on Windows platform there is a bug in
        # control key handling implementation, because '=' key
        # is recognized as '+' key.
        # On Linux, '+' key seems to be unsupported.
        self.bindKey("+", self._processKey)
        self.bindKey("-", self._processKey)
        self.bindKey("d", self._processKey)
        self.bindKey("t", self._processKey)
        self.bindKey("[", self._processKey)
        self.bindKey("]", self._processKey)
        self.bindKey("m", self._processKey)
        self.bindKey("h", self._processKey)
        self.bindKey("y", self._processKey)
        self.bindKey("r", self._processKey)
        self.bindKey("=", self._processKey)
        self.bindKey("backspace", self._processKey)
        self.bindKey("delete", self._processKey)

    def _getPyValue(self, val):
        if self._lastWasNone:
            val = None
        elif val:
            if self._valueMode == "d":
                val = datetime.date(val.year, val.month, val.day)
            else:
                val = val.combine(
                    val,
                    datetime.time(self._timePart[0], self._timePart[1],
                                  self._timePart[2], self._timePart[3]))

        return val

    def _getWxValue(self, val):
        if isinstance(val, basestring):
            val = datetime.datetime.strptime(val, "%Y-%m-%d")
        elif isinstance(val, tuple):
            val = datetime.datetime(*val)
        elif isinstance(val, wx.DateTime):
            return val
        if val is not None:
            self._valueMode = "d" if type(val) == datetime.date else "t"
        if self._valueMode == "t":
            if val is None:
                self._timePart = [0, 0, 0, 0]
            else:
                self._timePart[0] = val.hour
                self._timePart[1] = val.minute
                self._timePart[2] = val.second
                self._timePart[3] = val.microsecond
        if val is None:
            self._lastWasNone = True
            if self.AllowNullDate:
                val = wx.DateTime()
            else:
                val = self.GetLowerLimit()
        else:
            self._lastWasNone = False
            val = dateTimePy2Wx(val)
        return val

    def setInvalidDate(self):
        self.Value = wx.DefaultDateTime

    def GetValue(self):
        try:
            val = dateTimeWx2Py(super(dDatePicker, self).GetValue())
        except wx.PyAssertionError:
            val = None
        return self._getPyValue(val)

    def SetValue(self, val):
        val = self._getWxValue(val)
        try:
            super(dDatePicker, self).SetValue(val)
        except ValueError as e:
            nm = self.Name
            ue = ustr(e)
            dabo.log.error(
                _(u"Object '%(nm)s' has the following error: %(ue)s") %
                locals())

    def _getAllowNullDate(self):
        return self._hasWindowStyleFlag(wx.DP_ALLOWNONE)

    def _setAllowNullDate(self, val):
        if val:
            self._addWindowStyleFlag(wx.DP_ALLOWNONE)
        else:
            self._delWindowStyleFlag(wx.DP_ALLOWNONE)

    def _getForceShowCentury(self):
        return self._hasWindowStyleFlag(wx.DP_SHOWCENTURY)

    def _setForceShowCentury(self):
        if val:
            self._addWindowStyleFlag(wx.DP_SHOWCENTURY)
        else:
            self._delWindowStyleFlag(wx.DP_SHOWCENTURY)

    def _getInvalidBackColor(self):
        return self._invalidBackColor

    def _setInvalidBackColor(self, val):
        self._invalidBackColor = val

    def _getIsDateValid(self):
        return self.Value is not None

    def _getMaxValue(self):
        return self._getPyValue(dateTimeWx2Py(self.UpperLimit))

    def _setMaxValue(self, val):
        if self._constructed():
            val = self._getWxValue(val)
            self.SetRange(self.LowerLimit, val)
        else:
            self._properties["MinValue"] = val

    def _getMinValue(self):
        return self._getPyValue(dateTimeWx2Py(self.LowerLimit))

    def _setMinValue(self, val):
        if self._constructed():
            val = self._getWxValue(val)
            self.SetRange(val, self.UpperLimit)
        else:
            self._properties["MinValue"] = val

    def _getPickerMode(self):
        if self._hasWindowStyleFlag(wx.DP_DROPDOWN):
            mode = "Dropdown"
        else:
            mode = "Spin"
        return mode

    def _setPickerMode(self, val):
        mode = val[:1].lower()
        if mode in "ds":
            self._addWindowStyleFlag({
                "d": wx.DP_DROPDOWN,
                "s": wx.DP_SPIN
            }[mode])
        else:
            raise ValueError(
                _("The only allowed values are: 'Dropdown', 'Spin'."))

    def _getValueMode(self):
        return {"d": "Date", "t": "Timestamp"}[self._valueMode]

    def _setValueMode(self, val):
        val = val[:1].lower()
        if val in "dt":
            self._valueMode = val
        else:
            raise ValueError(
                _("The only allowed values are: 'Date', 'Timestamp'."))

    # Property definitions:
    AllowNullDate = property(
        _getAllowNullDate, _setAllowNullDate, None,
        _("""If True enable Null vale in date. (bool)(Default=False)"""))

    ForceShowCentury = property(
        _getForceShowCentury, _setForceShowCentury, None,
        _("""Regardless of locale setting, century is shown if True. (bool)
		(Default=False)"""))

    IsDateValid = property(
        _getIsDateValid, None, None,
        _("""Read-only property tells if Value holds valid date type value.""")
    )

    InvalidBackColor = property(
        _getInvalidBackColor, _setInvalidBackColor, None,
        _("""Color value used for illegal values or values out-of-teh bounds. (str)
		(Default="Yellow")"""))

    MaxValue = property(
        _getMaxValue, _setMaxValue, None,
        _("""Holds upper value limit. (date, tuple, str)(Default=None)"""))

    MinValue = property(
        _getMinValue, _setMinValue, None,
        _("""Holds lower value limit. (date, tuple, str)(Default=None)"""))

    PickerMode = property(
        _getPickerMode, _setPickerMode, None,
        _("""Creates control with spin or dropdown calendar. (str)
		Available values are:
			- Spin
			- Dropdown (default)"""))

    ValueMode = property(
        _getValueMode, _setValueMode, None,
        _("""Enables handling Timestamp type. (str)(Default="Date")"""))

    DynamicMaxValue = makeDynamicProperty(MaxValue)
    DynamicMinValue = makeDynamicProperty(MinValue)
예제 #11
0
			When False, the value will revert back to the last numeric value when the
			control loses focus.

			The default comes from dabo.dTextBox_NumericBlankToZero, which defaults to
			False."""))

	PasswordEntry = property(_getPasswordEntry, _setPasswordEntry, None,
			_("Specifies whether plain-text or asterisks are echoed. (bool)"))

	StrictDateEntry = property(_getStrictDateEntry, _setStrictDateEntry, None,
			_("""Specifies whether date values must be entered in strict ISO8601 format. Default=False.

			If not strict, dates can be accepted in YYYYMMDD, YYMMDD, and MMDD format,
			which will be coerced into sensible date values automatically."""))

	StrictNumericEntry = property(_getStrictNumericEntry, _setStrictNumericEntry, None,
			_("""When True, the DataType will be preserved across numeric types. When False, the
			DataType will respond to user input to convert to the 'obvious' numeric type.
			Default=True. (bool)"""))

	Value = property(_getValue, _setValue, None,
			_("Specifies the current state of the control (the value of the field). (varies)"))


	# Dynamic property declarations
	DynamicPasswordEntry = makeDynamicProperty(PasswordEntry)
	DynamicStrictDateEntry = makeDynamicProperty(StrictDateEntry)
	DynamicValue = makeDynamicProperty(Value)

예제 #12
0
	MaxRows = property(_getMaxRows, _setMaxRows, None,
			_("When adding elements to the sizer, controls the max number "
			"of rows to add before a new column is started. (int)") )

	MaxCols = property(_getMaxCols, _setMaxCols, None,
			_("When adding elements to the sizer, controls the max number "
			"of columns to add before a new row is started. (int)") )

	MaxDimension = property(_getMaxDimension, _setMaxDimension, None,
			_("When adding elements to the sizer, this property determines "
			" if we use rows or columns as the limiting value. (char: 'r' or 'c'(default) )") )

	Orientation = property(_getMaxDimension, _setMaxDimension, None,
			_("Alias for the MaxDimensions property. (char: 'r' or 'c'(default) )") )

	VGap = property(_getVGap, _setVGap, None,
			_("Vertical gap between cells in the sizer  (int)"))


	DynamicHGap = makeDynamicProperty(HGap)
	DynamicMaxRows = makeDynamicProperty(MaxRows)
	DynamicMaxCols = makeDynamicProperty(MaxCols)
	DynamicMaxDimension = makeDynamicProperty(MaxDimension)
	DynamicOrientation = makeDynamicProperty(Orientation)
	DynamicVGap = makeDynamicProperty(VGap)


if __name__ == "__main__":
	s = dGridSizer()
예제 #13
0
파일: dButton.py 프로젝트: xfxf/dabo
class dButton(cm.dControlMixin, wx.Button):
    """
	Creates a button that can be pressed by the user to trigger an action.

	Example::

		class MyButton(dabo.ui.dButton):
			def initProperties(self):
				self.Caption = "Press Me"

			def onHit(self, evt):
				self.Caption = "Press Me one more time"

	"""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 *args,
                 **kwargs):
        self._baseClass = dButton
        preClass = wx.PreButton
        cm.dControlMixin.__init__(self,
                                  preClass,
                                  parent,
                                  properties=properties,
                                  attProperties=attProperties,
                                  *args,
                                  **kwargs)

    def _initEvents(self):
        super(dButton, self)._initEvents()
        self.Bind(wx.EVT_BUTTON, self._onWxHit)

    def _onCancelButton(self, evt, recurse=True):
        # This callback exists for when the user presses ESC and this button
        # is the cancel button. Raise dEvents.Hit.
        if self.VisibleOnScreen:
            self.raiseEvent(dEvents.Hit)
        else:
            # There may be another cancel button: give it a chance, too:
            if recurse:
                otherCancelButton = self.Form.FindWindowById(wx.ID_CANCEL)
                if otherCancelButton:
                    otherCancelButton._onCancelButton(evt, recurse=False)

    # Property get/set/del methods follow. Scroll to bottom to see the property
    # definitions themselves.
    def _getCancelButton(self):
        return self.GetId() == wx.ID_CANCEL

    def _setCancelButton(self, val):
        if self._constructed():
            ## pkm: We can bind the key to self, Parent, or Form (or any object).
            ##      If bound to self, the <esc> keypress will only fire the Hit
            ##      when self has the focus. If bound to self.Parent, Hit will
            ##      fire when self.Parent or any of its children has the focus.
            ##      If bound to self.Form, Hit will fire whenever <esc> is pressed.
            ##      I'm making the decision to bind it to self.Form, even though
            ##      self.Parent is also a valid choice.
            ### egl: changed the binding on OS X to the form. Parent just doesn't work.
            ### pkm: followed suit with GTK (we should test Win too).
            ### pkm: removed GTK to bind to parent because it wasn't working on the form.
            target = self.Parent
            if self.Application.Platform in ("Mac"):
                target = self.Form
            if val:
                target.bindKey("esc", self._onCancelButton)
                self.SetId(wx.ID_CANCEL)
            else:
                target.unbindKey("esc")
                self.SetId(wx.NewId())
        else:
            # In order to get the stock cancel button behavior from the OS, we need
            # to set the id here. So, getting the stock button behavior must happen
            # in the constructor, but theoretically we can get the escape behavior
            # anytime.
            if val:
                self._preInitProperties["id"] = wx.ID_CANCEL
            self._properties["CancelButton"] = val

    def _getDefaultButton(self):
        try:
            v = self._defaultButton
        except AttributeError:
            v = self._defaultButton = False
        return v

    def _setDefaultButton(self, value):
        if self._constructed():
            if value:
                # Need to unset default from any other buttons:
                for child in self.Parent.Children:
                    if child is self:
                        continue
                    try:
                        db = child.DefaultButton
                    except AttributeError:
                        db = False
                    if db:
                        child.DefaultButton = False
                # Now set it for this button
                self.SetDefault()
            else:
                # No wx-way to unset default button. Probably a rare need, anyway.
                # One idea would be to create a hidden button, set default to it,
                # and then destroy it.
                pass
            self._defaultButton = value
        else:
            self._properties["DefaultButton"] = value

    # Property definitions:
    CancelButton = property(
        _getCancelButton, _setCancelButton, None,
        _("Specifies whether this command button gets clicked on -Escape-."))

    DefaultButton = property(
        _getDefaultButton, _setDefaultButton, None,
        _("Specifies whether this command button gets clicked on -Enter-."))

    DynamicCancelButton = makeDynamicProperty(CancelButton)
    DynamicDefaultButton = makeDynamicProperty(DefaultButton)
예제 #14
0
파일: dTimer.py 프로젝트: xfxf/dabo
class dTimer(PM):
	"""Creates a timer, for causing something to happen at regular intervals."""
	def __init__(self, parent=None, properties=None, *args, **kwargs):
		self._baseClass = dTimer
		super(dTimer, self).__init__(preClass=None, parent=parent, properties=properties, *args, **kwargs)


	def isRunning(self):
		return self.Enabled


	def start(self, interval=-1):
		if interval >= 0:
			self.Interval = interval
		self.Enabled = self.Interval > 0
		return self.Enabled


	def stop(self):
		self.Enabled = False


	def release(self):
		"""Make sure that the timer is stopped first"""
		self.stop()
		super(dTimer, self).release()


	# The following methods are not needed except for
	# compatibility with the various properties.
	def Show(self, val):
		pass
	def GetSize(self):
		return (-1, -1)
	def SetBestFittingSize(self, val):
		pass
	def GetParent(self):
		return None
	def Bind(self, *args, **kwargs):
		pass
	def Destroy(self):
		pass


	def _onTimerHit(self):
		if self.Enabled and self.Interval > 0:
			self.raiseEvent(dEvents.Hit)
			dabo.ui.callAfterInterval(self.Interval, self._onTimerHit)


	# property get/set functions
	def _getEnabled(self):
		return getattr(self, "_enabled", False)

	def _setEnabled(self, val):
		self._enabled = val
		if val:
			dabo.ui.callAfterInterval(self.Interval, self._onTimerHit)
		else:
			self._properties["Enabled"] = val


	def _getInterval(self):
		try:
			v = self._interval
		except AttributeError:
			v = self._interval = 0
		return v

	def _setInterval(self, val):
		self._interval = val


	Enabled = property(_getEnabled, _setEnabled, None,
			_("""Alternative means of starting/stopping the timer, or determining
			its status. If Enabled is set to True and the timer has a positive value
			for its Interval, the timer will be started.  (bool)"""))

	Interval = property(_getInterval, _setInterval, None,
			_("Specifies the timer interval (milliseconds)."))


	DynamicEnabled = makeDynamicProperty(Enabled)
	DynamicInterval = makeDynamicProperty(Interval)
예제 #15
0
파일: dGridSizer.py 프로젝트: xfxf/dabo
    MaxCols = property(
        _getMaxCols, _setMaxCols, None,
        _("When adding elements to the sizer, controls the max number "
          "of columns to add before a new row is started. (int)"))

    MaxDimension = property(
        _getMaxDimension, _setMaxDimension, None,
        _("When adding elements to the sizer, this property determines "
          " if we use rows or columns as the limiting value. (char: 'r' or 'c'(default) )"
          ))

    Orientation = property(
        _getMaxDimension, _setMaxDimension, None,
        _("Alias for the MaxDimensions property. (char: 'r' or 'c'(default) )")
    )

    VGap = property(_getVGap, _setVGap, None,
                    _("Vertical gap between cells in the sizer  (int)"))

    DynamicHGap = makeDynamicProperty(HGap)
    DynamicMaxRows = makeDynamicProperty(MaxRows)
    DynamicMaxCols = makeDynamicProperty(MaxCols)
    DynamicMaxDimension = makeDynamicProperty(MaxDimension)
    DynamicOrientation = makeDynamicProperty(Orientation)
    DynamicVGap = makeDynamicProperty(VGap)


if __name__ == "__main__":
    s = dGridSizer()
예제 #16
0
class dSlider(dcm.dDataControlMixin, wx.Slider):
    """
	Creates a slider control, allowing editing integer values. Unlike dSpinner,
	dSlider does not allow entering a value with the keyboard.
	"""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 *args,
                 **kwargs):
        self._baseClass = dSlider
        self._continuous = False
        self._lastVal = None
        style = self._extractKey((kwargs, properties, attProperties), "style")
        if style is None:
            style = wx.SL_AUTOTICKS
        else:
            style = style | wx.SL_AUTOTICKS
        kwargs["style"] = style
        # These need to be added to the style kwarg in _initProperties
        self._tickPosition = None
        self._reversed = False

        preClass = wx.PreSlider
        dcm.dDataControlMixin.__init__(self,
                                       preClass,
                                       parent,
                                       properties=properties,
                                       attProperties=attProperties,
                                       *args,
                                       **kwargs)

    def _initProperties(self):
        super(dSlider, self)._initProperties()
        style = self._preInitProperties["style"]
        if self._tickPosition:
            tickpos = self.TickPosition[0].upper()
            style = style | {
                "T": wx.SL_TOP,
                "B": wx.SL_BOTTOM,
                "L": wx.SL_LEFT,
                "R": wx.SL_RIGHT
            }[tickpos]
        if self._reversed:
            style = style | wx.SL_INVERSE
        self._preInitProperties["style"] = style

    def _initEvents(self):
        super(dSlider, self)._initEvents()
        self.Bind(wx.EVT_SCROLL, self._onWxHit)

    def _onWxHit(self, evt):
        newval = self.GetValue()
        changed = (newval != self._lastVal)
        self._lastVal = newval
        if (changed and self._continuous) or not dabo.ui.isMouseLeftDown():
            self.flushValue()
            super(dSlider, self)._onWxHit(evt)

    # Property get/set/del methods follow. Scroll to bottom to see the property
    # definitions themselves.
    def _getContinuous(self):
        try:
            ret = self._continuous
        except AttributeError:
            ret = self._continuous = True
        return ret

    def _setContinuous(self, val):
        if self._constructed():
            self._continuous = val
        else:
            self._properties["Continuous"] = val

    def _getMax(self):
        return self.GetMax()

    def _setMax(self, val):
        if self._constructed():
            currmin = self.GetMin()
            currval = min(self.GetValue(), val)
            self.SetRange(currmin, val)
            self.SetValue(currval)
        else:
            self._properties["Max"] = val

    def _getMin(self):
        return self.GetMin()

    def _setMin(self, val):
        if self._constructed():
            currmax = self.GetMax()
            currval = max(self.GetValue(), val)
            self.SetRange(val, currmax)
            self.SetValue(currval)
        else:
            self._properties["Min"] = val

    def _getOrientation(self):
        if self.GetWindowStyle() & wx.SL_VERTICAL:
            return "Vertical"
        else:
            return "Horizontal"

    def _setOrientation(self, val):
        tickpos = self._tickPosition
        isHoriz = (val.lower()[:1] == "h")
        if isHoriz and tickpos in ("Left", "Right"):
            dabo.log.error(
                _("Cannot set the slider to Horizontal when TickPosition is %s."
                  ) % tickpos)
        elif not isHoriz and tickpos in ("Top", "Bottom"):
            dabo.log.error(
                _("Cannot set the slider to Vertical when TickPosition is %s.")
                % tickpos)
        self._delWindowStyleFlag(wx.SL_HORIZONTAL)
        self._delWindowStyleFlag(wx.SL_VERTICAL)
        if isHoriz:
            self._addWindowStyleFlag(wx.SL_HORIZONTAL)
        else:
            self._addWindowStyleFlag(wx.SL_VERTICAL)

    def _getReversed(self):
        return self._reversed

    def _setReversed(self, val):
        # Ignore this once constructed
        if not self._constructed():
            self._reversed = val

    def _getShowLabels(self):
        return (self.GetWindowStyle() & wx.SL_LABELS > 0)

    def _setShowLabels(self, val):
        self._delWindowStyleFlag(wx.SL_LABELS)
        if val:
            self._addWindowStyleFlag(wx.SL_LABELS)

    def _getTickPosition(self):
        try:
            tp = self._tickPosition[0].upper()
        except TypeError:
            # No tick position set; return Bottom
            return "Bottom"
        return {"T": "Top", "B": "Bottom", "L": "Left", "R": "Right"}[tp]

    def _setTickPosition(self, val):
        # Ignore this once constructed
        if not self._constructed():
            self._tickPosition = val

    # Property definitions:
    Continuous = property(
        _getContinuous, _setContinuous, None,
        _("""When True, the Hit event is raised as the slider moves. When False (default),
			it is only raised when the thumb control is released.  (bool)"""))

    Max = property(
        _getMax, _setMax, None,
        _("Specifies the maximum value for the Slider. Default=100  (int)"))

    Min = property(
        _getMin, _setMin, None,
        _("Specifies the minimum value for the Slider. Default=0  (int)"))

    Orientation = property(
        _getOrientation, _setOrientation, None,
        _("""Specifies whether the Slider is displayed as Horizontal or Vertical.
			Default='Horizontal'  (str)"""))

    Reversed = property(
        _getReversed, _setReversed, None,
        _("""When True, the position of the Min and Max values are reversed. Must be set
			when the object is created; setting it afterwards has no effect. Default=False  (bool)"""
          ))

    ShowLabels = property(
        _getShowLabels, _setShowLabels, None,
        _("""Specifies if the labels are shown on the slider. Must be set when the object is
			created; setting it afterwards has no effect. Default=True  (bool)"""))

    TickPosition = property(
        _getTickPosition, _setTickPosition, None,
        _("""Position of the tick marks; must be one of Top, Bottom (default), Left or Right.
			Not fully supported on all platforms. Must be set during object creation; has no
			effect once created.  (str)"""))

    DynamicOrientation = makeDynamicProperty(Orientation)
    DynamicMax = makeDynamicProperty(Max)
    DynamicMin = makeDynamicProperty(Min)
    DynamicShowLabels = makeDynamicProperty(ShowLabels)
예제 #17
0
class dShellForm(dSplitForm):
    def _onDestroy(self, evt):
        self._clearOldHistory()
        __builtin__.raw_input = self._oldRawInput

    def _beforeInit(self, pre):
        # Set the sash
        self._sashPct = 0.6
        # Class to use for creating the interactive shell
        self._shellClass = dShell
        super(dShellForm, self)._beforeInit(pre)

    def _afterInit(self):
        super(dShellForm, self)._afterInit()
        self.cmdHistKey = self.PreferenceManager.command_history
        self._historyPanel = None
        self._lastCmd = None

        # PyShell sets the raw_input function to a function of PyShell,
        # but doesn't set it back on destroy, resulting in errors later
        # on if something other than PyShell asks for raw_input (pdb, for
        # example).
        self._oldRawInput = __builtin__.raw_input
        self.bindEvent(dEvents.Destroy, self._onDestroy)

        splt = self.Splitter
        splt.MinimumPanelSize = 80
        splt.unbindEvent()
        self.Orientation = "H"
        self.unsplit()
        self._splitState = False
        self.MainSplitter.bindEvent(dEvents.SashDoubleClick,
                                    self.sashDoubleClick)
        self.MainSplitter.bindEvent(dEvents.SashPositionChanged,
                                    self.sashPosChanged)

        cp = self.CmdPanel = self.Panel1
        op = self.OutPanel = self.Panel2
        cp.unbindEvent(dEvents.ContextMenu)
        op.unbindEvent(dEvents.ContextMenu)

        cp.Sizer = dabo.ui.dSizer()
        op.Sizer = dabo.ui.dSizer()
        pgf = self.pgfCodeShell = dabo.ui.dPageFrame(cp, PageCount=2)
        self.pgShell = pgf.Pages[0]
        self.pgCode = pgf.Pages[1]
        self.pgShell.Caption = _("Shell")
        self.pgCode.Caption = _("Code")
        cp.Sizer.append1x(pgf)

        self.shell = self.ShellClass(self.pgShell,
                                     DroppedTextHandler=self,
                                     DroppedFileHandler=self)
        self.pgShell.Sizer.append1x(self.shell, border=4)
        # Configure the shell's behavior
        self.shell.AutoCompSetIgnoreCase(True)
        self.shell.AutoCompSetAutoHide(
            False)  ## don't hide when the typed string no longer matches
        self.shell.AutoCompStops(
            " ")  ## characters that will stop the autocomplete
        self.shell.AutoCompSetFillUps(".(")
        # This lets you go all the way back to the '.' without losing the AutoComplete
        self.shell.AutoCompSetCancelAtStart(False)
        self.shell.Bind(wx.EVT_RIGHT_UP, self.onShellRight)
        self.shell.Bind(wx.wx.EVT_CONTEXT_MENU, self.onShellContext)

        # Create the Code control
        codeControl = dabo.ui.dEditor(self.pgCode,
                                      RegID="edtCode",
                                      Language="python",
                                      OnKeyDown=self.onCodeKeyDown,
                                      OnMouseRightDown=self.onCodeRightDown,
                                      DroppedTextHandler=self,
                                      DroppedFileHandler=self)
        self.pgCode.Sizer.append1x(codeControl, border=4)
        # This adds the interpreter's local namespace to the editor for code completion, etc.
        codeControl.locals = self.shell.interp.locals
        lbl = dabo.ui.dLabel(
            self.pgCode,
            ForeColor="blue",
            WordWrap=True,
            Caption=
            _("""Ctrl-Enter to run the code (or click the button to the right).
Ctrl-Up/Down to scroll through history."""))
        lbl.FontSize -= 3
        runButton = dabo.ui.dButton(self.pgCode,
                                    Caption=_("Run"),
                                    OnHit=self.onRunCode)
        hsz = dabo.ui.dSizer("h")
        hsz.appendSpacer(20)
        hsz.append(lbl)
        hsz.append1x(dabo.ui.dPanel(self.pgCode))
        hsz.append(runButton, valign="middle")
        hsz.appendSpacer(20)
        self.pgCode.Sizer.append(hsz, "x")
        # Stack to hold code history
        self._codeStack = []
        self._codeStackPos = 0

        # Restore the history
        self.restoreHistory()
        # Bring up history search
        self.bindKey("Ctrl+R", self.onHistoryPop)
        # Show/hide the code editing pane
        self.bindKey("Ctrl+E", self.onToggleCodePane)

        # Force the focus to the editor when the code page is activated.
        def _delayedSetFocus(evt):
            dabo.ui.callAfter(self.edtCode.setFocus)

        self.pgCode.bindEvent(dEvents.PageEnter, _delayedSetFocus)

        # create the output control
        outControl = dabo.ui.dEditBox(op, RegID="edtOut", ReadOnly=True)
        op.Sizer.append1x(outControl)
        outControl.bindEvent(dEvents.MouseRightDown, self.onOutputRightDown)

        self._stdOut = self.shell.interp.stdout
        self._stdErr = self.shell.interp.stderr
        self._pseudoOut = pseudo.PseudoFileOut(write=self.appendOut)
        self._pseudoErr = pseudo.PseudoFileOut(write=self.appendOut)
        self.SplitState = True

        # Make 'self' refer to the calling form, or this form if no calling form.
        # Make 'bo' refer to the primary bizobj of the calling form, if any.
        if self.Parent is None:
            ns = self
        else:
            ns = self.Parent
            bo = getattr(ns, "PrimaryBizobj", None)
            if bo:
                self.shell.interp.locals['bo'] = bo
        self.shell.interp.locals['self'] = ns

        self.Caption = _("dShellForm: self is %s") % ns.Name
        self.setStatusText(
            _("Use this shell to interact with the runtime environment"))
        self.fillMenu()
        self.shell.SetFocus()

    def appendOut(self, tx):
        ed = self.edtOut
        ed.Value += tx
        endpos = ed.GetLastPosition()
        # Either of these commands should scroll the edit box
        # to the bottom, but neither do (at least on OS X) when
        # called directly or via callAfter().
        dabo.ui.callAfter(ed.ShowPosition, endpos)
        dabo.ui.callAfter(ed.SetSelection, endpos, endpos)

    def addToHistory(self, cmd=None):
        if cmd is None:
            cmd = self.shell.history[0]
        chk = self.cmdHistKey
        if cmd == self._lastCmd:
            # Don't add again
            return
        # Delete any old instances of this command
        chk.deleteByValue(cmd)
        self._lastCmd = cmd
        stamp = "%s" % int(round(time.time() * 100, 0))
        self.cmdHistKey.setValue(stamp, cmd)

    def _loadHistory(self):
        ck = self.cmdHistKey
        cmds = []
        for k in ck.getPrefKeys():
            cmds.append({"stamp": k, "cmd": ck.get(k)})
        dsu = dabo.db.dDataSet(cmds)
        if dsu:
            ds = dsu.sort("stamp", "asc")
            return ds
        else:
            return dsu

    def onToggleCodePane(self, evt):
        """Toggle between the Code Pane and the Output Pane"""
        self.pgfCodeShell.cyclePages(1)

    def processDroppedFiles(self, filelist):
        """
		This will fire if files are dropped on the code editor. If more than one
		file is dropped, only open the first, and warn the user.
		"""
        if len(filelist) > 1:
            dabo.ui.exclaim(_("Only one file can be dropped at a time"))
        if self.pgfCodeShell.SelectedPage == self.pgShell:
            self.shell.AddText(filelist[0])
        else:
            self.edtCode.Value = file(filelist[0]).read()

    def processDroppedText(self, txt):
        """Add the text to the code editor."""
        cc = self.edtCode
        currText = cc.Value
        selStart, selEnd = cc.SelectionPosition
        cc.Value = "%s%s%s" % (currText[:selStart], txt, currText[selEnd:])

    def onHistoryPop(self, evt):
        """
		Let the user type in part of a command, and retrieve the matching commands
		from their history.
		"""
        ds = self._loadHistory()
        hp = self._HistoryPanel
        hp.History = ds
        fp = self.FloatingPanel
        # We want it centered, so set Owner to None
        fp.Owner = None
        hp.clear()
        fp.show()
        if hp.ok:
            cmds = hp.getCmd()
            for num, cmd in enumerate(cmds):
                # For all but the first, we need to process the previous command.
                if num:
                    self.shell.processLine()
                try:
                    pos = self.shell.history.index(cmd)
                except ValueError:
                    # Not in the list
                    return
                self.shell.replaceFromHistory(pos - self.shell.historyIndex)

    def restoreHistory(self):
        """
		Get the stored history from previous sessions, and set the shell's
		internal command history list to it.
		"""
        ds = self._loadHistory()
        self.shell.history = [rec["cmd"] for rec in ds]

    def _clearOldHistory(self):
        """For performance reasons, only save up to 500 commands."""
        numToSave = 500
        ck = self.cmdHistKey
        ds = self._loadHistory()
        if len(ds) <= numToSave:
            return
        cutoff = ds[numToSave]["stamp"]
        bad = []
        for rec in ds:
            if rec["stamp"] <= cutoff:
                bad.append(rec["stamp"])
        for bs in bad:
            ck.deletePref(bs)

    def onRunCode(self, evt, addReturn=True):
        code = self.edtCode.Value.rstrip()
        if not code:
            return
        # See if this is already in the stack
        try:
            self._codeStackPos = self._codeStack.index(code)
        except ValueError:
            self._codeStack.append(code)
            self._codeStackPos = len(self._codeStack)
        self.edtCode.Value = ""
        self.shell.Execute(code)
        # If the last line is indented, run a blank line to complete the block
        if code.splitlines()[-1][0] in " \t":
            self.shell.run("", prompt=False)
        self.addToHistory()
        self.pgfCodeShell.SelectedPage = self.pgShell

    def onCodeKeyDown(self, evt):
        if not evt.controlDown:
            return
        keyCode = evt.keyCode
        if (keyCode == 13):
            evt.stop()
            self.onRunCode(None, addReturn=True)
        elif keyCode in (dKeys.key_Up, dKeys.key_Down):
            direction = {dKeys.key_Up: -1, dKeys.key_Down: 1}[keyCode]
            self.moveCodeStack(direction)

    def moveCodeStack(self, direction):
        size = len(self._codeStack)
        pos = self._codeStackPos
        newpos = max(0, pos + direction)
        if newpos == size:
            # at the end; clear the code
            self._codeStackPos = size - 1
            self.edtCode.Value = ""
        else:
            code = self._codeStack[newpos]
            self._codeStackPos = newpos
            self.edtCode.Value = code

    def onCodeRightDown(self, evt):
        dabo.ui.info("Code!")

    def onOutputRightDown(self, evt):
        pop = dabo.ui.dMenu()
        pop.append(_("Clear"), OnHit=self.onClearOutput)
        if self.edtOut.SelectionLength:
            pop.append(_("Copy"), OnHit=self.Application.onEditCopy)
        self.showContextMenu(pop)
        evt.stop()

    def onClearOutput(self, evt):
        self.edtOut.Value = ""

    def onShellContext(self, evt):
        pop = dabo.ui.dMenu()
        if self.SplitState:
            pmpt = _("Unsplit")
        else:
            pmpt = _("Split")
        pop.append(pmpt, OnHit=self.onSplitContext)
        self.showContextMenu(pop)
        evt.StopPropagation()

    def onShellRight(self, evt):
        pop = dabo.ui.dMenu()
        if self.SplitState:
            pmpt = _("Unsplit")
        else:
            pmpt = _("Split")
        pop.append(pmpt, OnHit=self.onSplitContext)
        self.showContextMenu(pop)
        evt.StopPropagation()

    def onSplitContext(self, evt):
        self.SplitState = not self.SplitState
        evt.stop()

    def onResize(self, evt):
        self.SashPosition = self._sashPct * self.Height

    def sashDoubleClick(self, evt):
        # We don't want the window to unsplit
        evt.stop()

    def sashPosChanged(self, evt):
        self._sashPct = float(self.SashPosition) / self.Height

    def fillMenu(self):
        viewMenu = self.MenuBar.getMenu("base_view")
        if viewMenu.Children:
            viewMenu.appendSeparator()
        viewMenu.append(_("Zoom &In"),
                        HotKey="Ctrl+=",
                        OnHit=self.onViewZoomIn,
                        ItemID="view_zoomin",
                        bmp="zoomIn",
                        help=_("Zoom In"))
        viewMenu.append(_("&Normal Zoom"),
                        HotKey="Ctrl+/",
                        OnHit=self.onViewZoomNormal,
                        ItemID="view_zoomnormal",
                        bmp="zoomNormal",
                        help=_("Normal Zoom"))
        viewMenu.append(_("Zoom &Out"),
                        HotKey="Ctrl+-",
                        OnHit=self.onViewZoomOut,
                        ItemID="view_zoomout",
                        bmp="zoomOut",
                        help=_("Zoom Out"))
        viewMenu.append(_("&Toggle Code Pane"),
                        HotKey="Ctrl+E",
                        OnHit=self.onToggleCodePane,
                        ItemID="view_togglecode",
                        bmp="",
                        help=_("Show/hide Code Pane"))
        editMenu = self.MenuBar.getMenu("base_edit")
        if editMenu.Children:
            editMenu.appendSeparator()
        editMenu.append(_("nClear O&utput"),
                        HotKey="Ctrl+Back",
                        ItemID="edit_clearoutput",
                        OnHit=self.onClearOutput,
                        help=_("Clear Output Window"))

    def onViewZoomIn(self, evt):
        self.shell.SetZoom(self.shell.GetZoom() + 1)

    def onViewZoomNormal(self, evt):
        self.shell.SetZoom(0)

    def onViewZoomOut(self, evt):
        self.shell.SetZoom(self.shell.GetZoom() - 1)

    @classmethod
    def getBaseShellClass(cls):
        return dShell

    def _getFontSize(self):
        return self.shell.FontSize

    def _setFontSize(self, val):
        if self._constructed():
            self.shell.FontSize = val
        else:
            self._properties["FontSize"] = val

    def _getFontFace(self):
        return self.shell.FontFace

    def _setFontFace(self, val):
        if self._constructed():
            self.shell.FontFace = val
        else:
            self._properties["FontFace"] = val

    def _getHistoryPanel(self):
        fp = self.FloatingPanel
        try:
            create = self._historyPanel is None
        except AttributeError:
            create = True
        if create:
            fp.clear()
            pnl = self._historyPanel = _LookupPanel(fp)
            pnl.Height = max(200, self.Height - 100)
            fp.Sizer.append(pnl)
            fp.fitToSizer()
        return self._historyPanel

    def _getShellClass(self):
        return self._shellClass

    def _setShellClass(self, val):
        if self._constructed():
            self._shellClass = val
        else:
            self._properties["ShellClass"] = val

    def _getSplitState(self):
        return self._splitState

    def _setSplitState(self, val):
        if self._splitState != val:
            self._splitState = val
            if val:
                self.split()
                self.shell.interp.stdout = self._pseudoOut
                self.shell.interp.stderr = self._pseudoErr
            else:
                self.unsplit()
                self.shell.interp.stdout = self._stdOut
                self.shell.interp.stderr = self._stdErr

    FontFace = property(_getFontFace, _setFontFace, None,
                        _("Name of the font face used in the shell  (str)"))

    FontSize = property(_getFontSize, _setFontSize, None,
                        _("Size of the font used in the shell  (int)"))

    _HistoryPanel = property(
        _getHistoryPanel, None, None,
        _("Popup to display the command history  (read-only) (dDialog)"))

    ShellClass = property(
        _getShellClass, _setShellClass, None,
        _("Class to use for the interactive shell  (dShell)"))

    SplitState = property(
        _getSplitState, _setSplitState, None,
        _("""Controls whether the output is in a separate pane (default)
			or intermixed with the commands.  (bool)"""))

    DynamicSplitState = makeDynamicProperty(SplitState)
예제 #18
0
파일: dLine.py 프로젝트: xfxf/dabo
class dLine(cm.dControlMixin, wx.StaticLine):
    """
	Creates a horizontal or vertical line.

	If Orientation is "Vertical", Height refers to the length of the line.
	If Orientation is "Horizontal", Width refers to the length of the line.
	The other value refers to how wide the control is, which affects how much
	buffer space will enclose the line, which will appear in the center of
	this space.
	"""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 *args,
                 **kwargs):
        self._baseClass = dLine
        preClass = wx.PreStaticLine

        cm.dControlMixin.__init__(self,
                                  preClass,
                                  parent,
                                  properties=properties,
                                  attProperties=attProperties,
                                  *args,
                                  **kwargs)

    def _initEvents(self):
        super(dLine, self)._initEvents()

    # property get/set functions
    def _getOrientation(self):
        if self._hasWindowStyleFlag(wx.LI_VERTICAL):
            return "Vertical"
        else:
            return "Horizontal"

    def _setOrientation(self, value):
        # Note: Orientation must be set before object created.
        self._delWindowStyleFlag(wx.LI_VERTICAL)
        self._delWindowStyleFlag(wx.LI_HORIZONTAL)

        value = ustr(value)[0].lower()
        if value == "v":
            self._addWindowStyleFlag(wx.LI_VERTICAL)
        elif value == "h":
            self._addWindowStyleFlag(wx.LI_HORIZONTAL)
        else:
            raise ValueError("The only possible values are "
                             "'Horizontal' and 'Vertical'.")

    # property definitions follow:
    Orientation = property(
        _getOrientation, _setOrientation, None,
        "Specifies the Orientation of the line. (str) \n"
        "   Horizontal (default) \n"
        "   Vertical"
        "This is determined by the Width and Height properties. "
        "If the Width is greater than the Height, it will be Horizontal. "
        "Otherwise, it will be Vertical.")
    DynamicOrientation = makeDynamicProperty(Orientation)
예제 #19
0
class dEditableList(dcm.dControlMixin, wx.gizmos.EditableListBox):
    """
	Creates an editable list box, complete with buttons to control
	editing, adding/deleting items, and re-ordering them.
	"""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 *args,
                 **kwargs):
        self._baseClass = dEditableList
        preClass = wx.gizmos.EditableListBox
        self._canAdd = self._extractKey((kwargs, properties, attProperties),
                                        "CanAdd", True)
        if isinstance(self._canAdd, basestring):
            self._canAdd = (self._canAdd == "True")
        self._canDelete = self._extractKey((kwargs, properties, attProperties),
                                           "CanDelete", True)
        if isinstance(self._canDelete, basestring):
            self._canDelete = (self._canDelete == "True")
        self._canOrder = self._extractKey((kwargs, properties, attProperties),
                                          "CanOrder", True)
        if isinstance(self._canOrder, basestring):
            self._canOrder = (self._canOrder == "True")
        self._editable = self._extractKey((kwargs, properties, attProperties),
                                          "Editable", True)
        style = self._extractKey((kwargs, properties, attProperties), "style",
                                 0)
        if self._canAdd:
            style = style | wx.gizmos.EL_ALLOW_NEW
        if self._editable:
            style = style | wx.gizmos.EL_ALLOW_EDIT
        if self._canDelete:
            style = style | wx.gizmos.EL_ALLOW_DELETE
        kwargs["style"] = style
        # References to the components of this control
        self._addButton = None
        self._deleteButton = None
        self._editButton = None
        self._downButton = None
        self._upButton = None
        self._panel = None

        dcm.dControlMixin.__init__(self,
                                   preClass,
                                   parent,
                                   properties=properties,
                                   attProperties=attProperties,
                                   *args,
                                   **kwargs)

    def GetValue(self):
        """
		This control doesn't natively support values, as it is designed
		to simply order and/or edit the list. We need to provide this so that
		the dControlMixin code which calls GetValue() doesn't barf.
		"""
        return None

    def layout(self):
        """
		Calling the native Layout() method isn't sufficient, as it doesn't seem
		to call the top panel's Layout(). So we'll do it manually.
		"""
        self.Layout()
        self._Panel.Layout()
        if self.Application.Platform == "Win":
            self.refresh()

    ## property get/set methods follow ##
    def _getAddButton(self):
        if self._addButton is None:
            self._addButton = self.GetNewButton()
        return self._addButton

    def _getCanAdd(self):
        return self._canAdd

    def _setCanAdd(self, val):
        if self._constructed():
            self._canAdd = val
            self._AddButton.Show(val)
            self.layout()
        else:
            self._properties["CanAdd"] = val

    def _getCanDelete(self):
        return self._canDelete

    def _setCanDelete(self, val):
        if self._constructed():
            self._canDelete = val
            self._DeleteButton.Show(val)
            self.layout()
        else:
            self._properties["CanDelete"] = val

    def _getCanOrder(self):
        return self._canOrder

    def _setCanOrder(self, val):
        if self._constructed():
            self._canOrder = val
            self._UpButton.Show(val)
            self._DownButton.Show(val)
        else:
            self._properties["CanOrder"] = val
        self.layout()

    def _getCaption(self):
        return self._Panel.GetChildren()[0].GetLabel()

    def _setCaption(self, val):
        if self._constructed():
            self._Panel.GetChildren()[0].SetLabel(val)
        else:
            self._properties["Caption"] = val

    def _getChoices(self):
        return self.GetStrings()

    def _setChoices(self, val):
        if self._constructed():
            self.SetStrings(val)
        else:
            self._properties["Choices"] = val

    def _getDeleteButton(self):
        if self._deleteButton is None:
            self._deleteButton = self.GetDelButton()
        return self._deleteButton

    def _getDownButton(self):
        if self._downButton is None:
            self._downButton = self.GetDownButton()
        return self._downButton

    def _getEditable(self):
        return self._editable

    def _setEditable(self, val):
        if self._constructed():
            self._editable = val
            self._EditButton.Show(val)
            self.layout()
        else:
            self._properties["Editable"] = val

    def _getEditButton(self):
        if self._editButton is None:
            self._editButton = self.GetEditButton()
        return self._editButton

    def _getPanel(self):
        if self._panel is None:
            self._panel = [
                pp for pp in self.Children if isinstance(pp, wx.Panel)
            ][0]
        return self._panel

    def _getUpButton(self):
        if self._upButton is None:
            self._upButton = self.GetUpButton()
        return self._upButton

    _AddButton = property(_getAddButton, None, None,
                          _("Reference to the new item button  (wx.Button)"))

    CanAdd = property(
        _getCanAdd, _setCanAdd, None,
        _("Determines if the user can add new entries to the list  (bool)"))
    DynamicCanAdd = makeDynamicProperty(CanAdd)

    CanDelete = property(
        _getCanDelete, _setCanDelete, None,
        _("Determines if the user can delete entries from the list  (bool)"))
    DynamicCanDelete = makeDynamicProperty(CanDelete)

    CanOrder = property(_getCanOrder, _setCanOrder, None,
                        _("Determines if the user can re-order items  (bool)"))
    DynamicCanOrder = makeDynamicProperty(CanOrder)

    Caption = property(
        _getCaption, _setCaption, None,
        _("Text that appears in the top panel of the control  (str)"))
    DynamicCaption = makeDynamicProperty(Caption)

    Choices = property(
        _getChoices, _setChoices, None,
        _("List that contains the entries in the control  (list)"))

    _DeleteButton = property(
        _getDeleteButton, None, None,
        _("Reference to the delete item button  (wx.Button)"))

    _DownButton = property(
        _getDownButton, None, None,
        _("Reference to the move item down button  (wx.Button)"))

    Editable = property(
        _getEditable, _setEditable, None,
        _("Determines if the user can change existing entries  (bool)"))
    DynamicEditable = makeDynamicProperty(Editable)

    _EditButton = property(_getEditButton, None, None,
                           _("Reference to the edit item button  (wx.Button)"))

    _Panel = property(
        _getPanel, None, None,
        _("""Reference to the panel that contains the caption
			and buttons  (wx.Panel)"""))

    _UpButton = property(
        _getUpButton, None, None,
        _("Reference to the move item up button  (wx.Button)"))
예제 #20
0
class dSplitForm(dabo.ui.dForm):
    def __init__(self, *args, **kwargs):
        self._splitter = None
        super(dSplitForm, self).__init__(*args, **kwargs)

    def unsplit(self):
        self.Splitter.unsplit()

    def split(self, dir=None):
        self.Splitter.split(dir)

    def _getMinPanelSize(self):
        return self.Splitter.MinPanelSize

    def _setMinPanelSize(self, val):
        if self._constructed():
            self.Splitter.MinPanelSize = val
        else:
            self._properties["MinPanelSize"] = val

    def _getOrientation(self):
        return self.Splitter.Orientation

    def _setOrientation(self, val):
        if self._constructed():
            self.Splitter.Orientation = val
        else:
            self._properties["MinPanelSize"] = val

    def _getPanel1(self):
        return self.Splitter.Panel1

    def _setPanel1(self, pnl):
        if self._constructed():
            self.Splitter.Panel1 = pnl
        else:
            self._properties["Panel1"] = pnl

    def _getPanel2(self):
        return self.Splitter.Panel2

    def _setPanel2(self, pnl):
        if self._constructed():
            self.Splitter.Panel2 = pnl
        else:
            self._properties["Panel2"] = pnl

    def _getSashPosition(self):
        return self.Splitter.SashPosition

    def _setSashPosition(self, val):
        if self._constructed():
            self.Splitter.SashPosition = val
        else:
            self._properties["SashPosition"] = val

    def _getSplitter(self):
        if self._splitter is None:
            win = self._splitter = dSplitter(self,
                                             createPanes=True,
                                             createSizers=True,
                                             RegID="MainSplitter")

            def addToSizer(frm, itm):
                if not frm.Sizer:
                    dabo.ui.callAfter(addToSizer, frm, itm)
                else:
                    frm.Sizer.append1x(itm)
                    frm.layout()

            win.Visible = True
            dabo.ui.callAfter(addToSizer, self, win)
        return self._splitter

    MinPanelSize = property(
        _getMinPanelSize, _setMinPanelSize, None,
        _("Controls the minimum width/height of the panels.  (int)"))

    Orientation = property(
        _getOrientation, _setOrientation, None,
        _("Determines if the window splits Horizontally or Vertically.  (str)")
    )

    Panel1 = property(_getPanel1, _setPanel1, None,
                      _("Returns the Top/Left panel.  (SplitterPanel)"))

    Panel2 = property(_getPanel2, _setPanel2, None,
                      _("Returns the Bottom/Right panel.  (SplitterPanel)"))

    SashPosition = property(
        _getSashPosition, _setSashPosition, None,
        _("Position of the sash when the window is split.  (int)"))

    Splitter = property(
        _getSplitter, None, None,
        _("Reference to the main splitter in the form  (dSplitter"))

    DynamicMinPanelSize = makeDynamicProperty(MinPanelSize)
    DynamicOrientation = makeDynamicProperty(Orientation)
    DynamicSashPosition = makeDynamicProperty(SashPosition)
예제 #21
0
파일: dTreeView.py 프로젝트: xfxf/dabo
class dNode(dObject):
    """Wrapper class for the tree nodes."""
    def __init__(self, tree, itemID, parent):
        self._baseClass = dNode
        self.tree = tree
        # The 'itemID' in this case is a wxPython wx.TreeItemID object used
        # by wx to work with separate nodes.
        self.itemID = itemID
        self.parent = parent
        # Nodes can have objects associated with them
        self._object = None
        # Nodes can also be associated with a file path
        self._filePath = None
        # Custom text to display as a tooltip
        self._toolTipText = None
        # Add minimal Dabo functionality
        self.afterInit()

    def afterInit(self):
        pass

    def expand(self):
        self.tree.expand(self)

    def collapse(self):
        self.tree.collapse(self)

    def show(self):
        self.tree.showNode(self)

    def release(self):
        self.tree.removeNode(self)

    def appendChild(self, txt):
        return self.tree.appendNode(self, txt)

    def removeChild(self, txt):
        """Removes the child node whose text matches the passed value"""
        mtch = self.tree.find(txt)
        # We have a list of matching nodes. Find the first whose parent
        # is this object, and delete it
        for m in mtch:
            if m.parent == self:
                self.tree.removeNode(m)
                break
        return

    def _onFontPropsChanged(self, evt):
        # Sent by the dFont object when any props changed. Wx needs to be notified:
        self.tree.SetItemFont(self.itemID, self.Font._nativeFont)

    def _constructed(self):
        # For compatibility with mixin props.
        return True

    # Property definition code begins here
    def _getBackColor(self):
        return self.tree.GetItemBackgroundColour(self.itemID).Get()

    def _setBackColor(self, val):
        if isinstance(val, basestring):
            val = dColors.colorTupleFromName(val)
        self.tree.SetItemBackgroundColour(self.itemID, val)

    def _getCap(self):
        try:
            ret = self.tree.GetItemText(self.itemID)
        except dabo.ui.assertionException:
            ret = ""
        return ret

    def _setCap(self, val):
        self.tree.SetItemText(self.itemID, val)

    def _getChildren(self):
        return self.tree.getChildren(self)

    def _getDescendents(self):
        return self.tree.getDescendents(self)

    def _getExpanded(self):
        return self.tree.IsExpanded(self.itemID)

    def _setExpanded(self, val):
        try:
            if val:
                self.tree.expand(self)
            else:
                self.tree.collapse(self)
        except wx._core.PyAssertionError:
            # Happens when expandAll() is called and the root node is hidden
            # especially from dTreeView.refreshDisplay()
            pass

    def _getFont(self):
        if hasattr(self, "_font"):
            v = self._font
        else:
            v = self.Font = dabo.ui.dFont(
                _nativeFont=self.tree.GetItemFont(self.itemID))
        return v

    def _setFont(self, val):
        assert isinstance(val, dabo.ui.dFont)
        self._font = val
        if not self.IsRootNode or self.tree.ShowRootNode:
            # On some platforms exception is raised while operation
            # on hidden root node.
            self.tree.SetItemFont(self.itemID, val._nativeFont)
            val.bindEvent(dEvents.FontPropertiesChanged,
                          self._onFontPropsChanged)
            dabo.ui.callAfterInterval(100, self.tree.refreshDisplay)

    def _getFontBold(self):
        try:
            return self.Font.Bold
        except AttributeError:
            return False

    def _setFontBold(self, val):
        self.Font.Bold = val
        dabo.ui.callAfterInterval(100, self.tree.refreshDisplay)

    def _getFontDescription(self):
        try:
            return self.Font.Description
        except AttributeError:
            return ""

    def _getFontInfo(self):
        try:
            return self.Font._nativeFont.GetNativeFontInfoDesc()
        except AttributeError:
            return ""

    def _getFontItalic(self):
        try:
            return self.Font.Italic
        except AttributeError:
            return False

    def _setFontItalic(self, val):
        self.Font.Italic = val
        dabo.ui.callAfterInterval(100, self.tree.refreshDisplay)

    def _getFontFace(self):
        try:
            return self.Font.Face
        except AttributeError:
            return ""

    def _setFontFace(self, val):
        self.Font.Face = val
        dabo.ui.callAfterInterval(100, self.tree.refreshDisplay)

    def _getFontSize(self):
        try:
            return self.Font.Size
        except AttributeError:
            return 10

    def _setFontSize(self, val):
        self.Font.Size = val
        dabo.ui.callAfterInterval(100, self.tree.refreshDisplay)

    def _getFontUnderline(self):
        try:
            return self.Font.Underline
        except AttributeError:
            return False

    def _setFontUnderline(self, val):
        self.Font.Underline = val
        dabo.ui.callAfterInterval(100, self.tree.refreshDisplay)

    def _getForeColor(self):
        return self.tree.GetItemTextColour(self.itemID).Get()

    def _setForeColor(self, val):
        if isinstance(val, basestring):
            val = dColors.colorTupleFromName(val)
        self.tree.SetItemTextColour(self.itemID, val)

    def _getFullCaption(self):
        ret = self.Caption
        if self.parent:
            ret = "%s.%s" % (self.parent._getFullCaption(), ret)
        return ret

    def _getImg(self):
        return self.tree.getNodeImg(self)

    def _setImg(self, key):
        return self.tree.setNodeImg(self, key)
        dabo.ui.callAfterInterval(100, self.tree.refreshDisplay)

    def _getIsRootNode(self):
        try:
            ret = self._isRootNode
        except AttributeError:
            ret = self._isRootNode = (self.tree.GetRootItem() == self.itemID)
        return ret

    def _getObject(self):
        return self._object

    def _setObject(self, val):
        if self._constructed():
            self._object = val
        else:
            self._properties["Object"] = val

    def _getSel(self):
        sel = self.tree.Selection
        if isinstance(sel, list):
            ret = self in sel
        else:
            ret = (self == sel)
        return ret

    def _setSel(self, val):
        self.tree.SelectItem(self.itemID, val)

    def _getSiblings(self):
        return self.tree.getSiblings(self)

    def _getToolTipText(self):
        return self._toolTipText

    def _setToolTipText(self, val):
        if self._constructed():
            self._toolTipText = val
        else:
            self._properties["ToolTipText"] = val

    BackColor = property(
        _getBackColor, _setBackColor, None,
        _("Background color of this node  (str, 3-tuple, or wx.Colour)"))

    Caption = property(_getCap, _setCap, None,
                       _("Returns/sets the text of this node.  (str)"))

    Children = property(
        _getChildren, None, None,
        _("List of all nodes for which this is their parent node.  (list of dNodes)"
          ))

    Descendents = property(
        _getDescendents, None, None,
        _("List of all nodes for which this node is a direct ancestor.  (list of dNodes)"
          ))

    Expanded = property(
        _getExpanded, _setExpanded, None,
        _("Represents whether the node is Expanded (True) or collapsed.  (bool)"
          ))

    Font = property(_getFont, _setFont, None,
                    _("The font properties of the node. (obj)"))

    FontBold = property(_getFontBold, _setFontBold, None,
                        _("Specifies if the node font is bold-faced. (bool)"))

    FontDescription = property(
        _getFontDescription, None, None,
        _("Human-readable description of the node's font settings. (str)"))

    FontFace = property(_getFontFace, _setFontFace, None,
                        _("Specifies the font face for the node. (str)"))

    FontInfo = property(
        _getFontInfo, None, None,
        _("Specifies the platform-native font info string for the node. Read-only. (str)"
          ))

    FontItalic = property(
        _getFontItalic, _setFontItalic, None,
        _("Specifies whether the node's font is italicized. (bool)"))

    FontSize = property(
        _getFontSize, _setFontSize, None,
        _("Specifies the point size of the node's font. (int)"))

    FontUnderline = property(
        _getFontUnderline, _setFontUnderline, None,
        _("Specifies whether node text is underlined. (bool)"))

    ForeColor = property(
        _getForeColor, _setForeColor, None,
        _("Foreground (text) color of this node  (str, 3-tuple, or wx.Colour)")
    )

    FullCaption = property(
        _getFullCaption, None, None,
        _("Full dot-separated string of the captions of this node and its ancestors (read-only) (str)"
          ))

    Image = property(
        _getImg, _setImg, None,
        _("""Sets the image that is displayed on the node. This is
			determined by the key value passed, which must refer to an
			image already added to the parent tree. 	When used to retrieve
			an image, it returns the index of the node's image in the parent
			tree's image list.   (int)"""))

    IsRootNode = property(
        _getIsRootNode, None, None,
        _("Returns True if this is the root node (read-only) (bool)"))

    Object = property(
        _getObject, _setObject, None,
        _("Optional object associated with this node. Default=None  (object)"))

    Selected = property(_getSel, _setSel, None,
                        _("Is this node selected?.  (bool)"))

    Siblings = property(
        _getSiblings, None, None,
        _("List of all nodes with the same parent node.  (list of dNodes)"))

    ToolTipText = property(
        _getToolTipText, _setToolTipText, None,
        _("""Text to display when the mouse hovers over this node. The tree's
			UseNodeToolTips property must be True for this to have any effect.  (str)"""
          ))

    DynamicBackColor = makeDynamicProperty(BackColor)
    DynamicCaption = makeDynamicProperty(Caption)
    DynamicFont = makeDynamicProperty(Font)
    DynamicFontBold = makeDynamicProperty(FontBold)
    DynamicFontFace = makeDynamicProperty(FontFace)
    DynamicFontItalic = makeDynamicProperty(FontItalic)
    DynamicFontSize = makeDynamicProperty(FontSize)
    DynamicFontUnderline = makeDynamicProperty(FontUnderline)
    DynamicForeColor = makeDynamicProperty(ForeColor)
    DynamicImage = makeDynamicProperty(Image)
    DynamicSelected = makeDynamicProperty(Selected)
    DynamicToolTipText = makeDynamicProperty(ToolTipText)
예제 #22
0
파일: dBitmapButton.py 프로젝트: xfxf/dabo
class dBitmapButton(cm.dControlMixin, dim.dImageMixin, wx.BitmapButton):
    """
	Creates a button with a picture.

	The button can have up to three pictures associated with it:

		Picture: the normal picture shown on the button.
		DownPicture: the picture displayed when the button is depressed.
		FocusPicture: the picture displayed when the button has the focus.

	Otherwise, dBitmapButton behaves the same as a normal dButton.
	"""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 *args,
                 **kwargs):
        self._baseClass = dBitmapButton
        preClass = wx.PreBitmapButton
        # Initialize the self._*picture attributes
        self._picture = self._downPicture = self._focusPicture = ""
        # These atts underlie the image sizing properties.
        self._imgScale = self._imgHt = self._imgWd = None
        # This controls whether the button automatically resizes
        # itself when its Picture changes.
        self._autoSize = False
        # On some platforms, we need to add some 'breathing room'
        # around the bitmap image in order for it to appear correctly
        self._bmpBorder = 10

        dim.dImageMixin.__init__(self)
        cm.dControlMixin.__init__(self,
                                  preClass,
                                  parent,
                                  properties=properties,
                                  attProperties=attProperties,
                                  *args,
                                  **kwargs)

    def _initEvents(self):
        super(dBitmapButton, self)._initEvents()
        self.Bind(wx.EVT_BUTTON, self._onWxHit)

    def _sizeToBitmap(self):
        if self.Picture:
            bmp = self.Bitmap
            self.Size = (bmp.GetWidth() + self._bmpBorder,
                         bmp.GetHeight() + self._bmpBorder)

    # Property get/set/del methods follow. Scroll to bottom to see the property
    # definitions themselves.

    def _getAutoSize(self):
        return self._autoSize

    def _setAutoSize(self, val):
        self._autoSize = val

    def _getBmpBorder(self):
        return self._bmpBorder

    def _setBmpBorder(self, val):
        self._bmpBorder = val
        if self._autoSize:
            self._sizeToBitmap()

    def _getBorderStyle(self):
        if self._hasWindowStyleFlag(wx.BU_AUTODRAW):
            return "Simple"
        elif self._hasWindowStyleFlag(wx.NO_BORDER):
            return "None"
        else:
            return "Default"

    def _setBorderStyle(self, val):
        self._delWindowStyleFlag(wx.NO_BORDER)
        self._delWindowStyleFlag(wx.BU_AUTODRAW)

        if val == "None":
            self._addWindowStyleFlag(wx.NO_BORDER)
        elif val == "Simple":
            self._addWindowStyleFlag(wx.BU_AUTODRAW)

    def _getCancelButton(self):
        # need to implement
        return False

    def _setCancelButton(self, val):
        warnings.warn(_("CancelButton isn't implemented yet."), Warning)

    def _getDefaultButton(self):
        if self.Parent is not None:
            return self.Parent.GetDefaultItem() == self
        else:
            return False

    def _setDefaultButton(self, val):
        if self._constructed():
            if val:
                if self.Parent is not None:
                    self.Parent.SetDefaultItem(self._pemObject)
            else:
                if self._pemObject.GetParent().GetDefaultItem(
                ) == self._pemObject:
                    # Only change the default item to None if it wasn't self: if another object
                    # is the default item, setting self.DefaultButton = False shouldn't also set
                    # that other object's DefaultButton to False.
                    self.SetDefaultItem(None)
        else:
            self._properties["DefaultButton"] = val

    def _getDownBitmap(self):
        return self.GetBitmapSelected()

    def _getDownPicture(self):
        return self._downPicture

    def _setDownPicture(self, val):
        self._downPicture = val
        if self._constructed():
            if isinstance(val, wx.Bitmap):
                bmp = val
            else:
                bmp = dabo.ui.strToBmp(val, self._imgScale, self._imgWd,
                                       self._imgHt)
            self.SetBitmapSelected(bmp)
        else:
            self._properties["DownPicture"] = val

    def _getFocusBitmap(self):
        return self.GetBitmapFocus()

    def _getFocusPicture(self):
        return self._focusPicture

    def _setFocusPicture(self, val):
        self._focusPicture = val
        if self._constructed():
            if isinstance(val, wx.Bitmap):
                bmp = val
            else:
                bmp = dabo.ui.strToBmp(val, self._imgScale, self._imgWd,
                                       self._imgHt)
            self.SetBitmapFocus(bmp)
        else:
            self._properties["FocusPicture"] = val

    def _getNormalBitmap(self):
        return self.GetBitmapLabel()

    def _getNormalPicture(self):
        return self._picture

    def _setNormalPicture(self, val):
        self._picture = val
        if self._constructed():
            if isinstance(val, wx.Bitmap):
                bmp = val
            else:
                bmp = dabo.ui.strToBmp(val, self._imgScale, self._imgWd,
                                       self._imgHt)
            self.SetBitmapLabel(bmp)
            # If the others haven't been specified, default them to the same
            if not self._downPicture:
                self.SetBitmapSelected(bmp)
            if not self._focusPicture:
                self.SetBitmapFocus(bmp)
            if self._autoSize:
                self._sizeToBitmap()
        else:
            self._properties["Picture"] = val

    # Property definitions:
    AutoSize = property(
        _getAutoSize, _setAutoSize, None,
        _("Controls whether the button resizes when the Picture changes. (bool)"
          ))

    Bitmap = property(
        _getNormalBitmap, None, None,
        _("""The bitmap normally displayed on the button.  (wx.Bitmap)"""))

    BitmapBorder = property(
        _getBmpBorder, _setBmpBorder, None,
        _("""Extra space around the bitmap, used when auto-sizing.  (int)"""))

    BorderStyle = property(
        _getBorderStyle, _setBorderStyle, None,
        _("""Specifies the type of border for this window. (String).

				Possible choices are:
					"None" - No border
					"Simple" - Border like a regular button
			"""))

    CancelButton = property(
        _getCancelButton, _setCancelButton, None,
        _("Specifies whether this Bitmap button gets clicked on -Escape-."))

    DefaultButton = property(
        _getDefaultButton, _setDefaultButton, None,
        _("Specifies whether this Bitmap button gets clicked on -Enter-."))

    DownBitmap = property(
        _getDownBitmap, None, None,
        _("The bitmap displayed on the button when it is depressed.  (wx.Bitmap)"
          ))

    DownPicture = property(
        _getDownPicture, _setDownPicture, None,
        _("Specifies the image displayed on the button when it is depressed.  (str)"
          ))

    FocusBitmap = property(
        _getFocusBitmap, None, None,
        _("The bitmap displayed on the button when it receives focus.  (wx.Bitmap)"
          ))

    FocusPicture = property(
        _getFocusPicture, _setFocusPicture, None,
        _("Specifies the image displayed on the button when it receives focus.  (str)"
          ))

    Picture = property(
        _getNormalPicture, _setNormalPicture, None,
        _("""Specifies the image normally displayed on the button.  This is the
		default if none of the other Picture properties are
		specified.  (str)"""))

    DynamicAutoSize = makeDynamicProperty(AutoSize)
    DynamicBitmap = makeDynamicProperty(Bitmap)
    DynamicBitmapBorder = makeDynamicProperty(BitmapBorder)
    DynamicCancelButton = makeDynamicProperty(CancelButton)
    DynamicDefaultButton = makeDynamicProperty(DefaultButton)
    DynamicDownBitmap = makeDynamicProperty(DownBitmap)
    DynamicDownPicture = makeDynamicProperty(DownPicture)
    DynamicFocusBitmap = makeDynamicProperty(FocusBitmap)
    DynamicFocusPicture = makeDynamicProperty(FocusPicture)
    DynamicPicture = makeDynamicProperty(Picture)
예제 #23
0
	def _getValue(self):
		return self.GetValue()

	def _setValue(self, val):
		if self._constructed():
			currVal = self.Value
			if type(currVal) != type(val):
				val = self._coerceValue(val, currVal)
			if (type(currVal) != type(val) or currVal != val):
				setter = self.SetValue
				if hasattr(self, "ChangeValue"):
					setter = self.ChangeValue
				try:
					setter(val)
				except (TypeError, ValueError), e:
					nm = self._name
					dabo.log.error(_("Could not set value of %(nm)s to %(val)s. Error message: %(e)s")
							% locals())
			self._afterValueChanged()
		else:
			self._properties["Value"] = val


	Value = property(_getValue, _setValue, None,
			_("""Specifies the current state of the control (the value of the field).  (varies)"""))


	DynamicValue = makeDynamicProperty(Value)

예제 #24
0
	MaxValue = property(_getMaxValue, _setMaxValue, None,
		_("""Holds upper value limit. (date, tuple, str)(Default=None)"""))

	MinValue = property(_getMinValue, _setMinValue, None,
		_("""Holds lower value limit. (date, tuple, str)(Default=None)"""))

	PickerMode = property(_getPickerMode, _setPickerMode, None,
		_("""Creates control with spin or dropdown calendar. (str)
		Available values are:
			- Spin
			- Dropdown (default)"""))

	ValueMode = property(_getValueMode, _setValueMode, None,
		_("""Enables handling Timestamp type. (str)(Default="Date")"""))

	DynamicMaxValue = makeDynamicProperty(MaxValue)
	DynamicMinValue = makeDynamicProperty(MinValue)


if __name__ == "__main__":
	import datetime
	import test

	class TestBase(dDatePicker):

		def onValueChanged(self, evt):
			print "onValueChanged"

	test.Test().runTest(TestBase, AllowNullDate=True, Value=datetime.date(1970,12,03))
	test.Test().runTest(TestBase, BackColor="orange", PickerMode="Spin", AllowNullDate=True)
예제 #25
0
class dPage(dabo.ui.dScrollPanel):
    """Creates a page to appear as a tab in a pageframe."""
    def __init__(self, *args, **kwargs):
        self._caption = ""
        self._pendingUpdates = False
        self._deferredUpdates = False
        kwargs["AlwaysResetSizer"] = self._extractKey(kwargs,
                                                      "AlwaysResetSizer", True)
        super(dPage, self).__init__(*args, **kwargs)
        self._baseClass = dPage

    def _afterInit(self):
        self.initSizer()
        self.itemsCreated = False
        super(dPage, self)._afterInit()

    def _initEvents(self):
        super(dPage, self)._initEvents()
        self.bindEvent(dEvents.PageEnter, self.__onPageEnter)
        self.bindEvent(dEvents.PageLeave, self.__onPageLeave)

    def initSizer(self):
        """Set up the default vertical box sizer for the page."""
        try:
            szCls = self.Parent.PageSizerClass
        except AttributeError:
            # Not part of a paged control
            return
        if szCls is not None:
            self.Sizer = szCls("vertical")

    def _createItems(self):
        self.lockDisplay()
        self.createItems()
        self.itemsCreated = True
        self.layout()
        dabo.ui.callAfter(self.unlockDisplay)

    def createItems(self):
        """
		Create the controls in the page.

		Called when the page is entered for the first time, allowing subclasses
		to delay-populate the page.
		"""
        pass

    def update(self):
        if self.DeferredUpdates:
            try:
                if self.Parent.SelectedPage == self:
                    self._pendingUpdates = False
                else:
                    self._pendingUpdates = True
                    return
            except (ValueError, AttributeError):
                pass
        super(dPage, self).update()

    def __onPageEnter(self, evt):
        if not self.itemsCreated:
            self._createItems()
        if self._pendingUpdates:
            dabo.ui.callAfter(self.update)

    def __onPageLeave(self, evt):
        if hasattr(self, "Form"):
            form = self.Form
            if hasattr(form, "activeControlValid"):
                form.activeControlValid()

    def _saveLastActiveControl(self):
        self._lastFocusedControl = self.Form.ActiveControl

    def _restoreLastActiveControl(self):
        if getattr(self, "_lastFocusedControl", None):
            self.Form.ActiveControl = self._lastFocusedControl

    def _getPagePosition(self):
        """Returns the position of this page within its parent."""
        try:
            ret = self.Parent.Pages.index(self)
        except (ValueError, AttributeError):
            ret = -1
        return ret

    def _getCaption(self):
        # Need to determine which page we are
        ret = ""
        pos = self._getPagePosition()
        if pos > -1:
            ret = self.Parent.GetPageText(pos)
        if not ret:
            ret = self._caption
        return ret

    def _setCaption(self, val):
        self._caption = val
        if self._constructed():
            pos = self._getPagePosition()
            if pos > -1:
                self.Parent.SetPageText(pos, val)
        else:
            self._properties["Caption"] = val

    def _getDeferredUpdates(self):
        return self._deferredUpdates

    def _setDeferredUpdates(self, val):
        self._deferredUpdates = val

    def _getImage(self):
        return self.Parent.getPageImage(self)

    def _setImage(self, imgKey):
        if self._constructed():
            self.Parent.setPageImage(self, imgKey)
        else:
            self._properties["Image"] = imgKey

    Caption = property(_getCaption, _setCaption, None,
                       _("The text identifying this particular page.  (str)"))

    DeferredUpdates = property(
        _getDeferredUpdates, _setDeferredUpdates, None,
        _("Allow to defer controls updates until page become active.  (bool)"))

    Image = property(
        _getImage, _setImage, None,
        _("""Sets the image that is displayed on the page tab. This is
			determined by the key value passed, which must refer to an
			image already added to the parent pageframe.
			When used to retrieve an image, it returns the index of the
			page's image in the parent pageframe's image list.   (int)"""))

    DynamicCaption = makeDynamicProperty(Caption)
    DynamicImage = makeDynamicProperty(Image)
예제 #26
0
class dLabel(cm.dControlMixin, AlignmentMixin, wx.StaticText):
	"""Creates a static label, to make a caption for another control, for example."""
	_layout_on_set_caption = True

	def __init__(self, parent, properties=None, attProperties=None, *args, **kwargs):
		self._baseClass = dLabel
		self._wordWrap = False
		self._inResizeEvent = False
		self._resetAutoResize = True
		preClass = wx.PreStaticText
		cm.dControlMixin.__init__(self, preClass, parent, properties=properties,
				attProperties=attProperties, *args, **kwargs)
		self.bindEvent(dEvents.Resize, self.__onResize)


	def __onResize(self, evt):
		"""
		Event binding is set when WordWrap=True. Tell the label
		to wrap to its current width.
		"""
		if self.WordWrap:
			if self._inResizeEvent:
				return
			self._inResizeEvent = True
			dabo.ui.callAfterInterval(100, self.__resizeExecute)


	def __resizeExecute(self):
		# We need to set the caption to the internally-saved caption, since
		# WordWrap can introduce additional linefeeds.
		try:
			self.Parent.lockDisplay()
		except dabo.ui.deadObjectException:
			# Form is being destroyed; bail
			return
		self.SetLabel(self._caption)
		wd = {True: self.Width, False: -1}[self.WordWrap]
		self.Wrap(wd)
		dabo.ui.callAfterInterval(50, self.__endResize)


	def __endResize(self):
		"""
		To prevent infinite loops while resizing, the _inResizeEvent
		flag must be reset outside of the execution method.
		"""
		self.Parent.unlockDisplayAll()
		self._inResizeEvent = False


	# property get/set functions
	def _getAutoResize(self):
		return not self._hasWindowStyleFlag(wx.ST_NO_AUTORESIZE)

	def _setAutoResize(self, val):
		self._delWindowStyleFlag(wx.ST_NO_AUTORESIZE)
		if not val:
			self._addWindowStyleFlag(wx.ST_NO_AUTORESIZE)


	def _getFontBold(self):
		return super(dLabel, self)._getFontBold()

	def _setFontBold(self, val):
		super(dLabel, self)._setFontBold(val)
		if self._constructed():
			# This will force an auto-resize
			self.SetLabel(self.GetLabel())


	def _getFontFace(self):
		return super(dLabel, self)._getFontFace()

	def _setFontFace(self, val):
		super(dLabel, self)._setFontFace(val)
		if self._constructed():
			# This will force an auto-resize
			self.SetLabel(self.GetLabel())


	def _getFontItalic(self):
		return super(dLabel, self)._getFontItalic()

	def _setFontItalic(self, val):
		super(dLabel, self)._setFontItalic(val)
		if self._constructed():
			# This will force an auto-resize
			self.SetLabel(self.GetLabel())


	def _getFontSize(self):
		return super(dLabel, self)._getFontSize()

	def _setFontSize(self, val):
		super(dLabel, self)._setFontSize(val)
		if self._constructed():
			# This will force an auto-resize
			self.SetLabel(self.GetLabel())


	def _getWordWrap(self):
		return self._wordWrap

	def _setWordWrap(self, val):
		if self._constructed():
			changed = (self._wordWrap != val)
			if not changed:
				return
			self._wordWrap = val
			if val:
				# Make sure AutoResize is False.
				if self.AutoResize:
					self._resetAutoResize = True
					self.AutoResize = False
				try:
					dabo.ui.callAfter(self.Parent.layout)
				except AttributeError:
					# Parent has no layout() method.
					pass
			else:
				# reset the value
				self.AutoResize = self._resetAutoResize
			self.__resizeExecute()
		else:
			self._properties["WordWrap"] = val


	# property definitions follow:
	AutoResize = property(_getAutoResize, _setAutoResize, None,
			_("""Specifies whether the length of the caption determines
			the size of the label. This cannot be True if WordWrap is
			also set to True. Default=True.  (bool)""") )

	FontBold = property(_getFontBold, _setFontBold, None,
			_("Sets the Bold of the Font (int)") )

	FontFace = property(_getFontFace, _setFontFace, None,
			_("Sets the face of the Font (int)") )

	FontItalic = property(_getFontItalic, _setFontItalic, None,
			_("Sets the Italic of the Font (int)") )

	FontSize = property(_getFontSize, _setFontSize, None,
			_("Sets the size of the Font (int)") )

	WordWrap = property(_getWordWrap, _setWordWrap, None,
			_("""When True, the Caption is wrapped to the Width. Note
			that the control must have sufficient Height to display any
			wrapped text.
			Default=False  (bool)"""))


	DynamicFontBold = makeDynamicProperty(FontBold)
	DynamicFontFace = makeDynamicProperty(FontFace)
	DynamicFontItalic = makeDynamicProperty(FontItalic)
	DynamicFontSize = makeDynamicProperty(FontSize)
	DynamicWordWrap = makeDynamicProperty(WordWrap)
예제 #27
0
class dSpinner(dabo.ui.dDataPanel, wx.Control):
    """
	Control for allowing a user to increment a value by discreet steps across a range
	of valid values.
	"""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 TextBoxClass=None,
                 *args,
                 **kwargs):
        self.__constructed = False
        self._spinWrap = False
        self._min = 0
        self._max = 100
        self._increment = 1
        nm = self._extractKey((properties, attProperties, kwargs), "NameBase",
                              "")
        if not nm:
            nm = self._extractKey((properties, attProperties, kwargs), "Name",
                                  "dSpinner")
        super(dSpinner, self).__init__(parent=parent,
                                       properties=properties,
                                       attProperties=attProperties,
                                       *args,
                                       **kwargs)
        self._baseClass = dSpinner
        # Create the child controls
        if TextBoxClass is None:
            TextBoxClass = dabo.ui.dTextBox
        self._proxy_textbox = TextBoxClass(self,
                                           Value=0,
                                           Width=32,
                                           StrictNumericEntry=False,
                                           _EventTarget=self)
        self._proxy_spinner = _dSpinButton(parent=self, _EventTarget=self)
        self.__constructed = True
        self.Sizer = dabo.ui.dSizer("h")
        self.Sizer.append1x(self._proxy_textbox)
        self.Sizer.append(self._proxy_spinner, "expand")
        self.layout()

        self.Bind(wx.EVT_WINDOW_DESTROY, self.__onWxDestroy)

        # Because several properties could not be set until after the child
        # objects were created, we need to manually call _setProperties() here.
        self._properties["NameBase"] = nm
        self._setNameAndProperties(self._properties, **kwargs)
        ps = self._proxy_spinner
        pt = self._proxy_textbox
        # Set an essentially infinite range. We'll handle the range ourselves.
        ps.SetRange(-2**30, 2**30)
        # We'll also control wrapping ourselves
        self._proxy_spinner._addWindowStyleFlag(wx.SP_WRAP)
        ps.Bind(wx.EVT_SPIN_UP, self.__onWxSpinUp)
        ps.Bind(wx.EVT_SPIN_DOWN, self.__onWxSpinDown)
        #ps.Bind(wx.EVT_SPIN, self._onWxHit)
        pt.Bind(wx.EVT_TEXT, self._onWxHit)
        pt.Bind(wx.EVT_KEY_DOWN, self._onWxKeyDown)
        ps.Bind(wx.EVT_KEY_DOWN, self._onWxKeyDown)
        #self.bindEvent(dEvents.KeyChar, self._onChar)
        self._rerestoreValue()
        dabo.ui.callAfter(self.layout)

    def __onWxDestroy(self, evt):
        # This doesn't otherwise happen
        self.raiseEvent(dEvents.Destroy)

    def _rerestoreValue(self):
        # Hack because when restoreValue() was originally called in onCreate,
        # the name of the control hadn't been set yet.
        if self.SaveRestoreValue:
            self.restoreValue()
            # Additionally, if the user never changes the Value, _value will be None:
            self._value = self.Value

    def _constructed(self):
        """Returns True if the ui object has been fully created yet, False otherwise."""
        return self.__constructed

    def _toDec(self, val):
        """Convenience method for converting various types to decimal."""
        return decimal(ustr(val))

    def _toFloat(self, val):
        """Convenience method for converting various types to float."""
        return float(ustr(val))

    def _coerceTypes(self, newVal, minn, maxx, margin):
        """
		Handle the problems when min/max/increment values are
		of one type, and the edited value another.
		"""
        typN = type(newVal)
        # Only problem here is Decimal and float combinations
        if typN == decimal:
            margin = self._toDec(margin)
            if type(maxx) == float:
                maxx = self._toDec(maxx)
            if type(minn) == float:
                minn = self._toDec(minn)
        elif typN == float:
            if type(maxx) == decimal:
                maxx = float(maxx)
            if type(minn) == decimal:
                minn = float(minn)
        return minn, maxx, margin

    def _applyIncrement(self, op):
        """
		Returns the value obtained by modifying the current value by the increment
		according to the passed operation. It expects to be passed either
		operator.add or operator.sub.
		"""
        curr = self.Value
        inc = self.Increment
        try:
            ret = op(curr, inc)
        except TypeError:
            # Usually Decimal/float problems
            tCurr = type(curr)
            if tCurr == decimal:
                ret = op(curr, self._toDec(inc))
            elif tCurr == float:
                ret = op(curr, self._toFloat(inc))
        return ret

    def _spin(self, direction, spinType=None):
        assert direction in ("up", "down")

        incrementFunc = operator.add
        margin = 0.0001
        if direction == "down":
            incrementFunc = operator.sub
            margin = -0.0001

        ret = True
        newVal = self._applyIncrement(incrementFunc)
        minn, maxx, margin = self._coerceTypes(newVal, self.Min, self.Max,
                                               margin)

        valueToSet = None

        if direction == "up":
            diff = newVal - maxx
            if diff < margin:
                valueToSet = newVal
            elif self._spinWrap:
                valueToSet = minn
            else:
                ret = False
            if ret:
                self.raiseEvent(dEvents.SpinUp, spinType=spinType)
                self.raiseEvent(dEvents.Spinner, spinType=spinType)

        else:
            diff = newVal - minn
            if diff > margin:
                valueToSet = newVal
            elif self._spinWrap:
                valueToSet = maxx
            else:
                ret = False
            if ret:
                self.raiseEvent(dEvents.SpinDown, spinType=spinType)
                self.raiseEvent(dEvents.Spinner, spinType=spinType)

        self._checkBounds()

        if ret:
            self._userChanged = True
            self.Value = valueToSet
            self._userChanged = True
            self.flushValue()
        self.raiseEvent(dEvents.Hit, hitType=spinType)
        return ret

    def __onWxSpinUp(self, evt):
        """Respond to the wx event by raising the Dabo event."""
        self._spin("up", spinType="button")

    def __onWxSpinDown(self, evt):
        """Respond to the wx event by raising the Dabo event."""
        self._spin("down", spinType="button")

    def _checkBounds(self):
        """Make sure that the value is within the current Min/Max"""
        if self._proxy_textbox.Value < self.Min:
            self._proxy_textbox.Value = self._proxy_spinner.Value = self.Min
        elif self._proxy_textbox.Value > self.Max:
            self._proxy_textbox.Value = self._proxy_spinner.Value = self.Max

    def _onWxHit(self, evt):
        # Determine what type of event caused Hit to be raised.
        if evt is None:
            typ = "key"
        elif evt.GetEventObject() is self._proxy_textbox:
            typ = "text"
        else:
            typ = "spin"
        super(dSpinner, self)._onWxHit(evt, hitType=typ)

    def _onWxKeyDown(self, evt):
        """
		Handle the case where the user presses the up/down arrows to
		activate the spinner.
		"""
        keys = dabo.ui.dKeys
        kc = evt.GetKeyCode()
        if kc in (keys.key_Up, keys.key_Numpad_up):
            self._spin("up", spinType="key")
        elif kc in (keys.key_Down, keys.key_Numpad_down):
            self._spin("down", spinType="key")
        else:
            evt.Skip()

    def flushValue(self):
        self._checkBounds()
        super(dSpinner, self).flushValue()

    def _numericStringVal(self, val):
        """
		If passed a string, attempts to convert it to the appropriate numeric
		type. If such a conversion is not possible, returns None.
		"""
        ret = val
        if isinstance(val, basestring):
            if val.count(locale.localeconv()["decimal_point"]) > 0:
                func = decimal
            else:
                func = int
            try:
                ret = func(val)
            except ValueError:
                ret = None
        return ret

    def fontZoomIn(self, amt=1):
        """Zoom in on the font, by setting a higher point size."""
        self._proxy_textbox._setRelativeFontZoom(amt)

    def fontZoomOut(self, amt=1):
        """Zoom out on the font, by setting a lower point size."""
        self._proxy_textbox._setRelativeFontZoom(-amt)

    def fontZoomNormal(self):
        """Reset the font zoom back to zero."""
        self._proxy_textbox._setAbsoluteFontZoom(0)

    def getBlankValue(self):
        return 0

    # Property get/set definitions begin here
    def _getButtonWidth(self):
        return self._proxy_spinner.Width

    def _setButtonWidth(self, val):
        if self._constructed():
            self._proxy_spinner.Width = val
        else:
            self._properties["ButtonWidth"] = val

    def _getChildren(self):
        # The native wx control will return the items that make up this composite
        # control, which our user doesn't want.
        return []

    def _getIncrement(self):
        return self._increment

    def _setIncrement(self, val):
        if self._constructed():
            self._increment = val
        else:
            self._properties["Increment"] = val

    def _getMax(self):
        return self._max

    def _setMax(self, val):
        if self._constructed():
            self._max = val
            self._checkBounds()
        else:
            self._properties["Max"] = val

    def _getMin(self):
        return self._min

    def _setMin(self, val):
        if self._constructed():
            self._min = val
            self._checkBounds()
        else:
            self._properties["Min"] = val

    def _getSpinnerWrap(self):
        return self._spinWrap

    def _setSpinnerWrap(self, val):
        if self._constructed():
            self._spinWrap = val
        else:
            self._properties["SpinnerWrap"] = val

    def _getValue(self):
        try:
            return self._proxy_textbox.Value
        except AttributeError:
            return None

    def _setValue(self, val):
        if self._constructed():
            self._proxy_textbox._inDataUpdate = self._inDataUpdate
            if isinstance(val, (int, long, float, decimal)):
                self._proxy_textbox.Value = val
            else:
                numVal = self._numericStringVal(val)
                if numVal is None:
                    dabo.log.error(
                        _("Spinner values must be numeric. Invalid:'%s'") %
                        val)
                else:
                    self._proxy_textbox.Value = val
            self._proxy_textbox._inDataUpdate = False
        else:
            self._properties["Value"] = val

    ButtonWidth = property(
        _getButtonWidth, _setButtonWidth, None,
        _("""Allows the developer to explicitly specify the width of the up/down buttons."""
          ))

    Children = property(
        _getChildren, None, None,
        _("""Returns a list of object references to the children of
			this object. Only applies to containers. Children will be None for
			non-containers.  (list or None)"""))

    Increment = property(
        _getIncrement, _setIncrement, None,
        _("Amount the control's value changes when the spinner buttons are clicked  (int/float)"
          ))

    Max = property(_getMax, _setMax, None,
                   _("Maximum value for the control  (int/float)"))

    Min = property(_getMin, _setMin, None,
                   _("Minimum value for the control  (int/float)"))

    SpinnerWrap = property(
        _getSpinnerWrap, _setSpinnerWrap, None,
        _("Specifies whether the spinner value wraps at the high/low value. (bool)"
          ))

    Value = property(_getValue, _setValue, None,
                     _("Value of the control  (int/float)"))

    DynamicIncrement = makeDynamicProperty(Increment)
    DynamicMax = makeDynamicProperty(Max)
    DynamicMin = makeDynamicProperty(Min)
    DynamicSpinnerWrap = makeDynamicProperty(SpinnerWrap)

    # Pass-through props. These are simply ways of exposing the text control's props
    # through this control
    _proxyDict = {}
    Alignment = makeProxyProperty(
        _proxyDict,
        "Alignment",
        "_proxy_textbox",
    )
    BackColor = makeProxyProperty(_proxyDict, "BackColor",
                                  ("_proxy_textbox", "self"))
    Enabled = makeProxyProperty(_proxyDict, "Enabled",
                                ("self", "_proxy_spinner", "_proxy_textbox"))
    Font = makeProxyProperty(_proxyDict, "Font", "_proxy_textbox")
    FontInfo = makeProxyProperty(_proxyDict, "FontInfo", "_proxy_textbox")
    FontSize = makeProxyProperty(_proxyDict, "FontSize", "_proxy_textbox")
    FontFace = makeProxyProperty(_proxyDict, "FontFace", "_proxy_textbox")
    FontBold = makeProxyProperty(_proxyDict, "FontBold", "_proxy_textbox")
    FontItalic = makeProxyProperty(_proxyDict, "FontItalic", "_proxy_textbox")
    FontUnderline = makeProxyProperty(_proxyDict, "FontUnderline",
                                      "_proxy_textbox")
    ForeColor = makeProxyProperty(_proxyDict, "ForeColor", "_proxy_textbox")
    Height = makeProxyProperty(_proxyDict, "Height",
                               ("self", "_proxy_spinner", "_proxy_textbox"))
    ReadOnly = makeProxyProperty(_proxyDict, "ReadOnly", "_proxy_textbox")
    SelectOnEntry = makeProxyProperty(_proxyDict, "SelectOnEntry",
                                      "_proxy_textbox")
    ToolTipText = makeProxyProperty(
        _proxyDict, "ToolTipText",
        ("self", "_proxy_spinner", "_proxy_textbox"))
    Visible = makeProxyProperty(_proxyDict, "Visible",
                                ("self", "_proxy_spinner", "_proxy_textbox"))
예제 #28
0
파일: dRadioList.py 프로젝트: xfxf/dabo
class dRadioList(cim.dControlItemMixin, wx.Panel):
    """
	Creates a group of radio buttons, allowing mutually-exclusive choices.

	Like a dDropdownList, use this to present the user with multiple choices and
	for them to choose from one of the choices. Where the dDropdownList is
	suitable for lists of one to a couple hundred choices, a dRadioList is
	really only suitable for lists of one to a dozen at most.
	"""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 *args,
                 **kwargs):
        self._baseClass = dRadioList
        self._sizerClass = dabo.ui.dBorderSizer
        self._buttonClass = _dRadioButton
        self._showBox = True
        self._caption = ""
        preClass = wx.PrePanel
        style = self._extractKey((properties, attProperties, kwargs), "style",
                                 0)
        style = style | wx.TAB_TRAVERSAL
        kwargs["style"] = style
        # Tracks individual member radio buttons.
        self._items = []
        self._selpos = 0
        # Tracks timing to determine whether any of the buttons
        # have changed focus so got/lost events can be raised
        self._lastGotFocusEvent = self._lastLostFocusEvent = 0
        # Default spacing between buttons. Can be changed with the
        # 'ButtonSpacing' property.
        self._buttonSpacing = 5

        cim.dControlItemMixin.__init__(self,
                                       preClass,
                                       parent,
                                       properties=properties,
                                       attProperties=attProperties,
                                       *args,
                                       **kwargs)

    def _resetChoices(self):
        # Need to override as the base behavior calls undefined Clear() and AppendItems()
        pass

    def getBaseButtonClass(cls):
        return _dRadioButton

    getBaseButtonClass = classmethod(getBaseButtonClass)

    def _checkSizer(self):
        """Makes sure the sizer is created before setting props that need it."""
        if self.Sizer is None:
            self.Sizer = self.SizerClass(self,
                                         orientation=self.Orientation,
                                         Caption=self.Caption)

    def _onWxHit(self, evt):
        pos = self._items.index(evt.GetEventObject())
        self.PositionValue = pos
        # This allows the event processing to properly
        # set the EventData["index"] properly.
        evt.SetInt(pos)
        self._userChanged = True
        super(dRadioList, self)._onWxHit(evt)

    def _onButtonGotFocus(self, wxEvt):
        # Received from individual buttons
        now = time.time()
        if now - self._lastLostFocusEvent > .01:
            # Newly focused; raise the event.
            # Missing uiEvent parameter in call? See note below.
            self.raiseEvent(dEvents.GotFocus)
        self._lastGotFocusEvent = now

    def _onButtonLostFocus(self, wxEvt):
        # Received from individual buttons
        now = time.time()
        self._lastLostFocusEvent = now

        @dabo.ui.deadCheck
        def checkForFocus(timeCalled):
            if timeCalled - self._lastGotFocusEvent > .01:
                # No other button has gotten focus in the intervening time
                # Don't raise event if parent form loses focus!
                # Doing it on Windows platform raises global Python exception.
                app = self.Application
                if app is None or app.ActiveForm == self.Form:
                    # Passing wxEvt as uiEvent parameter under some conditions
                    # causes Python interpreter crash or unspecified problems
                    # with GC. I decided to remove this reference for both,
                    # GotFocus and LostFocus event of control to retain symmetry.
                    self.raiseEvent(dEvents.LostFocus)

        # Normal changing selection of buttons will cause buttons to lose focus;
        # we need to see if this control has truly lost focus.
        dabo.ui.callAfter(checkForFocus, now)

    def layout(self):
        """Wrap the wx version of the call, if possible."""
        self.Layout()
        try:
            # Call the Dabo version, if present
            self.Sizer.layout()
        except AttributeError:
            pass
        if self.Application.Platform == "Win":
            self.refresh()

    def _setSelection(self, val):
        """
		Set the selected state of the buttons to match this
		control's Value.
		"""
        for pos, itm in enumerate(self._items):
            itm.SetValue(pos == val)

    def enableKey(self, itm, val=True):
        """Enables or disables an individual button, referenced by key value."""
        index = self.Keys[itm]
        self._items[index].Enabled = val

    def enablePosition(self, itm, val=True):
        """Enables or disables an individual button, referenced by position (index)."""
        self._items[itm].Enabled = val

    def enableString(self, itm, val=True):
        """Enables or disables an individual button, referenced by string display value."""
        mtch = [
            btn for btn in self.Children
            if isinstance(btn, _dRadioButton) and btn.Caption == itm
        ]
        try:
            itm = mtch[0]
            idx = self._items.index(itm)
            self._items[idx].Enabled = val
        except IndexError:
            dabo.log.error(
                _("Could not find a button with Caption of '%s'") % itm)

    def enable(self, itm, val=True):
        """
		Enables or disables an individual button.

		The itm argument specifies which button to enable/disable, and its type
		depends on the setting of self.ValueType:

			============ ====================
			"position"   The item is referenced by index position.
			"string"     The item is referenced by its string display value.
			"key"        The item is referenced by its key value.
			============ ====================

		"""
        if self.ValueMode == "position":
            self.enablePosition(itm, val)
        elif self.ValueMode == "string":
            self.enableString(itm, val)
        elif self.ValueMode == "key":
            self.enableKey(itm, val)

    def showKey(self, itm, val=True):
        """Shows or hides an individual button, referenced by key value."""
        index = self.Keys[itm]
        self._items[index].Visible = val
        self.layout()

    def showPosition(self, itm, val=True):
        """Shows or hides an individual button, referenced by position (index)."""
        self._items[itm].Visible = val
        self.layout()

    def showString(self, itm, val=True):
        """Shows or hides an individual button, referenced by string display value."""
        mtch = [btn for btn in self._items if btn.Caption == itm]
        if mtch:
            mtch[0].Visible = val
        self.layout()

    def show(self, itm, val=True):
        """
		Shows or hides an individual button.

		The itm argument specifies which button to hide/show, and its type
		depends on the setting of self.ValueType:

			============ ====================
			"position"   The item is referenced by index position.
			"string"     The item is referenced by its string display value.
			"key"        The item is referenced by its key value.
			============ ====================

		"""
        if self.ValueMode == "position":
            self.showPosition(itm, val)
        elif self.ValueMode == "string":
            self.showString(itm, val)
        elif self.ValueMode == "key":
            self.showKey(itm, val)

    def _getFudgedButtonSpacing(self):
        val = self._buttonSpacing
        if "linux" in sys.platform:
            # Buttons too widely spaced on Linux. Fudge it down...
            val -= 9
        val = (val, 0) if self.Orientation[:1].lower() == "h" else (0, val)
        return val

    # Property get/set/del methods follow. Scroll to bottom to see the property
    # definitions themselves.
    def _getButtonClass(self):
        return self._buttonClass

    def _setButtonClass(self, val):
        self._buttonClass = val

    def _getButtonSpacing(self):
        return self._buttonSpacing

    def _setButtonSpacing(self, val):
        if self._constructed():
            self._buttonSpacing = val
            self._checkSizer()
            sizer = self.Sizer
            spacing = self._getFudgedButtonSpacing()
            for itm in sizer.ChildSpacers:
                sizer.setItemProp(itm, "Spacing", spacing)
            self.layout()
        else:
            self._properties["ButtonSpacing"] = val

    def _getCaption(self):
        ret = self._caption
        if isinstance(self.Sizer, dabo.ui.dBorderSizer):
            ret = self._caption = self.Sizer.Caption
        return ret

    def _setCaption(self, val):
        if self._constructed():
            self._checkSizer()
            self._caption = val
            try:
                self.Sizer.Caption = val
            except AttributeError:
                pass
            try:
                self.Parent.layout()
            except AttributeError:
                self.layout()
        else:
            self._properties["Caption"] = val

    def _getChoices(self):
        try:
            _choices = self._choices
        except AttributeError:
            _choices = self._choices = []
        return _choices

    def _setChoices(self, choices):
        if self._constructed():
            self._checkSizer()
            # Save the current values for possible re-setting afterwards.
            old_length = len(self.Choices)
            sv = (self.KeyValue, self.StringValue, self.PositionValue)
            [itm.release() for itm in self._items]
            self._choices = choices
            self._items = []
            self.Sizer.clear()
            for idx, itm in enumerate(choices):
                style = 0
                if idx == 0:
                    if len(choices) == 1:
                        style = wx.RB_SINGLE
                    else:
                        style = wx.RB_GROUP
                else:
                    self.Sizer.appendSpacer(self._getFudgedButtonSpacing())
                btn = self.ButtonClass(self, Caption=itm, style=style)
                btn._index = idx
                self.Sizer.append(btn)
                self._items.append(btn)

            if old_length:
                # Try each saved value to restore which button is active:
                if self.Keys:
                    self.KeyValue = sv[0]

                if not self.Keys or self.KeyValue != sv[0]:
                    try:
                        self.StringValue = sv[1]
                    except ValueError:
                        self.PositionValue = sv[2]
                        if self.PositionValue != sv[2]:
                            # Bail!
                            self.PositionValue = 0
            else:
                self.PositionValue = 0

            self.layout()
        else:
            self._properties["Choices"] = choices

    def _getOrientation(self):
        return getattr(self, "_orientation", "Vertical")

    def _setOrientation(self, val):
        if self._constructed():
            self._checkSizer()
            if val[0].lower() not in "hv":
                val = "vertical"
            self._orientation = self.Sizer.Orientation = val
            # Reset button spacing also.
            self.ButtonSpacing = self.ButtonSpacing
        else:
            self._properties["Orientation"] = val

    def _getPositionValue(self):
        return self._selpos

    def _setPositionValue(self, val):
        if self._constructed():
            self._selpos = val
            self._setSelection(val)
        else:
            self._properties["PositionValue"] = val

    def _getShowBox(self):
        return self._showBox

    def _setShowBox(self, val):
        if self._constructed():
            fromSz = self.Sizer
            if fromSz is None:
                # Control hasn't been constructed yet
                dabo.ui.setAfter(self, "ShowBox", val)
                return
            self._showBox = val
            parent = fromSz.Parent
            isInSizer = fromSz.ControllingSizer is not None
            if isInSizer:
                csz = fromSz.ControllingSizer
                pos = fromSz.getPositionInSizer()
                szProps = csz.getItemProps(fromSz)
            isBorderSz = isinstance(fromSz, dabo.ui.dBorderSizer)
            needChange = (val and not isBorderSz) or (not val and isBorderSz)
            if not needChange:
                return
            if isBorderSz:
                toCls = fromSz.getNonBorderedClass()
                toSz = toCls()
            else:
                toCls = fromSz.getBorderedClass()
                toSz = toCls(parent)
                toSz.Caption = self._caption
            toSz.Orientation = fromSz.Orientation
            memberItems = fromSz.Children
            members = [fromSz.getItem(mem) for mem in memberItems]
            memberProps = dict.fromkeys(members)
            szProps = ("Border", "Proportion", "Expand", "HAlign", "VAlign",
                       "BorderSides")
            for pos, member in enumerate(members):
                pd = {}
                for sp in szProps:
                    pd[sp] = fromSz.getItemProp(memberItems[pos], sp)
                memberProps[member] = pd
            for member in members[::-1]:
                try:
                    fromSz.remove(member)
                except AttributeError:
                    # probably a spacer
                    pass
            setSizer = (parent is not None) and (parent.Sizer is fromSz)
            if setSizer:
                parent.Sizer = None
            # Delete the old sizer.
            fromSz.release()
            if setSizer:
                parent.Sizer = toSz
            if isInSizer:
                itm = csz.insert(pos, toSz)
                csz.setItemProps(itm, szProps)
            for member in members:
                itm = toSz.append(member)
                toSz.setItemProps(itm, memberProps[member])
            try:
                self.Parent.layout()
            except AttributeError:
                self.layout()
        else:
            self._properties["ShowBox"] = val

    def _getSizerClass(self):
        return self._sizerClass

    def _setSizerClass(self, val):
        self._sizerClass = val

    def _getStringValue(self):
        try:
            ret = self._items[self._selpos].Caption
        except IndexError:
            ret = None
        return ret

    def _setStringValue(self, val):
        if self._constructed():
            try:
                idx = [
                    btn._index for btn in self._items if btn.Caption == val
                ][0]
                self.PositionValue = idx
            except IndexError:
                if val is not None:
                    # No such string.
                    raise ValueError, _(
                        "No radio button matching '%s' was found.") % val
        else:
            self._properties["StringValue"] = val

    # Property definitions:
    ButtonClass = property(
        _getButtonClass, _setButtonClass, None,
        _("Class to use for the radio buttons. Default=_dRadioButton  (dRadioButton)"
          ))

    ButtonSpacing = property(
        _getButtonSpacing, _setButtonSpacing, None,
        _("Spacing in pixels between buttons in the control  (int)"))

    Caption = property(
        _getCaption, _setCaption, None,
        _("String to display on the box surrounding the control  (str)"))

    Choices = property(
        _getChoices, _setChoices, None,
        _("""Specifies the string choices to display in the list.
			-> List of strings. Read-write at runtime.
			The list index becomes the PositionValue, and the string
			becomes the StringValue."""))

    Orientation = property(
        _getOrientation, _setOrientation, None,
        _("""Specifies whether this is a vertical or horizontal RadioList.
			String. Possible values:
				'Vertical' (the default)
				'Horizontal'"""))

    PositionValue = property(
        _getPositionValue, _setPositionValue, None,
        _("""Specifies the position (index) of the selected button.
			Integer. Read-write at runtime.
			Returns the current position, or sets the current position."""))

    ShowBox = property(_getShowBox, _setShowBox, None,
                       _("Is the surrounding box visible?  (bool)"))

    SizerClass = property(
        _getSizerClass, _setSizerClass, None,
        _("Class to use for the border sizer. Default=dabo.ui.dBorderSizer  (dSizer)"
          ))

    StringValue = property(
        _getStringValue, _setStringValue, None,
        _("""Specifies the text of the selected button.
			String. Read-write at runtime.
			Returns the text of the current item, or changes the current position
			to the position with the specified text. An exception is raised if there
			is no position with matching text."""))

    DynamicOrientation = makeDynamicProperty(Orientation)
    DynamicPositionValue = makeDynamicProperty(PositionValue)
    DynamicStringValue = makeDynamicProperty(StringValue)
예제 #29
0
파일: dCheckBox.py 프로젝트: xfxf/dabo
class dCheckBox(dcm.dDataControlMixin, wx.CheckBox):
    """Creates a checkbox, allowing editing boolean values."""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 *args,
                 **kwargs):
        self._baseClass = dCheckBox
        preClass = wx.PreCheckBox
        dcm.dDataControlMixin.__init__(self,
                                       preClass,
                                       parent,
                                       properties=properties,
                                       attProperties=attProperties,
                                       *args,
                                       **kwargs)

    def _initEvents(self):
        super(dCheckBox, self)._initEvents()
        self.Bind(wx.EVT_CHECKBOX, self._onWxHit)

    def _initProperties(self):
        self._3StateToValue = {
            wx.CHK_UNCHECKED: False,
            wx.CHK_CHECKED: True,
            wx.CHK_UNDETERMINED: None
        }
        self._ValueTo3State = dict(
            [[v, k] for k, v in self._3StateToValue.iteritems()])
        super(dCheckBox, self)._initProperties()

    def _getInitPropertiesList(self):
        additional = ["ThreeState", "Alignment"]
        original = list(super(dCheckBox, self)._getInitPropertiesList())
        return tuple(original + additional)

    def _onWxHit(self, evt):
        self._userChanged = True
        self.flushValue()
        super(dCheckBox, self)._onWxHit(evt)

    def getBlankValue(self):
        return False

    # property get/set functions
    def _getAlignment(self):
        if self._hasWindowStyleFlag(wx.ALIGN_RIGHT):
            return "Right"
        else:
            return "Left"

    def _setAlignment(self, val):
        self._delWindowStyleFlag(wx.ALIGN_RIGHT)
        if val.lower()[0] == "r":
            self._addWindowStyleFlag(wx.ALIGN_RIGHT)
        elif val.lower()[0] == "l":
            pass
        else:
            raise ValueError(
                _("The only possible values are 'Left' and 'Right'."))

    def _getThreeState(self):
        return self._hasWindowStyleFlag(wx.CHK_3STATE)

    def _setThreeState(self, val):
        self._delWindowStyleFlag(wx.CHK_3STATE)
        if val == True:
            self._addWindowStyleFlag(wx.CHK_3STATE)

    def _getUserThreeState(self):
        return self._hasWindowStyleFlag(wx.CHK_ALLOW_3RD_STATE_FOR_USER)

    def _setUserThreeState(self, val):
        self._delWindowStyleFlag(wx.CHK_ALLOW_3RD_STATE_FOR_USER)
        if val == True:
            self._addWindowStyleFlag(wx.CHK_ALLOW_3RD_STATE_FOR_USER)

    def _getValue(self):
        if not self._hasWindowStyleFlag(wx.CHK_3STATE):
            return dcm.dDataControlMixin._getValue(self)
        else:
            return self._3StateToValue.get(self.Get3StateValue(), None)

    def _setValue(self, val):
        if self._constructed():
            if not self._hasWindowStyleFlag(wx.CHK_3STATE):
                dcm.dDataControlMixin._setValue(self, val)
            else:
                try:
                    state = self._ValueTo3State[val]
                except KeyError:
                    state = False
                self.Set3StateValue(state)
        else:
            self._properties["Value"] = val

    # property definitions follow:
    Alignment = property(
        _getAlignment, _setAlignment, None,
        _("""Specifies the alignment of the text.

				Left  : Checkbox to left of text (default)
				Right : Checkbox to right of text"""))

    ThreeState = property(
        _getThreeState, _setThreeState, None,
        _("""Specifies wether the checkbox support 3 states.

				True  : Checkbox supports 3 states
				False : Checkbox supports 2 states (default)"""))

    UserThreeState = property(
        _getUserThreeState, _setUserThreeState, None,
        _("""Specifies whether the user is allowed to set the third state.

				True  : User is allowed to set the third state.
				False : User isn't allowed to set the third state.(default)"""))

    Value = property(
        _getValue, _setValue, None,
        _("Specifies the current state of the control (the value of the field). (varies)"
          ))

    DynamicAlignment = makeDynamicProperty(Alignment)
    DynamicThreeState = makeDynamicProperty(ThreeState)
    DynamicUserThreeState = makeDynamicProperty(UserThreeState)
    DynamicValue = makeDynamicProperty(Value)
예제 #30
0
class dNumericBox(dtbm.dTextBoxMixin, masked.NumCtrl):
    """This is a specialized textbox class that maintains numeric values."""
    def __init__(self,
                 parent,
                 properties=None,
                 attProperties=None,
                 *args,
                 **kwargs):
        localeData = locale.localeconv()
        enc = locale.getdefaultlocale()[1]
        self._baseClass = dNumericBox
        kwargs["integerWidth"] = self._extractKey(
            (properties, attProperties, kwargs), "IntegerWidth", 10)
        kwargs["fractionWidth"] = self._extractKey(
            (properties, attProperties, kwargs), "DecimalWidth", 2)
        kwargs["Alignment"] = self._extractKey(
            (properties, attProperties, kwargs), "Alignment", "Right")
        kwargs["selectOnEntry"] = self._extractKey(
            (properties, attProperties, kwargs), "SelectOnEntry",
            self.SelectOnEntry)
        groupChar = self._extractKey((properties, attProperties, kwargs),
                                     "GroupChar",
                                     localeData["thousands_sep"].decode(enc))
        # Group char can't be empty string.
        if groupChar or groupChar >= " ":
            kwargs["groupChar"] = groupChar
            kwargs["groupDigits"] = True
        else:
            kwargs["groupChar"] = " "
            kwargs["groupDigits"] = False
        kwargs["autoSize"] = self._extractKey(
            (properties, attProperties, kwargs), "AutoWidth", True)
        kwargs["allowNegative"] = self._extractKey(
            (properties, attProperties, kwargs), "AllowNegative", True)
        kwargs["useParensForNegatives"] = self._extractKey(
            (properties, attProperties, kwargs), "ParensForNegatives", False)
        kwargs["decimalChar"] = self._extractKey(
            (properties, attProperties, kwargs), "DecimalChar",
            localeData["decimal_point"].decode(enc))
        kwargs["foregroundColour"] = self._extractKey(
            (properties, attProperties, kwargs), "ForeColor", "Black")
        kwargs["validBackgroundColour"] = self._extractKey(
            (properties, attProperties, kwargs), "BackColor",
            wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))
        kwargs["invalidBackgroundColour"] = self._extractKey(
            (properties, attProperties, kwargs), "InvalidBackColor", "Yellow")
        kwargs["signedForegroundColour"] = self._extractKey(
            (properties, attProperties, kwargs), "SignedForeColor", "Red")
        kwargs["allowNone"] = self._extractKey(
            (properties, attProperties, kwargs), "AllowNoneValue", False)
        kwargs["max"] = self._extractKey((properties, attProperties, kwargs),
                                         "MaxValue", None)
        kwargs["min"] = self._extractKey((properties, attProperties, kwargs),
                                         "MinValue", None)
        # Base class 'limited' property is inconvenient.
        kwargs["limited"] = False
        fontFace = self._extractKey((properties, attProperties, kwargs),
                                    "FontFace", "")
        if not fontFace and self.Application.Platform in ("Win", ):
            fontFace = "Tahoma"
        elif not fontFace and self.Application.Platform in ("Mac", ):
            fontFace = "Lucida Grande"
        if fontFace:
            kwargs["FontFace"] = fontFace
        dtbm.dTextBoxMixin.__init__(self, masked.NumCtrl, parent, properties,
                                    attProperties, *args, **kwargs)

    #--- Public interface.

    def flushValue(self):
        # Because dTextBoxMixin method is improper here,
        # we use superclass method instead.
        return ddcm.dDataControlMixin.flushValue(self)

    def getBlankValue(self):
        dec = self.DecimalWidth
        if dec > 0:
            return Decimal("0.%s" % ("0" * dec))
        else:
            return 0

    def GetParensForNegatives(self):
        return self._useParensForNegatives

    def update(self):
        # Be very careful! If limits across allowed value,
        # control value will be automatically reseted to default value.
        maxVal = self.MaxValue
        self.MaxValue = None
        minVal = self.MinValue
        self.MinValue = None
        super(dNumericBox, self).update()
        if not "MaxValue" in self._dynamic:
            self.MaxValue = maxVal
        if not "MinValue" in self._dynamic:
            self.MinValue = minVal

    #--- Internal class interface.

    def _initEvents(self):
        super(dNumericBox, self)._initEvents()
        self.bindEvent(dEvents.GotFocus, self._onGotFocusFix)
        self.bindEvent(dEvents.LostFocus, self._onLostFocusFix)

    def _onGotFocusFix(self, evt):
        dabo.ui.callAfter(self._fixInsertionPoint)

    def _onLostFocusFix(self, evt):
        if self.LimitValue:
            max = self.MaxValue
            min = self.MinValue
            #if (max is not None and not (max >= self._value)) or \
            #		(min is not None and not (self._value >= min)):
            #	evt.stop()
            #	self.setFocus()

    def _onWxHit(self, evt, *args, **kwargs):
        # This fix wx masked controls issue firing multiple EVT_TEXT events.
        if self._value != self.Value:
            super(dNumericBox, self)._onWxHit(evt, *args, **kwargs)

    def _fixInsertionPoint(self):
        """Fixes insertion point position when value change or
		when getting focus with mouse click."""
        if self.Enabled and not self.ReadOnly:
            dw = self.DecimalWidth
            if dw > 0:
                self.InsertionPoint = self._masklength - dw - 1
            else:
                self.InsertionPoint = self._masklength
            if self.SelectOnEntry:
                dabo.ui.callAfter(self.select, 0, self.InsertionPoint)

    #--- Properties methods.

    def _getGroupChar(self):
        if self.GetGroupDigits():
            ret = self.GetGroupChar()
        else:
            ret = None
        return ret

    def _setGroupChar(self, val):
        """Set GroupChar to None to avoid grouping."""
        if self._constructed():
            if val is None:
                self.SetGroupDigits(False)
            else:
                self.SetGroupChar(val)
                self.SetGroupDigits(True)
        else:
            self._properties["GroupChar"] = val

    def _getAllowNegative(self):
        return self.GetAllowNegative()

    def _setAllowNegative(self, val):
        if self._constructed():
            self.SetAllowNegative(val)
        else:
            self._properties["AllowNegative"] = val

    def _getAllowNoneValue(self):
        return self.GetAllowNone()

    def _setAllowNoneValue(self, val):
        if self._constructed():
            self.SetAllowNone(val)
        else:
            self._properties["AllowNoneValue"] = val

    def _getAutoWidth(self):
        return self.GetAutoSize()

    def _setAutoWidth(self, val):
        if self._constructed():
            self.SetAutoSize(val)
        else:
            self._properties["AutoWidth"] = val

    def _getLimitValue(self):
        return getattr(self, "_limitValue", False)

    def _setLimitValue(self, val):
        self._limitValue = bool(val)

    def _getMinValue(self):
        val = self.GetMin()
        if val is not None and self._lastDataType is Decimal:
            val = Decimal(str(val))
        return val

    def _setMinValue(self, val):
        if self._constructed():
            if isinstance(val, Decimal):
                val = float(val)
            self.SetMin(val)
        else:
            self._properties["MinValue"] = val

    def _getMaxValue(self):
        val = self.GetMax()
        if val is not None and self._lastDataType is Decimal:
            val = Decimal(str(val))
        return val

    def _setMaxValue(self, val):
        if self._constructed():
            if isinstance(val, Decimal):
                val = float(val)
            self.SetMax(val)
        else:
            self._properties["MaxValue"] = val

    def _getIntegerWidth(self):
        return self.GetIntegerWidth()

    def _setIntegerWidth(self, val):
        if self._constructed():
            self.SetIntegerWidth(val)
        else:
            self._properties["IntegerWidth"] = val

    def _getInvalidBackColor(self):
        return self.GetInvalidBackgroundColour()

    def _setInvalidBackColor(self, val):
        if self._constructed():
            self.SetInvalidBackgroundColour(val)
        else:
            self._properties["InvalidBackColor"] = val

    def _getDecimalChar(self):
        return self.GetDecimalChar()

    def _setDecimalChar(self, val):
        if self._constructed():
            self.SetDecimalChar(val)
        else:
            self._properties["DecimalChar"] = val

    def _getDecimalWidth(self):
        return self.GetFractionWidth()

    def _setDecimalWidth(self, val):
        if self._constructed():
            self.SetFractionWidth(val)
        else:
            self._properties["DecimalWidth"] = val

    def _getParensForNegatives(self):
        return self.GetUseParensForNegatives()

    def _setParensForNegatives(self, val):
        if self._constructed():
            self.SetUseParensForNegatives(val)
        else:
            self._properties["ParensForNegatives"] = val

    def _getSignedForeColor(self):
        return self.GetSignedForegroundColour()

    def _setSignedForeColor(self, val):
        if self._constructed():
            self.SetSignedForegroundColour(val)
        else:
            self._properties["SignedForeColor"] = val

    def _getValue(self):
        val = ddcm.dDataControlMixin._getValue(self)
        if self._lastDataType is Decimal:
            val = Decimal(str(val))
        elif self._lastDataType is NoneType:
            chkVal = int(val)
            if chkVal != val:
                val = Decimal(str(val))
            elif chkVal <> 0:
                val = chkVal
            else:
                val = None
        return val

    def _setValue(self, val):
        self._lastDataType = type(val)
        if self._lastDataType is Decimal:
            val = float(val)
        elif val is None:
            val = float(0)
        ddcm.dDataControlMixin._setValue(self, val)
        dabo.ui.callAfter(self._fixInsertionPoint)

    def _getSelectOnEntry(self):
        try:
            return self.GetSelectOnEntry()
        except AttributeError:
            return False

    def _setSelectOnEntry(self, val):
        self.SetSelectOnEntry(bool(val))

    #--- Properties definitions.

    AllowNegative = property(
        _getAllowNegative, _setAllowNegative, None,
        _("""Enables/disables negative numbers. (bool)
			Default=True"""))

    AllowNoneValue = property(
        _getAllowNoneValue, _setAllowNoneValue, None,
        _("""Enables/disables undefined value - None. (bool)
			Default=False"""))

    AutoWidth = property(
        _getAutoWidth, _setAutoWidth, None,
        _("""Indicates whether or not the control should set its own
			width based on the integer and fraction widths. (bool)
			Default=True"""))

    DecimalChar = property(
        _getDecimalChar, _setDecimalChar, None,
        _("""Defines character that will be used to represent
			the decimal point. (str)
			Default value comes from locale setting."""))

    DecimalWidth = property(
        _getDecimalWidth, _setDecimalWidth, None,
        _("""Tells how many decimal places to show for numeric value. (int)
			Default=2"""))

    GroupChar = property(
        _getGroupChar, _setGroupChar, None,
        _("""What grouping character will be used if allowed.
			If set to None, no grouping is allowed. (str)
			Default value comes from locale setting."""))

    IntegerWidth = property(
        _getIntegerWidth, _setIntegerWidth, None,
        _("""Indicates how many places to the right of any decimal point
	        should be allowed in the control. (int)
	        Default=10"""))

    InvalidBackColor = property(
        _getInvalidBackColor, _setInvalidBackColor, None,
        _("""Color value used for illegal values or values
			out-of-bounds. (str)
			Default='Yellow'"""))

    LimitValue = property(
        _getLimitValue, _setLimitValue, None,
        _("""Limit control value to Min and Max bounds. When set to True,
			if invalid, will be automatically reseted to default.
			When False, only background color will change. (bool)
			Default=False"""))

    MaxValue = property(
        _getMaxValue, _setMaxValue, None,
        _("""The maximum value that the control should allow.
			Set to None if limit is disabled. (int, decimal)
			Default=None"""))

    MinValue = property(
        _getMinValue, _setMinValue, None,
        _("""The minimum value that the control should allow.
			Set to None if limit is disabled. (int, decimal)
			Default=None"""))

    ParensForNegatives = property(
        _getParensForNegatives, _setParensForNegatives, None,
        _("""If true, this will cause negative numbers to be displayed with parens
			rather than with sign mark. (bool)
			Default=False"""))

    SelectOnEntry = property(
        _getSelectOnEntry, _setSelectOnEntry, None,
        _("""Specifies whether all text gets selected upon receiving focus. (bool)
			Default=False"""))

    SignedForeColor = property(
        _getSignedForeColor, _setSignedForeColor, None,
        _("""Color value used for negative values of the control. (str)
			Default='Red'"""))

    Value = property(
        _getValue, _setValue, None,
        _("""Specifies the current state of the control (the value of the field).
			(int, Decimal)"""))

    DynamicMaxValue = makeDynamicProperty(MaxValue)
    DynamicMinValue = makeDynamicProperty(MinValue)
예제 #31
0
파일: dBorderSizer.py 프로젝트: xfxf/dabo
class dBorderSizer(dabo.ui.dSizerMixin, wx.StaticBoxSizer):
    """
	A BorderSizer is a regular box sizer, but with a visible box around
	the perimiter. You must either create the box first and pass it to the
	dBorderSizer's constructor, or pass a parent object, and the box
	will be created for you in the constructor as a child object of the parent
	you passed.
	"""
    def __init__(self, box, orientation="h", properties=None, **kwargs):
        self._baseClass = dBorderSizer
        self._border = 0
        self._parent = None
        # Make sure that they got the params in the right order
        if isinstance(box, basestring):
            box, orientation = orientation, box
        if not isinstance(box, dabo.ui.dBox):
            prnt = box
            box = dabo.ui.dBox(prnt)
            box.sendToBack()
        # Convert Dabo orientation to wx orientation
        orient = self._extractKey((kwargs, properties), "Orientation",
                                  orientation)
        if orient[0].lower() == "v":
            orientation = wx.VERTICAL
        else:
            orientation = wx.HORIZONTAL
        wx.StaticBoxSizer.__init__(self, box, orientation)

        self._properties = {}
        # The keyword properties can come from either, both, or none of:
        #    + the properties dict
        #    + the kwargs dict
        # Get them sanitized into one dict:
        if properties is not None:
            # Override the class values
            for k, v in properties.items():
                self._properties[k] = v
        properties = self._extractKeywordProperties(kwargs, self._properties)
        self.setProperties(properties)

        if kwargs:
            # Some kwargs haven't been handled.
            bad = ", ".join(kwargs.keys())
            raise TypeError(
                ("Invalid keyword arguments passed to dBorderSizer: %s") %
                kwargs)

        # Mark the box as part of the sizer
        self.Box._belongsToBorderSizer = True

        self._afterInit()

    def getNonBorderedClass(self):
        """Return the class that is the non-border sizer version of this class."""
        return dabo.ui.dSizer

    def _getBackColor(self):
        return self.Box.BackColor

    def _setBackColor(self, val):
        self.Box.BackColor = val

    def _getBox(self):
        return self.GetStaticBox()

    def _getCaption(self):
        return self.Box.Caption

    def _setCaption(self, val):
        self.Box.Caption = val

    def _getFontBold(self):
        return self.Box.FontBold

    def _setFontBold(self, val):
        self.Box.FontBold = val

    def _getFontFace(self):
        return self.Box.FontFace

    def _setFontFace(self, val):
        self.Box.FontFace = val

    def _getFontItalic(self):
        return self.Box.FontItalic

    def _setFontItalic(self, val):
        self.Box.FontItalic = val

    def _getFontSize(self):
        return self.Box.FontSize

    def _setFontSize(self, val):
        self.Box.FontSize = val

    def _getFontUnderline(self):
        return self.Box.FontUnderline

    def _setFontUnderline(self, val):
        self.Box.FontUnderline = val

    BackColor = property(_getBackColor, _setBackColor, None,
                         _("Color of the box background  (str or tuple)"))

    Box = property(_getBox, None, None,
                   _("Reference to the box used in the sizer  (dBox)"))

    Caption = property(_getCaption, _setCaption, None,
                       _("Caption for the box  (str)"))

    FontBold = property(
        _getFontBold, _setFontBold, None,
        _("Controls the bold setting of the box caption  (bool)"))

    FontFace = property(_getFontFace, _setFontFace, None,
                        _("Controls the type face of the box caption  (str)"))

    FontItalic = property(
        _getFontItalic, _setFontItalic, None,
        _("Controls the italic setting of the box caption  (bool)"))

    FontSize = property(_getFontSize, _setFontSize, None,
                        _("Size of the box caption font  (int)"))

    FontUnderline = property(
        _getFontUnderline, _setFontUnderline, None,
        _("Controls the underline setting of the box caption  (bool)"))

    # Dynamic property declarations
    DynamicBackColor = makeDynamicProperty(BackColor)
    DynamicCaption = makeDynamicProperty(Caption)
    DynamicFontBold = makeDynamicProperty(FontBold)
    DynamicFontFace = makeDynamicProperty(FontFace)
    DynamicFontItalic = makeDynamicProperty(FontItalic)
    DynamicFontSize = makeDynamicProperty(FontSize)
    DynamicFontUnderline = makeDynamicProperty(FontUnderline)
예제 #32
0
class dScrollPanel(_PanelMixin, wx.ScrolledWindow):
	"""
	This is a basic container for controls that allows scrolling.

	Panels can contain subpanels to unlimited depth, making them quite
	flexible for many uses. Consider laying out your forms on panels
	instead, and then adding the panel to the form.
	"""
	def __init__(self, parent, properties=None, attProperties=None, *args, **kwargs):
		self._horizontalScroll = self._verticalScroll = True
		self._baseClass = dScrollPanel
		preClass = wx.PreScrolledWindow
		kwargs["AlwaysResetSizer"] = self._extractKey((properties, kwargs, attProperties), "AlwaysResetSizer", True)
		_PanelMixin.__init__(self, preClass=preClass, parent=parent, properties=properties,
				attProperties=attProperties, *args, **kwargs)
		self.SetScrollRate(10, 10)
		self.Bind(wx.EVT_SCROLLWIN, self.__onWxScrollWin)


	def __onWxScrollWin(self, evt):
		evtClass = dabo.ui.getScrollWinEventClass(evt)
		self.raiseEvent(evtClass, evt)
		evt.Skip()


	def scrollHorizontally(self, amt):
		"""Change the horizontal scroll position by 'amt' units."""
		self._scroll(amt, 0)


	def scrollVertically(self, amt):
		"""Change the vertical scroll position by 'amt' units."""
		# Y scrolling is a negative change
		self._scroll(0, -amt)


	def _scroll(self, xOff, yOff):
		x,y = self.GetViewStart()
		self.Scroll(x+xOff, y+yOff)
		dabo.ui.callAfterInterval(250, self.layout)


	def pageLeft(self):
		self.pageHorizontally(-1)
	def pageRight(self):
		self.pageHorizontally(1)
	def pageHorizontally(self, direction):
		"""Scroll horizontally one 'page' width."""
		sz = self.GetScrollPageSize(wx.HORIZONTAL)
		if sz:
			x,y = self.GetViewStart()
			self.Scroll(x + (direction * sz), y)


	def pageUp(self):
		self.pageVertically(-1)
	def pageDown(self):
		self.pageVertically(1)
	def pageVertically(self, direction):
		"""Scroll vertically one 'page' height."""
		sz = self.GetScrollPageSize(wx.VERTICAL)
		if sz:
			x,y = self.GetViewStart()
			self.Scroll(x, y + (direction * sz))


	def _getChildren(self):
		ret = super(dScrollPanel, self)._getChildren()
		return [kid for kid in ret
				if isinstance(kid, dabo.ui.dPemMixinBase.dPemMixinBase)]

	def _setChildren(self, val):
		super(dScrollPanel, self)._setChildren(val)


	def _getHorizontalScroll(self):
		return self._horizontalScroll

	def _setHorizontalScroll(self, val, do=False):
		if do:
			self._horizontalScroll = val
			self.EnableScrolling(self._horizontalScroll, self._verticalScroll)
			rt = self.GetScrollPixelsPerUnit()
			self.SetScrollRate({True:rt[0], False:0}[val], rt[1])
		else:
			# on Mac at least, this is needed when setting from the constructor.
			dabo.ui.callAfter(self._setHorizontalScroll, val, do=True)

	def _getVerticalScroll(self):
		return self._verticalScroll

	def _setVerticalScroll(self, val, do=False):
		if do:
			self._verticalScroll = val
			self.EnableScrolling(self._horizontalScroll, self._verticalScroll)
			rt = self.GetScrollPixelsPerUnit()
			self.SetScrollRate(rt[0], {True:rt[1], False:0}[val])
		else:
			dabo.ui.callAfter(self._setVerticalScroll, val, do=True)


	Children = property(_getChildren, _setChildren, None,
			_("""Child controls of this panel. This excludes the wx-specific
			scroll bars  (list of objects)"""))

	HorizontalScroll = property(_getHorizontalScroll, _setHorizontalScroll, None,
			_("Controls whether this object will scroll horizontally (default=True)  (bool)"))

	VerticalScroll = property(_getVerticalScroll, _setVerticalScroll, None,
			_("Controls whether this object will scroll vertically (default=True)  (bool)"))


	DynamicHorizontalScroll = makeDynamicProperty(HorizontalScroll)
	DynamicVerticalScroll = makeDynamicProperty(VerticalScroll)
예제 #33
0
파일: dImage.py 프로젝트: jjkalucki/dabo
				=============== ===================
				Clip            Only that part of the image that fits in the control's size is displayed
				Proportional    The image resizes to fit the control without changing its original proportions. (default)
				Stretch         The image resizes to the Height/Width of the control.
				=============== ===================
				
			"""))

	Value = property(_getValue, _setValue, None,
			_("Image content for this control  (binary img data)"))

	_Image = property(_getImg, None, None,
			_("Underlying image handler object  (wx.Image)"))


	DynamicPicture = makeDynamicProperty(Picture)
	DynamicScaleMode = makeDynamicProperty(ScaleMode)


if __name__ == "__main__":
	from dabo.dApp import dApp
	class ImgForm(dabo.ui.dForm):
		def afterInit(self):
			self.Caption = "dImage Demonstration"
			self.mainPanel = mp = dabo.ui.dPanel(self)
			self.Sizer.append1x(mp)
			sz = dabo.ui.dSizer("v")
			mp.Sizer = sz
			# Create a panel with horiz. and vert.  sliders
			self.imgPanel = dabo.ui.dPanel(mp)
			self.VSlider = dabo.ui.dSlider(mp, Orientation="V", Min=1, Max=100,
예제 #34
0
class dMenuItem(pm.dPemMixin, wx.MenuItem):
    """Creates a menu item, which is usually represented as a string."""
    def __init__(self, parent=None, properties=None, *args, **kwargs):
        self._baseClass = dMenuItem
        preClass = wx.MenuItem
        self.Parent = parent

        ## see comments in _setCaption for explanation of below:
        text = kwargs.get("text", "")
        if not text:
            text = "dMenuItem"
        kwargs["text"] = text
        # Main text of the menu item
        self._caption = ""
        # Holds the key combination used to trigger the menu
        self._hotKey = None
        # Holds the unique ID, if any
        self._itemID = None

        pm.dPemMixin.__init__(self, preClass, parent, properties, *args,
                              **kwargs)

    def _initEvents(self):
        ## wx.MenuItems don't have a Bind() of their own, so this serves to
        ## override the base behavior in dPemMixin._initEvents() which has
        ## a bunch of wx Events that don't exist for menu items (IOW, don't
        ## call the superclass method!).

        if self.Application is not None:
            # Set up a mechanism to catch menu selected events
            # and re-raise Dabo dEvents.Hit events. If Application
            # is None, however, this won't work because of wx limitations.
            self.Application.uiApp.Bind(wx.EVT_MENU, self.__onWxHit, self)
            self.Application.uiApp.Bind(wx.EVT_MENU_HIGHLIGHT,
                                        self.__onWxMenuHighlight, self)
        # Handle delayed event bindings
        if self._delayedEventBindings:
            dabo.ui.callAfter(self._bindDelayed)

    def __onWxMenuHighlight(self, evt):
        self.raiseEvent(dEvents.MenuHighlight)
        evt.Skip()

    def __onWxHit(self, evt):
        self.raiseEvent(dEvents.Hit, evt)
        evt.Skip(False)

    def _redefine(self):
        """Combine the Caption and HotKey into the format needed by wxPython."""
        cap = self.Caption
        hk = self.HotKey
        if not cap:
            return
        if hk:
            cap = "%s\t%s" % (cap, hk)
        curr = self.GetItemLabel()
        ## pkm: On Windows at least, setting the Icon needs to happen before setting the caption.
        self.SetBitmap(self.Icon)

        if ustr(cap) != ustr(curr):
            ## Win32 seems to need to clear the caption first, or funkiness
            ## can arise. And win32 in wx2.8 needs for the caption to never be
            ## an empty string, or you'll get an invalid stock id assertion.
            self.SetItemLabel(" ")
            if cap == "":
                cap = " "
            self.SetItemLabel(cap)

    def _getCaption(self):
        return self._caption

    def _setCaption(self, val):
        if self._constructed():
            tabsplit = val.split("\t")
            if len(tabsplit) > 1:
                # They're using the technique of caption + tab + hotkey
                # Override any prior setting of self.HotKey with the new one.
                self._hotKey = tabsplit[1]
            self._caption = tabsplit[0]
            self._redefine()
        else:
            self._properties["Caption"] = val

    def _getEnabled(self):
        return self.IsEnabled()

    def _setEnabled(self, val):
        if self._constructed():
            self.Enable(bool(val))
        else:
            self._properties["Enabled"] = val

    def _getForm(self):
        return self.Parent.Form

    def _getHelpText(self):
        return self.GetHelp()

    def _setHelpText(self, val):
        if self._constructed():
            self.SetHelp(val)
        else:
            self._properties["HelpText"] = val

    def _getHotKey(self):
        return self._hotKey

    def _setHotKey(self, val):
        if self._constructed():
            self._hotKey = val
            self._redefine()
        else:
            self._properties["HotKey"] = val

    def _getIcon(self):
        return self.GetBitmap()

    def _setIcon(self, val):
        if self._constructed():
            if val in (None, ""):
                return
            if isinstance(val, basestring):
                # Icon name was passed; get the actual bitmap
                val = dabo.ui.strToBmp(val)
            self.SetBitmap(val)

            # Win32 at least needs the following line, or the caption
            # will look really funky, but Linux can't have this line or
            # the underlined hotkeys will get messed up. I don't know about
            # Mac so I'll leave that alone for now:
            if wx.PlatformInfo[0] == "__WXMSW__":
                #			if self.Application.Platform in ("Win",):
                self.Caption = self.Caption
        else:
            self._properties["Icon"] = val

    def _getItemID(self):
        return self._itemID

    def _setItemID(self, val):
        if self._constructed():
            self._itemID = val
        else:
            self._properties["ItemID"] = val

    def _getParent(self):
        try:
            ret = self._parent
        except AttributeError:
            ret = self._parent = None
        return ret

    def _setParent(self, val):
        self._parent = val

    Caption = property(_getCaption, _setCaption, None,
                       _("Specifies the text of the menu item."))

    Enabled = property(
        _getEnabled, _setEnabled, None,
        _("Specifies whether the menu item can be interacted with."))

    Form = property(_getForm, None, None, _("Specifies the containing form."))

    HelpText = property(
        _getHelpText, _setHelpText, None,
        _("Specifies the help text associated with this menu. (str)"))

    HotKey = property(_getHotKey, _setHotKey, None,
                      _("Key combination that will trigger the menu  (str)"))

    Icon = property(_getIcon, _setIcon, None,
                    _("Specifies the icon for the menu item."))

    ItemID = property(
        _getItemID, _setItemID, None,
        _("""Identifying value for this menuitem. NOTE: there is no checking for
			duplicate values; it is the responsibility to ensure that ItemID values
			are unique within a menu.  (varies)"""))

    Parent = property(_getParent, _setParent, None,
                      _("Specifies the parent menu."))

    DynamicCaption = makeDynamicProperty(Caption)
    DynamicEnabled = makeDynamicProperty(Enabled)
    DynamicIcon = makeDynamicProperty(Icon)
    DynamicHelpText = makeDynamicProperty(HelpText)