All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.parosproxy.paros.view.WorkbenchPanel Maven / Gradle / Ivy

Go to download

The Zed Attack Proxy (ZAP) is an easy to use integrated penetration testing tool for finding vulnerabilities in web applications. It is designed to be used by people with a wide range of security experience and as such is ideal for developers and functional testers who are new to penetration testing. ZAP provides automated scanners as well as a set of tools that allow you to find security vulnerabilities manually.

There is a newer version: 2.15.0
Show newest version
/*
 *
 * Paros and its related class files.
 *
 * Paros is an HTTP/HTTPS proxy for assessing web application security.
 * Copyright (C) 2003-2004 Chinotec Technologies Company
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the Clarified Artistic License
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * Clarified Artistic License for more details.
 *
 * You should have received a copy of the Clarified Artistic License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
// ZAP: 2011/05/31 Added option to dynamically change the display
// ZAP: 2011/07/25 Added automatically save/restore of divider locations
// ZAP: 2013/02/17 Issue 496: Allow to see the request and response at the same
// time in the main window
// ZAP: 2013/02/26 Issue 540: Maximised work tabs hidden when response tab
// position changed
// ZAP: 2013/03/03 Issue 546: Remove all template Javadoc comments
// ZAP: 2013/05/02 Removed redundant final modifiers from private methods
// ZAP: 2013/12/13 Added support for 'Full Layout'.
// ZAP: 2014/01/28 Issue 207: Support keyboard shortcuts
// ZAP: 2014/10/07 Issue 1357: Hide unused tabs
// ZAP: 2015/02/11 Ensure that a tab is always selected when the layout is switched
// ZAP: 2015/12/14 Disable request/response tab buttons location when in full layout
// ZAP: 2016/04/06 Fix layouts' issues
// ZAP: 2017/08/30 Add tool tip to response tab.
// ZAP: 2018/02/14 Add new layout ResponsePanelPosition.TAB_SIDE_BY_SIDE (Issue 4331).
// ZAP: 2018/04/03 Update for behavioural changes in TabbedPanel2.
// ZAP: 2019/06/01 Normalise line endings.
// ZAP: 2019/06/05 Normalise format/style.
// ZAP: 2020/11/02 Add OneTouchExapandable control to Sites Tree/Request&Response panels
// ZAP: 2020/11/26 Use Log4j 2 classes for logging.
// ZAP: 2022/02/26 Remove deprecated methods in 2.5.0
// ZAP: 2022/09/21 Use format specifiers instead of concatenation when logging.
// ZAP: 2023/01/10 Tidy up logger.
package org.parosproxy.paros.view;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.parosproxy.paros.Constant;
import org.parosproxy.paros.extension.AbstractPanel;
import org.parosproxy.paros.extension.option.OptionsParamView;
import org.zaproxy.zap.utils.DisplayUtils;
import org.zaproxy.zap.view.ComponentMaximiser;
import org.zaproxy.zap.view.ComponentMaximiserMouseListener;
import org.zaproxy.zap.view.TabbedPanel2;

/**
 * A workbench panel, responsible to show and manage the main panels.
 *
 * @since 1.0.0
 */
@SuppressWarnings("serial")
public class WorkbenchPanel extends JPanel {

