Skip to content

Commit

Permalink
update the dock window
Browse files Browse the repository at this point in the history
this shifts the logic for automatically closing a dock window to the
dock window itself. The window remains open unless the child dock area
is completely empty of all content and dock bars.
  • Loading branch information
sccolbert committed Jul 2, 2013
1 parent fab7660 commit e687bd4
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 65 deletions.
69 changes: 6 additions & 63 deletions enaml/qt/docking/dock_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@

from enaml.layout.dock_layout import docklayout, dockarea, dockitem

from enaml.qt.QtCore import Qt, QPoint, QRect, QObject, QMetaObject
from enaml.qt.QtCore import QPoint, QRect, QObject
from enaml.qt.QtGui import QApplication

from .dock_overlay import DockOverlay
from .event_types import DockAreaContentsChanged
from .layout_handling import (
build_layout, save_layout, layout_hit_test, plug_frame, iter_containers
)
Expand Down Expand Up @@ -57,59 +56,6 @@ def ensure_on_screen(rect):
return rect


class DockAreaFilter(QObject):
""" An event filter to listen for content changes in a dock area.
"""
def eventFilter(self, obj, event):
""" Filter the events for dock area.
"""
if event.type() == DockAreaContentsChanged:
self.processArea(obj)
return False

def processArea(self, area):
""" Process the contents change of a dock area.
This will close the dock window if there is only one remaining
container in the dock area.
Parameters
----------
area : QDockArea
The dock area whose contents have changed.
"""
window = area.parent()
if isinstance(window, QDockWindow):
widget = area.centralWidget()
if widget is None or isinstance(widget, QDockContainer):
if window.isMaximized():
window.showNormal()
geo = window.geometry()
area.setCentralWidget(None)
if widget is not None:
widget.float()
widget.setGeometry(geo)
attr = Qt.WA_ShowWithoutActivating
old = widget.testAttribute(attr)
widget.setAttribute(attr, True)
widget.show()
widget.setAttribute(attr, old)
manager = widget.manager()
if manager is not None:
manager.stack_under_top(widget)
# Hide before closing, or the window will steal mouse
# events from the container being dragged, event though
# the container has grabbed the mouse.
window.hide()
# Invoke the close slot later since it would remove this
# event filter from the dock area while the event is in
# process resulting in a segfault.
QMetaObject.invokeMethod(window, 'close', Qt.QueuedConnection)


class DockContainerMonitor(QObject):
""" A QObject class which monitors dock container toplevel changes.
Expand Down Expand Up @@ -150,9 +96,6 @@ class DockManager(Atom):
#: The overlay used when hovering over a dock area.
_overlay = Typed(DockOverlay, ())

#: The dock area filter installed on floating dock windows.
_area_filter = Typed(DockAreaFilter, ())

#: The list of QDockFrame instances maintained by the manager. The
#: QDockFrame class maintains this list in proper Z-order.
_dock_frames = List()
Expand Down Expand Up @@ -377,9 +320,7 @@ def popuplate_area(area, layout):
targets.append((target, item))
for item in multi_areas:
target = QDockWindow.create(self, self._dock_area)
win_area = target.dockArea()
popuplate_area(win_area, item)
win_area.installEventFilter(self._area_filter)
popuplate_area(target.dockArea(), item)
self._dock_frames.append(target)
self._proximity_handler.addFrame(target)
targets.append((target, item))
Expand Down Expand Up @@ -643,13 +584,16 @@ def close_window(self, window, event):
"""
area = window.dockArea()
if area is not None:
area.removeEventFilter(self._area_filter)
containers = list(iter_containers(area))
geometries = {}
for container in containers:
pos = container.mapToGlobal(QPoint(0, 0))
size = container.size()
geometries[container] = QRect(pos, size)
for container, ignored in area.dockBarContainers():
containers.append(container)
size = container.sizeHint()
geometries[container] = QRect(window.pos(), size)
for container in containers:
if not container.close():
container.unplug()
Expand Down Expand Up @@ -896,7 +840,6 @@ def _dock_context(self, container):
plug_frame(win_area, None, container, QGuideRose.Guide.AreaCenter)
yield
if is_window:
win_area.installEventFilter(self._area_filter)
window.show()
if is_maxed:
window.showMaximized()
Expand Down
41 changes: 39 additions & 2 deletions enaml/qt/docking/q_dock_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
#------------------------------------------------------------------------------
from atom.api import Bool, Typed

from enaml.qt.QtCore import Qt, QMargins, QPoint, QRect, QSize, Signal
from enaml.qt.QtCore import (
Qt, QMetaObject, QMargins, QPoint, QRect, QSize, Signal
)
from enaml.qt.QtGui import QFrame, QHBoxLayout, QLayout

from .event_types import DockAreaContentsChanged
from .q_bitmap_button import QBitmapButton, QCheckedBitmapButton
from .q_dock_area import QDockArea
from .q_dock_frame import QDockFrame
Expand Down Expand Up @@ -192,6 +195,9 @@ class FrameState(QDockFrame.FrameState):
#: Whether or not the window is being dragged by the user.
dragging = Bool(False)

#: Whether the window is inside it's close event.
in_close_event = Bool(False)

@classmethod
def create(cls, manager, parent=None):
""" A classmethod to create a new QDockWindow.
Expand Down Expand Up @@ -352,7 +358,12 @@ def setDockArea(self, dock_area):
The dock area to use in the container.
"""
old = self.dockArea()
if old is not None:
old.removeEventFilter(self)
self.layout().setWidget(dock_area)
if dock_area is not None:
dock_area.installEventFilter(self)

def isLinked(self):
""" Get whether or not the window is linked.
Expand Down Expand Up @@ -382,14 +393,40 @@ def toggleMaximized(self):
else:
self.showMaximized()

def eventFilter(self, area, event):
""" Filter the events on the dock area.
This filter listens for contents changes on the dock area and
will close the window when the dock area is empty.
"""
if event.type() == DockAreaContentsChanged and area.isEmpty():
# Hide the window so that it doesn't steal events from
# the floating window when this window is closed.
self.hide()
# Close the window later so that the event filter can
# return before the child dock area is destroyed.
QMetaObject.invokeMethod(self, 'close', Qt.QueuedConnection)
return False

#--------------------------------------------------------------------------
# Event Handlers
#--------------------------------------------------------------------------
def closeEvent(self, event):
""" Handle a close event for the window.
"""
self.manager().close_window(self, event)
# Protect against reentrency and posted contents events which
# get delivered after the manager has already been removed.
state = self.frame_state
if state.in_close_event:
return
manager = self.manager()
if manager is None:
return
state.in_close_event = True
manager.close_window(self, event)
state.in_close_event = False

def resizeEvent(self, event):
""" Handle the resize event for the dock window.
Expand Down

0 comments on commit e687bd4

Please sign in to comment.