This commit is contained in:
François
2022-01-26 19:21:00 +01:00
parent 1ef30c2b17
commit 766904b714
576 changed files with 16833 additions and 1 deletions

View File

@ -0,0 +1,12 @@
package misc;
import java.awt.Container;
import java.util.Hashtable;
import javax.swing.AbstractButton;
import javax.swing.JMenu;
public interface ApplicationManager {
public void addMenuItem (JMenu... jMenu);
public void addIconButtons (Container... containers);
public void addActiveButtons (Hashtable<String, AbstractButton> buttons);
}

532
src/java/misc/Bundle.java Normal file
View File

@ -0,0 +1,532 @@
package misc;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Properties;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;
import java.util.Vector;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.border.TitledBorder;
/**
Managed the internalization by using files properties and ResourceBundle.
This class could be used to managed all texts show in a application (buttons, menus, labels).
The files properties could be embedded in a jar (mix of class and data) or a dedicated directory.
The name file look like : applicationBundle[_langage[_COUNTRY[_VARIANT]]].properties .
Each file contains a "bundle" of key/value association.
The values are string represent message or formated sentences (with numbered holes to put variables values).
*/
public class Bundle {
static public final String FS = System.getProperty ("file.separator");
// = Constants ============================
/** Bundle file extension. */
static public final String bundleExt = ".properties";
/** Postfix for title. */
static public final String titlePostfix = "Title";
/** Prefixe for all actioners (button, menus, menuItem) */
static public final String actionPrefix = "Action";
/** XXX commentaire */
static public final String labelPrefix = "Label";
static public final String storyPrefix = "Story";
/** XXX commentaire */
static public final String messagePrefix = "Message";
/** XXX commentaire */
static public final String exceptionPrefix = "Exception";
/** XXX commentaire */
static public final String userPrefix = "User_";
/** XXX commentaire */
static public final String enumPrefix = "Enum";
/** Message shows when when try use bundle before load it. */
static private final String bundleUseException = "Can''t find token \"{0}\" in Bundle. Continue?";
static private final String bundleSaveException = "Bundle {0} can''t be save.";
// = Attributs ============================
static class ApplicationInfo {
public ResourceBundle messages;
public Hashtable<String, String> patch = new Hashtable<String, String> ();
public boolean modified;
public ApplicationInfo (ResourceBundle messages) { this.messages = messages; }
}
/** Labels to bundle to find to display.*/
static private Hashtable<String, String> labels = new Hashtable<String, String> ();
/** Applications bundle name to bundle. */
static private Hashtable<String, ApplicationInfo> applications = new Hashtable<String, ApplicationInfo> ();
static private ArrayList<String> applicationsOrder = new ArrayList<String> ();
/** The current locale used to display messages. */
static private Locale locale;
// = Accessors ============================
/**
Accessors to locale.
@return current locale.
*/
static public Locale getLocale () { return locale; }
/**
Accesor to locale.
@param locale the new locale value.
*/
static public void setLocale (Locale locale) {
resetLocale (locale);
broadcastBundleReloaded ();
}
static private final void initLocale () {
if (locale != null)
return;
Locale locale = Locale.getDefault ();
if (Config.getString ("Language") != null)
try {
locale = new Locale (Config.getString ("Language"),
Config.getString ("Country"),
Config.getString ("Variant"));
} catch (Exception e) {
}
resetLocale (locale);
}
static private void resetLocale (Locale locale) {
if (Bundle.locale == locale ||
(Bundle.locale != null && Bundle.locale.equals (locale)))
return;
Locale.setDefault (locale);
Bundle.locale = locale;
for (String application : applicationsOrder) {
ResourceBundle messages = ResourceBundle.getBundle (application, locale, bundleControl);
applications.put (application, new ApplicationInfo (messages));
}
}
static ResourceBundle.Control bundleControl = new ResourceBundle.Control () {
private String toResourceName0 (String bundleName, String suffix) {
if (bundleName.contains ("://"))
return null;
else
return toResourceName (bundleName, suffix);
}
public ResourceBundle newBundle (String baseName, Locale locale, String format, ClassLoader loader, boolean reload)
throws IllegalAccessException, InstantiationException, IOException {
String bundleName = toBundleName (baseName, locale);
ResourceBundle bundle = null;
final String resourceName = toResourceName0 (bundleName, "properties");
if (resourceName == null)
return bundle;
URLConnection connection = Config.getDataUrl (Config.dataDirname, Config.configDirname, resourceName).openConnection ();
connection.setUseCaches (false);
InputStream stream = connection.getInputStream ();
try {
bundle = new PropertyResourceBundle (stream);
} finally {
stream.close ();
}
return bundle;
}
};
// = Reading files ========================
/**
Set the new application and load bundle with parameter saved in configuration or the default system locale.
@param application the application bundle name.
*/
static public final void load (String application) {
initLocale ();
load (application, locale);
}
/**
Set the new application and load bundle according the locale in parameter.
@param application the application bundle name.
@param locale the localization to used.
*/
static public final void load (String application, Locale locale) {
try {
resetLocale (locale);
if (applicationsOrder.contains (application))
return;
applicationsOrder.add (application);
ResourceBundle messages = ResourceBundle.getBundle (application, locale, bundleControl);
// XXX anciennes valeurs de patch perdues
applications.put (application, new ApplicationInfo (messages));
for (String key : messages.keySet ())
labels.put (key, application);
boolean needSetLanguage = Config.getString ("Language") == null;
broadcastBundleReloaded ();
if (needSetLanguage)
HelpManager.actionLocale (null);
} catch (RuntimeException e) {
if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog
(null, "Would you like to continue?",
" Can't load Bundle "+application, JOptionPane.YES_NO_OPTION))
throw e;
}
}
static public final void save (String applicationName) {
File configDir = new File (Config.findDataDir (true), Config.configDirname);
File bundleFile = new File (configDir, applicationName+"_"+locale+bundleExt);
try {
save (applicationName, bundleFile);
} catch (IOException e) {
try {
configDir.mkdirs ();
save (applicationName, bundleFile);
} catch (IOException e2) {
System.err.println (MessageFormat.format (bundleSaveException, applicationName));
}
} catch (NullPointerException e) {
throw new IllegalArgumentException (bundleUseException);
}
}
static private boolean configurationModified = false;
static public final void save (String applicationName, File file)
throws IOException {
ApplicationInfo applicationInfo = applications.get (applicationName);
if (!applicationInfo.modified && file.exists ())
return;
if (!file.exists ())
file.createNewFile ();
Properties properties = new Properties ();
ResourceBundle messages = applicationInfo.messages;
for (String key : messages.keySet ())
properties.setProperty (key, messages.getString (key));
Hashtable<String, String> patch = applicationInfo.patch;
for (String key : patch.keySet ())
properties.setProperty (key, patch.get (key));
FileOutputStream fileOutputStream = new FileOutputStream (file);
properties.store (fileOutputStream, "Produit automatiquement par Bundle");
fileOutputStream.close ();
FileInputStream fileInputStream = new FileInputStream (file);
applicationInfo.messages = new PropertyResourceBundle (fileInputStream);
fileInputStream.close ();
applicationInfo.patch.clear ();
applicationInfo.modified = false;
}
static public void setString (String applicationName, String key, String val) {
ApplicationInfo applicationInfo = applications.get (applicationName);
String oldVal = null;
try {
oldVal = applicationInfo.messages.getString (key);
} catch (Exception e) {
}
if (val == oldVal || val.equals (oldVal)) {
applicationInfo.patch.remove (key);
return;
}
oldVal = applicationInfo.patch.get (key);
if (val == oldVal || val.equals (oldVal))
return;
applicationInfo.patch.put (key, val);
applicationInfo.modified = true;
labels.put (key, applicationName);
}
// = Available files ======================
/**
Give the list of locale available for a dedicated application.
@param application the application bundle name.
@return a array of string denoted locale that could be used for this application.
*/
static public final Locale[] getApplicationsLocales () {
Vector<Locale> result = new Vector<Locale> ();
scanLocale: for (Locale locale : getAvailableLocales ()) {
for (String application : applications.keySet ())
if (ClassLoader.getSystemResource (Config.configSystemDir+application+"_"+locale+bundleExt) == null &&
ClassLoader.getSystemResource (Config.configJarDir+application+"_"+locale+bundleExt) == null)
continue scanLocale;
result.add (locale);
}
Locale [] locales = result.toArray (new Locale[0]);
Arrays.sort (locales, new Comparator<Locale> () {
public int compare(Locale o1, Locale o2) {
return o1.toString ().compareTo (o2.toString ());
}
});
return locales;
}
// ========================================
static public Locale[] getAvailableLocales () {
ArrayList<Locale> all = new ArrayList<Locale> (Arrays.asList (Locale.getAvailableLocales ()));
//all.add (new Locale.Builder ().setLanguage ("br").setRegion ("BR").setVariant ("gallo").build ());
//all.add (new Locale.Builder ().setLanguage ("br").setRegion ("BR").setVariant ("breton").build ());
all.add (new Locale.Builder ().setLanguage ("br").setRegion ("FR").setVariant ("gallo").build ());
all.add (new Locale.Builder ().setLanguage ("br").setRegion ("FR").setVariant ("breton").build ());
//all.add (new Locale.Builder ().setLanguage ("es").setRegion ("ES").build ());
return all.toArray (new Locale[0]);
}
static public final Locale[] getAllLocales () {
Locale[] locales = getAvailableLocales ();
Arrays.sort (locales, new Comparator<Locale> () {
public int compare(Locale o1, Locale o2) {
return o1.toString ().compareTo (o2.toString ());
}
});
return locales;
}
static public ImageIcon getMixFlag (String language, String country) {
ImageIcon countryFlag = Util.loadImageIcon (Config.dataDirname, Config.iconsDirname, Config.flagsDirname,
country.toLowerCase () + Config.iconsExt);
ImageIcon langFlag = Util.loadImageIcon (Config.dataDirname, Config.iconsDirname, Config.flagsDirname,
language.toLowerCase () + Config.iconsExt);
if (countryFlag == null)
return langFlag;
if (langFlag == null)
return countryFlag;
int width = countryFlag.getIconWidth ();
int height = countryFlag.getIconHeight ();
BufferedImage newFlag = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = newFlag.createGraphics ();
Polygon topLeftCorner = new Polygon (new int[] {0, width, 0}, new int[] {0, 0, height}, 3);
g2.setClip (topLeftCorner);
g2.drawImage (langFlag.getImage (), 0, 0, width, height, null);
Polygon bottomRightCorner = new Polygon (new int[] {0, width, width}, new int[] {height, 0, height}, 3);
g2.setClip (bottomRightCorner);
g2.drawImage (countryFlag.getImage (), 0, 0, width, height, null);
return new ImageIcon (newFlag);
}
// ========================================
static public final JComboBox<String> getJComboFlags (final Locale[] locales) {
final ImageIcon [] flags = new ImageIcon [locales.length];
String [] labels = new String [locales.length];
final Hashtable<String,Integer> labelIndex = new Hashtable<String,Integer> ();
for (int i = 0; i < locales.length; i++) {
labelIndex.put (labels [i] = locales[i].toString (), i);
flags [i] = getMixFlag (locales[i].getLanguage (), locales[i].getCountry ());
if (flags [i] != null)
flags [i].setDescription (locales [i].toString ());
}
JComboBox<String> localesList = new JComboBox<String> (labels);
localesList.setRenderer (new DefaultListCellRenderer () {
{
setOpaque (true);
setVerticalAlignment (CENTER);
}
static private final long serialVersionUID = 1L;
public Component getListCellRendererComponent (JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
int selectedIndex = labelIndex.get (value);
if (isSelected) {
setBackground (list.getSelectionBackground ());
setForeground (list.getSelectionForeground ());
} else {
setBackground (list.getBackground ());
setForeground (list.getForeground ());
}
setIcon (flags[selectedIndex]);
setText (locales[selectedIndex].toString ());
return this;
}
});
return localesList;
}
// = Use localized texts ==================
/**
Give the string to display according to the message identifier.
@param messageId a sting used to tag message.
@return the string to display.
*/
static public boolean askBundleUseException = true;
static public final String getString (String messageId, String defaultValue) {
try {
ApplicationInfo applicationInfo = applications.get (labels.get (messageId));
String val = applicationInfo.patch.get (messageId);
if (val != null)
return val;
return applicationInfo.messages.getString (messageId);
} catch (Exception e) {
if (defaultValue != null)
return defaultValue;
if (askBundleUseException && JOptionPane.YES_OPTION !=
JOptionPane.showConfirmDialog (null, MessageFormat.format (bundleUseException, messageId),
" Bundle corrupted ", JOptionPane.YES_NO_OPTION))
throw new IllegalArgumentException (MessageFormat.format (bundleUseException, messageId));
askBundleUseException = false;
System.err.println (messageId+"= ### Bundle ###");
return messageId;
}
}
static public final String getStory (String messageId) { return getString (storyPrefix+messageId, messageId); }
static public final String getLabel (String messageId) { return messageId == null ? "" : getString (labelPrefix+messageId, null); }
static public final String getMessage (String messageId) { return getString (messagePrefix+messageId, null); }
static public final String getException (String messageId) { return getString (exceptionPrefix+messageId, null); }
static public final String getAction (String messageId) { return getString (actionPrefix+messageId, null); }
static public final String getTitle (String messageId) { return getString (messageId+titlePostfix, null); }
static public final String getUser (String messageId) { return getString (userPrefix+messageId, messageId); }
static public final void setUser (String applicationName, String messageId, String value) {
setString (applicationName, userPrefix+messageId, value);
}
static public final String getEnum (String enumId, String valueId) { return getString (enumPrefix+enumId+valueId, null); }
static public final String getEnum (Enum<?> enumValue) { return getEnum (enumValue.getClass ().getSimpleName (), enumValue.toString ()); }
static public final JComboBox<String> getEnum (Class<?> enumClass, Enum<?> defaultValue) {
String enumName = enumClass.getSimpleName ();
if (!enumClass.isEnum ())
throw new IllegalArgumentException (enumName+" is not Enum!");
JComboBox<String> jComboBox = new JComboBox<String> ();
try {
Object[] values = (Object[]) enumClass.getMethod ("values").invoke (null);
for (Object value : values)
jComboBox.addItem (getEnum (enumName, value.toString ()));
jComboBox.setEditable (false);
if (defaultValue != null)
jComboBox.setSelectedIndex (defaultValue.ordinal ());
} catch (Exception e) {
throw new IllegalArgumentException (enumName+" is not Enum!");
}
return jComboBox;
}
// = Automatic update =====================
static public void setBorder (JComponent jComponent) {
jComponent.setBorder (BorderFactory.createTitledBorder (Bundle.getTitle (Util.getClassName (jComponent.getClass ()))));
}
static public void updateBorder (JComponent jComponent) {
((TitledBorder) jComponent.getBorder ()).setTitle (Bundle.getTitle (Util.getClassName (jComponent.getClass ())));
}
/** List of actioners (button, ...) to update if the locale is updated. */
static private Vector<AbstractButton> allActioners = new Vector<AbstractButton> ();
/** List of actioners (menu, ...) to update if the locale is updated. */
static private Vector<AbstractButton> allMenus = new Vector<AbstractButton> ();
/** List of frame to update if the locale is updated. */
static private Hashtable<Dialog, String> allDialogs = new Hashtable<Dialog, String> ();
/** List of icon ToolTips to update if the locale is updated. */
static private Vector<AbstractButton> allIconToolTips = new Vector<AbstractButton> ();
/** List of application module which managed localized texts to update if the locale is updated. */
static private Hashtable<JLabel, String> allLabels = new Hashtable<JLabel, String> ();
/** XXX commentaire. */
static private Hashtable<JComboBox<String>, Class<?>> allEnums = new Hashtable<JComboBox<String>, Class<?>> ();
/** XXX commentaire. */
static private StateNotifier bundleObservable = new StateNotifier ();
/**
Say to each actioner and application module that locale change.
*/
static void broadcastBundleReloaded () {
if (Config.isLoaded ()) {
Config.setString ("Country", locale.getCountry ());
Config.setString ("Language", locale.getLanguage ());
Config.setString ("Variant", locale.getVariant ());
}
for (AbstractButton actioner : allActioners)
if (!actioner.getText ().isEmpty ())
actioner.setText (getAction (actioner.getActionCommand ()));
for (AbstractButton menu : allMenus)
if (!menu.getText ().isEmpty ())
menu.setText (getTitle (menu.getActionCommand ()));
for (Dialog dialog : allDialogs.keySet ())
dialog.setTitle (getTitle (allDialogs.get (dialog)));
for (AbstractButton actioner : allIconToolTips)
actioner.setToolTipText (Bundle.getAction (actioner.getActionCommand ()));
for (JLabel jLabel : allLabels.keySet ())
jLabel.setText (getLabel (allLabels.get (jLabel)));
for (JComboBox<String> jComboBox : allEnums.keySet ())
try {
Class<?> enumClass = allEnums.get (jComboBox);
String enumName = enumClass.getSimpleName ();
// XXX remove listeners
// XXX sauve selection multiple ?
int idx = jComboBox.getSelectedIndex ();
jComboBox.removeAllItems ();
Object[] values = (Object[]) enumClass.getMethod ("values").invoke (null);
for (Object value : values)
jComboBox.addItem (getEnum (enumName, value.toString ()));
jComboBox.setEditable (false);
jComboBox.setSelectedIndex (idx);
// XXX add listeners
} catch (Exception e) {
}
bundleObservable.broadcastUpdate ("Bundle");
}
/**
Declare an actioner to updated if the locale is updated.
@param button the actioner to update. The messageId is find by performed getActionCommand method on it.
*/
static public void addLocalizedActioner (AbstractButton button) {
allActioners.add (button);
}
static public void addLocalizedMenu (AbstractButton button) {
allMenus.add (button);
}
static public void addLocalizedDialog (Dialog dialog, String titleId) {
allDialogs.put (dialog, titleId);
}
/**
XXX commentaire
*/
static public void addLocalizedToolTip (AbstractButton button) {
allIconToolTips.add (button);
}
/**
XXX commentaire
*/
static public void addLocalizedLabel (JLabel jLabel, String messageId) {
allLabels.put (jLabel, messageId);
}
/**
XXX commentaire
*/
static public void addLocalizedEnum (JComboBox<String> jComboBox, Class<?> enumClass) {
allEnums.put (jComboBox, enumClass);
}
/**
Declare an application module which managed localized to updated if the locale is updated.
@param object the application module that managed some texts to localized.
*/
static public void addBundleObserver (Object object) {
bundleObservable.addUpdateObserver (object, "Bundle");
}
// ========================================
}

View File

@ -0,0 +1,24 @@
package misc;
public class ColorCheckedLine {
// ============================================================
static public final int NBV = 8;
static public final int NBT = 60;
/** voir http://www.termsys.demon.co.uk/vtansi.htm */
static public final String
MOVE_TO_COL_START = "\033[300C\033[",
MOVE_TO_COL_END = "D",
SETCOLOR_SUCCESS = "\033[1;32m",
SETCOLOR_FAILURE ="\033[1;31m",
SETCOLOR_WARNING ="\033[1;33m",
SETCOLOR_NORMAL ="\033[0;39m";
static public final String
MOVE_TO_60 = MOVE_TO_COL_START+(80-60)+MOVE_TO_COL_END,
MSG_OK = MOVE_TO_60+"["+SETCOLOR_SUCCESS+"OK"+SETCOLOR_NORMAL+"]",
MSG_KO = MOVE_TO_60+"["+SETCOLOR_FAILURE+"KO"+SETCOLOR_NORMAL+"]";
// ========================================
}

View File

@ -0,0 +1,154 @@
package misc;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Hashtable;
import java.util.TreeSet;
import java.util.Vector;
public class CommandLineServer<Model> {
// ========================================
private Model model;
private Class<? extends CommandLineWaiter<Model>> classWaiter;
private String classWaiterName;
/** List of commands. */
private TreeSet<String> commands = new TreeSet<String> ();
/** Help for each command. */
private Hashtable<String, String> help = new Hashtable<String, String> ();
private Hashtable<String, Method> actionsMethod = new Hashtable<String, Method> ();
// ========================================
public TreeSet<String> getCommands () { return commands; }
public Hashtable<String, String> getHelp () { return help; }
public Hashtable<String, Method> getActionsMethod () { return actionsMethod; }
public String getClassWaiterName () { return classWaiterName; }
// ========================================
public void showMsg (String msg) {}
public void showStatus (String msg) {}
// ========================================
public CommandLineServer (Model model, Class<? extends CommandLineWaiter<Model>> classWaiter, Collection<String> commands) {
this.model = model;
this.classWaiter = classWaiter;
String[] path = classWaiter.getName ().split ("\\.");
classWaiterName = path [path.length-1];
for (String action : commands)
this.commands.add (action.toLowerCase ());
for (String action : this.commands) {
try {
String methodName = "action"+Util.toCapital (action);
actionsMethod.put (action, classWaiter.getMethod (methodName));
} catch (NoSuchMethodException e) {
Log.keepLastException ("CommandLineServer", e);
}
}
updateBundle ();
Bundle.addBundleObserver (this);
}
// ========================================
public void updateBundle () {
help.clear ();
for (String cmd : commands)
help.put (cmd, Bundle.getString ("Help"+classWaiterName+"_"+cmd, null).replaceAll ("\\\\n", "\n"));
}
/** In case of multiple started, this is the only thread wich have right to run. */
private Thread thread;
// ========================================
public boolean isAliveServer () {
return thread != null && thread.isAlive ();
}
// ========================================
private int lastPort;
/** Interrupt the server after a TIME_OUT. */
public void stopServer () {
thread = null;
try {
// force le accept pour sortir du run
(new Socket ("localhost", lastPort)).close ();
} catch (Exception e) {
}
stopCalls ();
}
Vector<Socket> calls = new Vector<Socket> ();
public synchronized void addCall (Socket call) {
calls.add (call);
}
public synchronized void removeCall (Socket call) {
calls.remove (call);
}
public synchronized void stopCalls () {
for (Socket call : calls) {
try {
call.close ();
} catch (Exception e) {
}
}
calls.clear ();
}
// ========================================
/**
* Start a server on a dedicated port.
* @param port the internet port number.
*/
public void startServer (final int port) {
(new Thread () {
public void run () {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket (port);
CommandLineServer.this.lastPort = port;
} catch (IOException e) {
showMsg (Bundle.getMessage ("CanTCreateSocket"));
Log.keepLastException ("CommandLineServer::startServer", e);
return;
}
showMsg (MessageFormat.format (Bundle.getMessage (classWaiterName+"Starts"), port));
showStatus (MessageFormat.format (Bundle.getMessage (classWaiterName+"Starts"), port));
thread = Thread.currentThread ();
try {
while (thread == Thread.currentThread ()) {
try {
Socket call = serverSocket.accept ();
addCall (call);
classWaiter.getConstructor (CommandLineServer.class, model.getClass (), Socket.class).
newInstance (CommandLineServer.this, model, call);
} catch (IOException e) {
showMsg (Bundle.getMessage ("ClientAbort"));
Log.keepLastException ("CommandLineServer::startServer", e);
}
}
} catch (java.lang.reflect.InvocationTargetException e) {
Log.keepLastException ("CommandLineServer::startServer", e);
} catch (NoSuchMethodException e) {
Log.keepLastException ("CommandLineServer::startServer", e);
} catch (IllegalAccessException e) {
Log.keepLastException ("CommandLineServer::startServer", e);
} catch (InstantiationException e) {
Log.keepLastException ("CommandLineServer::startServer", e);
}
try {
showMsg (Bundle.getMessage (classWaiterName+"Stopped"));
showStatus (Bundle.getMessage (classWaiterName+"Stopped"));
serverSocket.close ();
} catch (IOException e) {
}
}
}).start();
}
// ========================================
}

View File

@ -0,0 +1,165 @@
package misc;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.net.Socket;
import java.net.SocketException;
import java.text.MessageFormat;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.TreeSet;
public class CommandLineWaiter<Model> {
// ========================================
static public final int MAX_COL = 6;
// ========================================
protected Model model;
protected CommandLineServer<Model> commandLineServer;
private TreeSet<String> commands;
private Hashtable<String, String> help;
private Hashtable<String, Method> actionsMethod;
/** The original call socket to be close at the end of analyse. */
protected Socket call;
/** Input chanel (of the socket). */
protected BufferedReader in;
/** Output chanel (of the socket). */
protected PrintWriter out;
protected String line;
protected StringTokenizer arguments;
public boolean hasMoreArg () {
return arguments.hasMoreTokens ();
}
public String nextArg () {
return arguments.nextToken ().trim ();
}
public void startCall () {}
// ========================================
public String getCommandLine (BufferedReader in)
throws IOException {
try {
return in.readLine ().trim ();
} catch (SocketException e) {
return null;
} catch (NullPointerException e) {
return null;
}
}
// ========================================
/**
* Send a answer to the client with a newline and flush the output chanel.
* @param str the answer to send.
*/
public void answerln (String str) {
out.println (str);
out.flush ();
}
public void syntaxError () {
answerln (Bundle.getMessage ("SyntaxeError"));
}
// ========================================
/**
* Give a help to the client.
* @param cmd is null or empty, give the list of commands. Else, give a appropriate help for the command cmd.
*/
public void actionHelp () {
String arg = null;
if (hasMoreArg ())
arg = nextArg ().toLowerCase ();
if (arg == null || arg.isEmpty ())
answerln (Bundle.getString ("Help"+commandLineServer.getClassWaiterName ()+"_", null).replaceAll ("\\\\n", "\n")+
Util.toColumn (Util.set2string (commands), MAX_COL));
else {
String explanation = help.get (arg);
if (explanation == null)
answerln (MessageFormat.format (Bundle.getMessage ("NotACommand"), arg));
else
answerln (arg.toLowerCase ()+" "+explanation);
}
}
// ========================================
public void actionQuit () {
answerln (Bundle.getMessage ("SeeYouSoon").replaceAll ("\\\\n", "\n"));
try {
call.close ();
} catch (Exception e) {
}
}
// ========================================
public void actionExit () {
answerln (Bundle.getMessage ("GoodBye").replaceAll ("\\\\n", "\n"));
System.exit (0);
}
// ========================================
/**
* Open a chanel and start a shell interpretor.
* @param call the client connection.
*/
public CommandLineWaiter (CommandLineServer<Model> commandLineServer, Model model, Socket call) {
this.commandLineServer = commandLineServer;
this.model = model;
this.call = call;
commands = commandLineServer.getCommands ();
help = commandLineServer.getHelp ();
actionsMethod = commandLineServer.getActionsMethod ();
try {
in = new BufferedReader (new InputStreamReader (call.getInputStream ()));
out = new PrintWriter (call.getOutputStream ());
startCall ();
(new Thread () {
public void run() {
analyse ();
}
}).start();
} catch (IOException e) {
if (!call.isClosed ())
Log.keepLastException ("CommandLineWaiter", e);
}
}
// ========================================
public void analyse () {
String cmd = null;
try {
for (; ! call.isClosed (); ) {
line = getCommandLine (in);
if (line == null)
break;
if (line.isEmpty ())
continue;
arguments = new StringTokenizer (line);
if (!arguments.hasMoreTokens ())
continue;
cmd = arguments.nextToken ().trim ().toLowerCase ();
if (commands.contains (cmd))
actionsMethod.get (cmd).invoke (this);
else
answerln (MessageFormat.format (Bundle.getMessage ("NotACommand"), cmd));
}
} catch (Exception e) {
Log.keepLastException ("CommandLineWaiter::analyse ("+cmd+")", e);
} finally {
try {
call.close ();
} catch (Exception e) {
}
}
}
// ========================================
}

523
src/java/misc/Config.java Normal file
View File

@ -0,0 +1,523 @@
package misc;
import java.awt.Component;
import java.awt.Point;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.MessageFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Properties;
import java.util.Vector;
import javax.swing.JComboBox;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.ListModel;
/**
Managed the persistance key/value strings association.
This class could be used to managed all constants values in a application.
The values commme from a bundle jar (mix of class and data) or a dedicated directeory.
*/
public class Config {
static public final String FS = System.getProperty ("file.separator");
static public final String
dataDirname = "data",
configDirname = "config",
textsDirname = "texts",
logDirname = "log",
imagesDirname = "images",
iconsDirname = "images",
buttonDirname = "button",
flagsDirname = "flags";
/** Path to configuration files in files system. */
static public final String
configSystemDir = dataDirname+FS+configDirname+FS,
logSystemDir = dataDirname+FS+logDirname+FS,
buttonSystemDir = dataDirname+FS+imagesDirname+FS+buttonDirname+FS;
/** Path to configuration files in jar. */
static public final String
configJarDir = dataDirname+"/"+configDirname+"/",
imagesJarDir = dataDirname+"/"+imagesDirname+"/",
textsJarDir = dataDirname+"/"+textsDirname+"/";
/** Configuration file extension. */
static public final String
configExt = ".xml",
iconsExt = ".png",
imagesExt = ".png",
htmlExt = ".html",
logExt = ".log";
/** Enconding charset for saving configuration. */
static public final String configEncoding = "UTF8";
/** Comment used as header configuration file. */
static public final String configHeaderFile =
"This file is automaticaly generated by {0} application at {1,time,short} on {1,date}.";
/** Somme postfix for constants name in configuration file. */
static public final String
checkedPostfix = "Checked",
undockedPostfix = "Undocked",
locationPostfix = "Location";
/** Message shows when trying to get string with a null key. */
static private final String configNullKeyException = "No configuration associates with null key.";
/** Message shows when trying to use configuration before load it. */
static private final String configUseException = "No configuration loaded.";
/** Message shows when load exception appears. */
static private final String configLoadException = "Configuration {0} can''t be load (corrupted file ?).";
/** Message shows when save exception appears. */
static private final String configSaveException = "Configuration {0} can''t be save.";
/** Liste of constants (key/value strings association). */
//static private Properties configuration;
static public Properties configuration;
/** True if configuration need to be saved. */
static private boolean configurationModified = false;
// ========================================
static private File PWD;
static private String[] dataPath;
static {
setPWD (Util.class);
setDataPath (".:..");
}
static public File getJarFileOrClassDir (Class<?> applicationClass) {
try {
return new File (applicationClass.getProtectionDomain ().getCodeSource ().getLocation ().toURI ());
} catch (Exception e) {
// dosn't work for applet
return null;
}
}
static public File getPWD () { return PWD; }
// XXX static public String getPWD () { return PWD.getAbsolutePath (); }
static public void setPWD (Class<?> applicationClass) {
try {
PWD = getJarFileOrClassDir (applicationClass).getParentFile ();
} catch (Exception e) {
}
}
static public void setDataPath (String path) {
dataPath = path.split (":");
}
static public File findDataDir () {
return findDataDir (false);
}
static public File findDataDir (boolean writable) {
String name = dataDirname;
try {
// search from excecution dir
File file = (new File (name));
if (file.exists () && file.isDirectory () && (!writable || file.canWrite ()))
return file;
} catch (Exception e) {
}
for (String path : dataPath) {
try {
// search in relative path from jar
File file = (new File (PWD, path+FS+name));
if (file.exists () && file.isDirectory () && (!writable || file.canWrite ()))
return file;
} catch (Exception e) {
}
}
return null;
}
static public URL getDataUrl (String... names) {
if (names.length < 1)
return null;
String name = names[names.length - 1];
String jarPath = "", systemPath = "";
for (int i = 0; i < names.length - 1; i++) {
jarPath += names[i]+"/";
systemPath += names[i]+FS;
}
try {
// search from excecution dir
File file = new File (systemPath+name);
if (file.exists ())
return file.toURI ().toURL ();
} catch (Exception e) {
}
for (String path : dataPath) {
try {
// search in relative path from jar
File file = new File (PWD, path+FS+systemPath+name);
if (file.exists ())
return file.getCanonicalFile ().toURI ().toURL ();
} catch (Exception e) {
}
}
try {
// search in jar
URL result = ClassLoader.getSystemResource (jarPath+name);
return result;
} catch (Exception e) {
}
return null;
}
// ========================================
/**
Load XML configuration file contains constants (key/value strings association).
@param applicationName the application name use to find file.
*/
static public final void load (String applicationName) {
configuration = new Properties ();
try {
File configDir = new File (findDataDir (), configDirname);
File configFile = new File (configDir, applicationName+configExt);
FileInputStream fileInputStream = new FileInputStream (configFile);
configuration.loadFromXML (fileInputStream);
fileInputStream.close ();
configurationModified = false;
} catch (Exception e) {
try {
configuration.loadFromXML (ClassLoader.getSystemResourceAsStream
(configJarDir+applicationName+configExt));
configurationModified = false;
} catch (Exception e2) {
try {
configuration.loadFromXML (ClassLoader.getSystemResourceAsStream
(configJarDir+applicationName+configExt));
configurationModified = false;
} catch (Exception e3) {
if (JOptionPane.YES_OPTION != JOptionPane.showConfirmDialog
(null, "Would you like to continue?",
" Can't load Configuration ", JOptionPane.YES_NO_OPTION))
throw new IllegalArgumentException (MessageFormat.format (configLoadException, applicationName));
}
}
}
}
// ========================================
/**
Return the loading state of the configuration.
@return true if the configuration is loaded.
*/
static public boolean isLoaded () {
return configuration != null;
}
// ========================================
/**
Save XML configuration file contains key/value strings association.
The file is not writing if no modification occure.
@param applicationName the application name use to save file.
*/
static public final void save (String applicationName) {
File configDir = new File (findDataDir (true), configDirname);
File configFile = new File (configDir, applicationName+configExt);
try {
save (applicationName, configFile);
} catch (IOException e) {
try {
e.printStackTrace ();
configDir.mkdirs ();
save (applicationName,configFile);
} catch (IOException e2) {
System.err.println (MessageFormat.format (configSaveException, applicationName));
}
} catch (NullPointerException e) {
throw new IllegalArgumentException (configUseException);
}
}
static public final void save (String applicationName, File file)
throws IOException {
if (!configurationModified && file.exists ())
return;
if (!file.exists ())
file.createNewFile ();
FileOutputStream fileOutputStream = new FileOutputStream (file);
configuration.storeToXML (fileOutputStream,
(new MessageFormat (configHeaderFile, Locale.US)).format (new Object[] {applicationName, new Date ()},
new StringBuffer(), null).toString (),
configEncoding);
fileOutputStream.close ();
configurationModified = false;
}
// ========================================
// XXX defaultValue peut être placé systématiquement (voir à null)
/**
Searches for the value with the specified key in this configuration list.
@param key the name of the configuration parameter.
@return the configuration value associated with the key or null if not found.
*/
static public final String getString (String key) {
if (key == null)
throw new IllegalArgumentException (configNullKeyException);
try {
return configuration.getProperty (key);
} catch (NullPointerException e) {
throw new IllegalArgumentException (configUseException);
}
}
/**
Searches for the value with the specified key in this configuration list.
@param key the name of the configuration parameter.
@param defaultValue the defaultValue in case the key is not found.
@return the configuration value associated with the key or defaultValue if not found.
*/
static public final String getString (String key, String defaultValue) {
String value = configuration.getProperty (key);
if (value != null)
return value;
configuration.setProperty (key, defaultValue);
return defaultValue;
}
/**
Change the value with the specified key in this configuration list.
@param key the name of the configuration parameter.
@param value the new configuration value associated with the key.
*/
static public final void setString (String key, String value) {
try {
configuration.setProperty (key, value);
configurationModified = true;
} catch (NullPointerException e) {
throw new IllegalArgumentException (configUseException);
}
}
// ========================================
static public final File getFile (String key) {
String fileName = getString (key);
if (fileName == null)
return null;
return new File (fileName);
}
static public final void setFile (String key, File file) {
setString (key, file.getPath ());
}
// ========================================
static public final boolean getBoolean (String key) {
return Boolean.parseBoolean (getString (key));
}
static public final boolean getBoolean (String key, boolean defaultValue) {
return Boolean.parseBoolean (getString (key, ""+defaultValue));
}
static public final void setBoolean (String key, boolean value) {
setString (key, ""+value);
}
// ========================================
static public final int getInt (String key) {
return Integer.parseInt (getString (key));
}
static public final int getInt (String key, int defaultValue) {
try {
return Integer.parseInt (getString (key, ""+defaultValue));
} catch (Exception e) {
return defaultValue;
}
}
static public final void setInt (String key, int value) {
setString (key, ""+value);
}
// ========================================
static public final float getFloat (String key) {
return Float.parseFloat (getString (key));
}
static public final float getFloat (String key, float defaultValue) {
try {
return Float.parseFloat (getString (key, ""+defaultValue));
} catch (Exception e) {
return defaultValue;
}
}
static public final void setFloat (String key, float value) {
setString (key, ""+value);
}
// ========================================
static public final double getDouble (String key) {
return Double.parseDouble (getString (key));
}
static public final double getDouble (String key, double defaultValue) {
try {
return Double.parseDouble (getString (key, ""+defaultValue));
} catch (Exception e) {
return defaultValue;
}
}
static public final void setDouble (String key, double value) {
setString (key, ""+value);
}
// ========================================
static public final<T> T getEnum (String key, T defaultValue) {
return Util.toEnum (getString (key, ""+defaultValue), defaultValue);
}
// ========================================
static public final DecimalFormat indexFormat = new DecimalFormat ("-0000");
static public final Vector<String> getList (String key, String defaultValue) {
Vector<String> result = new Vector<String> ();
int size = Integer.parseInt (getString (key+"-size", "1"));
result.add (getString (key, defaultValue));
for (int i = 1; i < size; i++)
result.add (getString (key+indexFormat.format (i)));
return result;
}
static public final void setList (String key, Vector<String> value) {
// XXX suppression des anciennes valeurs
int size = value.size ();
int max = Integer.parseInt (getString (key+"-max", "10"));
setString (key+"-max", ""+max);
setString (key+"-size", ""+size);
setString (key, value.elementAt (0));
size = Math.min (size, max);
for (int i = 1; i < size; i++)
setString (key+indexFormat.format (i), value.elementAt (i));
}
// ========================================
// XXX faire un defaultValue en vector
static public final void loadJList (String key, JList<String> jList, String defaultValue) {
Vector<String> list = getList (key, defaultValue);
jList.setListData (list);
jList.setSelectedIndex (0);
}
static public final void saveJList (String key, JList<String> jList) {
Vector<String> result = new Vector<String> ();
ListModel<String> model = jList.getModel ();
int size = model.getSize ();
for (int i = 0; i < size; i++)
result.add (model.getElementAt (i));
int index = jList.getSelectedIndex ();
if (index >= 0) {
result.insertElementAt (result.remove (index), 0);
jList.setListData (result);
jList.setSelectedIndex (0);
}
setList (key, result);
}
// ========================================
// XXX faire un defaultValue en vector
static public final void loadJComboBox (String key, JComboBox<String> jComboBox, String defaultValue) {
Vector<String> list = getList (key, defaultValue);
jComboBox.removeAllItems ();
for (int i = 0; i < list.size (); i++)
jComboBox.addItem (list.elementAt (i));
jComboBox.setSelectedIndex (0);
}
static public final void loadJComboBoxInteger (String key, JComboBox<Integer> jComboBox, String defaultValue) {
Vector<String> list = getList (key, defaultValue);
jComboBox.removeAllItems ();
for (int i = 0; i < list.size (); i++) {
try {
jComboBox.addItem (Integer.parseInt (list.elementAt (i)));
} catch (Exception e) {
}
}
jComboBox.setSelectedIndex (0);
}
static public final void saveJComboBox (String key, JComboBox<String> jComboBox) {
// XX peut être ajouter la valeur éditer dans la liste
Vector<String> result = new Vector<String> ();
int size = jComboBox.getItemCount ();
for (int i = 0; i < size; i++)
result.add (jComboBox.getItemAt (i));
int index = jComboBox.getSelectedIndex ();
if (index < 0)
result.insertElementAt ((String) jComboBox.getSelectedItem (), 0);
else
result.insertElementAt (result.remove (index), 0);
if (index != 0) {
jComboBox.removeAllItems ();
for (int i = 0; i < result.size (); i++)
jComboBox.addItem (result.elementAt (i));
jComboBox.setSelectedIndex (0);
}
setList (key, result);
}
static public final void saveJComboBoxInteger (String key, JComboBox<Integer> jComboBox) {
// XX peut être ajouter la valeur éditer dans la liste
Vector<String> result = new Vector<String> ();
int size = jComboBox.getItemCount ();
for (int i = 0; i < size; i++)
result.add (""+jComboBox.getItemAt (i));
int index = jComboBox.getSelectedIndex ();
if (index < 0)
result.insertElementAt ((String) jComboBox.getSelectedItem (), 0);
else
result.insertElementAt (result.remove (index), 0);
setList (key, result);
}
// ========================================
/** Text format used to represent coordonates (i.e. [x=123,y=456] ). */
static public final MessageFormat coordonateFormat = new MessageFormat ("[x={0,number,integer},y={1,number,integer}]");
/**
Set component location from a constant coordonates in configuration.
@param key the name used to denoted the contant.
@param component modified by the coordonates retreived in configuration.
@param defaultLocation default coordonates used if non key present.
*/
static public final void loadLocation (String key, Component component, Point defaultLocation) {
try {
Object [] location = coordonateFormat.parse (getString (key+locationPostfix),
new java.text.ParsePosition (0));
component.setLocation (((Number) location [0]).intValue (), ((Number) location [1]).intValue ());
} catch (Exception e) {
component.setLocation (defaultLocation);
}
}
/**
Save constant coordonates to configuration form a component location.
@param key the name used to denoted the contant.
@param component used to set the contant coordonates value.
*/
static public final void saveLocation (String key, Component component) {
Point location = component.getLocation ();
setString (key+locationPostfix,
coordonateFormat.format (new Object [] {location.x, location.y},
new StringBuffer(), null).toString ());
}
// ========================================
}

View File

@ -0,0 +1,216 @@
package misc;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import javax.swing.AbstractButton;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public abstract class Controller<T> implements ApplicationManager, OwnFrame, ActionListener {
// ========================================
// remplace <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
// a placer avant la création de socket (y compris celle pour X11 faite par swing)
static {
java.util.Properties props = System.getProperties ();
props.setProperty ("java.net.preferIPv4Stack", ""+true);
System.setProperties (props);
}
// ========================================
static public final List<String> actionsNames = Arrays.asList ("Quit");
@SuppressWarnings("unchecked")
static public final Hashtable<String, Method> actionsMethod = Util.collectMethod (Controller.class, actionsNames);
public void actionPerformed (ActionEvent e) {
Util.actionPerformed (actionsMethod, e, this);
}
// ========================================
protected JFrame jFrame;
protected Component component;
protected JMenuBar menuBar;
public JFrame getJFrame () { return jFrame; }
// ========================================
public Controller (T t) {
createModel (t);
createAndShowFrame (createGUI (), createMenuBar ());
Plugins.hideSate ();
}
// ========================================
// XXX ATTENTION
// createModel est appelé avant la création des attribut pas le constructer de "super"
// les attrubuts ne doivent donc pas être initialisé durant leur déclaration
protected abstract void createModel (T t);
public abstract String getTitle ();
public abstract Image getIcon ();
public void updateBundle () {
SwingUtilities.invokeLater (new Runnable () {
public void run () {
jFrame.setTitle (getTitle ());
}
});
}
// ========================================
public void reborn () {
// XXX on pert les boites de dialog attachées à l'ancienne fenêtre
jFrame.dispose ();
jFrame.setJMenuBar (null);
jFrame.getContentPane ().remove (component);
createAndShowFrame (component, menuBar);
}
// ========================================
protected void createAndShowFrame (final Component component, final JMenuBar menuBar) {
final JFrame newJFrame = new JFrame (getTitle ());
newJFrame.setIconImage (getIcon ());
newJFrame.setJMenuBar (menuBar);
newJFrame.getContentPane ().add (component, BorderLayout.CENTER);
newJFrame.pack ();
newJFrame.addWindowListener (new WindowAdapter () {
public void windowClosing (WindowEvent e) {
Config.saveLocation ("Frame", jFrame);
if (tryClosingWindows ())
quit ();
else
reborn ();
}
});
if (jFrame == null) {
newJFrame.setLocationRelativeTo (null);
Config.loadLocation ("Frame", newJFrame, newJFrame.getLocation ());
} else
newJFrame.setLocation (jFrame.getLocation ());
jFrame = newJFrame;
this.component = component;
this.menuBar = menuBar;
jFrame.setVisible (true);
newJFrame ();
}
// ========================================
protected void newJFrame () { }
// ========================================
protected Component createGUI () {
Bundle.addBundleObserver (this);
return new JLabel ("Empty controller");
}
// ========================================
protected JMenuBar createMenuBar () {
return null;
}
// ========================================
public void quit () {
System.exit (0);
}
// ========================================
public void actionQuit () {
Config.saveLocation ("Frame", jFrame);
if (tryClosingWindows ())
quit ();
}
// ========================================
protected boolean tryClosingWindows () {
switch (JOptionPane.showConfirmDialog (jFrame, "Do you want to quit ?", "Quit",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE)) {
case JOptionPane.YES_OPTION:
return true;
case JOptionPane.NO_OPTION:
case JOptionPane.CLOSED_OPTION:
return false;
}
return true;
}
// ========================================
public void addMenuItem (JMenu... jMenu) {
Util.addMenuItem (actionsNames, this, jMenu[0]);
}
// ========================================
public void addIconButtons (Container... containers) {
Util.addIconButton (actionsNames, this, containers[0]);
}
// ========================================
public void addActiveButtons (Hashtable<String, AbstractButton> buttons) {
}
// ========================================
static public void main (String[] args) {
Config.load ("Misc");
Bundle.load ("Help");
Bundle.load ("Controller");
@SuppressWarnings ("serial")
class JControllerTestMenu extends JMenuBar {
public JControllerTestMenu (ApplicationManager controllerManager, ApplicationManager helpManager) {
setLayout (new BoxLayout (this, BoxLayout.X_AXIS));
JMenu fileMenu = Util.addJMenu (this, "File");
add (Box.createHorizontalGlue ());
JMenu helpMenu = Util.addJMenu (this, "Help");
controllerManager.addMenuItem (fileMenu);
helpManager.addMenuItem (helpMenu);
Hashtable<String, AbstractButton> buttons = new Hashtable<String, AbstractButton> ();
Util.collectButtons (buttons, fileMenu);
Util.collectButtons (buttons, helpMenu);
controllerManager.addActiveButtons (buttons);
helpManager.addActiveButtons (buttons);
}
};
class ControllerTest extends Controller<String> {
public ControllerTest () { super (""); }
protected void createModel (String s) {}
public String getTitle () { return null; }
public Image getIcon () {
return Util.loadImageIcon (Config.getString ("MiscIcon",
Config.imagesJarDir+"misc"+Config.imagesExt)).getImage ();
}
protected JMenuBar createMenuBar () {
return new JControllerTestMenu (this, new HelpManager (this, "Misc"));
}
protected Component createGUI () {
return new JLabel ("Affichage de la licence.");
}
protected boolean tryClosingWindows () {
Config.save ("Misc");
return true;
}
};
SwingUtilities.invokeLater (new Runnable () {
public void run () {
new ControllerTest ();
}
});
}
// ========================================
}

View File

@ -0,0 +1,242 @@
// ================================================================================
// Copyright (c) Francois Merciol 2002
// Project : Classe
// Name : DatePanel.java
// Language : Java
// Type : Source file for DatePanel class
// Author : Francois Merciol
// Creation : 02/09/2002
// ================================================================================
// History
// --------------------------------------------------------------------------------
// Author :
// Date :
// Reason :
// ================================================================================
// To be improved :
// ================================================================================
package misc;
import java.awt.Dimension;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.swing.JTextField;
/**
Champ de saisie d'une date au format dd/MM/yyyy.
Autres fonctions :<ul>
<li> (espace) : éfface le champs
<li> '+' ou (fleche haut) : incrémente d'un jour
<li> '-' ou (fleche bas) : décrémente d'un jour
<li> (retoure chariot) ou (perte de "focus") : transforme une date sur deux chiffres en relatif à la date actuelle.
</ul>
*/
@SuppressWarnings ("serial") public class DatePanel extends JTextField implements KeyListener, FocusListener {
// ========================================
/** Format d'une date en francais. */
static public final SimpleDateFormat dateFormat = new SimpleDateFormat ("dd/MM/yyyy");
/** Ensemble des caractères ayant une action sur ce champs.
Il faudrais ajouter le retoure chariot et le caractère d'effacement. */
static public final String acceptChar = "0123456789/+- "+KeyEvent.VK_UP+KeyEvent.VK_DOWN;
// ========================================
/**
Création d'une date en reservant une taille maximal puis mis à la date actuelle.
*/
public DatePanel () {
super ("31/12/9999");
addKeyListener (this);
addFocusListener (this);
set (new Date ());
}
// ========================================
// api
// ========================================
/**
Interprétation d'une année sur 2 chiffres.
*/
public void enter () {
tune2ky ();
}
// ========================================
/**
Fixe une date.
@param date la nouvelle valeur.
*/
public void set (Date date) {
setText (dateFormat.format (date));
}
// ========================================
// Listener
// ========================================
/** Interface KeyListener. */
public void keyPressed (KeyEvent e) {
}
// ========================================
/** Interface KeyListener. */
public void keyReleased (KeyEvent e) {
int c = e.getKeyCode ();
switch (c) {
case KeyEvent.VK_UP:
incr (1);
e.consume ();
return;
case KeyEvent.VK_DOWN:
incr (-1);
e.consume ();
return;
}
}
// ========================================
/** Interface KeyListener. */
public void keyTyped (KeyEvent e) {
char c = e.getKeyChar ();
switch (c) {
case KeyEvent.VK_ENTER:
enter ();
return;
case ';':
// le ; sera s<>parateur
e.consume ();
return;
case KeyEvent.VK_BACK_SPACE:
// on laisse java faire
return;
case KeyEvent.VK_SPACE:
setText ("");
e.consume ();
return;
case '+':
incr (1);
e.consume ();
return;
case '-':
incr (-1);
e.consume ();
return;
}
if (acceptChar.indexOf (c) < 0) {
e.consume ();
return;
}
if (getSelectedText () == null && getText ().length () >= 12) {
e.consume ();
return;
}
}
// ========================================
/** Interface FocusListener. */
public void focusGained (FocusEvent e) {
}
// ========================================
/** Interface FocusListener. */
public void focusLost (FocusEvent e) {
tune2ky ();
}
// ========================================
// Listener spécial
// ========================================
/**
Interprétation d'une année sur 2 chiffre.
*/
public void tune2ky () {
try {
Date origDate = dateFormat.parse (getText ().trim ());
GregorianCalendar cal = new GregorianCalendar ();
cal.setTime (origDate);
int y = cal.get (Calendar.YEAR);
if (y < 100) {
cal.add (Calendar.YEAR, cur2ky);
if (y < min2ky)
cal.add (Calendar.YEAR, 100);
else if (y > max2ky)
cal.add (Calendar.YEAR, -100);
}
setText (dateFormat.format (cal.getTime ()));
getSize (tmpSize);
if (tmpSize.width != 0)
size = tmpSize;
} catch (Exception ex) {
}
}
// ========================================
/** Taille actuelle du champ. */
private Dimension tmpSize = new Dimension ();
/** Derniére taille maximum utilisée. */
private Dimension size;
// ========================================
/**
@return la taille maximum déjà utilisé.
*/
public Dimension getPreferredSize () {
if (size != null)
return size;
return super.getPreferredSize ();
}
// ========================================
/**
@return la taille maximum déjà utilisé.
*/
public Dimension getMinimumSize () {
if (size != null)
return size;
return super.getPreferredSize ();
}
// ========================================
/**
Change la date d'une certain nombre de jours.
@param incr le nombre de jour à avancer (diminuer si négatif).
*/
public void incr (int incr) {
try {
tune2ky ();
Date origDate = dateFormat.parse (getText ().trim ());
GregorianCalendar cal = new GregorianCalendar ();
cal.setTime (origDate);
cal.add (Calendar.DATE, incr);
setText (dateFormat.format (cal.getTime ()));
} catch (Exception ex) {
}
}
// ========================================
// valeurs d'une année sur 2 chiffres
// ========================================
/** XXX commentaire sur l'optimisation d'une année sur 2 chiffre. */
static public int min2ky, max2ky, cur2ky;
/** Initialisation des champs. */
static {
GregorianCalendar cal = new GregorianCalendar ();
cal.setTime (new Date ());
int y = cal.get(Calendar.YEAR);
int yMod1ky = y % 100;
min2ky = yMod1ky - 50;
max2ky = yMod1ky + 50;
cur2ky = y - yMod1ky;
}
// ========================================
}

View File

@ -0,0 +1,62 @@
// ================================================================================
// François MERCIOL 2015
// Name : Dimension2D.java
// Language : Java
// Author : François Merciol
// CopyLeft : Cecil B
// Creation : 2015
// Version : 0.1 (xx/xx/xx)
// ================================================================================
package misc;
import java.awt.geom.Dimension2D;
@SuppressWarnings ("overrides")
public class DimensionDouble extends Dimension2D {
// ========================================
public double width, height;
public DimensionDouble () {
}
public DimensionDouble (double width, double height) {
this.width = width;
this.height = height;
}
public boolean equals (Object obj) {
try {
DimensionDouble dim = (DimensionDouble) obj;
return width == dim.width && height == dim.height;
} catch (Exception e) {
return false;
}
}
// ========================================
public double getHeight () {
return height;
}
public double getWidth () {
return width;
}
public void setSize (Dimension2D d) {
width = d.getWidth ();
height = d.getHeight ();
}
public void setSize (double width, double height) {
this.width = width;
this.height = height;
}
// ========================================
public String toString () {
return DimensionDouble.class.getSimpleName ()+"[width="+width+",height="+height+"]";
}
// ========================================
}

View File

@ -0,0 +1,53 @@
package misc;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
public class EasterEgg {
public static final SimpleDateFormat birthFormat = new SimpleDateFormat("MMdd");
String defaultValue;
class Periode {
String start;
String stop;
String value;
Periode(String start, String stop, String value) {
this.start = start;
this.stop = stop;
this.value = value;
}
}
ArrayList<Periode> periodes = new ArrayList<>();
public EasterEgg(String defaultValue) {
this.defaultValue = defaultValue;
}
public void addPeriode(String start, String stop, String value) {
this.periodes.add(new Periode(start, stop, value));
}
public String getValue() {
return get(new Date());
}
public String get(Date date) {
String day = birthFormat.format(date);
for (Periode periode : this.periodes) {
if (periode.start.compareTo(periode.stop) <= 0) {
if (day.compareTo(periode.start) >= 0 && day.compareTo(periode.stop) <= 0)
return periode.value;
continue;
}
if (day.compareTo(periode.start) <= 0 || day.compareTo(periode.stop) >= 0)
return periode.value;
}
return this.defaultValue;
}
}

208
src/java/misc/Guide.java Normal file
View File

@ -0,0 +1,208 @@
package misc;
import java.awt.Color;
import java.awt.Component;
import java.awt.Frame;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLFrameHyperlinkEvent;
@SuppressWarnings ("serial") public class Guide extends HtmlDialog {
// ========================================
static public final int H_SPACE = 5;
static public final int V_SPACE = 2;
// ========================================
Color standardBackground = Color.gray;
Color highlightColor = Color.orange;
Component [] component;
Color [] componentBackgroundColor;
int next = -1;
boolean [] done;
// ========================================
public Guide (Frame frame, String titleName, String fileName, Component [] component,
Color standardBackground, Color highlightColor) {
super (frame, titleName, fileName);
this.component = component;
this.standardBackground = standardBackground;
this.highlightColor = highlightColor;
done = new boolean [component.length];
componentBackgroundColor = new Color [component.length];
for (int i = 0; i < component.length; i++)
if (component [i] != null)
componentBackgroundColor [i] = component [i].getBackground ();
reset ();
editorPane.addHyperlinkListener (new Hyperactive ());
}
// ========================================
class Hyperactive implements HyperlinkListener {
public void hyperlinkUpdate (HyperlinkEvent e) {
if (e.getEventType () == HyperlinkEvent.EventType.ACTIVATED) {
String file = e.getURL ().getPath ();
String command = file.substring (file.lastIndexOf ("/")+1);
int idx = command.indexOf ("?");
if (idx >= 0)
command = command.substring (0, idx);
if ("Reset".equals (command)) {
reset ();
setNext ();
} else if (command.startsWith ("ActionG")) {
String [] bound = command.substring ("ActionG".length ()).split ("\\-");
flipGroup (Integer.parseInt (bound[0]), Integer.parseInt (bound[1]));
} else if (command.startsWith ("Action"))
flipStep (Integer.parseInt (command.substring ("Action".length ())));
else if (e instanceof HTMLFrameHyperlinkEvent) {
HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e;
HTMLDocument doc = (HTMLDocument) editorPane.getDocument ();
doc.processHTMLFrameHyperlinkEvent (evt);
} else {
try {
editorPane.setPage (e.getURL ());
} catch (Throwable t) {
Log.keepLastException ("Guide::hyperlinkUpdate", t);
}
}
}
}
}
// ========================================
public void setVisible (boolean visible) {
reset ();
super.setVisible (visible);
if (visible) {
setNext ();
editorPane.scrollToReference ("Top");
}
}
// ========================================
public void changeHtmlClassAction (String actionName, String className) {
String newPage = editorPane.getText ().
replaceAll ("<div[^>]*name=\"Action("+actionName+")\"[^>]*>",
"<div name=\"Action$1\" class=\""+className.toLowerCase ()+"\">").
replaceAll ("<img[^>]*name=\"Action("+actionName+")\"[^>]*>",
"<img name=\"Action$1\" border=\"0\" src=\"../images/button/"+className+".png\">");
editorPane.setText (newPage);
}
// ========================================
public void reset () {
next = -1;
if (done == null)
return;
for (int step = 0; step < done.length; step++) {
done [step] = false;
if (component [step] != null)
component [step].setBackground (componentBackgroundColor [step]);
}
// XXX pb d'affichage
editorPane.getText ();
try {
Thread.sleep (200);
} catch (InterruptedException e) {
}
changeHtmlClassAction ("(G[0-9]+-)?[0-9]+", "Unknown");
editorPane.scrollToReference ("Top");
}
// ========================================
public void unsetNext () {
if (next < 0)
return;
changeHtmlClassAction (""+next, "Unknown");
if (component [next] != null)
component [next].setBackground (componentBackgroundColor [next]);
next = -1;
}
// ========================================
public void setNext () {
if (next >= 0 && ! done [next])
return;
next = -1;
for (int step = 0; step < done.length; step++)
if (!done [step]) {
next = step;
changeHtmlClassAction (""+next, "Todo");
if (component [next] != null)
component [next].setBackground (highlightColor);
editorPane.scrollToReference ("Action"+next);
return;
}
}
// ========================================
private void stepIsDone (int step) {
done [step] = true;
changeHtmlClassAction (""+step, "Done");
if (component [step] != null)
component [step].setBackground (componentBackgroundColor [step]);
}
// ========================================
private void stepIsUnknown (int step) {
done [step] = false;
changeHtmlClassAction (""+step, "Unknown");
}
// ========================================
public void flipStep (int step) {
unsetNext ();
if (done [step])
stepIsUnknown (step);
else
stepIsDone (step);
checkGroup ();
setNext ();
}
// ========================================
public void flipGroup (int step1, int step2) {
unsetNext ();
boolean allDone = true;
for (int step = step1; step <= step2; step++)
if (!done [step]) {
allDone = false;
break;
}
if (allDone) {
for (int step = step1; step <= step2; step++)
stepIsUnknown (step);
changeHtmlClassAction ("G"+step1+"-"+step2, "Unknown");
} else {
for (int step = step1; step <= step2; step++)
stepIsDone (step);
changeHtmlClassAction ("G"+step1+"-"+step2, "Done");
}
checkGroup ();
setNext ();
}
// ========================================
public void checkGroup () {
String newPage = editorPane.getText ();
Pattern pattern = Pattern.compile ("<img[^>]*name=\"ActionG(([0-9]+)-([0-9]+))\"[^>]*>");
Matcher matcher = pattern.matcher (newPage);
while (matcher.find()) {
int step1 = Integer.parseInt (matcher.group (2));
int step2 = Integer.parseInt (matcher.group (3));
boolean allDone = true;
for (int step = step1; step <= step2; step++)
if (!done [step]) {
allDone = false;
break;
}
changeHtmlClassAction ("G"+step1+"-"+step2, allDone ? "Done" : "Unknown");
}
}
// ========================================
}

View File

@ -0,0 +1,197 @@
package misc;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Vector;
import javax.swing.AbstractButton;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import misc.Bundle;
import misc.Log;
import misc.Util;
/**
Les drapeaux peuvent être trouvé sur http://flags.blogpotato.de/
*/
@SuppressWarnings ("serial") public class HelpManager implements ApplicationManager, ActionListener {
// ========================================
private Frame frame;
private OwnFrame controller;
private String applicationName;
private JConsole jConsole;
// ========================================
static public final String
//actionPackBug = "PackBug",
actionForcePack = "ForcePack",
actionBugReport = "BugReport",
actionJConsole = "JConsole";
static public final List<String> actionsNames =
Arrays.asList ("About", "Licence", "Locale");
static public final List<String> actionsBugNames =
Arrays.asList (/*actionPackBug, */actionForcePack, actionBugReport, actionJConsole);
@SuppressWarnings("unchecked")
static public final Hashtable<String, Method> actionsMethod =
Util.collectMethod (HelpManager.class, actionsNames, actionsBugNames);
public void actionPerformed (ActionEvent e) {
Util.actionPerformed (actionsMethod, e, this);
}
// ========================================
public HelpManager (OwnFrame controller, String applicationName) {
this.controller = controller;
this.applicationName = applicationName;
frame = new Frame ();
frame.setIconImage (controller.getIcon ());
aboutDialog = new HtmlDialog (frame, "About", Config.textsJarDir+"About"+applicationName+Config.htmlExt);
licenceDialog = new HtmlDialog (frame, "Licence", Config.textsJarDir+applicationName+"Licence"+Config.htmlExt);
jConsole = new JConsole (frame);
//Util.packBug = Config.getBoolean (actionPackBug+Config.checkedPostfix, false);
}
// ========================================
private HtmlDialog aboutDialog;
private HtmlDialog licenceDialog;
// ========================================
public void actionAbout () {
aboutDialog.restart ();
aboutDialog.setVisible (true);
}
// ========================================
public void actionLicence () {
licenceDialog.restart ();
licenceDialog.setVisible (true);
}
// ========================================
public void actionLocale () {
actionLocale (controller);
}
static public void actionLocale (OwnFrame controller) {
try {
Locale [] locales = Bundle.getApplicationsLocales ();
JComboBox<String> localesList = Bundle.getJComboFlags (locales);
Locale currentLocale = Bundle.getLocale ();
int currentIndex = 0;
if (currentLocale != null)
for (int i = 0; i < locales.length; i++)
if (currentLocale.equals (locales[i])) {
currentIndex = i;
break;
}
localesList.setSelectedIndex (currentIndex);
JPanel jPanel = new JPanel (new BorderLayout ());
jPanel.add (new JLabel (Bundle.getMessage ("ChooseLocale")), BorderLayout.PAGE_START);
jPanel.add (localesList, BorderLayout.CENTER);
Frame frame = controller != null ? controller.getJFrame () : null;
Frame frmOpt = null;
if (frame == null) {
frmOpt = new JFrame ();
frmOpt.setVisible (true);
frmOpt.setLocationRelativeTo (null);
frmOpt.setAlwaysOnTop (true);
frame = frmOpt;
}
try {
if (JOptionPane.OK_OPTION !=
JOptionPane.showConfirmDialog (frame, jPanel, Bundle.getTitle ("ChangeLocale"),
JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE))
return;
} finally {
if (frmOpt != null)
frmOpt.dispose();
}
Bundle.setLocale (locales[localesList.getSelectedIndex ()]);
Util.packWindow (frame);
} catch (Exception e) {
Log.keepLastException ("HelpManager::actionLocale", e);
}
}
// // ========================================
// public void actionPackBug () {
// Util.packBug = ! Util.packBug;
// Config.setBoolean (actionPackBug+Config.checkedPostfix, Util.packBug);
// ImageIcon icon = Util.loadActionIcon (actionPackBug+(Util.packBug ? "On" : "Off"));
// for (AbstractButton packBugCommand : packBugCommands) {
// packBugCommand<.setSelected (Util.packBug);
// // XXX bug Java
// packBugCommand.setIcon (icon);
// }
// }
// ========================================
public void actionForcePack () {
controller.reborn ();
}
// ========================================
public void actionBugReport () {
Log.dumpSaveDialog (controller.getJFrame ());
}
// ========================================
public void actionJConsole (boolean checked) {
jConsole.setVisible (checked);
Util.updateCheckBox (actionJConsole, checked);
}
// ========================================
// static private Vector<AbstractButton> packBugCommands = new Vector<AbstractButton> ();
// static public void addPackBugCommand (AbstractButton packBugCommand) {
// if (packBugCommand == null)
// return;
// packBugCommands.add (packBugCommand);
// packBugCommand.setSelected (Util.packBug);
// // XXX bug Java
// packBugCommand.setIcon (Util.loadActionIcon (actionPackBug+(Util.packBug ? "On" : "Off")));
// }
// static public void removePackBugCommand (AbstractButton packBugCommand) {
// packBugCommands.remove (packBugCommand);
// }
// ========================================
public void addMenuItem (JMenu... jMenu) {
Util.addMenuItem (actionsNames, this, jMenu[0]);
//Util.addCheckMenuItem (actionPackBug, this, Util.packBug, jMenu[0]);
Util.addMenuItem (actionForcePack, this, jMenu[0]);
Util.addMenuItem (actionBugReport, this, jMenu[0]);
Util.addCheckMenuItem (actionJConsole, this, jMenu[0]);
}
// ========================================
public void addIconButtons (Container... containers) {
Util.addIconButton (actionsNames, this, containers[0]);
//Util.addIconButton (actionPackBug, this, containers[0]);
Util.addIconButton (actionForcePack, this, containers[0]);
Util.addIconButton (actionBugReport, this, containers[0]);
}
// ========================================
public void addActiveButtons (Hashtable<String, AbstractButton> buttons) {
//addPackBugCommand (buttons.get (actionPackBug));
Log.addDumpCommand (buttons.get (actionBugReport));
}
// ========================================
}

View File

@ -0,0 +1,253 @@
// ================================================================================
// Copyright (c) Francois Merciol 2002
// Project : Perso
// Name : HourPanel.java
// Language : Java
// Type : Source file for HourPanel class
// Author : Francois Merciol
// Creation : 02/09/2002
// ================================================================================
// History
// --------------------------------------------------------------------------------
// Author :
// Date :
// Reason :
// ================================================================================
// To be improved :
// ================================================================================
package misc;
import java.awt.Dimension;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JTextField;
/**
Champ de saisie d'une heure au format HH:mm.
Autres fonctions :<ul>
<li> (espace) : éfface le champs
<li> (retoure chariot) ou (perte de "focus") : remet le champ au format.
<li> Le premier caractère frappé éfface le champs. Des caractères peuvent être concervé si le prmier caractère
concerne un déplacement ou un éffacement.
</ul>
*/
@SuppressWarnings ("serial") public class HourPanel extends JTextField implements KeyListener, FocusListener {
// ========================================
/** Format d'une heure. */
static public final SimpleDateFormat hourFormat = new SimpleDateFormat ("HH:mm");
/** Ensemble des caractères ayant une action sur ce champs.
Il faudrais ajouter le retoure chariot et le caractère d'effacement. */
static public final String acceptChar = "0123456789: ";
// ========================================
/** mémorise si le caractère frappé et le premier dans le champs. */
private boolean justFocus = false;
// ========================================
/**
Création d'une date en reservant une taille maximal puis mis à la date actuelle.
*/
public HourPanel () {
super ("23:59");
addKeyListener (this);
addFocusListener (this);
set (new Date ());
}
// ========================================
// api
// ========================================
/**
Remet en forme le champs.
*/
public void enter () {
tuneHour ();
}
// ========================================
/**
Fixe une heure.
@param date la nouvelle valeur.
*/
public void set (Date date) {
setText (hourFormat.format (date));
}
// ========================================
// Listener
// ========================================
/** Dernière possition du curseur. */
int lastJTextPos = -1;
// ========================================
/** Interface KeyListener. */
public void keyPressed (KeyEvent e) {
lastJTextPos = getCaretPosition ();
}
// ========================================
/** Interface KeyListener. */
public void keyReleased (KeyEvent e) {
}
// ========================================
/** Interface KeyListener. */
public void keyTyped (KeyEvent e) {
char c = e.getKeyChar ();
switch (c) {
case KeyEvent.VK_ENTER:
enter ();
return;
case ';':
// le ; sera s<>parateur
e.consume ();
return;
case KeyEvent.VK_BACK_SPACE:
// on laisse java faire
justFocus = false;
return;
case KeyEvent.VK_SPACE:
setText ("");
e.consume ();
return;
}
if (acceptChar.indexOf (c) < 0) {
e.consume ();
return;
}
if (getSelectedText () == null) {
if (justFocus)
setText ("");
if (c != ':' && getText ().length () >= 5) {
e.consume ();
return;
}
} else {
String text = getText ();
lastJTextPos = getSelectionStart ();
setText (text.substring (0, getSelectionStart ())+ text.substring (getSelectionEnd ()));
}
justFocus = false;
processHour (e);
}
// ========================================
/** Interface FocusListener. */
public void focusGained (FocusEvent e) {
justFocus = true;
}
// ========================================
/** Interface FocusListener. */
public void focusLost (FocusEvent e) {
justFocus = false;
tuneHour ();
}
// ========================================
// Listener spécial
// ========================================
/**
Traite l'insertion d'un caractère dur champ (chiffre ou ':').
@param e touche frappé au clavier.
*/
public void processHour (KeyEvent e) {
char c = e.getKeyChar ();
String text = getText ();
int dpPos = text.indexOf (":");
if (dpPos >= 0) {
if (c == ':') {
if (lastJTextPos <= dpPos)
setText (((lastJTextPos == 0) ? "0" : text.substring (0, lastJTextPos))+":"+
text.substring (dpPos+1));
else
setText (text.substring (0, dpPos)+":"+text.substring (lastJTextPos));
setCaretPosition (text.indexOf (":")+1);
e.consume ();
return;
}
} else {
if (c == ':')
return;
// traiter l'apparition du :
if (text.length () < 1)
return;
if (text.charAt (0) > '2') {
// XXX pb si lastJTextPos = 0
setText (text.charAt (0)+":"+text.substring (1));
setCaretPosition (lastJTextPos+1);
return;
}
if (text.length () > 1) {
// XXX pb si lastJTextPos < 2
setText (text.substring (0, 2)+":"+text.substring (2));
setCaretPosition (lastJTextPos+1);
return;
}
}
}
// ========================================
/**
Remise en forme de l'heure.
*/
public void tuneHour () {
try {
String text = getText ().trim ();
if (text.isEmpty ()) {
setText ("00:00");
return;
}
switch (text.indexOf (":")) {
case -1:
text += ":0";
break;
case 0:
text = "0"+text;
}
if (text.indexOf (":") == (text.length ()-1))
text += "0";
setText (hourFormat.format (hourFormat.parse (text)));
getSize (tmpSize);
if (tmpSize.width != 0)
size = tmpSize;
} catch (Exception ex) {
}
}
// ========================================
/** Taille actuelle du champ. */
private Dimension tmpSize = new Dimension ();
/** Derni<6E>re taille maximum utilisée. */
private Dimension size;
// ========================================
/**
@return la taille maximum déjà utilisé.
*/
public Dimension getPreferredSize () {
if (size != null)
return size;
return super.getPreferredSize ();
}
// ========================================
/**
@return la taille maximum déjà utilisé.
*/
public Dimension getMinimumSize () {
if (size != null)
return size;
return super.getPreferredSize ();
}
// ========================================
}

View File

@ -0,0 +1,85 @@
package misc;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Frame;
import java.io.IOException;
import java.net.URL;
import java.text.MessageFormat;
import javax.swing.BorderFactory;
import javax.swing.JEditorPane;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLFrameHyperlinkEvent;
// XXX rechercher le fichier à afficher en fonction de la langue
// XXX mise à jour dynamique en cas de changement de langue
@SuppressWarnings ("serial") public class HtmlDialog extends TitledDialog {
// ========================================
public JEditorPane editorPane;
protected URL startedURL;
// ========================================
public HtmlDialog (Frame frame, String titleName, String fileName) {
super (frame, titleName);
editorPane = new JEditorPane ();
changeFileName (fileName);
editorPane.setBackground (getBackground ());
editorPane.setBorder (BorderFactory.createCompoundBorder (BorderFactory.createRaisedBevelBorder (),
BorderFactory.createEmptyBorder (2, 5, 2, 5)));
editorPane.setEditable (false);
editorPane.setCaretPosition (0);
editorPane.scrollToReference ("Top");
JScrollPane editorScrollPane = new JScrollPane (editorPane);
editorScrollPane.setVerticalScrollBarPolicy (JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
editorScrollPane.setPreferredSize (new Dimension (600, 300));
getContentPane ().add (editorScrollPane, BorderLayout.CENTER);
}
// ========================================
public void changeFileName (String fileName) {
try {
URL newURL = Config.getDataUrl (fileName);
if (newURL.equals (startedURL))
return;
startedURL = newURL;
restart ();
} catch (Exception e) {
}
}
// ========================================
HyperlinkListener hyperlinkListener = new HyperlinkListener () {
public void hyperlinkUpdate (HyperlinkEvent e) {
if (e.getEventType () == HyperlinkEvent.EventType.ACTIVATED) {
if (e instanceof HTMLFrameHyperlinkEvent) {
((HTMLDocument) editorPane.getDocument ()).processHTMLFrameHyperlinkEvent ((HTMLFrameHyperlinkEvent) e);
} else {
try {
editorPane.setPage (e.getURL ());
} catch (Exception ioe) {
System.err.println ("IOE: " + ioe);
}
}
}
}
};
public void restart () {
try {
editorPane.setPage (startedURL);
editorPane.setDragEnabled (true);
editorPane.removeHyperlinkListener (hyperlinkListener);
editorPane.addHyperlinkListener (hyperlinkListener);
} catch (Exception e) {
}
}
// ========================================
}

View File

@ -0,0 +1,89 @@
package misc;
import javax.swing.*;
import java.beans.*;
import java.awt.*;
import java.io.File;
/* ImagePreview.java by FileChooserDemo2.java. */
@SuppressWarnings("serial")
public class ImagePreview extends JComponent
implements PropertyChangeListener {
static public int maxInSide = 90;
static public int border = 5;
static public int maxOutSide = maxInSide+2*border;
protected ImageIcon thumbnail = null;
protected File file = null;
protected long maxSize;
public ImagePreview (JFileChooser fc, long maxSize) {
this.maxSize = maxSize;
setPreferredSize (new Dimension (maxOutSide, maxOutSide));
fc.addPropertyChangeListener (this);
}
public void loadImage () {
if (file == null || (maxSize > 0 && file.length () > maxSize)) {
thumbnail = null;
return;
}
//Don't use createImageIcon (which is a wrapper for getResource)
//because the image we're trying to load is probably not one
//of this program's own resources.
ImageIcon tmpIcon = new ImageIcon (file.getPath ());
if (tmpIcon != null) {
thumbnail = tmpIcon;
if (tmpIcon.getIconWidth () > tmpIcon.getIconHeight ()) {
if (tmpIcon.getIconWidth () > maxInSide)
thumbnail =
new ImageIcon (tmpIcon.getImage ().getScaledInstance (maxInSide, -1, Image.SCALE_DEFAULT));
} else {
if (tmpIcon.getIconHeight () > maxInSide)
thumbnail =
new ImageIcon (tmpIcon.getImage ().getScaledInstance (-1, maxInSide, Image.SCALE_DEFAULT));
}
}
}
public void propertyChange (PropertyChangeEvent e) {
boolean update = false;
String prop = e.getPropertyName ();
//If the directory changed, don't show an image.
if (JFileChooser.DIRECTORY_CHANGED_PROPERTY.equals (prop)) {
file = null;
update = true;
//If a file became selected, find out which one.
} else if (JFileChooser.SELECTED_FILE_CHANGED_PROPERTY.equals (prop)) {
file = (File) e.getNewValue ();
update = true;
}
//Update the preview accordingly.
if (update) {
thumbnail = null;
if (isShowing ()) {
loadImage ();
repaint ();
}
}
}
protected void paintComponent (Graphics g) {
if (thumbnail == null)
loadImage ();
if (thumbnail != null) {
int x = getWidth ()/2 - thumbnail.getIconWidth ()/2;
int y = getHeight ()/2 - thumbnail.getIconHeight ()/2;
if (y < border)
y = border;
if (x < border)
x = border;
thumbnail.paintIcon (this, g, x, y);
}
}
}

View File

@ -0,0 +1,77 @@
package misc;
import java.io.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
@SuppressWarnings ("serial") public class JConsole extends TitledDialog {
// ========================================
private JTextArea textArea = new JTextArea (5, 20);
public static boolean copy = true;
// ========================================
public JConsole (Frame frame) {
super (frame, "JConsole");
textArea.setEditable (false);
setPreferredSize (new Dimension (550, 300));
getContentPane ().add (new JScrollPane (textArea), BorderLayout.CENTER);
getContentPane ().add (Util.newButton ("Clear", new ActionListener () {
public void actionPerformed (ActionEvent evt) {
synchronized (textArea) {
textArea.setText ("");
}
}
}), BorderLayout.SOUTH);
if (copy) {
copyOut (true);
copyOut (false);
}
pack ();
}
// ========================================
public void copyOut (boolean err) {
Thread thread = new Thread () {
public void run () {
for (;;) {
try {
PipedInputStream pin = new PipedInputStream ();
PrintStream out = new PrintStream (new PipedOutputStream (pin), true, "UTF-8");
if (err)
System.setErr (out);
else
System.setOut (out);
BufferedReader in = new BufferedReader (new InputStreamReader (pin));
for (;;) {
String line = in.readLine ();
synchronized (textArea) {
textArea.append (line+"\n");
}
}
} catch (Exception e) {
textArea.append (e.toString());
ByteArrayOutputStream buf = new ByteArrayOutputStream ();
e.printStackTrace (new PrintStream (buf));
textArea.append (buf.toString ());
try {
Thread.sleep (1000);
} catch (InterruptedException e2) {
}
}
}
}
};
thread.setDaemon (true);
thread.start ();
}
// ========================================
public static void main (String[] arg) {
new JConsole (null);
}
// ========================================
}

View File

@ -0,0 +1,237 @@
package misc;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.TreeSet;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableModel;
import static misc.Util.GBC;
import static misc.Util.GBCNL;
import static misc.RemoteUpdate.CheckPeriod;
import static misc.RemoteUpdate.FileDescriptor;
import static misc.RemoteUpdate.FileInfo;
import static misc.RemoteUpdate.TodoFile;
public class JRemoteUpdate implements SwingConstants {
static public String
actionDetails = "Details",
labelFileName = "FileName", labelLocal= "Local", labelRemote = "Remote";
// ========================================
private OwnFrame controller;
RemoteUpdate remoteUpdate;
Runnable actionAfterDownLoad;
JPanel jPanel = Util.getGridBagPanel ();
ArrayList<MirrorInfo> allMirrorInfo;
JFrame jFrame = new JFrame ();
JButton startAction;
// ========================================
public JRemoteUpdate (OwnFrame controller, RemoteUpdate remoteUpdate, Runnable actionAfterDownLoad) {
this.controller = controller;
this.remoteUpdate = remoteUpdate;
this.actionAfterDownLoad = actionAfterDownLoad;
jFrame.setIconImage (controller.getIcon ());
}
public class MirrorInfo {
RemoteUpdate.Mirror mirror;
StateNotifier notifier = new StateNotifier ();
public ProgressState progressState = new ProgressState (notifier, "Progress");
TodoFile transfertAction, cleanAction;
JCheckBox transfertBoutton, cleanBoutton;
JLabel info;
ProgressStatePanel progressStatePanel = new ProgressStatePanel (progressState);
MirrorInfo (RemoteUpdate.Mirror mirror, TodoFile transfertAction) {
this.mirror = mirror;
// XXX check transfertAction in Download|Upload
this.transfertAction = transfertAction;
cleanAction = transfertAction == TodoFile.Download ? TodoFile.LocalRemove : TodoFile.RemoteRemove;
transfertBoutton = Util.addCheckIcon (""+transfertAction, null,
Config.getBoolean (transfertAction+mirror.token+Config.checkedPostfix, false),
jPanel, GBC);
cleanBoutton = Util.addCheckIcon (""+cleanAction, null,
Config.getBoolean (cleanAction+mirror.token+Config.checkedPostfix, false),
jPanel, GBC);
notifier.addUpdateObserver (progressStatePanel, "Progress");
info = new JLabel (mirror.getInfo (mirror.check (transfertAction), transfertAction));
Util.addComponent (info, jPanel, GBC);
Util.addIconButton (actionDetails, new ActionListener () {
public void actionPerformed (ActionEvent e) {
JOptionPane.showMessageDialog (jFrame, getDetails (), Bundle.getTitle (""+actionDetails), JOptionPane.INFORMATION_MESSAGE);
}
}, jPanel);
Util.unBoxButton (jPanel);
Util.addComponent (progressStatePanel, jPanel, GBCNL);
}
public void setConfig () {
Config.setBoolean (transfertAction+mirror.token+Config.checkedPostfix, transfertBoutton.isSelected ());
Config.setBoolean (cleanAction+mirror.token+Config.checkedPostfix, cleanBoutton.isSelected ());
}
public void update () {
(new Thread () {
public void run () {
mirror.update ();
info.setText (mirror.getInfo (mirror.check (transfertAction), transfertAction));
//Util.packWindow (jPanel);
}
}).start ();
}
public JScrollPane getDetails () {
@SuppressWarnings ("serial")
DefaultTableModel dataObjectModel = new DefaultTableModel () {
public Class<?> getColumnClass (int column) {
if (column != 1)
return String.class;
return javax.swing.ImageIcon.class;
}
};
JTable jTableObject = new JTable (dataObjectModel);
jTableObject.getTableHeader ().setReorderingAllowed (true);
jTableObject.setShowVerticalLines (false);
JScrollPane scrollPane = Util.getJScrollPane (jTableObject, true, false);
jTableObject.setFillsViewportHeight (true);
dataObjectModel.setColumnCount (6);
Util.setColumnLabels (jTableObject, new String[] {"FileName", null, "LocalDate", "LocalSize", "RemoteDate", "RemoteSize"});
for (TodoFile action : new TodoFile []{transfertAction, cleanAction})
for (String fileName : mirror.check (action)) {
FileDescriptor fd = mirror.getInfo (fileName);
FileInfo lfi = fd.local, rfi = fd.remote;
dataObjectModel.addRow (new Object [] {fileName, Util.loadActionIcon (""+fd.todo+Util.ON),
FileInfo.getDate (lfi), FileInfo.getSize (lfi),
FileInfo.getDate (rfi), FileInfo.getSize (rfi)});
}
scrollPane.setPreferredSize (new java.awt.Dimension (800, 400));
return scrollPane;
}
public void startAction () {
(new Thread () {
public void run () {
try {
String messagePrefix = transfertAction == TodoFile.Download ? "Download" : "Upload";
if (!(cleanBoutton.isSelected () || transfertBoutton.isSelected ()))
return;
mirror.update ();
TreeSet<String> removed = new TreeSet<String> ();
if (cleanBoutton.isSelected ())
removed = mirror.performe (cleanAction, null);
TreeSet<String> transfered = new TreeSet<String> ();
if (transfertBoutton.isSelected ()) {
transfered = mirror.performe (transfertAction, progressState);
mirror.update ();
info.setText (mirror.getInfo (mirror.check (transfertAction), transfertAction));
}
if (removed.size () == 0 && transfered.size () == 0)
return;
JPanel msgPanel = Util.getGridBagPanel ();
Util.addComponent (new JLabel (MessageFormat.format (Bundle.getMessage (messagePrefix+"Completed"),
transfered.size ())), msgPanel, GBCNL);
if (transfered.size () > 0) {
Util.addLabel (""+transfertAction, LEFT, msgPanel, GBCNL);
Util.addComponent (Util.getJScrollPane (new JList<String> (new Vector<String> (transfered))),
msgPanel, GBCNL);
}
if (removed.size () > 0) {
Util.addLabel ("Remove", LEFT, msgPanel, GBCNL);
Util.addComponent (Util.getJScrollPane (new JList<String> (new Vector<String> (removed))),
msgPanel, GBCNL);
}
JOptionPane.showMessageDialog (jFrame,
msgPanel,
Bundle.getTitle (""+transfertAction), JOptionPane.INFORMATION_MESSAGE);
} finally {
decrThreads ();
}
}
}).start ();
}
};
private int nbThreads;
private boolean isDownload;
private synchronized void resetThreads (int nbThreads, boolean isDownload) {
if (nbThreads < 1)
return;
while (this.nbThreads != 0)
try {
wait ();
} catch (Exception InterruptedException) {
}
this.isDownload = isDownload;
startAction.setEnabled (false);
this.nbThreads = nbThreads;
}
private synchronized void decrThreads () {
nbThreads--;
if (nbThreads != 0)
return;
notifyAll ();
startAction.setEnabled (true);
if (isDownload && actionAfterDownLoad != null)
actionAfterDownLoad.run ();
}
// ========================================
public void dialog (TodoFile action, boolean checkPeriod) {
jPanel.removeAll ();
allMirrorInfo = new ArrayList<MirrorInfo> ();
for (RemoteUpdate.Mirror mirror : remoteUpdate.mirrors)
allMirrorInfo.add (new MirrorInfo (mirror, action));
for (MirrorInfo mirrorInfo : allMirrorInfo)
mirrorInfo.update ();
startAction = Util.addButton (""+action, null, jPanel, GBCNL);
startAction.addActionListener (new ActionListener () {
public void actionPerformed (ActionEvent e) {
(new Thread () {
public void run () {
resetThreads (allMirrorInfo.size (), action == TodoFile.Download);
for (MirrorInfo mirrorInfo : allMirrorInfo)
mirrorInfo.startAction ();
}
}).start ();
}
});
if (checkPeriod) {
JPanel line = Util.getGridBagPanel ();
Util.addLabel ("CheckingPeriod", LEFT, line, GBC);
JComboBox<String> periodChooser = Util.addEnum (CheckPeriod.class, remoteUpdate.currentPeriod (), line, GBCNL);
Util.addComponent (line, jPanel, GBCNL);
if (JOptionPane.showConfirmDialog (jFrame, jPanel, Bundle.getTitle (""+action),
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION)
Config.setString ("CheckPeriod", ""+CheckPeriod.values () [periodChooser.getSelectedIndex ()]);
} else
JOptionPane.showMessageDialog (jFrame, jPanel, Bundle.getTitle (""+action), JOptionPane. QUESTION_MESSAGE);
for (MirrorInfo mirrorInfo : allMirrorInfo)
mirrorInfo.progressState.abort ();
for (MirrorInfo mirrorInfo : allMirrorInfo)
mirrorInfo.setConfig ();
}
public void downloadDialog () {
dialog (TodoFile.Download, true);
}
public void uploadDialog () {
dialog (TodoFile.Upload, false);
}
// ========================================
}

View File

@ -0,0 +1,79 @@
// ================================================================================
// François MERCIOL 2015
// Name : LocalizedUserLabel.java
// Language : Java
// Author : François Merciol
// CopyLeft : Cecil B
// Creation : 2015
// Version : 0.1 (xx/xx/xx)
// ================================================================================
package misc;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Locale;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import static misc.Util.GBC;
import static misc.Util.GBCNL;
public class LocalizedUserLabel {
// ========================================
protected boolean isCustomized;
protected String labelName;
protected String currentLabel;
protected String newLabel;
protected JLabel jLabel;
public String getLabel () { return labelName; }
public String getNewLabel () { return isCustomized ? newLabel : null; }
public String getCurrentLabel () { return currentLabel; }
public JLabel getJLabel () { return jLabel; }
// ========================================
public LocalizedUserLabel (String labelName, boolean isLocalized, boolean admin) {
isCustomized = isLocalized && admin;
this.labelName = labelName;
currentLabel = isLocalized ? Bundle.getUser (labelName) : labelName;
jLabel = new JLabel (currentLabel, SwingConstants.RIGHT);
if (!isCustomized)
return;
jLabel.addMouseListener (new MouseAdapter () {
public void mousePressed (MouseEvent e) {
LocalizedUserLabel.this.mousePressed (e);
}
});
}
// ========================================
public void mousePressed (MouseEvent e) {
if (!isCustomized || !SwingUtilities.isRightMouseButton (e))
return;
Locale locale = Bundle.getLocale ();
ImageIcon flag = Util.loadImageIcon (Config.dataDirname, Config.iconsDirname, Config.flagsDirname,
locale.getCountry ().toLowerCase () + Config.iconsExt);
if (flag != null)
flag.setDescription (locale.toString ());
JLabel jLocal = new JLabel (locale.toString (), flag, SwingConstants.LEFT);
JTextField jValue = new JTextField (newLabel == null ? Bundle.getUser (labelName) : newLabel, 9);
JPanel content = Util.getGridBagPanel ();
Util.addComponent (new JLabel (), content, GBC);
Util.addComponent (jLocal, content, GBCNL);
Util.addComponent (new JLabel (labelName+" : ", SwingConstants.RIGHT), content, GBC);
Util.addComponent (jValue, content, GBCNL);
if (JOptionPane.showConfirmDialog (e.getComponent (), content, Bundle.getTitle ("Localized"),
JOptionPane.YES_NO_OPTION) != JOptionPane.YES_OPTION)
return;
currentLabel = newLabel = jValue.getText ();
jLabel.setText (currentLabel);
}
// ========================================
}

102
src/java/misc/Log.java Normal file
View File

@ -0,0 +1,102 @@
package misc;
import java.awt.Component;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import java.util.Vector;
import javax.swing.AbstractButton;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter;
public class Log {
// ========================================
static private final SimpleDateFormat dateFormat = new SimpleDateFormat ("[yyyy/MM/dd HH:mm:ss] ");
// static private final String separator = System.getProperty ("file.separator");
// static public final String dumpExtension = "log";
static public final boolean debug = true;
// ========================================
static public void writeLog (String serviceName, String message) {
try {
BufferedWriter out = new BufferedWriter
(new FileWriter (Config.getString ("logPath", Config.logSystemDir)+Config.FS+serviceName+Config.logExt, true));
out.write (dateFormat.format (new Date ())+message+"\n");
out.flush ();
out.close ();
} catch (IOException e) {
}
}
// ========================================
static public Hashtable<String, String> lastExceptions = new Hashtable<String, String> ();
static public boolean keepLastException;
// ========================================
static public void keepLastException (String where, Throwable t) {
try {
if (debug)
t.printStackTrace ();
ByteArrayOutputStream baos = new ByteArrayOutputStream ();
PrintWriter printWriter = new PrintWriter (baos);
printWriter.println ("Exception:\nDate: "+dateFormat.format (new Date ())+"\n");
t.printStackTrace (printWriter);
printWriter.flush ();
printWriter.close ();
lastExceptions.put (where, baos.toString ("ISO-8859-1"));
System.err.println ("Exception "+t+" find in "+where+"\nSee log file.");
keepLastException = true;
for (AbstractButton dumpCommand : dumpCommands)
dumpCommand.setEnabled (keepLastException);
} catch (Exception e2) {
}
}
// ========================================
static public void dumpLastException (File file) {
PrintWriter printWriter = null;
try {
printWriter = new PrintWriter (new FileWriter (file));
for (String where : lastExceptions.keySet ())
printWriter.println ("\n\nContext: "+where+"\n"+lastExceptions.get (where));
printWriter.flush ();
} catch (Exception e) {
} finally {
try {
printWriter.close ();
} catch (Exception e) {
}
}
}
// ========================================
static public void dumpSaveDialog (Component component) {
JFileChooser dumpChooser =
new JFileChooser (Config.getString ("dumpDir", Config.logSystemDir));
dumpChooser.setFileFilter (new FileNameExtensionFilter (Bundle.getLabel ("DumpFilter"), Config.logExt));
dumpChooser.setDialogTitle (Bundle.getTitle ("Dump"));
if (dumpChooser.showSaveDialog (component) != JFileChooser.APPROVE_OPTION)
return;
dumpLastException (dumpChooser.getSelectedFile ());
}
// ========================================
static private Vector<AbstractButton> dumpCommands = new Vector<AbstractButton> ();
static public void addDumpCommand (AbstractButton dumpCommand) {
if (dumpCommand == null)
return;
dumpCommands.add (dumpCommand);
dumpCommand.setEnabled (keepLastException);
}
static public void removeDumpCommand (AbstractButton dumpCommand) {
dumpCommands.remove (dumpCommand);
}
// ========================================
}

View File

@ -0,0 +1,318 @@
package misc;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager2;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.TreeSet;
import javax.swing.SwingConstants;
public class MultiToolBarBorderLayout implements LayoutManager2, SwingConstants {
static public final Hashtable<String, Integer> positionStringToInt;
static public final Hashtable<Integer, String> positionIntToString;
static {
positionIntToString = new Hashtable<Integer, String> ();
positionIntToString.put (CENTER, BorderLayout.CENTER);
positionIntToString.put (NORTH, BorderLayout.NORTH);
positionIntToString.put (EAST, BorderLayout.EAST);
positionIntToString.put (SOUTH, BorderLayout.SOUTH);
positionIntToString.put (WEST, BorderLayout.WEST);
positionStringToInt = new Hashtable<String, Integer> ();
for (int key : positionIntToString.keySet ())
positionStringToInt.put (positionIntToString.get (key), key);
}
// ========================================
int hgap;
int vgap;
Container menu;
Hashtable<Component, Integer> positions = new Hashtable<Component, Integer> ();
Component center;
public MultiToolBarBorderLayout () {
this (0, 0);
}
public MultiToolBarBorderLayout (int hgap, int vgap) {
this.hgap = hgap;
this.vgap = vgap;
}
public int getHgap () {
return hgap;
}
public void setHgap (int hgap) {
this.hgap = hgap;
}
public int getVgap () {
return vgap;
}
public void setVgap (int vgap) {
this.vgap = vgap;
}
public void setMenu (Container menu) {
this.menu = menu;
}
private ArrayList<Component> orderedComponents = new ArrayList<Component> ();
public void setLayoutOrderedComponents (ArrayList<Component> orderedComponents) {
if (orderedComponents== null)
return;
this.orderedComponents = orderedComponents;
}
// ========================================
public void addLayoutComponent (Component comp, Object constraints) {
synchronized (comp.getTreeLock ()) {
if ((constraints == null) || (constraints instanceof String))
addLayoutComponent ((String)constraints, comp);
else
throw new IllegalArgumentException ("cannot add to layout: constraint must be a string (or null)");
}
}
@Deprecated
public void addLayoutComponent (String name, Component comp) {
synchronized (comp.getTreeLock ()) {
if (name == null)
name = BorderLayout.CENTER;
Integer position = positionStringToInt.get (name);
if (position == CENTER) {
if (center != null)
// XXX ou erreur
positions.remove (comp);
center = comp;
}
positions.put (comp, position);
}
}
public void removeLayoutComponent (Component comp) {
synchronized (comp.getTreeLock ()) {
positions.remove (comp);
if (center == comp)
center = null;
}
}
public Object getConstraints (Component comp) {
try {
return positionIntToString.get (positions.get (comp));
} catch (Exception e) {
return null;
}
}
// ========================================
public Dimension minimumLayoutSize (Container target) {
return layoutSize (target, true);
}
public Dimension preferredLayoutSize (Container target) {
return layoutSize (target, false);
}
public Dimension maximumLayoutSize (Container target) {
return new Dimension (Integer.MAX_VALUE, Integer.MAX_VALUE);
}
Hashtable<Integer, ArrayList<Component>> getSortedComponents (Container target) {
ArrayList<Component> allComponents = new ArrayList<Component> (orderedComponents);
for (Component c : target.getComponents ())
if (!allComponents.contains (c))
allComponents.add (c);
Hashtable<Integer, ArrayList<Component>> sortedComponents = new Hashtable<Integer, ArrayList<Component>> ();
for (int pos : positionIntToString.keySet ())
sortedComponents.put (pos, new ArrayList<Component> ());
for (Component c : allComponents) {
Integer position = positions.get (c);
if (!c.isVisible () || position == null)
continue;
sortedComponents.get (position).add (c);
}
return sortedComponents;
}
int maxSize (ArrayList<Component> components, boolean isMinimum, boolean isHorizontal) {
int max = 0;
int componentCount = components.size ();
for (int i = 0; i < componentCount; i++) {
Component c = components.get (i);
Dimension d = isMinimum ? c.getMinimumSize () : c.getPreferredSize ();
max = isHorizontal ? Math.max (max, d.width) : Math.max (max, d.height);
}
return max;
}
TreeSet<Integer> getIntermediate (ArrayList<Component> components, boolean isMinimum, boolean isHorizontal, int minSize) {
ArrayList<Integer> sizes = new ArrayList<Integer> ();
int componentCount = components.size ();
for (int i = 0; i < componentCount; i++) {
Component c = components.get (i);
Dimension d = isMinimum ? c.getMinimumSize () : c.getPreferredSize ();
sizes.add (isHorizontal ? d.width : d.height);
}
TreeSet<Integer> result = new TreeSet<Integer> ();
int maxComp = componentCount-1;
for (int i = 0; i < componentCount; i++) {
int size = 0;
for (int j = i; j < maxComp; j++) {
size += sizes.get (j);
if (size > minSize)
result.add (size);
}
maxComp = componentCount;
}
return result;
}
void swapAxes (Dimension d) {
int tmp = d.width;
d.width = d.height;
d.height = tmp;
}
Dimension fill (ArrayList<Component> components, boolean isMinimum, boolean isHorizontal, int maxWidth) {
int componentCount = components.size ();
int x = 0, y = 0, maxX = 0, rowHeight = 0;
for (int i = 0; i < componentCount; i++) {
Component c = components.get (i);
Dimension d = isMinimum ? c.getMinimumSize () : c.getPreferredSize ();
if (!isHorizontal)
swapAxes (d);
if (x == 0 || x + d.width <= maxWidth) {
if (x > 0)
x += isHorizontal ? hgap : vgap;
x += d.width;
rowHeight = Math.max (rowHeight, d.height);
continue;
}
maxX = Math.max (maxX, x);
x = d.width;
y += (isHorizontal ? vgap : hgap) + rowHeight;
rowHeight = d.height;
}
Dimension result = new Dimension (Math.max (maxX, x), y+rowHeight);
// !!! if !isHorizontal : width => main axes
return result;
}
Dimension getExtra (Hashtable<Integer, ArrayList<Component>> sortedComponents,
int northPos, int southPos, boolean isMinimum, boolean isHorizontal,
int menuWidth, int extraCenter) {
int minWidth = Util.max (maxSize (sortedComponents.get (CENTER), isMinimum, isHorizontal)+extraCenter,
menuWidth,
maxSize (sortedComponents.get (northPos), isMinimum, isHorizontal),
maxSize (sortedComponents.get (southPos), isMinimum, isHorizontal));
TreeSet<Integer> sizes = new TreeSet<Integer> ();
sizes.add (minWidth);
sizes.addAll (getIntermediate (sortedComponents.get (northPos), isMinimum, isHorizontal, minWidth));
sizes.addAll (getIntermediate (sortedComponents.get (southPos), isMinimum, isHorizontal, minWidth));
int minSurface = Integer.MAX_VALUE;
int extraHeight = 0;
for (int size : sizes) {
Dimension northDim = fill (sortedComponents.get (northPos), isMinimum, isHorizontal, size);
Dimension southDim = fill (sortedComponents.get (southPos), isMinimum, isHorizontal, size);
int width = Util.max (size, northDim.width, southDim.width);
int height = northDim.height+southDim.height;
int surface = height*width;
if (surface < minSurface) {
minSurface = surface;
minWidth = width;
extraHeight = height;
}
}
Dimension result = new Dimension (minWidth, extraHeight);
if (!isHorizontal)
swapAxes (result);
return result;
}
Dimension layoutSize (Container target, boolean isMinimum) {
synchronized (target.getTreeLock ()) {
Hashtable<Integer, ArrayList<Component>> sortedComponents = getSortedComponents (target);
Dimension extraSide = getExtra (sortedComponents, WEST, EAST, isMinimum, false, 0, 0);
int menuWidth = menu == null ? 0 : (isMinimum ? menu.getMinimumSize () : menu.getPreferredSize ()).width;
Dimension extra = getExtra (sortedComponents, NORTH, SOUTH, isMinimum, true, menuWidth, extraSide.width);
Insets insets = target.getInsets ();
return new Dimension (extra.width+insets.left+insets.right,
extraSide.height+extra.height+insets.top+insets.bottom);
}
}
public float getLayoutAlignmentX (Container parent) {
return 0.5f;
}
public float getLayoutAlignmentY (Container parent) {
return 0.5f;
}
// ========================================
public void invalidateLayout (Container target) {
}
public void layoutContainer (Container target) {
synchronized (target.getTreeLock ()) {
Hashtable<Integer, ArrayList<Component>> sortedComponents = getSortedComponents (target);
Insets insets = target.getInsets ();
int top = insets.top;
int bottom = target.getHeight () - insets.bottom;
int left = insets.left;
int right = target.getWidth () - insets.right;
int maxWidth = right-left;
top += setComponents (target, sortedComponents.get (NORTH), insets.top, insets.left, true, maxWidth);
bottom -= setComponents (target, sortedComponents.get (SOUTH), insets.top, insets.left, true, maxWidth);
moveComponents (sortedComponents.get (SOUTH), 0, bottom-insets.top);
int maxHeight = bottom-top;
left += setComponents (target, sortedComponents.get (WEST), top, insets.left, false, maxHeight);
right -= setComponents (target, sortedComponents.get (EAST), top, insets.left, false, maxHeight);
moveComponents (sortedComponents.get (EAST), right-insets.left, 0);
if (center != null && center.isVisible ())
center.setBounds (left, top, right - left, bottom - top);
target.repaint ();
}
}
private void moveComponents (ArrayList<Component> components, int dx, int dy) {
int componentCount = components.size ();
for (int i = 0; i < componentCount; i++) {
Component c = components.get (i);
c.setLocation (c.getX ()+dx, c.getY ()+dy);
}
}
private int setComponents (Container target, ArrayList<Component> components, int top, int left, boolean isHorizontal, int maxWidth) {
int x = 0, y = 0, rowHeight = 0, rowStart = 0;
int componentCount = components.size ();
for (int i = 0; i < componentCount; i++) {
Component c = components.get (i);
Dimension d = c.getPreferredSize ();
c.setSize (d.width, d.height);
if (!isHorizontal)
swapAxes (d);
if (x == 0 || x + d.width <= maxWidth) {
if (x > 0)
x += isHorizontal ? hgap : vgap;
x += d.width;
rowHeight = Math.max (rowHeight, d.height);
continue;
}
setComponents (target, left, top, components, rowStart, i, isHorizontal, y, rowHeight);
x = d.width;
y += (isHorizontal ? vgap : hgap) + rowHeight;
rowHeight = d.height;
rowStart = i;
}
setComponents (target, left, top, components, rowStart, componentCount, isHorizontal, y, rowHeight);
return y+rowHeight;
}
private void setComponents (Container target, int x, int y,
ArrayList<Component> components, int rowStart, int rowEnd,
boolean isHorizontal, int delta, int maxSize) {
for (int i = rowStart; i < rowEnd; i++) {
Component c = components.get (i);
if (isHorizontal) {
int cy = y + delta + (maxSize - c.getHeight ())/2;
c.setLocation (x, cy);
x += c.getWidth () + hgap;
} else {
int cx = x + delta + (maxSize - c.getWidth ())/2;
c.setLocation (cx, y);
y += c.getHeight () + vgap;
}
}
}
// ========================================
public String toString () {
return getClass ().getName () + "[hgap=" + hgap + ",vgap=" + vgap + "]";
}
}

View File

@ -0,0 +1,11 @@
package misc;
import java.awt.Image;
import javax.swing.JFrame;
public interface OwnFrame {
public JFrame getJFrame ();
public String getTitle ();
public Image getIcon ();
public void reborn ();
}

165
src/java/misc/Plugins.java Normal file
View File

@ -0,0 +1,165 @@
package misc;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Vector;
import javax.swing.ImageIcon;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class Plugins {
// ========================================
static public URL getDataUrl (String name) {
try {
File file = (new File (name));
if (file.exists ()) {
URL result = file.toURI ().toURL ();
return result;
}
} catch (Exception e) {
}
try {
URL result = ClassLoader.getSystemResource (name);
return result;
} catch (Exception e) {
}
return null;
}
// ========================================
static public ImageIcon loadImageIcon (String name) {
URL url = getDataUrl ("data/images/button/"+name+".png");
return (url != null) ? new ImageIcon (url) : null;
}
// ========================================
// Change Util.version too !
static public final Long version = 20171101L;
static public final String[] stateLabel = {"not found", "old version", "updated"};
static public final ImageIcon[] stateIcon = { loadImageIcon ("Bad"), loadImageIcon ("Warning"), loadImageIcon ("Good")};
static public class PluginInfo {
public String name;
public String url;
public boolean mandatory, loaded, update;
public PluginInfo (String name, String url, boolean mandatory) {
this.name = name;
this.url = url;
this.mandatory = mandatory;
}
};
static ArrayList<PluginInfo> pluginsInfo = new ArrayList<PluginInfo> ();
// ========================================
@SuppressWarnings ("rawtypes")
static public void check (String name, String url, String className, boolean mandatory, Long dateNeed) {
PluginInfo pluginInfo = new PluginInfo (name, url, mandatory);
pluginsInfo.add (pluginInfo);
try {
Class plugin = ClassLoader.getSystemClassLoader ().loadClass (className);
pluginInfo.loaded = true;
pluginInfo.update =
dateNeed == null ||
dateNeed <= (Long) plugin.getDeclaredField ("version").get (null);
} catch (Exception e) {
}
}
// ========================================
@SuppressWarnings ("serial")
static public class ImageCellRenderer extends JLabel implements TableCellRenderer {
public Component getTableCellRendererComponent (JTable jTable, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof ImageIcon) {
setIcon ((ImageIcon) value);
setText (null);
} else {
setIcon (null);
setText ((String) value);
}
return this;
}
}
// ========================================
static public JDialog jDialog;
static public boolean warning = false;
static public void showSate () {
Vector<Vector<Object>> data = new Vector<Vector<Object>> ();
boolean ready = true;
for (PluginInfo pluginInfo : pluginsInfo) {
ready &= !pluginInfo.mandatory || pluginInfo.loaded;
int state = (pluginInfo.loaded ? (pluginInfo.update ? 2 : 1) : 0);
if (state != 2)
warning = true;
data.add
(new Vector<Object>
(Arrays.asList (pluginInfo.name, stateIcon[state], stateLabel[state], (pluginInfo.update ? "" : pluginInfo.url) )));
}
Vector<String> columnNames = new Vector<String> (Arrays.asList ("Plugin name", "", "State", "URL"));
@SuppressWarnings ("serial")
JTable table = new JTable (data, columnNames) {
public Component prepareRenderer (final TableCellRenderer renderer, final int row, final int column) {
final Component prepareRenderer = super.prepareRenderer (renderer, row, column);
final TableColumn tableColumn = getColumnModel ().getColumn (column);
int width = Math.max (prepareRenderer.getPreferredSize ().width, tableColumn.getPreferredWidth ());
tableColumn.setPreferredWidth (width);
return prepareRenderer;
}
};
table.setDefaultRenderer (Object.class, new ImageCellRenderer ());
final TableCellRenderer renderer = table.getTableHeader ().getDefaultRenderer ();
for (int i = 0; i < table.getColumnCount (); ++i) {
int width = renderer.getTableCellRendererComponent (table, table.getModel ().getColumnName (i), false, false, 0, i).getPreferredSize ().width;
TableColumn tableColumn = table.getColumnModel ().getColumn (i);
tableColumn.setPreferredWidth (width);
}
JPanel container = new JPanel ();
container.setLayout (new BorderLayout());
container.add (table.getTableHeader(), BorderLayout.PAGE_START);
container.add (table, BorderLayout.CENTER);
if (!ready) {
Dimension containerSize = container.getSize ();
containerSize.width = Math.max (containerSize.width, 600);
containerSize.height = Math.max (containerSize.height, 100);
container.setPreferredSize (containerSize);
container.add (new JLabel ("Would you like to continue?"), BorderLayout.PAGE_END);
if (JOptionPane.YES_OPTION !=
JOptionPane.showConfirmDialog (null, container, " Can't load plugins ", JOptionPane.YES_NO_OPTION))
System.exit (1);
return;
}
jDialog = new JDialog ((java.awt.Frame)null, " Plugins state ", false);
jDialog.getContentPane ().add (container, BorderLayout.CENTER);
jDialog.setVisible (true);
jDialog.pack ();
jDialog.setLocationRelativeTo (null);
jDialog.toFront ();
}
static public void hideSate () {
if (jDialog == null)
return;
jDialog.pack ();
//jDialog.toFront ();
if (!warning)
jDialog.setVisible (false);
}
// ========================================
}

View File

@ -0,0 +1,67 @@
package misc;
import java.util.HashSet;
public class ProgressState {
// ========================================
HashSet<Thread> workingThreads = new HashSet<Thread> ();
StateNotifier observable;
String valueName;
static public enum State {Init, Value, End};
public State state;
public String domain;
public int value;
public int maxValue;
// ========================================
public ProgressState (StateNotifier observable, String valueName) {
this.observable = observable;
this.valueName = valueName;
}
// ========================================
public synchronized void init (String domain, int maxValue) {
this.domain = domain;
this.value = 0;
this.maxValue = maxValue;
state = State.Init;
workingThreads = new HashSet<Thread> ();
workingThreads.add (Thread.currentThread ());
observable.broadcastUpdate (valueName);
}
public synchronized void addThread (Thread thread) {
// XXX test ! State.end
workingThreads.add (thread);
}
// ========================================
public synchronized void abort () {
workingThreads.clear ();
}
// ========================================
public synchronized boolean isInterrupted () {
return !workingThreads.contains (Thread.currentThread ());
}
// ========================================
public synchronized boolean setValue (int value) {
this.value = value;
state = State.Value;
observable.broadcastUpdate (valueName);
return workingThreads.contains (Thread.currentThread ());
}
// ========================================
public synchronized boolean addValue (int delta) {
if (delta > 0) {
value += delta;
state = State.Value;
observable.broadcastUpdate (valueName);
}
return workingThreads.contains (Thread.currentThread ());
}
// ========================================
public synchronized void end () {
state = State.End;
observable.broadcastUpdate (valueName);
}
// ========================================
}

View File

@ -0,0 +1,78 @@
// ================================================================================
// Copyright (c) Francois Merciol 2002
// Project : Classe
// Name : DatePanel.java
// Language : Java
// Type : Source file for DatePanel class
// Author : Francois Merciol
// Creation : 02/09/2002
// ================================================================================
// History
// --------------------------------------------------------------------------------
// Author :
// Date :
// Reason :
// ================================================================================
// To be improved :
// ================================================================================
package misc;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
@SuppressWarnings ("serial") public class ProgressStatePanel extends JPanel implements ActionListener {
// ========================================
JProgressBar jProgressBar = new JProgressBar ();
JButton stopButton = new JButton (Util.loadActionIcon ("Abort"));
ProgressState progressState;
// ========================================
public ProgressStatePanel (ProgressState progressState) {
this.progressState = progressState;
jProgressBar.setMaximum (1);
jProgressBar.setString ("");
jProgressBar.setStringPainted (true);
jProgressBar.setAlignmentX (Component.LEFT_ALIGNMENT);
setLayout (new BorderLayout ());
add (jProgressBar, BorderLayout.CENTER);
stopButton.setActionCommand ("Abort");
stopButton.addActionListener (this);
stopButton.setEnabled (false);
add (stopButton, BorderLayout.LINE_END);
}
public void actionPerformed (ActionEvent e) {
if (e.getSource () != stopButton)
return;
progressState.abort ();
}
// ========================================
public void updateProgress () {
switch (progressState.state) {
case Value:
jProgressBar.setValue (progressState.value);
break;
case Init:
jProgressBar.setString (progressState.domain);
jProgressBar.setValue (progressState.value);
jProgressBar.setMaximum (progressState.maxValue);
stopButton.setEnabled (true);
break;
case End:
jProgressBar.setString ("");
jProgressBar.setValue (0);
stopButton.setEnabled (false);
break;
}
}
// ========================================
}

View File

@ -0,0 +1,110 @@
package misc;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import static misc.Util.GBCNL;
@SuppressWarnings ("serial")
public class ProxyManager implements ApplicationManager, ActionListener {
static public final String
actionSetProxy = "SetProxy",
actionNoProxy = "NoProxy",
actionSystemConfigProxy = "SystemConfigProxy",
actionManualConfigProxy = "ManualConfigProxy";
static public final List<String> radioButtonNames = Arrays.asList (actionNoProxy, actionSystemConfigProxy, actionManualConfigProxy);
static public final List<String> actionsNames = Arrays.asList (actionSetProxy);
@SuppressWarnings("unchecked")
static public final Hashtable<String, Method> actionsMethod =
Util.collectMethod (ProxyManager.class, actionsNames, radioButtonNames);
public void actionPerformed (ActionEvent e) {
Util.actionPerformed (actionsMethod, e, this);
}
// ========================================
public void addMenuItem (JMenu... jMenu) {
Util.addMenuItem (actionsNames, this, jMenu[0]);
}
public void addIconButtons (Container... containers) {
Util.addIconButton (actionsNames, this, containers[0]);
}
public void addActiveButtons (Hashtable<String, AbstractButton> buttons) {
// disable if no network ?
}
JPanel manualPanel;
private String getConfig () {
if ("true".equals (System.getProperty ("java.net.useSystemProxies")))
return actionSystemConfigProxy;
String host = System.getProperty ("http.proxyHost");
String port = System.getProperty ("http.proxyPort");
if (host == null || port == null || host.isEmpty () || port.isEmpty ())
return actionNoProxy;
return actionManualConfigProxy;
}
public void actionSetProxy () {
JFrame jFrame = new JFrame ();
jFrame.setIconImage (controller.getIcon ());
JPanel msgPanel = Util.getGridBagPanel ();
String proxyConfig = getConfig ();
ButtonGroup group = new ButtonGroup ();
Util.addRadioButton (actionNoProxy, this, group, proxyConfig, msgPanel, GBCNL);
Util.addRadioButton (actionSystemConfigProxy, this, group, proxyConfig, msgPanel, GBCNL);
Util.addRadioButton (actionManualConfigProxy, this, group, proxyConfig, msgPanel, GBCNL);
manualPanel = Util.getGridBagPanel ();
JTextField hostTF = new JTextField (Config.getString ("ProxyHostName", "squid"), 18);
JTextField portTF = new JTextField (Config.getString ("ProxyPort", "3128"), 6);
// System.setProperty("http.proxyUser", "user");
// System.setProperty("http.proxyPassword", "password");
Util.addLabelFields (manualPanel, "Host", hostTF);
Util.addLabelFields (manualPanel, "Port", portTF);
Util.addComponent (manualPanel, msgPanel, GBCNL);
Util.setEnabled (manualPanel, proxyConfig.equals (actionManualConfigProxy));
if (JOptionPane.showConfirmDialog (jFrame, msgPanel, misc.Bundle.getTitle ("Proxy"), JOptionPane.YES_NO_OPTION)
!= JOptionPane.YES_OPTION)
return;
Config.setString ("ProxyHostName", hostTF.getText ());
Config.setString ("ProxyPort", portTF.getText ());
proxyConfig = group.getSelection ().getActionCommand ();
if (actionSystemConfigProxy.equals (proxyConfig)) {
System.setProperty ("java.net.useSystemProxies", "true");
System.setProperty ("http.proxyHost", "");
} else {
System.setProperty ("java.net.useSystemProxies", "false");
if (actionNoProxy.equals (proxyConfig))
System.setProperty ("http.proxyHost", "");
else if (actionManualConfigProxy.equals (proxyConfig)) {
System.setProperty ("http.proxyHost", hostTF.getText ());
System.setProperty ("http.proxyPort", portTF.getText ());
}
}
java.net.ProxySelector.setDefault (java.net.ProxySelector.getDefault ());
}
public void actionNoProxy () {
Util.setEnabled (manualPanel, false);
}
public void actionSystemConfigProxy () {
Util.setEnabled (manualPanel, false);
}
public void actionManualConfigProxy () {
Util.setEnabled (manualPanel, true);
}
// ========================================
private OwnFrame controller;
public ProxyManager (OwnFrame controller) {
this.controller = controller;
}
// ========================================
}

View File

@ -0,0 +1,73 @@
package misc;
@SuppressWarnings ("serial")
class NewChalenger extends RuntimeException {
public NewChalenger () {
super ("NewChalenger");
}
}
public class RealTime {
// ========================================
private int nbChalengers;
private Thread leadership;
public void start (Runnable task) {
(new Thread () {
public void run () {
if (!getLeadership ())
return;
try {
task.run ();
} catch (NewChalenger e) {
} finally {
loseLeaderShip ();
}
}
}).start ();
}
// ========================================
public synchronized void waitTerminaison () {
if (leadership == Thread.currentThread ())
return;
while (leadership != null && nbChalengers > 0)
try {
wait ();
} catch (InterruptedException e) {
}
}
// ========================================
public synchronized boolean getLeadership () {
if (leadership != null) {
nbChalengers++;
try {
wait ();
} catch (InterruptedException e) {
}
nbChalengers--;
if (nbChalengers != 0) {
notifyAll ();
return false;
}
}
leadership = Thread.currentThread ();
return true;
}
public synchronized void loseLeaderShip () {
leadership = null;
notifyAll ();
}
public synchronized void checkChalengers () {
if (nbChalengers != 0)
throw new NewChalenger ();
}
// ========================================
static public void checkChalengers (RealTime realTime) {
if (realTime != null)
realTime.checkChalengers ();
}
// ========================================
}

View File

@ -0,0 +1,748 @@
package misc;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.TimeZone;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
public class RemoteUpdate {
// ========================================
static long delay = 2000;
static CookieManager cookieManager = new CookieManager();
static {
try {
((CookieManager) CookieHandler.getDefault ()).setCookiePolicy (CookiePolicy.ACCEPT_ALL);
} catch (Exception e) {
cookieManager.setCookiePolicy (CookiePolicy.ACCEPT_ALL);
CookieHandler.setDefault (cookieManager);
}
}
// ========================================
static public final String backExtention = "back";
static public final int bufSize = 1024*1024;
static public final SimpleDateFormat dateFormat = new SimpleDateFormat ("yyyyMMdd");
static public final SimpleDateFormat timeFormat = new SimpleDateFormat ("yyyyMMddHHmmss");
static public final SimpleDateFormat displayFormat = new SimpleDateFormat ("dd/MM/yyyy HH:mm:ss");
static public final NumberFormat numberFormat = NumberFormat.getInstance ();
static public enum CheckPeriod { NoCheck, Day, Week, Month, Year; };
static public final List<String> excludeFileName = Arrays.asList ("timestamp");
static public enum TodoFile {LocalRemove, Download, NoChange, Upload, RemoteRemove};
static public class FileInfo {
long date, size;
public FileInfo (long date, long size) { this.date = date; this.size = size; }
public String toString () { return "{"+displayFormat.format (new Date (date))+" "+size+"}"; }
static public String getDate (FileInfo fileInfo) { return fileInfo == null ? "" : displayFormat.format (fileInfo.date); }
static public String getSize (FileInfo fileInfo) { return fileInfo == null ? "" : ""+fileInfo.size; }
};
static public FilenameFilter mirrorFilter = new FilenameFilter () {
public boolean accept (File dir, String name) {
return ! (excludeFileName.contains (name) || name.endsWith ("."+backExtention) || name.endsWith (".new"));
}
};
// ========================================
static public class FileDescriptor {
// ----------------------------------------
public TodoFile todo = TodoFile.NoChange;
public FileInfo local, remote;
public String toString () { return ""+todo+" "+local+" "+remote; }
// ----------------------------------------
public void updateTodo (TodoFile action) {
todo = TodoFile.NoChange;
if (remote == null) {
switch (action) {
case LocalRemove:
case Upload:
todo = action;
case Download:
break;
case NoChange:
case RemoteRemove:
break;
}
return;
}
if (local == null) {
switch (action) {
case RemoteRemove:
case Download:
todo = action;
case LocalRemove:
break;
case NoChange:
case Upload:
break;
}
return;
}
if (local.size != remote.size) {
switch (action) {
case LocalRemove:
todo = TodoFile.Download;
break;
case RemoteRemove:
todo = TodoFile.Upload;
break;
default:
todo = action;
}
return;
}
if (local.date+delay < remote.date) {
if (action == TodoFile.Download || action == TodoFile.LocalRemove)
todo = TodoFile.Download;
return;
}
if (local.date > remote.date+delay) {
if (action == TodoFile.Upload || action == TodoFile.RemoteRemove)
todo = TodoFile.Upload;
//System.err.print (" "+local.date+" "+remote.date+" "+action);
return;
}
}
// ----------------------------------------
};
// ========================================
public class Mirror {
String token;
File localRepository;
FilenameFilter mirrorFilter = RemoteUpdate.mirrorFilter;
TreeSet<String> excludeFiles;
TreeMap<String, FileInfo> localFiles, remoteFiles;
TreeMap<String, FileDescriptor> allFiles;
// ----------------------------------------
public Mirror (File root, String... params) {
token = params[0];
if (params.length > 1) {
localRepository = root;
for (int i = 1; i < params.length; i++)
localRepository = new File (localRepository, params[i]);
} else
localRepository = new File (root, token);
}
public String toString () { return token+": "+localFiles+" "+remoteFiles; }
public synchronized void update () {
updateRemoteFiles ();
updateLocalFiles ();
if (remoteFiles == null)
return;
TreeSet<String> allFilesName = new TreeSet<String> ();
allFilesName.addAll (localFiles.keySet ());
allFilesName.addAll (remoteFiles.keySet ());
allFiles = new TreeMap<String, FileDescriptor> ();
for (String fileName : allFilesName)
allFiles.put (fileName, new FileDescriptor ());
for (String fileName : localFiles.keySet ())
allFiles.get (fileName).local = localFiles.get (fileName);
for (String fileName : remoteFiles.keySet ())
allFiles.get (fileName).remote = remoteFiles.get (fileName);
}
public void updateTodo (TodoFile action) {
if (allFiles == null)
return;
for (String fileName : allFiles.keySet ()) {
//System.err.print ("coucou : "+fileName+" ");
allFiles.get (fileName).updateTodo (action);
//System.err.println ();
}
}
public long getSize (TreeSet<String> filesName, TodoFile action) {
long result = 0;
if (allFiles == null || action == TodoFile.NoChange)
return result;
boolean remote = false;
switch (action) {
case LocalRemove:
case Download:
remote = true;
case NoChange:
break;
case RemoteRemove:
case Upload:
break;
}
for (String fileName : filesName) {
FileDescriptor file = allFiles.get (fileName);
if (file == null)
continue;
try {
if (file.todo == action)
result += remote ? file.remote.size : file.local.size;
} catch (Exception e) {
}
}
return result;
}
public TreeSet<String> getFileAction (TodoFile action) {
TreeSet<String> result = new TreeSet<String> ();
if (allFiles == null)
return result;
for (String fileName : allFiles.keySet ())
if (allFiles.get (fileName).todo == action)
result.add (fileName);
return result;
}
public synchronized boolean hasNewVersion () {
update ();
return check (TodoFile.Download).size () > 0;
}
public synchronized TreeSet<String> check (TodoFile action) {
updateTodo (action);
return getFileAction (action);
}
public TreeSet<String> performe (TodoFile action, ProgressState progressState) {
try {
TreeSet<String> files = check (action);
if (progressState != null)
progressState.init (Bundle.getMessage (""+action), (int) getSize (files, action));
switch (action) {
case LocalRemove:
return localRemove (this, files, progressState);
case RemoteRemove:
return remoteRemove (this, files, progressState);
case Download:
return getRemoteFiles (this, files, progressState);
case Upload:
return putRemoteFiles (this, files, progressState);
case NoChange:
break;
}
} finally {
if (progressState != null)
progressState.end ();
}
return new TreeSet<String> ();
}
public String getInfo (TreeSet<String> files, TodoFile action) {
return MessageFormat.format (Bundle.getMessage ("DownloadInfo"),
Bundle.getLabel (Util.toCapital (token)),
allFiles == null ? 0 : 1, files.size (), Util.toNumIn2Units (getSize (files, action)));
}
public FileDescriptor getInfo (String fileName) {
return allFiles.get (fileName);
}
// ----------------------------------------
private void updateLocalFiles () {
excludeFiles = new TreeSet<String> ();
localFiles = new TreeMap<String, FileInfo> ();
updateLocalFiles (localRepository, token);
}
private void updateLocalFiles (File localRepository, String name) {
if (localRepository.isFile ()) {
if (excludeFileName.contains (name) || name.endsWith ("."+backExtention)) {
excludeFiles.add (name);
return;
}
localFiles.put (name, new FileInfo (localRepository.lastModified (), localRepository.length ()));
return;
}
if (!localRepository.isDirectory ())
return;
for (String child : localRepository.list ()) {
updateLocalFiles (new File (localRepository, child), name+"/"+child);
}
}
private void getExcludeFiles (File localRepository, String name) {
if (localRepository.isFile ()) {
localFiles.put (name, new FileInfo (localRepository.lastModified (), localRepository.length ()));
return;
}
if (!localRepository.isDirectory ())
return;
for (String child : localRepository.list (mirrorFilter)) {
if (excludeFileName.contains (child))
continue;
updateLocalFiles (new File (localRepository, child), name+"/"+child);
}
}
// ----------------------------------------
private void updateRemoteFiles () {
try {
allFiles = null;
remoteFiles = null;
URLConnection urlConnection = getUrlConnection ("zipList", token);
urlConnection.connect ();
remoteFiles = new TreeMap<String, FileInfo> ();
receiveZip (urlConnection, new ZipLineReader () {
public void readLine (String line) {
ParsePosition pos = new ParsePosition (0);
try {
long date = timeFormat.parse (line, pos).getTime ();
pos.setIndex (pos.getIndex ()+1);
long size = numberFormat.parse (line, pos).longValue ();
String fileName = line.substring (pos.getIndex ()+1);
remoteFiles.put (fileName, new FileInfo (date, size));
} catch (Exception e) {
}
}}, token);
} catch (Exception e) {
System.err.println (e);
//e.printStackTrace ();
}
}
// ----------------------------------------
};
// ========================================
public String protocol;
public String serverName;
public String versionName;
public String requestModel;
public Mirror[] mirrors;
public RemoteUpdate (String protocol, String serverName, String versionName, String requestModel, String []... mirrorsParams) {
this.protocol = protocol;
this.serverName = serverName;
this.versionName = versionName;
this.requestModel = requestModel;
File root = Config.getPWD ().getParentFile ();
this.mirrors = new Mirror[mirrorsParams.length];
int idx = 0;
for (String [] params : mirrorsParams)
mirrors[idx++] = new Mirror (root, params);
}
public CheckPeriod currentPeriod () {
return CheckPeriod.valueOf (CheckPeriod.class, Config.getString ("CheckPeriod", ""+CheckPeriod.Month));
}
public boolean hasNewVersion () {
CheckPeriod period = currentPeriod ();
Date lastCheck = new Date ();
try {
lastCheck = dateFormat.parse (Config.getString ("LastCheck", "20150401"));
} catch (Exception e) {
}
Date today = new Date ();
long age = (today.getTime ()-lastCheck.getTime ())/(24*60*60*1000);
switch (period) {
case NoCheck:
return false;
case Day:
if (age < 1)
return false;
break;
case Week:
if (age < 7)
return false;
break;
case Month:
if (age < 31)
return false;
break;
case Year:
if (age < 366)
return false;
break;
}
Config.setString ("LastCheck", dateFormat.format (today));
for (Mirror mirror : mirrors)
if (mirror.hasNewVersion ())
return true;
return false;
}
// ========================================
private URLConnection getUrlConnection (String cmd, String arg)
throws IOException {
return getUrlConnection (MessageFormat.format (requestModel, versionName, cmd, arg));
}
private URLConnection getUrlConnection (String uri)
throws IOException {
URL url = new URL (protocol+"://"+serverName+uri);
URLConnection urlConnection = url.openConnection ();
urlConnection.setRequestProperty ("User-Agent", "Adecwatt Agent");
urlConnection.setUseCaches (true);
return urlConnection;
}
static private Random random = new Random ();
static private final String charset = "UTF-8";
static private final String LINE_FEED = "\r\n";
static public String getBoundary () {
// XXX we must check not apears in message :-(
return "=-="+Long.toString (random.nextLong (), 36).toUpperCase ()+"=-=";
}
// ========================================
public abstract class ZipBuilder {
public abstract void writeEntry (String token, ZipOutputStream zipOut) throws IOException;
};
public class TextZipBuilder extends ZipBuilder {
private TreeSet<String> filesName;
public TextZipBuilder (TreeSet<String> filesName) { this.filesName = filesName; }
public void writeEntry (String token, ZipOutputStream zipOut) throws IOException {
ZipEntry zipOutEntry = new ZipEntry (token);
zipOut.putNextEntry (zipOutEntry);
PrintWriter entryWriter = new PrintWriter (new OutputStreamWriter (zipOut));
for (String fileName : filesName)
entryWriter.print (fileName+"\n");
entryWriter.flush ();
zipOut.closeEntry ();
}
};
public abstract class ZipFileReader {
public abstract boolean readEntry (ZipInputStream zipIn, String entryName, String token) throws IOException;
};
public abstract class ZipLineReader extends ZipFileReader {
public boolean readEntry (ZipInputStream zipIn, String entryName, String token) throws IOException {
if (! entryName.equals (token))
return true;
BufferedReader in = new BufferedReader (new InputStreamReader (zipIn));
for (;;) {
String line = in.readLine ();
if (line == null)
break;
if ("".equals (line))
continue;
readLine (line);
}
return false;
}
public abstract void readLine (String line);
};
// ========================================
public void receiveZip (URLConnection urlConnection, ZipFileReader zipFileReader, String token) {
try {
String contentType = urlConnection.getContentType ();
if (contentType == null || !contentType.startsWith ("application/zip"))
return;
ZipInputStream zipIn = new ZipInputStream (urlConnection.getInputStream ());
for (;;) {
ZipEntry zipInEntry = zipIn.getNextEntry ();
if (zipInEntry == null)
break;
String entryName = zipInEntry.getName ();
if (!entryName.startsWith (token))
continue;
if (!zipFileReader.readEntry (zipIn, entryName, token))
break;
}
} catch (Exception e) {
e.printStackTrace ();
}
}
// ========================================
public URLConnection sendZip (String cmd, String token, ZipBuilder zipBuilder) {
try {
URLConnection urlConnection = getUrlConnection (cmd, token);
String boundary = getBoundary ();
urlConnection.setRequestProperty ("Content-Type", "multipart/form-data; boundary="+boundary);
urlConnection.setDoOutput (true);
urlConnection.setDoInput (true);
OutputStream httpStream = urlConnection.getOutputStream ();
PrintWriter httpWriter = new PrintWriter (new OutputStreamWriter (httpStream, charset), true);
httpWriter.append ("--"+boundary).append (LINE_FEED);
httpWriter.append ("Content-Disposition: form-data; name=\""+cmd+"\"; filename=\""+cmd+"\"").append (LINE_FEED);
httpWriter.append ("Content-Type: application/zip").append (LINE_FEED);
httpWriter.append ("Content-Transfer-Encoding: binary").append (LINE_FEED);
httpWriter.append (LINE_FEED).flush ();
ByteArrayOutputStream memStream = new ByteArrayOutputStream ();
ZipOutputStream zipOut = new ZipOutputStream (memStream);
zipBuilder.writeEntry (token, zipOut);
zipOut.flush ();
zipOut.close ();
httpWriter.flush ();
httpStream.write (memStream.toByteArray ());
httpWriter.append (LINE_FEED).flush ();
httpWriter.append ("--"+boundary+"--").append(LINE_FEED);
httpWriter.close ();
urlConnection.connect ();
return urlConnection;
} catch (Exception e) {
e.printStackTrace ();
}
return null;
}
// ========================================
public TreeSet<String> localRemove (Mirror mirror, TreeSet<String> filesName, ProgressState progressState) {
if (filesName == null)
filesName = new TreeSet<String> ();
if (mirror.excludeFiles != null)
filesName.addAll (mirror.excludeFiles);
TreeSet<String> removed = new TreeSet<String> ();
for (String fileName : filesName) {
if (! fileName.startsWith (mirror.token))
continue;
fileName = fileName.substring (mirror.token.length ());
File oldFile = new File (mirror.localRepository.getAbsolutePath ()+fileName);
if (!oldFile.delete ())
System.err.println ("coucou pb delete: "+oldFile);
removed.add (fileName);
}
return removed;
}
// ========================================
public TreeSet<String> remoteRemove (Mirror mirror, TreeSet<String> filesName, ProgressState progressState) {
if (filesName == null)
filesName = new TreeSet<String> ();
if (mirror.excludeFiles != null)
filesName.addAll (mirror.excludeFiles);
TreeSet<String> removed = new TreeSet<String> ();
if (filesName.size () < 1)
return removed;
URLConnection urlConnection = sendZip ("zipRemove", mirror.token, new TextZipBuilder (filesName));
receiveZip (urlConnection, new ZipLineReader () {
public void readLine (String line) {
removed.add (line);
}}, mirror.token);
return removed;
}
// ========================================
public TreeSet<String> getRemoteFiles (Mirror mirror, TreeSet<String> filesName, ProgressState progressState) {
TreeSet<String> downloaded = new TreeSet<String> ();
try {
if (filesName.size () < 1)
return downloaded;
URLConnection urlConnection = sendZip ("zipGets", mirror.token, new TextZipBuilder (filesName));
byte[] tmp = new byte[bufSize];
receiveZip (urlConnection, new ZipFileReader () {
public boolean readEntry (ZipInputStream zipIn, String entryName, String token) throws IOException {
File newFile = mirror.localRepository;
for (String item : entryName.substring (mirror.token.length ()).split ("/")) {
if (item == null || item.isEmpty ())
continue;
newFile = new File (newFile, item);
}
File dirFile = newFile.getParentFile ();
dirFile.mkdirs ();
File tmpFile = File.createTempFile ("download", "tmp", dirFile);
tmpFile.deleteOnExit ();
Util.copy (zipIn, new FileOutputStream (tmpFile), tmp, progressState, false, true);
// XXX tmpFile.setLastModified (zipInEntry.getLastModifiedTime ().toMillis ());
tmpFile.setLastModified (mirror.allFiles.get (entryName).remote.date);
if (progressState != null && progressState.isInterrupted ())
return false;
Util.backup (newFile, Util.getExtention (newFile), backExtention);
try {
Files.move (tmpFile.toPath (), newFile.toPath (), StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
}
if (tmpFile.exists ()) {
System.err.println ("can't change open file!");
tmpFile.renameTo (new File (""+newFile+".new"));
}
downloaded.add (entryName);
return true;
}}, mirror.token);
} catch (Exception e) {
e.printStackTrace ();
}
return downloaded;
}
// ========================================
public static boolean newFileExists (File file) {
if (file.isFile () && file.exists () && "new".equals (Util.getExtention (file)))
return true;
if (!file.isDirectory ())
return false;
for (File subFile : file.listFiles (new FileFilter () {
public boolean accept (File file2) {
return file2.isDirectory () || (file2.isFile () && "new".equals (Util.getExtention (file2)));
}
}))
if (newFileExists (subFile))
return true;
return false;
}
public static void renameNewFile (File file) {
if (file.isFile () && file.exists () && "new".equals (Util.getExtention (file))) {
try {
File newFile = new File (file.getParentFile (), Util.getBase (file));
Files.move (file.toPath (), newFile.toPath (), StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
}
}
if (!file.isDirectory ())
return;
for (File subFile : file.listFiles (new FileFilter () {
public boolean accept (File file2) {
return file2.isDirectory () || (file2.isFile () && "new".equals (Util.getExtention (file2)));
}
}))
renameNewFile (subFile);
}
// ========================================
public static void launch (File jarFile) {
try {
Runtime.getRuntime ().exec ("java -jar "+jarFile.getName (), null, jarFile.getParentFile ());
System.exit (0);
} catch (Exception e) {
e.printStackTrace ();
}
}
// ========================================
public TreeSet<String> putRemoteFiles (Mirror mirror, TreeSet<String> filesName, ProgressState progressState) {
TreeSet<String> uploaded = new TreeSet<String> ();
if (filesName == null || filesName.size () < 1)
return uploaded;
try {
byte[] tmp = new byte[bufSize];
TimeZone timeZone = TimeZone.getDefault ();
URLConnection urlConnection = sendZip ("zipPuts", mirror.token, new ZipBuilder () {
public void writeEntry (String token, ZipOutputStream zipOut) throws IOException {
for (String fileName : filesName) {
if (! fileName.startsWith (token))
continue;
ZipEntry zipOutEntry = new ZipEntry (fileName);
File file = new File (mirror.localRepository, fileName.substring (token.length ()));
long dateMs = file.lastModified ();
dateMs -= timeZone.getOffset (dateMs);
zipOutEntry.setTime (dateMs);
zipOut.putNextEntry (zipOutEntry);
PrintWriter entryWriter = new PrintWriter (new OutputStreamWriter (zipOut));
Util.copy (new FileInputStream (file), zipOut, tmp, progressState, true, false);
entryWriter.flush ();
zipOut.closeEntry ();
}
}});
receiveZip (urlConnection, new ZipLineReader () {
public void readLine (String line) {
uploaded.add (line);
}}, mirror.token);
} catch (Exception e) {
e.printStackTrace ();
}
return uploaded;
}
// ========================================
public String getRoles (String login) {
try {
URLConnection urlConnection = getUrlConnection ("getRoles", login);
urlConnection.connect ();
BufferedReader br = new BufferedReader (new InputStreamReader (urlConnection.getInputStream ()));
String roles = br.readLine ();
for (;;) {
String line = br.readLine ();
if (line == null)
break;
}
if (roles.indexOf ("|") < 0)
return null;
return roles;
} catch (Exception e) {
return null;
}
}
public void logoutDokuwiki () {
try {
URLConnection urlConnection = getUrlConnection ("?do=logout");
urlConnection.connect ();
forceOpenConnection (urlConnection);
} catch (Exception e) {
}
}
public void loginDokuwiki (String login, String password) {
try {
// page de connexion
URLConnection urlConnection = getUrlConnection ("?do=login");
urlConnection.connect ();
String sectok = null;
BufferedReader br = new BufferedReader (new InputStreamReader (urlConnection.getInputStream ()));
for (;;) {
String line = br.readLine ();
if (line == null)
break;
if (line.indexOf ("name=\"sectok\"") < 0)
continue;
Pattern p = Pattern.compile (".*<([^<]*name=\"sectok\"[^>]*)>.*");
Matcher m = p.matcher (line);
if (!m.matches ())
break;
line = m.group (1);
p = Pattern.compile (".*value=\"([^\"]*)\".*");
m = p.matcher (line);
if (!m.matches ())
break;
sectok = m.group (1);
break;
}
if (sectok == null)
return;
// envoie de mot de passe
urlConnection = getUrlConnection ("?do=login");
urlConnection.setDoOutput (true);
urlConnection.setDoInput (true);
urlConnection.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded");
String post =
"sectok="+sectok+"&"+
"id=debut&"+
"do=login&"+
"u="+URLEncoder.encode (login, charset)+"&"+
"p="+URLEncoder.encode (password, charset);
urlConnection.setRequestProperty ("Content-Length", ""+post.getBytes ().length);
OutputStream httpStream = urlConnection.getOutputStream ();
PrintWriter httpWriter = new PrintWriter (new OutputStreamWriter (httpStream, charset), true);
httpWriter.append (post).append (LINE_FEED).flush ();
urlConnection.connect ();
forceOpenConnection (urlConnection);
} catch (Exception e) {
e.printStackTrace ();
}
}
// ========================================
static public void forceOpenConnection (URLConnection urlConnection) {
try {
BufferedReader br = new BufferedReader (new InputStreamReader (urlConnection.getInputStream ()));
for (;;) {
String line = br.readLine ();
if (line == null)
break;
}
} catch (Exception e) {
}
}
// ========================================
}

View File

@ -0,0 +1,74 @@
package misc;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import javax.swing.AbstractButton;
import javax.swing.JMenu;
@SuppressWarnings ("serial")
public class RemoteUpdateManager implements ApplicationManager, ActionListener {
// ========================================
static public final String
actionUpdate = "Update",
actionOnline = "Online";
static public final List<String> actionsNames = Arrays.asList (actionUpdate, actionOnline);
@SuppressWarnings("unchecked")
static public final Hashtable<String, Method> actionsMethod =
Util.collectMethod (RemoteUpdateManager.class, actionsNames);
public void actionPerformed (ActionEvent e) {
Util.actionPerformed (actionsMethod, e, this);
}
// ========================================
public void addMenuItem (JMenu... jMenu) {
Util.addMenuItem (actionsNames, this, jMenu[0]);
}
public void addIconButtons (Container... containers) {
Util.addIconButton (actionsNames, this, containers[0]);
}
private ArrayList<AbstractButton> enabledConnectedButtons = new ArrayList<AbstractButton> ();
public void addActiveButtons (Hashtable<String, AbstractButton> buttons) {
enabledConnectedButtons.add (buttons.get (actionOnline));
updateActiveButtons ();
}
public void updateActiveButtons () {
for (AbstractButton button : enabledConnectedButtons)
button.setEnabled (connected);
}
public void actionUpdate () {
jRemoteUpdate.downloadDialog ();
}
public void actionOnline () {
jRemoteUpdate.uploadDialog ();
}
// ========================================
private boolean connected = false;
private RemoteUpdate remoteUpdate;
private JRemoteUpdate jRemoteUpdate;
public void setConnected (boolean connected) { this.connected = connected; updateActiveButtons (); }
public RemoteUpdate getRemoteUpdate () { return remoteUpdate; }
public JRemoteUpdate getJRemoteUpdate () { return jRemoteUpdate; }
public RemoteUpdateManager (OwnFrame controller, RemoteUpdate remoteUpdate, Runnable actionAfterUpdate) {
this.remoteUpdate = remoteUpdate;
jRemoteUpdate = new JRemoteUpdate (controller, remoteUpdate, actionAfterUpdate);
}
public void check () {
(new Thread () { public void run () {
if (remoteUpdate.hasNewVersion ())
jRemoteUpdate.downloadDialog ();
} }).start ();
}
// ========================================
}

View File

@ -0,0 +1,238 @@
// ================================================================================
// François MERCIOL 2015
// Name : ScaledImage.java
// Language : Java
// Author : François Merciol
// CopyLeft : Cecil B
// Creation : 2015
// Version : 0.1 (xx/xx/xx)
// ================================================================================
package misc;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.geom.Dimension2D;
import java.awt.geom.Point2D;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.util.Hashtable;
import javax.swing.ImageIcon;
public class ScaledImage {
static public class ImageInfo {
public AffineTransform at;
public double [] bounds;
public double x, y;
Hashtable<Dimension, ImageIcon> tiles = new Hashtable<Dimension, ImageIcon> ();
public ImageInfo (AffineTransform at, double [] bounds, double x, double y) {
this.at = at;
this.bounds = bounds;
this.x = x;
this.y = y;
}
}
// ========================================
static public final RenderingHints renderingHints;
static {
renderingHints = new RenderingHints (RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
// renderingHints.put (RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// renderingHints.put (RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
// renderingHints.put (RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
// renderingHints.put (RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
}
static public final int defaultAdjust = 8;
public BufferedImage reference;
public boolean horizontalSpin, verticalSpin;
Hashtable<Integer, Hashtable<Dimension, ImageInfo>> scalesRotations = new Hashtable<Integer, Hashtable<Dimension, ImageInfo>> ();
public ScaledImage (BufferedImage image) {
reference = image;
}
public ScaledImage (BufferedImage image, boolean horizontalSpin, boolean verticalSpin) {
reference = image;
this.horizontalSpin = horizontalSpin;
this.verticalSpin = verticalSpin;
}
public ScaledImage getNewSpin (boolean horizontalSpin, boolean verticalSpin) {
if (this.horizontalSpin == horizontalSpin && this.verticalSpin == verticalSpin)
return this;
return new ScaledImage (reference, this.horizontalSpin ^ horizontalSpin, this.verticalSpin ^ verticalSpin);
}
public void changeReference (BufferedImage image) {
reference = image;
clearCache ();
}
public void clearCache () {
scalesRotations.clear ();
}
// ========================================
public AffineTransform getAffineTransform (Dimension2D size, double theta) {
int width = reference.getWidth ();
int height = reference.getHeight ();
double scaleX = size.getWidth () / width;
double scaleY = size.getHeight () / height;
if (scaleX == 0 || scaleY == 0)
return null;
if (horizontalSpin)
scaleX = -scaleX;
if (verticalSpin)
scaleY = -scaleY;
AffineTransform at = AffineTransform.getRotateInstance (Math.toRadians ((int) Math.toDegrees (theta)));
at.scale (scaleX, scaleY);
at.translate (-width/2., -height/2.);
return at;
}
static public final Point2D ORIGINE = new Point2D.Double (0, 0);
static public final Dimension ONE_TILE = new Dimension (1, 1);
public ImageIcon get (Dimension size, double theta) {
return get (size, theta, ONE_TILE);
}
public ImageIcon get (Dimension size, double theta, Dimension tile) {
if (tile.width <= 0 || tile.height <= 0)
return null;
ImageInfo imageInfo = getInfo (size, theta);
if (imageInfo == null)
return null;
ImageIcon imageIcon = imageInfo.tiles.get (tile);
if (imageIcon != null)
return imageIcon;
AffineTransformOp op = new AffineTransformOp (imageInfo.at, renderingHints);
BufferedImage image = op.createCompatibleDestImage (reference, null);
Graphics2D printGraphics = (Graphics2D) image.getGraphics ();
printGraphics.setRenderingHint (RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
print (printGraphics, null, imageInfo, tile);
imageIcon = new ImageIcon (image);
imageInfo.tiles.put (tile, imageIcon);
return imageIcon;
}
public void print (Graphics2D printGraphics, Point2D pos, ImageInfo imageInfo, Dimension tile) {
if (pos != null)
printGraphics.translate (pos.getX ()+imageInfo.x, pos.getY ()+imageInfo.y);
if (ONE_TILE.equals (tile))
printGraphics.drawImage (reference, imageInfo.at, null);
else {
double width = reference.getWidth (), height = reference.getHeight ();
double scaleX = 1.0/tile.width, scaleY = 1.0/tile.height;
double stepX = width/tile.width, stepY = height/tile.height;
for (int i = 0; i < tile.width; i++)
for (int j = 0; j < tile.height; j++) {
AffineTransform at = new AffineTransform (imageInfo.at);
at.translate (i*stepX, j*stepY);
at.scale (scaleX, scaleY);
printGraphics.drawImage (reference, at, null);
}
}
if (pos != null)
printGraphics.translate (-pos.getX ()-imageInfo.x, -pos.getY ()-imageInfo.y);
}
public void print (Graphics2D printGraphics, Point2D pos, DimensionDouble size, double theta, Dimension tile) {
print (printGraphics, pos, newInfo (size, theta), tile);
}
public double[] getBounds (Dimension size, double theta) {
ImageInfo imageInfo = getInfo (size, theta);
if (imageInfo == null)
return null;
return imageInfo.bounds;
}
public ImageInfo getInfo (Dimension size, double theta) {
int angle = (int) Math.toDegrees (theta);
Hashtable<Dimension, ImageInfo> rotated = scalesRotations.get (angle);
if (rotated == null) {
rotated = new Hashtable<Dimension, ImageInfo> ();
scalesRotations.put (angle, rotated);
}
ImageInfo imageInfo = rotated.get (size);
if (imageInfo != null)
return imageInfo;
imageInfo = newInfo (new DimensionDouble (size.width, size.height), theta);
if (imageInfo == null)
return null;
rotated.put (size, imageInfo);
return imageInfo;
}
public ImageInfo newInfo (DimensionDouble size, double theta) {
int width = reference.getWidth ();
int height = reference.getHeight ();
double scaleX = size.getWidth () / width;
double scaleY = size.getHeight () / height;
if (scaleX == 0 || scaleY == 0)
return null;
if (horizontalSpin)
scaleX = -scaleX;
if (verticalSpin)
scaleY = -scaleY;
AffineTransform at = getAffineTransform (size, theta);
double [] bounds = new double [] {0, 0, 0, height, width, height, width, 0};
at.transform (bounds, 0, bounds, 0, 4);
double dx = bounds[0];
double dy = bounds[1];
for (int i = 1; i < 4; i++) {
dx = Math.min (dx, bounds [i*2]);
dy = Math.min (dy, bounds [i*2+1]);
}
at.preConcatenate (AffineTransform.getTranslateInstance (-dx, -dy));
return new ImageInfo (at, bounds, dx, dy);
}
public ImageInfo newInfo2 (DimensionDouble size, double theta) {
int width = reference.getWidth ();
int height = reference.getHeight ();
double scaleX = size.getWidth () / width;
double scaleY = size.getHeight () / height;
if (scaleX == 0 || scaleY == 0)
return null;
if (horizontalSpin)
scaleX = -scaleX;
if (verticalSpin)
scaleY = -scaleY;
AffineTransform at = AffineTransform.getRotateInstance (theta);
at.scale (scaleX, scaleY);
at.translate (-width/2., -height/2.);
double [] bounds = new double [] {0, 0, 0, height, width, height, width, 0};
at.transform (bounds, 0, bounds, 0, 4);
double dx = bounds[0];
double dy = bounds[1];
for (int i = 1; i < 4; i++) {
dx = Math.min (dx, bounds [i*2]);
dy = Math.min (dy, bounds [i*2+1]);
}
at.preConcatenate (AffineTransform.getTranslateInstance (-dx, -dy));
return new ImageInfo (at, bounds, dx, dy);
}
public ImageIcon getSide (int max) {
int width = reference.getWidth ();
int height = reference.getHeight ();
return get (width>height ? new Dimension (max, (height*max)/width) : new Dimension ((width*max)/height, max), 0);
}
public ImageIcon getInsideFit (int maxWidth, int maxHeight, int adjust) {
return getInside (Math.min (reference.getWidth (), (maxWidth/adjust)*adjust),
Math.min (reference.getHeight (), (maxHeight/adjust)*adjust));
}
public ImageIcon getInside (int maxWidth, int maxHeight) {
int width = reference.getWidth ();
int height = reference.getHeight ();
return get ((width*maxHeight)/height > maxWidth ?
new Dimension (maxWidth, (height*maxWidth)/width) :
new Dimension ((width*maxHeight)/height, maxHeight), 0);
}
public ImageIcon get (DimensionDouble real, double scale, double theta) {
return get (new Dimension ((int)(real.getWidth ()*scale), (int)(real.getHeight ()*scale)), 0);
}
// ========================================
}

View File

@ -0,0 +1,125 @@
package misc;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Locale;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeListener;
import misc.Util;
import static misc.Util.GBC;
import static misc.Util.GBCNL;
/**
Spinner and Slider
*/
@SuppressWarnings ("serial")
public class SpinnerSlider extends JPanel implements ChangeListener {
static public int MaxPrecision = 10000;
static public NumberFormat numberFormat;
static {
numberFormat = NumberFormat.getInstance (Locale.FRENCH);
//numberFormat = new DecimalFormat ("#,##0.###,#");
numberFormat.setGroupingUsed (true);
numberFormat.setMinimumFractionDigits (0);
numberFormat.setMaximumFractionDigits (12);
}
// ========================================
public interface Accessor {
/** current */
public void set (double value);
/** minValue, maxValue, current */
public double [] get ();
};
Accessor accessor;
// ========================================
public double minValue, maxValue;
public SpinnerNumberModel snm = new SpinnerNumberModel (0., 0., 0., 1.) {
public Object getPreviousValue () {
Number value = (Number) super.getPreviousValue ();
return SpinnerSlider.this.getPreviousValue (value);
}
public Object getNextValue () {
Number value = (Number) super.getNextValue ();
return SpinnerSlider.this.getNextValue (value);
}
};
public JSpinner spinner = new JSpinner (snm);
public JLabel label = new JLabel ("/0");
private JSlider slider = new JSlider (0, MaxPrecision, 1);
// ========================================
public SpinnerSlider (Accessor accessor, int textLength, float slideWidthCoef) {
super (null);
this.accessor = accessor;
snm.addChangeListener (this);
slider.addChangeListener (this);
((JSpinner.DefaultEditor) spinner.getEditor ()).getTextField ().setColumns (textLength);
JSpinner.NumberEditor editor = (JSpinner.NumberEditor) spinner.getEditor ();
DecimalFormat format = editor.getFormat ();
format.setDecimalSeparatorAlwaysShown (true);
format.setMinimumFractionDigits (0);
format.setMaximumFractionDigits (12);
setLayout (new GridBagLayout ());
Util.addComponent (spinner, this, GBC);
Util.addComponent (label, this, GBC);
Util.addComponent (slider, this, GBCNL);
Dimension d = slider.getPreferredSize ();
d.width = (int)(slideWidthCoef*d.width);
slider.setPreferredSize (d);
slider.setMinimumSize (d);
}
// ========================================
public void stateChanged (ChangeEvent e) {
try {
if (e.getSource () == slider)
accessor.set (((double)slider.getValue ()/MaxPrecision)*(maxValue - minValue)+minValue);
else if (e.getSource () == snm)
accessor.set (((Number)snm.getValue ()).doubleValue ());
} catch (Exception e2) {
e2.printStackTrace ();
}
}
// ========================================
public void update () {
double [] doubleValues = accessor.get ();
minValue = doubleValues [0];
maxValue = doubleValues [1];
slider.removeChangeListener (this);
snm.removeChangeListener (this);
snm.setMinimum (doubleValues [0]);
snm.setMaximum (doubleValues [1]); // XXX ?
snm.setValue (doubleValues [2]);
//snm.setStepSize ((maxValue-minValue)/MaxPrecision);
slider.setValue ((int)((doubleValues [2]-minValue)/(maxValue-minValue)*MaxPrecision));
label.setText ("/"+numberFormat.format ((float)doubleValues [1]));
snm.addChangeListener (this);
slider.addChangeListener (this);
}
// ========================================
public Number getPreviousValue (Number value) {
return value;
}
public Number getNextValue (Number value) {
return value;
}
// ========================================
}

View File

@ -0,0 +1,109 @@
// ================================================================================
// François MERCIOL 2013
// Name : StateNotifier.java
// Language : Java
// Author : François Merciol
// CopyLeft : Cecil B
// Creation : 2012
// Version : 0.1 (xx/xx/xx)
// ================================================================================
package misc;
import java.lang.reflect.Method;
import java.util.Hashtable;
import java.util.List;
import java.util.TreeSet;
public class StateNotifier {
// ========================================
private Hashtable<Object, TreeSet<String>> observers = new Hashtable<Object, TreeSet<String>> ();
private Hashtable<String, Hashtable<Object, Method>> observableNames= new Hashtable<String, Hashtable<Object, Method>> ();
// ========================================
private void broadcast (String observable) {
Hashtable<Object, Method> objectMethod = observableNames.get (observable);
if (objectMethod == null)
return;
try {
for (Object object : objectMethod.keySet ())
objectMethod.get (object).invoke (object);
} catch (Exception e) {
Log.keepLastException ("ModelInfoSender::broadcast <"+observable+">", e);
}
}
// ========================================
private void broadcast (String observable, Object... args) {
Hashtable<Object, Method> objectMethod = observableNames.get (observable);
if (objectMethod == null)
return;
try {
for (Object object : objectMethod.keySet ())
objectMethod.get (object).invoke (object, new Object[]{args});
} catch (Exception e) {
Log.keepLastException ("ModelInfoSender::broadcast <"+observable+">", e);
}
}
// ========================================
public void broadcastUpdate (String observable) {
broadcast ("update"+observable);
}
public void broadcastDisplay (String observable, Object... args) {
broadcast ("display"+observable, args);
}
// ========================================
private void addObserver (Object object, boolean arg, String... observable) {
TreeSet<String> newNames = new TreeSet<String> ();
for (String obs : observable) {
String name = (arg ? "display" : "update")+obs;
try {
Method method = arg ?
object.getClass ().getMethod (name, Object[].class):
object.getClass ().getMethod (name);
Hashtable<Object, Method> objectMethod = observableNames.get (name);
if (objectMethod == null)
observableNames.put (name, objectMethod = new Hashtable<Object, Method> ());
objectMethod.put (object, method);
newNames.add (name);
} catch (NoSuchMethodException e) {
Log.keepLastException ("StateNotifier::addObserver no method <"+name+"> in class <"+object.getClass ()+">", e);
}
}
if (newNames.size () == 0)
return;
try {
TreeSet<String> oldNames = observers.get (object);
oldNames.addAll (newNames);
} catch (Exception e) {
observers.put (object, newNames);
}
}
// ========================================
public void addUpdateObserver (Object object, String... observable) {
addObserver (object, false, observable);
}
public void addMsgObserver (Object object, String... observable) {
addObserver (object, true, observable);
}
// ========================================
public void removeObserver (Object object) {
TreeSet<String> names = observers.get (object);
if (names == null)
return;
for (String name : names) {
Hashtable<Object, Method> objectMethod = observableNames.get (name);
objectMethod.remove (object);
if (objectMethod.size () == 0)
observableNames.remove (name);
}
observers.remove (object);
}
// ========================================
}

156
src/java/misc/Story.java Normal file
View File

@ -0,0 +1,156 @@
package misc;
import java.util.ArrayList;
import java.util.Stack;
import java.util.Vector;
public class Story {
// ========================================
static public final String
BroadcastStory = "Story";
public abstract class Command {
public final String name;
public Command (String name) { this.name = name; }
public abstract void exec ();
public abstract void undo ();
public void displayExec () { display (); }
public void displayUndo () { display (); }
public void display () {}
}
public abstract class Commands extends Command {
ArrayList<Command> commands = new ArrayList<Command> ();
public Commands (String name) { super (name); }
public Story getStory () { return Story.this; }
public int size () { return commands.size (); }
public void add (Command command) {
commands.add (command);
}
public void exec () {
// XXX si erreur undo jusqu'a l'etape
for (Command command : commands) {
command.exec ();
command.displayExec ();
}
}
public void undo () {
for (int i = commands.size ()-1; i >= 0; i--) {
Command command = commands.get (i);
command.undo ();
command.displayUndo ();
}
}
public String toString () {
String result = "";
for (Command command : commands)
result += " "+command.name;
return result;
}
}
// ========================================
StateNotifier observable;
Stack<Command> undo = new Stack<Command> ();
Stack<Command> redo = new Stack<Command> ();
public Vector<String> getUndoCmd () {
return getCmd (undo);
}
public Vector<String> getRedoCmd () {
return getCmd (redo);
}
public Vector<String> getCmd (Stack<Command> commands) {
Vector<String> result = new Vector<String> (commands.size ());
for (int i = commands.size () - 1; i >= 0; i--)
result.add (commands.get (i).name);
return result;
}
public Story (StateNotifier observable) {
this.observable = observable;
}
public void addUpdateObserver (Object object) {
observable.addUpdateObserver (object, BroadcastStory);
}
public void removeObserver (Object object) {
observable.removeObserver (object);
}
public void add (Command command) {
try {
if (command instanceof Commands && ((Commands) command).commands.size () < 1)
return;
command.exec ();
command.displayExec ();
undo.push (command);
} finally {
redo.clear ();
observable.broadcastUpdate (BroadcastStory);
}
};
// ========================================
Command lastSaved;
Command lastCommand () {
return undo.empty () ? null : undo.peek ();
}
public void markNotSaved () {
lastSaved = new Command ("") { public void exec () {} public void undo () {} };
observable.broadcastUpdate (BroadcastStory);
}
public void markSaved () {
lastSaved = lastCommand ();
observable.broadcastUpdate (BroadcastStory);
}
public boolean isModified () {
return lastSaved != lastCommand ();
}
// ========================================
public boolean undoAvailable () {
return !undo.empty ();
}
public boolean redoAvailable () {
return !redo.empty ();
}
public ArrayList<String> getUndoCommande () { return getString (undo); }
public ArrayList<String> getRedoCommande () { return getString (redo); }
ArrayList<String> getString (Stack<Command> stack) {
ArrayList<String> result = new ArrayList<String> ();
for (Command command : stack)
result.add (command.name);
return result;
}
// ========================================
public void undo (int level) {
try {
for (int i = 0; i < level; i++) {
Command command = undo.pop ();
command.undo ();
command.displayUndo ();
redo.push (command);
}
} catch (Exception e) {
}
observable.broadcastUpdate (BroadcastStory);
}
public void redo (int level) {
try {
for (int i = 0; i < level; i++) {
Command command = redo.pop ();
command.exec ();
command.displayExec ();
undo.push (command);
}
} catch (Exception e) {
}
observable.broadcastUpdate (BroadcastStory);
}
// ========================================
}

View File

@ -0,0 +1,142 @@
package misc;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
public class StoryManager implements ApplicationManager, ActionListener {
// ========================================
static public final String
actionUndo = "Undo",
actionRedo = "Redo";
static public final List<String>
actionsNames = Arrays.asList (actionUndo, actionRedo);
@SuppressWarnings("unchecked")
static public final Hashtable<String, Method> actionsMethod =
Util.collectMethod (StoryManager.class, actionsNames);
public void actionPerformed (ActionEvent e) {
Util.actionPerformed (actionsMethod, e, this);
}
private ArrayList<AbstractButton> enabledUndoButtons = new ArrayList<AbstractButton> ();
private ArrayList<AbstractButton> enabledRedoButtons = new ArrayList<AbstractButton> ();
// ========================================
public void addMenuItem (JMenu... jMenu) {
Util.addMenuItem (actionsNames, this, jMenu[0]);
}
public void addIconButtons (Container... containers) {
addListButton (Util.addIconButton (actionUndo, this, containers[0]), true);
addListButton (Util.addIconButton (actionRedo, this, containers[0]), false);
}
public void addListButton (JButton button, boolean undo) {
Dimension currentSize = button.getPreferredSize ();
button.setLayout (new BorderLayout ());
JLabel develop = new JLabel (Util.loadActionIcon ("develop"));
Dimension addedSize = develop.getPreferredSize ();
button.add (develop, BorderLayout.EAST);
currentSize.width += addedSize.width;
button.setPreferredSize (currentSize);
develop.addMouseListener (new MouseAdapter () {
public void mousePressed (MouseEvent e) {
button.setSelected (false);
if (!button.isEnabled () || story == null)
return;
new JStoryPopup (button, undo, SwingUtilities.convertMouseEvent (develop, e, button).getPoint ());
}
});
}
@SuppressWarnings ("serial")
class JStoryPopup extends JPopupMenu {
public JStoryPopup (JButton button, boolean undo, Point pos) {
Vector<String> cmds = undo ? story.getUndoCmd () : story.getRedoCmd ();
for (int i = 0; i < cmds.size (); i++) {
if (i >= 10) {
add (new JLabel ("..."));
break;
}
JMenuItem jMenu = new JMenuItem (Bundle.getStory (cmds.get (i)));
final int count = i+1;
jMenu.addActionListener (new ActionListener () {
public void actionPerformed (ActionEvent e) {
if (undo)
story.undo (count);
else
story.redo (count);
}
});
add (jMenu);
}
show (button, pos.x, pos.y);
}
}
public void addActiveButtons (Hashtable<String, AbstractButton> buttons) {
enabledUndoButtons.add (buttons.get (actionUndo));
enabledRedoButtons.add (buttons.get (actionRedo));
updateActiveButtons ();
}
public void updateActiveButtons () {
updateStory ();
}
public void updateStory () {
boolean undo = false, redo = false;
if (story != null) {
undo = story.undoAvailable ();
redo = story.redoAvailable ();
}
for (AbstractButton button : enabledUndoButtons)
button.setEnabled (undo);
for (AbstractButton button : enabledRedoButtons)
button.setEnabled (redo);
}
public void actionUndo () {
if (story == null)
return;
story.undo (1);
}
public void actionRedo () {
if (story == null)
return;
story.redo (1);
}
// ========================================
Story story;
public void setStory (Story story) {
if (this.story != null)
this.story.removeObserver (this);
this.story = story;
if (story != null)
story.addUpdateObserver (this);
updateStory ();
}
// public StoryManager () {
// }
// ========================================
}

58
src/java/misc/Timer.java Normal file
View File

@ -0,0 +1,58 @@
package misc;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.TimeZone;
public class Timer {
// ========================================
static public SimpleDateFormat sdf = new SimpleDateFormat ("H:mm:ss.S");
static {
sdf.setTimeZone (TimeZone.getTimeZone ("GMT"));
}
class Milestone {
String name;
long end;
long last;
Milestone (String name, long end, long last) {
this.name = name;
this.end = end;
this.last = last;
}
}
// ========================================
long start = System.currentTimeMillis ();
long lastEnd = start;
ArrayList<Milestone> milestones = new ArrayList<Milestone> ();
public String getLap (String milestoneName) {
long now = System.currentTimeMillis ();
long end = now-start;
long last = now - lastEnd;
lastEnd = now;
milestones.add (new Milestone (milestoneName, end, last));
return milestoneName+": "+sdf.format (end)+" ("+end+")"+": "+sdf.format (last)+" ("+last+")";
}
public String getNames () {
String result = "";
for (Milestone milestone : milestones)
result += ":"+milestone.name;
return result;
}
public String getEnds () {
String result = "";
for (Milestone milestone : milestones)
result += ":"+sdf.format (milestone.end)+" ("+milestone.end+")";
return result;
}
public String getLasts () {
String result = "";
for (Milestone milestone : milestones)
result += ":"+sdf.format (milestone.last)+" ("+milestone.last+")";
return result;
}
// ========================================
}

View File

@ -0,0 +1,34 @@
package misc;
public class Timestamp {
// ========================================
private long changeTimestamp, updateTimestamp;
public long[] getValues () { return new long[]{changeTimestamp, updateTimestamp}; }
// ========================================
public void reset () {
changeTimestamp = updateTimestamp = System.currentTimeMillis ();
}
// ========================================
public void change () {
changeTimestamp = System.currentTimeMillis ();
}
// ========================================
public void update () {
updateTimestamp = System.currentTimeMillis ();
}
// ========================================
public boolean isUpdated (Timestamp... others) {
if (changeTimestamp > updateTimestamp)
return false;
for (Timestamp other : others)
if (other.updateTimestamp > updateTimestamp)
return false;
return true;
}
// ========================================
}

View File

@ -0,0 +1,57 @@
package misc;
import java.awt.Frame;
import java.awt.Point;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingConstants;
@SuppressWarnings ("serial") public class TitledDialog extends JDialog implements SwingConstants {
// ========================================
protected String titleId;
// ========================================
public TitledDialog (Frame frame, final String titleId) {
super (frame, Bundle.getTitle (titleId), false);
this.titleId = titleId;
Bundle.addLocalizedDialog (this, titleId);
addWindowListener (new WindowAdapter () {
public void windowClosing (WindowEvent e) {
Util.updateCheckBox (titleId, false);
}
});
boolean visible = Config.getBoolean (titleId+Config.checkedPostfix, false);
setVisible (visible);
//Util.updateCheckBox (titleId, visible);
}
// ========================================
public void setVisible (boolean visible) {
// if (visible == isVisible ())
// return;
super.setVisible (visible);
Util.updateCheckBox (titleId, visible);
if (visible) {
pack ();
setLocationRelativeTo (null);
Config.loadLocation (titleId, this, getLocation ());
toFront ();
} else {
saveLocation ();
}
}
// ========================================
public void setJFrame (JFrame jFrame) {
setIconImage (jFrame.getIconImage ());
}
// ========================================
public void saveLocation () {
Config.saveLocation (titleId, this);
}
// ========================================
}

View File

@ -0,0 +1,462 @@
package misc;
import java.util.Comparator;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.TreeSet;
import java.util.Vector;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JToolBar;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import javax.swing.plaf.basic.BasicButtonUI;
import javax.swing.table.AbstractTableModel;
import misc.TitledDialog;
import static misc.Util.GBCNL;
/**
...
*/
public class ToolBarManager implements ApplicationManager, ActionListener, ContainerListener, SwingConstants {
// ========================================
static public BasicButtonUI buttonUI = new BasicButtonUI ();
static public Border buttonBorder = BorderFactory.createEmptyBorder (2, 2, 2, 2);
static public final String
actionUp = "Up",
actionDown = "Down",
actionToolBarProfil = "ToolBarProfil";
static public final List<String> actionsToolBar =
Arrays.asList (actionToolBarProfil);
@SuppressWarnings("unchecked")
static public final Hashtable<String, Method> actionsMethod =
Util.collectMethod (ToolBarManager.class, actionsToolBar);
public void actionPerformed (ActionEvent e) {
try {
AbstractButton button = ((AbstractButton) e.getSource ());
Component component = toolBarComponent.get (button.getActionCommand ());
if (component != null) {
if (button.isSelected ())
show (component);
else
hide (component);
return;
}
} catch (Exception e2) {
Log.keepLastException ("ToolBarManager::actionPerformed", e2);
}
Util.actionPerformed (actionsMethod, e, this);
}
public void addMenuItem (JMenu... jMenu) {
Util.addMenuItem (actionsToolBar, this, jMenu[0]);
((MultiToolBarBorderLayout) container.getLayout ()).setMenu (jMenu[0].getParent ());
}
public void addIconButtons (Container... containers) {
Util.addIconButton (actionsToolBar, this, containers[0]);
}
public void addActiveButtons (Hashtable<String, AbstractButton> buttons) {
// disable if no toolbar to manage (orderedComponents.size () < 1 => container listener)
}
// ========================================
@SuppressWarnings ("serial") public class TableObjectModel extends AbstractTableModel {
public int getColumnCount () { return 2; }
public int getRowCount () { return orderedComponents.size (); }
public Object getValueAt (int row, int column) {
if (row >= orderedComponents.size ())
return null;
return column == 0 ?
orderedComponents.get (row).getParent () != null :
Bundle.getTitle (toolBarName.get (orderedComponents.get (row)));
}
public String getColumnName (int column) {
return column == 0 ? Bundle.getLabel ("ToolBarShowed") : Bundle.getLabel ("ToolBarNamed");
}
public Class<?> getColumnClass (int column) {
return column == 0 ? Boolean.class : String.class;
}
public boolean isCellEditable (int row, int column) {
return column == 0;
}
public void setValueAt (Object aValue, int row, int column) {
if (column > 0 || row >= orderedComponents.size ())
return;
Component component = orderedComponents.get (row);
if ((Boolean) aValue)
show (component);
else
hide (component);
}
public void move (int delta) {
int idx = table.getSelectedRow ();
if (idx < 0)
return;
int mod = orderedComponents.size ();
Component old = orderedComponents.remove (idx);
idx = (idx+delta+mod) % mod;
if (idx == orderedComponents.size ())
orderedComponents.add (old);
else
orderedComponents.add (idx, old);
table.revalidate ();
table.getSelectionModel ().setLeadSelectionIndex (idx);
container.getLayout ().layoutContainer (container);
}
};
TableObjectModel dataObjectModel = new TableObjectModel ();
JTable table = new JTable (dataObjectModel);
public void actionToolBarProfil () {
JPanel panel = new JPanel (new BorderLayout ());
panel.add (Util.getJScrollPane (table), BorderLayout.CENTER);
JPanel leftPropCmdPanel = new JPanel ();
panel.add (leftPropCmdPanel, BorderLayout.SOUTH);
leftPropCmdPanel.add (Util.newIconButton (actionUp, new ActionListener () {
public void actionPerformed (ActionEvent e) { dataObjectModel.move (-1); }
}));
leftPropCmdPanel.add (Util.newIconButton (actionDown, new ActionListener () {
public void actionPerformed (ActionEvent e) { dataObjectModel.move (+1); }
}));
Hashtable<String, AbstractButton> buttons = Util.collectButtons (null, leftPropCmdPanel);
Util.collectButtons (buttons, leftPropCmdPanel);
for (AbstractButton button : buttons.values ()) {
button.setUI (buttonUI);
button.setBorder (buttonBorder);
}
//table.getTableHeader ().setReorderingAllowed (true);
table.setShowHorizontalLines (false);
table.setShowVerticalLines (false);
table.setRowSelectionAllowed (true);
table.setColumnSelectionAllowed (false);
table.setSelectionMode (0);
Dimension preferredSize = new Dimension (table.getPreferredSize ());
preferredSize.height += 40;
table.getParent ().getParent ().setPreferredSize (preferredSize);
for (int row = 0; row < table.getRowCount (); row++)
// check bundle before grab dialog
table.getValueAt (row, 1);
JOptionPane.showMessageDialog (frame, panel);
int i = 0;
for (Component component : orderedComponents)
Config.setInt (toolBarName.get (component)+"Order", i++);
}
// ========================================
/** Les points cardinaux sur lesquels l'orientation des boîtes doit être horizontal. */
static final List<Integer> horizontalCardinal = Arrays.asList (NORTH, SOUTH);
// ========================================
/** receptacle qui accueille les boîtes (doit avoir une mise en forme de type bordure "BorderLayout"). */
private Container container;
/**
* Nom donné à chaque boîte. Ce nom est utilisé comme racine pour trouver des valeur dans la configuration ou l'internationnalisation.
* Exemple si le nom est "Horloge" on trouvera dans la configuration :
* "HorlogeChecked" (true indiquant que la boîte est visible) et
* "HorlogePlace" (East indiquant que la boîte s'attachera à droite)
* On trouvera dans le fichier des
* "ActionHorloge" associant le texte à la case à cocher ("Montre l'horloge" pour le texte en français)
* Enfin un évenement de type "Horloge" pourra être traité par "actionPerformed".
*/
private Hashtable<Component, String> toolBarName = new Hashtable<Component, String>();
private Hashtable<Component, Integer> toolBarOrder = new Hashtable<Component, Integer>();
private ArrayList<Component> orderedComponents = new ArrayList<Component> ();
/** Assoication permettant de trouver un composant d'après son nom. */
private Hashtable<String, Component> toolBarComponent = new Hashtable<String, Component>();
/** mémorise la position relative (points cardinaux) de la boîte lorsqu'elle est attachée. */
private Hashtable<Component, String> toolBarPlace = new Hashtable<Component, String>();
/** Liste des cases à cocher associé à la visibilité d'une boîte. */
private Hashtable<String, Vector<AbstractButton>> nameCheckBox = new Hashtable<String, Vector<AbstractButton>>();
JFrame frame = new JFrame ();
// ========================================
/**
* créer un gestionnaire de boîte à outil détachable gravitant autour d'un receptacle.
* Le receptacle doit avoir une mise en forme de type bordure "BorderLayout".
* Le gestionnaire se mets automatiquement à l'écoute de l'ajout et de la suppression de composant qui peuvent résulter de l'attachement ou du détachment de boîte.
*/
public ToolBarManager (Image icon, Container container) {
this.container = container;
((MultiToolBarBorderLayout) container.getLayout ()).setLayoutOrderedComponents (orderedComponents);
frame.setIconImage (icon);
container.addContainerListener (this);
}
// ========================================
public JToolBar newJToolBar (String toolBarId, String defaultCardinalPoint) {
JToolBar toolBar = new JToolBar (toolBarId);
// XXX
//Bundle.addLocalizedActioner (toolBar);
add (toolBar, defaultCardinalPoint);
return toolBar;
}
/**
* Enregistre un composant détachable.
* Il ne devrait pas y avoir plus de 4 boîtes visible en même temps (au maximum un par point cardinal).
*/
public void add (Component component, String defaultCardinalPoint) {
String name = component.getName (); //+toolBarPostfix;
//Util.getClassName (component.getClass ());
if (toolBarName.contains (component))
throw new IllegalArgumentException (MessageFormat.format (Bundle.getException ("AlreadyRegistredTool"),
name, defaultCardinalPoint));
toolBarName.put (component, name);
toolBarComponent.put (name, component);
nameCheckBox.put (name, new Vector<AbstractButton>());
toolBarOrder.put (component, Config.getInt (name+"Order", toolBarOrder.size ()));
orderedComponents.add (component);
orderedComponents.sort (componentsComparator);
String place = Config.getString (name+"Place", defaultCardinalPoint);
Integer cardinal = MultiToolBarBorderLayout.positionStringToInt.get (place);
if (cardinal == null || cardinal == CENTER)
throw new IllegalArgumentException (MessageFormat.format (Bundle.getException ("NotCardinalPoint"), place));
put (component, place);
showIfVisible (component);
}
// ========================================
/**
* Ajoute un case à cocher concernée par la visibilité d'une boîte détachable.
* La case sera mise à jour suivant le changement de visibilité du composant.
* Le gestionaire de boîte se mets automatiquement à l'écoute du changement d'état de la case (que cela soit un JButton ou un JCheckBoxMenuItem).
*/
public void addCheckBox (AbstractButton checkbox) {
String name = checkbox.getActionCommand ();
Vector<AbstractButton> buttons = nameCheckBox.get (name);
if (buttons == null)
return;
buttons.add (checkbox);
checkbox.addActionListener (this);
}
// ========================================
/**
* les seuls évènement pris en charge provienne du changement d'état de case à cocher.
* L'action doit avoir le même nom que celui utilisé pour désigner la boîte détachable.
*/
// ========================================
/** Mets à jour les boîtes à cocher refletant la visibilité d'une boîte à outils. */
public void checkBoxComponent (Component component) {
boolean showed = component.getParent () != null;
for (AbstractButton checkbox : nameCheckBox.get (toolBarName.get (component))) {
try {
checkbox.getClass ().getMethod ("setState", boolean.class).invoke (checkbox, showed);
} catch (NoSuchMethodException e) {
Log.keepLastException ("ToolBarManager::checkBoxComponent", e);
} catch (InvocationTargetException e) {
Log.keepLastException ("ToolBarManager::checkBoxComponent", e);
} catch (IllegalAccessException e) {
Log.keepLastException ("ToolBarManager::checkBoxComponent", e);
}
}
}
// ========================================
/** Creer une boîte de dialogue pour une boîte detache au lancement de l'application. */
private void newUndocked (final Component component) {
final String name = toolBarName.get (component);
final TitledDialog jdialog = new TitledDialog (frame, name);
jdialog.add (component);
((JToolBar) component).setFloatable (false);
String place = get (component);
try {
int cardinal = MultiToolBarBorderLayout.positionStringToInt.get (place);
((JToolBar) component).setOrientation (horizontalCardinal.contains (cardinal) ?
SwingConstants.HORIZONTAL : SwingConstants.VERTICAL);
} catch (Exception e) {
}
((JToolBar) component).addContainerListener (new ContainerListener () {
public void componentAdded (ContainerEvent e) { Util.packWindow (component); }
public void componentRemoved (ContainerEvent e) { Util.packWindow (component); }
});
jdialog.addWindowListener (new WindowAdapter () {
public void windowClosing (WindowEvent e) {
jdialog.remove (component);
((JToolBar) component).setFloatable (true);
show (component);
}
});
jdialog.setLocationRelativeTo (null);
Config.loadLocation (name, jdialog, jdialog.getLocation ());
jdialog.setVisible (true);
jdialog.pack ();
}
public void saveLocation () {
for (Component component : toolBarName.keySet ()) {
if (component.getParent () == null || container.isAncestorOf (component))
continue;
Config.saveLocation (toolBarName.get (component), getUndocked (component));
}
}
// ========================================
/** Montre le composant au lancement de l'application s'il est marqué comme visible dans le fichier de configuration. */
public void showIfVisible (final Component component) {
if (Config.getBoolean (toolBarName.get (component)+Config.checkedPostfix, true))
if (Config.getBoolean (toolBarName.get (component)+Config.undockedPostfix, false))
newUndocked (component);
else {
show (component);
}
}
// ========================================
/** Montre le composant, adapte l'orientation (horizontal ou non), mémorise l'état dans le fichier de configuration et mets à jour les cases à cocher. */
public void show (Component component) {
String place = get (component);
try {
int cardinal = MultiToolBarBorderLayout.positionStringToInt.get (place);
((JToolBar) component).setOrientation (horizontalCardinal.contains (cardinal) ?
SwingConstants.HORIZONTAL : SwingConstants.VERTICAL);
} catch (Exception e){
}
Container parent = component.getParent ();
if (parent!= null)
return;
((JToolBar) component).setFloatable (true);
container.invalidate ();
container.add (component, place);
container.validate ();
Config.setBoolean (toolBarName.get (component)+Config.checkedPostfix, true);
checkBoxComponent (component);
}
// ========================================
private Container getUndocked (Component component) {
Container frame = component.getParent ();
for (;;) {
if (frame instanceof Window)
return frame;
frame = frame.getParent ();
}
}
// ========================================
/** Cache le composant, mémorise l'état dans le fichier de configuration et mets à jour les cases à cocher. */
public void hide (Component component) {
Container parent = component.getParent ();
if (parent == null)
return;
if (container.isAncestorOf (component)) {
container.invalidate ();
container.remove (component);
container.validate ();
} else {
try {
getUndocked (component).setVisible (false);
} catch (Exception e) {
}
parent.remove (component);
}
Config.setBoolean (toolBarName.get (component)+Config.checkedPostfix, false);
checkBoxComponent (component);
}
// ========================================
/** Change l'état de visibilité de la boîte détachable. */
public void showHide (Component component) {
if (component.getParent () == null)
show (component);
else
hide (component);
}
// ========================================
/** Recherche le point cardinal réel d'une boîte detachable dans le receptacle (exemple : cas d'une boîte vient d'être réttachée). */
private String find (Component component) {
return (String) ((MultiToolBarBorderLayout) container.getLayout ()).getConstraints (component);
}
// ========================================
/** Recherche un point cardinal pour une boîte. */
private String get (Component component) {
String place = toolBarPlace.get (component);
if (place != null)
return place;
place = BorderLayout.NORTH;
put (component, place);
return place;
}
// ========================================
/** Mémorise, sans controle, le point cardinal pour une boîte (y compris dans le fichier de configuration). */
private void put (Component component, String place) {
toolBarPlace.put (component, place);
Config.setString (toolBarName.get (component)+"Place", place);
}
// ========================================
/**
* Traite l'ajout d'une boîte détachable par insertion (coche d'une case ou fermeture de sa boîte de dialogue quand elle est détachée).
* Vérifie si elle attérie sur une place déjà prise.
*/
public void componentAdded (ContainerEvent e) {
Component component = e.getChild ();
if (! toolBarName.keySet ().contains (component))
// boîte non géré par ce gestionnaire
return;
String place = find (component);
put (component, place);
Util.packWindow (container);
Config.setBoolean (toolBarName.get (component)+Config.undockedPostfix, false);
}
// ========================================
/**
* Traite le retrait d'une boîte détachable par suppression (décoche d'une case ou détachement vers une doite de dialogue).
*/
public void componentRemoved (ContainerEvent e) {
Util.packWindow (container);
Component component = e.getChild ();
if (! toolBarName.keySet ().contains (component))
// boîte non géré par ce gestionnaire
return;
Config.setBoolean (toolBarName.get (component)+Config.undockedPostfix, true);
}
// ========================================
public Comparator<Component> componentsComparator =
new Comparator<Component> () {
public int compare (Component o1, Component o2) {
Integer i1 = toolBarOrder.get (o1);
Integer i2 = toolBarOrder.get (o2);
if (i1 == i2)
return o1.hashCode ()-o2.hashCode ();
if (i1 == null || i2 == null)
return i2 == null ? 1 : -1;
return i1-i2;
}
};
// ========================================
}

964
src/java/misc/Util.java Normal file
View File

@ -0,0 +1,964 @@
// ================================================================================
// François MERCIOL 2012
// Name : Util.java
// Language : Java
// Author : François Merciol
// CopyLeft : Cecil B
// Creation : 2012
// Version : 0.1 (xx/xx/xx)
// ================================================================================
package misc;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.Normalizer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.DefaultCellEditor;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.plaf.basic.BasicButtonUI;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
public class Util implements SwingConstants {
// ========================================
// Change Plugins.version too !
static public final Long version = 20171101L;
static public final int bufSize = 1024*1024;
static public final String NL = System.getProperty ("line.separator");
static public final String ON = "On";
static public final String OFF = "Off";
static public BasicButtonUI buttonNoUI = new BasicButtonUI ();
static public Border buttonNoBorder = BorderFactory.createEmptyBorder (2, 2, 2, 2);
// ========================================
static public final String toNumIn2Units (long bytes) {
if (bytes == 0)
return "0 ";
int u = 0;
for (; bytes > 1024*1024; bytes >>= 10)
u++;
if (bytes < 1024)
return String.format ("%d %c", bytes, " kMGTPEZY".charAt (u)).replace (" ", "");
u++;
return String.format ("%.1f %c", bytes/1024f, " kMGTPEZY".charAt (u)).replace (",0 ", " ").replace (" ", "");
}
static public final String toNumIn10Units (long bytes) {
if (bytes == 0)
return "0 ";
int u = 0;
for (; bytes > 1000*1000; bytes >>= 10)
u++;
if (bytes < 1000)
return String.format ("%d %c", bytes, " kMGTPEZY".charAt (u)).replace (" ", "");
u++;
return String.format ("%.1f %c", bytes/1000f, " kMGTPEZY".charAt (u)).replace (",0 ", " ").replace (" ", "");
}
@SuppressWarnings ({"unchecked", "rawtypes"})
static public final<T> T toEnum (String value, T defaultValue) {
try {
return (T) Enum.valueOf ((Class<? extends Enum>)defaultValue.getClass (), value);
} catch (Exception e) {
}
return defaultValue;
}
// ========================================
static public final String toColumn (String [] lines, int nbColumn) {
int size = lines.length;
if (size < 1)
return "";
if (size < 2)
return lines [0]+"\n";
String result = "";
int nbLignes = size/nbColumn;
int nbLongColumn = size % nbColumn;
for (int i = 0, k = 0; k < size; i++) {
int idx = i;
String sep = "";
for (int j = 0; j < nbColumn && k < size; j++, k++) {
result += sep + lines [idx];
sep = "\t";
idx += nbLignes;
if (j < nbLongColumn)
idx++;
}
result += "\n";
}
return result;
}
// ========================================
static public final String[] set2string (Set<String> set) {
String [] result = new String [set.size ()];
int idx = 0;
for (String key : set)
result [idx++] = key;
return result;
}
// ======================================================================
static public JScrollPane getJScrollPane (Component view) {
return getJScrollPane (view, true, true);
}
static public JScrollPane getJScrollPane (Component view, boolean vNeed, boolean hNeed) {
return new JScrollPane (view,
vNeed ? JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED : JScrollPane.VERTICAL_SCROLLBAR_NEVER,
hNeed ? JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED : JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
}
// ========================================
static public JSplitPane getJSplitPane (int newOrientation, Component newLeftComponent, Component newRightComponent) {
JSplitPane result = new JSplitPane (newOrientation, newLeftComponent, newRightComponent);
result.setResizeWeight (0);
result.setOneTouchExpandable (true);
result.setContinuousLayout (true);
return result;
}
// ========================================
static public final void setEnabled (Component component, boolean enabled) {
component.setEnabled (enabled);
try {
for (Component component2 : ((Container) component).getComponents ())
setEnabled (component2, enabled);
} catch (Exception e) {
}
}
// ========================================
static public final GridBagConstraints
GBC, GBCNL, GBCLNL, GBCBNL;
static {
GBC = new GridBagConstraints ();
GBC.insets = new Insets (1, 2, 1, 2);
GBC.weightx = GBC.weighty = 1.;
GBC.fill = GridBagConstraints.HORIZONTAL;
GBCLNL = (GridBagConstraints) GBC.clone ();
GBCLNL.anchor = GridBagConstraints.WEST;
GBCLNL.fill = GridBagConstraints.NONE;
GBCLNL.gridwidth = GridBagConstraints.REMAINDER;
GBCNL = (GridBagConstraints) GBC.clone ();
GBCNL.gridwidth = GridBagConstraints.REMAINDER;
GBCBNL = (GridBagConstraints) GBCNL.clone ();
GBCBNL.fill = GridBagConstraints.BOTH;
}
static public JPanel getGridBagPanel () {
return new JPanel (new GridBagLayout ());
}
static public void addLabelFields (Container container, String label, Component... components) {
addLabel (label, RIGHT, container, GBC);
for (int i = 0; i < components.length; i++)
addComponent (components[i], container, i == components.length -1 ? GBCNL : GBC);
}
// ========================================
static public AbstractButton activeButton (AbstractButton button, String action, ActionListener actionListener) {
button.setActionCommand (action);
Bundle.addLocalizedActioner (button);
button.setToolTipText (Bundle.getAction (action));
Bundle.addLocalizedToolTip (button);
if (actionListener != null)
button.addActionListener (actionListener);
return button;
}
// ========================================
static public final JCheckBox newCheckIcon (String action, ActionListener actionListener) {
JCheckBox button = new JCheckBox (loadActionIcon (action+OFF));
button.setSelectedIcon (loadActionIcon (action+ON));
activeButton (button, action, actionListener);
return button;
}
static public final JCheckBox newCheckIcon (String action, ActionListener actionListener, boolean defaultValue) {
JCheckBox button = newCheckIcon (action, actionListener);
button.setSelected (defaultValue);
return button;
}
static public final JCheckBox addCheckIcon (String action, ActionListener actionListener, Container container) {
JCheckBox button = newCheckIcon (action, actionListener);
container.add (button);
return button;
}
static public final JCheckBox addCheckIcon (String action, ActionListener actionListener, boolean defaultValue, Container container) {
JCheckBox button = newCheckIcon (action, actionListener);
container.add (button);
button.setSelected (defaultValue);
return button;
}
static public final void addCheckIcon (List<String> actions, ActionListener actionListener, Container container) {
for (String action : actions)
addCheckIcon (action, actionListener, container);
}
static public final JCheckBox addCheckIcon (String action, ActionListener actionListener, boolean defaultValue,
Container container, GridBagConstraints constraint) {
JCheckBox button = newCheckIcon (action, actionListener, defaultValue);
addComponent (button, container, constraint);
return button;
}
static public void setCheckIconTableCellEditorRenderer (String action, TableColumn tableColumn) {
tableColumn.setCellRenderer (new CheckIconTableCellEditorRenderer (action));
tableColumn.setCellEditor (new DefaultCellEditor (newCheckIcon (action, null)));
}
static public class CheckIconTableCellEditorRenderer implements TableCellRenderer {
JCheckBox jCheckBox;
public CheckIconTableCellEditorRenderer (String action) {
jCheckBox = Util.newCheckIcon (action, null);
}
public Component getTableCellRendererComponent (JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
jCheckBox.setBackground (isSelected ? table.getSelectionBackground () : table.getBackground ());
jCheckBox.setForeground (isSelected ? table.getSelectionForeground () : table.getForeground ());
if (value instanceof Boolean)
jCheckBox.setSelected (((Boolean) value).booleanValue ());
return jCheckBox;
}
}
// ========================================
static public final JCheckBox newCheckButton (String action, ActionListener actionListener) {
JCheckBox button = new JCheckBox (Bundle.getAction (action), loadActionIcon (action+OFF));
button.setSelectedIcon (loadActionIcon (action+ON));
activeButton (button, action, actionListener);
return button;
}
static public final JCheckBox addCheckButton (String action, ActionListener actionListener, Container container) {
JCheckBox button = newCheckButton (action, actionListener);
container.add (button);
return button;
}
static public final void addCheckButton (List<String> actions, ActionListener actionListener, Container container) {
for (String action : actions)
addCheckButton (action, actionListener, container);
}
static public final JCheckBox addCheckButton (String action, ActionListener actionListener,
Container container, GridBagConstraints constraint) {
JCheckBox button = newCheckButton (action, actionListener);
addComponent (button, container, constraint);
return button;
}
// ========================================
static public final JCheckBox newCheckButtonConfig (String action, ActionListener actionListener, boolean defaultValue) {
boolean startValue = Config.getBoolean (action+Config.checkedPostfix, defaultValue);
JCheckBox button = newCheckButton (action, actionListener);
button.setSelected (startValue);
return button;
}
static public final JCheckBox addCheckButtonConfig (String action, ActionListener actionListener, boolean defaultValue,
Container container) {
JCheckBox button = newCheckButtonConfig (action, actionListener, defaultValue);
container.add (button);
return button;
}
static public final JCheckBox addCheckButtonConfig (String action, ActionListener actionListener, boolean defaultValue,
Container container, GridBagConstraints constraint) {
JCheckBox button = newCheckButtonConfig (action, actionListener, defaultValue);
// XXX le test suivant a été supprimer, il faut vérifier que cela tourne toujours
//if (container != null)
addComponent (button, container, constraint);
return button;
}
// ========================================
static public final JRadioButton newRadioButton (String action, ActionListener actionListener, ButtonGroup group, String selected) {
JRadioButton button = new JRadioButton (Bundle.getAction (action), loadActionIcon (action+OFF),
action.equals (selected));
button.setSelectedIcon(loadActionIcon (action+ON));
activeButton (button, action, actionListener);
group.add (button);
return button;
}
static public final void addRadioButton (List<String> actions, ActionListener actionListener, ButtonGroup group, String selected,
Container container) {
for (String action : actions) {
JRadioButton button = newRadioButton (action, actionListener, group, selected);
container.add (button);
}
}
static public final JRadioButton addRadioButton (String action, ActionListener actionListener, ButtonGroup group, String selected,
Container container, GridBagConstraints constraint) {
JRadioButton button = newRadioButton (action, actionListener, group, selected);
addComponent (button, container, constraint);
return button;
}
// ========================================
static public final JButton newButton (String action, ActionListener actionListener) {
JButton button = new JButton (Bundle.getAction (action), loadActionIcon (action));
activeButton (button, action, actionListener);
return button;
}
static public final void newButton (List<String> actions, ActionListener actionListener) {
for (String action : actions)
newButton (action, actionListener);
}
static public final JButton addButton (String action, ActionListener actionListener, Container container) {
JButton button = newButton (action, actionListener);
container.add (button);
return button;
}
static public final void addButton (List<String> actions, ActionListener actionListener, Container container) {
for (String action : actions)
addButton (action, actionListener, container);
}
static public final JButton addButton (String action, ActionListener actionListener, Container container, GridBagConstraints constraint) {
JButton button = newButton (action, actionListener);
addComponent (button, container, constraint);
return button;
}
// ========================================
static public final JButton newIconButton (String action, ActionListener actionListener) {
JButton button = new JButton (loadActionIcon (action));
button.setAlignmentX (Component.CENTER_ALIGNMENT);
activeButton (button, action, actionListener);
return button;
}
static public final void newIconButton (List<String> actions, ActionListener actionListener) {
for (String action : actions)
newIconButton (action, actionListener);
}
static public final JButton addIconButton (String action, ActionListener actionListener, Container container) {
JButton button = newIconButton (action, actionListener);
container.add (button);
return button;
}
static public final void addIconButton (List<String> actions, ActionListener actionListener, Container container) {
for (String action : actions)
addIconButton (action, actionListener, container);
}
static public final JButton addIconButton (String action, ActionListener actionListener, Container container, GridBagConstraints constraint) {
JButton button = new JButton (loadActionIcon (action));
activeButton (button, action, actionListener);
addComponent (button, container, constraint);
return button;
}
static public final void unBoxButton (Container container) {
for (AbstractButton button : collectButtons (null, container).values ())
unBoxButton (button);
}
static public final void unBoxButton (AbstractButton button) {
button.setUI (buttonNoUI);
button.setBorder (buttonNoBorder);
}
// ========================================
static public final void addMenuItem (String action, ActionListener actionListener, Container container) {
JMenuItem item = new JMenuItem (Bundle.getAction (action), loadActionIcon (action));
activeButton (item, action, actionListener);
container.add (item);
}
static public final void addMenuItem (List<String> actions, ActionListener actionListener, Container container) {
for (String action : actions)
addMenuItem (action, actionListener, container);
}
// ========================================
static public Hashtable<String, ArrayList<AbstractButton>> allCheckBox = new Hashtable<String, ArrayList<AbstractButton>> ();
static public void updateCheckBox (String action, boolean value) {
ArrayList<AbstractButton> buttons = allCheckBox.get (action);
if (buttons == null)
return;
Config.setBoolean (action+Config.checkedPostfix, value);
for (AbstractButton button : buttons)
if (button.isSelected () != value)
button.setSelected (value);
}
static public final void addCheckMenuItem (List<String> actions, ActionListener actionListener, Container container) {
for (String action : actions)
addCheckMenuItem (action, actionListener, container);
}
static public final JCheckBoxMenuItem addCheckMenuItem (String action, ActionListener actionListener, Container container) {
return addCheckMenuItem (action, actionListener, Config.getBoolean (action+Config.checkedPostfix, false), container);
}
static public final JCheckBoxMenuItem addCheckMenuItem (String action, ActionListener actionListener,
boolean defaultValue, Container container) {
boolean startValue = Config.getBoolean (action+Config.checkedPostfix, defaultValue);
JCheckBoxMenuItem item = new JCheckBoxMenuItem (Bundle.getAction (action), loadActionIcon (action+OFF), startValue);
item.setSelectedIcon (loadActionIcon (action+ON));
activeButton (item, action, actionListener);
container.add (item);
ArrayList<AbstractButton> checkList = allCheckBox.get (action);
if (checkList == null)
allCheckBox.put (action, checkList = new ArrayList<AbstractButton> ());
checkList.add (item);
return item;
}
// ========================================
static public final JMenu addJMenu (JMenuBar jMenuBar, String menuId) {
JMenu menu = new JMenu (Bundle.getTitle (menuId));
menu.setActionCommand (menuId);
Bundle.addLocalizedMenu (menu);
jMenuBar.add (menu);
return menu;
}
// ========================================
static public void addComponent (Component component, Container container, GridBagConstraints constraint) {
GridBagLayout gridbag = (GridBagLayout) container.getLayout ();
gridbag.setConstraints (component, constraint);
container.add (component);
}
// ========================================
static public final Dimension space = new Dimension (10, 10);
static public void addTextFieldSlider (JTextField textField, JLabel label, JSlider slider, Container container, GridBagConstraints constraint) {
JPanel panel = getGridBagPanel ();
addComponent (textField, panel, GBC);
addComponent (label, panel, GBC);
addComponent (slider, panel, GBCBNL);
addComponent (panel, container, constraint);
}
// ========================================
static public JLabel newLabel (String messageId, int position) {
JLabel jLabel = new JLabel (Bundle.getLabel (messageId), position);
Bundle.addLocalizedLabel (jLabel, messageId);
return jLabel;
}
// ========================================
static public JLabel addLabel (String messageId, int position, Container container) {
JLabel jLabel = newLabel (messageId, position);
container.add (jLabel);
return jLabel;
}
// ========================================
static public JLabel addLabel (String messageId, int position, Container container, GridBagConstraints constraint) {
JLabel jLabel = newLabel (messageId, position);
addComponent (jLabel, container, constraint);
return jLabel;
}
// ========================================
static public JComboBox<String> newEnum (Class<? extends Enum<?>> enumClass, Enum<?> defaultValue) {
JComboBox<String> jComboBox = Bundle.getEnum (enumClass, defaultValue);
Bundle.addLocalizedEnum (jComboBox, enumClass);
return jComboBox;
}
// ========================================
static public JComboBox<String> addEnum (Class<? extends Enum<?>> enumClass, Enum<?> defaultValue, Container container) {
JComboBox<String> jComboBox = newEnum (enumClass, defaultValue);
container.add (jComboBox);
return jComboBox;
}
// ========================================
static public JComboBox<String> addEnum (Class<? extends Enum<?>> enumClass, Enum<?> defaultValue, Container container, GridBagConstraints constraint) {
JComboBox<String> jComboBox = newEnum (enumClass, defaultValue);
addComponent (jComboBox, container, constraint);
return jComboBox;
}
// ========================================
static public final void setColumnLabels (JTable jTable, String [] columnLabels) {
for (int i = 0; i < columnLabels.length; i++)
jTable.getColumnModel ().getColumn (i).setHeaderValue (Bundle.getLabel (columnLabels [i]));
try {
Container parent = jTable.getParent ();
parent.repaint ();
} catch (Exception e) {
}
}
static public int viewToModel (JTable table, int vColIndex) {
if (vColIndex >= table.getColumnCount()) {
return -1;
}
return table.getColumnModel ().getColumn (vColIndex).getModelIndex ();
}
public int modelToView (JTable table, int mColIndex) {
for (int c = 0; c < table.getColumnCount (); c++) {
TableColumn col = table.getColumnModel ().getColumn (c);
if (col.getModelIndex () == mColIndex) {
return c;
}
}
return -1;
}
// ========================================
static public boolean packBug = false;
static public final void packWindow (final Component startComponent) {
if (packBug)
return;
SwingUtilities.invokeLater (new Runnable() {
public void run () {
for (Component component = startComponent;
component != null;
component = component.getParent ()) {
try {
((Window) component).pack ();
return;
} catch (Exception e) {
}
}
}
});
}
// ========================================
static public final JFrame newJFrame (String title, Component component, boolean exit) {
JFrame jFrame = new JFrame (title);
jFrame.addWindowListener (new WindowAdapter () {
public void windowClosing (WindowEvent e) {
if (exit)
System.exit (0);
jFrame.setVisible (false);
}
});
jFrame.getContentPane ().add (component, BorderLayout.CENTER);
jFrame.pack ();
jFrame.setLocationRelativeTo (null);
jFrame.setVisible (true);
return jFrame;
}
// ========================================
static public ImageIcon loadActionIcon (String action) {
return loadImageIcon (Config.dataDirname, Config.iconsDirname, Config.buttonDirname, action+Config.iconsExt);
}
// ========================================
static public ImageIcon loadImageIcon (String... names) {
URL url = Config.getDataUrl (names);
return (url != null) ? new ImageIcon (url) : null;
}
// ========================================
static public Image loadImage (String... names) {
try {
return loadImageIcon (names).getImage ();
} catch (Exception e) {
return null;
}
}
// ========================================
static public final AudioInputStream loadAudio (String... names) {
URL url = Config.getDataUrl (names);
try {
return AudioSystem.getAudioInputStream (url);
} catch (Exception e) {
return null;
}
}
static public final void play (AudioInputStream stream) {
if (stream == null)
return;
try {
AudioFormat format = stream.getFormat ();
DataLine.Info info = new DataLine.Info (Clip.class, format);
Clip clip = (Clip) AudioSystem.getLine (info);
clip.open (stream);
clip.addLineListener (new LineListener () {
public void update (LineEvent event) {
LineEvent.Type type = event.getType();
if (type == LineEvent.Type.START) {
// System.err.println ("Playback started.");
} else if (type == LineEvent.Type.STOP) {
// System.er.println ("Playback completed.");
clip.close ();
}
}
});
clip.start ();
} catch (LineUnavailableException e) {
Log.keepLastException ("Audio line for playing back is unavailable", e);
} catch (IOException e) {
Log.keepLastException ("Error playing the audio file", e);
}
}
// ========================================
@SuppressWarnings({"rawtypes", "unchecked"})
static public final Hashtable<String, Method> collectMethod (Class javaClass, List<String>... actions) {
Hashtable<String, Method> actionsMethod = new Hashtable<String, Method> ();
for (List<String> arg : actions)
for (String action : arg) {
try {
actionsMethod.put (action, javaClass.getMethod ("action"+action));
} catch (NoSuchMethodException e) {
try {
actionsMethod.put (action, javaClass.getMethod ("action"+action, new Class<?>[] { boolean.class }));
} catch (NoSuchMethodException e1) {
Log.keepLastException ("Util::collectMethod can't find methode "+"action"+action, e1);
e.printStackTrace ();
}
}
}
return actionsMethod;
}
// ========================================
static public final Hashtable<String, AbstractButton> collectButtons (Hashtable<String, AbstractButton> buttons, JMenu jMenu) {
if (buttons == null)
buttons = new Hashtable<String, AbstractButton> ();
for (int i = 0; i < jMenu.getItemCount (); i++) {
try {
AbstractButton button = jMenu.getItem (i);
buttons.put (button.getActionCommand (), button);
} catch (Exception e) {
}
}
return buttons;
}
static public class ActionControl {
String action;
int key;
boolean control;
public ActionControl (String action, int key) {
this (action, key, true);
}
public ActionControl (String action, int key, boolean control) {
this.action = action;
this.key = key;
this.control = control;
}
}
static public void setAccelerator (Hashtable<String, AbstractButton> buttons, ActionControl... actionsControl) {
for (ActionControl actionControl : actionsControl)
((JMenuItem) buttons.get (actionControl.action)).setAccelerator (KeyStroke.getKeyStroke (actionControl.key, actionControl.control ? InputEvent.CTRL_DOWN_MASK : 0));
}
// ========================================
static public final Hashtable<String, AbstractButton> collectButtons (Hashtable<String, AbstractButton> buttons, Container container) {
if (buttons == null)
buttons = new Hashtable<String, AbstractButton> ();
for (Component component : container.getComponents ()) {
try {
AbstractButton button = (AbstractButton) component;
buttons.put (button.getActionCommand (), button);
} catch (Exception e) {
}
}
return buttons;
}
// ========================================
@SuppressWarnings("rawtypes")
static public final void actionPerformed (final Hashtable<String, Method> actionsMethod, ActionEvent e, final Object object) {
String cmd = null;
try {
final Object source = e.getSource ();
if (source instanceof AbstractButton)
cmd = ((AbstractButton) source).getActionCommand ();
else if (source instanceof JComboBox)
cmd = ((JComboBox) source).getActionCommand ();
final String cmd2 = cmd;
if (cmd2 != null)
SwingUtilities.invokeLater (new Runnable() {
public void run () {
if (source instanceof JCheckBoxMenuItem) {
try {
boolean value = ((JCheckBoxMenuItem) source).isSelected ();
actionsMethod.get (cmd2).invoke (object, value);
updateCheckBox (cmd2, value);
return;
} catch (IllegalArgumentException e2) {
} catch (Exception e1) {
Log.keepLastException ("Util::actionPerformed (action "+cmd2+" on "+object+")", e1);
return;
}
}
try {
actionsMethod.get (cmd2).invoke (object);
} catch (Exception e1) {
Log.keepLastException ("Util::actionPerformed (action "+cmd2+" on "+object+")", e1);
}
}
});
} catch (Exception e2) {
e2.printStackTrace ();
Log.keepLastException ("Util::actionPerformed (action "+cmd+" on "+object+")", e2);
}
}
// ========================================
@SuppressWarnings("unchecked")
static public List<String> merge (List<String>... args) {
List<String> result = new ArrayList<String> ();
for (List<String> arg : args)
result.addAll (arg);
return result;
}
// ========================================
// static public File checkExt (File file, String ext) {
// try {
// String fileExt = file.getName ();
// fileExt = fileExt.substring (fileExt.lastIndexOf (".")).toLowerCase ();
// if (ext.toLowerCase ().equals (fileExt))
// return file;
// } catch (Exception e) {
// }
// return new File (file.getParent (), file.getName ()+ext);
// }
static public String getExtention (File file) {
return getExtention (file.getName ());
}
static public String getExtention (String filename) {
try {
filename = filename.substring (filename.lastIndexOf (".")).toLowerCase ();
return filename.substring (1);
} catch (Exception e) {
return null;
}
}
static public String getBase (File file) {
return getBase (file.getName ());
}
static public String getBase (String filename) {
try {
return filename.substring (0, filename.lastIndexOf ("."));
} catch (Exception e) {
return filename;
}
}
static public String changeExtention (String filename, String extention) {
try {
return filename.substring (0, filename.lastIndexOf ("."))+"."+extention;
} catch (Exception e) {
return filename+"."+extention;
}
}
// ========================================
static public void backup (File file, String extention, String backExtention) {
if (!file.exists ())
return;
String newFileName = file.getName ();
if (newFileName.endsWith ("."+extention))
newFileName = newFileName.substring (0, newFileName.length () - ("."+extention).length ());
File backFile = new File (file.getParent (), newFileName+"."+backExtention);
backFile.delete ();
try {
Files.move (file.toPath (), backFile.toPath (), StandardCopyOption.REPLACE_EXISTING);
} catch (Exception e) {
}
}
// ========================================
static public void copy (InputStream src, OutputStream dst, byte[] tmp, ProgressState progressState)
throws IOException {
copy (src, dst, tmp, progressState, true, true);
}
static public void copy (InputStream src, OutputStream dst, byte[] tmp, ProgressState progressState, boolean srcClose, boolean dstClose)
throws IOException {
try {
if (tmp == null)
tmp = new byte[bufSize];
for (;;) {
if (progressState != null && progressState.isInterrupted ())
return;
int nbRead = src.read (tmp, 0, tmp.length);
if (nbRead < 0)
break;
dst.write (tmp, 0, nbRead);
if (progressState != null && !progressState.addValue (nbRead))
return;
}
} finally {
dst.flush ();
try {
if (dstClose)
dst.close ();
if (srcClose)
src.close ();
} catch (Exception e) {
}
}
}
// ========================================
static public final String ctrlName (String s) {
return s.replaceAll ("[^0-9a-zA-Z_\\-.]", "");
}
// ========================================
static public final String toCapital (final String s) {
return s.substring (0, 1).toUpperCase ()+s.substring (1).toLowerCase ();
}
static public final<T> boolean containsOne (Collection<T> set1, Collection<T> set2) {
try {
if (set1.size () > set2.size ()) {
Collection<T> tmp = set1;
set1 = set2;
set2 = tmp;
}
for (T e : set1)
if (set2.contains (e))
return true;
} catch (Exception e) {
}
return false;
}
static public final boolean containsPart (String subString, Collection<String> set) {
if (set == null)
return false;
for (String s : set)
if (s.indexOf (subString) >= 0)
return true;
return false;
}
// ========================================
@SuppressWarnings("rawtypes")
static public final String getClassName (final Class aClass) {
String[] path = aClass.getName ().split ("\\.");
return path [path.length-1];
}
// ========================================
/**
retourne vrai si s1 existe et est égale à s2
*/
static public boolean cmp (String s1, String s2) {
return (s1 == s2) || ((s1 != null) && (s1.equals (s2)));
}
// ========================================
static int max (int... values) {
int result = 0;
for (int val : values)
result = Math.max (result, val);
return result;
}
// ========================================
static public void sleep (int s) {
try {
Thread.sleep (s*1000);
} catch (InterruptedException e) {
}
}
// ========================================
static public void deciSleep (int s) {
try {
Thread.sleep (s*100);
} catch (InterruptedException e) {
}
}
// ========================================
static private String convertToHex (byte[] data) {
StringBuffer buf = new StringBuffer ();
for (int i = 0; i < data.length; i++) {
int halfbyte = (data[i] >>> 4) & 0x0F;
int two_halfs = 0;
do {
if ((0 <= halfbyte) && (halfbyte <= 9))
buf.append ((char) ('0' + halfbyte));
else
buf.append ((char) ('a' + (halfbyte - 10)));
halfbyte = data[i] & 0x0F;
} while (two_halfs++ < 1);
}
return buf.toString ();
}
public static String removeAccent (String source) {
return Normalizer.normalize (source, Normalizer.Form.NFD).replaceAll ("[\u0300-\u036F]", "");
}
static public String sha1 (String text)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest md;
md = MessageDigest.getInstance ("SHA-1");
byte[] sha1hash = new byte[40];
md.update (text.getBytes ("iso-8859-1"), 0, text.length ());
sha1hash = md.digest ();
return convertToHex (sha1hash);
}
// ========================================
}

114
src/java/misc/XML.java Normal file
View File

@ -0,0 +1,114 @@
package misc;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Hashtable;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
public class XML {
// ========================================
/** une idée de Kohsuke Kawaguchi
http://weblogs.java.net/blog/kohsuke/archive/2005/07/socket_xml_pitf.html */
static public class NoWaittingNoCloseInputStream extends java.io.FilterInputStream {
public NoWaittingNoCloseInputStream (InputStream in) { super (in); }
public int read (byte[] b, int off, int len) throws IOException {
if (super.available () <= 0)
return -1;
int nb = super.read (b, off, len);
return nb;
}
public void close () throws IOException {}
}
// ========================================
static public Document readDocument (InputStream stream)
throws java.io.IOException {
try {
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance ().newDocumentBuilder ();
Document document = documentBuilder.parse (new NoWaittingNoCloseInputStream (stream));
document.normalizeDocument ();
return document;
} catch (javax.xml.parsers.ParserConfigurationException e) {
throw new IOException (e);
} catch (org.xml.sax.SAXException e) {
throw new IOException (e);
}
}
// ========================================
static public void writeDocument (Document document, OutputStream stream) {
try {
Source source = new DOMSource (document);
Result result = new StreamResult (stream);
Transformer xformer = TransformerFactory.newInstance ().newTransformer ();
xformer.setOutputProperty (OutputKeys.INDENT, "yes");
xformer.setOutputProperty ("{http://xml.apache.org/xslt}indent-amount", "2");
xformer.transform (source, result);
stream.write ("\n".getBytes ());
stream.flush ();
} catch (Exception e) {
Log.keepLastException ("XML::writeDocument", e);
}
}
// ========================================
static public void writeElement (Element element, OutputStream stream) {
try {
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance ().newDocumentBuilder ();
Document document = documentBuilder.newDocument ();
document.setXmlStandalone (true);
document.appendChild (document.importNode (element, true));
XML.writeDocument (document, stream);
stream.flush ();
} catch (Exception e) {
Log.keepLastException ("XML::writeElement", e);
}
}
// ========================================
static public final void putToken (Hashtable<String, String> hashtable, String token, String value) {
hashtable.put (token, (value == null) ? "" : value);
}
// ========================================
static public final Hashtable<String, String> node2hashtable (Node child) {
Hashtable<String, String> hashtable = new Hashtable<String, String> ();
for (; child != null; child = child.getNextSibling ()) {
if (child.getNodeType () == Node.ELEMENT_NODE) {
Element elementTag = (Element) child;
String token = child.getNodeName ();
NodeList nodeList = ((Element) child).getChildNodes ();
if (nodeList.getLength () > 0)
hashtable.put (token, ((Text) nodeList.item (0)).getWholeText ());
}
}
return hashtable;
}
// ========================================
static public final void hashtable2node (Document document, Element container, Hashtable<String, String> hashtable) {
for (String token : hashtable.keySet ()) {
Element tag = document.createElement (token);
tag.appendChild (document.createTextNode (hashtable.get (token)));
container.appendChild (tag);
}
}
// ========================================
}

View File

@ -0,0 +1,34 @@
/**
* Ordre de lecture des classes<ul>
* <li>Log</li>
* <li>Config</li>
* <li>Bundle</li>
* <li>Util</li>
* <li>StateNotifier</li>
* <li>ProgressState</li>
* <li>SpinnerSlider</li>
* <li>DatePanel</li>
* <li>HourPanel</li>
* <li>ImagePreview</li>
* <li>TitledDialog</li>
* <li>HtmlDialog</li>
* <li>ApplicationManager</li>
* <li>OwnFrame</li>
* <li>Controller</li>
* <li>HelpManager</li>
* <li>ToolBarManager</li>
* <li>Guide</li>
* <li>XML</li>
* <li>ColorCheckedLine</li>
* <li>CommandLineServer</li>
* <li>CommandLineWaiter</li>
* </ul>
* @author F. Merciol
*/
package misc;

View File

@ -0,0 +1,147 @@
package network;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import org.w3c.dom.Element;
import misc.Log;
import misc.XML;
public class Client extends Protocol {
// ========================================
static public final boolean trace = false;
static public final boolean socketNotURL = false;
// ========================================
private String host;
private int port;
private String uri = "/";
private Proxy proxy;
// ========================================
public Client (String host, int port) {
super (ClientProtocolType);
this.host = host;
this.port = port;
}
public Client (String host, int port, String uri) {
this (host, port);
this.uri = uri;
}
public Client (String host, int port, String uri, String proxyHost, int proxyPort) {
this (host, port, uri);
proxy = new Proxy (Proxy.Type.HTTP, new InetSocketAddress (proxyHost, proxyPort));
if (trace)
System.err.println (type+": proxy: "+proxy.address ());
}
public Client (String host, int port, String proxyHost, int proxyPort) {
this (host, port, "/", proxyHost, proxyPort);
}
// ========================================
public void start () {
(new Thread () {
public void run () {
Log.writeLog ("Protocol", "Client started pulling to "+host+":"+port+"("+proxy+")");
for (currentThread = Thread.currentThread (); currentThread == Thread.currentThread (); ) {
long startTime = System.currentTimeMillis ();
try {
// XXX prendre la date
Log.writeLog ("Protocol", "client connected to "+host+":"+port+"("+proxy+")");
URLConnection call = XMLConnection.getXMLConnection (new URL ("http", host, port, uri), proxy);
exchangeXML (call, true);
} catch (IOException e) {
// include : ConnectException, MalformedURLException, UnknownHostException
long stopTime = System.currentTimeMillis ();
if (stopTime - startTime < 1000) {
Log.keepLastException ("Client::start", e);
break;
}
// XXX si date trop courte sortir de la boucle
System.err.println ("coucou:"+e);
}
}
Log.writeLog ("Protocol", "Client stopped pulling to "+host+":"+port+"("+proxy+")");
}
}).start ();
}
// ========================================
public synchronized void send (String applicationName, Element applicationArgument) {
super.send (applicationName, applicationArgument);
if (trace)
System.err.println (type+":send: immediat send "+applicationName);
// puis force l'envoie immediat
(new Thread () {
public void run () {
try {
Log.writeLog ("Protocol", "client connected to "+host+":"+port+"("+proxy+")");
URLConnection call = XMLConnection.getXMLConnection (new URL ("http", host, port, uri), proxy);
exchangeXML (call, false);
} catch (IOException e) {
//} catch (UnknownHostException e) {
Log.keepLastException ("Client::send", e);
}
}
}).start ();
}
// ========================================
private void exchangeXML (URLConnection urlConnection, boolean askWaiting)
throws IOException {
OutputStream out = urlConnection.getOutputStream ();
PendingRequest pendingRequest = getPendingRequest ();
if (askWaiting)
pendingRequest.request.getDocumentElement ().setAttribute (waitAnswerToken, "yes");
XML.writeDocument (pendingRequest.request, out);
out.flush ();
out.close ();
InputStream in = urlConnection.getInputStream ();
Element bundle = getBundle (in);
in.close ();
broadcastApplications (bundle);
}
// ========================================
private PendingRequest pendingRequest = new PendingRequest ();
// ========================================
private synchronized PendingRequest getPendingRequest () {
if (trace)
System.err.println (type+":getPendingRequest:");
PendingRequest old = pendingRequest;
pendingRequest = new PendingRequest ();
return old;
}
// ========================================
protected void addPendingApplication (String applicationName, Element applicationArgument) {
Element applicationNode = pendingRequest.request.createElement (applicationToken);
applicationNode.setAttribute (nameToken, applicationName);
if (applicationArgument != null)
applicationNode.appendChild (pendingRequest.request.importNode (applicationArgument, true));
pendingRequest.localPaquet.appendChild (applicationNode);
pendingRequest.readyToSend = true;
if (trace) {
System.err.println (type+":addPendingApplication: ");
XML.writeDocument (pendingRequest.request, System.err);
System.err.flush ();
}
}
// ========================================
}

View File

@ -0,0 +1,61 @@
package network;
import java.io.IOException;
import java.io.InputStream;
import java.io.FilterInputStream;
import java.util.Hashtable;
public class HTTPInputStream extends FilterInputStream {
// ========================================
public String command;
public Hashtable<String, String> headers = new Hashtable<String, String> ();
private String lastHeader;
// ========================================
public HTTPInputStream (InputStream in)
throws IOException {
super (in);
parseHeaders ();
}
// ========================================
private void parseHeaders ()
throws IOException {
for (;;) {
String line = readLine ();
if (line.equals ("")) {
break;
}
int pos = line.indexOf (":");
if (pos < 0) {
if (lastHeader == null)
command = line;
else
throw new IllegalArgumentException (line+" is not a mime line");
} else {
lastHeader = line.substring (0, pos).trim ();
headers.put (lastHeader, line.substring (pos+1).trim ());
}
}
}
// ========================================
public String readLine ()
throws IOException {
StringBuffer result = new StringBuffer ();
for (;;) {
int c = super.read ();
if (c < 0)
break;
if (c == '\r')
continue;
if (c == '\n')
break;
result.append ((char) c);
}
return result.toString ();
}
// ========================================
}

View File

@ -0,0 +1,49 @@
package network;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
public class HTTPOutputStream extends ByteArrayOutputStream {
// ========================================
private static SimpleDateFormat dateFormat = new SimpleDateFormat ("EEE, d MMM yyyy HH:mm:ss z");
// ========================================
private OutputStream out;
private String status = "HTTP/1.0 200 OK";
public Hashtable<String, String> headers = new Hashtable<String, String> ();
// ========================================
public HTTPOutputStream (OutputStream out) {
this.out = out;
headers.put ("Server", "Merciol");
headers.put ("Date", dateFormat.format (new Date ()));
headers.put ("Content-Type", "text/html");
headers.put ("Connection", "close");
}
public void setStatus (String status) {
this.status = status;
}
public void setHeader (String key, String value) {
headers.put (key, value);
}
public void close ()
throws IOException {
out.write ((status+"\n").getBytes ());
for (String key : headers.keySet ()) {
out.write ((key+": "+headers.get (key)+"\n").getBytes ());
}
out.write (("Content-Length: "+size ()+"\n").getBytes ());
out.write ("\n".getBytes ());
writeTo (out);
}
// ========================================
}

View File

@ -0,0 +1,225 @@
package network;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.List;
import java.util.Random;
import java.util.Vector;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import misc.Log;
import misc.XML;
/**
<bundle waitAnswer="yes">
<paquet pearId="XXXXXXXX">
<application name="chat">
<argument date="HH:MM:SS" speudo="inconnu_XXXX">msg</argument>
</application>
</paquet>
</bundle>
*/
public abstract class Protocol {
// remplace <jvmarg value="-Djava.net.preferIPv4Stack=true"/>
// a placer avant la création de socket dans le cas ou elle n'a pas déjà été fait avant l'utilisation de X11 (via swing)
static public final void setIpV4 () {
java.util.Properties props = System.getProperties ();
props.setProperty ("java.net.preferIPv4Stack", ""+true);
System.setProperties (props);
}
static {
setIpV4 ();
}
// ========================================
static public final boolean trace = false;
static public final String bundleToken = "bundle";
static public final String waitAnswerToken = "waitAnswer";
static public final String paquetToken = "paquet";
static public final String pearIdToken = "pearId";
static public final String applicationToken = "application";
static public final String nameToken = "name";
static public final String argumentToken = "argument";
// ========================================
static public final String ServerProtocolType = "ServerProtocol";
static public final String ClientProtocolType = "ClientProtocol";
/** socket, serverHTTP or clientHTTP */
protected String type;
public String getType () { return type; }
protected final String pearId = Long.toHexString ((new Random ()).nextLong ()).toUpperCase ();
public Protocol (String type) {
this.type = type;
if (trace)
System.err.println (type+":pearId: "+pearId);
}
// ========================================
protected Thread currentThread;
public abstract void start ();
public synchronized boolean isAlive () {
return currentThread != null && currentThread.isAlive ();
}
public void stop () {
currentThread = null;
}
// ========================================
public class PendingRequest {
public Document request;
public Element bundle;
public Element localPaquet;
public boolean readyToSend;
public PendingRequest () {
try {
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance ().newDocumentBuilder ();
request = documentBuilder.newDocument ();
request.setXmlStandalone (true);
bundle = request.createElement (bundleToken);
request.appendChild (bundle);
localPaquet = request.createElement (paquetToken);
localPaquet.setAttribute (pearIdToken, pearId);
bundle.appendChild (localPaquet);
} catch (ParserConfigurationException e) {
Log.keepLastException ("Protocol::PendingRequest", e);
}
}
}
// ========================================
static public Element getBundle (InputStream in)
throws IOException {
Document request = null;
request = XML.readDocument (in);
if (trace) {
System.err.println ("Protocol:getBundle: ");
XML.writeDocument (request, System.err);
System.err.flush ();
}
return request.getDocumentElement ();
}
// ========================================
protected void broadcastApplication (final String applicationName, final Element applicationArgument) {
Vector<Waiter> waiters = namedWaiters.get (applicationName);
if (waiters == null) {
if (trace)
Log.writeLog ("Protocol", "no "+applicationName+" application registered for "+type);
return;
}
for (final Waiter waiter : waiters)
(new Thread () {
public void run () {
if (trace)
System.err.println (type+" start "+applicationName);
waiter.receive (applicationArgument);
}
}).start ();
}
// ========================================
// c'est la réception
protected synchronized void broadcastApplications (Element bundle) {
NodeList paquets = bundle.getElementsByTagName (paquetToken);
for (int i = paquets.getLength () - 1; i >= 0; i--) {
Element paquet = (Element) paquets.item (i);
NodeList applications = paquet.getElementsByTagName (applicationToken);
for (int j = applications.getLength () - 1; j >= 0; j--) {
Element application = (Element) applications.item (j);
String applicationName = application.getAttribute (nameToken);
NodeList applicationArguments = application.getElementsByTagName (argumentToken);
if (applicationArguments.getLength () > 1)
throw new IllegalArgumentException ("too many argument for application "+applicationName);
broadcastApplication (applicationName, (Element) applicationArguments.item (0));
}
}
}
// ========================================
abstract protected void addPendingApplication (String applicationName, Element applicationArgument);
// ========================================
// gestion des applications
// ========================================
private Hashtable<String, Vector<Waiter>> namedWaiters = new Hashtable<String, Vector<Waiter>> ();
public synchronized void addWaiter (String applicationName, Waiter waiter) {
if (trace)
System.err.println (type+" addWaiter: "+applicationName+" waiter:"+waiter);
if (waiter == null)
return;
Vector<Waiter> waiters = namedWaiters.get (applicationName);
if (waiters == null) {
waiters = new Vector<Waiter> ();
namedWaiters.put (applicationName, waiters);
}
if (! waiters.contains (waiter))
waiters.add (waiter);
}
public synchronized void removeWaiter (String applicationName, Waiter waiter) {
if (trace)
System.err.println (type+" removeWaiter: "+applicationName+" waiter:"+waiter);
if (waiter == null)
return;
Vector<Waiter> waiters = namedWaiters.get (applicationName);
if (waiters == null)
return;
waiters.remove (waiter);
if (waiters.size () < 1)
namedWaiters.remove (applicationName);
}
// ========================================
// c'est l'envoi
public synchronized void send (String applicationName, Element applicationArgument) {
if (trace)
System.err.println (type+": send "+applicationName);
addPendingApplication (applicationName, applicationArgument);
}
// ========================================
// c'est l'envoi
public synchronized void send (String applicationName, String... args) {
if (trace)
System.err.print (type+": send "+applicationName);
Element applicationArgument = createArgument ();
for (int i = 0; i < args.length; i += 2) {
if (trace)
System.err.print (" "+args[i]+"=\""+args[i+1]+"\"");
applicationArgument.setAttribute (args[i], args[i+1]);
}
if (trace)
System.err.println ();
send (applicationName, applicationArgument);
}
// ========================================
static public Element createArgument () {
try {
Document document = DocumentBuilderFactory.newInstance ().newDocumentBuilder ().newDocument ();
return document.createElement (argumentToken);
} catch (ParserConfigurationException e) {
return null;
}
}
// ========================================
}

View File

@ -0,0 +1,318 @@
package network;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.TreeSet;
import java.util.Vector;
import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingConstants;
import misc.ApplicationManager;
import misc.Bundle;
import misc.Config;
import misc.OwnFrame;
import misc.Util;
import static misc.Util.GBC;
import static misc.Util.GBCNL;
@SuppressWarnings ("serial") public class ProtocolManager implements ApplicationManager, ActionListener {
// ========================================
private OwnFrame controller;
private Protocol protocol;
private JPanel protoPanel;
private ButtonGroup group = new ButtonGroup ();
private JComboBox<String> nsHostCB;
private JComboBox<String> hostCB;
private JComboBox<Integer> portCB;
private JComboBox<String> uriCB;
private JCheckBox proxyCheckBox;
private JComboBox<String> proxyHostCB;
private JComboBox<Integer> proxyPortCB;
public Protocol getProtocol () { return protocol; }
public void setProtocol (Protocol protocol) {
if (this.protocol != null)
this.protocol.stop ();
this.protocol = protocol;
if (protocol != null)
protocol.start ();
Thread.yield ();
updateCommands ();
updateProtocol ();
broadcastStartProtocol ();
}
// ========================================
public ProtocolManager (OwnFrame controller) {
this.controller = controller;
createGUI ();
start ();
}
// ========================================
protected Thread currentThread;
public void stop () {
currentThread = null;
}
public void start () {
(new Thread () {
public void run () {
for (currentThread = Thread.currentThread (); currentThread == Thread.currentThread (); ) {
updateCommands ();
Util.sleep (5);
}
}
}).start ();
}
// ========================================
public void createGUI () {
final TreeSet<String> hosts = new TreeSet<String> ();
hosts.add ("localhost");
nsHostCB = new JComboBox<String> (new Vector<String> (hosts));
nsHostCB.setSelectedItem ("localhost");
(new Thread () {
public void run () {
try {
for (Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces (); e.hasMoreElements (); ) {
NetworkInterface ni = e.nextElement ();
for (Enumeration<InetAddress> e2 = ni.getInetAddresses (); e2.hasMoreElements (); ) {
InetAddress ia = e2.nextElement ();
for (String host : Arrays.asList (ia.getHostAddress (), ia.getHostName ()))
if (!hosts.contains (host)) {
nsHostCB.addItem (host);
hosts.add (host);
}
}
}
} catch (Exception e3) {
}
}
}).start ();
hostCB = new JComboBox<String> ();
portCB = new JComboBox<Integer> ();
uriCB = new JComboBox<String> ();
proxyHostCB = new JComboBox<String> ();
proxyPortCB = new JComboBox<Integer> ();
Config.loadJComboBox ("hostProtocol", hostCB, "localhost");
Config.loadJComboBoxInteger ("portProtocol", portCB, "8080");
Config.loadJComboBox ("uriProtocol", uriCB, "/");
Config.loadJComboBox ("hostProxy", proxyHostCB, "localhost");
Config.loadJComboBoxInteger ("portProxy", proxyPortCB, "3128");
hostCB.setEditable (true);
portCB.setEditable (true);
uriCB.setEditable (true);
proxyHostCB.setEditable (true);
proxyPortCB.setEditable (true);
String protocolType = Config.getString (protocolTypeToken, setServerToken);
protoPanel = Util.getGridBagPanel ();
Util.addLabelFields (protoPanel, "AvailableNetworkCard", nsHostCB);
Util.addLabel ("ConnectionType", SwingConstants.CENTER, protoPanel, GBCNL);
Util.addRadioButton (setServerToken, this, group, protocolType, protoPanel, GBC);
Util.addComponent (hostCB, protoPanel, GBC);
Util.addComponent (new JLabel (":"), protoPanel, GBC);
Util.addComponent (portCB, protoPanel, GBCNL);
Util.addRadioButton (setClientToken, this, group, protocolType, protoPanel, GBC);
Util.addComponent (uriCB, protoPanel, GBCNL);
proxyCheckBox = Util.addCheckButtonConfig (setProxyToken, this, false, protoPanel, GBC);
Util.addComponent (proxyHostCB, protoPanel, GBC);
Util.addComponent (new JLabel (":"), protoPanel, GBC);
Util.addComponent (proxyPortCB, protoPanel, GBCNL);
Util.addComponent (new JLabel (), protoPanel, GBCNL);
Util.addRadioButton (unsetProtocolToken, this, group, protocolType, protoPanel, GBC);
Util.addComponent (new JLabel (), protoPanel, GBCNL);
if (unsetProtocolToken.equals (protocolType))
actionUnsetProtocol ();
else if (setClientToken.equals (protocolType))
actionSetClient ();
else
actionSetServer ();
}
// ========================================
static public final List<String> actionsNames = Arrays.asList ("LinkType");
static public final String protocolTypeToken = "ProtocolType";
static public final String setServerToken = "SetServer";
static public final String setClientToken = "SetClient";
static public final String unsetProtocolToken = "UnsetProtocol";
static public final List<String> typeActionsNames =
Arrays.asList (setClientToken, setServerToken, unsetProtocolToken);
static public final String setProxyToken = "SetProxy";
@SuppressWarnings("unchecked")
static public final Hashtable<String, Method> actionsMethod =
Util.collectMethod (ProtocolManager.class,
Util.merge (actionsNames, typeActionsNames,
Arrays.asList (setProxyToken)));
public void actionPerformed (ActionEvent e) {
Util.actionPerformed (actionsMethod, e, this);
}
// ========================================
public synchronized void setIPEnable (boolean enable) {
hostCB.setEnabled (enable);
portCB.setEnabled (enable);
uriCB.setEnabled (enable);
proxyCheckBox.setEnabled (enable);
}
public synchronized void setProxyEnable (boolean enable) {
proxyHostCB.setEnabled (enable);
proxyPortCB.setEnabled (enable);
}
// ========================================
public synchronized void actionSetServer () {
setIPEnable (false);
portCB.setEnabled (true);
setProxyEnable (false);
}
public synchronized void actionSetClient () {
setIPEnable (true);
actionSetProxy ();
}
public synchronized void actionSetProxy () {
boolean selected = proxyCheckBox.isSelected ();
Config.setBoolean (setProxyToken+Config.checkedPostfix, selected);
setProxyEnable (selected);
}
public synchronized void actionUnsetProtocol () {
setIPEnable (false);
setProxyEnable (false);
}
// ========================================
public synchronized void actionLinkType () {
if (JOptionPane.OK_OPTION !=
JOptionPane.showConfirmDialog (controller.getJFrame (), protoPanel,
Bundle.getTitle ("LinkType"),
JOptionPane.OK_CANCEL_OPTION))
return;
String protocolType = group.getSelection ().getActionCommand ();
Config.setString (protocolTypeToken, protocolType);
Config.saveJComboBox ("hostProtocol", hostCB);
Config.saveJComboBoxInteger ("portProtocol", portCB);
Config.saveJComboBox ("uriProtocol", uriCB);
Config.saveJComboBox ("hostProxy", proxyHostCB);
Config.saveJComboBoxInteger ("portProxy", proxyPortCB);
Protocol protocol = null;
if (unsetProtocolToken.equals (protocolType))
;
} else if (setClientToken.equals (protocolType)) {
if (proxyCheckBox.isSelected ())
protocol = new Client (hostCB.getItemAt (hostCB.getSelectedIndex ()),
portCB.getItemAt (portCB.getSelectedIndex ()),
uriCB.getItemAt (uriCB.getSelectedIndex ()),
proxyHostCB.getItemAt (proxyHostCB.getSelectedIndex ()),
proxyPortCB.getItemAt (proxyPortCB.getSelectedIndex ()));
else
protocol = new Client (hostCB.getItemAt (hostCB.getSelectedIndex ()),
portCB.getItemAt (portCB.getSelectedIndex ()),
uriCB.getItemAt (uriCB.getSelectedIndex ()));
} else if (setServerToken.equals (protocolType))
protocol = new Server (portCB.getItemAt (portCB.getSelectedIndex ()));
setProtocol (protocol);
}
// ========================================
private Vector<AbstractButton> noNetworkCommands = new Vector<AbstractButton> ();
public synchronized void addNoNetworkCommand (AbstractButton noNetworkCommand) {
if (noNetworkCommand == null)
return;
boolean isAlive = protocol != null && protocol.isAlive ();
noNetworkCommands.add (noNetworkCommand);
noNetworkCommand.setEnabled (!isAlive);
}
public synchronized void updateCommands () {
boolean isAlive = protocol != null && protocol.isAlive ();
for (AbstractButton noNetworkCommand : noNetworkCommands)
noNetworkCommand.setEnabled (!isAlive);
}
// ========================================
private Vector<Waiter> waiters = new Vector<Waiter> ();
public synchronized void addWaiter (Waiter waiter) {
waiters.add (waiter);
}
public synchronized void updateProtocol () {
for (Waiter waiter : waiters)
waiter.setProtocol (protocol);
}
// ========================================
Vector<ProtocolObserver> protocolObservers = new Vector<ProtocolObserver> ();
public void addProtocolObserver (ProtocolObserver protocolObserver) {
protocolObservers.add (protocolObserver);
}
public void removeProtocolObserver (ProtocolObserver protocolObserver) {
protocolObservers.remove (protocolObserver);
}
// ========================================
public void broadcastStartProtocol () {
if (protocol != null)
for (ProtocolObserver protocolObserver : protocolObservers)
protocolObserver.startProtocol (protocol);
}
// ========================================
public void addMenuItem (JMenu... jMenu) {
Util.addMenuItem (actionsNames, this, jMenu[0]);
}
// ========================================
public void addIconButtons (Container... container) {
Util.addIconButton (actionsNames, this, container[0]);
}
// ========================================
public void addActiveButtons (Hashtable<String, AbstractButton> buttons) {
// XXX ??? fournir la sous-liste
for (String action : Arrays.asList (GameManager.actionPlayersClass, GameManager.actionCut,
GameManager.actionEmpty, GameManager.actionOpen))
addNoNetworkCommand (buttons.get (action));
}
// ========================================
}

View File

@ -0,0 +1,6 @@
package network;
public interface ProtocolObserver {
public void startProtocol (Protocol protocol);
}

View File

@ -0,0 +1,278 @@
package network;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Hashtable;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import misc.Log;
import misc.XML;
public class Server extends Protocol {
// ========================================
static public final boolean trace = false;
static public final String loginApplicationName = "login";
static public final String askToken = "ask";
static public final String connectToken = "connect";
static public final String disconnectToken = "disconnect";
static public final String userToken = "user";
static public final String acceptToken = "accept";
static public final String unknownToken = "unknown";
// ========================================
private int port;
public Server (int port) {
super (ServerProtocolType);
this.port = port;
}
// ========================================
public void start () {
(new Thread () {
public void run () {
try {
final ServerSocket serverSocket = new ServerSocket (port);
Log.writeLog ("Protocol", "Server started on port "+port);
// pour pouvoir arreter proprement l'activité
for (currentThread = Thread.currentThread (); currentThread == Thread.currentThread (); ) {
try {
final Socket call = serverSocket.accept ();
(new Thread () {
public void run () {
try {
Log.writeLog ("Protocol", "Server accept "+call);
exchangeXML (new HTTPInputStream (call.getInputStream ()),
new HTTPOutputStream (call.getOutputStream ()));
call.close ();
} catch (SocketException e) {
Log.writeLog ("Protocol", "Server connection lost "+call);
try {
serverSocket.close ();
Log.writeLog ("Protocol", "Server close");
} catch (IOException e2) {
Log.writeLog ("Protocol", "Server: "+e2);
}
} catch (IOException e) {
Log.keepLastException ("Server::start", e);
}
}
}).start ();
} catch (SocketTimeoutException e) {
}
}
serverSocket.close ();
} catch (SocketException e) {
Log.writeLog ("Protocol", "Server connection lost: "+e);
} catch (IOException e) {
//} catch (SocketException e) {
Log.keepLastException ("Server::start", e);
}
Log.writeLog ("Protocol", "Server stopped on port "+port);
}
}).start ();
}
// ========================================
public void stop () {
currentThread = null;
try {
// force le accept pour sortir du run
(new Socket ("localhost", port)).close ();
} catch (Exception e) {
}
pendingRequests = new Hashtable<String, PendingRequest> ();
}
// ========================================
private String getAskAndDelLogin (Element paquet) {
if (trace)
System.err.println (type+":getConnectAndDelLogin:");
String result = null;
NodeList applications = paquet.getElementsByTagName (applicationToken);
for (int j = applications.getLength () - 1; j >= 0; j--) {
Element application = (Element) applications.item (j);
if (loginApplicationName.equals (application.getAttribute (nameToken))) {
NodeList applicationArguments = application.getElementsByTagName (argumentToken);
if (applicationArguments.getLength () < 1)
continue;
Element applicationArgument = (Element) applicationArguments.item (0);
String ask = applicationArgument.getAttribute (askToken);
if (connectToken.equals (ask) || disconnectToken.equals (ask))
result = ask;
paquet.removeChild (application);
}
}
return result;
}
// ========================================
private Element createUserAnswer (String state) {
Element argument = createArgument ();
argument.setAttribute (userToken, state);
return argument;
}
// ========================================
/** Server way : receive then send. */
private synchronized void exchangeXML (InputStream in, OutputStream out)
throws IOException {
Element bundle = getBundle (in);
String waitRequest = bundle.getAttribute (waitAnswerToken);
NodeList paquets = bundle.getElementsByTagName (paquetToken);
if (paquets.getLength () != 1)
// Si c'est un client, il n'y a qu'un paquet
Log.writeLog ("Protocol", "exchangeXML: Only one paquet expected ("+paquets.getLength ()+")!");
// XXX test si nombre incohérant (normalement un seul paquet par bundle)
Element paquet = (Element) paquets.item (0);
String pearId = paquet.getAttribute (pearIdToken);
addClient (pearId);
String ask = getAskAndDelLogin (paquet);
if (ask != null) {
try {
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance ().newDocumentBuilder ();
Document emptyRequest = documentBuilder.newDocument ();
emptyRequest.setXmlStandalone (true);
Element applicationNode = emptyRequest.createElement (applicationToken);
applicationNode.setAttribute (nameToken, loginApplicationName);
applicationNode.appendChild (emptyRequest.importNode (createUserAnswer (connectToken.equals (ask) ? acceptToken : unknownToken), true));
addPendingApplicationToClient (pearId, applicationNode);
} catch (ParserConfigurationException e) {
Log.keepLastException ("Server::exchangeXML", e);
}
}
broadcastClients (paquet, pearId);
broadcastApplications (bundle);
PendingRequest pendingRequest = getPendingRequest (pearId, waitRequest != null && "yes".equals (waitRequest));
XML.writeDocument (pendingRequest.request, out);
out.flush ();
out.close ();
}
// ========================================
private Hashtable<String, PendingRequest> pendingRequests = new Hashtable<String, PendingRequest> ();
// ========================================
private synchronized void addClient (String pearId) {
if (trace)
System.err.println (type+":addClient: "+pearId);
// XXX si pearId est null ???
if (pearId == null || pendingRequests.get (pearId) != null)
return;
resetClient (pearId);
// YYY nouveau client => startProtocol
}
// ========================================
private synchronized void resetClient (String pearId) {
if (trace)
System.err.println (type+":resetClient: "+pearId);
pendingRequests.put (pearId, new PendingRequest ());
}
// ========================================
private synchronized void sendClient (String toClientId, Element paquet) {
PendingRequest pendingRequest = pendingRequests.get (toClientId);
pendingRequest.bundle.appendChild (pendingRequest.request.importNode (paquet, true));
pendingRequest.readyToSend = true;
notifyAll ();
if (trace) {
System.err.println (type+":broadcastClients: "+pearId);
XML.writeDocument (pendingRequest.request, System.err);
System.err.flush ();
}
}
// ========================================
private synchronized void broadcastClients (Element paquet, String fromClientId) {
NodeList applications = paquet.getElementsByTagName (applicationToken);
if (applications.getLength () < 1)
return;
for (String toClientId : pendingRequests.keySet ()) {
if (toClientId.equals (fromClientId))
continue;
sendClient (toClientId, paquet);
}
}
// ========================================
private synchronized PendingRequest getPendingRequest (String pearId, boolean waitRequest) {
if (waitRequest) {
if (trace)
System.err.println (type+":getPendingRequest: waitting for "+pearId);
for (;;) {
PendingRequest pendingRequest = pendingRequests.get (pearId);
if (pendingRequest.readyToSend)
break;
try {
wait ();
} catch (InterruptedException e) {
}
}
if (trace)
System.err.println (type+": getPendingRequest "+pearId+" is ready");
}
PendingRequest old = pendingRequests.get (pearId);
resetClient (pearId);
return old;
}
// ========================================
protected void addPendingApplicationToClient (String pearId, Element applicationNode) {
PendingRequest pendingRequest = pendingRequests.get (pearId);
pendingRequest.localPaquet.appendChild (pendingRequest.request.importNode (applicationNode, true));
pendingRequest.readyToSend = true;
notifyAll ();
if (trace) {
System.err.println (type+":addPendingApplication: "+pearId);
XML.writeDocument (pendingRequest.request, System.err);
System.err.flush ();
}
}
// ========================================
protected void addPendingApplication (String applicationName, Element applicationArgument) {
try {
if (loginApplicationName.equals (applicationName)) {
String ask = applicationArgument.getAttribute (askToken);
if (connectToken.equals (ask))
broadcastApplication (loginApplicationName, createUserAnswer (acceptToken));
else if (disconnectToken.equals (ask))
broadcastApplication (loginApplicationName, createUserAnswer (unknownToken));
return;
}
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance ().newDocumentBuilder ();
Document emptyRequest = documentBuilder.newDocument ();
emptyRequest.setXmlStandalone (true);
Element applicationNode = emptyRequest.createElement (applicationToken);
applicationNode.setAttribute (nameToken, applicationName);
if (applicationArgument != null)
applicationNode.appendChild (emptyRequest.importNode (applicationArgument, true));
for (String pearId : pendingRequests.keySet ())
addPendingApplicationToClient (pearId, applicationNode);
} catch (ParserConfigurationException e) {
Log.keepLastException ("Server::addPendingApplication", e);
}
}
// ========================================
}

View File

@ -0,0 +1,14 @@
package network;
import org.w3c.dom.Element;
public interface Waiter {
// ========================================
public void setProtocol (Protocol protocol);
// ========================================
public void receive (Element argument);
// ========================================
}

View File

@ -0,0 +1,39 @@
package network;
import java.io.IOException;
import java.net.URLConnection;
import java.net.URL;
import java.net.Proxy;
public class XMLConnection {
// ========================================
static public URLConnection getXMLConnection (URL url)
throws IOException {
URLConnection urlConnection = url.openConnection ();
urlConnection.setDoOutput (true);
urlConnection.setUseCaches (false);
urlConnection.setRequestProperty ("Accept", "application/xml");
urlConnection.setRequestProperty ("User-Agent", "Merciol");
urlConnection.setRequestProperty ("Content-type", "application/xml");
return urlConnection;
}
// ========================================
static public URLConnection getXMLConnection (URL url, Proxy proxy)
throws IOException{
URLConnection urlConnection = (proxy == null) ? url.openConnection () : url.openConnection (proxy);
urlConnection.setDoOutput (true);
urlConnection.setUseCaches (false);
urlConnection.setRequestProperty ("Accept", "application/xml");
urlConnection.setRequestProperty ("User-Agent", "Merciol");
urlConnection.setRequestProperty ("Content-type", "application/xml");
return urlConnection;
}
public void connect () {
throw new IllegalArgumentException ("Can't reconnect an XMLConnection");
}
// ========================================
}

View File

@ -0,0 +1,192 @@
package network.chat;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Random;
import java.util.Vector;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import misc.Bundle;
import misc.Config;
import misc.Log;
import misc.XML;
import network.Protocol;
import network.Waiter;
/**
* Modèle.
* <?xml version="1.0" encoding="UTF-8"?>
* <bundle>
* <paquet pearId="AA6C1B8851EBBAC2">
* <application name="chat">
* <argument sequence="1" date="08:30:50" speudo="inconnu_561C">azertyuiop</argument>
* </application>
* </paquet>
* </bundle>
*/
public class Chat implements Waiter {
// ========================================
static public final String applicationName = "chat";
static public final String quoteToken = "quote";
static public final String sequenceToken = "sequence";
static public final String dateToken = "date";
static public final String speakerToken = "speaker";
static public final SimpleDateFormat dateFormat = new SimpleDateFormat ("HH:mm:ss");
private Protocol protocol;
private String pseudo;
private int lastSequence;
private Vector<ChatQuote> dialog = new Vector<ChatQuote> ();
private boolean modified = false;
public synchronized void setProtocol (Protocol protocol) {
if (this.protocol != null)
this.protocol.removeWaiter (applicationName, this);
this.protocol = protocol;
if (protocol != null)
protocol.addWaiter (applicationName, this);
}
static public String getRandomPseudo () {
return
Bundle.getString ("anonymous", null)+"_"+Integer.toHexString ((new Random ()).nextInt ()).toUpperCase ().substring (0, 4);
}
public String getPseudo () { return pseudo; }
public void setPseudo (String pseudo) {
this.pseudo = pseudo;
broadcastRenameSpeaker ();
Config.setString ("chatLogin", pseudo);
}
public boolean getModified () { return modified; }
// ========================================
public Chat (String pseudo) {
this.pseudo = pseudo;
dateFormat.setLenient (false);
}
public Chat (String pseudo, Protocol protocol) {
this (pseudo);
setProtocol (protocol);
}
// ========================================
public void clear () {
dialog = new Vector<ChatQuote> ();
modified = false;
broadcastClearChat ();
}
// ========================================
public void save (File file)
throws IOException {
try {
file.setExecutable (false);
Collections.sort (dialog, new ChatQuote (0, new Date (), "", ""));
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance ().newDocumentBuilder ();
Document document = documentBuilder.newDocument ();
document.setXmlStandalone (true);
Element applicationNode = document.createElement (applicationName);
document.appendChild (applicationNode);
for (ChatQuote quote : dialog) {
Element quoteElement = document.createElement (quoteToken);
applicationNode.appendChild (quoteElement);
quoteElement.setAttribute (sequenceToken, ""+quote.sequence);
quoteElement.setAttribute (dateToken, dateFormat.format (quote.date));
quoteElement.setAttribute (speakerToken, quote.speaker);
quoteElement.appendChild (document.createTextNode (quote.sentence));
}
FileOutputStream out = new FileOutputStream (file);
XML.writeDocument (document, out);
out.close ();
modified = false;
broadcastChatModifiedChange ();
} catch (ParserConfigurationException e) {
Log.keepLastException ("Chat::save", e);
}
}
// ========================================
public synchronized void say (String sentence) {
if (sentence == null)
sentence = "";
ChatQuote quote = new ChatQuote (++lastSequence, new Date (), pseudo, sentence);
broadcastTalk (quote);
if (protocol == null)
return;
Element argument = Protocol.createArgument ();
argument.setAttribute (sequenceToken, ""+quote.sequence);
argument.setAttribute (dateToken, dateFormat.format (quote.date));
argument.setAttribute (speakerToken, quote.speaker);
argument.appendChild (argument.getOwnerDocument ().createTextNode (quote.sentence));
protocol.send (applicationName, argument);
}
// ========================================
public synchronized void receive (Element argument) {
String speaker = argument.getAttribute (speakerToken);
Date date = new Date ();
try {
dateFormat.parse (argument.getAttribute (dateToken));
} catch (ParseException e) {
Log.keepLastException ("Chat::receive", e);
}
int sequence = Integer.parseInt (argument.getAttribute (sequenceToken));
lastSequence = Math.max (lastSequence, sequence);
String sentence = "";
NodeList nodeList = argument.getChildNodes ();
if (nodeList.getLength () > 0)
sentence = ((Text) nodeList.item (0)).getWholeText ();
broadcastTalk (new ChatQuote (sequence, date, speaker, sentence));
}
// ========================================
Vector<ChatObserver> chatObservers = new Vector<ChatObserver> ();
public void addChatObserver (ChatObserver chatObserver) { chatObservers.add (chatObserver); }
public void removeChatObserver (ChatObserver chatObserver) { chatObservers.remove (chatObserver); }
public void broadcastTalk (ChatQuote quote) {
dialog.add (quote);
modified = true;
for (ChatObserver chatObserver : chatObservers)
chatObserver.talk (quote);
broadcastChatModifiedChange ();
}
public void broadcastRenameSpeaker () {
for (ChatObserver chatObserver : chatObservers)
chatObserver.renameSpeaker (pseudo);
}
public void broadcastChatModifiedChange () {
for (ChatObserver chatObserver : chatObservers)
chatObserver.chatModifiedChange (modified);
}
public void broadcastClearChat () {
for (ChatObserver chatObserver : chatObservers)
chatObserver.clearChat ();
broadcastChatModifiedChange ();
}
// ========================================
}

View File

@ -0,0 +1,107 @@
package network.chat;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Image;
import java.text.MessageFormat;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import network.login.Login;
import network.login.LoginManager;
import network.ProtocolManager;
import misc.Controller;
import misc.Bundle;
import misc.Config;
import misc.HelpManager;
import misc.MultiToolBarBorderLayout;
import misc.Util;
/**
Créer et relie le modèle avec le graphisme.
*/
public class ChatController extends Controller<Chat> implements ChatObserver {
// ========================================
public ChatController () {
super (new Chat (Config.getString ("chatLogin", Bundle.getString ("anonymous", null))));
}
// ========================================
Chat chat;
Login login;
ProtocolManager protocolManager;
ChatManager chatManager;
LoginManager loginManager;
HelpManager helpManager;
JChat jChat;
JChatMenuBar jChatMenuBar;
// ========================================
public String getTitle () { return MessageFormat.format (Bundle.getTitle ("Chat"), chat.getPseudo ()); }
public Image getIcon () { return Util.loadImage (Config.getString ("ChatIcon", "data/images/chat/chat.png")); }
// ========================================
protected boolean tryClosingWindows () {
Config.save ("Chat");
if (chat.getModified ()) {
switch (JOptionPane.showConfirmDialog (jFrame, Bundle.getMessage ("SaveChat"),
Bundle.getTitle ("ChatNotSaved"),
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE)) {
case JOptionPane.YES_OPTION:
chatManager.actionSaveAs ();
return true;
case JOptionPane.NO_OPTION:
return true;
case JOptionPane.CANCEL_OPTION:
case JOptionPane.CLOSED_OPTION:
return false;
}
}
return true;
}
// ========================================
protected void createModel (Chat chat) {
this.chat = chat;
login = new Login (Config.getString ("pseudo", Login.getRandomLogin ()));
chat.addChatObserver (this);
}
// ========================================
protected Component createGUI () {
JPanel contentPane = new JPanel (new MultiToolBarBorderLayout ());
protocolManager = new ProtocolManager (this);
protocolManager.addWaiter (login);
protocolManager.addWaiter (chat);
protocolManager.start ();
chatManager = new ChatManager (this, chat);
loginManager = new LoginManager (this, login);
helpManager = new HelpManager (this, "Chat");
jChat = new JChat (protocolManager, loginManager, chatManager);
contentPane.add (jChat, BorderLayout.CENTER);
return contentPane;
}
// ========================================
protected JMenuBar createMenuBar () {
jChatMenuBar = new JChatMenuBar (this, protocolManager, loginManager, chatManager, helpManager, null);
return jChatMenuBar;
}
// ========================================
public void talk (ChatQuote quote) {}
public void renameSpeaker (String speaker) { jFrame.setTitle (getTitle ()); }
public void chatModifiedChange (boolean modified) {}
public void clearChat () {}
// ========================================
}

View File

@ -0,0 +1,142 @@
package network.chat;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;
import javax.swing.AbstractButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;
import misc.ApplicationManager;
import misc.Bundle;
import misc.Config;
import misc.OwnFrame;
import misc.Util;
/**
comportement déclanché par des actionneurs graphiques (menu ou bouton).
*/
@SuppressWarnings ("serial") public class ChatManager implements ApplicationManager, ActionListener, ChatObserver {
// ========================================
private OwnFrame controller;
static public final String actionPseudo = "Pseudo";
static public final String extention = "chat";
static public final String actionClear = "Clear";
static public final List<String> loginActionsNames = Arrays.asList (actionPseudo);
static public final List<String> saveActionsNames = Arrays.asList (actionClear, "SaveAs");
@SuppressWarnings("unchecked")
static public final List<String> actionsNames =
Util.merge (loginActionsNames, saveActionsNames, Arrays.asList ("ManageExtention"));
@SuppressWarnings("unchecked")
static public final Hashtable<String, Method> actionsMethod =
Util.collectMethod (ChatManager.class, actionsNames);
public void actionPerformed (ActionEvent e) {
Util.actionPerformed (actionsMethod, e, this);
}
// ========================================
private Chat chat;
public Chat getChat () { return chat; }
// ========================================
public ChatManager (OwnFrame controller, Chat chat) {
this.controller = controller;
this.chat = chat;
chat.addChatObserver (this);
jFileChooser.setFileFilter (new FileNameExtensionFilter (Bundle.getLabel ("ChatFilter"), extention));
jFileChooser.setAccessory (manageExtensionCheckBox =
Util.newCheckButtonConfig ("ManageExtention", this, true));
}
// ========================================
public void actionManageExtention () {
// rien a faire
}
public void actionPseudo () {
String newName =
(String) JOptionPane.showInputDialog (controller.getJFrame (), Bundle.getLabel ("NewPseudo"),
Bundle.getTitle ("ChangePseudo"), JOptionPane.INFORMATION_MESSAGE,
null, null, Chat.getRandomPseudo ());
if (newName == null)
return;
chat.setPseudo (newName);
}
public synchronized void actionClear () {
if (chat.getModified () &&
JOptionPane.YES_OPTION !=
JOptionPane.showConfirmDialog (controller.getJFrame (), Bundle.getMessage ("RealyClearChat"),
Bundle.getTitle ("ChatNotSaved"), JOptionPane.WARNING_MESSAGE))
return;
chat.clear ();
}
final JFileChooser jFileChooser = new JFileChooser (Config.getString ("ChatDir", "data/chat"));
final JCheckBox manageExtensionCheckBox;
public synchronized void actionSaveAs () {
jFileChooser.setFileSelectionMode (JFileChooser.FILES_ONLY);
if (jFileChooser.showSaveDialog (controller.getJFrame ()) != JFileChooser.APPROVE_OPTION)
return;
File file = jFileChooser.getSelectedFile ();
Config.setString ("ChatDir", file.getParent ());
Config.save ("Chat");
try {
if (manageExtensionCheckBox.isSelected () && !file.getName ().endsWith ("."+extention))
file = new File (file.getParent (), file.getName () + "."+extention);
chat.save (file);
} catch (IOException e) {
JOptionPane.showMessageDialog (controller.getJFrame (), e.getMessage (), "alert", JOptionPane.WARNING_MESSAGE);
}
}
// ========================================
private Vector<AbstractButton> saveCommands = new Vector<AbstractButton> ();
public void addSaveCommand (AbstractButton saveCommand) {
saveCommands.add (saveCommand);
saveCommand.setEnabled (chat.getModified ());
}
// ========================================
public void talk (ChatQuote quote) {}
public void renameSpeaker (String speaker) {}
public void chatModifiedChange (boolean modified) {
for (AbstractButton saveCommand : saveCommands)
saveCommand.setEnabled (modified);
}
public void clearChat () {}
// ========================================
public void addMenuItem (JMenu... jMenu) {
Util.addMenuItem (loginActionsNames, this, jMenu[0]);
Util.addMenuItem (saveActionsNames, this, jMenu[0]);
}
// ========================================
public void addIconButtons (Container... containers) {
Util.addIconButton (loginActionsNames, this, containers[0]);
Util.addIconButton (saveActionsNames, this, containers[0]);
}
// ========================================
public void addActiveButtons (Hashtable<String, AbstractButton> buttons) {
addSaveCommand (buttons.get (actionClear));
}
// ========================================
}

View File

@ -0,0 +1,17 @@
package network.chat;
import java.util.Date;
/**
Modificaion de modèle qui peuvent être observé.
*/
public interface ChatObserver {
// ========================================
public void talk (ChatQuote quote);
public void renameSpeaker (String speaker);
public void chatModifiedChange (boolean modified);
public void clearChat ();
// ========================================
}

View File

@ -0,0 +1,45 @@
package network.chat;
import java.util.Comparator;
import java.util.Date;
/**
Modificaion de modèle qui peuvent être observé.
*/
public class ChatQuote implements Comparator<ChatQuote> {
int sequence;
Date date;
String speaker;
String sentence;
// ========================================
public ChatQuote (int sequence, Date date, String speaker, String sentence) {
this.sequence = sequence;
this.date = date;
this.speaker = speaker;
this.sentence = sentence;
}
// ========================================
public int compare (ChatQuote o1, ChatQuote o2) {
if (o1.sequence != o2.sequence)
return o1.sequence - o2.sequence;
int diff = o1.date.compareTo (o2.date);
if (diff != 0)
return diff;
diff = o1.speaker.compareTo (o2.speaker);
if (diff != 0)
return diff;
return o1.sentence.compareTo (o2.sentence);
}
// ========================================
public boolean equals (ChatQuote obj) {
return
sentence == obj.sentence && date == obj.date &&
speaker.equals (obj.speaker) && sentence.equals (obj.sentence);
}
// ========================================
}

View File

@ -0,0 +1,150 @@
package network.chat;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collections;
import java.util.Date;
import java.util.Hashtable;
import java.util.Vector;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.plaf.basic.BasicBorders;
import javax.swing.text.BadLocationException;
import misc.Config;
import misc.Log;
import misc.Util;
import network.ProtocolManager;
import network.login.Login;
import network.login.LoginManager;
import network.login.LoginObserver;
@SuppressWarnings ("serial") public class JChat extends JPanel implements ChatObserver, LoginObserver, ActionListener {
// ========================================
private Chat chat;
public JTextArea forum;
public Vector<ChatQuote> dialog;
public JScrollPane jScrollPane;
public JLabel pseudo;
public JTextField message;
public Chat getChat () { return chat; }
// ========================================
public JChat (ProtocolManager protocolManager, LoginManager loginManager, ChatManager chatManager) {
super (new BorderLayout ());
chat = chatManager.getChat ();
chat.addChatObserver (this);
loginManager.getLogin ().addLoginObserver (this);
forum = new JTextArea (Integer.parseInt (Config.getString ("ChatRows", "18")),
Integer.parseInt (Config.getString ("ChatColumns", "64")));
dialog = new Vector <ChatQuote> ();
jScrollPane = new JScrollPane (forum);
jScrollPane.setVerticalScrollBarPolicy (ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
forum.setEditable (false);
message = new JTextField ();
message.setEnabled (true);
message.addActionListener (this);
pseudo = new JLabel (chat.getPseudo ()+" : ");
pseudo.setEnabled (true);
add (jScrollPane, BorderLayout.CENTER);
JPanel buttonsPanel = new JPanel (null);
buttonsPanel.setLayout (new BoxLayout (buttonsPanel, BoxLayout.X_AXIS));
Util.addIconButton (ChatManager.loginActionsNames, chatManager, buttonsPanel);
Util.addIconButton (ProtocolManager.actionsNames, protocolManager, buttonsPanel);
Util.addIconButton (ChatManager.saveActionsNames, chatManager, buttonsPanel);
Hashtable<String, AbstractButton> buttons = new Hashtable<String, AbstractButton> ();
Util.collectButtons (buttons, buttonsPanel);
Border buttonBorder =
BorderFactory.createCompoundBorder (new EtchedBorder (),
BorderFactory.createCompoundBorder (BasicBorders.getMenuBarBorder (),
new EmptyBorder (3, 3, 3, 3)));
for (Component component : buttonsPanel.getComponents ()) {
try {
AbstractButton button = (AbstractButton) component;
button.setBorder (buttonBorder);
} catch (Exception e) {
}
}
chatManager.addSaveCommand (buttons.get (ChatManager.actionClear));
JPanel footer = new JPanel (new BorderLayout ());
footer.add (pseudo, BorderLayout.WEST);
footer.add (message, BorderLayout.CENTER);
footer.add (buttonsPanel, BorderLayout.EAST);
add (footer, BorderLayout.SOUTH);
}
// ========================================
public void actionPerformed (ActionEvent e) {
actionSay ();
}
public void actionSay () {
chat.say (message.getText ());
message.setText ("");
}
// ========================================
private ChatQuote control = new ChatQuote (0, new Date (), "", "");
public synchronized void talk (ChatQuote quote) {
dialog.add (quote);
Collections.sort (dialog, control);
String newLine = Chat.dateFormat.format (quote.date)+" "+quote.speaker+" > "+quote.sentence+"\n";
int quoteIndex = dialog.indexOf (quote);
try {
int lineOffset = forum.getLineStartOffset (quoteIndex);
forum.insert (newLine, lineOffset);
forum.setCaretPosition (lineOffset);
} catch (BadLocationException e) {
try {
forum.append (newLine);
forum.setCaretPosition (forum.getLineEndOffset (forum.getLineCount ()-1));
} catch (BadLocationException e2) {
Log.keepLastException ("JChat::talk", e2);
}
}
}
public void renameSpeaker (String speaker) {
pseudo.setText (speaker+" : ");
}
public void chatModifiedChange (boolean modified) { }
public void clearChat () {
forum.setText ("");
dialog = new Vector<ChatQuote> ();
message.setText ("");
}
// ========================================
public void updateLogin (String login) {}
public void updateGroup (String groupName) {}
public void updateGroups (String[] groupsName) {}
public void infoGroup (Login.Group group) {}
public void loginState (String state) {
boolean connected = !Login.unknownToken.equals (state);
pseudo.setEnabled (connected);
message.setEnabled (connected);
}
// ========================================
}

View File

@ -0,0 +1,44 @@
package network.chat;
import java.awt.Frame;
import java.text.MessageFormat;
import misc.Bundle;
import misc.TitledDialog;
/**
fenêtre d'habillage pour inclusion.
*/
@SuppressWarnings ("serial") public class JChatDialog extends TitledDialog implements ChatObserver {
// ========================================
public String pseudo;
// ========================================
public JChatDialog (Frame frame, JChat jChat) {
super (frame, "Chat");
pseudo = jChat.getChat ().getPseudo ();
jChat.getChat ().addChatObserver (this);
add (jChat);
updateBundle ();
Bundle.addBundleObserver (this);
}
// ========================================
public void updateBundle () {
setTitle (getTitle ());
}
// ========================================
public String getTitle () {
return MessageFormat.format (Bundle.getTitle (titleId), pseudo);
}
// ========================================
public void talk (ChatQuote quote) {}
public void renameSpeaker (String speaker) { pseudo = speaker; updateBundle (); }
public void chatModifiedChange (boolean modified) {}
public void clearChat () {}
// ========================================
}

View File

@ -0,0 +1,55 @@
package network.chat;
import java.util.Hashtable;
import javax.swing.AbstractButton;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import network.ProtocolManager;
import network.login.LoginManager;
import misc.ApplicationManager;
import misc.Log;
import misc.ToolBarManager;
import misc.Util;
/**
La barre de menu.
*/
@SuppressWarnings ("serial") public class JChatMenuBar extends JMenuBar {
// ========================================
public JChatMenuBar (ApplicationManager controllerManager,
ProtocolManager protocolManager, LoginManager loginManager, ChatManager chatManager,
ApplicationManager helpManager, ToolBarManager toolBarManager) {
setLayout (new BoxLayout (this, BoxLayout.X_AXIS));
JMenu fileMenu = Util.addJMenu (this, "File");
JMenu networkMenu = Util.addJMenu (this, "Network");
add (Box.createHorizontalGlue ());
JMenu helpMenu = Util.addJMenu (this, "Help");
Util.addMenuItem (ChatManager.loginActionsNames, chatManager, fileMenu);
Util.addMenuItem (ChatManager.saveActionsNames, chatManager, fileMenu);
controllerManager.addMenuItem (fileMenu);
protocolManager.addMenuItem (networkMenu);
loginManager.addMenuItem (networkMenu);
helpManager.addMenuItem (helpMenu);
if (toolBarManager != null)
toolBarManager.addMenuItem (helpMenu);
Hashtable<String, AbstractButton> buttons = new Hashtable<String, AbstractButton> ();
Util.collectButtons (buttons, fileMenu);
Util.collectButtons (buttons, networkMenu);
Util.collectButtons (buttons, helpMenu);
controllerManager.addActiveButtons (buttons);
helpManager.addActiveButtons (buttons);
chatManager.addSaveCommand (buttons.get (ChatManager.actionClear));
if (toolBarManager != null)
toolBarManager.addActiveButtons (buttons);
}
// ========================================
}

View File

@ -0,0 +1,32 @@
package network.chat;
import javax.swing.SwingUtilities;
import misc.Bundle;
import misc.Config;
/**
Lance le controleur.
*/
public class LaunchChat {
// ========================================
static public void main (String[] args) {
Config.setPWD (LaunchChat.class);
Config.load ("Chat");
Bundle.load ("Help");
Bundle.load ("ToolBar");
Bundle.load ("Controller");
Bundle.load ("Protocol");
Bundle.load ("Login");
Bundle.load ("Chat");
SwingUtilities.invokeLater (new Runnable () {
public void run () {
new ChatController ();
}
});
}
// ========================================
}

View File

@ -0,0 +1,66 @@
package network.login;
import java.awt.Component;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Hashtable;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.plaf.basic.BasicBorders;
import misc.Util;
import network.ProtocolManager;
import static misc.Util.GBC;
import static misc.Util.GBCNL;
@SuppressWarnings ("serial") public class JLogin extends JPanel implements LoginObserver {
// ========================================
private Login login;
public JLabel loggedLabel = new JLabel ();
public JLabel groupLabel = new JLabel ();
private JLabel stateLabel = new JLabel ();
public Login getLogin () { return login; }
// ========================================
public JLogin (ProtocolManager protocolManager, LoginManager loginManager) {
super (new GridBagLayout ());
login = loginManager.getLogin ();
login.addLoginObserver (this);
Util.addLabelFields (this, "Logged", loggedLabel);
Util.addLabelFields (this, "Group", groupLabel);
Util.addLabelFields (this, "State", stateLabel);
}
// ========================================
public void updateLogin (String login) {
loggedLabel.setText (login);
}
public void updateGroup (String group) {
groupLabel.setText (group);
}
public void updateGroups (String[] groupsName) {
}
public void infoGroup (Login.Group group) {
}
public void loginState (String state) {
stateLabel.setText (state);
}
// ========================================
}

View File

@ -0,0 +1,53 @@
package network.login;
import java.util.Hashtable;
import javax.swing.AbstractButton;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import network.ProtocolManager;
import misc.ApplicationManager;
import misc.Log;
import misc.ToolBarManager;
import misc.Util;
/**
La barre de menu.
*/
@SuppressWarnings ("serial") public class JLoginMenuBar extends JMenuBar {
// ========================================
public JLoginMenuBar (ApplicationManager controllerManager,
ProtocolManager protocolManager, LoginManager loginManager,
ApplicationManager helpManager, ToolBarManager toolBarManager) {
setLayout (new BoxLayout (this, BoxLayout.X_AXIS));
JMenu fileMenu = Util.addJMenu (this, "File");
JMenu networkMenu = Util.addJMenu (this, "Network");
JMenu loginMenu = Util.addJMenu (this, "Connection");
add (Box.createHorizontalGlue ());
JMenu helpMenu = Util.addJMenu (this, "Help");
controllerManager.addMenuItem (fileMenu);
protocolManager.addMenuItem (networkMenu);
loginManager.addMenuItem (loginMenu);
helpManager.addMenuItem (helpMenu);
toolBarManager.addMenuItem (helpMenu);
Hashtable<String, AbstractButton> buttons = new Hashtable<String, AbstractButton> ();
Util.collectButtons (buttons, fileMenu);
Util.collectButtons (buttons, networkMenu);
Util.collectButtons (buttons, loginMenu);
Util.collectButtons (buttons, helpMenu);
controllerManager.addActiveButtons (buttons);
protocolManager.addActiveButtons (buttons);
loginManager.addActiveButtons (buttons);
helpManager.addActiveButtons (buttons);
toolBarManager.addActiveButtons (buttons);
}
// ========================================
}

View File

@ -0,0 +1,44 @@
package network.login;
import java.awt.Component;
import java.util.Hashtable;
import javax.swing.AbstractButton;
import javax.swing.JToolBar;
import network.ProtocolManager;
import misc.ApplicationManager;
import misc.ToolBarManager;
import misc.Util;
public class JLoginToolBar {
static public String defaultCardinalPoint = "North";
public JLoginToolBar (ApplicationManager controllerManager,
ProtocolManager protocolManager, LoginManager loginManager,
ApplicationManager helpManager, ToolBarManager toolBarManager) {
JToolBar fileToolBar = toolBarManager.newJToolBar ("File", defaultCardinalPoint);
JToolBar loginToolBar = toolBarManager.newJToolBar ("Connection", defaultCardinalPoint);
JToolBar protocolToolBar = toolBarManager.newJToolBar ("Network", defaultCardinalPoint);
JToolBar helpToolBar = toolBarManager.newJToolBar ("Help", defaultCardinalPoint);
controllerManager.addIconButtons (fileToolBar);
loginManager.addIconButtons (loginToolBar);
protocolManager.addIconButtons (protocolToolBar);
if (helpManager != null)
helpManager.addIconButtons (helpToolBar);
toolBarManager.addIconButtons (helpToolBar);
Hashtable<String, AbstractButton> buttons = new Hashtable<String, AbstractButton> ();
Util.collectButtons (buttons, fileToolBar);
Util.collectButtons (buttons, loginToolBar);
Util.collectButtons (buttons, protocolToolBar);
Util.collectButtons (buttons, helpToolBar);
controllerManager.addActiveButtons (buttons);
loginManager.addActiveButtons (buttons);
protocolManager.addActiveButtons (buttons);
helpManager.addActiveButtons (buttons);
toolBarManager.addActiveButtons (buttons);
}
}

View File

@ -0,0 +1,27 @@
package network.login;
import javax.swing.SwingUtilities;
import misc.Bundle;
import misc.Config;
public class LaunchLogin {
// ========================================
static public void main (String[] args) {
Config.setPWD (LaunchLogin.class);
Config.load ("Login");
Bundle.load ("Help");
Bundle.load ("ToolBar");
Bundle.load ("Controller");
Bundle.load ("Protocol");
Bundle.load ("Login");
SwingUtilities.invokeLater (new Runnable () {
public void run () {
new LoginController ();
}
});
}
// ========================================
}

View File

@ -0,0 +1,370 @@
package network.login;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Random;
import java.util.Vector;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import misc.Bundle;
import misc.Log;
import misc.Util;
import network.Protocol;
import network.Waiter;
/**
* <?xml version="1.0" encoding="UTF-8"?>
* <bundle>
* <paquet>
* <application name="login">
* <argument user="unknown" />
* <argument user="unknown" challenge="AA6C1B8851EBBAC2" try="x" />
* <argument user="reject" />
* <argument user="accept" result="AA6C1B8851EBBAC2" />
* <argument info="passwdUnchanged" />
* <argument info="passwdUpdated" />
* </application>
* </paquet>
* </bundle>
*
* <?xml version="1.0" encoding="UTF-8"?>
* <bundle>
* <paquet pearId="AA6C1B8851EBBAC2">
* <application name="login">
* <argument ask="connect" login="inconnu_561C" />
* <argument ask="connect" login="inconnu_561C" result="AA6C1B8851EBBAC2" />
* <argument ask="disconnect" />
* <argument ask="changepass" old="" new="" />
* </application>
* </paquet>
* </bundle>
*/
public class Login implements Waiter {
static public final boolean trace = false;
// ========================================
static public final String applicationName = "login";
static public final String userToken = "user";
static public final String askToken = "ask";
static public final String loginToken = "login";
static public final String challengeToken = "challenge";
static public final String tryIndexToken = "try";
static public final String resultToken = "result";
static public final String oldToken = "old";
static public final String newToken = "new";
static public final String unknownToken = "unknown";
static public final String rejectToken = "reject";
static public final String acceptToken = "accept";
static public final String connectToken = "connect";
static public final String disconnectToken = "disconnect";
static public final String changepassToken = "changepass";
static public final String groupToken = "group";
static public final String groupsToken = "groups";
static public final String setGroupToken = "setGroup";
static public final String infoToken = "info";
static public final String nameToken = "name";
static public final String joinToken = "join";
static public final String leftToken = "left";
static public final String createdToken = "created";
static public final String updatedToken = "updated";
static public final String ipToken = "ip";
static public final String updatedByToken = "updatedBy";
static public final String adminToken = "admin";
static public final String memberToken = "member";
static public final String createGroupToken = "createGroup";
static public final String removeGroupToken = "removeGroup";
static public final String addGroupAdminToken = "addGroupAdmin";
static public final String removeGroupAdminToken = "removeGroupAdmin";
static public final String addGroupMemberToken = "addGroupMember";
static public final String removeGroupMemberToken = "removeGroupMember";
// ========================================
private Protocol protocol;
/** unknown, reject, accept, untrusted */
private String state = unknownToken;
private String login = "";
private String tryIndex = "";
private String cifferPasswd = "";
private String challenge;
private String group = "";
private String[] groups = new String [0];
public synchronized void setProtocol (Protocol protocol) {
if (trace)
System.err.println ("setProtocol: protocol:"+protocol);
if (this.protocol != null)
this.protocol.removeWaiter (applicationName, this);
this.protocol = protocol;
if (protocol != null)
protocol.addWaiter (applicationName, this);
}
public String getState () { return state; }
public String getTryIndex () { return tryIndex; }
public String getLogin () { return login; }
public String getGroup () { return group; }
public Protocol getProtocol () { return protocol; }
// ========================================
static public String getRandomLogin () {
return
Bundle.getString ("anonymous", null)+"_"+Integer.toHexString ((new Random ()).nextInt ()).toUpperCase ().substring (0, 4);
}
// ========================================
public Login (String login) {
this.login = login;
}
public Login (String login, Protocol protocol) {
this (login);
setProtocol (protocol);
}
// ========================================
public synchronized void unlog () {
if (protocol == null)
return;
protocol.send (applicationName, askToken, disconnectToken);
}
// ========================================
public synchronized void log (String login, String cifferPasswd) {
if (trace)
System.err.println ("log: login:"+login+" cifferPasswd:"+cifferPasswd+" challenge:"+challenge);
if (login == null)
return;
if (protocol == null)
return;
this.login = login;
try {
if (challenge != null) {
this.cifferPasswd = cifferPasswd;
protocol.send (applicationName, askToken, connectToken, loginToken, login, resultToken, Util.sha1 (challenge+cifferPasswd));
} else
protocol.send (applicationName, askToken, connectToken, loginToken, login);
} catch (Exception e) {
Log.keepLastException ("Login::log", e);
protocol.send (applicationName, askToken, connectToken, loginToken, login);
}
}
// ========================================
public synchronized void setGroup (String groupName) {
if (protocol == null)
return;
protocol.send (applicationName, askToken, setGroupToken, groupToken, groupName);
}
public synchronized void unsetGroup () {
setGroup ("");
}
public synchronized void askGroups () {
if (protocol == null)
return;
groups = new String [0];
protocol.send (applicationName, askToken, groupsToken);
}
public synchronized void askGroup (String groupName) {
if (protocol == null)
return;
protocol.send (applicationName, askToken, groupToken, groupToken, groupName);
}
public synchronized void createGroup (String groupName) {
if (protocol == null)
return;
protocol.send (applicationName, askToken, createGroupToken, groupToken, groupName);
}
public synchronized void removeGroup (String groupName) {
if (protocol == null)
return;
protocol.send (applicationName, askToken, removeGroupToken, groupToken, groupName);
}
public synchronized void addGroupAdmin (String groupName, String admin) {
if (protocol == null)
return;
protocol.send (applicationName, askToken, addGroupAdminToken, groupToken, groupName, loginToken, admin);
}
public synchronized void removeGroupAdmin (String groupName, String admin) {
if (protocol == null)
return;
protocol.send (applicationName, askToken, removeGroupAdminToken, groupToken, groupName, loginToken, admin);
}
public synchronized void addGroupMember (String groupName, String member) {
if (protocol == null)
return;
protocol.send (applicationName, askToken, addGroupMemberToken, groupToken, groupName, loginToken, member);
}
public synchronized void removeGroupMember (String groupName, String member) {
if (protocol == null)
return;
protocol.send (applicationName, askToken, removeGroupMemberToken, groupToken, groupName, loginToken, member);
}
// ========================================
public synchronized void receiveUser (String state, String result, String challenge, String tryIndex) {
if (unknownToken.equals (state)) {
this.state = state;
this.challenge = challenge;
this.tryIndex = tryIndex;
group = "";
broadcastUpdateGroup ();
broadcastLoginState ();
} else if (rejectToken.equals (state)) {
this.state = state;
broadcastLoginState ();
} else if (acceptToken.equals (state)) {
this.tryIndex = "";
String check = null;
try {
check = Util.sha1 (this.challenge+login+cifferPasswd);
} catch (Exception e) {
}
if (trace)
System.err.println ("receive: challenge:"+this.challenge+" login:"+login+" cifferPasswd:"+cifferPasswd+" check:"+check);
if (result.equals (check)) {
this.state = state;
broadcastLoginState ();
broadcastUpdateLogin ();
} else {
this.state = "Untrusted";
broadcastLoginState ();
}
} else
System.err.println ("receive: unknown state:"+state+" challenge:"+challenge+" result:"+result);
}
public class Group {
public String name;
public String created;
public String updated;
public String ip;
public String updatedBy;
public String[] admin = new String [0];
public String[] member = new String [0];
}
// ========================================
public synchronized void receive (Element argument) {
String state = argument.getAttribute (userToken);
if (!state.isEmpty ()) {
String tryIndex = argument.getAttribute (tryIndexToken);
String challenge = argument.getAttribute (challengeToken);
String result = argument.getAttribute (resultToken);
if (trace)
System.err.println ("receive: state:"+state+" challenge:"+challenge+" result:"+result);
receiveUser (state, result, challenge, tryIndex);
return;
}
String groupA = argument.getAttribute (groupToken);
if (!groupA.isEmpty ()) {
if (joinToken.equals (groupA))
this.group = argument.getAttribute (nameToken);
else if (leftToken.equals (groupA))
this.group = "";
broadcastUpdateGroup ();
return;
}
String info = argument.getAttribute (infoToken);
if (!info.isEmpty ()) {
if (groupsToken.equals (info)) {
NodeList groupsName = argument.getElementsByTagName (groupToken);
Vector<String> result = new Vector<String> ();
for (int i = 0; i < groupsName.getLength (); i++) {
Element groupName = (Element) groupsName.item (i);
result.add (groupName.getAttribute (nameToken));
}
groups = result.toArray (new String [0]);
Arrays.sort (groups);
broadcastUpdateGroups ();
} else if (groupToken.equals (info)) {
Group group = new Group ();
NodeList groupsNL = argument.getElementsByTagName (groupToken);
// XXX vérification 1 seul élément
Element groupE = (Element) groupsNL.item (0);
group.name = groupE.getAttribute (nameToken);
group.created = groupE.getAttribute (createdToken);
group.updated = groupE.getAttribute (updatedToken);
group.ip = groupE.getAttribute (ipToken);
group.updatedBy = groupE.getAttribute (updatedByToken);
NodeList AdminNL = argument.getElementsByTagName (adminToken);
Vector<String> result = new Vector<String> ();
for (int i = 0; i < AdminNL.getLength (); i++) {
Element AdminE = (Element) AdminNL.item (i);
result.add (AdminE.getAttribute (nameToken));
}
group.admin = result.toArray (new String [0]);
Arrays.sort (group.admin);
NodeList memberNL = argument.getElementsByTagName (memberToken);
result = new Vector<String> ();
for (int i = 0; i < memberNL.getLength (); i++) {
Element memberE = (Element) memberNL.item (i);
result.add (memberE.getAttribute (nameToken));
}
group.member = result.toArray (new String [0]);
Arrays.sort (group.member);
broadcastInfoGroup (group);
}
// XXX passwdUnchanged
// XXX passwdUpdated
}
}
// ========================================
Vector<LoginObserver> loginObservers = new Vector<LoginObserver> ();
public void addLoginObserver (LoginObserver loginObserver) { loginObservers.add (loginObserver); }
public void removeLoginObserver (LoginObserver loginObserver) { loginObservers.remove (loginObserver); }
public void broadcastUpdateLogin () {
if (trace)
System.err.println ("broadcastUpdateLogin: login:"+login);
for (LoginObserver loginObserver : loginObservers)
loginObserver.updateLogin (login);
}
public void broadcastUpdateGroup () {
if (trace)
System.err.println ("broadcastUpdateGroup: group:"+group);
for (LoginObserver loginObserver : loginObservers)
loginObserver.updateGroup (group);
}
public void broadcastUpdateGroups () {
if (trace)
System.err.println ("broadcastUpdateGroups: groups size:"+groups.length);
for (LoginObserver loginObserver : loginObservers)
loginObserver.updateGroups (groups);
}
public void broadcastInfoGroup (Group group) {
if (trace)
System.err.println ("broadcastInfoGroup: group:");
for (LoginObserver loginObserver : loginObservers)
loginObserver.infoGroup (group);
}
public void broadcastLoginState () {
if (trace)
System.err.println ("broadcastLoginState: state:"+state);
for (LoginObserver loginObserver : loginObservers)
loginObserver.loginState (state);
}
// ========================================
}

View File

@ -0,0 +1,87 @@
package network.login;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Image;
import java.text.MessageFormat;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import network.ProtocolManager;
import misc.Controller;
import misc.Bundle;
import misc.Config;
import misc.HelpManager;
import misc.MultiToolBarBorderLayout;
import misc.ToolBarManager;
import misc.Util;
public class LoginController extends Controller<Login> implements LoginObserver {
// ========================================
public LoginController () {
super (new Login (Config.getString ("pseudo", Login.getRandomLogin ())));
}
// ========================================
Login login;
ProtocolManager protocolManager;
LoginManager loginManager;
HelpManager helpManager;
ToolBarManager toolBarManager;
JLogin jLogin;
JLoginMenuBar jLoginMenuBar;
JLoginToolBar jLoginToolBar;
// ========================================
public String getTitle () { return MessageFormat.format (Bundle.getTitle ("Login"), login.getLogin ()); }
public Image getIcon () { return Util.loadImage (Config.getString ("LoginIcon", "data/images/login/login.png")); }
// ========================================
protected boolean tryClosingWindows () {
Config.save ("Login");
return true;
}
// ========================================
protected void createModel (Login login) {
this.login = login;
login.addLoginObserver (this);
}
// ========================================
protected Component createGUI () {
JPanel contentPane = new JPanel (new MultiToolBarBorderLayout ());
toolBarManager = new ToolBarManager (getIcon (), contentPane);
protocolManager = new ProtocolManager (this);
protocolManager.addWaiter (login);
protocolManager.start ();
loginManager = new LoginManager (this, login);
helpManager = new HelpManager (this, "Login");
jLogin = new JLogin (protocolManager, loginManager);
jLoginToolBar = new JLoginToolBar (this, protocolManager, loginManager, helpManager, toolBarManager);
contentPane.add (jLogin, BorderLayout.CENTER);
return contentPane;
}
// ========================================
protected JMenuBar createMenuBar () {
jLoginMenuBar = new JLoginMenuBar (this, protocolManager, loginManager, helpManager, toolBarManager);
return jLoginMenuBar;
}
// ========================================
public void updateLogin (String login) {}
public void updateGroup (String group) {}
public void updateGroups (String[] groupsName) {}
public void infoGroup (Login.Group group) {}
public void loginState (String state) {}
// ========================================
}

View File

@ -0,0 +1,443 @@
package network.login;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Vector;
import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import misc.ApplicationManager;
import misc.Bundle;
import misc.Config;
import misc.Log;
import misc.OwnFrame;
import misc.Util;
import static misc.Util.GBC;
import static misc.Util.GBCNL;
/**
XXX loginTitle a mettre à jour "Login"+Bundle.titlePostfix
comportement déclanché par des actionneurs graphiques (menu ou bouton).
*/
@SuppressWarnings ("serial") public class LoginManager implements ApplicationManager, ActionListener, LoginObserver {
// ========================================
static public final String actionLog = "Log";
static public final String actionUnlog = "Unlog";
static public final String actionJoinGroup = "JoinGroup";
static public final String actionLeftGroup = "LeftGroup";
static public final String actionEditLogin = "EditLogin";
static public final String actionEditGroup = "EditGroup";
static public final String actionCreateGroup = "CreateGroup";
static public final String actionRemoveGroup = "RemoveGroup";
static public final String actionAddAdmin = "AddAdmin";
static public final String actionRemoveAdmin = "RemoveAdmin";
static public final String actionAddMember = "AddMember";
static public final String actionRemoveMember = "RemoveMember";
static public final List<String> loginActionsNames =
Arrays.asList (actionLog, actionUnlog, actionJoinGroup, actionLeftGroup,
actionEditLogin, actionEditGroup);
static public final List<String> dialogActionsNames =
Arrays.asList (actionCreateGroup, actionRemoveGroup,
actionAddAdmin, actionRemoveAdmin, actionAddMember, actionRemoveMember);
@SuppressWarnings ("unchecked")
static public final List<String> actionsNames =
Util.merge (loginActionsNames, dialogActionsNames);
@SuppressWarnings ("unchecked")
static public final Hashtable<String, Method> actionsMethod =
Util.collectMethod (LoginManager.class, actionsNames);
public void actionPerformed (ActionEvent e) {
Util.actionPerformed (actionsMethod, e, this);
}
// ========================================
private OwnFrame controller;
private Login login;
private JPanel loginPanel;
private JComboBox<String> pseudoCB;
private JPasswordField pseudoPasswordField;
private JLabel tryLabel;
private JPanel groupPanel;
private JList<String> groupsList;
private JPanel editLoginPanel;
private JLabel pseudoLabel;
private JLabel createdAtLoginLabel;
private JLabel updatedAtLoginLabel;
private JLabel updatedByIPLoginLabel;
private JLabel updatedByLoginLabel;
private JTextField emailTF;
private JPasswordField oldPasswordField;
private JPasswordField newPasswordField;
private JPasswordField confirmPasswordField;
private String askedGroupName;
private JPanel editGroupPanel;
private JComboBox<String> groupNameCB;
private JList<String> groupsNameList;
private JButton createGroupButton;
private JButton removeGroupButton;
private JLabel groupNameLabel;
private JLabel createdLabel;
private JLabel updatedLabel;
private JLabel ipLabel;
private JLabel updatedByLabel;
private JComboBox<String> adminCB;
private JList<String> adminList;
private JButton addAdminButton;
private JButton removeAdminButton;
private JComboBox<String> memberCB;
private JList<String> memberList;
private JButton addMemberButton;
private JButton removeMemberButton;
public Login getLogin () { return login; }
public void addMenuItem (JMenu... jMenu) {
int idx = 0;
Util.addMenuItem (loginActionsNames, this, jMenu[idx++]);
}
public void addIconButtons (Container... containers) {
int idx = 0;
Util.addIconButton (loginActionsNames, this, containers[idx++]);
}
// ========================================
public LoginManager (OwnFrame controller, Login login) {
this.controller = controller;
this.login = login;
for (String actionName : Arrays.asList (actionLog, actionUnlog,
actionEditLogin, actionEditGroup, actionJoinGroup, actionLeftGroup))
commands.put (actionName, new Vector<AbstractButton> ());
pseudoCB = new JComboBox<String> ();
Config.loadJComboBox ("pseudo", pseudoCB, Login.getRandomLogin ());
pseudoCB.setEditable (true);
pseudoPasswordField = new JPasswordField ();
tryLabel = new JLabel ();
loginPanel = Util.getGridBagPanel ();
Util.addLabelFields (loginPanel, "Login", pseudoCB);
Util.addLabelFields (loginPanel, "Password", pseudoPasswordField);
Util.addLabelFields (loginPanel, "Try", tryLabel);
groupsList = new JList<String> ();
groupsList.setSelectionMode (ListSelectionModel.SINGLE_INTERVAL_SELECTION);
groupsList.setLayoutOrientation (JList.VERTICAL_WRAP);
groupsList.setVisibleRowCount (-1);
JScrollPane listScroller = new JScrollPane (groupsList);
listScroller.setPreferredSize (new Dimension (250, 80));
groupPanel = Util.getGridBagPanel ();
Util.addLabel ("JoinGroup", SwingConstants.RIGHT, groupPanel, GBCNL);
Util.addComponent (listScroller, groupPanel, GBCNL);
groupsNameList = new JList<String> ();
groupsNameList.setSelectionMode (ListSelectionModel.SINGLE_INTERVAL_SELECTION);
groupsNameList.setLayoutOrientation (JList.VERTICAL_WRAP);
groupsNameList.setVisibleRowCount (-1);
JScrollPane groupsNameListScroller = new JScrollPane (groupsNameList);
groupsNameListScroller.setPreferredSize (new Dimension (200, 50));
groupsNameList.addListSelectionListener (new ListSelectionListener () {
public void valueChanged (ListSelectionEvent e) {
actionSelectGroup ();
}
});
adminList = new JList<String> ();
adminList.setSelectionMode (ListSelectionModel.SINGLE_INTERVAL_SELECTION);
adminList.setLayoutOrientation (JList.VERTICAL_WRAP);
adminList.setVisibleRowCount (-1);
JScrollPane adminListScroller = new JScrollPane (adminList);
adminListScroller.setPreferredSize (new Dimension (200, 50));
memberList = new JList<String> ();
memberList.setSelectionMode (ListSelectionModel.SINGLE_INTERVAL_SELECTION);
memberList.setLayoutOrientation (JList.VERTICAL_WRAP);
memberList.setVisibleRowCount (-1);
JScrollPane memberListScroller = new JScrollPane (memberList);
memberListScroller.setPreferredSize (new Dimension (200, 50));
editLoginPanel = Util.getGridBagPanel ();
pseudoLabel = new JLabel ();
createdAtLoginLabel = new JLabel ();
updatedAtLoginLabel = new JLabel ();
updatedByLoginLabel = new JLabel ();
updatedByIPLoginLabel = new JLabel ();
emailTF = new JTextField (20);
oldPasswordField = new JPasswordField (10);
newPasswordField = new JPasswordField (10);
confirmPasswordField = new JPasswordField (10);
Util.addLabelFields (editLoginPanel, "Login", pseudoLabel);
Util.addLabelFields (editLoginPanel, "CreatedAt", createdAtLoginLabel);
Util.addLabelFields (editLoginPanel, "UpdatedAt", updatedAtLoginLabel);
Util.addLabelFields (editLoginPanel, "UpdatedBy", updatedByLoginLabel);
Util.addLabelFields (editLoginPanel, "UpdatedByIP", updatedByIPLoginLabel);
Util.addLabelFields (editLoginPanel, "Email", emailTF);
Util.addLabelFields (editLoginPanel, "OldPasswd", oldPasswordField);
Util.addLabelFields (editLoginPanel, "NewPasswd", newPasswordField);
Util.addLabelFields (editLoginPanel, "ConfirmPasswd", confirmPasswordField);
groupNameCB = new JComboBox<String> ();
adminCB = new JComboBox<String> ();
memberCB = new JComboBox<String> ();
Config.loadJComboBox ("groupName", groupNameCB, "");
Config.loadJComboBox ("groupAdmin", adminCB, "");
Config.loadJComboBox ("groupMember", memberCB, "");
groupNameCB.setEditable (true);
adminCB.setEditable (true);
memberCB.setEditable (true);
editGroupPanel = Util.getGridBagPanel ();
Util.addComponent (groupNameCB, editGroupPanel, GBC);
createGroupButton = Util.addButton (actionCreateGroup, this, editGroupPanel, GBCNL);
Util.addComponent (groupsNameListScroller, editGroupPanel, GBC);
removeGroupButton = Util.addButton (actionRemoveGroup, this, editGroupPanel, GBCNL);
groupNameLabel = new JLabel ();
createdLabel = new JLabel ();
updatedLabel = new JLabel ();
ipLabel = new JLabel ();
updatedByLabel = new JLabel ();
Util.addLabelFields (editGroupPanel, "GroupName", groupNameLabel);
Util.addLabelFields (editGroupPanel, "CreatedAt", createdLabel);
Util.addLabelFields (editGroupPanel, "UpdatedAt", updatedLabel);
Util.addLabelFields (editGroupPanel, "UpdatedByIP", ipLabel);
Util.addLabelFields (editGroupPanel, "UpdatedBy", updatedByLabel);
Util.addComponent (adminCB, editGroupPanel, GBC);
addAdminButton = Util.addButton (actionAddAdmin, this, editGroupPanel, GBCNL);
Util.addComponent (adminListScroller, editGroupPanel, GBC);
removeAdminButton = Util.addButton (actionRemoveAdmin, this, editGroupPanel, GBCNL);
Util.addComponent (memberCB, editGroupPanel, GBC);
addMemberButton = Util.addButton (actionAddMember, this, editGroupPanel, GBCNL);
Util.addComponent (memberListScroller, editGroupPanel, GBC);
removeMemberButton = Util.addButton (actionRemoveMember, this, editGroupPanel, GBCNL);
login.addLoginObserver (this);
}
// ========================================
public void actionLog () {
tryLabel.setText (login.getTryIndex ());
if (JOptionPane.showConfirmDialog (controller.getJFrame (),
loginPanel,
Bundle.getTitle ("Login"),
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE) != JOptionPane.YES_OPTION)
return;
Config.saveJComboBox ("pseudo", pseudoCB);
String passwd = null;
try {
if (pseudoPasswordField.getPassword ().length > 0)
passwd = Util.sha1 (new String (pseudoPasswordField.getPassword ()));
} catch (Exception e) {
Log.keepLastException ("LoginManager::actionLog", e);
}
login.log ((String) pseudoCB.getSelectedItem (), passwd);
}
// ========================================
public void actionUnlog () {
login.unlog ();
}
// ========================================
public void actionJoinGroup () {
login.askGroups ();
if (JOptionPane.
showConfirmDialog (controller.getJFrame (),
groupPanel,
Bundle.getTitle ("Group"),
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE) != JOptionPane.YES_OPTION)
return;
login.setGroup (groupsList.getSelectedValue ());
}
// ========================================
public void actionLeftGroup () {
login.unsetGroup ();
}
// ========================================
public void actionEditLogin () {
if (JOptionPane.showConfirmDialog (controller.getJFrame (),
editLoginPanel,
Bundle.getTitle ("ManageLogin"),
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE) != JOptionPane.YES_OPTION)
return;
// XXX ecrire la fonction : edit login, password et email
JOptionPane.
showMessageDialog (controller.getJFrame (),
"Cette fonction n'est encore pas developpee",
"Developpement en cours",
JOptionPane.QUESTION_MESSAGE);
}
// ========================================
public void actionEditGroup () {
login.askGroups ();
JOptionPane.
showMessageDialog (controller.getJFrame (),
editGroupPanel,
Bundle.getTitle ("ManageGroup"),
JOptionPane.QUESTION_MESSAGE);
groupsNameList.setListData (new String [0]);
adminList.setListData (new String [0]);
memberList.setListData (new String [0]);
Config.saveJComboBox ("groupName", groupNameCB);
Config.saveJComboBox ("groupAdmin", adminCB);
Config.saveJComboBox ("groupMember", memberCB);
}
// ========================================
public void actionSelectGroup () {
infoGroup (null);
askedGroupName = groupsNameList.getSelectedValue ();
if (!askedGroupName.isEmpty ())
login.askGroup (askedGroupName);
}
// ========================================
public void actionCreateGroup () {
login.createGroup ((String) groupNameCB.getSelectedItem ());
}
public void actionRemoveGroup () {
login.removeGroup (groupsNameList.getSelectedValue ());
}
public void actionAddAdmin () {
login.addGroupAdmin (groupNameLabel.getText (), adminCB.getItemAt (adminCB.getSelectedIndex ()));
}
public void actionRemoveAdmin () {
login.removeGroupAdmin (groupNameLabel.getText (), adminList.getSelectedValue ());
}
public void actionAddMember () {
login.addGroupMember (groupNameLabel.getText (), memberCB.getItemAt (memberCB.getSelectedIndex ()));
}
public void actionRemoveMember () {
login.removeGroupMember (groupNameLabel.getText (), memberList.getSelectedValue ());
}
// ========================================
public void updateLogin (String login) {}
public void updateGroup (String group) {
updateCommands ();
groupsList.setSelectedValue (group, true);
}
public void updateGroups (String[] groupsName) {
if (groupsName == null)
return;
groupsNameList.setListData (groupsName);
if (askedGroupName != null && Arrays.binarySearch (groupsName, askedGroupName) < 0) {
askedGroupName = null;
infoGroup (null);
}
groupsList.setListData (groupsName);
groupsList.setSelectedValue (login.getGroup (), true);
}
public void infoGroup (Login.Group group) {
if (askedGroupName == null || group == null) {
groupNameLabel.setText ("");
createdLabel.setText ("");
updatedLabel.setText ("");
ipLabel.setText ("");
updatedByLabel.setText ("");
adminList.setListData (new String [0]);
memberList.setListData (new String [0]);
} else if (askedGroupName.equals (group.name)) {
groupNameLabel.setText (group.name);
createdLabel.setText (group.created);
updatedLabel.setText (group.updated);
ipLabel.setText (group.ip);
updatedByLabel.setText (group.updatedBy);
adminList.setListData (group.admin);
memberList.setListData (group.member);
}
}
public void loginState (String state) {
updateCommands ();
if (Login.unknownToken.equals (state)) {
actionLog ();
}
}
// ========================================
private Hashtable<String, Vector<AbstractButton>> commands = new Hashtable<String, Vector<AbstractButton>> ();
public void addActiveButtons (Hashtable<String, AbstractButton> buttons) {
for (String actionName : loginActionsNames)
commands.get (actionName).add (buttons.get (actionName));
updateCommands ();
}
// public void removeCommand (String actionName, AbstractButton command) {
// commands.get (actionName).remove (command);
// }
// ========================================
public synchronized void updateCommands () {
boolean isUnknowned = Login.unknownToken.equals (login.getState ());
for (AbstractButton logCommand : commands.get (actionLog))
logCommand.setEnabled (isUnknowned);
for (AbstractButton unlogCommand : commands.get (actionUnlog))
unlogCommand.setEnabled (!isUnknowned);
for (AbstractButton editLoginCommand : commands.get (actionEditLogin))
editLoginCommand.setEnabled (!isUnknowned);
for (AbstractButton editGroupCommand : commands.get (actionEditGroup))
editGroupCommand.setEnabled (!isUnknowned);
boolean isGroup = !login.getGroup ().isEmpty ();
for (AbstractButton joinGroupCommand : commands.get (actionJoinGroup))
joinGroupCommand.setEnabled (!isUnknowned && !isGroup);
for (AbstractButton leftGroupCommand : commands.get (actionLeftGroup))
leftGroupCommand.setEnabled (!isUnknowned && isGroup);
}
// ========================================
}

View File

@ -0,0 +1,16 @@
package network.login;
/**
Modificaion de modèle qui peuvent être observé.
*/
public interface LoginObserver {
// ========================================
public void updateLogin (String login);
public void updateGroup (String groupName);
public void updateGroups (String[] groupsName);
public void infoGroup (Login.Group group);
public void loginState (String state);
// ========================================
}

24
src/java/overview.html Normal file
View File

@ -0,0 +1,24 @@
<html><body>
<p>
En r&eacute;sum&eacute;, les fichiers sources qui vous sont pr&eacute;sent&eacute;s,
sont les versions succ&eacute;ssives de la m&ecirc;me application,
pour vous permettre d'aprendre Java pas apr&egrave;s pas.
</p>
<p>
La premi&egrave;re version &agrave; consulter est bien &eacute;videment
la version 1.
Les versions suivantes suivent l'ordre num&eacute;rique.
</p>
<p>
Ce texte provient de la documentation mise dans le "pseudo" fichier HTML de nom
"overview.html" &agrave; la racines des fichiers sources.
Voici un ordre de lecture des paquetages.
<ul>
<li>misc</li>
<li>tool</li>
<li>network</li>
</ul>
@author F. Merciol
</p>
</body></html>

View File

@ -0,0 +1,29 @@
package tool;
import javax.swing.SwingUtilities;
import misc.Bundle;
import misc.Config;
import tool.controller.BundleManagerController;
public class LaunchBundleManager {
// ========================================
static public void main (String [] arg) {
Config.setPWD (LaunchBundleManager.class);
Config.load ("BundleManager");
Bundle.load ("Help");
Bundle.load ("ToolBar");
Bundle.load ("Controller");
Bundle.load ("BundleManager");
SwingUtilities.invokeLater (new Runnable() {
public void run() {
new BundleManagerController ();
}
});
}
// ========================================
}

View File

@ -0,0 +1,110 @@
package tool.controller;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Image;
import java.text.MessageFormat;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import misc.Bundle;
import misc.Config;
import misc.Controller;
import misc.HelpManager;
import misc.MultiToolBarBorderLayout;
import misc.ToolBarManager;
import misc.Util;
import tool.model.BundleManagerModel;
import tool.model.BundleManagerObserver;
import tool.view.BundleManagerManager;
import tool.view.BundleManagerMenu;
import tool.view.BundleManagerToolBar;
import tool.view.BundleManagerView;
import tool.view.SourceIteratorView;
public class BundleManagerController extends Controller<BundleManagerModel> implements BundleManagerObserver {
// ========================================
public BundleManagerController () {
super (new BundleManagerModel ());
}
// ========================================
BundleManagerModel bundleManagerModel;
BundleManagerManager bundleManagerManager;
HelpManager helpManager;
BundleManagerView bundleManagerView;
BundleManagerMenu bundleManagerMenu;
BundleManagerToolBar bundleManagerToolBar;
ToolBarManager toolBarManager;
// ========================================
public String getTitle () {
String bundleName = bundleManagerManager.getBundleName ();
return MessageFormat.format (Bundle.getTitle ("BundleEditor"),
(bundleName == null) ? Bundle.getAction ("Empty") : bundleName);
}
public Image getIcon () { return Util.loadImage (Config.getString ("BundleIcon", "data/images/bundle/bundle.png")); }
// ========================================
protected void createModel (BundleManagerModel bundleManagerModel) {
this.bundleManagerModel = bundleManagerModel;
bundleManagerModel.addBundleObserver (this);
}
// ========================================
protected Component createGUI () {
JPanel contentPane = new JPanel (new MultiToolBarBorderLayout ());
toolBarManager = new ToolBarManager (getIcon (), contentPane);
bundleManagerView = new BundleManagerView (bundleManagerModel);
bundleManagerManager = new BundleManagerManager (this, bundleManagerModel, bundleManagerView);
JSplitPane splitPane = new JSplitPane (JSplitPane.VERTICAL_SPLIT,
bundleManagerView, new SourceIteratorView ());
splitPane.setOneTouchExpandable (true);
helpManager = new HelpManager (this, "BundleManager");
bundleManagerToolBar = new BundleManagerToolBar (this, bundleManagerManager, helpManager, toolBarManager);
contentPane.add (splitPane, BorderLayout.CENTER);
return contentPane;
}
// ========================================
protected JMenuBar createMenuBar () {
return bundleManagerMenu = new BundleManagerMenu (this, bundleManagerManager, helpManager, toolBarManager);
}
// ========================================
protected boolean tryClosingWindows () {
toolBarManager.saveLocation ();
Config.save ("BundleManager");
if (bundleManagerModel.getModified ()) {
switch (JOptionPane.showConfirmDialog (jFrame, Bundle.getLabel ("SaveBundle"), Bundle.getTitle ("BundleNotSaved"),
JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE)) {
case JOptionPane.YES_OPTION:
bundleManagerManager.actionSave ();
return true;
case JOptionPane.NO_OPTION:
return true;
case JOptionPane.CANCEL_OPTION:
case JOptionPane.CLOSED_OPTION:
return false;
}
}
return true;
}
// ========================================
public void dataModifiedChange () { jFrame.setTitle (getTitle ()); }
public void localesUpdated () {}
public void dataUpdated () {}
// ========================================
}

View File

@ -0,0 +1,248 @@
package tool.model;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Hashtable;
import java.util.Properties;
import java.util.TreeSet;
import java.util.Vector;
import misc.Bundle;
import misc.Log;
public class BundleManagerModel {
// ========================================
static public final String extention = ".properties";
private Hashtable<String, Properties> bundles;
private TreeSet<String> keys;
private TreeSet<String> locales;
// ========================================
public final TreeSet<String> getKeys () {
return keys;
}
// ========================================
public String getKeyByIndex (int idx) {
return (String) keys.toArray () [idx];
}
// ========================================
public final TreeSet<String> getLocales () {
return locales;
}
// ========================================
public String getLocaleByIndex (int idx) {
return (String) locales.toArray () [idx];
}
// ========================================
private boolean modified = false;
public boolean getModified () {
return modified;
}
// ========================================
public BundleManagerModel () {
empty ();
}
// ========================================
public void empty () {
bundles = new Hashtable<String, Properties> ();
keys = new TreeSet<String> ();
locales = new TreeSet<String> ();
modified = false;
broadcastMethode ("localesUpdated");
broadcastMethode ("dataUpdated");
broadcastMethode ("dataModifiedChange");
}
// ========================================
public void open (File bundleDir, final String bundleName, boolean merge) {
File [] bundleFile = bundleDir.listFiles (new FilenameFilter () {
public boolean accept (File dir, String name) {
return name.startsWith (bundleName) && name.endsWith (extention);
}
});
if (!merge)
empty ();
int bundleNameLength = bundleName.length ();
int extentionLength = extention.length ();
for (File file : bundleFile) {
String fileName = file.getName ();
locales.add (fileName.substring (bundleNameLength, fileName.length ()-extentionLength));
}
for (String locale : locales) {
try {
Properties properties = new Properties ();
FileInputStream fileInputStream = new FileInputStream (new File (bundleDir, bundleName+locale+extention));
properties.load (fileInputStream);
fileInputStream.close ();
Properties old = bundles.get (locale);
if (old != null && merge) {
for (Object key : old.keySet ())
properties.put (key, old.get (key));
}
bundles.put (locale, properties);
for (Object key : properties.keySet ())
keys.add ((String) key);
} catch (IOException e) {
System.err.println (MessageFormat.format (Bundle.getException ("CantLoad"), locale));
}
}
modified = merge;
broadcastMethode ("localesUpdated");
broadcastMethode ("dataUpdated");
broadcastMethode ("dataModifiedChange");
}
// ========================================
public void saveAs (File bundleDir, final String bundleName) {
// XXX en cas de réécriture dans le meme repertoire supprimer les "locale" supprimes
bundleDir.mkdirs ();
boolean trouble = false;
for (String locale : locales) {
try {
FileOutputStream fileOutputStream = new FileOutputStream (new File (bundleDir, bundleName+locale+extention));
bundles.get (locale).store (fileOutputStream, Bundle.getString ("HeaderBundleFile", null));
fileOutputStream.close ();
} catch (IOException e) {
System.err.println (MessageFormat.format (Bundle.getException ("CantSave"), locale));
trouble = true;
}
}
modified = trouble;
broadcastMethode ("dataModifiedChange");
}
// ========================================
public void addKey (String newKey) {
if (keys.contains (newKey))
throw new IllegalArgumentException (MessageFormat.format (Bundle.getException ("DuplicatedKey"), newKey));
keys.add (newKey);
broadcastMethode ("dataUpdated");
}
// ========================================
public void renameKey (String key, String newKey) {
if (keys.contains (newKey))
throw new IllegalArgumentException (MessageFormat.format (Bundle.getException ("DuplicatedKey"), newKey));
for (String locale : locales) {
try {
Properties properties = bundles.get (locale);
String val = properties.getProperty (key);
properties.remove (key);
properties.setProperty (newKey, val);
modified = true;
} catch (Exception e) {
// key not defined on this locale
}
}
keys.remove (key);
keys.add (newKey);
broadcastMethode ("dataUpdated");
broadcastMethode ("dataModifiedChange");
}
// ========================================
public void removeKey (String key) {
if (!keys.contains (key))
return;
for (String locale : locales) {
try {
Properties properties = bundles.get (locale);
properties.remove (key);
modified = true;
} catch (Exception e) {
// key not defined on this locale
}
}
keys.remove (key);
broadcastMethode ("dataUpdated");
broadcastMethode ("dataModifiedChange");
}
// ========================================
public void add (String locale) {
if (locales.contains (locale))
return;
locales.add (locale);
bundles.put (locale, new Properties ());
modified = true;
broadcastMethode ("localesUpdated");
broadcastMethode ("dataModifiedChange");
}
// ========================================
public void renameLocale (String locale, String newLocale) {
if (!locales.contains (locale))
return;
if (locales.contains (newLocale))
throw new IllegalArgumentException (MessageFormat.format (Bundle.getException ("DuplicatedLocale"),
newLocale));
locales.remove (locale);
bundles.put (newLocale, bundles.remove (locale));
locales.add (newLocale);
modified = true;
broadcastMethode ("localesUpdated");
broadcastMethode ("dataModifiedChange");
}
// ========================================
public void removeLocale (String locale) {
if (!locales.contains (locale))
return;
locales.remove (locale);
bundles.remove (locale);
modified = true;
broadcastMethode ("localesUpdated");
broadcastMethode ("dataModifiedChange");
}
// ========================================
public String get (String locale, String key) {
try {
return bundles.get (locale).getProperty (key);
} catch (Exception e) {
return null;
}
}
// ========================================
public void set (String locale, String key, String val) {
String oldVal = get (locale, key);
if (val == oldVal || val.equals (oldVal))
return;
bundles.get (locale).setProperty (key, val);
modified = true;
broadcastMethode ("dataUpdated");
broadcastMethode ("dataModifiedChange");
}
// ========================================
Vector<BundleManagerObserver> bundleObservers = new Vector<BundleManagerObserver> ();
public void addBundleObserver (BundleManagerObserver bundleObserver) { bundleObservers.add (bundleObserver); }
public void removeBundleObserver (BundleManagerObserver bundleObserver) { bundleObservers.remove (bundleObserver); }
// ========================================
public void broadcastMethode (String methodeName) {
try {
Method methode = BundleManagerObserver.class.getMethod (methodeName);
for (BundleManagerObserver bundleObserver : bundleObservers)
methode.invoke (bundleObserver);
} catch (Exception e) {
Log.keepLastException ("BundleManagerModel::broadcastMethode", e);
}
}
// ========================================
}

View File

@ -0,0 +1,11 @@
package tool.model;
public interface BundleManagerObserver {
// ========================================
public void dataModifiedChange ();
public void localesUpdated ();
public void dataUpdated ();
// ========================================
}

View File

@ -0,0 +1,104 @@
package tool.model;
import java.io.*;
import java.util.*;
public class SourceIteratorModel {
// ========================================
Vector<File> files = new Vector<File> ();
Enumeration<File> javaEnumeration;
// ========================================
public SourceIteratorModel (File dir) {
add (dir);
javaEnumeration = files.elements ();
}
// ========================================
private void add (File dir) {
for (File file :
dir.listFiles (new FilenameFilter () {
public boolean accept (File dir, String name) {
return name.endsWith (".java");
}
}))
files.add (file);
for (File subdir :
dir.listFiles (new FileFilter () {
public boolean accept (File child) {
return child.isDirectory ();
}
}))
add (subdir);
}
// ========================================
public boolean hasMoreJava () {
return javaEnumeration.hasMoreElements ();
}
// ========================================
public File nextJava () {
return javaEnumeration.nextElement ();
}
// ========================================
String nextString = null;
int currentLine = 0;
File currentFile;
BufferedReader currentBuffered = null;
// ========================================
public int getCurrentLine () {
return currentLine;
}
// ========================================
public File getCurrentFile () {
return currentFile;
}
// ========================================
public boolean hasMoreString () {
for (;;) {
if (nextString != null)
return true;
if (currentBuffered == null) {
if (! hasMoreJava ())
return false;
try {
currentLine = -1;
currentFile = nextJava ();
currentBuffered = new BufferedReader (new FileReader (currentFile));
} catch (FileNotFoundException e) {
System.err.println ("skip not found file ("+e+")");
continue;
}
}
try {
String line = currentBuffered.readLine ();
currentLine++;
if (line == null) {
currentBuffered = null;
continue;
}
if (line.indexOf ("\"") >= 0)
nextString = line;
} catch (IOException e) {
System.err.println ("skip premature end of file ("+e+")");
}
}
}
// ========================================
public String nextString () {
if (! hasMoreString ())
return null;
String result = nextString;
nextString = null;
return result;
}
// ========================================
}

View File

@ -0,0 +1,9 @@
/**
* Ordre de lecture des paquetages et des classes<ul>
* <li>BundleManagerObserver</li>
* <li>BundleManagerModel</li>
* <li>SourceIteratorModel</li>
* </ul>
* @author F. Merciol
*/
package tool.model;

View File

@ -0,0 +1,11 @@
/**
* Ordre de lecture des paquetages et des classes<ul>
* <li>model</li>
* <li>view</li>
* <li>controller</li>
* <li>LaunchBundleManager</li>
* </ul>
* @author F. Merciol
*/
package tool;

View File

@ -0,0 +1,286 @@
package tool.view;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.Vector;
import java.util.regex.Pattern;
import javax.swing.AbstractButton;
import javax.swing.Box;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.filechooser.FileNameExtensionFilter;
import misc.ApplicationManager;
import misc.Bundle;
import misc.Config;
import misc.OwnFrame;
import misc.Util;
import tool.model.BundleManagerModel;
import tool.model.BundleManagerObserver;
@SuppressWarnings ("serial") public class BundleManagerManager
implements ApplicationManager, ActionListener, BundleManagerObserver {
// ========================================
BundleManagerModel bundleManagerModel;
OwnFrame controller;
BundleManagerView bundleManagerView;
JFileChooser jFileChooser = new JFileChooser (Config.getString ("BundleDir", "."));
File bundleDir = null;
String bundleName = null;
public String getBundleName () { return bundleName; }
// ========================================
static public final List<String> fileActionsNames = Arrays.asList ("Empty", "Open", "Merge", "Save", "SaveAs");
static public final List<String> modelActionsNames = Arrays.asList ("AddKey", "RemoveKey", "AddLocale", "RenameLocale", "RemoveLocale");
@SuppressWarnings ("unchecked")
static public final Hashtable<String, Method> actionsMethod =
Util.collectMethod (BundleManagerManager.class, Util.merge (fileActionsNames, modelActionsNames));
public void actionPerformed (ActionEvent e) {
Util.actionPerformed (actionsMethod, e, this);
}
// ========================================
public void updateBundle () {
jFileChooser.setFileFilter (new FileNameExtensionFilter (Bundle.getLabel ("BundelPropertieFile"), "properties"));
}
// ========================================
public BundleManagerManager (OwnFrame controller, BundleManagerModel bundleManagerModel, BundleManagerView bundleManagerView) {
this.controller = controller;
this.bundleManagerModel = bundleManagerModel;
this.bundleManagerView = bundleManagerView;
jFileChooser.setMultiSelectionEnabled (false);
Bundle.addBundleObserver (this);
bundleManagerModel.addBundleObserver (this);
updateBundle ();
}
// ========================================
public void actionEmpty () {
if (bundleManagerModel.getModified () &&
JOptionPane.showConfirmDialog (controller.getJFrame (), Bundle.getLabel ("RealyDiscardBundle"),
Bundle.getTitle ("BundleNotSaved"),
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE) != JOptionPane.YES_OPTION)
return;
bundleName = null;
bundleManagerModel.empty ();
}
// ========================================
private void actionOpen (boolean merge) {
if (bundleManagerModel.getModified () &&
JOptionPane.showConfirmDialog (controller.getJFrame (), Bundle.getLabel ("RealyDiscardBundle"),
Bundle.getTitle ("BundleNotSaved"),
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE) != JOptionPane.YES_OPTION)
return;
jFileChooser.setFileSelectionMode (JFileChooser.FILES_ONLY);
if (jFileChooser.showOpenDialog (controller.getJFrame ()) != JFileChooser.APPROVE_OPTION)
return;
File file = jFileChooser.getSelectedFile ();
setBundleDir (file.getParentFile ());
setBundleName (file.getName ());
bundleManagerModel.open (bundleDir, bundleName, merge);
Config.save ("BundleManager");
}
// ========================================
public void actionOpen () {
actionOpen (false);
}
// ========================================
public void actionMerge () {
actionOpen (true);
}
// ========================================
private void setBundleName (String fileName) {
if (fileName.endsWith (BundleManagerModel.extention))
fileName = fileName.substring (0, fileName.length () - BundleManagerModel.extention.length ());
Pattern pattern = Pattern.compile (".*_[a-zA-Z]{2}");
if (pattern.matcher (fileName).matches ())
fileName = fileName.substring (0, fileName.length () - 3);
if (pattern.matcher (fileName).matches ())
fileName = fileName.substring (0, fileName.length () - 3);
bundleName = fileName;
}
// ========================================
public void actionSave () {
if (bundleDir == null || bundleName == null) {
actionSaveAs ();
return;
}
bundleManagerModel.saveAs (bundleDir, bundleName);
Config.save ("BundleManager");
}
// ========================================
public void actionSaveAs () {
jFileChooser.setFileSelectionMode ((bundleName == null) ?
JFileChooser.FILES_ONLY : JFileChooser.FILES_AND_DIRECTORIES);
if (jFileChooser.showSaveDialog (controller.getJFrame ()) != JFileChooser.APPROVE_OPTION)
return;
File file = jFileChooser.getSelectedFile ();
if (file.isDirectory ())
setBundleDir (file);
else {
setBundleDir (file.getParentFile ());
setBundleName (file.getName ());
}
actionSave ();
}
// ========================================
public void actionAddKey () {
String newKey =
JOptionPane.showInputDialog (controller.getJFrame (), Bundle.getLabel ("NewKey"),
Bundle.getTitle ("AddKey"),
JOptionPane.INFORMATION_MESSAGE);
if (newKey == null)
return;
bundleManagerModel.addKey (newKey);
}
// ========================================
public void actionRemoveKey () {
if (bundleManagerView.bundleJTable.getSelectedRowCount () != 1) {
JOptionPane.showMessageDialog (controller.getJFrame (), Bundle.getMessage ("NoKey"), Bundle.getTitle ("NoKey"),
JOptionPane.WARNING_MESSAGE);
return;
}
int selected = bundleManagerView.bundleJTable.getSelectedRow ();
bundleManagerModel.removeKey (bundleManagerModel.getKeyByIndex (selected));
}
// ========================================
public void actionAddLocale () {
Locale [] locales = Bundle.getAllLocales ();
JComboBox<String> localesList = Bundle.getJComboFlags (locales);
localesList.setEditable (true);
JPanel jPanel = new JPanel (new BorderLayout ());
jPanel.add (new JLabel (Bundle.getMessage ("AddLocale")), BorderLayout.PAGE_START);
jPanel.add (localesList, BorderLayout.CENTER);
if (JOptionPane.OK_OPTION != JOptionPane.showConfirmDialog (controller.getJFrame (), jPanel, Bundle.getTitle ("AddLocale"),
JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE))
return;
bundleManagerModel.add ("_"+locales[localesList.getSelectedIndex ()].toString ());
}
// ========================================
public void actionRenameLocale () {
if (bundleManagerView.bundleJTable.getSelectedColumnCount () != 1) {
JOptionPane.showMessageDialog (controller.getJFrame (), Bundle.getMessage ("NoLocale"),
Bundle.getTitle ("NoLocale"),
JOptionPane.WARNING_MESSAGE);
return;
}
String newLocale =
JOptionPane.showInputDialog (controller.getJFrame (), Bundle.getMessage ("RenameLocale"),
Bundle.getTitle ("RenameLocale"),
JOptionPane.INFORMATION_MESSAGE);
if (newLocale == null)
return;
bundleManagerModel.renameLocale (bundleManagerView.bundleColumnNames.get (bundleManagerView.bundleJTable.getSelectedColumn ()), newLocale);
}
// ========================================
public void actionRemoveLocale () {
if (bundleManagerView.bundleJTable.getSelectedColumnCount () != 1) {
JOptionPane.showMessageDialog (controller.getJFrame (), Bundle.getMessage ("NoLocale"),
Bundle.getTitle ("NoLocale"),
JOptionPane.WARNING_MESSAGE);
return;
}
bundleManagerModel.removeLocale (bundleManagerView.bundleColumnNames.get (bundleManagerView.bundleJTable.getSelectedColumn ()));
}
// ========================================
private void setBundleDir (File dir) {
bundleDir = dir;
try {
Config.setString ("BundleDir", dir.getCanonicalPath ());
} catch (Exception e) {
}
}
// ========================================
private Vector<AbstractButton> saveCommands = new Vector<AbstractButton> ();
public void addSaveCommand (AbstractButton saveCommand) {
if (saveCommand == null)
return;
saveCommands.add (saveCommand);
saveCommand.setEnabled (bundleName != null && bundleManagerModel.getModified ());
}
// ========================================
private Vector<AbstractButton> saveAsCommands = new Vector<AbstractButton> ();
public void addSaveAsCommand (AbstractButton saveAsCommand) {
if (saveAsCommand == null)
return;
saveAsCommands.add (saveAsCommand);
saveAsCommand.setEnabled (bundleManagerModel.getModified ());
}
// ========================================
public void broadcastSaveUpdate () {
boolean enable = bundleName != null && bundleManagerModel.getModified ();
for (AbstractButton saveCommand : saveCommands)
saveCommand.setEnabled (enable);
}
// ========================================
public void broadcastSaveAsUpdate () {
boolean enable = bundleManagerModel.getModified ();
for (AbstractButton saveAsCommand : saveAsCommands)
saveAsCommand.setEnabled (enable);
}
// ========================================
public void dataModifiedChange () {
broadcastSaveUpdate ();
broadcastSaveAsUpdate ();
}
public void localesUpdated () {}
public void dataUpdated () {}
// ========================================
public void addMenuItem (JMenu... jMenu) {
int idx = 0;
Util.addMenuItem (fileActionsNames, this, jMenu[idx++]);
Util.addMenuItem (modelActionsNames, this, jMenu[idx++]);
}
public void addIconButtons (Container... containers) {
int idx = 0;
Util.addIconButton (fileActionsNames, this, containers[idx++]);
Util.addIconButton (modelActionsNames, this, containers[idx++]);
}
public void addActiveButtons (Hashtable<String, AbstractButton> buttons) {
addSaveCommand (buttons.get ("Save"));
addSaveAsCommand (buttons.get ("SaveAs"));
}
// ========================================
}

View File

@ -0,0 +1,44 @@
package tool.view;
import java.util.Hashtable;
import javax.swing.AbstractButton;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import misc.ApplicationManager;
import misc.HelpManager;
import misc.Log;
import misc.ToolBarManager;
import misc.Util;
@SuppressWarnings ("serial") public class BundleManagerMenu extends JMenuBar {
// ========================================
public BundleManagerMenu (ApplicationManager controllerManager, ApplicationManager bundleManagerManager,
ApplicationManager helpManager, ToolBarManager toolBarManager) {
setLayout (new BoxLayout (this, BoxLayout.X_AXIS));
JMenu fileMenu = Util.addJMenu (this, "File");
JMenu bundleMenu = Util.addJMenu (this, "Bundle");
add (Box.createHorizontalGlue ());
JMenu helpMenu = Util.addJMenu (this, "Help");
controllerManager.addMenuItem (fileMenu);
bundleManagerManager.addMenuItem (fileMenu, bundleMenu);
helpManager.addMenuItem (helpMenu);
toolBarManager.addMenuItem (helpMenu);
Hashtable<String, AbstractButton> buttons = new Hashtable<String, AbstractButton> ();
Util.collectButtons (buttons, fileMenu);
Util.collectButtons (buttons, bundleMenu);
Util.collectButtons (buttons, helpMenu);
controllerManager.addActiveButtons (buttons);
bundleManagerManager.addActiveButtons (buttons);
helpManager.addActiveButtons (buttons);
toolBarManager.addActiveButtons (buttons);
}
// ========================================
}

View File

@ -0,0 +1,45 @@
package tool.view;
import java.awt.Component;
import java.util.Hashtable;
import javax.swing.AbstractButton;
import javax.swing.Box;
import javax.swing.JComponent;
import javax.swing.JToolBar;
import misc.ApplicationManager;
import misc.Bundle;
import misc.HelpManager;
import misc.Log;
import misc.ToolBarManager;
import misc.Util;
public class BundleManagerToolBar {
// ========================================
static public String defaultCardinalPoint = "North";
public BundleManagerToolBar (ApplicationManager controllerManager, BundleManagerManager bundleManagerManager,
HelpManager helpManager, ToolBarManager toolBarManager) {
JToolBar fileToolBar = toolBarManager.newJToolBar ("File", defaultCardinalPoint);
JToolBar bundleToolBar = toolBarManager.newJToolBar ("Bundle", defaultCardinalPoint);
JToolBar helpToolBar = toolBarManager.newJToolBar ("Help", defaultCardinalPoint);
controllerManager.addIconButtons (fileToolBar);
bundleManagerManager.addIconButtons (fileToolBar, bundleToolBar);
helpManager.addIconButtons (helpToolBar);
toolBarManager.addIconButtons (helpToolBar);
Hashtable<String, AbstractButton> buttons = new Hashtable<String, AbstractButton> ();
Util.collectButtons (buttons, fileToolBar);
Util.collectButtons (buttons, bundleToolBar);
Util.collectButtons (buttons, helpToolBar);
controllerManager.addActiveButtons (buttons);
bundleManagerManager.addActiveButtons (buttons);
helpManager.addActiveButtons (buttons);
toolBarManager.addActiveButtons (buttons);
}
// ========================================
}

View File

@ -0,0 +1,108 @@
package tool.view;
import java.awt.BorderLayout;
import java.util.Vector;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.DefaultTableModel;
import misc.Bundle;
import tool.model.BundleManagerModel;
import tool.model.BundleManagerObserver;
@SuppressWarnings ("serial") public class BundleManagerView extends JPanel implements BundleManagerObserver {
// ========================================
BundleManagerModel bundleManagerModel;
// ========================================
Vector<String> bundleColumnNames;
DefaultTableModel bundleTableModel;
JTable bundleJTable;
// ========================================
public void updateBundle () {
localesUpdated ();
}
// ========================================
public BundleManagerView (final BundleManagerModel bundleManagerModel) {
super (new BorderLayout ());
this.bundleManagerModel = bundleManagerModel;
bundleJTable = new JTable ();
bundleJTable.getColumnModel ().setColumnSelectionAllowed (true);
bundleJTable.setSelectionMode (ListSelectionModel.SINGLE_SELECTION);
JScrollPane scrollBundle = new JScrollPane (bundleJTable);
bundleJTable.setFillsViewportHeight (true);
add (scrollBundle, BorderLayout.CENTER);
bundleManagerModel.addBundleObserver (this);
updateBundle ();
Bundle.addBundleObserver (this);
}
// ========================================
public void dataModifiedChange () {}
// ========================================
public void localesUpdated () {
bundleColumnNames = new Vector<String> ();
bundleColumnNames.add (Bundle.getLabel ("Keys"));
bundleColumnNames.addAll (bundleManagerModel.getLocales ());
bundleTableModel = new DefaultTableModel (bundleColumnNames, 0) {
private static final long serialVersionUID = 1L;
public String getColumnName(int col) {
return bundleColumnNames.get (col);
}
public int getColumnCount () {
return bundleColumnNames.size ();
}
public Object getValueAt (int row, int col) {
String key = bundleManagerModel.getKeyByIndex (row);
if (col == 0)
return key;
String locale = bundleManagerModel.getLocaleByIndex (col-1);
return bundleManagerModel.get (locale, key);
}
public void setValueAt (Object value, int row, int col) {
String key = bundleManagerModel.getKeyByIndex (row);
if (col == 0) {
String newKey = (String) value;
if (newKey.equals (key))
return;
bundleManagerModel.renameKey (key, newKey);
return;
}
String locale = bundleManagerModel.getLocaleByIndex (col-1);
bundleManagerModel.set (locale, key, (String) value);
//fireTableCellUpdated (row, col);
}
public boolean isCellEditable (int row, int column) {
return true;
}
};
bundleJTable.setModel (bundleTableModel);
dataUpdated ();
}
// ========================================
public void dataUpdated () {
bundleTableModel.setRowCount (0);
for (String key : bundleManagerModel.getKeys ()) {
Vector<String> row = new Vector<String> ();
row.add (key);
for (String locale : bundleManagerModel.getLocales ())
row.add (bundleManagerModel.get (locale, key));
bundleTableModel.addRow (row);
}
bundleTableModel.fireTableDataChanged ();
}
// ========================================
}

View File

@ -0,0 +1,127 @@
package tool.view;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import misc.Bundle;
import misc.Config;
import misc.Util;
import tool.model.SourceIteratorModel;
@SuppressWarnings ("serial") public class SourceIteratorView extends JPanel implements ActionListener {
// ========================================
SourceIteratorModel sourceIteratorModel = null;
// ========================================
String[] columnLabels = { "FileName", "LineNumber", "Line" };
DefaultTableModel sourceIteratorTableModel;
JTable sourceIteratorJTable;
// ========================================
static public final List<String> actionsNames = Arrays.asList ("Init", "Next");
@SuppressWarnings ("unchecked")
static public final Hashtable<String, Method> actionsMethod =
Util.collectMethod (SourceIteratorView.class, actionsNames);
public void actionPerformed (ActionEvent e) {
Util.actionPerformed (actionsMethod, e, this);
}
// ========================================
public void updateBundle () {
Util.setColumnLabels (sourceIteratorJTable, columnLabels);
}
// ========================================
DefaultTableCellRenderer greenRendered = new DefaultTableCellRenderer ();
DefaultTableCellRenderer whiteRendered = new DefaultTableCellRenderer ();
// ========================================
public SourceIteratorView () {
super (new BorderLayout ());
greenRendered.setBackground (Color.GREEN);
whiteRendered.setBackground (Color.WHITE);
int [] columnWidth = {
200,
5,
1000
};
sourceIteratorTableModel = new DefaultTableModel (columnLabels, 1);
sourceIteratorJTable = new JTable (sourceIteratorTableModel);
updateBundle ();
for (int i = 0; i < sourceIteratorTableModel.getColumnCount (); i++)
sourceIteratorJTable.getColumnModel ().getColumn (i).setPreferredWidth (columnWidth [i]);
sourceIteratorJTable.getColumnModel ().setColumnSelectionAllowed (true);
sourceIteratorJTable.setSelectionMode (ListSelectionModel.SINGLE_SELECTION);
add (sourceIteratorJTable.getTableHeader (), BorderLayout.PAGE_START);
add (sourceIteratorJTable, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel ();
Util.addButton (actionsNames, this, buttonPanel);
add (buttonPanel, BorderLayout.PAGE_END);
Bundle.addBundleObserver (this);
}
// ========================================
JFileChooser jFileChooser = new JFileChooser (Config.getString ("SourceIteratorDir", "."));
// ========================================
public void actionInit () {
jFileChooser.setFileSelectionMode (JFileChooser.DIRECTORIES_ONLY);
if (jFileChooser.showOpenDialog (this) != JFileChooser.APPROVE_OPTION)
return;
File dir = jFileChooser.getSelectedFile ();
sourceIteratorModel = new SourceIteratorModel (dir);
actionNext ();
try {
Config.setString ("SourceIteratorDir", dir.getCanonicalPath ());
} catch (Exception e) {
}
}
// ========================================
public void actionNext () {
if (sourceIteratorModel == null) {
JOptionPane.showMessageDialog (this, Bundle.getMessage ("NoSourceDir"), Bundle.getTitle ("NoSource"),
JOptionPane.WARNING_MESSAGE);
return;
}
if (! sourceIteratorModel.hasMoreString ()) {
sourceIteratorTableModel.setRowCount (0);
sourceIteratorTableModel.addRow (new String [] {"", "", ""});
sourceIteratorModel = null;
return;
}
String next = sourceIteratorModel.nextString ();
sourceIteratorTableModel.setRowCount (0);
sourceIteratorTableModel.addRow (new String [] {
""+sourceIteratorModel.getCurrentFile (),
""+sourceIteratorModel.getCurrentLine (),
next
});
sourceIteratorJTable.getColumnModel ().getColumn (2).setCellRenderer
((next.indexOf ("Bundle.") >= 0 || next.indexOf ("Config.") >= 0 ) ? greenRendered : whiteRendered);
}
// ========================================
}

View File

@ -0,0 +1,80 @@
package misc;
import java.util.Locale;
import javax.swing.JButton;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.JUnitCore;
public class BundleTest extends Assert {
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (BundleTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("misc.BundleTest");
}
// ========================================
static public int countObserver;
static public int countActioner;
@BeforeClass static public void setBundleObserver () {
Bundle.addBundleObserver (new Object () {
public void updateBundle () {
countObserver++;
}
});
Bundle.load ("BundleManager", Locale.US);
String action = "Quit";
JButton button = new JButton (Bundle.getAction (action)) {
private static final long serialVersionUID = 1L;
public void setText (String text) {
super.setText (text);
countActioner++;
}
};
Bundle.addLocalizedActioner (button);
button.setActionCommand (action);
}
// ========================================
@Test public void setLocale () {
Bundle.load ("BundleManager", Locale.US);
int oldValue = countObserver;
Bundle.setLocale (Locale.FRANCE);
assertTrue (oldValue+1 == countObserver);
assertTrue (countActioner == countObserver);
}
@Test public void load () {
int oldValue = countObserver;
Bundle.load ("BundleManager");
assertTrue (oldValue+1 == countObserver);
assertTrue (countActioner == countObserver);
}
@Test public void getLocales () {
Locale[] locales = Bundle.getApplicationsLocales ();
assertTrue (locales.length > 0);
Bundle.load ("BundleManager");
for (Locale locale : locales)
Bundle.setLocale (locale);
}
@Test public void getString () {
Bundle.load ("BundleManager", Locale.US);
String s1 = Bundle.getTitle ("BundleEditor");
Bundle.setLocale (Locale.FRANCE);
String s2 = Bundle.getTitle ("BundleEditor");
assertNotNull (s1);
assertNotNull (s2);
assertFalse (s1.equals (s2));
}
// ========================================
}

View File

@ -0,0 +1,46 @@
package misc;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.JUnitCore;
public class ColorCheckedLineTest extends Assert {
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (ColorCheckedLineTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("misc.ColorCheckedLineTest");
}
// ========================================
@Test public void ok () {
try {
System.err.print ("Test ok : ");
// something right
System.err.println (ColorCheckedLine.MSG_OK);
} catch (Exception e) {
System.err.println (ColorCheckedLine.MSG_OK);
}
}
// ========================================
@Test public void ko () {
try {
System.err.print ("Test ko : ");
// something wrong
int i = 0;
i = 1/i;
System.err.println (ColorCheckedLine.MSG_OK);
} catch (Exception e) {
System.err.println (ColorCheckedLine.MSG_KO);
}
}
// ========================================
}

View File

@ -0,0 +1,153 @@
package misc;
import java.awt.Container;
import java.awt.Point;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.JUnitCore;
public class ConfigTest extends Assert {
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (ConfigTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("misc.ConfigTest");
}
// ========================================
static public final String testApplicationName = "Test";
static public final String testConfigFileName =
Config.configSystemDir+System.getProperty ("file.separator")+testApplicationName+Config.configExt;
static public final String result = "result";
static public final String booleanTrue = "booleanTrue";
static public final String example = "example";
static public final String value = "value";
static public final String configContent =
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"+
"<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\">\n"+
"<properties>\n"+
" <entry key=\"FrameLocation\">[x=100,y=200]</entry>\n"+
" <entry key=\""+example+"\">"+value+"</entry>\n"+
" <entry key=\""+booleanTrue+"\">"+true+"</entry>\n"+
"</properties>\n";
public int getLines (String fileName)
throws FileNotFoundException, IOException {
long fileSize = (new File (fileName)).length ();
LineNumberReader lineNumberReader = new LineNumberReader (new FileReader (fileName));
lineNumberReader.skip (fileSize);
return lineNumberReader.getLineNumber ();
}
@BeforeClass static public void createTestConfig ()
throws FileNotFoundException {
PrintWriter configFile = new PrintWriter (testConfigFileName);
configFile.write (configContent);
configFile.close ();
}
@AfterClass static public void removeTestConfig () {
(new File (testConfigFileName)).delete ();
}
// ========================================
@Test public void load () {
boolean findFile = false;
for (String fileName :
(new File (Config.configSystemDir)).list (new FilenameFilter () {
public boolean accept (File dir, String name) {
return name.endsWith (Config.configExt);
}
})) {
findFile = true;
Config.setPWD (ConfigTest.class);
Config.load (fileName.substring (0, fileName.length () - Config.configExt.length ()));
assertTrue (Config.isLoaded ());
}
assertTrue (findFile);
}
@Test public void getString () {
Config.setPWD (ConfigTest.class);
Config.load (testApplicationName);
assertEquals (result, Config.getString (null, result));
assertEquals (value, Config.getString (example));
}
@Test (expected=IllegalArgumentException.class) public void getStringNullKey () {
Config.getString (null);
}
@Test public void getBoolean () {
Config.setPWD (ConfigTest.class);
Config.load (testApplicationName);
assertTrue (Config.getBoolean (booleanTrue, false));
assertFalse (Config.getBoolean (example, false));
}
@Test (expected=IllegalArgumentException.class) public void getBooleanNullKey () {
Config.getBoolean (null);
}
@Test public void save ()
throws FileNotFoundException, IOException {
int lines = getLines (testConfigFileName);
Config.setPWD (ConfigTest.class);
Config.load (testApplicationName);
Config.setString ("a", "b");
Config.save (testApplicationName);
assertTrue (lines < getLines (testConfigFileName));
Config.load (testApplicationName);
assertEquals ("b", Config.getString ("a"));
}
@Test public void setString () {
Config.setPWD (ConfigTest.class);
Config.load (testApplicationName);
Config.setString ("a", "b");
assertEquals ("b", Config.getString ("a"));
}
@Test public void setBoolean () {
Config.setPWD (ConfigTest.class);
Config.load (testApplicationName);
Config.setBoolean ("bool", true);
assertTrue (Config.getBoolean ("bool"));
Config.setBoolean ("bool", false);
assertFalse (Config.getBoolean ("bool"));
}
@Test public void saveLocation () {
Config.setPWD (ConfigTest.class);
Config.load (testApplicationName);
assertNull (Config.getString ("test"+Config.locationPostfix, null));
Container container = new Container ();
container.setLocation (10, 20);
Config.saveLocation ("test", container);
assertEquals ("[x=10,y=20]", Config.getString ("test"+Config.locationPostfix));
}
@Test public void loadLocation () {
Config.setPWD (ConfigTest.class);
Config.load (testApplicationName);
Container container = new Container ();
Config.loadLocation ("Frame", container, new Point (0, 0));
assertEquals (new Point (100, 200), container.getLocation ());
}
// ========================================
}

View File

@ -0,0 +1,39 @@
package misc;
import java.util.ResourceBundle;
import java.util.Locale;
import java.io.FileOutputStream;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.JUnitCore;
public class LocaleTest extends Assert {
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (LocaleTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("misc.LocaleTest");
}
// ========================================
@Test public void launch () {
Locale currentLocale = Locale.getDefault ();
//Locale currentLocale = new Locale ("fr", "FR");
ResourceBundle messages = ResourceBundle.getBundle ("Misc", currentLocale, Bundle.bundleControl);
assertNotNull (messages.getString ("ActionQuit"));
}
// ========================================
@Test public void save ()
throws java.io.IOException {
String arg = "/tmp/RemDumpProperties";
Bundle.load ("Misc");
System.getProperties ().storeToXML (new FileOutputStream (arg), Bundle.getString ("RemDumpProperties", null));
}
// ========================================
}

View File

@ -0,0 +1,63 @@
package misc;
import java.awt.Frame;
import java.util.Locale;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.JUnitCore;
public class TitledDialogTest extends Assert {
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (TitledDialogTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("misc.TitledDialogTest");
}
// ========================================
static public TitledDialog titledDialog;
@BeforeClass static public void setBundleObserver () {
Bundle.load ("BundleManager");
titledDialog = new TitledDialog (new Frame (), "BundleEditor");
}
// ========================================
@Test public void bundleReloaded () {
Bundle.load ("BundleManager", Locale.US);
String s1 = titledDialog.getTitle ();
Bundle.setLocale (Locale.FRANCE);
String s2 = titledDialog.getTitle ();
assertNotNull (s1);
assertNotNull (s2);
assertFalse (s1.equals (s2));
}
@Test public void setVisible () {
Config.setPWD (TitledDialogTest.class);
Config.load ("BundleManager");
titledDialog.setVisible (true);
assertTrue (titledDialog.isVisible ());
titledDialog.setVisible (false);
assertFalse (titledDialog.isVisible ());
}
@Test public void saveLocation () {
Config.setPWD (TitledDialogTest.class);
Config.load ("BundleManager");
assertNull (Config.getString ("BundleEditor"+Config.locationPostfix, null));
titledDialog.setVisible (true);
titledDialog.setVisible (false);
titledDialog.saveLocation ();
Object [] location = Config.coordonateFormat.parse (Config.getString ("BundleEditor"+Config.locationPostfix, null),
new java.text.ParsePosition (0));
assertTrue (((Number) location [0]).intValue () > 0);
assertTrue (((Number) location [1]).intValue () > 0);
}
// ========================================
}

View File

@ -0,0 +1,147 @@
package misc;
import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.List;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JMenuItem;
import javax.swing.JRadioButton;
import javax.swing.JMenuBar;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.JUnitCore;
public class UtilTest extends Assert {
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (UtilTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("misc.UtilTest");
}
// ========================================
static public final void isCapital (String s) {
assertTrue (Character.isUpperCase (s.charAt(0)));
for (int i = 1; i < s.length (); i++)
assertTrue (Character.isLowerCase (s.charAt(i)));
}
static public final List<String> actions = Arrays.asList ("Open", "Save", "Quit");
static public final ActionListener actionListener = new ActionListener () {
public void actionPerformed (ActionEvent e) {
}
};
@BeforeClass static public void createTestConfig () {
Bundle.load ("BundleManager");
}
// ========================================
@Test public void addRadioButton () {
Container container = new Container ();
ButtonGroup group = new ButtonGroup ();
Util.addRadioButton (actions, actionListener, group, "Quit", container);
assertTrue (actions.contains (group.getSelection ().getActionCommand ()));
assertTrue (container.getComponentCount () == actions.size ());
for (Component component : container.getComponents ()) {
JRadioButton button = (JRadioButton) component;
assertTrue (actions.contains (button.getActionCommand ()));
Arrays.asList (button.getActionListeners ()).contains (actionListener);
if ("Quit".equals (button.getActionCommand ())) {
assertEquals (group.getSelection ().getActionCommand (), button.getActionCommand ());
assertTrue (button.isSelected ());
} else
assertFalse (button.isSelected ());
}
}
@Test public void addButton () {
Container container = new Container ();
Util.addButton (actions, actionListener, container);
assertTrue (container.getComponentCount () == actions.size ());
for (Component component : container.getComponents ()) {
JButton button = (JButton) component;
assertTrue (actions.contains (button.getActionCommand ()));
Arrays.asList (button.getActionListeners ()).contains (actionListener);
}
}
@Test public void addIconButton () {
Container container = new Container ();
Util.addIconButton (actions, actionListener, container);
assertTrue (container.getComponentCount () == actions.size ());
for (Component component : container.getComponents ()) {
JButton button = (JButton) component;
assertNotNull (button.getIcon ());
assertTrue (actions.contains (button.getActionCommand ()));
Arrays.asList (button.getActionListeners ()).contains (actionListener);
}
}
@Test public void addMenuItem () {
Container container = new Container ();
Util.addMenuItem (actions, actionListener, container);
assertTrue (container.getComponentCount () == actions.size ());
for (Component component : container.getComponents ()) {
JMenuItem item = (JMenuItem) component;
assertTrue (actions.contains (item.getActionCommand ()));
Arrays.asList (item.getActionListeners ()).contains (actionListener);
}
}
@Test public void addCheckMenuItem () {
Container container = new Container ();
Util.addCheckMenuItem (actions, actionListener, container);
assertTrue (container.getComponentCount () == actions.size ());
for (Component component : container.getComponents ()) {
JMenuItem item = (JMenuItem) component;
assertTrue (actions.contains (item.getActionCommand ()));
Arrays.asList (item.getActionListeners ()).contains (actionListener);
}
}
@Test public void addJMenu () {
JMenuBar jMenuBar = new JMenuBar ();
Util.addJMenu (jMenuBar, "Help");
}
@Test public void setColumnLabels () {
// YYY
}
@Test public void packWindow () {}
@Test public void newJFrame () {}
@Test public void WindowAdapter () {}
@Test public void windowClosing () {}
@Test public void loadActionIcon () {}
@Test public void loadImageIcon () {}
@Test public void getDataUrl () {}
@Test public void collectMethod () {}
@Test public void collectButtons () {}
@Test public void actionPerformed () {}
@Test public void merge () {}
@Test public void toCapital () {
for (String s : Arrays.asList ("abcd", "AbCd", "aBcD", "ABCD"))
isCapital (Util.toCapital (s));
}
@Test (timeout=1500) public void sleep () {
long before = System.currentTimeMillis ();
Util.sleep (1);
long after = System.currentTimeMillis ();
long delta = after-before;
assertTrue (delta > 900 && delta < 1100);
}
}

View File

@ -0,0 +1,70 @@
package misc;
import java.io.StringBufferInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.junit.Test;
import org.junit.Ignore;
import org.junit.runner.JUnitCore;
import misc.XML;
@SuppressWarnings("deprecation")
public class XMLTest {
@Ignore ("for exemple") @Test (expected=IndexOutOfBoundsException.class, timeout=100) public void empty () {
new java.util.ArrayList<Object> ().get (0);
}
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (XMLTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("misc.XMLTest");
}
// ========================================
// XXX lecture de chaine, exriture dans une chaine différence
String badXmlString = "Hello Word";
String xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
"<request>\n"+
" <application name=\"ping\"/>\n"+
"</request>\n";
// ========================================
@Test (expected=java.io.IOException.class) public void badRead ()
throws javax.xml.parsers.ParserConfigurationException, org.xml.sax.SAXException, java.io.IOException {
XML.readDocument (new StringBufferInputStream (badXmlString));
}
// ========================================
@Test public void read ()
throws javax.xml.parsers.ParserConfigurationException, org.xml.sax.SAXException, java.io.IOException {
XML.readDocument (new StringBufferInputStream (xmlString));
}
// ========================================
@Test public void write ()
throws javax.xml.parsers.ParserConfigurationException {
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance ().newDocumentBuilder ();
Document doc = documentBuilder.newDocument ();
doc.setXmlStandalone (true);
Element elem = doc.createElement ("noeud1");
doc.appendChild (elem);
elem.setAttribute ("attr1", "val 1");
elem.appendChild (doc.createElement ("noeud2")).appendChild (doc.createElement ("noeud3"));
elem.appendChild (doc.createElement ("noeud4"));
Element elem3 = doc.createElement ("noeud5");
elem.appendChild (elem3);
elem3.setAttribute ("attr5", "val 5&");
XML.writeDocument (doc, System.out);
}
// ========================================
}

View File

@ -0,0 +1,89 @@
package network;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import org.junit.Test;
import org.junit.runner.JUnitCore;
import misc.XML;
public class HTTPInputStreamTest {
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (HTTPInputStreamTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("network.HTTPInputStreamTest");
}
static {
Protocol.setIpV4 ();
}
// ========================================
@Test (timeout=3000) public void launch ()
throws IOException {
String xmlRequest =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
"<request>\n"+
" <application name=\"ping\"/>\n"+
"</request>\n";
final String xmlResponse =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
"<response>\n"+
" <status value=\"ok\"/>\n"+
"</response>\n";
System.err.println ("start test");
System.err.flush ();
final ServerSocket serverSocket = new ServerSocket (8080);
serverSocket.setReuseAddress (true);
(new Thread () {
public void run () {
try {
System.err.println ("run");
System.err.flush ();
Socket call = serverSocket.accept ();
System.err.println ("Accept call "+call);
HTTPInputStream httpInputStream = new HTTPInputStream (call.getInputStream ());
System.err.println ("Server:main headers "+httpInputStream.headers+
" available:"+httpInputStream.available ());
System.err.println ("Server:main server receiveXML : ");
XML.writeDocument (XML.readDocument (httpInputStream), System.err);
System.err.flush ();
HTTPOutputStream httpPOutputStream = new HTTPOutputStream (call.getOutputStream ());
httpPOutputStream.setHeader ("Content-type", "application/xml");
httpPOutputStream.write (xmlResponse.getBytes ());
httpPOutputStream.close ();
} catch (IOException e) {
e.printStackTrace ();
}
}
}).start ();
System.err.println ("url");
System.err.flush ();
URLConnection urlConnection = XMLConnection.getXMLConnection (new URL ("http://localhost:8080/"));
OutputStreamWriter out = new OutputStreamWriter (urlConnection.getOutputStream ());
out.write (xmlRequest);
out.close ();
// attention l'ouverture de inputstream provoque la fermeture de outputstream
InputStream in = urlConnection.getInputStream ();
System.err.println ("Server:main client receiveXML : ");
XML.writeDocument (XML.readDocument (in), System.err);
System.err.flush ();
}
// ========================================
}

View File

@ -0,0 +1,52 @@
package network;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.JUnitCore;
public class HTTPOutputStreamTest extends Assert {
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (HTTPOutputStreamTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("network.HTTPOutputStreamTest");
}
static {
Protocol.setIpV4 ();
}
// ========================================
@Test (timeout=3000) public void launch ()
throws IOException {
final java.net.ServerSocket serverSocket = new java.net.ServerSocket (8080);
serverSocket.setReuseAddress (true);
(new Thread () {
public void run () {
try {
java.net.Socket call = serverSocket.accept ();
HTTPOutputStream out = new HTTPOutputStream (call.getOutputStream ());
out.setHeader ("Content-type", "application/xml");
out.write ("coucou\n".getBytes ());
out.close ();
} catch (Exception e) {
fail ("Server side exception:"+e);
}
}
}).start ();
java.net.Socket client = new java.net.Socket ("localhost", 8080);
java.io.InputStream in = client.getInputStream ();
byte[] b = new byte [8196];
int nb = in.read (b);
System.err.println ("Client:in:"+new String (b, 0, nb));
System.err.flush ();
}
// ========================================
}

View File

@ -0,0 +1,41 @@
package network;
import org.junit.Test;
import org.junit.runner.JUnitCore;
import misc.Util;
public class ServerTest {
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (ServerTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("network.ServerTest");
}
// ========================================
@Test public void launch () {
Server server = new Server (8080);
Client client = new Client ("127.0.0.1", 8080);
server.start ();
server.send ("service avant ecoute client");
Util.sleep (2);
client.start ();
Util.sleep (2);
server.send ("service apres ecoute client");
Util.sleep (2);
client.send ("service immediat");
}
// ========================================
}

View File

@ -0,0 +1,48 @@
package network.chat;
import org.junit.Test;
import org.junit.runner.JUnitCore;
import network.Client;
import network.Server;
public class ChatTest {
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (ChatTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("network.chat.ChatTest");
}
// ========================================
@Test public void launch () {
Server server = new Server (8080);
Client client = new Client ("127.0.0.1", 8080);
Chat chatServer = new Chat ("chatServer", server);
Chat chatClient = new Chat ("chatClient", client);
ChatObserver chatObserver = new ChatObserver () {
public void talk (ChatQuote quote) {
System.err.println (Chat.dateFormat.format (quote.date)+" "+quote.speaker+" > "+quote.sentence);
}
public void renameSpeaker (String speaker) {}
public void chatModifiedChange (boolean modified) {}
public void clearChat () {}
};
chatServer.addChatObserver (chatObserver);
chatClient.addChatObserver (chatObserver);
server.start ();
misc.Util.sleep (1);
client.start ();
misc.Util.sleep (1);
chatServer.say ("hello");
misc.Util.sleep (1);
chatClient.say ("world");
}
// ========================================
}

View File

@ -0,0 +1,68 @@
package network.chat;
import java.awt.Image;
import org.junit.Test;
import org.junit.runner.JUnitCore;
import misc.Bundle;
import misc.Config;
import misc.Controller;
import misc.Util;
import network.Client;
import network.ProtocolManager;
import network.Server;
import network.login.Login;
import network.login.LoginManager;
public class JChatTest {
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (JChatTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("network.chat.JChatTest");
}
public class Controller2 extends Controller<String> {
public Controller2 () { super (""); }
protected void createModel (String s) {}
public String getTitle () { return null; }
public Image getIcon () { return null; }
};
// ========================================
@Test public void launch () {
Config.setPWD (JChatTest.class);
Config.load ("Chat");
Bundle.load ("Chat");
Controller<String> controller = new Controller2 ();
ProtocolManager serverProtocolManager = new ProtocolManager (controller);
ProtocolManager clientProtocolManager = new ProtocolManager (controller);
Server server = new Server (8080);
Client client = new Client ("localhost", 8080);
server.start ();
client.start ();
serverProtocolManager.setProtocol (server);
clientProtocolManager.setProtocol (client);
Login login1 = new Login ("");
Login login2 = new Login ("");
LoginManager loginManager1 = new LoginManager (controller, login1);
LoginManager loginManager2 = new LoginManager (controller, login2);
Util.newJFrame ("Serge", new JChat (serverProtocolManager, loginManager1,
new ChatManager (controller, new Chat ("Serge", server))), true);
Util.newJFrame ("Clement", new JChat (clientProtocolManager, loginManager2,
new ChatManager (controller, new Chat ("Clement", client))), true);
}
// ========================================
}

View File

@ -0,0 +1,38 @@
package tool;
import java.io.File;
import java.util.Vector;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.JUnitCore;
import tool.model.SourceIteratorModel;
public class SourceIteratorModelTest extends Assert {
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (SourceIteratorModelTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("tool.SourceIteratorModelTest");
}
// ========================================
@Test public void parse () {
Vector<File> files = new Vector<File> ();
for (SourceIteratorModel si = new SourceIteratorModel (new File ("../src")); si.hasMoreJava (); ) {
File file = si.nextJava ();
files.add (file);
assertTrue (file.isFile ());
}
for (SourceIteratorModel si = new SourceIteratorModel (new File ("../src")); si.hasMoreString (); ) {
String next = si.nextString ();
assertTrue (files.contains (si.getCurrentFile ()));
assertTrue (next.indexOf ("\"") >= 0);
}
}
// ========================================
}

View File

@ -0,0 +1,34 @@
package tool.model;
import java.io.File;
import org.junit.Test;
import org.junit.Ignore;
import org.junit.runner.JUnitCore;
import misc.Bundle;
public class BundleManagerModelTest {
@Ignore ("for exemple") @Test (expected=IndexOutOfBoundsException.class, timeout=100) public void empty () {
new java.util.ArrayList<Object> ().get (0);
}
static public junit.framework.Test suite () {
return new junit.framework.JUnit4TestAdapter (BundleManagerModelTest.class);
}
static public void main (String args[]) {
JUnitCore.main ("tool.BundleManagerModelTest");
}
// ========================================
@Test public void copy () {
Bundle.load ("BundleManager");
BundleManagerModel bmm = new BundleManagerModel ();
bmm.open (new File ("data/config"), "BundleManager", false);
bmm.saveAs (new File ("/tmp"), "BundleManager");
}
// ========================================
}