    /**
     * The layouts available to a {@code WorkbenchPanel}.
     *
     * @since 2.5.0
     * @see ResponsePanelPosition
     */
    public enum Layout {
        /**
         * Divides the panel in 3 areas, {@code select}, {@code status} and {@code work}, containing
         * the {@link WorkbenchPanel.PanelType#SELECT SELECT}, {@link
         * WorkbenchPanel.PanelType#STATUS STATUS} and {@link WorkbenchPanel.PanelType#WORK WORK}
         * panels, respectively. The {@code select} area occupies the left portion of the workbench
         * panel while the areas {@code work} and {@code status} occupy the top-right and
         * bottom-right portions of the workbench panel, respectively.
         *
         * 

All the areas can be resized (using {@code JSplitPane}s) and maximised (using {@link * ComponentMaximiser}). */ EXPAND_SELECT(0), /** * The default layout, divides the panel in 3 areas, {@code select}, {@code status} and * {@code work}, containing the {@link WorkbenchPanel.PanelType#SELECT SELECT}, {@link * WorkbenchPanel.PanelType#STATUS STATUS} and {@link WorkbenchPanel.PanelType#WORK WORK} * panels, respectively. The {@code status} area is located at the bottom of the workbench * panel while the areas {@code select} and {@code work} are located in the top-left and * top-right portions of the workbench panel, respectively. * *

All the areas can be resized (using {@code JSplitPane}s) and maximised (using {@link * ComponentMaximiser}). */ EXPAND_STATUS(1), /** * A layout that has only one area that occupies the whole workbench panel and where all * panels ( {@link WorkbenchPanel.PanelType#SELECT SELECT}, {@link * WorkbenchPanel.PanelType#STATUS STATUS} and {@link WorkbenchPanel.PanelType#WORK WORK}) * are shown. * *

Since it already occupies the whole workbench panel the area can not be resized nor * maximised. */ FULL(2); /** The ID of the layout. */ private final int id; private Layout(int id) { this.id = id; } /** * Gets the ID of the layout. * *

Unique among all layouts, thus suitable for persistence of options. * * @return the ID of the layout * @see #getLayout(int) */ public int getId() { return id; } /** * Gets the {@code Layout} corresponding to the given ID. * * @param id the ID of the layout * @return the {@code Layout} corresponding to the given ID, or {@link #EXPAND_STATUS} if * the ID is unknown. */ public static Layout getLayout(int id) { if (id == Layout.EXPAND_SELECT.getId()) { return Layout.EXPAND_SELECT; } if (id == Layout.EXPAND_STATUS.getId()) { return Layout.EXPAND_STATUS; } if (id == Layout.FULL.getId()) { return Layout.FULL; } return Layout.EXPAND_STATUS; } } /** * The position of the response panel, with respect to the request panel. * *

The position of the response panel can be changed dynamically but might not be used by all * layouts, for example, the Full Layout. * * @since 2.5.0 * @see Layout */ public enum ResponsePanelPosition { /** Request and response panels are shown, side-by-side, in the same tabbed panel. */ TABS_SIDE_BY_SIDE, /** * Request panel is shown above the response panel, in different tabbed panels. * *

Not supported in {@link Layout#FULL FULL layout}. */ PANEL_ABOVE, /** * Request and response panels are shown, side-by-side, in different tabbed panels. * *

Not supported in {@link Layout#FULL FULL layout}. */ PANELS_SIDE_BY_SIDE, /** * Request and response panels are shown, side-by-side, in the same tab. * * @since 2.8.0 */ TAB_SIDE_BY_SIDE } /** * The type of panels added to the {@code WorkbenchPanel}, used as hint when doing the layout of * the panels. * *

Panels of the same type might be shown in the same area of the workbench panel. Some * layouts, like {@link Layout#FULL}, might choose to ignore the type of the panels. * * @since 2.5.0 */ public enum PanelType { /** * The panels that provide status/data about extensions/components, for example, History * panel. */ STATUS, /** * The panels that allow to select/display general data, for example, Sites or Scripts * panels. */ SELECT, /** * The panels that allow to display/manipulate common data, for example, Request and * Response panels. */ WORK } private static final long serialVersionUID = -4610792807151921550L; private static final Logger LOGGER = LogManager.getLogger(WorkbenchPanel.class); private static final String PREF_DIVIDER_LOCATION = "divider.location"; private static final String DIVIDER_VERTICAL = "vertical"; private static final String DIVIDER_HORIZONTAL = "horizontal"; private final Preferences preferences; private final String prefnzPrefix = this.getClass().getSimpleName() + "."; /** * The request panel, used for positioning the response panel. * * @see #setResponsePanelPosition(ResponsePanelPosition) */ private final AbstractPanel requestPanel; /** * The response panel, moved around depending on the option {@code response panel position}. * * @see #setResponsePanelPosition(ResponsePanelPosition) */ private final AbstractPanel responsePanel; /** * A tabbed panel to show the response panel, when it is shown separately from other panels. * *

Main purpose is to show the request and response panels at the same time (in different * tabs). * * @see #setResponsePanelPosition(ResponsePanelPosition) */ private final TabbedPanel2 responseTabbedPanel; /** * The index of the {@link #requestPanel} in the tabbed pane of the current {@link #layout}. * * @see #getCurrentRequestTabIndex() */ private int requestTabIndex; /** * A {@code JSplitPane} to show the request and response in the same tab. * *

Lazily initialised. * * @see ResponsePanelPosition#TAB_SIDE_BY_SIDE * @see #splitResponsePanelWithRequestPanel(int, TabbedPanel2) */ private JSplitPane splitRequestAndResponse; /** * The panel that shows the request and response in the same tab. * *

Lazily initialised. * * @see ResponsePanelPosition#TAB_SIDE_BY_SIDE * @see #splitResponsePanelWithRequestPanel(int, TabbedPanel2) */ private AbstractPanel splitRequestAndResponsePanel; /** * The object to maximise the components when in some layouts. * *

The components are not maximised in Full Layout, they already occupy the whole workbench * panel. */ private final ComponentMaximiser componentMaximiser; /** * The layout of the workbench panel. * * @see #setWorkbenchLayout(Layout) */ private Layout layout; /** * The position of the response panel. * * @see #setResponsePanelPosition(ResponsePanelPosition) */ private ResponsePanelPosition responsePanelPosition; /** * The tabbed panel for {@link PanelType#STATUS STATUS} panels. * *

Lazily initialised. * * @see #getTabbedStatus() */ private TabbedPanel2 tabbedStatus; /** * The {@code JPanel} that has the tabbed panel {@link #tabbedStatus}, represents the {@code * status} area. * *

Lazily initialised. * * @see #getPaneStatus() */ private JPanel paneStatus; /** * The tabbed panel for {@link PanelType#SELECT SELECT} panels. * *

Lazily initialised. * * @see #getTabbedSelect() */ private TabbedPanel2 tabbedSelect; /** * The {@code JPanel} that has the tabbed panel {@link #tabbedSelect}, represents the {@code * select} area. * *

Lazily initialised. * * @see #getPaneSelect() */ private JPanel paneSelect; /** * The tabbed panel for {@link PanelType#WORK WORK} panels. * *

Lazily initialised. * * @see #getTabbedWork() */ private TabbedPanel2 tabbedWork; /** * The {@code JPanel} that has the tabbed panel {@link #tabbedWork}, represents the {@code work} * area. * *

Lazily initialised. * * @see #getPaneWork() */ private JPanel paneWork; /** * The tabbed panel for all {@link PanelType types} of panels, when in {@link Layout#FULL FULL} * layout. * *

Lazily initialised. * * @see #getTabbedFull() */ private TabbedPanel2 tabbedFull; /** * The {@code JPanel} that has the tabbed panel {@link #tabbedFull}, that is, the {@link * Layout#FULL FULL} layout. * *

Lazily initialised. * * @see #getFullLayoutPanel() */ private JPanel fullLayoutPanel; /** * Flag that indicates whether or not the tabs should show the panels' names. * *

When false only the icons are shown, otherwise it is shown the icons and the names. */ private boolean showTabNames; /** * Constructs a {@code WorkbenchPanel} with the given options and request and response panels. * * @param viewOptions the options * @param requestPanel the request panel * @param responsePanel the response panel * @throws IllegalArgumentException if any of the parameters is {@code null}. * @since 2.5.0 */ public WorkbenchPanel( OptionsParamView viewOptions, AbstractPanel requestPanel, AbstractPanel responsePanel) { super(new BorderLayout()); validateNotNull(viewOptions, "viewOptions"); validateNotNull(requestPanel, "requestPanel"); validateNotNull(responsePanel, "responsePanel"); this.requestPanel = requestPanel; this.responsePanel = responsePanel; this.componentMaximiser = new ComponentMaximiser(this); this.showTabNames = true; ComponentMaximiserMouseListener maximiseMouseListener = new ComponentMaximiserMouseListener(viewOptions, componentMaximiser); responseTabbedPanel = new TabbedPanel2(); responseTabbedPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); responseTabbedPanel.addMouseListener(maximiseMouseListener); getTabbedWork().addMouseListener(maximiseMouseListener); getTabbedStatus().addMouseListener(maximiseMouseListener); getTabbedSelect().addMouseListener(maximiseMouseListener); addPanel(requestPanel, PanelType.WORK); addPanel(responsePanel, PanelType.WORK); this.preferences = Preferences.userNodeForPackage(getClass()); requestTabIndex = -1; setResponsePanelPosition(ResponsePanelPosition.TABS_SIDE_BY_SIDE); setWorkbenchLayout(Layout.EXPAND_STATUS); } /** * Validates that the given {@code parameter} is not {@code null}, throwing an {@code * IllegalArgumentException} if it is. * *

The given parameter name is used in the exception message to indicate which parameter must * not be {@code null}. * * @param parameter the parameter to be validated * @param parameterName the name of the parameter * @throws IllegalArgumentException if the parameter is {@code null}. */ private static void validateNotNull(Object parameter, String parameterName) { if (parameter == null) { throw new IllegalArgumentException("Parameter " + parameterName + " must not be null"); } } /** * Gets the layout of the workbench panel. * * @return the layout, never {@code null} * @since 2.5.0 */ public Layout getWorkbenchLayout() { return layout; } /** * Sets the layout of the workbench panel. * * @param layout the layout to set * @throws IllegalArgumentException if the given parameter is {@code null}. * @since 2.5.0 */ void setWorkbenchLayout(Layout layout) { validateNotNull(layout, "layout"); if (this.layout == layout) { return; } requestTabIndex = getCurrentRequestTabIndex(); Layout previousLayout = this.layout; this.layout = layout; componentMaximiser.unmaximiseComponent(); removeAll(); List visiblePanels; switch (layout) { case FULL: visiblePanels = getTabbedStatus().getVisiblePanels(); getTabbedStatus().hideAllTabs(); visiblePanels.addAll(getTabbedWork().getVisiblePanels()); getTabbedWork().hideAllTabs(); visiblePanels.addAll(getTabbedSelect().getVisiblePanels()); getTabbedSelect().hideAllTabs(); getTabbedFull().setVisiblePanels(visiblePanels); updateFullLayout(); this.add(getFullLayoutPanel()); break; case EXPAND_SELECT: case EXPAND_STATUS: default: this.add( layout == Layout.EXPAND_STATUS ? createStatusPanelsSplit() : createSelectPanelsSplit()); if (previousLayout == Layout.FULL) { visiblePanels = getTabbedFull().getVisiblePanels(); getTabbedFull().hideAllTabs(); getTabbedStatus().setVisiblePanels(visiblePanels); getTabbedWork().setVisiblePanels(visiblePanels); getTabbedSelect().setVisiblePanels(visiblePanels); setResponsePanelPosition(responsePanelPosition); } break; } this.validate(); this.repaint(); } /** * Gets index of the {@link #requestPanel} in the tabbed pane of the current {@link #layout}. * *

Note: This should be called prior changing the layout or position of the * response panel, as it affects the actual position of request panel. * * @return the index of the request panel. */ private int getCurrentRequestTabIndex() { if (layout == Layout.FULL) { if (responsePanelPosition == ResponsePanelPosition.TAB_SIDE_BY_SIDE) { return getTabbedFull().indexOfComponent(splitRequestAndResponsePanel); } return getTabbedFull().indexOfComponent(requestPanel); } if (responsePanelPosition == ResponsePanelPosition.TAB_SIDE_BY_SIDE) { int idx = getTabbedWork().indexOfComponent(splitRequestAndResponsePanel); if (idx != -1) { return idx; } } int idx = getTabbedWork().indexOfComponent(requestPanel); if (idx != -1) { return idx; } // Panel not shown yet, return "old" index. return requestTabIndex; } /** * Creates a split pane between the {@code status} area (bottom component) and {@code work} area * or a split between {@code work} and {@code select} areas (top component), if the layout is * {@link Layout#EXPAND_SELECT EXPAND_SELECT} or {@link Layout#EXPAND_STATUS EXPAND_STATUS}, * respectively. * * @return a {@code JSplitPane} between the {@code status} area and other areas */ private JSplitPane createStatusPanelsSplit() { JSplitPane splitVert = new JSplitPane(); splitVert.setDividerLocation(restoreDividerLocation(DIVIDER_VERTICAL, 300)); splitVert.addPropertyChangeListener( JSplitPane.DIVIDER_LOCATION_PROPERTY, new DividerResizedListener(DIVIDER_VERTICAL)); splitVert.setDividerSize(3); splitVert.setOrientation(JSplitPane.VERTICAL_SPLIT); splitVert.setResizeWeight(0.5D); switch (layout) { case EXPAND_SELECT: splitVert.setTopComponent(getPaneWork()); break; case EXPAND_STATUS: default: splitVert.setTopComponent(createSelectPanelsSplit()); break; } splitVert.setBottomComponent(getPaneStatus()); splitVert.setContinuousLayout(false); splitVert.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); return splitVert; } /** * Creates a split pane between the {@code select} area (left component) and {@code work} area * or a split between {@code work} and {@code status} areas (right component), if the layout is * {@link Layout#EXPAND_STATUS EXPAND_STATUS} or {@link Layout#EXPAND_SELECT EXPAND_SELECT}, * respectively. * * @return a {@code JSplitPane} between the {@code select} area and other areas */ private JSplitPane createSelectPanelsSplit() { JSplitPane splitHoriz = new JSplitPane(); splitHoriz.setOneTouchExpandable(true); splitHoriz.setLeftComponent(getPaneSelect()); switch (layout) { case EXPAND_SELECT: splitHoriz.setRightComponent(createStatusPanelsSplit()); break; case EXPAND_STATUS: default: splitHoriz.setRightComponent(getPaneWork()); break; } splitHoriz.setDividerLocation(restoreDividerLocation(DIVIDER_HORIZONTAL, 300)); splitHoriz.addPropertyChangeListener( JSplitPane.DIVIDER_LOCATION_PROPERTY, new DividerResizedListener(DIVIDER_HORIZONTAL)); splitHoriz.setResizeWeight(0.3D); splitHoriz.setContinuousLayout(false); splitHoriz.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); return splitHoriz; } /** * This method initializes paneStatus * * @return JPanel */ private JPanel getPaneStatus() { if (paneStatus == null) { paneStatus = new JPanel(); paneStatus.setLayout(new BorderLayout(0, 0)); paneStatus.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); paneStatus.add(getTabbedStatus()); } return paneStatus; } /** * This method initializes paneSelect * * @return JPanel */ private JPanel getPaneSelect() { if (paneSelect == null) { paneSelect = new JPanel(); paneSelect.setLayout(new BorderLayout(0, 0)); paneSelect.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); paneSelect.add(getTabbedSelect()); } return paneSelect; } /** * This method initializes paneWork, which is used for request/response/break/script console. * * @return JPanel */ private JPanel getPaneWork() { if (paneWork == null) { paneWork = new JPanel(); paneWork.setLayout(new BorderLayout(0, 0)); paneWork.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); paneWork.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); paneWork.add(getTabbedWork()); } return paneWork; } private JPanel getFullLayoutPanel() { if (fullLayoutPanel == null) { fullLayoutPanel = new JPanel(); fullLayoutPanel.setLayout(new BorderLayout(0, 0)); fullLayoutPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); fullLayoutPanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); fullLayoutPanel.add(getTabbedFull()); } return fullLayoutPanel; } private TabbedPanel2 getTabbedFull() { if (tabbedFull == null) { tabbedFull = new TabbedPanel2(); tabbedFull.setName("tabbedFull"); tabbedFull.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); } return tabbedFull; } /** * Gets the tabbed panel that has the {@link PanelType#STATUS STATUS} panels. * *

Direct access/manipulation of the tabbed panel is discouraged, the changes done to it * might be lost while changing layouts. * * @return the tabbed panel of the {@code status} panels, never {@code null} * @see #addPanel(AbstractPanel, PanelType) */ public TabbedPanel2 getTabbedStatus() { if (tabbedStatus == null) { tabbedStatus = new TabbedPanel2(); tabbedStatus.setPreferredSize(new Dimension(800, 200)); // ZAP: Move tabs to the top of the panel tabbedStatus.setTabPlacement(JTabbedPane.TOP); tabbedStatus.setName("tabbedStatus"); tabbedStatus.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); } return tabbedStatus; } /** * Gets the tabbed panel that has the {@link PanelType#WORK WORK} panels. * *

Direct access/manipulation of the tabbed panel is discouraged, the changes done to it * might be lost while changing layouts. * * @return the tabbed panel of the {@code work} panels, never {@code null} * @see #addPanel(AbstractPanel, PanelType) */ public TabbedPanel2 getTabbedWork() { if (tabbedWork == null) { tabbedWork = new TabbedPanel2(); tabbedWork.setPreferredSize(new Dimension(600, 400)); tabbedWork.setName("tabbedWork"); tabbedWork.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); } return tabbedWork; } /** * Sets whether or not the tabs should display the name of the panels. * *

The call to this method has not effect if the state is already set. * * @param showTabNames {@code true} if the names should be shown, {@code false} otherwise. * @since 2.4.0 */ public void toggleTabNames(boolean showTabNames) { if (this.showTabNames == showTabNames) { return; } this.showTabNames = showTabNames; responseTabbedPanel.setShowTabNames(showTabNames); if (layout != Layout.FULL) { getTabbedStatus().setShowTabNames(showTabNames); getTabbedSelect().setShowTabNames(showTabNames); getTabbedWork().setShowTabNames(showTabNames); } else { getTabbedFull().setShowTabNames(showTabNames); } } /** * Gets the tabbed panel that has the {@link PanelType#SELECT SELECT} panels. * *

Direct access/manipulation of the tabbed panel is discouraged, the changes done to it * might be lost while changing layouts. * * @return the tabbed panel of the {@code work} panels, never {@code null} * @see #addPanel(AbstractPanel, PanelType) */ public TabbedPanel2 getTabbedSelect() { if (tabbedSelect == null) { tabbedSelect = new TabbedPanel2(); tabbedSelect.setPreferredSize(new Dimension(200, 400)); tabbedSelect.setName("tabbedSelect"); tabbedSelect.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); } return tabbedSelect; } /** * Adds the given panels to the workbench, hinting with the given panel type. * * @param panels the panels to add to the workbench * @param panelType the type of the panels * @throws IllegalArgumentException if any of the parameters is {@code null}. * @since 2.5.0 * @see #removePanels(List, PanelType) * @see #addPanel(AbstractPanel, PanelType) */ public void addPanels(List panels, PanelType panelType) { validateNotNull(panels, "panels"); validateNotNull(panelType, "panelType"); boolean fullLayout = layout == Layout.FULL; addPanels(getTabbedFull(), panels, fullLayout); switch (panelType) { case SELECT: addPanels(getTabbedSelect(), panels, !fullLayout); break; case STATUS: addPanels(getTabbedStatus(), panels, !fullLayout); break; case WORK: addPanels(getTabbedWork(), panels, !fullLayout); break; default: break; } } /** * Adds the given {@code panels} to the given {@code tabbedPanel} and whether they should be * visible. * *

After adding all the panels the tabbed panel is revalidated. * * @param tabbedPanel the tabbed panel to add the panels * @param panels the panels to add * @param visible {@code true} if the panel should be visible, {@code false} otherwise. * @see #addPanel(TabbedPanel2, AbstractPanel, boolean) * @see javax.swing.JComponent#revalidate() */ private static void addPanels( TabbedPanel2 tabbedPanel, List panels, boolean visible) { for (AbstractPanel panel : panels) { addPanel(tabbedPanel, panel, visible); } tabbedPanel.revalidate(); } /** * Adds the given {@code panel} to the given {@code tabbedPanel}. * * @param tabbedPanel the tabbed panel to add the panel * @param panel the panel to add * @param visible {@code true} if the panel should be visible, {@code false} otherwise. * @see #addPanels(TabbedPanel2, List, boolean) */ private static void addPanel(TabbedPanel2 tabbedPanel, AbstractPanel panel, boolean visible) { if (visible) { tabbedPanel.addTab(panel); } else { tabbedPanel.addTabHidden(panel); } } /** * Adds the given panel to the workbench, hinting with the given panel type. * * @param panel the panel to add to the workbench * @param panelType the type of the panel * @throws IllegalArgumentException if any of the parameters is {@code null}. * @since 2.5.0 * @see #removePanel(AbstractPanel, PanelType) * @see #addPanels(List, PanelType) */ public void addPanel(AbstractPanel panel, PanelType panelType) { validateNotNull(panel, "panel"); validateNotNull(panelType, "panelType"); boolean fullLayout = layout == Layout.FULL; addPanel(getTabbedFull(), panel, fullLayout); switch (panelType) { case SELECT: addPanel(getTabbedSelect(), panel, !fullLayout); getTabbedSelect().revalidate(); break; case STATUS: addPanel(getTabbedStatus(), panel, !fullLayout); getTabbedStatus().revalidate(); break; case WORK: addPanel(getTabbedWork(), panel, !fullLayout); getTabbedWork().revalidate(); break; default: break; } } /** * Removes the given panels of given panel type from the workbench panel. * * @param panels the panels to remove from the workbench panel * @param panelType the type of the panels * @throws IllegalArgumentException if any of the parameters is {@code null}. * @since 2.5.0 * @see #addPanels(List, PanelType) * @see #removePanel(AbstractPanel, PanelType) */ public void removePanels(List panels, PanelType panelType) { validateNotNull(panels, "panels"); validateNotNull(panelType, "panelType"); removePanels(getTabbedFull(), panels); switch (panelType) { case SELECT: removePanels(getTabbedSelect(), panels); break; case STATUS: removePanels(getTabbedStatus(), panels); break; case WORK: removePanels(getTabbedWork(), panels); break; default: break; } } /** * Removes the given {@code panels} from the given {@code tabbedPanel}. * *

After removing all the panels the tabbed panel is revalidated. * * @param tabbedPanel the tabbed panel to remove the panels * @param panels the panels to remove * @see #addPanel(TabbedPanel2, AbstractPanel, boolean) * @see javax.swing.JComponent#revalidate() */ private static void removePanels(TabbedPanel2 tabbedPanel, List panels) { for (AbstractPanel panel : panels) { removeTabPanel(tabbedPanel, panel); } tabbedPanel.revalidate(); } /** * Removes the given {@code panel} from the given {@code tabbedPanel}. * * @param tabbedPanel the tabbed panel to remove the panel * @param panel the panel to remove * @see #removePanels(TabbedPanel2, List) */ private static void removeTabPanel(TabbedPanel2 tabbedPanel, AbstractPanel panel) { tabbedPanel.removeTab(panel); } /** * Removes the given panel of given panel type from the workbench panel. * * @param panel the panel to remove from the workbench panel * @param panelType the type of the panel * @throws IllegalArgumentException if any of the parameters is {@code null}. * @since 2.5.0 * @see #addPanel(AbstractPanel, PanelType) * @see #removePanels(List, PanelType) */ public void removePanel(AbstractPanel panel, PanelType panelType) { validateNotNull(panel, "panel"); validateNotNull(panelType, "panelType"); removeTabPanel(getTabbedFull(), panel); getTabbedFull().revalidate(); switch (panelType) { case SELECT: removeTabPanel(getTabbedSelect(), panel); getTabbedSelect().revalidate(); break; case STATUS: removeTabPanel(getTabbedStatus(), panel); getTabbedStatus().revalidate(); break; case WORK: removeTabPanel(getTabbedWork(), panel); getTabbedWork().revalidate(); break; default: break; } } /** * Gets the panels that were added to the workbench with the given panel type. * * @param panelType the type of the panel * @return a {@code List} with the panels of the given type * @throws IllegalArgumentException if the given parameter is {@code null}. * @since 2.5.0 */ public List getPanels(PanelType panelType) { validateNotNull(panelType, "panelType"); List panels = new ArrayList<>(); switch (panelType) { case SELECT: panels.addAll(getTabbedSelect().getPanels()); break; case STATUS: panels.addAll(getTabbedStatus().getPanels()); break; case WORK: panels.addAll(getTabbedWork().getPanels()); break; default: break; } return panels; } /** * Gets the panels, sorted by name, that were added to the workbench with the given panel type. * * @param panelType the type of the panel * @return a {@code List} with the sorted panels of the given type * @throws IllegalArgumentException if the given parameter is {@code null}. * @since 2.5.0 */ public SortedSet getSortedPanels(PanelType panelType) { validateNotNull(panelType, "panelType"); List panels = getPanels(panelType); SortedSet sortedPanels = new TreeSet<>( new Comparator() { @Override public int compare( AbstractPanel abstractPanel, AbstractPanel otherAbstractPanel) { String name = abstractPanel.getName(); String otherName = otherAbstractPanel.getName(); if (name == null) { if (otherName == null) { return 0; } return -1; } else if (otherName == null) { return 1; } return name.compareTo(otherName); } }); sortedPanels.addAll(panels); return sortedPanels; } /** * Sets whether or not the panels should be visible. * *

{@link AbstractPanel#isHideable() Non-hideable} and {@link AbstractPanel#isPinned() * pinned} panels are not affected by this call, when set to not be visible. * * @param visible {@code true} if all panels should be visible, {@code false} otherwise. * @since 2.5.0 */ public void setPanelsVisible(boolean visible) { if (layout == Layout.FULL) { getTabbedFull().setPanelsVisible(visible); } else { getTabbedSelect().setPanelsVisible(visible); getTabbedWork().setPanelsVisible(visible); getTabbedStatus().setPanelsVisible(visible); } } /** * Pins all visible panels. * * @since 2.5.0 * @see #unpinVisiblePanels() * @see AbstractPanel#setPinned(boolean) */ public void pinVisiblePanels() { if (layout == Layout.FULL) { getTabbedFull().pinVisibleTabs(); } else { getTabbedSelect().pinVisibleTabs(); getTabbedWork().pinVisibleTabs(); getTabbedStatus().pinVisibleTabs(); } } /** * Unpins all visible panels. * * @since 2.5.0 * @see #pinVisiblePanels() * @see AbstractPanel#setPinned(boolean) */ public void unpinVisiblePanels() { if (layout == Layout.FULL) { getTabbedFull().unpinTabs(); } else { getTabbedSelect().unpinTabs(); getTabbedWork().unpinTabs(); getTabbedStatus().unpinTabs(); } } /** * Shows the given panel, if it was previously added. * *

It does nothing, if the tab is already shown. * * @param panel the panel to be shown * @throws IllegalArgumentException if the given parameter is {@code null}. * @since 2.5.0 * @see #addPanel(AbstractPanel, PanelType) */ public void showPanel(AbstractPanel panel) { validateNotNull(panel, "panel"); if (layout == Layout.FULL) { getTabbedFull().setVisible(panel, true); } else { getTabbedSelect().setVisible(panel, true); getTabbedStatus().setVisible(panel, true); getTabbedWork().setVisible(panel, true); } panel.setTabFocus(); } /** * Sets the position of the response panel. * * @param position the position of the response panel * @throws IllegalArgumentException if the given parameter is {@code null}. * @since 2.5.0 */ void setResponsePanelPosition(ResponsePanelPosition position) { validateNotNull(position, "position"); requestTabIndex = getCurrentRequestTabIndex(); responsePanelPosition = position; if (layout == Layout.FULL) { updateFullLayout(); return; } Component currentTabbedPanel = componentMaximiser.getMaximisedComponent(); if (componentMaximiser.isComponentMaximised()) { componentMaximiser.unmaximiseComponent(); } boolean selectRequest = removeSplitRequestAndResponsePanel(tabbedWork); switch (position) { case PANEL_ABOVE: splitResponsePanelWithWorkTabbedPanel(JSplitPane.VERTICAL_SPLIT); break; case PANELS_SIDE_BY_SIDE: splitResponsePanelWithWorkTabbedPanel(JSplitPane.HORIZONTAL_SPLIT); break; case TAB_SIDE_BY_SIDE: splitResponsePanelWithRequestPanel(JSplitPane.HORIZONTAL_SPLIT, tabbedWork); getPaneWork().removeAll(); getPaneWork().add(getTabbedWork()); getPaneWork().validate(); break; case TABS_SIDE_BY_SIDE: default: if (currentTabbedPanel == responseTabbedPanel) { currentTabbedPanel = tabbedWork; } insertResponseTab(tabbedWork); getPaneWork().removeAll(); getPaneWork().add(getTabbedWork()); getPaneWork().validate(); } if (selectRequest || getTabbedWork().getSelectedComponent() == null) { getTabbedWork() .setSelectedComponent( responsePanelPosition == ResponsePanelPosition.TAB_SIDE_BY_SIDE ? splitRequestAndResponsePanel : requestPanel); } if (currentTabbedPanel != null) { componentMaximiser.maximiseComponent(currentTabbedPanel); } } private void updateFullLayout() { boolean selectRequest = removeSplitRequestAndResponsePanel(tabbedFull); if (responsePanelPosition == ResponsePanelPosition.TAB_SIDE_BY_SIDE) { splitResponsePanelWithRequestPanel(JSplitPane.HORIZONTAL_SPLIT, tabbedFull); } else { addRequestResponseTabs(tabbedFull); } getFullLayoutPanel().validate(); if (selectRequest || getTabbedFull().getSelectedComponent() == null) { tabbedFull.setSelectedComponent( responsePanelPosition == ResponsePanelPosition.TAB_SIDE_BY_SIDE ? splitRequestAndResponsePanel : requestPanel); } } private void addRequestResponseTabs(TabbedPanel2 tabbedPanel) { tabbedPanel.addTab(requestPanel, requestTabIndex); insertResponseTab(tabbedPanel); } private void insertResponseTab(TabbedPanel2 tabbedPanel) { String tabName = getNormalisedTabName(responsePanel); tabbedPanel.insertTab( tabName, DisplayUtils.getScaledIcon(responsePanel.getIcon()), responsePanel, tabName, tabbedPanel.indexOfComponent(requestPanel) + 1); } private String getNormalisedTabName(AbstractPanel panel) { return showTabNames ? panel.getName() : ""; } private void splitResponsePanelWithWorkTabbedPanel(int orientation) { responseTabbedPanel.hideAllTabs(); responseTabbedPanel.addTab( getNormalisedTabName(responsePanel), responsePanel.getIcon(), responsePanel); getPaneWork().removeAll(); JSplitPane split = createSplitPane(orientation); split.setRightComponent(responseTabbedPanel); split.setLeftComponent(getTabbedWork()); getPaneWork().add(split); getPaneWork().validate(); } private static JSplitPane createSplitPane(int orientation) { JSplitPane splitPane = new JSplitPane(orientation); splitPane.setDividerSize(3); splitPane.setResizeWeight(0.5D); splitPane.setContinuousLayout(false); splitPane.setDoubleBuffered(true); splitPane.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); return splitPane; } private void splitResponsePanelWithRequestPanel(int orientation, TabbedPanel2 tabbedPanel) { if (splitRequestAndResponsePanel == null) { splitRequestAndResponsePanel = new AbstractPanel(); splitRequestAndResponsePanel.setLayout(new BorderLayout()); splitRequestAndResponsePanel.setName( Constant.messages.getString("http.panel.requestAndResponse.title")); splitRequestAndResponsePanel.setIcon( new ImageIcon( WorkbenchPanel.class.getResource("/resource/icon/16/handshake.png"))); splitRequestAndResponsePanel.setHideable(false); splitRequestAndResponse = createSplitPane(orientation); splitRequestAndResponsePanel.add(splitRequestAndResponse); } Component selectedComponent = tabbedPanel.getSelectedComponent(); splitRequestAndResponse.setLeftComponent(requestPanel); tabbedPanel.removeTab(requestPanel); splitRequestAndResponse.setRightComponent(responsePanel); tabbedPanel.removeTab(responsePanel); tabbedPanel.addTab(splitRequestAndResponsePanel, requestTabIndex); if (selectedComponent == requestPanel || selectedComponent == responsePanel) { tabbedPanel.setSelectedComponent(splitRequestAndResponsePanel); } } private boolean removeSplitRequestAndResponsePanel(TabbedPanel2 tabbedPanel) { boolean selectRequest = false; int pos = tabbedPanel.indexOfComponent(splitRequestAndResponsePanel); if (pos != -1) { selectRequest = tabbedPanel.getSelectedComponent() == splitRequestAndResponsePanel; tabbedPanel.removeTab(splitRequestAndResponsePanel); addRequestResponseTabs(tabbedPanel); } return selectRequest; } /** * @param prefix * @param location */ private void saveDividerLocation(String prefix, int location) { if (location > 0) { LOGGER.debug( "Saving preference {}{}.{}={}", prefnzPrefix, prefix, PREF_DIVIDER_LOCATION, location); this.preferences.put( prefnzPrefix + prefix + "." + PREF_DIVIDER_LOCATION, Integer.toString(location)); // immediate flushing try { this.preferences.flush(); } catch (final BackingStoreException e) { LOGGER.error("Error while saving the preferences", e); } } } /** * @param prefix * @param fallback * @return the size of the frame OR fallback value, if there wasn't any preference. */ private int restoreDividerLocation(String prefix, int fallback) { int result = fallback; final String sizestr = preferences.get(prefnzPrefix + prefix + "." + PREF_DIVIDER_LOCATION, null); if (sizestr != null) { int location = 0; try { location = Integer.parseInt(sizestr.trim()); } catch (final Exception e) { // ignoring, cause is prevented by default values; } if (location > 0) { result = location; LOGGER.debug( "Restoring preference {}{}.{}={}", prefnzPrefix, prefix, PREF_DIVIDER_LOCATION, location); } } return result; } /* * ======================================================================== */ private final class DividerResizedListener implements PropertyChangeListener { private final String prefix; public DividerResizedListener(String prefix) { super(); assert prefix != null; this.prefix = prefix; } @Override public void propertyChange(PropertyChangeEvent evt) { JSplitPane component = (JSplitPane) evt.getSource(); if (component != null) { LOGGER.debug( "{}{}.location={}", prefnzPrefix, prefix, component.getDividerLocation()); saveDividerLocation(prefix, component.getDividerLocation()); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy