de.codesourcery.jasm16.ide.ui.viewcontainers.EditorContainer.java Source code

Java tutorial

Introduction

Here is the source code for de.codesourcery.jasm16.ide.ui.viewcontainers.EditorContainer.java

Source

/**
 * Copyright 2012 Tobias Gierke <tobias.gierke@code-sourcery.de>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.codesourcery.jasm16.ide.ui.viewcontainers;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.apache.commons.lang.StringUtils;

import de.codesourcery.jasm16.compiler.io.DefaultResourceMatcher;
import de.codesourcery.jasm16.compiler.io.IResource;
import de.codesourcery.jasm16.compiler.io.IResourceResolver;
import de.codesourcery.jasm16.exceptions.ResourceNotFoundException;
import de.codesourcery.jasm16.ide.*;
import de.codesourcery.jasm16.ide.ui.MenuManager;
import de.codesourcery.jasm16.ide.ui.MenuManager.MenuEntry;
import de.codesourcery.jasm16.ide.ui.utils.UIUtils;
import de.codesourcery.jasm16.ide.ui.views.*;

public class EditorContainer extends AbstractView implements IViewContainer, IResourceResolver {

    public static final String VIEW_ID = "editor-container";
    private JPanel panel;
    private final String title;

    private final ViewContainerHelper helper = new ViewContainerHelper();
    private final EditorFactory editorFactory;
    private final NavigationHistory navigationHistory = new NavigationHistory();

    private final IWorkspace workspace;
    private final List<ViewWithPanel> views = new ArrayList<ViewWithPanel>();
    private final JTabbedPane tabbedPane = new JTabbedPane();

    private final ChangeListener changeListener = new ChangeListener() {

        private int previouslySelectedTab = -1;

        @Override
        public void stateChanged(ChangeEvent e) {
            final int newIndex = tabbedPane.getSelectedIndex();
            int oldIndex = previouslySelectedTab;
            previouslySelectedTab = newIndex;

            if (oldIndex != newIndex) { // selected index changed

                if (oldIndex != -1) {
                    getViewWithPanelForTabIndex(oldIndex).tabDeselected();
                }
                getViewWithPanelForTabIndex(newIndex).tabSelected();
            }
        }
    };

    private MenuEntry saveCurrent = new MenuEntry("File/Save") {

        @Override
        public void onClick() {
            System.out.println("Save current editor contents");
        }

        public boolean isVisible() {
            return !mayBeDisposed();
        };
    };

    protected final class ViewWithPanel {
        public int tabIndex;

        public final IView view;
        public final JPanel panel;

        public ViewWithPanel(IView view, int tabIndex) {
            this.view = view;
            this.tabIndex = tabIndex;
            this.panel = view.getPanel(EditorContainer.this);
        }

        public void tabSelected() {
            if (view instanceof IViewStateListener) {
                ((IViewStateListener) view).viewVisible();
            }
        }

        public void tabDeselected() {
            if (view instanceof IViewStateListener) {
                ((IViewStateListener) view).viewHidden();
            }
        }

        public void toFront() {
            tabbedPane.setSelectedIndex(tabIndex);
        }
    }

    public EditorContainer(String title, IWorkspace workspace, IViewContainer parent, EditorFactory editorFactory) {
        this.title = title;
        this.workspace = workspace;
        this.editorFactory = editorFactory;
    }

    @Override
    protected JPanel getPanel() {
        if (panel == null) {
            panel = createPanel();
        }
        return panel;
    }

    @Override
    public void setBlockAllUserInput(boolean yesNo) {
        if (panel != null) {
            Container parent = panel.getParent();
            while (parent != null && !(parent instanceof JFrame)) {
                parent = parent.getParent();
            }
            if (parent != null && parent instanceof JFrame) {
                UIUtils.setBlockAllUserInput((JFrame) parent, yesNo);
            }
        }
    }

    @Override
    public void toFront(IView view) {
    }

    private JPanel createPanel() {
        final JPanel result = new JPanel();
        result.setLayout(new GridBagLayout());

        GridBagConstraints cnstrs = constraints(0, 0, true, true, GridBagConstraints.BOTH);

        setColors(result);
        tabbedPane.setBackground(Color.WHITE);
        tabbedPane.setForeground(Color.black);
        result.add(tabbedPane, cnstrs);

        if (getViewContainer().getMenuManager() != null) {
            getViewContainer().getMenuManager().addEntry(saveCurrent);
        }

        tabbedPane.addChangeListener(changeListener);

        tabbedPane.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_W && (e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0) {
                    int idx = tabbedPane.getSelectedIndex();
                    if (idx != -1) {
                        disposeView(getViewForTabIndex(idx));
                    }
                }
            }
        });
        return result;
    }

    public static final void addEditorCloseKeyListener(Component comp, final IEditorView view) {
        comp.addKeyListener(new KeyAdapter() {
            public void keyReleased(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_W && (e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) != 0) {
                    System.out.println("*** Closing editor " + view + " ***");
                    if (view.hasViewContainer()) {
                        view.getViewContainer().disposeView(view);
                    } else {
                        view.dispose();
                    }
                }
            }
        });
    }

    @Override
    public IView addView(IView view) {
        internalAddView(view);
        return view;
    }

    private ViewWithPanel internalAddView(IView view) {
        final int index = tabbedPane.getTabCount();
        final ViewWithPanel newView = new ViewWithPanel(view, index);
        views.add(newView);
        tabbedPane.add(view.getTitle(), newView.panel);
        return newView;
    }

    protected void selectTab(IView view) {
        for (ViewWithPanel v : views) {
            if (v.view == view) {
                tabbedPane.setSelectedIndex(v.tabIndex);
                return;
            }
        }
    }

    protected ViewWithPanel getViewWithPanelForTabIndex(int tabIndex) {
        for (ViewWithPanel v : views) {
            if (v.tabIndex == tabIndex) {
                return v;
            }
        }
        throw new IllegalArgumentException("Invalid tab index: " + tabIndex);
    }

    protected IView getViewForTabIndex(int tabIndex) {
        return getViewWithPanelForTabIndex(tabIndex).view;
    }

    @Override
    public void setTitle(IView view, String title) {
        for (ViewWithPanel p : this.views) {
            if (p.view == view) {
                final int index = tabbedPane.indexOfComponent(p.panel);
                if (index != -1) {
                    tabbedPane.setTitleAt(index, title);
                }
                break;
            }
        }
    }

    @Override
    public void disposeHook() {
        final List<ViewWithPanel> copy = new ArrayList<ViewWithPanel>(this.views);
        for (ViewWithPanel v : copy) {
            v.view.dispose();
        }
        this.views.clear();

        if (getViewContainer().getMenuManager() != null) {
            getViewContainer().getMenuManager().removeEntry(saveCurrent);
        }

        helper.fireViewContainerClosed(this);
    }

    @Override
    public List<IView> getViews() {
        final List<IView> result = new ArrayList<IView>();
        for (ViewWithPanel p : this.views) {
            result.add(p.view);
        }
        return result;
    }

    @Override
    public void disposeView(IView view) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be NULL");
        }

        int disposedTabIndex = -1;
        final List<ViewWithPanel> copy = new ArrayList<ViewWithPanel>(this.views);
        for (Iterator<ViewWithPanel> it = copy.iterator(); it.hasNext();) {
            final ViewWithPanel viewWithPanel = it.next();
            if (viewWithPanel.view == view) {
                this.views.remove(viewWithPanel);
                disposedTabIndex = viewWithPanel.tabIndex;
                this.tabbedPane.remove(viewWithPanel.panel);
                viewWithPanel.view.dispose();
                break;
            }
        }

        if (disposedTabIndex != -1) {
            // adjust tab indices
            int previousTabToFocus = -1;
            int nextTabToFocus = -1;
            for (ViewWithPanel v : this.views) {
                if (v.tabIndex >= disposedTabIndex) {
                    v.tabIndex--;
                    if (nextTabToFocus == -1) {
                        nextTabToFocus = v.tabIndex;
                    }
                } else {
                    previousTabToFocus = v.tabIndex;
                }
            }

            // focus next/previous tab
            if (nextTabToFocus != -1) {
                tabbedPane.setSelectedIndex(nextTabToFocus);
            } else if (previousTabToFocus != -1) {
                tabbedPane.setSelectedIndex(previousTabToFocus);
            }
        }
    }

    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public void refreshDisplay() {
        for (ViewWithPanel p : this.views) {
            p.view.refreshDisplay();
        }
    }

    public IEditorView getEditor(IResource resource) {
        if (resource == null) {
            throw new IllegalArgumentException("resource must not be NULL");
        }

        for (ViewWithPanel p : this.views) {
            if (p.view instanceof IEditorView) {
                if (DefaultResourceMatcher.INSTANCE.isSame(((IEditorView) p.view).getCurrentResource(), resource)) {
                    return (IEditorView) p.view;
                }
            }
        }
        return null;
    }

    @Override
    public boolean mayBeDisposed() {
        boolean result = false;
        for (ViewWithPanel p : this.views) {
            if (p.view instanceof IEditorView) {
                result |= ((IEditorView) p.view).hasUnsavedContent();
            }
        }
        return result;
    }

    @Override
    public String getID() {
        return VIEW_ID;
    }

    @Override
    public IView getViewByID(String viewId) {
        if (StringUtils.isBlank(viewId)) {
            throw new IllegalArgumentException("viewId must not be blank/null");
        }

        for (ViewWithPanel p : this.views) {
            if (p.view.getID().equals(viewId)) {
                return p.view;
            }
        }
        return null;
    }

    @Override
    public MenuManager getMenuManager() {
        return null;
    }

    @Override
    public void addViewContainerListener(IViewContainerListener listener) {
        helper.addViewContainerListener(listener);
    }

    @Override
    public void removeViewContainerListener(IViewContainerListener listener) {
        helper.removeViewContainerListener(listener);
    }

    public IEditorView openResource(IWorkspace workspace, IAssemblyProject project, IResource resource,
            int caretPosition) throws IOException {
        IEditorView editor = getEditor(resource);
        if (editor != null) {
            editor.refreshDisplay();
            selectTab(editor);
            return editor;
        }

        editor = editorFactory.createEditor(project, resource, this, navigationHistory);

        final ViewWithPanel viewWithPanel = internalAddView(editor);

        tabbedPane.setSelectedIndex(viewWithPanel.tabIndex);

        // open resource AFTER IView has been added to this container,
        // view may rely on methods of this container
        editor.openResource(project, resource, caretPosition);
        return editor;
    }

    private List<SourceCodeView> getSourceCodeViews() {
        List<SourceCodeView> result = new ArrayList<SourceCodeView>();
        for (ViewWithPanel view : this.views) {
            if (view.view instanceof SourceCodeView) {
                result.add((SourceCodeView) view.view);
            }
        }
        return result;
    }

    @Override
    public IResource resolve(String identifier) throws ResourceNotFoundException {
        IResource result = tryResolve(identifier);
        if (result == null) {
            throw new ResourceNotFoundException("Failed to find resource '" + identifier + "'", identifier);
        }
        return result;
    }

    private IResource tryResolve(String identifier) {
        for (SourceCodeView v : getSourceCodeViews()) {
            if (v.getSourceFromMemory().getIdentifier().equals(identifier)) {
                return v.getSourceFromMemory();
            }
        }
        return null;
    }

    @Override
    public IResource resolveRelative(String identifier, IResource parent) throws ResourceNotFoundException {
        IResource result = tryResolve(identifier);
        if (result == null) {
            throw new ResourceNotFoundException("Failed to find resource '" + identifier + "'", identifier);
        }
        return result;
    }
}