/*
* This file is part of muCommander, http://www.mucommander.com
* Copyright (C) 2002-2016 Maxence Bernard
*
* muCommander is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* muCommander 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
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.mucommander.ui.main;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.FocusTraversalPolicy;
import java.awt.Frame;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Vector;
import java.util.WeakHashMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.WindowConstants;
import javax.swing.table.TableColumnModel;
import com.apple.eawt.FullScreenUtilities;
import com.mucommander.commons.file.AbstractFile;
import com.mucommander.commons.file.protocol.FileProtocols;
import com.mucommander.commons.file.archive.AbstractArchiveEntryFile;
import com.mucommander.commons.runtime.JavaVersion;
import com.mucommander.commons.runtime.OsFamily;
import com.mucommander.commons.runtime.OsVersion;
import com.mucommander.conf.MuConfigurations;
import com.mucommander.conf.MuPreference;
import com.mucommander.conf.MuPreferences;
import com.mucommander.conf.MuSnapshot;
import com.mucommander.ui.action.ActionKeymap;
import com.mucommander.ui.action.ActionManager;
import com.mucommander.ui.action.impl.CloseWindowAction;
import com.mucommander.ui.button.ToolbarMoreButton;
import com.mucommander.ui.event.ActivePanelListener;
import com.mucommander.ui.event.LocationEvent;
import com.mucommander.ui.event.LocationListener;
import com.mucommander.ui.icon.IconManager;
import com.mucommander.ui.layout.ProportionalSplitPane;
import com.mucommander.ui.layout.YBoxPanel;
import com.mucommander.ui.main.commandbar.CommandBar;
import com.mucommander.ui.main.menu.MainMenuBar;
import com.mucommander.ui.main.table.Column;
import com.mucommander.ui.main.table.FileTable;
import com.mucommander.ui.main.table.FileTableConfiguration;
import com.mucommander.ui.main.table.SortInfo;
import com.mucommander.ui.main.tabs.ConfFileTableTab;
import com.mucommander.ui.main.toolbar.ToolBar;
/**
* This is the main frame, which contains all other UI components visible on a mucommander window.
*
* @author Maxence Bernard
*/
public class MainFrame extends JFrame implements LocationListener {
private ProportionalSplitPane splitPane;
private FolderPanel leftFolderPanel;
private FolderPanel rightFolderPanel;
private FileTable leftTable;
private FileTable rightTable;
/** Active table in the MainFrame */
private FileTable activeTable;
/** Toolbar panel */
private JPanel toolbarPanel;
/** Toolbar component */
private ToolBar toolbar;
/** Status bar instance */
private StatusBar statusBar;
/** Command bar instance */
private CommandBar commandBar;
/** Is no events mode enabled ? */
private boolean noEventsMode;
/** Is this MainFrame active in the foreground ? */
private boolean foregroundActive;
/** Is single panel view? */
private boolean singlePanel;
/** Contains all registered ActivePanelListener instances, stored as weak references */
private WeakHashMap<ActivePanelListener, ?> activePanelListeners = new WeakHashMap<ActivePanelListener, Object>();
/**
* Sets the window icon, using the best method (Java 1.6's Window#setIconImages when available, Window#setIconImage
* otherwise) and icon resolution(s) (OS-dependent).
*/
private void setWindowIcon() {
// TODO: this code should probably be moved to the desktop API
// - Mac OS X completely ignores calls to #setIconImage/setIconImages, no need to waste time
if(OsFamily.MAC_OS_X.isCurrent())
return;
// Use Java 1.6 's new Window#setIconImages(List<Image>) when available
if(JavaVersion.JAVA_1_6.isCurrentOrHigher()) {
java.util.List<Image> icons = new Vector<Image>();
// Start by adding a 16x16 image with 1-bit transparency, any OS should support that.
icons.add(IconManager.getIcon(IconManager.MUCOMMANDER_ICON_SET, "icon16_8.png").getImage());
// - Windows XP messes up 8-bit PNG transparency.
// We would be better off with the .ico of the launch4j exe (which has 8-bit alpha transparency) but there
// seems to be no way to keep it when in 'dontWrapJar' mode (separate exe and jar files).
if(OsFamily.WINDOWS.isCurrent() && OsVersion.WINDOWS_XP.isCurrentOrLower()) {
icons.add(IconManager.getIcon(IconManager.MUCOMMANDER_ICON_SET, "icon48_8.png").getImage());
}
// - Windows Vista supports 8-bit transparency and icon resolutions up to 256x256.
// - GNOME and KDE support 8-bit transparency.
else {
// Add PNG 24 images (8-bit transparency)
icons.add(IconManager.getIcon(IconManager.MUCOMMANDER_ICON_SET, "icon16_24.png").getImage());
icons.add(IconManager.getIcon(IconManager.MUCOMMANDER_ICON_SET, "icon32_24.png").getImage());
icons.add(IconManager.getIcon(IconManager.MUCOMMANDER_ICON_SET, "icon48_24.png").getImage());
icons.add(IconManager.getIcon(IconManager.MUCOMMANDER_ICON_SET, "icon128_24.png").getImage());
icons.add(IconManager.getIcon(IconManager.MUCOMMANDER_ICON_SET, "icon256_24.png").getImage());
}
setIconImages(icons);
}
else { // Java 1.5 or lower
// Err on the safe side by assuming that 8-bit transparency is not supported.
// Any OS should support 16x16 icons with 1-bit transparency.
setIconImage(IconManager.getIcon(IconManager.MUCOMMANDER_ICON_SET, "icon16_8.png").getImage());
}
}
private void init(FolderPanel leftFolderPanel, FolderPanel rightFolderPanel) {
// Set the window icon
setWindowIcon();
if (OsFamily.MAC_OS_X.isCurrent()) {
// Lion Fullscreen support
FullScreenUtilities.setWindowCanFullScreen(this, true);
}
// Enable window resize
setResizable(true);
// The toolbar should have no inset, this is why it is left out of the insetsPane
JPanel contentPane = new JPanel(new BorderLayout());
setContentPane(contentPane);
// Initializes the folder panels and file tables.
this.leftFolderPanel = leftFolderPanel;
this.rightFolderPanel = rightFolderPanel;
leftTable = leftFolderPanel.getFileTable();
rightTable = rightFolderPanel.getFileTable();
activeTable = leftTable;
// Create the toolbar and corresponding panel wrapping it, and show it only if it hasn't been disabled in the
// preferences.
// Note: Toolbar.setVisible() has to be called no matter if Toolbar is visible or not, in order for it to be
// properly initialized
this.toolbar = new ToolBar(this);
this.toolbarPanel = ToolbarMoreButton.wrapToolBar(toolbar);
this.toolbarPanel.setVisible(MuConfigurations.getPreferences().getVariable(MuPreference.TOOLBAR_VISIBLE, MuPreferences.DEFAULT_TOOLBAR_VISIBLE));
contentPane.add(toolbarPanel, BorderLayout.NORTH);
JPanel insetsPane = new JPanel(new BorderLayout()) {
// Add an x=3,y=3 gap around content pane
@Override
public Insets getInsets() {
return new Insets(0, 3, 3, 3); // No top inset
}
};
// Below the toolbar there is the pane with insets
contentPane.add(insetsPane, BorderLayout.CENTER);
// Listen to location change events to display the current folder in the window's title
leftFolderPanel.getLocationManager().addLocationListener(this);
rightFolderPanel.getLocationManager().addLocationListener(this);
// Create menu bar (has to be created after toolbar)
MainMenuBar menuBar = new MainMenuBar(this);
setJMenuBar(menuBar);
// Create the split pane that separates folder panels and allows to resize how much space is allocated to the
// both of them. The split orientation is loaded from and saved to the preferences.
// Note: the vertical/horizontal terminology used in muCommander is just the opposite of the one used
// in JSplitPane which is anti-natural / confusing.
splitPane = new ProportionalSplitPane(this,
MuConfigurations.getSnapshot().getVariable(MuSnapshot.getSplitOrientation(0), MuSnapshot.DEFAULT_SPLIT_ORIENTATION).equals(MuSnapshot.VERTICAL_SPLIT_ORIENTATION) ?
JSplitPane.HORIZONTAL_SPLIT:JSplitPane.VERTICAL_SPLIT,
false,
MainFrame.this.leftFolderPanel,
MainFrame.this.rightFolderPanel) {
// We don't want any extra space around split pane
@Override
public Insets getInsets() {
return new Insets(0, 0, 0, 0);
}
};
// Remove any default border the split pane has
splitPane.setBorder(null);
// Adds buttons that allow to collapse and expand the split pane in both directions
splitPane.setOneTouchExpandable(true);
// Disable all the JSPlitPane accessibility shortcuts that are registered by default, as some of them
// conflict with default mucommander action shortcuts (e.g. F6 and F8)
splitPane.disableAccessibilityShortcuts();
// Split pane will be given any extra space
insetsPane.add(splitPane, BorderLayout.CENTER);
// Add a 2-pixel gap between the file table and status bar
YBoxPanel southPanel = new YBoxPanel();
southPanel.addSpace(2);
// Add status bar
this.statusBar = new StatusBar(this);
southPanel.add(statusBar);
// Show command bar only if it hasn't been disabled in the preferences
this.commandBar = new CommandBar(this);
// Note: CommandBar.setVisible() has to be called no matter if CommandBar is visible or not, in order for it to be properly initialized
this.commandBar.setVisible(MuConfigurations.getPreferences().getVariable(MuPreference.COMMAND_BAR_VISIBLE, MuPreferences.DEFAULT_COMMAND_BAR_VISIBLE));
southPanel.add(commandBar);
insetsPane.add(southPanel, BorderLayout.SOUTH);
// Perform CloseAction when the user asked the window to close
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
ActionManager.performAction(CloseWindowAction.Descriptor.ACTION_ID, MainFrame.this);
}
});
ActionKeymap.registerActions(this);
// Fire table change events on registered ActivePanelListener instances, to notify of the intial active table.
fireActivePanelChanged(activeTable.getFolderPanel());
// Set the custom FocusTraversalPolicy that manages focus for both FolderPanel and their subcomponents.
setFocusTraversalPolicy(new CustomFocusTraversalPolicy());
}
public MainFrame(ConfFileTableTab leftTab, FileTableConfiguration leftTableConf,
ConfFileTableTab rightTab, FileTableConfiguration rightTableConf) {
this(new ConfFileTableTab[] {leftTab}, 0, leftTableConf, new ConfFileTableTab[] {rightTab}, 0, rightTableConf);
}
/**
* Creates a new main frame set to the given initial folders.
*
* @param leftInitialFolders the initial folders to display in the left panel's tabs
* @param rightInitialFolders the initial folders to display in the right panel's tabs
*/
public MainFrame(ConfFileTableTab[] leftTabs, int indexOfLeftSelectedTab, FileTableConfiguration leftTableConf,
ConfFileTableTab[] rightTabs, int indexOfRightSelectedTab, FileTableConfiguration rightTableConf) {
/*AbstractFile[] leftInitialFolders, AbstractFile[] rightInitialFolders,
int indexOfLeftSelectedTab, int indexOfRightSelectedTab,
FileURL[] leftLocationHistory, FileURL[] rightLocationHistory) { */
init(new FolderPanel(this, leftTabs, indexOfLeftSelectedTab, leftTableConf),
new FolderPanel(this, rightTabs, indexOfRightSelectedTab, rightTableConf));
for (boolean isLeft = true; ; isLeft=false) {
FileTable fileTable = isLeft ? leftTable : rightTable;
fileTable.sortBy(Column.valueOf(MuConfigurations.getSnapshot().getVariable(MuSnapshot.getFileTableSortByVariable(0, isLeft), MuSnapshot.DEFAULT_SORT_BY).toUpperCase()),
!MuConfigurations.getSnapshot().getVariable(MuSnapshot.getFileTableSortOrderVariable(0, isLeft), MuSnapshot.DEFAULT_SORT_ORDER).equals(MuSnapshot.SORT_ORDER_DESCENDING));
FolderPanel folderPanel = isLeft ? leftFolderPanel : rightFolderPanel;
folderPanel.setTreeWidth(MuConfigurations.getSnapshot().getVariable(MuSnapshot.getTreeWidthVariable(0, isLeft), 150));
folderPanel.setTreeVisible(MuConfigurations.getSnapshot().getVariable(MuSnapshot.getTreeVisiblityVariable(0, isLeft), false));
if (!isLeft)
break;
}
}
/**
* Copy constructor
*/
public MainFrame(MainFrame mainFrame) {
FolderPanel leftFolderPanel = mainFrame.getLeftPanel();
FolderPanel rightFolderPanel = mainFrame.getRightPanel();
FileTable leftFileTable = leftFolderPanel.getFileTable();
FileTable rightFileTable = rightFolderPanel.getFileTable();
init(new FolderPanel(this, new ConfFileTableTab[] {new ConfFileTableTab(leftFolderPanel.getCurrentFolder().getURL())}, 0, leftFileTable.getConfiguration()),
new FolderPanel(this, new ConfFileTableTab[] {new ConfFileTableTab(rightFolderPanel.getCurrentFolder().getURL())}, 0, rightFileTable.getConfiguration()));
// TODO: Sorting should be part of the FileTable configuration
this.leftTable.sortBy(leftFileTable.getSortInfo());
this.rightTable.sortBy(rightFileTable.getSortInfo());
}
/**
* Registers the given ActivePanelListener to receive events when the active table changes.
*
* @param activePanelListener the ActivePanelListener to add
*/
public void addActivePanelListener(ActivePanelListener activePanelListener) {
activePanelListeners.put(activePanelListener, null);
}
/**
* Unregisters the given ActivePanelListener so that it no longer receives events when the active table changes.
*
* @param activePanelListener the ActivePanelListener to remove
*/
public void removeActivePanelListener(ActivePanelListener activePanelListener) {
activePanelListeners.remove(activePanelListener);
}
/**
* Fires table change events on all registered ActivePanelListener instances.
*
* @param folderPanel the new active panel
*/
private void fireActivePanelChanged(FolderPanel folderPanel) {
for(ActivePanelListener listener : activePanelListeners.keySet())
listener.activePanelChanged(folderPanel);
}
/**
* Returns <code>true</code> if 'no events mode' is currently enabled.
*
* @return <code>true</code> if 'no events mode' is currently enabled
*/
public boolean getNoEventsMode() {
return this.noEventsMode;
}
/**
* Enables/disables the 'no events mode' which prevents mouse and keyboard events from being received
* by the application (MainFrame, its subcomponents and the menu bar).
*
* @param enabled <code>true</code> to enable 'no events mode', <code>false</code> to disable it
*/
public void setNoEventsMode(boolean enabled) {
// Piece of code used in 0.8 beta1 and removed after because it's way too slow, kept here for the record
// // Glass pane has empty mouse and key adapters (created in the constructor)
// // which will catch all mouse and keyboard events
// getGlassPane().setVisible(enabled);
// getJMenuBar().setEnabled(!enabled);
// // Remove focus from whatever component in FolderPanel which had focus
// getGlassPane().requestFocus();
this.noEventsMode = enabled;
}
/**
* Returns the {@link ToolBar} where shortcut buttons (go back, go forward, ...) are.
* Note that a non-null instance of {@link ToolBar} is returned even if it is currently hidden.
*
* @return the toolbar component
*/
public ToolBar getToolBar() {
return toolbar;
}
/**
* Returns the panel where the {@link ToolBar} component is.
* Note that a non-null instance of {@link ToolBar} is returned even if it is currently hidden.
*
* @return the toolbar component
*/
public JPanel getToolBarPanel() {
return toolbarPanel;
}
/**
* Returns the {@link CommandBar}, i.e. the component that contains shortcuts to certain actions such as
* View, Edit, Copy, Move, etc...
* Note that a non-null instance of {@link CommandBar} is returned even if it is currently hidden.
*
* @return the command bar component
*/
public CommandBar getCommandBar() {
return commandBar;
}
/**
* Returns the status bar, where information about selected files and volume are displayed.
* Note that a non-null instance of {@link StatusBar} is returned even if it is currently hidden.
*
* @return the status bar
*/
public StatusBar getStatusBar() {
return this.statusBar;
}
/**
* Returns the currently active table.
*
* <p>The returned table doesn't necessarily have focus, the focus can be in some other component
* of the active {@link FolderPanel}, or nowhere in the MainFrame if it is currently not in the foreground.</p>
*
* <p>Use {@link FileTable#hasFocus()} to test if the table currently has focus.</p>
*
* @return the currently active table
* @see FileTable#isActiveTable()
*/
public FileTable getActiveTable() {
return activeTable;
}
/**
* Returns the currently active panel.
*
* <p>The returned panel doesn't necessarily have focus, for example if the MainFrame is currently not in the
* foreground.</p>
*
* @return the currently active panel
*/
public FolderPanel getActivePanel() {
return activeTable.getFolderPanel();
}
/**
* Sets the currently active FileTable. This method is to be called by FolderPanel only.
*
* @param table the currently active FileTable
*/
void setActiveTable(FileTable table) {
boolean activeTableChanged = activeTable !=table;
if(activeTableChanged) {
this.activeTable = table;
// Update window title to reflect new active table
updateWindowTitle();
// Fire table change events on registered ActivePanelListener instances.
fireActivePanelChanged(table.getFolderPanel());
}
}
/**
* Returns the inactive table, i.e. the complement of {@link #getActiveTable()}.
*
* @return the inactive table
*/
public FileTable getInactiveTable() {
return activeTable == leftTable ? rightTable : leftTable;
}
/**
* Returns the inactive panel, i.e. the complement of {@link #getActivePanel()}.
*
* @return the inactive panel
*/
public FolderPanel getInactivePanel() {
return getInactiveTable().getFolderPanel();
}
/**
* Returns the FolderPanel instance corresponding to the left panel.
*
* @return the FolderPanel instance corresponding to the left panel
*/
public FolderPanel getLeftPanel() {
return leftFolderPanel;
}
/**
* Returns the FolderPanel instance corresponding to the right panel.
*
* @return the FolderPanel instance corresponding to the right panel
*/
public FolderPanel getRightPanel() {
return rightFolderPanel;
}
/**
* Returns the ProportionalSplitPane component that splits the two panels.
*
* @return the ProportionalSplitPane component that splits the two panels
*/
public ProportionalSplitPane getSplitPane() {
return splitPane;
}
/**
* Specifies how folder panels are split: if true is passed, the folder panels will be split vertically
* (default), horizontally otherwise.
*
* @param vertical if true, the folder panels will be split horizontally (default), vertically otherwise.
*/
public void setSplitPaneOrientation(boolean vertical) {
// Note: the vertical/horizontal terminology used in muCommander is just the opposite of the one used
// in JSplitPane which is anti-natural / confusing
splitPane.setOrientation(vertical?JSplitPane.HORIZONTAL_SPLIT:JSplitPane.VERTICAL_SPLIT);
}
/**
* Returns how folder panels are currently split: if <code>true</code> is returned, panels are split vertically
* (default), horizontally otherwise.
*
* @return <code>true</code> if folder panels are split vertically
*/
public boolean getSplitPaneOrientation() {
// Note: the vertical/horizontal terminology used in muCommander is just the opposite of the one used
// in JSplitPane which is anti-natural / confusing
return splitPane.getOrientation() == JSplitPane.HORIZONTAL_SPLIT;
}
/**
* Swaps the two FolderPanel instances: after a call to this method, the left FolderPanel will be the right one and
* vice-versa.
*/
public void swapFolders() {
splitPane.remove(leftFolderPanel);
splitPane.remove(rightFolderPanel);
// Swaps the folder panels.
FolderPanel tempPanel = leftFolderPanel;
leftFolderPanel = rightFolderPanel;
rightFolderPanel = tempPanel;
// swaps folders trees
int tempTreeWidth = leftFolderPanel.getTreeWidth();
leftFolderPanel.setTreeWidth(rightFolderPanel.getTreeWidth());
rightFolderPanel.setTreeWidth(tempTreeWidth);
boolean tempTreeVisible = leftFolderPanel.isTreeVisible();
leftFolderPanel.setTreeVisible(rightFolderPanel.isTreeVisible());
rightFolderPanel.setTreeVisible(tempTreeVisible);
// Resets the tables.
FileTable tempTable = leftTable;
leftTable = rightTable;
rightTable = tempTable;
// Preserve the sort order and columns visibility.
TableColumnModel model = leftTable.getColumnModel();
leftTable.setColumnModel(rightTable.getColumnModel());
rightTable.setColumnModel(model);
SortInfo sortInfo = (SortInfo)leftTable.getSortInfo().clone();
leftTable.sortBy(rightTable.getSortInfo());
leftTable.updateColumnsVisibility();
rightTable.sortBy(sortInfo);
rightTable.updateColumnsVisibility();
// Do the swap and update the split pane
splitPane.setLeftComponent(leftFolderPanel);
splitPane.setRightComponent(rightFolderPanel);
splitPane.doLayout();
// Update split pane divider's location
splitPane.updateDividerLocation();
activeTable.requestFocus();
}
/**
* Makes both folders the same, choosing the one which is currently active.
*/
public void setSameFolder() {
(activeTable == leftTable ? rightTable : leftTable).getFolderPanel().tryChangeCurrentFolder(activeTable.getFolderPanel().getCurrentFolder());
}
/**
* Returns <code>true</code> if this MainFrame is currently active in the foreground.
*
* @return <code>true</code> if this MainFrame is currently active in the foreground
*/
public boolean isForegroundActive() {
return foregroundActive;
}
/**
* Sets whether this MainFrame is currently active in the foreground. This method is to be called by WindowManager
* only.
*
* @param foregroundActive true if this MainFrame is currently active in the foreground
*/
void setForegroundActive(boolean foregroundActive) {
this.foregroundActive = foregroundActive;
}
/**
* Forces a refrehs of the frame's folder panel.
*/
public void tryRefreshCurrentFolders() {
leftFolderPanel.tryRefreshCurrentFolder();
rightFolderPanel.tryRefreshCurrentFolder();
}
/**
* Returns <code>true</code> if this MainFrame is active, or is an ancestor of a Window that is currently active.
*
* @return <code>true</code> if this MainFrame is active, or is an ancestor of a Window that is currently active
*/
public boolean isAncestorOfActiveWindow() {
if(isActive())
return true;
Window ownedWindows[] = getOwnedWindows();
int nbWindows = ownedWindows.length;
for(int i=0; i<nbWindows; i++)
if(ownedWindows[i].isActive())
return true;
return false;
}
/**
* Updates this window's title to show currently active folder and window number.
* This method is called by this class and WindowManager.
*/
public void updateWindowTitle() {
// Update window title
String title = activeTable.getFolderPanel().getCurrentFolder().getAbsolutePath();
// Add the application name to window title on all OSs except MAC
if (!OsFamily.MAC_OS_X.isCurrent())
title += " - muCommander";
java.util.List<MainFrame> mainFrames = WindowManager.getMainFrames();
if(mainFrames.size()>1)
title += " ["+(mainFrames.indexOf(this)+1)+"]";
setTitle(title);
// Use new Window decorations introduced in Mac OS X 10.5 (Leopard)
if(OsFamily.MAC_OS_X.isCurrent() && OsVersion.MAC_OS_X_10_5.isCurrentOrHigher()) {
// Displays the document icon in the window title bar, works only for local files
AbstractFile currentFolder = activeTable.getFolderPanel().getCurrentFolder();
Object javaIoFile;
if(currentFolder.getURL().getScheme().equals(FileProtocols.FILE)) {
// If the current folder is an archive entry, display the archive file, this is the closest we can get
// with a java.io.File
if(currentFolder.hasAncestor(AbstractArchiveEntryFile.class))
javaIoFile = currentFolder.getParentArchive().getUnderlyingFileObject();
else
javaIoFile = currentFolder.getUnderlyingFileObject();
}
else {
// If the current folder is not a local file, use the special /Network directory which is sort of
// 'Network Neighborhood'.
javaIoFile = new java.io.File("/Network");
}
// Note that for some strange reason (looks like a bug), setting the property to null won't remove
// the previous icon.
getRootPane().putClientProperty("Window.documentFile", javaIoFile);
}
}
/**
* Returns <code>true</code> if only one panel is show
*
* @return <code>true</code> if only one panel is show
*/
public boolean isSinglePanel() {
return singlePanel;
}
/**
* Toggles single panel view state and returns new one
*
* @return new state for singlePanel boolean
*/
public boolean toggleSinglePanel() {
singlePanel = !singlePanel;
return singlePanel;
}
///////////////////////
// Overridden methods //
///////////////////////
/**
* Overrides <code>java.awt.Window#toFront</code> to have the window return to a normal state if it is minimized.
*/
@Override
public void toFront() {
if((getExtendedState()&Frame.ICONIFIED)!=0)
setExtendedState(Frame.NORMAL);
super.toFront();
}
///////////////////
// Inner classes //
///////////////////
/**
* Manages focus for both FolderPanel and their subcomponents.
*
* @author Maxence Bernard
*/
protected class CustomFocusTraversalPolicy extends FocusTraversalPolicy {
@Override
public Component getComponentAfter(Container container, Component component) {
if (component==leftFolderPanel.getFoldersTreePanel().getTree())
return leftTable;
if (component==rightFolderPanel.getFoldersTreePanel().getTree())
return rightTable;
if(component== leftFolderPanel.getLocationTextField())
return leftTable;
if(component== leftTable)
return rightTable;
if(component== rightFolderPanel.getLocationTextField())
return rightTable;
// otherwise (component==table2)
return leftTable;
}
@Override
public Component getComponentBefore(Container container, Component component) {
// Completely symmetrical with getComponentAfter
return getComponentAfter(container, component);
}
@Override
public Component getFirstComponent(Container container) {
return leftTable;
}
@Override
public Component getLastComponent(Container container) {
return rightTable;
}
@Override
public Component getDefaultComponent(Container container) {
return getActiveTable();
}
}
public boolean isAutoSizeColumnsEnabled() {
return leftTable.isAutoSizeColumnsEnabled();
}
public void setAutoSizeColumnsEnabled(boolean b) {
leftTable.setAutoSizeColumnsEnabled(b);
rightTable.setAutoSizeColumnsEnabled(b);
}
/**********************************
* LocationListener Implementation
**********************************/
public void locationChanged(LocationEvent e) {
// Update window title to reflect the new current folder
updateWindowTitle();
}
public void locationChanging(LocationEvent locationEvent) { }
public void locationCancelled(LocationEvent locationEvent) { }
public void locationFailed(LocationEvent locationEvent) { }
}