CaRMtl/rene/dialogs/MyFileDialog.java
2018-09-04 22:51:42 -04:00

668 lines
17 KiB
Java

/*
Copyright 2006 Rene Grothmann, modified by Eric Hakenholz
This file is part of C.a.R. software.
C.a.R. is a 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, version 3 of the License.
C.a.R. 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 rene.dialogs;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Component;
import java.awt.FileDialog;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FilenameFilter;
import java.util.Enumeration;
import eric.JEricPanel;
import rene.gui.ButtonAction;
import rene.gui.CloseDialog;
import rene.gui.CloseFrame;
import rene.gui.DoActionListener;
import rene.gui.Global;
import rene.gui.HistoryTextField;
import rene.gui.HistoryTextFieldChoice;
import rene.gui.MyLabel;
import rene.gui.MyPanel;
import rene.gui.Panel3D;
import rene.gui.TextFieldAction;
import rene.lister.Lister;
import rene.lister.ListerMouseEvent;
import rene.util.FileList;
import rene.util.FileName;
import rene.util.MyVector;
class DirFieldListener implements DoActionListener {
MyFileDialog T;
public DirFieldListener(final MyFileDialog t) {
T = t;
}
public void doAction(final String o) {
T.setFile(o);
}
public void itemAction(final String o, final boolean flag) {
}
}
/**
* This is a file dialog. It is easy to handle, remembers its position and size,
* and performs pattern matching. The calls needs the rene.viewer.* class,
* unless you replace Lister with List everywhere. Moreover it needs the
* rene.gui.Global class to store field histories and determine the background
* color. Finally, it uses the FileList class to get the list of files.
* <p>
* The dialog does never check for files to exists. This must be done by the
* application.
* <p>
* There is a static main method, which demonstrates everything.
*/
public class MyFileDialog extends CloseDialog implements ItemListener,
FilenameFilter, MouseListener { // java.awt.List Dirs,Files;
/**
*
*/
private static final long serialVersionUID = 1L;
Lister Dirs, Files;
HistoryTextField DirField, FileField, PatternField;
HistoryTextFieldChoice DirHistory, FileHistory;
TextField Chosen;
String CurrentDir = ".";
boolean Aborted = true;
String DirAppend = "", PatternAppend = "", FileAppend = "";
Button Home;
Frame F;
/**
* @param title
* The dialog title.
* @param action
* The button string for the main action (e.g. Load)
* @param saving
* True, if this is a saving dialog.
*/
public MyFileDialog(final Frame f, final String title, final String action,
final boolean saving, final boolean help) {
super(f, title, true);
F = f;
setLayout(new BorderLayout());
// title prompt
add("North", new Panel3D(Chosen = new TextFieldAction(this, "")));
Chosen.setEditable(false);
// center panels
final JEricPanel center = new MyPanel();
center.setLayout(new GridLayout(1, 2, 5, 0));
Dirs = new Lister();
if (Global.NormalFont != null)
Dirs.setFont(Global.NormalFont);
Dirs.addActionListener(this);
Dirs.setMode(false, false, false, false);
center.add(Dirs);
Files = new Lister();
if (Global.NormalFont != null)
Files.setFont(Global.NormalFont);
Files.addActionListener(this);
Files.setMode(false, false, true, false);
center.add(Files);
add("Center", new Panel3D(center));
// south panel
final JEricPanel south = new MyPanel();
south.setLayout(new BorderLayout());
final JEricPanel px = new MyPanel();
px.setLayout(new BorderLayout());
final JEricPanel p0 = new MyPanel();
p0.setLayout(new GridLayout(0, 1));
final JEricPanel p1 = new MyPanel();
p1.setLayout(new BorderLayout());
p1.add("North", linePanel(new MyLabel(Global.name("myfiledialog.dir")),
DirField = new HistoryTextField(this, "Dir", 32) {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public boolean filterHistory(final String name)
// avoid a Windows bug with C: instead of c:
{
if (name.length() < 2)
return true;
if (name.charAt(1) == ':'
&& Character.isUpperCase(name.charAt(0)))
return false;
return true;
}
}));
DirField.setText(".");
p1.add("South", linePanel(new MyLabel(Global.name(
"myfiledialog.olddirs", "")),
DirHistory = new HistoryTextFieldChoice(DirField)));
p0.add(new Panel3D(p1));
final JEricPanel p2 = new MyPanel();
p2.setLayout(new BorderLayout());
p2.add("North", linePanel(
new MyLabel(Global.name("myfiledialog.file")),
FileField = new HistoryTextField(this, "File")));
p2.add("South", linePanel(new MyLabel(Global.name(
"myfiledialog.oldfiles", "")),
FileHistory = new HistoryTextFieldChoice(FileField)));
p0.add(new Panel3D(p2));
px.add("Center", p0);
px.add("South", new Panel3D(linePanel(new MyLabel(Global
.name("myfiledialog.pattern")),
PatternField = new HistoryTextField(this, "Pattern"))));
PatternField.setText("*");
south.add("Center", px);
final JEricPanel buttons = new MyPanel();
buttons.setLayout(new FlowLayout(FlowLayout.RIGHT));
// buttons.add(Home = new ButtonAction(this, Global.name(
// "myfiledialog.home", "Home"), "Home"));
buttons.add(new ButtonAction(this, Global.name("myfiledialog.mkdir",
"Create Directory"), "Create"));
buttons.add(new ButtonAction(this, Global.name("myfiledialog.back",
"Back"), "Back"));
buttons.add(new MyLabel(""));
buttons.add(new ButtonAction(this, action, "Action"));
buttons.add(new ButtonAction(this, Global.name("abort"), "Close"));
if (help) {
addHelp(buttons, "filedialog");
}
south.add("South", buttons);
add("South", new Panel3D(south));
// set sizes
pack();
setSize("myfiledialog");
addKeyListener(this);
DirField.addKeyListener(this);
DirField.setTrigger(true);
FileHistory.setDoActionListener(new DirFieldListener(this));
PatternField.addKeyListener(this);
PatternField.setTrigger(true);
FileField.addKeyListener(this);
FileField.setTrigger(true);
Home.addMouseListener(this);
}
JEricPanel linePanel(final Component x, final Component y) {
final JEricPanel p = new MyPanel();
p.setLayout(new GridLayout(1, 0));
p.add(x);
p.add(y);
return p;
}
public MyFileDialog(final Frame f, final String title, final String action,
final boolean saving) {
this(f, title, action, saving, false);
}
FileDialog FD;
public MyFileDialog(final Frame f, final String title, final boolean saving) {
super(f, "", true);
FD = new FileDialog(f, title, saving ? FileDialog.SAVE
: FileDialog.LOAD);
}
boolean HomeShiftControl = false;
public void mousePressed(final MouseEvent e) {
HomeShiftControl = e.isShiftDown() && e.isControlDown();
}
public void mouseReleased(final MouseEvent e) {
}
public void mouseClicked(final MouseEvent e) {
}
public void mouseEntered(final MouseEvent e) {
}
public void mouseExited(final MouseEvent e) {
}
@Override
public void doAction(final String o) {
if (o.equals("Dir") || o.equals("Pattern")) {
if (updateDir())
updateFiles();
PatternField.remember(PatternField.getText());
} else if (o.equals("File") || o.equals("Action")) {
if (FileField.getText().equals(""))
return;
leave();
} else if (o.equals("Home")) {
if (HomeShiftControl) {
final String s = Global.getParameter("myfiledialog.homdir", "");
if (s.equals(""))
Global.setParameter("myfiledialog.homdir", DirField
.getText());
else
Global.setParameter("myfiledialog.homdir", "");
}
try {
final String s = Global.getParameter("myfiledialog.homdir", "");
if (s.equals("")) {
final String s1 = System.getProperty("user.home");
final String s2 = Global.name("myfiledialog.windowshome",
"");
final String s3 = Global.name("myfiledialog.homedir", "");
final String sep = System.getProperty("file.separator");
if (new File(s1 + sep + s2 + sep + s3).exists())
DirField.setText(s1 + sep + s2 + sep + s3);
else if (new File(s1 + sep + s2).exists())
DirField.setText(s1 + sep + s2);
else
DirField.setText(s1);
} else
DirField.setText(s);
updateDir();
updateFiles();
} catch (final Exception e) {
}
} else if (o.equals("Create")) {
try {
final File f = new File(DirField.getText());
if (!f.exists()) {
f.mkdir();
}
updateDir();
updateFiles();
} catch (final Exception e) {
}
} else if (o.equals("Back")) {
final String dir = getUndo();
if (!dir.equals("")) {
DirField.setText(dir);
updateDir();
updateFiles();
}
} else
super.doAction(o);
}
@Override
public void actionPerformed(final ActionEvent e) {
if (e.getSource() == Dirs) {
final String s = Dirs.getSelectedItem();
if (s == null)
return;
if (s.equals(".."))
dirup();
else
dirdown(s);
}
if (e.getSource() == Files) {
if (e instanceof ListerMouseEvent) {
final ListerMouseEvent em = (ListerMouseEvent) e;
if (em.clickCount() >= 2)
leave();
else {
final String s = Files.getSelectedItem();
if (s != null)
FileField.setText(s);
}
}
} else
super.actionPerformed(e);
}
public void setFile(final String s) {
DirField.setText(FileName.path(s));
FileField.setText(FileName.filename(s));
// System.out.println(s);
update(false);
}
public void dirup() {
DirField.setText(FileName.path(CurrentDir));
if (DirField.getText().equals(""))
DirField.setText("" + File.separatorChar);
if (updateDir())
updateFiles();
}
public void dirdown(final String subdir) {
DirField.setText(CurrentDir + File.separatorChar + subdir);
if (updateDir())
updateFiles();
}
/**
* Leave the dialog and remember settings.
*/
void leave() {
if (FD != null)
return;
if (!FileField.getText().equals(""))
Aborted = false;
if (!Aborted) {
noteSize("myfiledialog");
DirField.remember(DirField.getText());
DirField.saveHistory("myfiledialog.dir.history" + DirAppend);
PatternField.saveHistory("myfiledialog.pattern.history"
+ PatternAppend);
FileField.remember(getFilePath());
FileField.saveHistory("myfiledialog.file.history" + FileAppend);
}
doclose();
}
/**
* Update the directory list.
*
* @return if the current content of DirField is indeed a directory.
*/
public boolean updateDir() {
if (FD != null)
return true;
final File dir = new File(DirField.getText() + File.separatorChar);
if (!dir.isDirectory())
return false;
try {
final String s = FileName.canonical(dir.getCanonicalPath());
addUndo(s);
DirField.setText(s);
Chosen.setText(FileName.chop(16, DirField.getText()
+ File.separatorChar + PatternField.getText(), 48));
} catch (final Exception e) {
return false;
}
return true;
}
MyVector Undo = new MyVector();
/**
* Note the directory in a history list.
*/
public void addUndo(final String dir) {
if (Undo.size() > 0
&& ((String) Undo.elementAt(Undo.size() - 1)).equals(dir))
return;
Undo.addElement(dir);
}
/**
* Get the undo directory and remove it.
*/
public String getUndo() {
if (Undo.size() < 2)
return "";
final String s = (String) Undo.elementAt(Undo.size() - 2);
Undo.truncate(Undo.size() - 1);
return s;
}
/**
* Update the file list.
*/
public void updateFiles() {
if (FD != null)
return;
final File dir = new File(DirField.getText());
if (!dir.isDirectory())
return;
CurrentDir = DirField.getText();
if (PatternField.getText().equals(""))
PatternField.setText("*");
try {
Files.clear();
Dirs.clear();
final FileList l = new FileList(DirField.getText(), PatternField
.getText(), false);
l.setCase(Global.getParameter("filedialog.usecaps", false));
l.search();
l.sort();
Enumeration e = l.files();
while (e.hasMoreElements()) {
final File f = (File) e.nextElement();
Files.addElement(FileName.filename(f.getCanonicalPath()));
}
Dirs.addElement("..");
e = l.dirs();
while (e.hasMoreElements()) {
final File f = (File) e.nextElement();
Dirs.addElement(FileName.filename(f.getCanonicalPath()));
}
} catch (final Exception e) {
}
Dirs.updateDisplay();
Files.updateDisplay();
Files.requestFocus();
}
public void setDirectory(final String dir) {
if (FD != null)
FD.setDirectory(dir);
else
DirField.setText(dir);
}
public void setPattern(final String pattern) {
if (FD != null) {
FD.setFilenameFilter(this); // does not work
final String s = pattern.replace(' ', ';');
FD.setFile(s);
} else
PatternField.setText(pattern);
}
public void setFilePath(final String file) {
if (FD != null) {
FD.setFile(file);
return;
}
final String dir = FileName.path(file);
if (!dir.equals("")) {
DirField.setText(dir);
FileField.setText(FileName.filename(file));
} else
FileField.setText(file);
}
/**
* Check, if the dialog was aborted.
*/
@Override
public boolean isAborted() {
if (FD != null)
return FD.getFile() == null || FD.getFile().equals("");
else
return Aborted;
}
/**
* @return The file plus its path.
*/
public String getFilePath() {
if (FD != null) {
if (FD.getFile() != null)
return FD.getDirectory() + FD.getFile();
else
return "";
}
final String file = FileField.getText();
if (!FileName.path(file).equals(""))
return file;
else
return CurrentDir + File.separatorChar + FileField.getText();
}
/**
* This should be called at the start.
*/
public void update(final boolean recent) {
if (FD != null)
return;
loadHistories(recent);
setFilePath(FileField.getText());
if (updateDir())
updateFiles();
Aborted = true;
}
public void update() {
update(true);
}
@Override
public void setVisible(final boolean flag) {
if (FD != null)
FD.setVisible(flag);
else
super.setVisible(flag);
}
@Override
public void center(final Frame f) {
if (FD != null)
CloseDialog.center(f, FD);
else
super.center(f);
}
public static void main(final String args[]) {
final Frame f = new CloseFrame() {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public void doclose() {
System.exit(0);
}
};
f.setSize(500, 500);
f.setLocation(400, 400);
f.setVisible(true);
final MyFileDialog d = new MyFileDialog(f, "Title", "Save", false);
d.center(f);
d.update();
d.setVisible(true);
}
@Override
public void focusGained(final FocusEvent e) {
FileField.requestFocus();
}
/**
* Can be overwritten by instances to accept only some files.
*/
public boolean accept(final File dir, final String file) {
return true;
}
public void loadHistories(final boolean recent) {
if (FD != null)
return;
DirField.loadHistory("myfiledialog.dir.history" + DirAppend);
DirHistory.update();
if (recent)
setDirectory(DirHistory.getRecent());
if (updateDir())
updateFiles();
PatternField
.loadHistory("myfiledialog.pattern.history" + PatternAppend);
FileField.loadHistory("myfiledialog.file.history" + FileAppend);
FileHistory.update();
}
public void loadHistories() {
loadHistories(true);
}
/**
* Loads the histories from the configuration file. If you want a unique
* history for your instance, you need to give a string unique for your
* instance. There are three types of histories.
*
* @param dir
* @param pattern
* @param file
* @see loadHistories
*/
public void loadHistories(final String dir, final String pattern,
final String file) {
setAppend(dir, pattern, file);
loadHistories();
}
/**
* Histories are used for the directories, the files and the patterns. The
* dialog can use different histories for each instance of this class. If
* you want that, you need to determine the history for the instance with a
* string, unique for the instance. If a string is empty, "default" is used.
*
* @param dir
* @param pattern
* @param file
*/
public void setAppend(final String dir, final String pattern,
final String file) {
if (FD != null)
return;
if (!dir.equals(""))
DirAppend = "." + dir;
else
DirAppend = ".default";
if (!pattern.equals(""))
PatternAppend = "." + pattern;
else
PatternAppend = ".default";
if (!file.equals(""))
FileAppend = "." + file;
else
FileAppend = ".default";
}
public void itemStateChanged(final ItemEvent e) {
}
}