/** * Copyright (c) 2009, 2014 Mark Feber, MulgaSoft * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package com.mulgasoft.emacsplus.e4.commands; import java.util.List; import javax.inject.Named; import org.eclipse.e4.core.contexts.Active; import org.eclipse.e4.core.di.annotations.Execute; import org.eclipse.e4.ui.model.application.ui.MElementContainer; import org.eclipse.e4.ui.model.application.ui.MUIElement; import org.eclipse.e4.ui.model.application.ui.basic.MPart; import org.eclipse.e4.ui.model.application.ui.basic.MTrimmedWindow; import org.eclipse.e4.ui.model.application.ui.basic.MWindow; import org.eclipse.e4.ui.workbench.modeling.EPartService.PartState; import org.eclipse.jface.text.BadLocationException; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.texteditor.ITextEditor; import com.mulgasoft.emacsplus.Beeper; import com.mulgasoft.emacsplus.EmacsPlusUtils; import com.mulgasoft.emacsplus.commands.EmacsPlusCmdHandler; import com.mulgasoft.emacsplus.commands.MinibufferHandler; import com.mulgasoft.emacsplus.minibuffer.IMinibufferExecutable; import com.mulgasoft.emacsplus.minibuffer.SwitchMinibuffer; /** * switch-to-buffer-other-frame: Select buffer in another frame * display-buffer-other-frame: Display buffer in another frame without selecting * * Prompt for a buffer and select it in another frame. If: * - only one frame, then make a new frame * - multiple frames, move buffer to adjacent frame if not in destination frame * - else simply expose in destination frame * * @author mfeber - Initial API and implementation */ public class SwitchToBufferFrameCmd extends FrameCreateCmd implements IMinibufferExecutable { MWindow window; private MPart apart; private EmacsPlusCmdHandler handler; private boolean displayOnly = false; private String prefix = "Buffer%s"; //$NON-NLS-1$ @Execute public Object execute(@Active MWindow window, @Active MPart apart, @Active IEditorPart editor, @Active EmacsPlusCmdHandler handler, @Named(E4CmdHandler.CMD_CTX_KEY)boolean display, @Named(E4CmdHandler.PRE_CTX_KEY) String prefix) { this.window = window; this.handler = handler; this.apart = apart; this.displayOnly = display; this.prefix = prefix; try { ITextEditor ted = EmacsPlusUtils.getTextEditor(editor, true); if (ted != null) { MinibufferHandler.bufferTransform(new SwitchMinibuffer(this, true), ted, null); } } catch (BadLocationException e) { // Shouldn't happen Beeper.beep(); } return null; } @SuppressWarnings("unchecked") // for safe cast to (MElementContainer<MUIElement>) public boolean executeResult(ITextEditor editor, Object minibufferResult) { if (minibufferResult instanceof IEditorPart) { // get the MPart from the editor MPart miniPart = (MPart) ((IEditorPart) minibufferResult).getSite().getService(MPart.class); Object minw = getTopElement(miniPart.getParent()); // crap - modelService always returns the main window MWindow partWindow = (minw instanceof MWindow) ? (MWindow)minw : modelService.getTopLevelWindowFor(miniPart); List<MTrimmedWindow> frames = getDetachedFrames(); if (partWindow == window) { if (frames == null || frames.isEmpty()) { // case 1: one frame, make a new one splitIt(miniPart, 0); } else { // case 2: multiple frames, move to adjacent frame MElementContainer<MUIElement> stack; int index = frames.indexOf(partWindow) + 1; MUIElement frame; if (index == frames.size()) { // get editor MArea of main window frame = getEditArea(modelService.getTopLevelWindowFor(miniPart)); } else { frame = frames.get((index < 0) ? 0 : index); } stack = getStacks((MElementContainer<MUIElement>)frame).get(0); modelService.move(miniPart, stack, 0); } } else if (!alreadyFramed(partWindow, frames)) { // case 3: different frames, move to this frame MElementContainer<MUIElement> stack = getParentStack(apart).getStack(); // get the topart's stack MElementContainer<MUIElement> mstack = getParentStack(miniPart).getStack(); if (stack != null && stack != mstack) { modelService.move(miniPart, stack, 0); } } if (displayOnly) { // brings to top partService.showPart(miniPart, PartState.VISIBLE); reactivate(apart); } else { reactivate(miniPart); } } return false; } private boolean alreadyFramed(MWindow partWindow, List<MTrimmedWindow> frames) { // NB: This differs from emacs behavior, but seems much more useful in Eclipse // as it allows easily adding a buffer to a frame's stack. // buffer is in a frame, and command comes from main window return frames.contains(partWindow) && !frames.contains(window); } public boolean isUniversalPresent() { return handler.isUniversalPresent(); } public String getMinibufferPrefix() { return prefix; } /** * @see com.mulgasoft.emacsplus.minibuffer.IMinibufferExecutable#setResultMessage(java.lang.String, boolean) */ public void setResultMessage(String resultMessage, boolean resultError) { } }