diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryApplicationDescriptor.cpp b/Plugins/org.blueberry.core.runtime/src/internal/berryApplicationDescriptor.cpp index be0f158a07..6b5eed9954 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryApplicationDescriptor.cpp +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryApplicationDescriptor.cpp @@ -1,270 +1,271 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "berryApplicationDescriptor.h" #include "berryApplicationHandle.h" #include "berryApplicationContainer.h" #include "berryIRuntimeConstants.h" #include namespace berry { const QString ApplicationDescriptor::APP_TYPE = "blueberry.application.type"; const QString ApplicationDescriptor::APP_DEFAULT = "blueberry.application.default"; const QString ApplicationDescriptor::APP_TYPE_MAIN_THREAD = "main.thread"; const QString ApplicationDescriptor::APP_TYPE_ANY_THREAD = "any.thread"; ApplicationDescriptor::ApplicationDescriptor(const QSharedPointer& contributor, const QString& pid, const QString& name, const QString& iconPath, const Flags& flags, int cardinality, ApplicationContainer* appContainer) : pid(pid) , name(name) , contributor(contributor) , appContainer(appContainer) , flags(flags) , cardinality(cardinality) , iconPath(iconPath) + , instanceId(0) , locked(false) { if (pid.isEmpty()) { throw std::invalid_argument("Application ID must not be empty!"); } } ApplicationDescriptor::~ApplicationDescriptor() { } QString ApplicationDescriptor::getApplicationId() const { return pid; } QHash ApplicationDescriptor::getProperties(const QLocale& /*locale*/) const { return this->getProperties(); } QHash berry::ApplicationDescriptor::getProperties() const { // just use the service properties; for now we do not localize any properties return GetServiceProperties(); } ctkApplicationHandle* ApplicationDescriptor::launch(const QHash& arguments) { CheckArgs(arguments); try { // if this application is locked throw an exception. /* if (GetLocked()) { throw ctkIllegalStateException("Cannot launch a locked application."); } */ // initialize the appHandle ApplicationHandle* appHandle = CreateAppHandle(arguments); try { // use the appContainer to launch the application on the main thread. appContainer->Launch(appHandle); } catch (const std::exception& t) { // be sure to destroy the appHandle if an error occurs try { appHandle->destroy(); } catch (...) { // ignore and clean up } throw t; } return appHandle; } catch (const ctkIllegalStateException& ise) { throw ise; } catch (const ctkApplicationException& ae) { throw ae; } catch (const ctkException& e) { throw ctkApplicationException(ctkApplicationException::APPLICATION_INTERNAL_ERROR, e); } catch (const std::exception& e) { throw ctkApplicationException(ctkApplicationException::APPLICATION_INTERNAL_ERROR, QString(e.what())); } catch (...) { throw ctkApplicationException(ctkApplicationException::APPLICATION_INTERNAL_ERROR); } } void ApplicationDescriptor::CheckArgs(const QHash arguments) { foreach(QString key, arguments.keys()) { if (key.isEmpty()) { throw std::invalid_argument("Empty string is an invalid key"); } } } ctkProperties ApplicationDescriptor::GetServiceProperties() const { ctkProperties props; props[ctkApplicationDescriptor::APPLICATION_PID] = getApplicationId(); if (!name.isEmpty()) { props[ctkApplicationDescriptor::APPLICATION_NAME] = name; } props[ctkApplicationDescriptor::APPLICATION_CONTAINER] = IRuntimeConstants::PI_RUNTIME(); props[ctkApplicationDescriptor::APPLICATION_LOCATION] = GetLocation(); bool launchable = appContainer->IsLocked(this) == 0 ? true : false; props[ctkApplicationDescriptor::APPLICATION_LAUNCHABLE] = launchable; props[ctkApplicationDescriptor::APPLICATION_LOCKED] = GetLocked(); bool visible = flags.testFlag(FLAG_VISIBLE); props[ctkApplicationDescriptor::APPLICATION_VISIBLE] = visible; props[APP_TYPE] = GetThreadTypeString(); if (flags.testFlag(FLAG_DEFAULT_APP)) { props[APP_DEFAULT] = true; } if (!iconPath.isEmpty()) { props[ctkApplicationDescriptor::APPLICATION_ICON] = iconPath; } return props; } ApplicationHandle* ApplicationDescriptor::CreateAppHandle(const QHash& arguments) { ApplicationHandle* newAppHandle = new ApplicationHandle(GetInstanceID(), arguments, this); //appContainer.lock(newAppHandle); QStringList clazzes; clazzes.push_back(qobject_interface_iid()); clazzes.push_back(qobject_interface_iid()); ctkServiceRegistration appHandleReg = appContainer->GetContext()->registerService(clazzes, newAppHandle, newAppHandle->GetServiceProperties()); newAppHandle->SetServiceRegistration(appHandleReg); return newAppHandle; } QString ApplicationDescriptor::GetInstanceID() const { QMutexLocker l(&mutex); // make sure the instanceID has not reached the max if (instanceId == std::numeric_limits::max()) { instanceId = 0; } // create a unique instance id return getApplicationId() + "." + instanceId++; } QString ApplicationDescriptor::GetLocation() const { if (!contributor) { return QString(); } return contributor->getLocation(); } bool ApplicationDescriptor::GetLocked() const { QMutexLocker l(&mutex); return locked; } QString ApplicationDescriptor::GetThreadTypeString() const { if (flags.testFlag(FLAG_TYPE_ANY_THREAD)) { return APP_TYPE_ANY_THREAD; } return APP_TYPE_MAIN_THREAD; } ApplicationContainer* ApplicationDescriptor::GetContainerManager() const { return appContainer; } void ApplicationDescriptor::RefreshProperties() { ctkServiceRegistration reg = GetServiceRegistration(); if (reg) { try { reg.setProperties(GetServiceProperties()); } catch (const ctkIllegalStateException&) { // this must mean the service was unregistered // just ignore } } } void ApplicationDescriptor::SetServiceRegistration(const ctkServiceRegistration& sr) { QMutexLocker l(®istrationMutex); this->sr = sr; registrationValidOrWaiting = sr; registrationMutexCondition.wakeAll(); } ctkServiceRegistration ApplicationDescriptor::GetServiceRegistration() const { QMutexLocker l(®istrationMutex); if (!sr && registrationValidOrWaiting) { registrationMutexCondition.wait(®istrationMutex, 1000); // timeout after 1 second } return sr; } void ApplicationDescriptor::Unregister() { ctkServiceRegistration temp = GetServiceRegistration(); if (temp) { SetServiceRegistration(ctkServiceRegistration()); temp.unregister(); } } int ApplicationDescriptor::GetThreadType() const { return flags & (FLAG_TYPE_ANY_THREAD | FLAG_TYPE_MAIN_THREAD); } } diff --git a/Plugins/org.blueberry.ui.qt/src/berryWindow.cpp b/Plugins/org.blueberry.ui.qt/src/berryWindow.cpp index c966c82229..5a03b59be3 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryWindow.cpp +++ b/Plugins/org.blueberry.ui.qt/src/berryWindow.cpp @@ -1,579 +1,579 @@ /*=================================================================== BlueBerry Platform Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "tweaklets/berryGuiWidgetsTweaklet.h" #include "berryWindow.h" #include "berryConstants.h" #include "berrySameShellProvider.h" #include "berryMenuManager.h" #include namespace berry { const int Window::OK = 0; const int Window::CANCEL = 1; QList Window::defaultImages = QList(); Window::IExceptionHandler::Pointer Window::exceptionHandler(new DefaultExceptionHandler()); IShellProvider::Pointer Window::defaultModalParent(new DefaultModalParent()); Window::WindowShellListener::WindowShellListener(Window* wnd) : window(wnd) { } void Window::WindowShellListener::ShellClosed(const ShellEvent::Pointer& event) { event->doit = false; // don't close now if (window->CanHandleShellCloseEvent()) { window->HandleShellCloseEvent(); } } void Window::DefaultExceptionHandler::HandleException(const std::exception& t) { // Try to keep running. std::cerr << t.what(); } Shell::Pointer Window::DefaultModalParent::GetShell() const { Shell::Pointer parent = Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetActiveShell(); // Make sure we don't pick a parent that has a modal child (this can lock the app) if (parent == 0) { // If this is a top-level window, then there must not be any open modal windows. parent = Window::GetModalChild(Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetShells()); } else { // If we picked a parent with a modal child, use the modal child instead Shell::Pointer modalChild = Window::GetModalChild(parent->GetShells()); if (modalChild != 0) { parent = modalChild; } } return parent; } Shell::Pointer Window::GetModalChild(const QList& toSearch) { int modal = Constants::APPLICATION_MODAL | Constants::SYSTEM_MODAL | Constants::PRIMARY_MODAL; int size = toSearch.size(); for (int i = size - 1; i < size; i--) { Shell::Pointer shell = toSearch[i]; // Check if this shell has a modal child QList children = shell->GetShells(); Shell::Pointer modalChild = GetModalChild(children); if (modalChild != 0) { return modalChild; } // If not, check if this shell is modal itself if (shell->IsVisible() && (shell->GetStyle() & modal) != 0) { return shell; } } return Shell::Pointer(nullptr); } //void Window::RunEventLoop() //{ // // //Use the display provided by the shell if possible // Display display; // if (shell == null) // { // display = Display.getCurrent(); // } // else // { // display = loopShell.getDisplay(); // } // // while (loopShell != null && !loopShell.isDisposed()) // { // try // { // if (!display.readAndDispatch()) // { // display.sleep(); // } // } catch (Throwable e) // { // exceptionHandler.handleException(e); // } // } // display.update(); //} Window::Window(Shell::Pointer parentShell) { this->parentShell = new SameShellProvider(parentShell); this->Init(); } Window::Window(IShellProvider::Pointer shellProvider) { poco_assert(shellProvider != 0); this->parentShell = shellProvider; this->Init(); } Window::~Window() { } void Window::Init() { this->shellStyle = Constants::SHELL_TRIM; this->returnCode = OK; this->block = false; } bool Window::CanHandleShellCloseEvent() { return true; } void Window::ConfigureShell(Shell::Pointer newShell) { // The single image version of this code had a comment related to bug // 46624, // and some code that did nothing if the stored image was already // disposed. // The equivalent in the multi-image version seems to be to remove the // disposed images from the array passed to the shell. if (defaultImages.size() > 0) { // ArrayList nonDisposedImages = new ArrayList(defaultImages.length); // for (int i = 0; i < defaultImages.length; ++i) // { // if (defaultImages[i] != null && !defaultImages[i].isDisposed()) // { // nonDisposedImages.add(defaultImages[i]); // } // } // // if (nonDisposedImages.size() <= 0) // { // System.err.println("Window.configureShell: images disposed"); //$NON-NLS-1$ // } // else // { // //Image[] array = new Image[nonDisposedImages.size()]; // nonDisposedImages.toArray(array); newShell->SetImages(defaultImages); // } } // Layout layout = getLayout(); // if (layout != null) // { // newShell.setLayout(layout); // } CreateTrimWidgets(newShell); } //voidWindow::ConstrainShellSize() //{ // // limit the shell size to the display size // QRect bounds = shell.getBounds(); // QRect constrained = getConstrainedShellBounds(bounds); // if (!bounds.equals(constrained)) // { // shell.setBounds(constrained); // } //} QWidget* Window::CreateContents(Shell::Pointer parent) { // by default, just create a composite //return new Composite(parent, SWT.NONE); return parent->GetControl(); } Shell::Pointer Window::CreateShell() { Shell::Pointer newParent = this->GetParentShell(); // if (newParent != 0 && newParent.isDisposed()) // { // parentShell = new SameShellProvider(null); // newParent = getParentShell();//Find a better parent // } //Create the shell Shell::Pointer newShell = Tweaklets::Get(GuiWidgetsTweaklet::KEY)->CreateShell(newParent, this->GetShellStyle()); // resizeListener = new Listener() { // public void handleEvent(Event e) { // resizeHasOccurred = true; // } // }; //newShell.addListener(SWT.Resize, resizeListener); newShell->SetData(Object::Pointer(this)); //Add a listener newShell->AddShellListener(this->GetShellListener()); //Set the layout this->ConfigureShell(newShell); // //Register for font changes // if (fontChangeListener == null) // { // fontChangeListener = new FontChangeListener(); // } // JFaceResources.getFontRegistry().addListener(fontChangeListener); return newShell; } QWidget* Window::GetContents() { return contents; } QPoint Window::GetInitialLocation(const QPoint& initialSize) { QWidget* parent = Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetParent(shell->GetControl()); QPoint centerPoint(0,0); QRect parentBounds(0,0,0,0); if (parent != nullptr) { parentBounds = Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetBounds(parent); centerPoint.setX(parentBounds.x() + parentBounds.width()/2); centerPoint.setY(parentBounds.y() - parentBounds.height()/2); } else { parentBounds = Tweaklets::Get(GuiWidgetsTweaklet::KEY) ->GetScreenSize(Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetPrimaryScreenNumber()); centerPoint.setX(parentBounds.width()/2); centerPoint.setY(parentBounds.height()/2); } return QPoint(centerPoint.x() - (initialSize.x() / 2), std::max(parentBounds.y(), std::min(centerPoint.y() - (initialSize.y() * 2 / 3), parentBounds.y() + parentBounds.height() - initialSize.y()))); } QPoint Window::GetInitialSize() { return shell->ComputeSize(Constants::DEFAULT, Constants::DEFAULT, true); } Shell::Pointer Window::GetParentShell() { Shell::Pointer parent = parentShell->GetShell(); int modal = Constants::APPLICATION_MODAL | Constants::SYSTEM_MODAL | Constants::PRIMARY_MODAL; if ((this->GetShellStyle() & modal) != 0) { // If this is a modal shell with no parent, pick a shell using defaultModalParent. if (parent == 0) { parent = defaultModalParent->GetShell(); } } return parent; } IShellListener* Window::GetShellListener() { if (windowShellListener.isNull()) windowShellListener.reset(new WindowShellListener(this)); return windowShellListener.data(); } int Window::GetShellStyle() { return shellStyle; } void Window::HandleShellCloseEvent() { this->SetReturnCode(CANCEL); this->Close(); } void Window::InitializeBounds() { // if (resizeListener != null) // { // shell.removeListener(SWT.Resize, resizeListener); // } // if (resizeHasOccurred) // { // Check if shell size has been set already. // return; // } QPoint size = this->GetInitialSize(); QPoint location = this->GetInitialLocation(size); shell->SetBounds(this->GetConstrainedShellBounds(QRect(location.x(), location.y(), size.x(), size.y()))); } QRect Window::GetConstrainedShellBounds(const QRect& preferredSize) { QRect result(preferredSize); GuiWidgetsTweaklet* guiTweaklet(Tweaklets::Get(GuiWidgetsTweaklet::KEY)); int screenNum = guiTweaklet->GetClosestScreenNumber(result); QRect bounds(guiTweaklet->GetAvailableScreenSize(screenNum)); if (result.height() > bounds.height()) { result.setHeight(bounds.height()); } if (result.width() > bounds.width()) { result.setWidth(bounds.width()); } - result.setX( std::max(bounds.x(), std::min(result.x(), bounds.x() + result.moveLeft( std::max(bounds.x(), std::min(result.x(), bounds.x() + bounds.width() - result.width()))); - result.setY(std::max(bounds.y(), std::min(result.y(), bounds.y() + result.moveTop(std::max(bounds.y(), std::min(result.y(), bounds.y() + bounds.height() - result.height()))); return result; } void Window::SetParentShell(Shell::Pointer newParentShell) { poco_assert(shell == 0); // "There must not be an existing shell."; //$NON-NLS-1$ parentShell = new SameShellProvider(newParentShell); } void Window::SetReturnCode(int code) { returnCode = code; } void Window::SetShellStyle(int newShellStyle) { shellStyle = newShellStyle; } void Window::AddMenuBar() { if (GetShell().IsNull() && menuBarManager.IsNull()) { menuBarManager = CreateMenuManager(); } } SmartPointer Window::CreateMenuManager() { MenuManager::Pointer manager(new MenuManager()); return manager; } void Window::CreateTrimWidgets(SmartPointer shell) { if (menuBarManager.IsNotNull()) { QMainWindow* mw = qobject_cast(shell->GetControl()); if (mw) { mw->setMenuBar(menuBarManager->CreateMenuBar(shell->GetControl())); menuBarManager->UpdateAll(true); } } // if (showTopSeperator()) // { // seperator1 = new Label(shell, SWT.SEPARATOR | SWT.HORIZONTAL); // } //CreateToolBarControl(shell); //CreateStatusLine(shell); } bool Window::Close() { // BERRY_INFO << "Window::Close()"; // // stop listening for font changes // if (fontChangeListener != null) // { // JFaceResources.getFontRegistry().removeListener(fontChangeListener); // fontChangeListener = null; // } // remove this window from a window manager if it has one if (windowManager != nullptr) { windowManager->Remove(Window::Pointer(this)); windowManager = nullptr; } if (shell == 0) { return true; } shell->RemoveShellListener(this->GetShellListener()); shell->SetData(Object::Pointer(nullptr)); // If we "close" the shell recursion will occur. // Instead, we need to "dispose" the shell to remove it from the // display. Tweaklets::Get(GuiWidgetsTweaklet::KEY)->DisposeShell(shell); shell = nullptr; contents = nullptr; return true; } void Window::Create() { shell = this->CreateShell(); contents = this->CreateContents(shell); //initialize the bounds of the shell to that appropriate for the // contents this->InitializeBounds(); } QIcon Window::GetDefaultImage() { return (defaultImages.size() < 1) ? QIcon() : defaultImages[0]; } QList Window::GetDefaultImages() { return defaultImages; } int Window::GetReturnCode() { return returnCode; } Shell::Pointer Window::GetShell() const { return shell; } WindowManager* Window::GetWindowManager() { return windowManager; } MenuManager *Window::GetMenuBarManager() const { return menuBarManager.GetPointer(); } int Window::Open() { if (shell == 0) { // create the window this->Create(); } // limit the shell size to the display size //constrainShellSize(); // open the window shell->Open(block); // // run the event loop if specified // if (block) // { // this->RunEventLoop(); // } return returnCode; } void Window::SetBlockOnOpen(bool shouldBlock) { block = shouldBlock; } void Window::SetDefaultImage(const QIcon& image) { if (!image.isNull()) defaultImages.push_back(image); } void Window::SetDefaultImages(const QList& images) { defaultImages = images; } void Window::SetWindowManager(WindowManager* manager) { windowManager = manager; // Code to detect invalid usage if (manager != nullptr) { QList windows = manager->GetWindows(); for (int i = 0; i < windows.size(); i++) { if (windows[i] == this) { return; } } manager->Add(Window::Pointer(this)); } } void Window::SetExceptionHandler(IExceptionHandler::Pointer handler) { if (exceptionHandler == 0) { exceptionHandler = handler; } } void Window::SetDefaultModalParent(IShellProvider::Pointer provider) { defaultModalParent = provider; } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryDetachedWindow.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryDetachedWindow.cpp index fc3aaf6ac0..e0e411954b 100755 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryDetachedWindow.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryDetachedWindow.cpp @@ -1,541 +1,541 @@ /*=================================================================== BlueBerry Platform Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "tweaklets/berryGuiWidgetsTweaklet.h" #include "berryDetachedWindow.h" #include "berryIWorkbenchPartConstants.h" #include "berryISaveablePart.h" #include "berryIContextService.h" #include "berryWorkbenchWindow.h" #include "berryWorkbenchConstants.h" #include "berryEditorManager.h" #include "berryDragUtil.h" namespace berry { DetachedWindow::ShellListener::ShellListener(DetachedWindow* wnd) : window(wnd) { } void DetachedWindow::ShellListener::ShellClosed(const ShellEvent::Pointer& e) { // hold on to a reference of the DetachedWindow instance // (otherwise, wnd->HandleClose() woulde delete the DetachedWindow // instance too early, trying to write to members afterwards) DetachedWindow::Pointer wnd(window); // only continue to close if the handleClose // wasn't canceled e->doit = wnd->HandleClose(); } DetachedWindow::ShellControlListener::ShellControlListener(DetachedWindow* wnd) : window(wnd) { } GuiTk::IControlListener::Events::Types DetachedWindow::ShellControlListener::GetEventTypes() const { return Events::RESIZED; } void DetachedWindow::ShellControlListener::ControlResized( GuiTk::ControlEvent::Pointer e) { window->folder->SetBounds( Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetClientArea(e->item)); } DetachedWindow::DetachedWindow(WorkbenchPage* workbenchPage) : folder(new PartStack(workbenchPage, false)) , page(workbenchPage) , hideViewsOnClose(true) , shellListener(new ShellListener(this)) , resizeListener(new ShellControlListener(this)) { } void DetachedWindow::PropertyChange(const Object::Pointer& /*source*/, int propId) { if (propId == IWorkbenchPartConstants::PROP_TITLE) { this->UpdateTitle(); } else if (propId == PartStack::PROP_SELECTION) { this->ActivePartChanged(this->GetPartReference(folder->GetSelection())); } } Shell::Pointer DetachedWindow::GetShell() { return windowShell; } void DetachedWindow::Create() { folder->AddListener(this); windowShell = page->GetWorkbenchWindow().Cast () ->GetDetachedWindowPool()->AllocateShell( shellListener.data()); windowShell->SetData(Object::Pointer(this)); windowShell->SetText(""); DragUtil::AddDragTarget(windowShell->GetControl(), this); hideViewsOnClose = true; if (bounds.isEmpty()) { QRect windowRect = page->GetWorkbenchWindow()->GetShell()->GetBounds(); QPoint center(windowRect.x() + windowRect.width() / 2, windowRect.y() - - windowRect.height() / 2); + + windowRect.height() / 2); bounds = QRect(center.x() - 150, center.y() + 100, 300, 200); } // Force the rect into the current display QRect dispBounds = Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetAvailableScreenSize(); if (bounds.width() > dispBounds.width()) bounds.setWidth(dispBounds.width()); if (bounds.height() > dispBounds.height()) bounds.setHeight(dispBounds.height()); if (bounds.x() + bounds.width() > dispBounds.width()) - bounds.setX(dispBounds.width() - bounds.width()); + bounds.moveLeft(dispBounds.width() - bounds.width()); if (bounds.y() + bounds.height() > dispBounds.height()) - bounds.setY(dispBounds.height() - bounds.height()); + bounds.moveTop(dispBounds.height() - bounds.height()); this->GetShell()->SetBounds(bounds); this->ConfigureShell(windowShell); this->CreateContents(windowShell->GetControl()); //windowShell->Layout(true); //folder->SetBounds(Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetClientArea(windowShell->GetControl())); } void DetachedWindow::Add(LayoutPart::Pointer part) { Shell::Pointer shell = this->GetShell(); if (shell != 0) { part->Reparent(shell->GetControl()); } folder->Add(part); this->UpdateMinimumSize(); } bool DetachedWindow::BelongsToWorkbenchPage( IWorkbenchPage::Pointer workbenchPage) { return (workbenchPage == this->page); } bool DetachedWindow::Close() { hideViewsOnClose = false; Shell::Pointer shell = this->GetShell(); if (shell != 0) { shell->Close(); } return true; } IDropTarget::Pointer DetachedWindow::Drag(QWidget* /*currentControl*/, const Object::Pointer& draggedObject, const QPoint& position, const QRect& /*dragRectangle*/) { if (draggedObject.Cast () == 0) { return IDropTarget::Pointer(nullptr); } PartPane::Pointer sourcePart = draggedObject.Cast (); if (sourcePart->GetWorkbenchWindow() != page->GetWorkbenchWindow()) { return IDropTarget::Pointer(nullptr); } // Only handle the event if the source part is acceptable to the particular PartStack IDropTarget::Pointer target; if (folder->AllowsDrop(sourcePart)) { target = folder->GetDropTarget(draggedObject, position); if (target == 0) { QRect displayBounds = DragUtil::GetDisplayBounds(folder->GetControl()); if (displayBounds.contains(position)) { StackDropResult::Pointer stackDropResult(new StackDropResult( displayBounds, Object::Pointer(nullptr))); target = folder->CreateDropTarget(sourcePart, stackDropResult); } else { return IDropTarget::Pointer(nullptr); } } } return target; } ILayoutContainer::ChildrenType DetachedWindow::GetChildren() const { return folder->GetChildren(); } WorkbenchPage::Pointer DetachedWindow::GetWorkbenchPage() { return WorkbenchPage::Pointer(this->page); } void DetachedWindow::RestoreState(IMemento::Pointer memento) { // Read the bounds. int x = 0; memento->GetInteger(WorkbenchConstants::TAG_X, x); int y = 0; memento->GetInteger(WorkbenchConstants::TAG_Y, y); int width = 0; memento->GetInteger(WorkbenchConstants::TAG_WIDTH, width); int height = 0; memento->GetInteger(WorkbenchConstants::TAG_HEIGHT, height); // memento->GetInteger(WorkbenchConstants::TAG_FLOAT); // Set the bounds. bounds = QRect(x, y, width, height); if (GetShell()) { GetShell()->SetBounds(bounds); } // Create the folder. IMemento::Pointer childMem = memento->GetChild(WorkbenchConstants::TAG_FOLDER); if (childMem) { folder->RestoreState(childMem); } } void DetachedWindow::SaveState(IMemento::Pointer memento) { if (GetShell()) { bounds = GetShell()->GetBounds(); } // Save the bounds. memento->PutInteger(WorkbenchConstants::TAG_X, bounds.x()); memento->PutInteger(WorkbenchConstants::TAG_Y, bounds.y()); memento->PutInteger(WorkbenchConstants::TAG_WIDTH, bounds.width()); memento->PutInteger(WorkbenchConstants::TAG_HEIGHT, bounds.height()); // Save the views. IMemento::Pointer childMem = memento->CreateChild( WorkbenchConstants::TAG_FOLDER); folder->SaveState(childMem); } QWidget* DetachedWindow::GetControl() { return folder->GetControl(); } int DetachedWindow::Open() { if (this->GetShell() == 0) { this->Create(); } QRect bounds = this->GetShell()->GetBounds(); if (!(bounds == this->GetShell()->GetBounds())) { this->GetShell()->SetBounds(bounds); } this->GetShell()->SetVisible(true); folder->SetBounds(Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetClientArea(this->GetShell()->GetControl())); return 0; } void DetachedWindow::ActivePartChanged( IWorkbenchPartReference::Pointer partReference) { if (activePart == partReference) { return; } if (activePart != 0) { activePart->RemovePropertyListener(this); } activePart = partReference; if (partReference != 0) { partReference->AddPropertyListener(this); } this->UpdateTitle(); } void DetachedWindow::ConfigureShell(Shell::Pointer shell) { this->UpdateTitle(); Tweaklets::Get(GuiWidgetsTweaklet::KEY)->AddControlListener( shell->GetControl(), resizeListener); //shell.addListener(SWT.Activate, activationListener); //shell.addListener(SWT.Deactivate, activationListener); //TODO DetachedWindow key bindings // Register this detached view as a window (for key bindings). //IContextService* contextService = this->GetWorkbenchPage()->GetWorkbenchWindow()-> // GetWorkbench()->GetService(); //contextService->RegisterShell(shell, IContextService::TYPE_WINDOW); // page.getWorkbenchWindow().getWorkbench().getHelpSystem().setHelp(shell, // IWorkbenchHelpContextIds.DETACHED_WINDOW); } QWidget* DetachedWindow::CreateContents(QWidget* parent) { // Create the tab folder. folder->CreateControl(parent); // Reparent each view in the tab folder. QList detachedChildren; this->CollectViewPanes(detachedChildren, this->GetChildren()); for (QList::iterator itr = detachedChildren.begin(); itr != detachedChildren.end(); ++itr) { PartPane::Pointer part = *itr; part->Reparent(parent); } //TODO DetachedWindow listen to folder events (update size?) // if (folder->GetPresentation() // instanceof TabbedStackPresentation) // { // TabbedStackPresentation stack = (TabbedStackPresentation) folder.getPresentation(); // AbstractTabFolder tabFolder = stack.getTabFolder(); // tabFolder.addListener(new TabFolderListener() // { // public void handleEvent(TabFolderEvent e) // { // switch (e.type) // { // case TabFolderEvent.EVENT_CLOSE: // { // updateMinimumSize(); // break; // } // case TabFolderEvent.EVENT_PREFERRED_SIZE: // { // updateMinimumSize(); // break; // } // } // } // }); // } // Return tab folder control. return folder->GetControl(); } void DetachedWindow::UpdateTitle() { if (activePart != 0) { // Uncomment to set the shell title to match the title of the active part // String text = activePart.getTitle(); // // if (!text.equals(s.getText())) { // s.setText(text); // } } } void DetachedWindow::UpdateMinimumSize() { // // We can only do this for 'Tabbed' stacked presentations. // if (folder.getPresentation().Cast() != 0) // { // TabbedStackPresentation stack = (TabbedStackPresentation) folder.getPresentation(); // // if (stack->GetPartList().size() == 1) // { // // Get the minimum space required for the part // int width = stack->ComputePreferredSize(true, Constants::INF, Constants::INF, 0); // int height = stack->ComputePreferredSize(false, Constants::INF, Constants::INF, 0); // // // Take the current shell 'trim' into account // int shellHeight = windowShell->GetBounds().height - windowShell->GetClientArea().height; // int shellWidth = windowShell->GetBounds().width - windowShell->GetClientArea().width; // // windowShell->SetMinimumSize(width + shellWidth, height + shellHeight); // } // } } IWorkbenchPartReference::Pointer DetachedWindow::GetPartReference( LayoutPart::Pointer pane) { if (pane == 0 || pane.Cast () == 0) { return IWorkbenchPartReference::Pointer(nullptr); } return pane.Cast ()->GetPartReference(); } bool DetachedWindow::HandleClose() { if (hideViewsOnClose) { QList views; this->CollectViewPanes(views, this->GetChildren()); // Save any dirty views if (!this->HandleSaves(views)) { return false; // User canceled the save } // OK, go on with the closing for (QList::iterator itr = views.begin(); itr != views.end(); ++itr) { PartPane::Pointer child = *itr; // Only close if closable... if (child->IsCloseable()) { page->HideView(child->GetPartReference().Cast ()); // Was the close cancelled? if (child->GetContainer() != 0) return false; } else { page->AttachView(child->GetPartReference().Cast ()); } } } if (folder != 0) { folder->Dispose(); } if (windowShell != 0) { Tweaklets::Get(GuiWidgetsTweaklet::KEY)->RemoveControlListener( windowShell->GetControl(), resizeListener); // windowShell.removeListener(SWT.Activate, activationListener); // windowShell.removeListener(SWT.Deactivate, activationListener); DragUtil::RemoveDragTarget(windowShell->GetControl(), this); bounds = windowShell->GetBounds(); // Unregister this detached view as a window (for key bindings). //IContextService* contextService = this->GetWorkbenchPage()->GetWorkbenchWindow()-> // GetWorkbench()->GetService(); //contextService->UnregisterShell(windowShell); windowShell->SetData(Object::Pointer(nullptr)); windowShell = nullptr; } return true; } bool DetachedWindow::HandleSaves(QList views) { QList dirtyViews; for (QList::iterator iterator = views.begin(); iterator != views.end(); ++iterator) { PartPane::Pointer pane = *iterator; IViewReference::Pointer ref = pane->GetPartReference().Cast (); IViewPart::Pointer part = ref->GetView(false); if (part.Cast () != 0) { ISaveablePart::Pointer saveable = part.Cast (); if (saveable->IsDirty() && saveable->IsSaveOnCloseNeeded()) { dirtyViews.push_back(part); } } } // If there are any prompt to save -before- any closing happens // FIXME: This code will result in a double prompt if the user // decides not to save a particular view at this stage they'll // get a second one from the 'hideView' call... if (dirtyViews.size() > 0) { IWorkbenchWindow::Pointer window = page->GetWorkbenchWindow(); bool success = EditorManager::SaveAll(dirtyViews, true, true, false, window); if (!success) { return false; // the user canceled. } } return true; } void DetachedWindow::CollectViewPanes(QList& result, const QList& parts) { for (QList::const_iterator iter = parts.begin(); iter != parts.end(); ++iter) { LayoutPart::Pointer part = *iter; if (part.Cast () != 0) { result.push_back(part.Cast ()); } } } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryQtTracker.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryQtTracker.cpp index d981ab15fe..d63a3699ef 100755 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryQtTracker.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryQtTracker.cpp @@ -1,332 +1,332 @@ /*=================================================================== BlueBerry Platform Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "berryTweaklets.h" #include "berryQtTracker.h" #include "berryConstants.h" #include "berryIDropTarget.h" #include "berryDragUtil.h" #include "berryGuiWidgetsTweaklet.h" #include #include #include #include #include namespace berry { CursorType QtDragManager::PositionToCursorType(int positionConstant) { if (positionConstant == Constants::LEFT) return CURSOR_LEFT; if (positionConstant == Constants::RIGHT) return CURSOR_RIGHT; if (positionConstant == Constants::TOP) return CURSOR_TOP; if (positionConstant == Constants::BOTTOM) return CURSOR_BOTTOM; if (positionConstant == Constants::CENTER) return CURSOR_CENTER; return CURSOR_INVALID; } int QtDragManager::CursorTypeToPosition(CursorType dragCursorId) { switch (dragCursorId) { case CURSOR_LEFT: return Constants::LEFT; case CURSOR_RIGHT: return Constants::RIGHT; case CURSOR_TOP: return Constants::TOP; case CURSOR_BOTTOM: return Constants::BOTTOM; case CURSOR_CENTER: return Constants::CENTER; default: return Constants::DEFAULT; } } bool QtDragManager::eventFilter(QObject* o, QEvent* e) { if (beingCancelled) { if (e->type() == QEvent::KeyRelease && ((QKeyEvent*) e)->key() == Qt::Key_Escape) { QApplication::instance()->removeEventFilter(this); beingCancelled = false; eventLoop->exit(); return true; // block the key release } return false; } if (!o->isWidgetType()) return false; if (e->type() == QEvent::MouseMove) { QMouseEvent* me = (QMouseEvent *) e; this->Move(me->globalPos()); return true; } else if (e->type() == QEvent::MouseButtonRelease) { //DEBUG("pre drop"); QApplication::instance()->removeEventFilter(this); beingCancelled = false; eventLoop->exit(); return true; } if (e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease) { QKeyEvent *ke = ((QKeyEvent*) e); if (ke->key() == Qt::Key_Escape && e->type() == QEvent::KeyPress) { this->Cancel(); QApplication::instance()->removeEventFilter(this); //beingCancelled = false; eventLoop->exit(); } else { // move(QCursor::pos()); } return true; // Eat all key events } // ### We bind modality to widgets, so we have to do this // ### "manually". // DnD is modal - eat all other interactive events switch (e->type()) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseButtonDblClick: case QEvent::MouseMove: case QEvent::KeyPress: case QEvent::KeyRelease: case QEvent::Wheel: case QEvent::ShortcutOverride: #ifdef QT3_SUPPORT case QEvent::Accel: case QEvent::AccelAvailable: #endif return true; default: return false; } } void QtDragManager::Cancel() { beingCancelled = true; } void QtDragManager::Move(const QPoint& globalPos) { emit tracker->Moved(tracker, globalPos); } bool QtDragManager::Drag(QtTracker* tracker) { if (tracker == nullptr) return false; this->tracker = tracker; beingCancelled = false; QApplication::instance()->installEventFilter(this); // if (!QWidget::mouseGrabber()) // rubberBand->grabMouse(); eventLoop = new QEventLoop; eventLoop->exec(); delete eventLoop; eventLoop = nullptr; return !beingCancelled; } QtTracker::QtTracker() : rubberBand(nullptr), dragManager(nullptr), cursorOverride(0) { rubberBand = new QRubberBand(QRubberBand::Rectangle); QPalette rubberPalette(rubberBand->palette()); //rubberPalette.setColor(QPalette::Button, QColor(Qt::darkRed)); rubberPalette.setBrush(QPalette::Foreground, QBrush(Qt::darkRed)); rubberPalette.setBrush(QPalette::Window, QBrush(Qt::darkRed)); rubberPalette.setBrush(QPalette::Background, QBrush(Qt::darkRed)); rubberPalette.setBrush(QPalette::Base, QBrush(Qt::darkRed)); rubberPalette.setBrush(QPalette::Text, QBrush(Qt::darkRed)); rubberBand->setPalette(rubberPalette); rubberBand->ensurePolished(); QPixmap pixCursorTop(":/org.blueberry.ui.qt/cursor_top.xpm"); auto cursorTop = new QCursor(pixCursorTop, 15, 8); cursorMap.insert(CURSOR_TOP, cursorTop); QPixmap pixCursorRight(":/org.blueberry.ui.qt/cursor_right.xpm"); auto cursorRight = new QCursor(pixCursorRight, 23, 15); cursorMap.insert(CURSOR_RIGHT, cursorRight); QPixmap pixCursorBottom(":/org.blueberry.ui.qt/cursor_bottom.xpm"); auto cursorBottom = new QCursor(pixCursorBottom, 16, 23); cursorMap.insert(CURSOR_BOTTOM, cursorBottom); QPixmap pixCursorLeft(":/org.blueberry.ui.qt/cursor_left.xpm"); auto cursorLeft = new QCursor(pixCursorLeft, 8, 15); cursorMap.insert(CURSOR_LEFT, cursorLeft); QPixmap pixCursorCenter(":/org.blueberry.ui.qt/cursor_center.xpm"); auto cursorCenter = new QCursor(pixCursorCenter, 15, 15); cursorMap.insert(CURSOR_CENTER, cursorCenter); QPixmap pixCursorOffscreen(":/org.blueberry.ui.qt/cursor_offscreen.xpm"); auto cursorOffscreen = new QCursor(pixCursorOffscreen, 15, 15); cursorMap.insert(CURSOR_OFFSCREEN, cursorOffscreen); auto cursorInvalid = new QCursor(Qt::ForbiddenCursor); cursorMap.insert(CURSOR_INVALID, cursorInvalid); } QtTracker::~QtTracker() { delete rubberBand; for (QHash::iterator iter = cursorMap.begin(); iter != cursorMap.end(); ++iter) { delete iter.value(); } } QRect QtTracker::GetRectangle() const { return rubberBand->geometry(); } void QtTracker::SetRectangle(const QRect& rectangle) { rubberBand->setGeometry(rectangle); } void QtTracker::SetCursor(CursorType cursorType) { QCursor* cursor = cursorMap[cursorType]; if (!cursor) return; if (cursorOverride > 0) { QApplication::changeOverrideCursor(*cursor); } else { ++cursorOverride; QApplication::setOverrideCursor(*cursor); } } bool QtTracker::Open() { rubberBand->show(); dragManager = new QtDragManager(); bool result = dragManager->Drag(this); delete dragManager; rubberBand->hide(); while (cursorOverride > 0) { QApplication::restoreOverrideCursor(); --cursorOverride; } return result; } QtTrackerMoveListener::QtTrackerMoveListener(Object::Pointer draggedItem, const QRect& sourceBounds, const QPoint& initialLocation, bool allowSnapping) : allowSnapping(allowSnapping) , draggedItem(draggedItem) , sourceBounds(sourceBounds) , initialLocation(initialLocation) { } void QtTrackerMoveListener::Moved(QtTracker* tracker, const QPoint& location) { // Select a drop target; use the global one by default IDropTarget::Pointer target; QWidget* targetControl = Tweaklets::Get(GuiWidgetsTweaklet::KEY)->GetCursorControl(); // Get the drop target for this location target = DragUtil::GetDropTarget(targetControl, draggedItem, location, tracker->GetRectangle()); // Set up the tracker feedback based on the target QRect snapTarget; if (target != 0) { snapTarget = target->GetSnapRectangle(); tracker->SetCursor(target->GetCursor()); } else { tracker->SetCursor(CURSOR_INVALID); } // If snapping then reset the tracker's rectangle based on the current drop target if (allowSnapping) { - if (snapTarget.width() < 0 || snapTarget.height() < 0) + if (snapTarget.width() <= 0 || snapTarget.height() <= 0) { snapTarget = QRect(sourceBounds.x() + location.x() - initialLocation.x(), sourceBounds.y() + location.y() - initialLocation.y(), sourceBounds.width(), sourceBounds.height()); } // Try to prevent flicker: don't change the rectangles if they're already in // the right location QRect currentRectangle = tracker->GetRectangle(); if (!(currentRectangle == snapTarget)) { tracker->SetRectangle(snapTarget); } } } }