Java tutorial
/** * 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; } }