/*
* Copyright (c) 2000, Jacob Smullyan.
*
* This is part of SkunkDAV, a WebDAV client. See http://skunkdav.sourceforge.net/
* for the latest version.
*
* SkunkDAV 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 2, or (at your option)
* any later version.
*
* SkunkDAV 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 SkunkDAV; see the file COPYING. If not, write to the Free
* Software Foundation, 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
package org.skunk.dav.client.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
import javax.swing.Box;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.skunk.dav.client.gui.editor.DAVEditor;
import org.skunk.trace.Debug;
public class ExplorerView implements View
{
private JFrame appFrame;
private JTabbedPane tabPane=null;
private ArrayList dockedBuffers=new ArrayList();
private ArrayList dockedStatusComponents=new ArrayList();
private AppContext appContext;
private Buffer focussedBuffer=null;
private JTextField statusField;
private JLabel locationField;
private Box statusBar;
public ExplorerView(AppContext appContext)
{
this.appContext=appContext;
initComponents();
}
public final AppContext getAppContext()
{
return this.appContext;
}
public Component getComponent()
{
return appFrame;
}
private void initComponents()
{
Explorer ex=new Explorer();
getAppContext().getConfigurator().configure(ex);
ExplorerMenuBar menubar=ExplorerMenuBar.getMenuBar(ex);
initStatusBar();
appFrame=new JFrame("SkunkDAV " + ResourceManager.getMessage(ResourceManager.RELEASE_VERSION));
appFrame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent woo)
{
System.exit(0);
}
});
appFrame.setJMenuBar(menubar);
dock(ex);
appFrame.pack();
appFrame.setVisible(true);
}
private void initStatusBar()
{
statusField=new JTextField();
statusField.setEnabled(false);
Font defaultFont=new Font("Serif", Font.PLAIN, 10);
statusField.setFont(defaultFont);
statusField.setBackground(UIManager.getColor("Label.background"));
statusField.setForeground(Color.black);
dockedStatusComponents.add(statusField);
locationField=new JLabel();
locationField.setFont(new Font("SansSerif", Font.PLAIN, 12));
locationField.setForeground(Color.black);
dockedStatusComponents.add(locationField);
statusBar=Box.createHorizontalBox();
StateMonitor.registerProperty(locationField,
"text",
StateProperties.CARET_POSITION,
new StateMonitor.Mapper()
{
public Object getTargetValue(Object applicationValue)
{
if (applicationValue instanceof TextPoint)
{
TextPoint p=(TextPoint) applicationValue;
return ResourceManager.getMessage(ResourceManager.LINE_AND_COLUMN,
p.getCoordinates());
}
else return "";
}
public boolean canMapValue(Object applicationValue)
{
return true;
}
},
new StateMonitor.DomainMatcher()
{
public boolean domainMatches(Object domainKey)
{
return domainKey!=null
&& domainKey.equals(ExplorerView.this);
}
});
layoutStatusBarComponents();
}
private void layoutStatusBarComponents()
{
statusBar.removeAll();
for (Iterator it=dockedStatusComponents.iterator();it.hasNext();)
{
statusBar.add((JComponent)it.next());
if (it.hasNext())
statusBar.add(Box.createHorizontalGlue());
}
statusBar.invalidate();
if (appFrame!=null)
{
Dimension d=appFrame.getSize();
appFrame.pack();
appFrame.setSize(d);
appFrame.repaint();
}
}
private void resetStatusBar()
{
if (!dockedStatusComponents.contains(statusField))
{
swapStatus((JComponent)dockedStatusComponents.get(0), statusField);
}
}
/**
* add the buffer to the application container widget
*/
public void dock(Buffer buffer)
{
if (! dockedBuffers.contains(buffer))
dockedBuffers.add(buffer);
buffer.docking();
resetStatusBar();
redoLayout();
focus(buffer);
}
/**
* remove the buffer from the application container widget
*/
public void undock(Buffer buffer)
{
if (buffer instanceof Explorer)
{
Debug.trace(this, Debug.DP3, "attempting to undock an Explorer");
return;
}
else
{
Debug.trace(this, Debug.DP3, "undocking "+buffer);
}
if (dockedBuffers.contains(buffer))
{
int index=dockedBuffers.indexOf(buffer);
dockedBuffers.remove(buffer);
buffer.undocking();
resetStatusBar();
redoLayout();
//show the nearest buffer to the one that was removed.
if (index>=dockedBuffers.size())
index--;
focus((Buffer)dockedBuffers.get(index));
}
}
/**
* @return list of current docked buffers
*/
public Iterator getDockedBuffers()
{
return dockedBuffers.listIterator();
}
/**
* ensure that the specified docked buffer is visible and has focus
*/
public void focus(Buffer buffer)
{
if (dockedBuffers.size()>1
&& getAppContext().getDockMode().equals(DockMode.TABBED_PANE_MODE))
{
tabPane.setSelectedComponent(buffer.getComponent());
}
focussedBuffer=buffer;
}
/**
* @return the buffer that has focus, or null if there are no buffers
*/
public Buffer getFocussedBuffer()
{
return focussedBuffer;
}
/**
* attempt to set for the given buffer the given visibility.
* Depending on the dock mode, certain settings of this property
* may be vetoed (e.g., in EMACS_MODE, at least one buffer must
* be visible at all times, so setting the only visible buffer
* invisible would not be permitted.) A change of visibility
* may entail a change to the focusedBuffer property, but it may
* not change the visibility of another buffer. (Hence, for
* single-buffer dock modes (like TABBED_PANE_MODE, if restricted to one frame)
* the setVisible method should throw an UnsupportedOperationException.)
* Preconditions: the buffer must be docked and non-null.
*
*/
public void setVisible(Buffer buffer, boolean visible)
throws UnsupportedOperationException, PropertyVetoException
{
if (getAppContext().getDockMode().equals(DockMode.TABBED_PANE_MODE))
throw new UnsupportedOperationException("setVisible not supported for DockMode.TABBED_PANE_MODE");
}
/**
* @return whether the given buffer is visible
*/
public boolean isVisible(Buffer buffer)
{
if (getAppContext().getDockMode().equals(DockMode.TABBED_PANE_MODE))
return buffer.equals(focussedBuffer);
//no other modes implemented yet
return false;
}
public void dispose()
{
appFrame.dispose();
StateMonitor.unregisterProperty(locationField, "text", StateProperties.CARET_POSITION);
}
public void showStatus(String message)
{
statusField.setText(message);
}
/**
* add a component to the status bar
*/
public void dockStatus(JComponent statusComponent)
{
swapStatus(statusField, statusComponent);
}
/**
* remove a component from the status bar
*/
public void undockStatus(JComponent statusComponent)
{
swapStatus(statusComponent, statusField);
}
private void swapStatus(JComponent firstComp, JComponent secondComp)
{
if (dockedStatusComponents.contains(firstComp))
{
int index=dockedStatusComponents.indexOf(firstComp);
dockedStatusComponents.remove(firstComp);
dockedStatusComponents.add(index, secondComp);
layoutStatusBarComponents();
}
else Debug.trace(this, Debug.DP3, "Component {0} not status-docked, cannot swap", firstComp);
}
private String getBufferName(Buffer buffer)
{
String bs=buffer.getName();
if (buffer instanceof DAVEditor)
{
if (((DAVEditor)buffer).isDirty())
{
return new StringBuffer(bs).append('*').toString();
}
}
return bs;
}
public void bufferDirtinessChanged(Buffer buffer)
{
int index=tabPane.indexOfComponent(buffer.getComponent());
if (index!=-1)
{
tabPane.setTitleAt(index, getBufferName(buffer));
}
if (buffer.equals(focussedBuffer) && buffer instanceof DAVEditor)
{
StateMonitor.setProperty(StateProperties.EDITOR_IN_FOCUS_AND_DIRTY,
new Boolean(((DAVEditor)buffer).isDirty()),
null);
}
}
private void redoLayout()
{
locationField.setText("");
if (dockedBuffers.size()==1)
{
Debug.trace(this, Debug.DP3, "only one buffer docked");
JPanel basePanel=new JPanel(new BorderLayout());
basePanel.add(statusBar, BorderLayout.SOUTH);
JComponent jc=((Buffer)dockedBuffers.get(0)).getComponent();
basePanel.add(jc, BorderLayout.CENTER);
appFrame.setContentPane(basePanel);
}
else
{
if (getAppContext().getDockMode().equals(DockMode.TABBED_PANE_MODE))
{
Debug.trace(this, Debug.DP3, "adding tab");
if (tabPane==null)
{
tabPane=new JTabbedPane(SwingConstants.BOTTOM);
tabPane.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent cheese)
{
setFocussedBufferFromTabPane();
resetStatusBar();
}
});
tabPane.setBackground(UIManager.getColor("Label.background"));
tabPane.setOpaque(true);
}
Dimension d0=appFrame.getContentPane().getPreferredSize();
Dimension d1=appFrame.getContentPane().getSize();
Dimension d=(d1==null) ? d0 : d1;
tabPane.removeAll();
for (ListIterator lit=dockedBuffers.listIterator();lit.hasNext();)
{
Buffer buffy=(Buffer)lit.next();
tabPane.addTab(getBufferName(buffy), buffy.getComponent());
}
tabPane.setPreferredSize(d);
JPanel basePanel=new JPanel(new BorderLayout());
basePanel.add(statusBar, BorderLayout.SOUTH);
basePanel.add(tabPane, BorderLayout.CENTER);
basePanel.setPreferredSize(d);
appFrame.setContentPane(basePanel);
}
}
appFrame.invalidate();
appFrame.validate();
appFrame.repaint();
}
private void setFocussedBufferFromTabPane()
{
Component c=tabPane.getSelectedComponent();
for (Iterator it=getDockedBuffers();it.hasNext();)
{
Buffer buffy=(Buffer)it.next();
JComponent jc=buffy.getComponent();
if (jc.equals(c))
{
focussedBuffer=buffy;
boolean haveAnEditor=buffy instanceof DAVEditor;
StateMonitor.setProperty(StateProperties.EDITOR_IN_FOCUS,
new Boolean(haveAnEditor),
null);
StateMonitor.setProperty(StateProperties.EDITOR_IN_FOCUS_AND_DIRTY,
new Boolean(haveAnEditor && ((DAVEditor)buffy).isDirty()),
null);
break;
}
}
}
}
/* $Log: ExplorerView.java,v $
/* Revision 1.13 2001/07/22 07:04:24 smulloni
/* changed the handling of release number.
/*
/* Revision 1.12 2000/12/19 22:36:05 smulloni
/* adjustments to preamble.
/*
/* Revision 1.11 2000/12/19 19:22:22 smulloni
/* some tweaks: ExitAction now cleans up the app's buffers. The app now does
/* not resize every time a buffer is added or removed.
/*
/* Revision 1.10 2000/12/04 23:51:16 smulloni
/* added ImageViewer; fixed word in SimpleTextEditor
/*
/* Revision 1.9 2000/12/03 23:53:26 smulloni
/* added license and copyright preamble to java files.
/*
/* Revision 1.8 2000/12/01 16:25:52 smullyan
/* improvements to look and feel; fixed NPE in DAVFile; new actions for text
/* editor
/*
/* Revision 1.7 2000/11/29 23:16:04 smullyan
/* adding first rough cut of search capability to the text editor. View
/* is being updated to allow components to be docked into the status bar.
/*
/* Revision 1.6 2000/11/28 00:01:38 smullyan
/* added a status bar/minibuffer, with a location field showing the current line and
/* column number (for the SimpleTextEditor and kin only).
/*
/* Revision 1.5 2000/11/22 00:11:27 smullyan
/* editor now locks and unlocks, more or less appropriately.
/*
/* Revision 1.4 2000/11/20 23:30:21 smullyan
/* more editor integration work.
/*
/* Revision 1.3 2000/11/18 04:36:04 smullyan
/* work on StateMonitor and related functionality.
/*
/* Revision 1.2 2000/11/17 20:25:05 smullyan
/* new SaveAction; a StateMonitor being added to handle application state.
/*
/* Revision 1.1 2000/11/16 20:45:18 smullyan
/* the start of editor integration.
/* */
|