/* * SoapUI, Copyright (C) 2004-2016 SmartBear Software * * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent * versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * * Unless required by applicable law or agreed to in writing, software distributed under the Licence is * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the Licence for the specific language governing permissions and limitations * under the Licence. */ package com.eviware.soapui.support.editor; import com.eviware.soapui.support.UISupport; import com.eviware.soapui.support.components.Inspector; import com.eviware.soapui.support.components.JInspectorPanel; import com.eviware.soapui.support.components.JInspectorPanelFactory; import com.eviware.soapui.support.components.VTextIcon; import com.eviware.soapui.support.components.VerticalMetalTabbedPaneUI; import com.eviware.soapui.support.components.VerticalWindowsTabbedPaneUI; import javax.swing.JPanel; import javax.swing.JTabbedPane; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.BorderLayout; import java.awt.Color; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.List; /** * Editor-framework for Documents * * @author ole.matzura */ @SuppressWarnings("serial") public class Editor<T extends EditorDocument> extends JPanel implements PropertyChangeListener, EditorLocationListener<T> { public final static String OUTLINE_TABLE_PROPERTY = Editor.class.getSimpleName() + "@outlineTable"; private JTabbedPane inputTabs; private List<EditorView<T>> views = new ArrayList<EditorView<T>>(); private EditorView<T> currentView; private T document; private JInspectorPanel inspectorPanel; private InputTabsChangeListener inputTabsChangeListener; public Editor(T document) { super(new BorderLayout()); this.document = document; document.addPropertyChangeListener(EditorDocument.DOCUMENT_PROPERTY, this); setBackground(Color.WHITE); inputTabs = new JTabbedPane(JTabbedPane.LEFT, JTabbedPane.SCROLL_TAB_LAYOUT); prettifyTabbedPaneUI(); inputTabs.setFont(inputTabs.getFont().deriveFont(8)); inputTabsChangeListener = new InputTabsChangeListener(); inputTabs.addChangeListener(inputTabsChangeListener); inspectorPanel = JInspectorPanelFactory.build(inputTabs); add(inspectorPanel.getComponent(), BorderLayout.CENTER); } private void prettifyTabbedPaneUI() { if (!UISupport.isMac()) { // For some reason the tabs get very wide in some L&Fs. Workaround is to replace the UI. if (inputTabs.getUI().getClass().getSimpleName().equals("WindowsTabbedPaneUI")) { inputTabs.setUI(new VerticalWindowsTabbedPaneUI()); } else { inputTabs.setUI(new VerticalMetalTabbedPaneUI()); } } } public void addEditorView(EditorView<T> editorView) { views.add(editorView); if (UISupport.isMac()) { inputTabs.addTab(editorView.getTitle(), editorView.getComponent()); } else { inputTabs.addTab(null, new VTextIcon(inputTabs, editorView.getTitle(), VTextIcon.ROTATE_LEFT), editorView.getComponent()); } editorView.addPropertyChangeListener(this); editorView.addLocationListener(this); editorView.setDocument(document); } public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals(EditorView.TITLE_PROPERTY)) { int ix = views.indexOf(evt.getSource()); if (ix == -1) { return; } inputTabs.setTitleAt(ix, (String) evt.getNewValue()); } if (evt.getPropertyName().equals(EditorDocument.DOCUMENT_PROPERTY)) { inputTabsChangeListener.refreshVisibleInspectors(); } } public void selectView(int viewIndex) { inputTabs.setSelectedIndex(viewIndex); } public void selectView(String viewId) { for (int c = 0; c < views.size(); c++) { if (views.get(c).getViewId().equals(viewId)) { inputTabs.setSelectedIndex(c); return; } } } @SuppressWarnings("unchecked") public void locationChanged(EditorLocation<T> location) { if (location != null) { for (Inspector inspector : inspectorPanel.getInspectors()) { ((EditorInspector<T>) inspector).locationChanged(location); } } } public void requestFocus() { if (currentView != null) { currentView.getComponent().requestFocus(); } } public T getDocument() { return document; } public boolean hasFocus() { return currentView == null ? false : currentView.getComponent().hasFocus(); } public final void setDocument(T document) { if (this.document != null) { this.document.release(); this.document.removePropertyChangeListener(EditorDocument.DOCUMENT_PROPERTY, this); } this.document = document; this.document.addPropertyChangeListener(EditorDocument.DOCUMENT_PROPERTY, this); for (EditorView<T> view : views) { view.setDocument(document); } inputTabsChangeListener.refreshVisibleInspectors(); } public final EditorView<T> getCurrentView() { return currentView; } public final JTabbedPane getInputTabs() { return inputTabs; } public final List<EditorView<T>> getViews() { return views; } public EditorView<T> getView(String viewId) { for (EditorView<T> view : views) { if (view.getViewId().equals(viewId)) { return view; } } return null; } public Inspector getInspector(String inspectorId) { return inspectorPanel.getInspector(inspectorId); } public void setEditable(boolean enabled) { for (EditorView<T> view : views) { view.setEditable(enabled); } } public void addInspector(EditorInspector<T> inspector) { inspectorPanel.addInspector(inspector); inspector.init(this); inspectorPanel .setInspectorVisible(inspector, currentView == null ? true : inspector.isEnabledFor(currentView)); } private final class InputTabsChangeListener implements ChangeListener { private int lastDividerLocation; @SuppressWarnings("unchecked") public void stateChanged(ChangeEvent e) { int currentViewIndex = views.indexOf(currentView); if (currentView != null) { if (inputTabs.getSelectedIndex() == currentViewIndex) { return; } if (!currentView.deactivate()) { inputTabs.setSelectedIndex(currentViewIndex); return; } } EditorView<T> previousView = currentView; int selectedIndex = inputTabs.getSelectedIndex(); if (selectedIndex == -1) { currentView = null; return; } currentView = views.get(selectedIndex); if (currentView != null && !currentView.activate(previousView == null ? null : previousView.getEditorLocation())) { inputTabs.setSelectedIndex(currentViewIndex); if (currentViewIndex == -1) { return; } } refreshVisibleInspectors(); SwingUtilities.invokeLater(new Runnable() { public void run() { if (currentView != null) { currentView.getComponent().requestFocus(); } } }); } private void refreshVisibleInspectors() { EditorInspector<T> currentInspector = (EditorInspector<T>) inspectorPanel.getCurrentInspector(); if (currentInspector != null) { lastDividerLocation = inspectorPanel.getDividerLocation(); } for (Inspector inspector : inspectorPanel.getInspectors()) { inspectorPanel.setInspectorVisible(inspector, ((EditorInspector<T>) inspector).isEnabledFor(currentView)); } if (currentInspector != null && ((EditorInspector<T>) currentInspector).isEnabledFor(currentView)) { if (lastDividerLocation == 0) { inspectorPanel.setResetDividerLocation(); } else { inspectorPanel.setDividerLocation(lastDividerLocation); } } else { currentInspector = null; } } } public void release() { for (EditorView<T> view : views) { view.release(); view.removePropertyChangeListener(this); } views.clear(); inputTabs.removeChangeListener(inputTabsChangeListener); inputTabs.removeAll(); inspectorPanel.release(); document.release(); } }