00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 from python_qt_binding.QtCore import qDebug, QEvent, QPoint, QRect, Qt
00032 from python_qt_binding.QtGui import QApplication, QDockWidget, QMainWindow, QMouseEvent
00033
00034 from .reparent_event import ReparentEvent
00035
00036
00037 class DockWidget(QDockWidget):
00038
00039 """Dock widget with the capability to be reparented via drag-and-drop to any other main window."""
00040
00041 def __init__(self, container_manager):
00042 super(DockWidget, self).__init__()
00043 self._container_manager = container_manager
00044 if self._container_manager is not None:
00045 self.event = self._event
00046 self._dragging_parent = None
00047 self._dragging_local_pos = None
00048 self._releasing_and_repressing_while_dragging = False
00049 self._main_windows = []
00050
00051 def _event(self, e):
00052 if e.type() == QEvent.MouseButtonPress and e.button() == Qt.LeftButton:
00053 qDebug('%spress, rel=%s, global=%s, diff=%s' % ((' - pseudo ' if self._releasing_and_repressing_while_dragging else ''), e.pos(), e.globalPos(), e.globalPos() - self.pos()))
00054 if e.type() == QEvent.MouseButtonRelease and e.button() == Qt.LeftButton:
00055 qDebug('%srelease, rel=%s, global=%s, diff=%s' % ((' - pseudo ' if self._releasing_and_repressing_while_dragging else ''), e.pos(), e.globalPos(), e.globalPos() - self.pos()))
00056
00057
00058 if self._dragging_parent is None and e.type() == QEvent.MouseButtonPress and e.button() == Qt.LeftButton:
00059 self._dragging_local_pos = e.pos()
00060
00061 if self._dragging_parent is None and self._dragging_local_pos is not None and e.type() == QEvent.Move and QApplication.mouseButtons() & Qt.LeftButton:
00062 if self._widget_at(e.pos()) is not None:
00063 qDebug('DockWidget._event() start drag, dockwidget=%s, parent=%s, floating=%s, pos=%s' % (str(self), str(self.parent()), str(self.isFloating()), str(self._dragging_local_pos)))
00064 self._dragging_parent = self.parent()
00065
00066 self.setAttribute(Qt.WA_TransparentForMouseEvents)
00067
00068
00069 self._main_windows = [self._container_manager.get_root_main_window()]
00070 for container in self._container_manager.get_containers():
00071 if container == self:
00072 continue
00073 self._main_windows.append(container.main_window)
00074
00075
00076 if self._dragging_local_pos is not None and e.type() == QEvent.MouseButtonRelease and e.button() == Qt.LeftButton and not self._releasing_and_repressing_while_dragging:
00077 self._dragging_local_pos = None
00078
00079 if self._dragging_parent is not None and e.type() == QEvent.MouseButtonRelease and e.button() == Qt.LeftButton and not self._releasing_and_repressing_while_dragging:
00080 qDebug('DockWidget._event() stop drag, dockwidget=%s, parent=%s\n' % (self, self.parent()))
00081 self._dragging_parent = None
00082 self.setAttribute(Qt.WA_TransparentForMouseEvents, False)
00083 self._main_windows = []
00084
00085 if self._dragging_parent is not None and e.type() == QEvent.MouseMove and e.buttons() & Qt.LeftButton and not self._releasing_and_repressing_while_dragging:
00086 widget = self._widget_at(e.globalPos())
00087 new_parent = self._get_new_parent(widget)
00088
00089 if new_parent is not None and new_parent != self.parent():
00090 self._releasing_and_repressing_while_dragging = True
00091
00092
00093 mouse_release_event = QMouseEvent(QEvent.MouseButtonRelease, self._dragging_local_pos, e.globalPos(), Qt.LeftButton, Qt.NoButton, e.modifiers())
00094 QApplication.instance().postEvent(self, mouse_release_event)
00095 QApplication.sendPostedEvents()
00096
00097
00098 reparent_event = ReparentEvent(self, new_parent)
00099 QApplication.instance().postEvent(self._container_manager, reparent_event)
00100 QApplication.sendPostedEvents()
00101
00102
00103 self.setAttribute(Qt.WA_TransparentForMouseEvents, False)
00104
00105
00106 mouse_repress_event = QMouseEvent(QEvent.MouseButtonPress, self._dragging_local_pos, e.globalPos(), Qt.LeftButton, Qt.LeftButton, e.modifiers())
00107 QApplication.instance().postEvent(self, mouse_repress_event)
00108 QApplication.sendPostedEvents()
00109
00110
00111
00112 mouse_move_event = QMouseEvent(QEvent.MouseMove, self._dragging_local_pos, e.globalPos() + QPoint(QApplication.startDragDistance(), 1), Qt.NoButton, Qt.LeftButton, e.modifiers())
00113 QApplication.instance().postEvent(self, mouse_move_event)
00114 QApplication.sendPostedEvents()
00115
00116 mouse_move_event = QMouseEvent(QEvent.MouseMove, self._dragging_local_pos, e.globalPos(), Qt.NoButton, Qt.LeftButton, e.modifiers())
00117 QApplication.instance().postEvent(self, mouse_move_event)
00118 QApplication.sendPostedEvents()
00119
00120
00121 self.setAttribute(Qt.WA_TransparentForMouseEvents)
00122
00123 self._releasing_and_repressing_while_dragging = False
00124
00125 return super(DockWidget, self).event(e)
00126
00127 def _get_new_parent(self, widget):
00128 from .dock_widget_container import DockWidgetContainer
00129 if isinstance(widget, DockWidgetContainer):
00130 if widget.isFloating():
00131 return None
00132 widget = widget.parent()
00133 while widget is not None:
00134 if isinstance(widget, QMainWindow):
00135 break
00136 widget = widget.parent()
00137 return widget
00138
00139 def _widget_at(self, global_point):
00140
00141 widget = QApplication.widgetAt(global_point)
00142
00143 root_main_window = self._container_manager.get_root_main_window()
00144
00145
00146 if widget == root_main_window and not self._widget_contains(root_main_window, global_point):
00147
00148 widget = None
00149
00150
00151 if widget is None and self.isFloating():
00152
00153 overlapping = {}
00154 for main_window in self._main_windows:
00155 if self._widget_contains(main_window, global_point):
00156 parent = main_window.parent()
00157 is_floating = parent is None or parent.isFloating()
00158 overlapping[main_window] = is_floating
00159
00160
00161 if len(overlapping) == 1:
00162
00163 widget, _ = overlapping.popitem()
00164 elif len(overlapping) > 1:
00165
00166
00167 overlapping_docked = [mw for mw, floating in overlapping.iteritems() if not floating]
00168
00169
00170
00171 if len(overlapping_docked) >= len(overlapping) - 1:
00172
00173
00174
00175
00176 parents = []
00177 for mw1 in overlapping_docked:
00178
00179 parent = mw1.parent()
00180 if parent is None:
00181 continue
00182
00183 parent = parent.parent()
00184 if parent is None:
00185 continue
00186 for mw2 in overlapping_docked:
00187 if mw2 == parent:
00188 parents.append(mw2)
00189 for parent in parents:
00190 overlapping_docked.remove(parent)
00191
00192
00193
00194 if len(overlapping_docked) == 1:
00195
00196 widget = overlapping_docked[0]
00197 else:
00198
00199 pass
00200
00201
00202 return widget
00203
00204 def _widget_contains(self, widget, point):
00205 topleft = widget.mapToGlobal(widget.mapFromParent(widget.geometry().topLeft()))
00206 rect = QRect(topleft, widget.geometry().size())
00207 return rect.contains(point)
00208
00209 def save_settings(self, settings):
00210
00211 settings.set_value('parent', self._parent_container_serial_number())
00212
00213 title_bar = self.titleBarWidget()
00214 title_bar.save_settings(settings)
00215
00216 def restore_settings(self, settings):
00217 serial_number = settings.value('parent', None)
00218
00219 if serial_number is not None:
00220 serial_number = int(serial_number)
00221 if self._parent_container_serial_number() != serial_number and self._container_manager is not None:
00222 floating = self.isFloating()
00223 pos = self.pos()
00224 new_container = self._container_manager.get_container(serial_number)
00225 if new_container is not None:
00226 new_parent = new_container.main_window
00227 else:
00228 new_parent = self._container_manager.get_root_main_window()
00229 area = self.parent().dockWidgetArea(self)
00230 new_parent.addDockWidget(area, self)
00231 if floating:
00232 self.setFloating(floating)
00233 self.move(pos)
00234
00235 title_bar = self.titleBarWidget()
00236 title_bar.restore_settings(settings)
00237
00238 def _parent_container(self, dock_widget):
00239 from .dock_widget_container import DockWidgetContainer
00240 parent = dock_widget.parent()
00241 if parent is not None:
00242 parent = parent.parent()
00243 if isinstance(parent, DockWidgetContainer):
00244 return parent
00245 return None
00246
00247 def _parent_container_serial_number(self):
00248 serial_number = None
00249 parent = self._parent_container(self)
00250 if parent is not None:
00251 serial_number = parent.serial_number()
00252 return serial_number