little style cleanups and use tabs for indentation (read below...)
the only reason i'm bothering with doing something semi-drastic like changing the entire indentation style from spaces to tabs is because i prefer tabs, but more importantly, since all my editors are configured to use tabs, i will likely accidentally introduce tab indenting somewhere without realizing it and then everything would end up being inconsistent. would rather just solve this problem right now. :)
This commit is contained in:
parent
378024c3b0
commit
5aebf5eefd
|
@ -2,23 +2,6 @@ package org.fenix.llanfair;
|
||||||
|
|
||||||
import com.thoughtworks.xstream.XStream;
|
import com.thoughtworks.xstream.XStream;
|
||||||
import com.thoughtworks.xstream.io.xml.DomDriver;
|
import com.thoughtworks.xstream.io.xml.DomDriver;
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.FileReader;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
import javax.swing.Action;
|
|
||||||
import javax.swing.JFileChooser;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import org.fenix.llanfair.config.Settings;
|
import org.fenix.llanfair.config.Settings;
|
||||||
import org.fenix.llanfair.dialog.EditRun;
|
import org.fenix.llanfair.dialog.EditRun;
|
||||||
import org.fenix.llanfair.dialog.EditSettings;
|
import org.fenix.llanfair.dialog.EditSettings;
|
||||||
|
@ -26,6 +9,14 @@ import org.fenix.llanfair.extern.WSplit;
|
||||||
import org.fenix.utils.about.AboutDialog;
|
import org.fenix.utils.about.AboutDialog;
|
||||||
import org.jnativehook.keyboard.NativeKeyEvent;
|
import org.jnativehook.keyboard.NativeKeyEvent;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regroups all actions, in the meaning of {@link Action}, used by Llanfair.
|
* Regroups all actions, in the meaning of {@link Action}, used by Llanfair.
|
||||||
* All inputs and menu items callbacks are processed by this delegate to
|
* All inputs and menu items callbacks are processed by this delegate to
|
||||||
|
@ -35,410 +26,410 @@ import org.jnativehook.keyboard.NativeKeyEvent;
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
*/
|
*/
|
||||||
final class Actions {
|
final class Actions {
|
||||||
|
|
||||||
private static final long GHOST_DELAY = 300L;
|
|
||||||
private static ResourceBundle BUNDLE = null;
|
|
||||||
|
|
||||||
private Llanfair master;
|
|
||||||
|
|
||||||
private File file;
|
|
||||||
private JFileChooser fileChooser;
|
|
||||||
|
|
||||||
private volatile long lastUnsplit;
|
|
||||||
private volatile long lastSkip;
|
|
||||||
|
|
||||||
/**
|
private static final long GHOST_DELAY = 300L;
|
||||||
* Creates a new delegate. This constructor is package private since it
|
private static ResourceBundle BUNDLE = null;
|
||||||
* only need be called by the main class.
|
|
||||||
*
|
|
||||||
* @param owner the Llanfair instance owning this delegate
|
|
||||||
*/
|
|
||||||
Actions( Llanfair owner ) {
|
|
||||||
assert ( owner != null );
|
|
||||||
master = owner;
|
|
||||||
|
|
||||||
file = null;
|
|
||||||
fileChooser = new JFileChooser( "." );
|
|
||||||
|
|
||||||
lastUnsplit = 0L;
|
|
||||||
lastSkip = 0L;
|
|
||||||
|
|
||||||
if ( BUNDLE == null ) {
|
|
||||||
BUNDLE = Llanfair.getResources().getBundle( "llanfair" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private Llanfair master;
|
||||||
* Processes the given native key event. This method must be called from
|
|
||||||
* a thread to prevent possible deadlock.
|
|
||||||
*
|
|
||||||
* @param event the native key event to process
|
|
||||||
*/
|
|
||||||
void process( NativeKeyEvent event ) {
|
|
||||||
assert ( event != null );
|
|
||||||
|
|
||||||
int keyCode = event.getKeyCode();
|
|
||||||
Run run = master.getRun();
|
|
||||||
Run.State state = run.getState();
|
|
||||||
|
|
||||||
if ( keyCode == Settings.KEY_SPLT.get() ) {
|
|
||||||
split();
|
|
||||||
} else if ( keyCode == Settings.KEY_RSET.get() ) {
|
|
||||||
reset();
|
|
||||||
} else if ( keyCode == Settings.KEY_USPL.get() ) {
|
|
||||||
unsplit();
|
|
||||||
} else if ( keyCode == Settings.KEY_SKIP.get() ) {
|
|
||||||
skip();
|
|
||||||
} else if ( keyCode == Settings.KEY_STOP.get() ) {
|
|
||||||
if ( state == Run.State.ONGOING ) {
|
|
||||||
run.stop();
|
|
||||||
}
|
|
||||||
} else if ( keyCode == Settings.KEY_PAUS.get() ) {
|
|
||||||
if ( state == Run.State.ONGOING ) {
|
|
||||||
run.pause();
|
|
||||||
} else if ( state == Run.State.PAUSED ) {
|
|
||||||
run.resume();
|
|
||||||
}
|
|
||||||
} else if ( keyCode == Settings.KEY_LOCK.get() ) {
|
|
||||||
master.setIgnoreNativeInputs( !master.ignoresNativeInputs() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes the given action event. It is assumed here that the action
|
|
||||||
* event is one triggered by a menu item. This method must be called from
|
|
||||||
* a thread to prevent possible deadlock.
|
|
||||||
*
|
|
||||||
* @param event the event to process
|
|
||||||
*/
|
|
||||||
void process( ActionEvent event ) {
|
|
||||||
assert ( event != null );
|
|
||||||
|
|
||||||
Run run = master.getRun();
|
|
||||||
MenuItem source = ( MenuItem ) event.getSource();
|
|
||||||
|
|
||||||
if ( source == MenuItem.EDIT ) {
|
|
||||||
EditRun dialog = new EditRun( run );
|
|
||||||
dialog.display( true, master );
|
|
||||||
} else if ( source == MenuItem.NEW ) {
|
|
||||||
if ( confirmOverwrite() ) {
|
|
||||||
master.setRun( new Run() );
|
|
||||||
}
|
|
||||||
} else if ( source == MenuItem.OPEN ) {
|
|
||||||
open( null );
|
|
||||||
} else if ( source == MenuItem.OPEN_RECENT ) {
|
|
||||||
open( new File( event.getActionCommand() ) );
|
|
||||||
} else if ( source == MenuItem.IMPORT ) {
|
|
||||||
imprt();
|
|
||||||
} else if ( source == MenuItem.SAVE ) {
|
|
||||||
run.saveLiveTimes( !run.isPersonalBest() );
|
|
||||||
run.reset();
|
|
||||||
save();
|
|
||||||
} else if ( source == MenuItem.SAVE_AS ) {
|
|
||||||
file = null;
|
|
||||||
save();
|
|
||||||
} else if ( source == MenuItem.RESET ) {
|
|
||||||
reset();
|
|
||||||
} else if ( source == MenuItem.LOCK ) {
|
|
||||||
master.setIgnoreNativeInputs( true );
|
|
||||||
} else if ( source == MenuItem.UNLOCK ) {
|
|
||||||
master.setIgnoreNativeInputs( false );
|
|
||||||
} else if ( source == MenuItem.SETTINGS ) {
|
|
||||||
EditSettings dialog = new EditSettings();
|
|
||||||
dialog.display( true, master );
|
|
||||||
} else if ( source == MenuItem.ABOUT ) {
|
|
||||||
about();
|
|
||||||
} else if ( source == MenuItem.EXIT ) {
|
|
||||||
if ( confirmOverwrite() ) {
|
|
||||||
master.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs a split or starts the run if it is ready. Can also resume a
|
|
||||||
* paused run in case the run is segmented.
|
|
||||||
*/
|
|
||||||
private void split() {
|
|
||||||
Run run = master.getRun();
|
|
||||||
Run.State state = run.getState();
|
|
||||||
if ( state == Run.State.ONGOING ) {
|
|
||||||
long milli = System.nanoTime() / 1000000L;
|
|
||||||
long start = run.getSegment( run.getCurrent() ).getStartTime();
|
|
||||||
if ( milli - start > GHOST_DELAY ) {
|
|
||||||
run.split();
|
|
||||||
}
|
|
||||||
} else if ( state == Run.State.READY ) {
|
|
||||||
run.start();
|
|
||||||
} else if ( state == Run.State.PAUSED && run.isSegmented() ) {
|
|
||||||
run.resume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the current run to a ready state. If the user asked to be warned
|
|
||||||
* a pop-up will ask confirmation in case some live times are better.
|
|
||||||
*/
|
|
||||||
private void reset() {
|
|
||||||
Run run = master.getRun();
|
|
||||||
if ( run.getState() != Run.State.NULL ) {
|
|
||||||
if ( !Settings.GNR_WARN.get() || confirmOverwrite() ) {
|
|
||||||
run.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs an "unsplit" on the current run. If a split has been made, it
|
|
||||||
* is canceled and the time that passed after said split is added back to
|
|
||||||
* the timer, as if the split had not taken place.
|
|
||||||
*/
|
|
||||||
private void unsplit() {
|
|
||||||
Run run = master.getRun();
|
|
||||||
Run.State state = run.getState();
|
|
||||||
if ( state == Run.State.ONGOING || state == Run.State.STOPPED ) {
|
|
||||||
long milli = System.nanoTime() / 1000000L;
|
|
||||||
if ( milli - lastUnsplit > GHOST_DELAY ) {
|
|
||||||
lastUnsplit = milli;
|
|
||||||
run.unsplit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Skips the current split in the run. Skipping a split sets an undefined
|
|
||||||
* time for the current segment and merges the live time of the current
|
|
||||||
* segment with the following one.
|
|
||||||
*/
|
|
||||||
private void skip() {
|
|
||||||
Run run = master.getRun();
|
|
||||||
if ( run.getState() == Run.State.ONGOING ) {
|
|
||||||
long milli = System.nanoTime() / 1000000L;
|
|
||||||
if ( milli - lastSkip > GHOST_DELAY ) {
|
|
||||||
lastSkip = milli;
|
|
||||||
run.skip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays a dialog to let the user select a file. The user is able to
|
|
||||||
* cancel this action, which results in a {@code null} being returned.
|
|
||||||
*
|
|
||||||
* @return a file selected by the user or {@code null} if he canceled
|
|
||||||
*/
|
|
||||||
private File selectFile() {
|
|
||||||
int option = fileChooser.showDialog( master,
|
|
||||||
Language.action_accept.get() );
|
|
||||||
|
|
||||||
if ( option == JFileChooser.APPROVE_OPTION ) {
|
|
||||||
return fileChooser.getSelectedFile();
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Asks the user to confirm the discard of the current run. The popup
|
|
||||||
* window will only trigger if the current run has not been saved after
|
|
||||||
* some editing or if the run presents better times.
|
|
||||||
*
|
|
||||||
* @return {@code true} if the user wants to discard the run
|
|
||||||
*/
|
|
||||||
private boolean confirmOverwrite() {
|
|
||||||
boolean before = master.ignoresNativeInputs();
|
|
||||||
master.setIgnoreNativeInputs( true );
|
|
||||||
|
|
||||||
Run run = master.getRun();
|
|
||||||
boolean betterRun = run.isPersonalBest();
|
|
||||||
boolean betterSgt = run.hasSegmentsBest();
|
|
||||||
|
|
||||||
if ( betterRun || betterSgt ) {
|
private File file;
|
||||||
String message = betterRun
|
private JFileChooser fileChooser;
|
||||||
? Language.WARN_BETTER_RUN.get()
|
|
||||||
: Language.WARN_BETTER_TIMES.get();
|
private volatile long lastUnsplit;
|
||||||
|
private volatile long lastSkip;
|
||||||
int option = JOptionPane.showConfirmDialog( master, message,
|
|
||||||
Language.WARNING.get(), JOptionPane.YES_NO_CANCEL_OPTION,
|
/**
|
||||||
JOptionPane.WARNING_MESSAGE );
|
* Creates a new delegate. This constructor is package private since it
|
||||||
|
* only need be called by the main class.
|
||||||
if ( option == JOptionPane.CANCEL_OPTION ) {
|
*
|
||||||
master.setIgnoreNativeInputs( false );
|
* @param owner the Llanfair instance owning this delegate
|
||||||
return false;
|
*/
|
||||||
} else if ( option == JOptionPane.YES_OPTION ) {
|
Actions( Llanfair owner ) {
|
||||||
run.saveLiveTimes( !betterRun );
|
assert ( owner != null );
|
||||||
run.reset();
|
master = owner;
|
||||||
save();
|
|
||||||
}
|
file = null;
|
||||||
}
|
fileChooser = new JFileChooser( "." );
|
||||||
master.setIgnoreNativeInputs( before );
|
|
||||||
return true;
|
lastUnsplit = 0L;
|
||||||
}
|
lastSkip = 0L;
|
||||||
|
|
||||||
/**
|
if ( BUNDLE == null ) {
|
||||||
* Opens the given file. If the file is {@code null}, the user is asked
|
BUNDLE = Llanfair.getResources().getBundle( "llanfair" );
|
||||||
* to select one. Before anything is done, the user is also asked for
|
}
|
||||||
* a confirmation if the current run has not been saved.
|
}
|
||||||
*
|
|
||||||
* @param file the file to open
|
/**
|
||||||
*/
|
* Processes the given native key event. This method must be called from
|
||||||
void open( File file ) {
|
* a thread to prevent possible deadlock.
|
||||||
if ( !confirmOverwrite() ) {
|
*
|
||||||
return;
|
* @param event the native key event to process
|
||||||
}
|
*/
|
||||||
if ( file == null ) {
|
void process( NativeKeyEvent event ) {
|
||||||
if ( ( file = selectFile() ) == null ) {
|
assert ( event != null );
|
||||||
return;
|
|
||||||
}
|
int keyCode = event.getKeyCode();
|
||||||
}
|
Run run = master.getRun();
|
||||||
this.file = file;
|
Run.State state = run.getState();
|
||||||
String name = file.getName();
|
|
||||||
try {
|
if ( keyCode == Settings.KEY_SPLT.get() ) {
|
||||||
open();
|
split();
|
||||||
} catch ( Exception ex ) {
|
} else if ( keyCode == Settings.KEY_RSET.get() ) {
|
||||||
master.showError( Language.error_read_file.get( name ) );
|
reset();
|
||||||
this.file = null;
|
} else if ( keyCode == Settings.KEY_USPL.get() ) {
|
||||||
}
|
unsplit();
|
||||||
}
|
} else if ( keyCode == Settings.KEY_SKIP.get() ) {
|
||||||
|
skip();
|
||||||
/**
|
} else if ( keyCode == Settings.KEY_STOP.get() ) {
|
||||||
* Opens the currently selected file. This method will first try to open
|
if ( state == Run.State.ONGOING ) {
|
||||||
* the file using the new method (XStream XML) and if it fails will try to
|
run.stop();
|
||||||
* use the legacy method (Java ObjectStream.)
|
}
|
||||||
*
|
} else if ( keyCode == Settings.KEY_PAUS.get() ) {
|
||||||
* @throws Exception if the reading operation fails
|
if ( state == Run.State.ONGOING ) {
|
||||||
*/
|
run.pause();
|
||||||
private void open() throws Exception {
|
} else if ( state == Run.State.PAUSED ) {
|
||||||
BufferedInputStream in = null;
|
run.resume();
|
||||||
try {
|
}
|
||||||
in = new BufferedInputStream( new FileInputStream( file ) );
|
} else if ( keyCode == Settings.KEY_LOCK.get() ) {
|
||||||
try {
|
master.setIgnoreNativeInputs( !master.ignoresNativeInputs() );
|
||||||
in.mark( Integer.MAX_VALUE );
|
}
|
||||||
xmlRead( in );
|
}
|
||||||
} catch ( Exception ex ) {
|
|
||||||
in.reset();
|
/**
|
||||||
legacyRead( new ObjectInputStream( in ) );
|
* Processes the given action event. It is assumed here that the action
|
||||||
}
|
* event is one triggered by a menu item. This method must be called from
|
||||||
MenuItem.recentlyOpened( "" + file );
|
* a thread to prevent possible deadlock.
|
||||||
} catch ( Exception ex ) {
|
*
|
||||||
throw ex;
|
* @param event the event to process
|
||||||
} finally {
|
*/
|
||||||
try {
|
void process( ActionEvent event ) {
|
||||||
in.close();
|
assert ( event != null );
|
||||||
} catch ( Exception ex ) {
|
|
||||||
//$FALL-THROUGH$
|
Run run = master.getRun();
|
||||||
}
|
MenuItem source = ( MenuItem ) event.getSource();
|
||||||
}
|
|
||||||
}
|
if ( source == MenuItem.EDIT ) {
|
||||||
|
EditRun dialog = new EditRun( run );
|
||||||
/**
|
dialog.display( true, master );
|
||||||
* Reads a stream on a run file using the new (since 1.5) XML method. This
|
} else if ( source == MenuItem.NEW ) {
|
||||||
* method will not be able to read a legacy run file and will throw an
|
if ( confirmOverwrite() ) {
|
||||||
* exception if confronted with such run file.
|
master.setRun( new Run() );
|
||||||
*
|
}
|
||||||
* @param in the input stream on the run file
|
} else if ( source == MenuItem.OPEN ) {
|
||||||
*/
|
open( null );
|
||||||
private void xmlRead( InputStream in ) {
|
} else if ( source == MenuItem.OPEN_RECENT ) {
|
||||||
XStream xml = new XStream( new DomDriver() );
|
open( new File( event.getActionCommand() ) );
|
||||||
master.setRun( ( Run ) xml.fromXML( in ) );
|
} else if ( source == MenuItem.IMPORT ) {
|
||||||
}
|
imprt();
|
||||||
|
} else if ( source == MenuItem.SAVE ) {
|
||||||
/**
|
run.saveLiveTimes( !run.isPersonalBest() );
|
||||||
* Reads a stream on a run file using the legacy Java method. This method
|
run.reset();
|
||||||
* might fail if the given file is not a Llanfair run.
|
save();
|
||||||
*
|
} else if ( source == MenuItem.SAVE_AS ) {
|
||||||
* @param in an input stream on the run file
|
file = null;
|
||||||
* @throws Exception if the stream cannot be read
|
save();
|
||||||
*/
|
} else if ( source == MenuItem.RESET ) {
|
||||||
private void legacyRead( ObjectInputStream in ) throws Exception {
|
reset();
|
||||||
master.setRun( ( Run ) in.readObject() );
|
} else if ( source == MenuItem.LOCK ) {
|
||||||
try {
|
master.setIgnoreNativeInputs( true );
|
||||||
Settings.GNR_SIZE.set( ( Dimension ) in.readObject(), true );
|
} else if ( source == MenuItem.UNLOCK ) {
|
||||||
} catch ( Exception ex ) {
|
master.setIgnoreNativeInputs( false );
|
||||||
// $FALL-THROUGH$
|
} else if ( source == MenuItem.SETTINGS ) {
|
||||||
}
|
EditSettings dialog = new EditSettings();
|
||||||
}
|
dialog.display( true, master );
|
||||||
|
} else if ( source == MenuItem.ABOUT ) {
|
||||||
/**
|
about();
|
||||||
* Saves the currently opened run to the currently selected file. If no
|
} else if ( source == MenuItem.EXIT ) {
|
||||||
* file has been selected, the user is asked for one.
|
if ( confirmOverwrite() ) {
|
||||||
*/
|
master.dispose();
|
||||||
private void save() {
|
}
|
||||||
if ( file == null ) {
|
}
|
||||||
if ( ( file = selectFile() ) == null ) {
|
}
|
||||||
return;
|
|
||||||
}
|
/**
|
||||||
}
|
* Performs a split or starts the run if it is ready. Can also resume a
|
||||||
Settings.GNR_COOR.set( master.getLocationOnScreen(), true );
|
* paused run in case the run is segmented.
|
||||||
Settings.GNR_SIZE.set( master.getSize(), true );
|
*/
|
||||||
|
private void split() {
|
||||||
String name = file.getName();
|
Run run = master.getRun();
|
||||||
BufferedOutputStream out = null;
|
Run.State state = run.getState();
|
||||||
try {
|
if ( state == Run.State.ONGOING ) {
|
||||||
XStream xml = new XStream( new DomDriver() );
|
long milli = System.nanoTime() / 1000000L;
|
||||||
out = new BufferedOutputStream( new FileOutputStream( file ) );
|
long start = run.getSegment( run.getCurrent() ).getStartTime();
|
||||||
xml.toXML( master.getRun(), out );
|
if ( milli - start > GHOST_DELAY ) {
|
||||||
} catch ( Exception ex ) {
|
run.split();
|
||||||
master.showError( Language.error_write_file.get( name ) );
|
}
|
||||||
} finally {
|
} else if ( state == Run.State.READY ) {
|
||||||
try {
|
run.start();
|
||||||
out.close();
|
} else if ( state == Run.State.PAUSED && run.isSegmented() ) {
|
||||||
} catch ( Exception ex ) {
|
run.resume();
|
||||||
// $FALL-THROUGH$
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
/**
|
||||||
|
* Resets the current run to a ready state. If the user asked to be warned
|
||||||
/**
|
* a pop-up will ask confirmation in case some live times are better.
|
||||||
* Imports a run from another timer application. If no file has been
|
*/
|
||||||
* selected, the user is asked for one. As of now, only WSplit run files
|
private void reset() {
|
||||||
* are supported.
|
Run run = master.getRun();
|
||||||
*/
|
if ( run.getState() != Run.State.NULL ) {
|
||||||
private void imprt() {
|
if ( !Settings.GNR_WARN.get() || confirmOverwrite() ) {
|
||||||
if ( !confirmOverwrite() ) {
|
run.reset();
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
if ( file == null ) {
|
}
|
||||||
if ( ( file = selectFile() ) == null ) {
|
|
||||||
return;
|
/**
|
||||||
}
|
* Performs an "unsplit" on the current run. If a split has been made, it
|
||||||
}
|
* is canceled and the time that passed after said split is added back to
|
||||||
String name = file.getName();
|
* the timer, as if the split had not taken place.
|
||||||
BufferedReader in = null;
|
*/
|
||||||
try {
|
private void unsplit() {
|
||||||
in = new BufferedReader( new FileReader( file ) );
|
Run run = master.getRun();
|
||||||
WSplit.parse( master, in );
|
Run.State state = run.getState();
|
||||||
} catch ( Exception ex ) {
|
if ( state == Run.State.ONGOING || state == Run.State.STOPPED ) {
|
||||||
master.showError( Language.error_import_run.get( name ) );
|
long milli = System.nanoTime() / 1000000L;
|
||||||
} finally {
|
if ( milli - lastUnsplit > GHOST_DELAY ) {
|
||||||
try {
|
lastUnsplit = milli;
|
||||||
in.close();
|
run.unsplit();
|
||||||
} catch ( Exception ex ) {
|
}
|
||||||
// $FALL-THROUGH$
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
/**
|
||||||
|
* Skips the current split in the run. Skipping a split sets an undefined
|
||||||
/**
|
* time for the current segment and merges the live time of the current
|
||||||
* Displays the "about" dialog. The dialog displays the version of Llanfair,
|
* segment with the following one.
|
||||||
* the creative commons licence, the credits of development, a link to
|
*/
|
||||||
* Llanfair's website and a link to donate.
|
private void skip() {
|
||||||
*/
|
Run run = master.getRun();
|
||||||
private void about() {
|
if ( run.getState() == Run.State.ONGOING ) {
|
||||||
AboutDialog dialog = new AboutDialog(
|
long milli = System.nanoTime() / 1000000L;
|
||||||
master, Language.title_about.get() );
|
if ( milli - lastSkip > GHOST_DELAY ) {
|
||||||
dialog.setMessage( BUNDLE.getString( "about" ));
|
lastSkip = milli;
|
||||||
try {
|
run.skip();
|
||||||
dialog.setWebsite( new URL( BUNDLE.getString( "website" ) ) );
|
}
|
||||||
} catch ( MalformedURLException ex ) {
|
}
|
||||||
// $FALL-THROUGH$
|
}
|
||||||
}
|
|
||||||
try {
|
/**
|
||||||
dialog.setDonateLink( new URL( BUNDLE.getString( "donate" ) ),
|
* Displays a dialog to let the user select a file. The user is able to
|
||||||
Llanfair.getResources().getIcon( "donate" ) );
|
* cancel this action, which results in a {@code null} being returned.
|
||||||
} catch ( MalformedURLException ex ) {
|
*
|
||||||
// $FALL-THROUGH$
|
* @return a file selected by the user or {@code null} if he canceled
|
||||||
}
|
*/
|
||||||
dialog.display();
|
private File selectFile() {
|
||||||
}
|
int option = fileChooser.showDialog( master,
|
||||||
|
Language.action_accept.get() );
|
||||||
|
|
||||||
|
if ( option == JFileChooser.APPROVE_OPTION ) {
|
||||||
|
return fileChooser.getSelectedFile();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asks the user to confirm the discard of the current run. The popup
|
||||||
|
* window will only trigger if the current run has not been saved after
|
||||||
|
* some editing or if the run presents better times.
|
||||||
|
*
|
||||||
|
* @return {@code true} if the user wants to discard the run
|
||||||
|
*/
|
||||||
|
private boolean confirmOverwrite() {
|
||||||
|
boolean before = master.ignoresNativeInputs();
|
||||||
|
master.setIgnoreNativeInputs( true );
|
||||||
|
|
||||||
|
Run run = master.getRun();
|
||||||
|
boolean betterRun = run.isPersonalBest();
|
||||||
|
boolean betterSgt = run.hasSegmentsBest();
|
||||||
|
|
||||||
|
if ( betterRun || betterSgt ) {
|
||||||
|
String message = betterRun
|
||||||
|
? Language.WARN_BETTER_RUN.get()
|
||||||
|
: Language.WARN_BETTER_TIMES.get();
|
||||||
|
|
||||||
|
int option = JOptionPane.showConfirmDialog( master, message,
|
||||||
|
Language.WARNING.get(), JOptionPane.YES_NO_CANCEL_OPTION,
|
||||||
|
JOptionPane.WARNING_MESSAGE );
|
||||||
|
|
||||||
|
if ( option == JOptionPane.CANCEL_OPTION ) {
|
||||||
|
master.setIgnoreNativeInputs( false );
|
||||||
|
return false;
|
||||||
|
} else if ( option == JOptionPane.YES_OPTION ) {
|
||||||
|
run.saveLiveTimes( !betterRun );
|
||||||
|
run.reset();
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
master.setIgnoreNativeInputs( before );
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the given file. If the file is {@code null}, the user is asked
|
||||||
|
* to select one. Before anything is done, the user is also asked for
|
||||||
|
* a confirmation if the current run has not been saved.
|
||||||
|
*
|
||||||
|
* @param file the file to open
|
||||||
|
*/
|
||||||
|
void open( File file ) {
|
||||||
|
if ( !confirmOverwrite() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( file == null ) {
|
||||||
|
if ( ( file = selectFile() ) == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.file = file;
|
||||||
|
String name = file.getName();
|
||||||
|
try {
|
||||||
|
open();
|
||||||
|
} catch ( Exception ex ) {
|
||||||
|
master.showError( Language.error_read_file.get( name ) );
|
||||||
|
this.file = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the currently selected file. This method will first try to open
|
||||||
|
* the file using the new method (XStream XML) and if it fails will try to
|
||||||
|
* use the legacy method (Java ObjectStream.)
|
||||||
|
*
|
||||||
|
* @throws Exception if the reading operation fails
|
||||||
|
*/
|
||||||
|
private void open() throws Exception {
|
||||||
|
BufferedInputStream in = null;
|
||||||
|
try {
|
||||||
|
in = new BufferedInputStream( new FileInputStream( file ) );
|
||||||
|
try {
|
||||||
|
in.mark( Integer.MAX_VALUE );
|
||||||
|
xmlRead( in );
|
||||||
|
} catch ( Exception ex ) {
|
||||||
|
in.reset();
|
||||||
|
legacyRead( new ObjectInputStream( in ) );
|
||||||
|
}
|
||||||
|
MenuItem.recentlyOpened( "" + file );
|
||||||
|
} catch ( Exception ex ) {
|
||||||
|
throw ex;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
in.close();
|
||||||
|
} catch ( Exception ex ) {
|
||||||
|
//$FALL-THROUGH$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a stream on a run file using the new (since 1.5) XML method. This
|
||||||
|
* method will not be able to read a legacy run file and will throw an
|
||||||
|
* exception if confronted with such run file.
|
||||||
|
*
|
||||||
|
* @param in the input stream on the run file
|
||||||
|
*/
|
||||||
|
private void xmlRead( InputStream in ) {
|
||||||
|
XStream xml = new XStream( new DomDriver() );
|
||||||
|
master.setRun( ( Run ) xml.fromXML( in ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a stream on a run file using the legacy Java method. This method
|
||||||
|
* might fail if the given file is not a Llanfair run.
|
||||||
|
*
|
||||||
|
* @param in an input stream on the run file
|
||||||
|
* @throws Exception if the stream cannot be read
|
||||||
|
*/
|
||||||
|
private void legacyRead( ObjectInputStream in ) throws Exception {
|
||||||
|
master.setRun( ( Run ) in.readObject() );
|
||||||
|
try {
|
||||||
|
Settings.GNR_SIZE.set( ( Dimension ) in.readObject(), true );
|
||||||
|
} catch ( Exception ex ) {
|
||||||
|
// $FALL-THROUGH$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the currently opened run to the currently selected file. If no
|
||||||
|
* file has been selected, the user is asked for one.
|
||||||
|
*/
|
||||||
|
private void save() {
|
||||||
|
if ( file == null ) {
|
||||||
|
if ( ( file = selectFile() ) == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Settings.GNR_COOR.set( master.getLocationOnScreen(), true );
|
||||||
|
Settings.GNR_SIZE.set( master.getSize(), true );
|
||||||
|
|
||||||
|
String name = file.getName();
|
||||||
|
BufferedOutputStream out = null;
|
||||||
|
try {
|
||||||
|
XStream xml = new XStream( new DomDriver() );
|
||||||
|
out = new BufferedOutputStream( new FileOutputStream( file ) );
|
||||||
|
xml.toXML( master.getRun(), out );
|
||||||
|
} catch ( Exception ex ) {
|
||||||
|
master.showError( Language.error_write_file.get( name ) );
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch ( Exception ex ) {
|
||||||
|
// $FALL-THROUGH$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports a run from another timer application. If no file has been
|
||||||
|
* selected, the user is asked for one. As of now, only WSplit run files
|
||||||
|
* are supported.
|
||||||
|
*/
|
||||||
|
private void imprt() {
|
||||||
|
if ( !confirmOverwrite() ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( file == null ) {
|
||||||
|
if ( ( file = selectFile() ) == null ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String name = file.getName();
|
||||||
|
BufferedReader in = null;
|
||||||
|
try {
|
||||||
|
in = new BufferedReader( new FileReader( file ) );
|
||||||
|
WSplit.parse( master, in );
|
||||||
|
} catch ( Exception ex ) {
|
||||||
|
master.showError( Language.error_import_run.get( name ) );
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
in.close();
|
||||||
|
} catch ( Exception ex ) {
|
||||||
|
// $FALL-THROUGH$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the "about" dialog. The dialog displays the version of Llanfair,
|
||||||
|
* the creative commons licence, the credits of development, a link to
|
||||||
|
* Llanfair's website and a link to donate.
|
||||||
|
*/
|
||||||
|
private void about() {
|
||||||
|
AboutDialog dialog = new AboutDialog(
|
||||||
|
master, Language.title_about.get() );
|
||||||
|
dialog.setMessage( BUNDLE.getString( "about" ));
|
||||||
|
try {
|
||||||
|
dialog.setWebsite( new URL( BUNDLE.getString( "website" ) ) );
|
||||||
|
} catch ( MalformedURLException ex ) {
|
||||||
|
// $FALL-THROUGH$
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
dialog.setDonateLink( new URL( BUNDLE.getString( "donate" ) ),
|
||||||
|
Llanfair.getResources().getIcon( "donate" ) );
|
||||||
|
} catch ( MalformedURLException ex ) {
|
||||||
|
// $FALL-THROUGH$
|
||||||
|
}
|
||||||
|
dialog.display();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,171 +1,169 @@
|
||||||
package org.fenix.llanfair;
|
package org.fenix.llanfair;
|
||||||
|
|
||||||
|
import org.fenix.utils.TableModelSupport;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.event.TableModelListener;
|
||||||
|
import javax.swing.table.TableModel;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.Icon;
|
|
||||||
import javax.swing.event.TableModelListener;
|
|
||||||
import javax.swing.table.TableModel;
|
|
||||||
import org.fenix.llanfair.Language;
|
|
||||||
|
|
||||||
import org.fenix.utils.TableModelSupport;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Xavier "Xunkar" Sencert
|
* @author Xavier "Xunkar" Sencert
|
||||||
*/
|
*/
|
||||||
public class Counters implements TableModel, Serializable {
|
public class Counters implements TableModel, Serializable {
|
||||||
|
|
||||||
// -------------------------------------------------------------- CONSTANTES
|
// -------------------------------------------------------------- CONSTANTES
|
||||||
|
|
||||||
public static final long serialVersionUID = 1000L;
|
public static final long serialVersionUID = 1000L;
|
||||||
|
|
||||||
public static final int COLUMN_ICON = 0;
|
public static final int COLUMN_ICON = 0;
|
||||||
|
|
||||||
public static final int COLUMN_NAME = 1;
|
public static final int COLUMN_NAME = 1;
|
||||||
|
|
||||||
public static final int COLUMN_START = 2;
|
public static final int COLUMN_START = 2;
|
||||||
|
|
||||||
public static final int COLUMN_INCREMENT = 3;
|
public static final int COLUMN_INCREMENT = 3;
|
||||||
|
|
||||||
public static final int COLUMN_COUNT = 4;
|
public static final int COLUMN_COUNT = 4;
|
||||||
|
|
||||||
// -------------------------------------------------------------- ATTRIBUTS
|
// -------------------------------------------------------------- ATTRIBUTS
|
||||||
|
|
||||||
private List<Counter> data;
|
private List<Counter> data;
|
||||||
|
|
||||||
private TableModelSupport tmSupport;
|
private TableModelSupport tmSupport;
|
||||||
|
|
||||||
// ---------------------------------------------------------- CONSTRUCTEURS
|
// ---------------------------------------------------------- CONSTRUCTEURS
|
||||||
|
|
||||||
public Counters() {
|
public Counters() {
|
||||||
data = new ArrayList<Counter>();
|
data = new ArrayList<Counter>();
|
||||||
tmSupport = new TableModelSupport(this);
|
tmSupport = new TableModelSupport(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getColumnCount() {
|
public int getColumnCount() {
|
||||||
return COLUMN_COUNT;
|
return COLUMN_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRowCount() {
|
public int getRowCount() {
|
||||||
return data.size();
|
return data.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||||
if (rowIndex < 0 || rowIndex >= data.size()) {
|
if (rowIndex < 0 || rowIndex >= data.size()) {
|
||||||
throw new IllegalArgumentException("illegal counter id " + rowIndex);
|
throw new IllegalArgumentException("illegal counter id " + rowIndex);
|
||||||
}
|
}
|
||||||
return data.get(rowIndex).get(columnIndex);
|
return data.get(rowIndex).get(columnIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getColumnName(int columnIndex) {
|
public String getColumnName(int columnIndex) {
|
||||||
switch (columnIndex) {
|
switch (columnIndex) {
|
||||||
case COLUMN_ICON: return "" + Language.ICON;
|
case COLUMN_ICON: return "" + Language.ICON;
|
||||||
case COLUMN_INCREMENT: return "" + Language.INCREMENT;
|
case COLUMN_INCREMENT: return "" + Language.INCREMENT;
|
||||||
case COLUMN_NAME: return "" + Language.NAME;
|
case COLUMN_NAME: return "" + Language.NAME;
|
||||||
case COLUMN_START: return "" + Language.START_VALUE;
|
case COLUMN_START: return "" + Language.START_VALUE;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<?> getColumnClass(int columnIndex) {
|
public Class<?> getColumnClass(int columnIndex) {
|
||||||
switch (columnIndex) {
|
switch (columnIndex) {
|
||||||
case COLUMN_ICON: return Icon.class;
|
case COLUMN_ICON: return Icon.class;
|
||||||
case COLUMN_INCREMENT: return Integer.class;
|
case COLUMN_INCREMENT: return Integer.class;
|
||||||
case COLUMN_NAME: return String.class;
|
case COLUMN_NAME: return String.class;
|
||||||
case COLUMN_START: return Integer.class;
|
case COLUMN_START: return Integer.class;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
||||||
if (rowIndex < 0 || rowIndex >= data.size()) {
|
if (rowIndex < 0 || rowIndex >= data.size()) {
|
||||||
throw new IllegalArgumentException("illegal counter id " + rowIndex);
|
throw new IllegalArgumentException("illegal counter id " + rowIndex);
|
||||||
}
|
}
|
||||||
data.get(rowIndex).set(columnIndex, aValue);
|
data.get(rowIndex).set(columnIndex, aValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addTableModelListener(TableModelListener l) {
|
public void addTableModelListener(TableModelListener l) {
|
||||||
tmSupport.addTableModelListener(l);
|
tmSupport.addTableModelListener(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeTableModelListener(TableModelListener l) {
|
public void removeTableModelListener(TableModelListener l) {
|
||||||
tmSupport.removeTableModelListener(l);
|
tmSupport.removeTableModelListener(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------- CLASSES
|
// ----------------------------------------------------------- CLASSES
|
||||||
|
|
||||||
public static class Counter implements Serializable {
|
public static class Counter implements Serializable {
|
||||||
|
|
||||||
public static final long serialVersionUID = 1000L;
|
public static final long serialVersionUID = 1000L;
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private Icon icon;
|
private Icon icon;
|
||||||
|
|
||||||
private int increment;
|
private int increment;
|
||||||
|
|
||||||
private int start;
|
private int start;
|
||||||
|
|
||||||
private int saved;
|
private int saved;
|
||||||
|
|
||||||
private int live;
|
private int live;
|
||||||
|
|
||||||
public Counter() {
|
public Counter() {
|
||||||
name = "" + Language.UNTITLED;
|
name = "" + Language.UNTITLED;
|
||||||
icon = null;
|
icon = null;
|
||||||
start = 0;
|
start = 0;
|
||||||
live = 0;
|
live = 0;
|
||||||
increment = 1;
|
increment = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object get(int columnIndex) {
|
public Object get(int columnIndex) {
|
||||||
switch (columnIndex) {
|
switch (columnIndex) {
|
||||||
case COLUMN_ICON: return icon;
|
case COLUMN_ICON: return icon;
|
||||||
case COLUMN_INCREMENT: return increment;
|
case COLUMN_INCREMENT: return increment;
|
||||||
case COLUMN_NAME: return name;
|
case COLUMN_NAME: return name;
|
||||||
case COLUMN_START: return start;
|
case COLUMN_START: return start;
|
||||||
default: return name;
|
default: return name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void set(int columnIndex, Object value) {
|
public void set(int columnIndex, Object value) {
|
||||||
switch (columnIndex) {
|
switch (columnIndex) {
|
||||||
case COLUMN_ICON: icon = (Icon) value; break;
|
case COLUMN_ICON: icon = (Icon) value; break;
|
||||||
case COLUMN_INCREMENT: increment = (Integer) value; break;
|
case COLUMN_INCREMENT: increment = (Integer) value; break;
|
||||||
case COLUMN_NAME: name = (String) value; break;
|
case COLUMN_NAME: name = (String) value; break;
|
||||||
case COLUMN_START: start = (Integer) value; break;
|
case COLUMN_START: start = (Integer) value; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Icon getIcon() {
|
public Icon getIcon() {
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLive() {
|
public int getLive() {
|
||||||
return live;
|
return live;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getStart() {
|
public int getStart() {
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSaved() {
|
public int getSaved() {
|
||||||
return saved;
|
return saved;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void nextStep() {
|
public void nextStep() {
|
||||||
live += increment;
|
live += increment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package org.fenix.llanfair;
|
package org.fenix.llanfair;
|
||||||
|
|
||||||
|
import org.fenix.utils.Resources;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.fenix.utils.Resources;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumeration of all externalized strings used by {@code Llanfair}. While it is
|
* Enumeration of all externalized strings used by {@code Llanfair}. While it is
|
||||||
|
@ -15,278 +16,278 @@ import org.fenix.utils.Resources;
|
||||||
* @see Resources
|
* @see Resources
|
||||||
*/
|
*/
|
||||||
public enum Language {
|
public enum Language {
|
||||||
|
|
||||||
// Settings > Generic
|
|
||||||
setting_alwaysOnTop,
|
|
||||||
setting_language,
|
|
||||||
setting_viewerLanguage,
|
|
||||||
setting_recentFiles,
|
|
||||||
setting_coordinates,
|
|
||||||
setting_dimension,
|
|
||||||
setting_compareMethod,
|
|
||||||
setting_accuracy,
|
|
||||||
setting_locked,
|
|
||||||
setting_warnOnReset,
|
|
||||||
|
|
||||||
// Settings > Color
|
|
||||||
setting_color_background,
|
|
||||||
setting_color_foreground,
|
|
||||||
setting_color_time,
|
|
||||||
setting_color_timer,
|
|
||||||
setting_color_timeGained,
|
|
||||||
setting_color_timeLost,
|
|
||||||
setting_color_newRecord,
|
|
||||||
setting_color_title,
|
|
||||||
setting_color_highlight,
|
|
||||||
setting_color_separators,
|
|
||||||
|
|
||||||
// Settings > Hotkey
|
|
||||||
setting_hotkey_split,
|
|
||||||
setting_hotkey_unsplit,
|
|
||||||
setting_hotkey_skip,
|
|
||||||
setting_hotkey_reset,
|
|
||||||
setting_hotkey_stop,
|
|
||||||
setting_hotkey_pause,
|
|
||||||
setting_hotkey_lock,
|
|
||||||
|
|
||||||
// Settings > Header
|
|
||||||
setting_header_goal,
|
|
||||||
setting_header_title,
|
|
||||||
|
|
||||||
// Settings > History
|
|
||||||
setting_history_rowCount,
|
|
||||||
setting_history_tabular,
|
|
||||||
setting_history_blankRows,
|
|
||||||
setting_history_multiline,
|
|
||||||
setting_history_merge,
|
|
||||||
setting_history_liveTimes,
|
|
||||||
setting_history_deltas,
|
|
||||||
setting_history_icons,
|
|
||||||
setting_history_iconSize,
|
|
||||||
setting_history_offset,
|
|
||||||
setting_history_alwaysShowLast,
|
|
||||||
setting_history_segmentFont,
|
|
||||||
setting_history_timeFont,
|
|
||||||
|
|
||||||
// Settings > Core
|
|
||||||
setting_core_accuracy,
|
|
||||||
setting_core_icons,
|
|
||||||
setting_core_iconSize,
|
|
||||||
setting_core_segmentName,
|
|
||||||
setting_core_splitTime,
|
|
||||||
setting_core_segmentTime,
|
|
||||||
setting_core_bestTime,
|
|
||||||
setting_core_segmentTimer,
|
|
||||||
setting_core_timerFont,
|
|
||||||
setting_core_segmentTimerFont,
|
|
||||||
|
|
||||||
// Settings > Graph
|
|
||||||
setting_graph_display,
|
|
||||||
setting_graph_scale,
|
|
||||||
|
|
||||||
// Settings > Footer
|
|
||||||
setting_footer_display,
|
|
||||||
setting_footer_useSplitData,
|
|
||||||
setting_footer_verbose,
|
|
||||||
setting_footer_bestTime,
|
|
||||||
setting_footer_multiline,
|
|
||||||
setting_footer_deltaLabels,
|
|
||||||
|
|
||||||
// Accuracy
|
|
||||||
accuracy_seconds,
|
|
||||||
accuracy_tenth,
|
|
||||||
accuracy_hundredth,
|
|
||||||
|
|
||||||
// Compare
|
|
||||||
compare_best_overall_run,
|
|
||||||
compare_sum_of_best_segments,
|
|
||||||
|
|
||||||
// Merge
|
|
||||||
merge_none,
|
|
||||||
merge_live,
|
|
||||||
merge_delta,
|
|
||||||
|
|
||||||
// MenuItem
|
|
||||||
menuItem_edit,
|
|
||||||
menuItem_new,
|
|
||||||
menuItem_open,
|
|
||||||
menuItem_open_recent,
|
|
||||||
menuItem_import,
|
|
||||||
menuItem_save,
|
|
||||||
menuItem_save_as,
|
|
||||||
menuItem_reset,
|
|
||||||
menuItem_lock,
|
|
||||||
menuItem_unlock,
|
|
||||||
menuItem_resize_default,
|
|
||||||
menuItem_resize_preferred,
|
|
||||||
menuItem_settings,
|
|
||||||
menuItem_about,
|
|
||||||
menuItem_exit,
|
|
||||||
|
|
||||||
// Errors
|
|
||||||
error_read_file,
|
|
||||||
error_write_file,
|
|
||||||
error_import_run,
|
|
||||||
|
|
||||||
// Actions
|
|
||||||
action_accept,
|
|
||||||
|
|
||||||
// Titles
|
|
||||||
title_about,
|
|
||||||
|
|
||||||
GENERAL,
|
|
||||||
TIMER,
|
|
||||||
FOOTER,
|
|
||||||
MISC,
|
|
||||||
USE_MAIN_FONT,
|
|
||||||
LB_GOAL,
|
|
||||||
ICON,
|
|
||||||
COLORS,
|
|
||||||
|
|
||||||
// Edit Dialog
|
|
||||||
ED_SEGMENTED,
|
|
||||||
TT_ED_SEGMENTED,
|
|
||||||
|
|
||||||
// Panels Title
|
|
||||||
PN_DIMENSION,
|
|
||||||
PN_DISPLAY,
|
|
||||||
PN_FONTS,
|
|
||||||
PN_SCROLLING,
|
|
||||||
|
|
||||||
// History
|
|
||||||
HISTORY,
|
|
||||||
MERGE_DELTA,
|
|
||||||
MERGE_LIVE,
|
|
||||||
MERGE_NONE,
|
|
||||||
TT_HS_OFFSET,
|
|
||||||
|
|
||||||
// Core
|
|
||||||
LB_CR_BEST,
|
|
||||||
LB_CR_SEGMENT,
|
|
||||||
LB_CR_SPLIT,
|
|
||||||
|
|
||||||
// Footer
|
|
||||||
LB_FT_BEST,
|
|
||||||
LB_FT_DELTA,
|
|
||||||
LB_FT_DELTA_BEST,
|
|
||||||
LB_FT_LIVE,
|
|
||||||
LB_FT_SEGMENT,
|
|
||||||
LB_FT_SPLIT,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Messages.
|
|
||||||
*/
|
|
||||||
ICON_TOO_BIG,
|
|
||||||
ILLEGAL_TIME,
|
|
||||||
ILLEGAL_SEGMENT_TIME,
|
|
||||||
INPUT_NAN,
|
|
||||||
INPUT_NEGATIVE,
|
|
||||||
INVALID_TIME_STAMP,
|
|
||||||
WARN_BETTER_RUN,
|
|
||||||
WARN_BETTER_TIMES,
|
|
||||||
WARN_RESET_SETTINGS,
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Tooltips.
|
|
||||||
*/
|
|
||||||
TT_ADD_SEGMENT,
|
|
||||||
TT_COLOR_PICK,
|
|
||||||
TT_COLUMN_BEST,
|
|
||||||
TT_COLUMN_SEGMENT,
|
|
||||||
TT_COLUMN_TIME,
|
|
||||||
TT_REMOVE_SEGMENT,
|
|
||||||
TT_MOVE_SEGMENT_UP,
|
|
||||||
TT_MOVE_SEGMENT_DOWN,
|
|
||||||
|
|
||||||
/*
|
// Settings > Generic
|
||||||
* Run.State enumeration.
|
setting_alwaysOnTop,
|
||||||
*/
|
setting_language,
|
||||||
RUN_NULL,
|
setting_viewerLanguage,
|
||||||
RUN_OVER,
|
setting_recentFiles,
|
||||||
RUN_READY,
|
setting_coordinates,
|
||||||
RUN_STOPPED,
|
setting_dimension,
|
||||||
|
setting_compareMethod,
|
||||||
|
setting_accuracy,
|
||||||
|
setting_locked,
|
||||||
|
setting_warnOnReset,
|
||||||
|
|
||||||
/*
|
// Settings > Color
|
||||||
* Time.Accuracy enumeration.
|
setting_color_background,
|
||||||
*/
|
setting_color_foreground,
|
||||||
ACCURACY,
|
setting_color_time,
|
||||||
|
setting_color_timer,
|
||||||
|
setting_color_timeGained,
|
||||||
|
setting_color_timeLost,
|
||||||
|
setting_color_newRecord,
|
||||||
|
setting_color_title,
|
||||||
|
setting_color_highlight,
|
||||||
|
setting_color_separators,
|
||||||
|
|
||||||
|
// Settings > Hotkey
|
||||||
|
setting_hotkey_split,
|
||||||
|
setting_hotkey_unsplit,
|
||||||
|
setting_hotkey_skip,
|
||||||
|
setting_hotkey_reset,
|
||||||
|
setting_hotkey_stop,
|
||||||
|
setting_hotkey_pause,
|
||||||
|
setting_hotkey_lock,
|
||||||
|
|
||||||
|
// Settings > Header
|
||||||
|
setting_header_goal,
|
||||||
|
setting_header_title,
|
||||||
|
|
||||||
|
// Settings > History
|
||||||
|
setting_history_rowCount,
|
||||||
|
setting_history_tabular,
|
||||||
|
setting_history_blankRows,
|
||||||
|
setting_history_multiline,
|
||||||
|
setting_history_merge,
|
||||||
|
setting_history_liveTimes,
|
||||||
|
setting_history_deltas,
|
||||||
|
setting_history_icons,
|
||||||
|
setting_history_iconSize,
|
||||||
|
setting_history_offset,
|
||||||
|
setting_history_alwaysShowLast,
|
||||||
|
setting_history_segmentFont,
|
||||||
|
setting_history_timeFont,
|
||||||
|
|
||||||
|
// Settings > Core
|
||||||
|
setting_core_accuracy,
|
||||||
|
setting_core_icons,
|
||||||
|
setting_core_iconSize,
|
||||||
|
setting_core_segmentName,
|
||||||
|
setting_core_splitTime,
|
||||||
|
setting_core_segmentTime,
|
||||||
|
setting_core_bestTime,
|
||||||
|
setting_core_segmentTimer,
|
||||||
|
setting_core_timerFont,
|
||||||
|
setting_core_segmentTimerFont,
|
||||||
|
|
||||||
|
// Settings > Graph
|
||||||
|
setting_graph_display,
|
||||||
|
setting_graph_scale,
|
||||||
|
|
||||||
|
// Settings > Footer
|
||||||
|
setting_footer_display,
|
||||||
|
setting_footer_useSplitData,
|
||||||
|
setting_footer_verbose,
|
||||||
|
setting_footer_bestTime,
|
||||||
|
setting_footer_multiline,
|
||||||
|
setting_footer_deltaLabels,
|
||||||
|
|
||||||
|
// Accuracy
|
||||||
|
accuracy_seconds,
|
||||||
|
accuracy_tenth,
|
||||||
|
accuracy_hundredth,
|
||||||
|
|
||||||
|
// Compare
|
||||||
|
compare_best_overall_run,
|
||||||
|
compare_sum_of_best_segments,
|
||||||
|
|
||||||
|
// Merge
|
||||||
|
merge_none,
|
||||||
|
merge_live,
|
||||||
|
merge_delta,
|
||||||
|
|
||||||
|
// MenuItem
|
||||||
|
menuItem_edit,
|
||||||
|
menuItem_new,
|
||||||
|
menuItem_open,
|
||||||
|
menuItem_open_recent,
|
||||||
|
menuItem_import,
|
||||||
|
menuItem_save,
|
||||||
|
menuItem_save_as,
|
||||||
|
menuItem_reset,
|
||||||
|
menuItem_lock,
|
||||||
|
menuItem_unlock,
|
||||||
|
menuItem_resize_default,
|
||||||
|
menuItem_resize_preferred,
|
||||||
|
menuItem_settings,
|
||||||
|
menuItem_about,
|
||||||
|
menuItem_exit,
|
||||||
|
|
||||||
|
// Errors
|
||||||
|
error_read_file,
|
||||||
|
error_write_file,
|
||||||
|
error_import_run,
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
action_accept,
|
||||||
|
|
||||||
|
// Titles
|
||||||
|
title_about,
|
||||||
|
|
||||||
|
GENERAL,
|
||||||
|
TIMER,
|
||||||
|
FOOTER,
|
||||||
|
MISC,
|
||||||
|
USE_MAIN_FONT,
|
||||||
|
LB_GOAL,
|
||||||
|
ICON,
|
||||||
|
COLORS,
|
||||||
|
|
||||||
|
// Edit Dialog
|
||||||
|
ED_SEGMENTED,
|
||||||
|
TT_ED_SEGMENTED,
|
||||||
|
|
||||||
|
// Panels Title
|
||||||
|
PN_DIMENSION,
|
||||||
|
PN_DISPLAY,
|
||||||
|
PN_FONTS,
|
||||||
|
PN_SCROLLING,
|
||||||
|
|
||||||
|
// History
|
||||||
|
HISTORY,
|
||||||
|
MERGE_DELTA,
|
||||||
|
MERGE_LIVE,
|
||||||
|
MERGE_NONE,
|
||||||
|
TT_HS_OFFSET,
|
||||||
|
|
||||||
|
// Core
|
||||||
|
LB_CR_BEST,
|
||||||
|
LB_CR_SEGMENT,
|
||||||
|
LB_CR_SPLIT,
|
||||||
|
|
||||||
|
// Footer
|
||||||
|
LB_FT_BEST,
|
||||||
|
LB_FT_DELTA,
|
||||||
|
LB_FT_DELTA_BEST,
|
||||||
|
LB_FT_LIVE,
|
||||||
|
LB_FT_SEGMENT,
|
||||||
|
LB_FT_SPLIT,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Messages.
|
||||||
|
*/
|
||||||
|
ICON_TOO_BIG,
|
||||||
|
ILLEGAL_TIME,
|
||||||
|
ILLEGAL_SEGMENT_TIME,
|
||||||
|
INPUT_NAN,
|
||||||
|
INPUT_NEGATIVE,
|
||||||
|
INVALID_TIME_STAMP,
|
||||||
|
WARN_BETTER_RUN,
|
||||||
|
WARN_BETTER_TIMES,
|
||||||
|
WARN_RESET_SETTINGS,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tooltips.
|
||||||
|
*/
|
||||||
|
TT_ADD_SEGMENT,
|
||||||
|
TT_COLOR_PICK,
|
||||||
|
TT_COLUMN_BEST,
|
||||||
|
TT_COLUMN_SEGMENT,
|
||||||
|
TT_COLUMN_TIME,
|
||||||
|
TT_REMOVE_SEGMENT,
|
||||||
|
TT_MOVE_SEGMENT_UP,
|
||||||
|
TT_MOVE_SEGMENT_DOWN,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run.State enumeration.
|
||||||
|
*/
|
||||||
|
RUN_NULL,
|
||||||
|
RUN_OVER,
|
||||||
|
RUN_READY,
|
||||||
|
RUN_STOPPED,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time.Accuracy enumeration.
|
||||||
|
*/
|
||||||
|
ACCURACY,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Miscellaneous tokens.
|
* Miscellaneous tokens.
|
||||||
*/
|
*/
|
||||||
ACCEPT,
|
ACCEPT,
|
||||||
APPLICATION,
|
APPLICATION,
|
||||||
BEST,
|
BEST,
|
||||||
CANCEL,
|
CANCEL,
|
||||||
COMPARE_METHOD,
|
COMPARE_METHOD,
|
||||||
COMPONENTS,
|
COMPONENTS,
|
||||||
DISABLED,
|
DISABLED,
|
||||||
EDITING,
|
EDITING,
|
||||||
ERROR,
|
ERROR,
|
||||||
GOAL,
|
GOAL,
|
||||||
IMAGE,
|
IMAGE,
|
||||||
INPUTS,
|
INPUTS,
|
||||||
MAX_ORDINATE,
|
MAX_ORDINATE,
|
||||||
NAME,
|
NAME,
|
||||||
RUN_TITLE,
|
RUN_TITLE,
|
||||||
SEGMENT,
|
SEGMENT,
|
||||||
SEGMENTS,
|
SEGMENTS,
|
||||||
SPLIT,
|
SPLIT,
|
||||||
TIME,
|
TIME,
|
||||||
UNTITLED,
|
UNTITLED,
|
||||||
WARNING,
|
WARNING,
|
||||||
|
|
||||||
/*
|
|
||||||
* 1.4
|
|
||||||
*/
|
|
||||||
INCREMENT,
|
|
||||||
START_VALUE;
|
|
||||||
|
|
||||||
public static final Locale[] LANGUAGES = new Locale[] {
|
|
||||||
Locale.ENGLISH,
|
|
||||||
Locale.FRENCH,
|
|
||||||
Locale.GERMAN,
|
|
||||||
new Locale("nl"),
|
|
||||||
new Locale("sv")
|
|
||||||
};
|
|
||||||
|
|
||||||
public static final Map<String, String> LOCALE_NAMES =
|
|
||||||
new HashMap<String, String>();
|
|
||||||
static {
|
|
||||||
LOCALE_NAMES.put("de", "Deutsch");
|
|
||||||
LOCALE_NAMES.put("en", "English");
|
|
||||||
LOCALE_NAMES.put("fr", "Français");
|
|
||||||
LOCALE_NAMES.put("nl", "Nederlands");
|
|
||||||
LOCALE_NAMES.put("sv", "Svenska");
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- INTERFACE
|
/*
|
||||||
|
* 1.4
|
||||||
|
*/
|
||||||
|
INCREMENT,
|
||||||
|
START_VALUE;
|
||||||
|
|
||||||
/**
|
public static final Locale[] LANGUAGES = new Locale[] {
|
||||||
* Returns the localized string get of this language element.
|
Locale.ENGLISH,
|
||||||
*
|
Locale.FRENCH,
|
||||||
* @return the localized string for this element.
|
Locale.GERMAN,
|
||||||
*/
|
new Locale("nl"),
|
||||||
public String get() {
|
new Locale("sv")
|
||||||
return Llanfair.getResources().getString(name());
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the localized string get of this language element. This method
|
|
||||||
* also passes down an array of parameters to replace the tokens with.
|
|
||||||
*
|
|
||||||
* @param parameters - the array of values for each token of the string.
|
|
||||||
* @return the localized string filled with the given parameters.
|
|
||||||
*/
|
|
||||||
public String get(Object... parameters) {
|
|
||||||
return Llanfair.getResources().getString(name(), parameters);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public static final Map<String, String> LOCALE_NAMES =
|
||||||
* The string representation of an enumerate is the localized string
|
new HashMap<String, String>();
|
||||||
* corresponding to its name.
|
static {
|
||||||
*/
|
LOCALE_NAMES.put("de", "Deutsch");
|
||||||
@Override public String toString() {
|
LOCALE_NAMES.put("en", "English");
|
||||||
return get();
|
LOCALE_NAMES.put("fr", "Français");
|
||||||
}
|
LOCALE_NAMES.put("nl", "Nederlands");
|
||||||
|
LOCALE_NAMES.put("sv", "Svenska");
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------- INTERFACE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the localized string get of this language element.
|
||||||
|
*
|
||||||
|
* @return the localized string for this element.
|
||||||
|
*/
|
||||||
|
public String get() {
|
||||||
|
return Llanfair.getResources().getString(name());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the localized string get of this language element. This method
|
||||||
|
* also passes down an array of parameters to replace the tokens with.
|
||||||
|
*
|
||||||
|
* @param parameters - the array of values for each token of the string.
|
||||||
|
* @return the localized string filled with the given parameters.
|
||||||
|
*/
|
||||||
|
public String get(Object... parameters) {
|
||||||
|
return Llanfair.getResources().getString(name(), parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The string representation of an enumerate is the localized string
|
||||||
|
* corresponding to its name.
|
||||||
|
*/
|
||||||
|
@Override public String toString() {
|
||||||
|
return get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,427 +31,427 @@ import java.util.Locale;
|
||||||
* @version 1.5
|
* @version 1.5
|
||||||
*/
|
*/
|
||||||
public class Llanfair extends BorderlessFrame implements TableModelListener,
|
public class Llanfair extends BorderlessFrame implements TableModelListener,
|
||||||
LocaleListener, MouseWheelListener, ActionListener, NativeKeyListener,
|
LocaleListener, MouseWheelListener, ActionListener, NativeKeyListener,
|
||||||
PropertyChangeListener, WindowListener {
|
PropertyChangeListener, WindowListener {
|
||||||
|
|
||||||
private static Resources RESOURCES = null;
|
private static Resources RESOURCES = null;
|
||||||
|
|
||||||
|
|
||||||
static {
|
|
||||||
ToolTipManager.sharedInstance().setInitialDelay( 1000 );
|
|
||||||
ToolTipManager.sharedInstance().setDismissDelay( 7000 );
|
|
||||||
ToolTipManager.sharedInstance().setReshowDelay( 0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
private Run run;
|
|
||||||
private RunPane runPane;
|
|
||||||
|
|
||||||
private Actions actions;
|
|
||||||
|
|
||||||
private JPopupMenu popupMenu;
|
static {
|
||||||
|
ToolTipManager.sharedInstance().setInitialDelay( 1000 );
|
||||||
|
ToolTipManager.sharedInstance().setDismissDelay( 7000 );
|
||||||
|
ToolTipManager.sharedInstance().setReshowDelay( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
private volatile boolean ignoreNativeInputs;
|
private Run run;
|
||||||
|
private RunPane runPane;
|
||||||
private Dimension preferredSize;
|
|
||||||
|
|
||||||
/**
|
private Actions actions;
|
||||||
* Creates and initializes the application. As with any Swing application
|
|
||||||
* this constructor should be called from within a thread to avoid
|
|
||||||
* dead-lock.
|
|
||||||
*/
|
|
||||||
private Llanfair() {
|
|
||||||
super( "Llanfair" );
|
|
||||||
LocaleDelegate.setDefault( Settings.GNR_LANG.get() );
|
|
||||||
LocaleDelegate.addLocaleListener( this );
|
|
||||||
|
|
||||||
//ResourceBundle b = ResourceBundle.getBundle("language");
|
private JPopupMenu popupMenu;
|
||||||
|
|
||||||
RESOURCES = new Resources();
|
|
||||||
registerFonts();
|
|
||||||
setLookAndFeel();
|
|
||||||
|
|
||||||
run = new Run();
|
private volatile boolean ignoreNativeInputs;
|
||||||
runPane = null;
|
|
||||||
ignoreNativeInputs = false;
|
|
||||||
preferredSize = null;
|
|
||||||
actions = new Actions( this );
|
|
||||||
|
|
||||||
setMenu();
|
|
||||||
setBehavior();
|
|
||||||
setRun( run );
|
|
||||||
|
|
||||||
setVisible( true );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main entry point of the application. This is the method called by Java
|
|
||||||
* when a user executes the JAR. Simply instantiantes a new Llanfair object.
|
|
||||||
* If an argument is passed, the program will not launch but will instead
|
|
||||||
* enter localization mode, dumping all language variables for the specified
|
|
||||||
* locale.
|
|
||||||
*
|
|
||||||
* @param args array of command line parameters supplied at launch
|
|
||||||
*/
|
|
||||||
public static void main( String[] args ) {
|
|
||||||
if ( args.length > 0 ) {
|
|
||||||
String locale = args[0];
|
|
||||||
LocaleDelegate.setDefault( new Locale( locale ) );
|
|
||||||
RESOURCES = new Resources();
|
|
||||||
dumpLocalization();
|
|
||||||
System.exit( 0 );
|
|
||||||
}
|
|
||||||
SwingUtilities.invokeLater( new Runnable() {
|
|
||||||
@Override public void run() {
|
|
||||||
new Llanfair();
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Grabs the resources of Llanfair. The Resources object is a front-end
|
|
||||||
* for every classpath resources associated with the application, including
|
|
||||||
* localization strings, icons, and properties.
|
|
||||||
*
|
|
||||||
* @return the resources object
|
|
||||||
*/
|
|
||||||
public static Resources getResources() {
|
|
||||||
return RESOURCES;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private Dimension preferredSize;
|
||||||
* Returns the run currently associated with this instance of Llanfair.
|
|
||||||
* While the run can be empty, it cannot be {@code null}.
|
|
||||||
*
|
|
||||||
* @return the current run
|
|
||||||
*/
|
|
||||||
Run getRun() {
|
|
||||||
return run;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the run to represent in this application to the given run. If the
|
|
||||||
* GUI does not exist (in other words, we are registering the first run) it
|
|
||||||
* is created on the fly.
|
|
||||||
*
|
|
||||||
* @param run the run to represent, cannot be {@code null}
|
|
||||||
*/
|
|
||||||
public final void setRun( Run run ) {
|
|
||||||
if ( run == null ) {
|
|
||||||
throw new NullPointerException( "Null run" );
|
|
||||||
}
|
|
||||||
this.run = run;
|
|
||||||
// If we have a GUI, set the new model; else, create the GUI
|
|
||||||
if ( runPane != null ) {
|
|
||||||
runPane.setRun( run );
|
|
||||||
} else {
|
|
||||||
runPane = new RunPane( run );
|
|
||||||
add( runPane );
|
|
||||||
}
|
|
||||||
Settings.setRun( run );
|
|
||||||
run.addTableModelListener( this );
|
|
||||||
run.addPropertyChangeListener( this );
|
|
||||||
MenuItem.setActiveState( run.getState() );
|
|
||||||
|
|
||||||
setPreferredSize( preferredSize );
|
|
||||||
pack();
|
|
||||||
|
|
||||||
// Replace the window to the run preferred location; center if none
|
|
||||||
Point location = Settings.GNR_COOR.get();
|
|
||||||
if ( location == null ) {
|
|
||||||
setLocationRelativeTo( null );
|
|
||||||
} else {
|
|
||||||
setLocation( location );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates whether or not Llanfair currently ignores all native inputs.
|
|
||||||
* Since native inputs can be caught even when the application does not have
|
|
||||||
* the focus, it is necessary to be able to lock the application when the
|
|
||||||
* user needs to do something else whilst not interfering with the behavior
|
|
||||||
* of Llanfair.
|
|
||||||
*
|
|
||||||
* @return {@code true} if the current instance ignores native inputs
|
|
||||||
*/
|
|
||||||
public synchronized boolean ignoresNativeInputs() {
|
|
||||||
return ignoreNativeInputs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells Llanfair whether to ignore native input events or not. Since native
|
|
||||||
* inputs can be caught even when the application does not have the focus,
|
|
||||||
* it is necessary to be able to lock the application when the user needs
|
|
||||||
* to do something else whilst not interfering with the behavior of
|
|
||||||
* Llanfair.
|
|
||||||
*
|
|
||||||
* @param ignore if Llanfair must ignore the native inputs or not
|
|
||||||
*/
|
|
||||||
public synchronized void setIgnoreNativeInputs( boolean ignore ) {
|
|
||||||
ignoreNativeInputs = ignore;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Outputs the given error in a dialog box. Only errors that are made for
|
|
||||||
* and useful to the user need to be displayed that way.
|
|
||||||
*
|
|
||||||
* @param message the localized error message
|
|
||||||
*/
|
|
||||||
void showError( String message ) {
|
|
||||||
JOptionPane.showMessageDialog(
|
|
||||||
this, message, Language.ERROR.get(), JOptionPane.ERROR_MESSAGE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the look and feel of the application. Provides a task bar icon and
|
|
||||||
* a general system dependent theme.
|
|
||||||
*/
|
|
||||||
private void setLookAndFeel() {
|
|
||||||
setIconImage( RESOURCES.getImage( "Llanfair" ) );
|
|
||||||
try {
|
|
||||||
UIManager.setLookAndFeel(
|
|
||||||
UIManager.getSystemLookAndFeelClassName()
|
|
||||||
);
|
|
||||||
} catch ( Exception ex ) {
|
|
||||||
// $FALL-THROUGH$
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register the fonts provided with Llanfair with its environment.
|
|
||||||
*/
|
|
||||||
private void registerFonts() {
|
|
||||||
InputStream fontFile = RESOURCES.getStream( "digitalism.ttf" );
|
|
||||||
try {
|
|
||||||
Font digitalism = Font.createFont( Font.TRUETYPE_FONT, fontFile );
|
|
||||||
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(
|
|
||||||
digitalism
|
|
||||||
);
|
|
||||||
} catch ( Exception ex ) {
|
|
||||||
// $FALL-THROUGH$
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes all values from the {@code Language} enum in a property file.
|
|
||||||
* This method will append all the newly defined entries to the list of
|
|
||||||
* already existing values.
|
|
||||||
*/
|
|
||||||
private static void dumpLocalization() {
|
|
||||||
try {
|
|
||||||
String iso = Locale.getDefault().getLanguage();
|
|
||||||
FileWriter fw = new FileWriter( "language_" + iso + ".properties" );
|
|
||||||
for ( Language lang : Language.values() ) {
|
|
||||||
String old = RESOURCES.getString( lang.name() );
|
|
||||||
fw.write( lang.name() + " = " );
|
|
||||||
if ( old != null ) {
|
|
||||||
fw.write( old );
|
|
||||||
}
|
|
||||||
fw.write( "\n" );
|
|
||||||
}
|
|
||||||
fw.close();
|
|
||||||
} catch ( IOException ex ) {
|
|
||||||
// $FALL-THROUGH$
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the locale changes, we first ask the resources to reload the locale
|
* Creates and initializes the application. As with any Swing application
|
||||||
* dependent resources and pass the event to the GUI.
|
* this constructor should be called from within a thread to avoid
|
||||||
*/
|
* dead-lock.
|
||||||
@Override public void localeChanged( LocaleEvent event ) {
|
*/
|
||||||
RESOURCES.defaultLocaleChanged();
|
private Llanfair() {
|
||||||
if ( runPane != null ) {
|
super( "Llanfair" );
|
||||||
runPane.processLocaleEvent( event );
|
LocaleDelegate.setDefault( Settings.GNR_LANG.get() );
|
||||||
}
|
LocaleDelegate.addLocaleListener( this );
|
||||||
MenuItem.localeChanged( event );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If we do not ignore the native inputs, register the input and invokes
|
|
||||||
* a new thread to treat the input whenever possible without hogging the
|
|
||||||
* main thread.
|
|
||||||
*/
|
|
||||||
@Override public void nativeKeyPressed( final NativeKeyEvent event ) {
|
|
||||||
int keyCode = event.getKeyCode();
|
|
||||||
boolean hotkeysEnabler = ( keyCode == Settings.KEY_LOCK.get() );
|
|
||||||
|
|
||||||
if ( !ignoresNativeInputs() || hotkeysEnabler ) {
|
|
||||||
SwingUtilities.invokeLater( new Runnable() {
|
|
||||||
@Override public void run() {
|
|
||||||
actions.process( event );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void nativeKeyReleased( NativeKeyEvent event ) {}
|
//ResourceBundle b = ResourceBundle.getBundle("language");
|
||||||
|
|
||||||
@Override public void nativeKeyTyped( NativeKeyEvent event ) {}
|
RESOURCES = new Resources();
|
||||||
|
registerFonts();
|
||||||
/**
|
setLookAndFeel();
|
||||||
* A property change event might be fired from either the settings
|
|
||||||
* singleton or the run itself. In either case, we propagate the event to
|
|
||||||
* our children and update ourself with the new value of the given property.
|
|
||||||
*/
|
|
||||||
@Override public void propertyChange( PropertyChangeEvent event ) {
|
|
||||||
runPane.processPropertyChangeEvent( event );
|
|
||||||
String property = event.getPropertyName();
|
|
||||||
|
|
||||||
if ( Run.STATE_PROPERTY.equals( property ) ) {
|
run = new Run();
|
||||||
MenuItem.setActiveState( run.getState() );
|
runPane = null;
|
||||||
} else if ( Settings.GNR_ATOP.equals( property ) ) {
|
ignoreNativeInputs = false;
|
||||||
setAlwaysOnTop( Settings.GNR_ATOP.get() );
|
preferredSize = null;
|
||||||
} else if (Settings.HST_ROWS.equals(property)
|
actions = new Actions( this );
|
||||||
|| Settings.GPH_SHOW.equals(property)
|
|
||||||
|| Settings.FOO_SHOW.equals(property)
|
|
||||||
|| Settings.FOO_SPLT.equals(property)
|
|
||||||
|| Settings.COR_ICSZ.equals(property)
|
|
||||||
|| Settings.GNR_ACCY.equals(property)
|
|
||||||
|| Settings.HDR_TTLE.equals(property)
|
|
||||||
|| Settings.HDR_GOAL.equals(property)
|
|
||||||
|| Settings.HST_DLTA.equals(property)
|
|
||||||
|| Settings.HST_SFNT.equals(property)
|
|
||||||
|| Settings.HST_TFNT.equals(property)
|
|
||||||
|| Settings.HST_LIVE.equals(property)
|
|
||||||
|| Settings.HST_MERG.equals(property)
|
|
||||||
|| Settings.HST_BLNK.equals(property)
|
|
||||||
|| Settings.HST_ICON.equals(property)
|
|
||||||
|| Settings.HST_ICSZ.equals(property)
|
|
||||||
|| Settings.HST_LINE.equals(property)
|
|
||||||
|| Settings.COR_NAME.equals(property)
|
|
||||||
|| Settings.COR_SPLT.equals(property)
|
|
||||||
|| Settings.COR_SEGM.equals(property)
|
|
||||||
|| Settings.COR_BEST.equals(property)
|
|
||||||
|| Settings.COR_ICON.equals(property)
|
|
||||||
|| Settings.COR_TFNT.equals(property)
|
|
||||||
|| Settings.COR_SFNT.equals(property)
|
|
||||||
|| Settings.COR_STMR.equals(property)
|
|
||||||
|| Settings.FOO_BEST.equals(property)
|
|
||||||
|| Settings.FOO_DLBL.equals(property)
|
|
||||||
|| Settings.FOO_VERB.equals(property)
|
|
||||||
|| Settings.FOO_LINE.equals(property)
|
|
||||||
|| Run.NAME_PROPERTY.equals(property)) {
|
|
||||||
setPreferredSize(null);
|
|
||||||
pack();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When the run's table of segments is updated, we ask the main panel to
|
|
||||||
* update itself accordingly and repack the frame as its dimensions may
|
|
||||||
* have changed.
|
|
||||||
*/
|
|
||||||
@Override public void tableChanged( TableModelEvent event ) {
|
|
||||||
runPane.processTableModelEvent( event );
|
|
||||||
// No need to recompute the size if we receive a HEADER_ROW UPDATE
|
|
||||||
// as we only use them when a segment is moved up or down and when
|
|
||||||
// the user cancel any changes made to his run.
|
|
||||||
if ( event.getType() == TableModelEvent.UPDATE
|
|
||||||
&& event.getFirstRow() == TableModelEvent.HEADER_ROW ) {
|
|
||||||
setPreferredSize( preferredSize );
|
|
||||||
} else {
|
|
||||||
setPreferredSize( null );
|
|
||||||
}
|
|
||||||
pack();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When the user scrolls the mouse wheel, we update the graph's scale to
|
|
||||||
* zoom in or out depending on the direction of the scroll.
|
|
||||||
*/
|
|
||||||
@Override public void mouseWheelMoved( MouseWheelEvent event ) {
|
|
||||||
int rotations = event.getWheelRotation();
|
|
||||||
float percent = Settings.GPH_SCAL.get();
|
|
||||||
if ( percent == 0.5F ) {
|
|
||||||
percent = 1.0F;
|
|
||||||
rotations--;
|
|
||||||
}
|
|
||||||
float newValue = Math.max( 0.5F, percent + rotations );
|
|
||||||
Settings.GPH_SCAL.set( newValue );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
setMenu();
|
||||||
* When the user clicks on the mouse's right-button, we bring up the
|
setBehavior();
|
||||||
* context menu at the click's location.
|
setRun( run );
|
||||||
*/
|
|
||||||
@Override public void mousePressed( MouseEvent event ) {
|
|
||||||
super.mousePressed( event );
|
|
||||||
if ( SwingUtilities.isRightMouseButton( event ) ) {
|
|
||||||
popupMenu.show( this, event.getX(), event.getY() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whenever the frame is being disposed of, we save the settings and
|
|
||||||
* unregister the native hook of {@code JNativeHook}.
|
|
||||||
*/
|
|
||||||
@Override public void windowClosed( WindowEvent event ) {
|
|
||||||
Settings.save();
|
|
||||||
GlobalScreen.unregisterNativeHook();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void windowClosing(WindowEvent event) {}
|
setVisible( true );
|
||||||
|
}
|
||||||
|
|
||||||
@Override public void windowOpened(WindowEvent event) {}
|
/**
|
||||||
|
* Main entry point of the application. This is the method called by Java
|
||||||
|
* when a user executes the JAR. Simply instantiantes a new Llanfair object.
|
||||||
|
* If an argument is passed, the program will not launch but will instead
|
||||||
|
* enter localization mode, dumping all language variables for the specified
|
||||||
|
* locale.
|
||||||
|
*
|
||||||
|
* @param args array of command line parameters supplied at launch
|
||||||
|
*/
|
||||||
|
public static void main( String[] args ) {
|
||||||
|
if ( args.length > 0 ) {
|
||||||
|
String locale = args[0];
|
||||||
|
LocaleDelegate.setDefault( new Locale( locale ) );
|
||||||
|
RESOURCES = new Resources();
|
||||||
|
dumpLocalization();
|
||||||
|
System.exit( 0 );
|
||||||
|
}
|
||||||
|
SwingUtilities.invokeLater( new Runnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
new Llanfair();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
@Override public void windowActivated(WindowEvent event) {}
|
/**
|
||||||
|
* Grabs the resources of Llanfair. The Resources object is a front-end
|
||||||
|
* for every classpath resources associated with the application, including
|
||||||
|
* localization strings, icons, and properties.
|
||||||
|
*
|
||||||
|
* @return the resources object
|
||||||
|
*/
|
||||||
|
public static Resources getResources() {
|
||||||
|
return RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
@Override public void windowDeactivated(WindowEvent event) {}
|
/**
|
||||||
|
* Returns the run currently associated with this instance of Llanfair.
|
||||||
|
* While the run can be empty, it cannot be {@code null}.
|
||||||
|
*
|
||||||
|
* @return the current run
|
||||||
|
*/
|
||||||
|
Run getRun() {
|
||||||
|
return run;
|
||||||
|
}
|
||||||
|
|
||||||
@Override public void windowIconified(WindowEvent event) {}
|
/**
|
||||||
|
* Sets the run to represent in this application to the given run. If the
|
||||||
|
* GUI does not exist (in other words, we are registering the first run) it
|
||||||
|
* is created on the fly.
|
||||||
|
*
|
||||||
|
* @param run the run to represent, cannot be {@code null}
|
||||||
|
*/
|
||||||
|
public final void setRun( Run run ) {
|
||||||
|
if ( run == null ) {
|
||||||
|
throw new NullPointerException( "Null run" );
|
||||||
|
}
|
||||||
|
this.run = run;
|
||||||
|
// If we have a GUI, set the new model; else, create the GUI
|
||||||
|
if ( runPane != null ) {
|
||||||
|
runPane.setRun( run );
|
||||||
|
} else {
|
||||||
|
runPane = new RunPane( run );
|
||||||
|
add( runPane );
|
||||||
|
}
|
||||||
|
Settings.setRun( run );
|
||||||
|
run.addTableModelListener( this );
|
||||||
|
run.addPropertyChangeListener( this );
|
||||||
|
MenuItem.setActiveState( run.getState() );
|
||||||
|
|
||||||
@Override public void windowDeiconified(WindowEvent event) {}
|
setPreferredSize( preferredSize );
|
||||||
|
pack();
|
||||||
/**
|
|
||||||
* Action events are fired by clicking on the entries of the context menu.
|
|
||||||
*/
|
|
||||||
@Override public synchronized void actionPerformed( final ActionEvent ev ) {
|
|
||||||
MenuItem source = ( MenuItem ) ev.getSource();
|
|
||||||
|
|
||||||
SwingUtilities.invokeLater( new Runnable() {
|
// Replace the window to the run preferred location; center if none
|
||||||
@Override public void run() {
|
Point location = Settings.GNR_COOR.get();
|
||||||
actions.process( ev );
|
if ( location == null ) {
|
||||||
}
|
setLocationRelativeTo( null );
|
||||||
} );
|
} else {
|
||||||
|
setLocation( location );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (source.equals(MenuItem.EDIT)) {
|
/**
|
||||||
|
* Indicates whether or not Llanfair currently ignores all native inputs.
|
||||||
|
* Since native inputs can be caught even when the application does not have
|
||||||
|
* the focus, it is necessary to be able to lock the application when the
|
||||||
|
* user needs to do something else whilst not interfering with the behavior
|
||||||
|
* of Llanfair.
|
||||||
|
*
|
||||||
|
* @return {@code true} if the current instance ignores native inputs
|
||||||
|
*/
|
||||||
|
public synchronized boolean ignoresNativeInputs() {
|
||||||
|
return ignoreNativeInputs;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (source.equals(MenuItem.RESIZE_DEFAULT)) {
|
/**
|
||||||
setPreferredSize(null);
|
* Tells Llanfair whether to ignore native input events or not. Since native
|
||||||
pack();
|
* inputs can be caught even when the application does not have the focus,
|
||||||
|
* it is necessary to be able to lock the application when the user needs
|
||||||
} else if (source.equals(MenuItem.RESIZE_PREFERRED)) {
|
* to do something else whilst not interfering with the behavior of
|
||||||
setPreferredSize(preferredSize);
|
* Llanfair.
|
||||||
pack();
|
*
|
||||||
}
|
* @param ignore if Llanfair must ignore the native inputs or not
|
||||||
}
|
*/
|
||||||
|
public synchronized void setIgnoreNativeInputs( boolean ignore ) {
|
||||||
|
ignoreNativeInputs = ignore;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the persistent behavior of the application and its components.
|
* Outputs the given error in a dialog box. Only errors that are made for
|
||||||
*
|
* and useful to the user need to be displayed that way.
|
||||||
* @throws IllegalStateException if JNativeHook cannot be registered.
|
*
|
||||||
*/
|
* @param message the localized error message
|
||||||
private void setBehavior() {
|
*/
|
||||||
try {
|
void showError( String message ) {
|
||||||
GlobalScreen.registerNativeHook();
|
JOptionPane.showMessageDialog(
|
||||||
} catch (NativeHookException e) {
|
this, message, Language.ERROR.get(), JOptionPane.ERROR_MESSAGE
|
||||||
throw new IllegalStateException("cannot register native hook");
|
);
|
||||||
}
|
}
|
||||||
setAlwaysOnTop(Settings.GNR_ATOP.get());
|
|
||||||
addWindowListener(this);
|
|
||||||
addMouseWheelListener(this);
|
|
||||||
Settings.addPropertyChangeListener(this);
|
|
||||||
GlobalScreen.getInstance().addNativeKeyListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the right-click context menu.
|
* Sets the look and feel of the application. Provides a task bar icon and
|
||||||
*/
|
* a general system dependent theme.
|
||||||
private void setMenu() {
|
*/
|
||||||
popupMenu = MenuItem.getPopupMenu();
|
private void setLookAndFeel() {
|
||||||
MenuItem.addActionListener( this );
|
setIconImage( RESOURCES.getImage( "Llanfair" ) );
|
||||||
MenuItem.populateRecentlyOpened();
|
try {
|
||||||
}
|
UIManager.setLookAndFeel(
|
||||||
|
UIManager.getSystemLookAndFeelClassName()
|
||||||
|
);
|
||||||
|
} catch ( Exception ex ) {
|
||||||
|
// $FALL-THROUGH$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the fonts provided with Llanfair with its environment.
|
||||||
|
*/
|
||||||
|
private void registerFonts() {
|
||||||
|
InputStream fontFile = RESOURCES.getStream( "digitalism.ttf" );
|
||||||
|
try {
|
||||||
|
Font digitalism = Font.createFont( Font.TRUETYPE_FONT, fontFile );
|
||||||
|
GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(
|
||||||
|
digitalism
|
||||||
|
);
|
||||||
|
} catch ( Exception ex ) {
|
||||||
|
// $FALL-THROUGH$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes all values from the {@code Language} enum in a property file.
|
||||||
|
* This method will append all the newly defined entries to the list of
|
||||||
|
* already existing values.
|
||||||
|
*/
|
||||||
|
private static void dumpLocalization() {
|
||||||
|
try {
|
||||||
|
String iso = Locale.getDefault().getLanguage();
|
||||||
|
FileWriter fw = new FileWriter( "language_" + iso + ".properties" );
|
||||||
|
for ( Language lang : Language.values() ) {
|
||||||
|
String old = RESOURCES.getString( lang.name() );
|
||||||
|
fw.write( lang.name() + " = " );
|
||||||
|
if ( old != null ) {
|
||||||
|
fw.write( old );
|
||||||
|
}
|
||||||
|
fw.write( "\n" );
|
||||||
|
}
|
||||||
|
fw.close();
|
||||||
|
} catch ( IOException ex ) {
|
||||||
|
// $FALL-THROUGH$
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the locale changes, we first ask the resources to reload the locale
|
||||||
|
* dependent resources and pass the event to the GUI.
|
||||||
|
*/
|
||||||
|
@Override public void localeChanged( LocaleEvent event ) {
|
||||||
|
RESOURCES.defaultLocaleChanged();
|
||||||
|
if ( runPane != null ) {
|
||||||
|
runPane.processLocaleEvent( event );
|
||||||
|
}
|
||||||
|
MenuItem.localeChanged( event );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we do not ignore the native inputs, register the input and invokes
|
||||||
|
* a new thread to treat the input whenever possible without hogging the
|
||||||
|
* main thread.
|
||||||
|
*/
|
||||||
|
@Override public void nativeKeyPressed( final NativeKeyEvent event ) {
|
||||||
|
int keyCode = event.getKeyCode();
|
||||||
|
boolean hotkeysEnabler = ( keyCode == Settings.KEY_LOCK.get() );
|
||||||
|
|
||||||
|
if ( !ignoresNativeInputs() || hotkeysEnabler ) {
|
||||||
|
SwingUtilities.invokeLater( new Runnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
actions.process( event );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void nativeKeyReleased( NativeKeyEvent event ) {}
|
||||||
|
|
||||||
|
@Override public void nativeKeyTyped( NativeKeyEvent event ) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A property change event might be fired from either the settings
|
||||||
|
* singleton or the run itself. In either case, we propagate the event to
|
||||||
|
* our children and update ourself with the new value of the given property.
|
||||||
|
*/
|
||||||
|
@Override public void propertyChange( PropertyChangeEvent event ) {
|
||||||
|
runPane.processPropertyChangeEvent( event );
|
||||||
|
String property = event.getPropertyName();
|
||||||
|
|
||||||
|
if ( Run.STATE_PROPERTY.equals( property ) ) {
|
||||||
|
MenuItem.setActiveState( run.getState() );
|
||||||
|
} else if ( Settings.GNR_ATOP.equals( property ) ) {
|
||||||
|
setAlwaysOnTop( Settings.GNR_ATOP.get() );
|
||||||
|
} else if (Settings.HST_ROWS.equals(property)
|
||||||
|
|| Settings.GPH_SHOW.equals(property)
|
||||||
|
|| Settings.FOO_SHOW.equals(property)
|
||||||
|
|| Settings.FOO_SPLT.equals(property)
|
||||||
|
|| Settings.COR_ICSZ.equals(property)
|
||||||
|
|| Settings.GNR_ACCY.equals(property)
|
||||||
|
|| Settings.HDR_TTLE.equals(property)
|
||||||
|
|| Settings.HDR_GOAL.equals(property)
|
||||||
|
|| Settings.HST_DLTA.equals(property)
|
||||||
|
|| Settings.HST_SFNT.equals(property)
|
||||||
|
|| Settings.HST_TFNT.equals(property)
|
||||||
|
|| Settings.HST_LIVE.equals(property)
|
||||||
|
|| Settings.HST_MERG.equals(property)
|
||||||
|
|| Settings.HST_BLNK.equals(property)
|
||||||
|
|| Settings.HST_ICON.equals(property)
|
||||||
|
|| Settings.HST_ICSZ.equals(property)
|
||||||
|
|| Settings.HST_LINE.equals(property)
|
||||||
|
|| Settings.COR_NAME.equals(property)
|
||||||
|
|| Settings.COR_SPLT.equals(property)
|
||||||
|
|| Settings.COR_SEGM.equals(property)
|
||||||
|
|| Settings.COR_BEST.equals(property)
|
||||||
|
|| Settings.COR_ICON.equals(property)
|
||||||
|
|| Settings.COR_TFNT.equals(property)
|
||||||
|
|| Settings.COR_SFNT.equals(property)
|
||||||
|
|| Settings.COR_STMR.equals(property)
|
||||||
|
|| Settings.FOO_BEST.equals(property)
|
||||||
|
|| Settings.FOO_DLBL.equals(property)
|
||||||
|
|| Settings.FOO_VERB.equals(property)
|
||||||
|
|| Settings.FOO_LINE.equals(property)
|
||||||
|
|| Run.NAME_PROPERTY.equals(property)) {
|
||||||
|
setPreferredSize(null);
|
||||||
|
pack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the run's table of segments is updated, we ask the main panel to
|
||||||
|
* update itself accordingly and repack the frame as its dimensions may
|
||||||
|
* have changed.
|
||||||
|
*/
|
||||||
|
@Override public void tableChanged( TableModelEvent event ) {
|
||||||
|
runPane.processTableModelEvent( event );
|
||||||
|
// No need to recompute the size if we receive a HEADER_ROW UPDATE
|
||||||
|
// as we only use them when a segment is moved up or down and when
|
||||||
|
// the user cancel any changes made to his run.
|
||||||
|
if ( event.getType() == TableModelEvent.UPDATE
|
||||||
|
&& event.getFirstRow() == TableModelEvent.HEADER_ROW ) {
|
||||||
|
setPreferredSize( preferredSize );
|
||||||
|
} else {
|
||||||
|
setPreferredSize( null );
|
||||||
|
}
|
||||||
|
pack();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the user scrolls the mouse wheel, we update the graph's scale to
|
||||||
|
* zoom in or out depending on the direction of the scroll.
|
||||||
|
*/
|
||||||
|
@Override public void mouseWheelMoved( MouseWheelEvent event ) {
|
||||||
|
int rotations = event.getWheelRotation();
|
||||||
|
float percent = Settings.GPH_SCAL.get();
|
||||||
|
if ( percent == 0.5F ) {
|
||||||
|
percent = 1.0F;
|
||||||
|
rotations--;
|
||||||
|
}
|
||||||
|
float newValue = Math.max( 0.5F, percent + rotations );
|
||||||
|
Settings.GPH_SCAL.set( newValue );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the user clicks on the mouse's right-button, we bring up the
|
||||||
|
* context menu at the click's location.
|
||||||
|
*/
|
||||||
|
@Override public void mousePressed( MouseEvent event ) {
|
||||||
|
super.mousePressed( event );
|
||||||
|
if ( SwingUtilities.isRightMouseButton( event ) ) {
|
||||||
|
popupMenu.show( this, event.getX(), event.getY() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whenever the frame is being disposed of, we save the settings and
|
||||||
|
* unregister the native hook of {@code JNativeHook}.
|
||||||
|
*/
|
||||||
|
@Override public void windowClosed( WindowEvent event ) {
|
||||||
|
Settings.save();
|
||||||
|
GlobalScreen.unregisterNativeHook();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void windowClosing(WindowEvent event) {}
|
||||||
|
|
||||||
|
@Override public void windowOpened(WindowEvent event) {}
|
||||||
|
|
||||||
|
@Override public void windowActivated(WindowEvent event) {}
|
||||||
|
|
||||||
|
@Override public void windowDeactivated(WindowEvent event) {}
|
||||||
|
|
||||||
|
@Override public void windowIconified(WindowEvent event) {}
|
||||||
|
|
||||||
|
@Override public void windowDeiconified(WindowEvent event) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action events are fired by clicking on the entries of the context menu.
|
||||||
|
*/
|
||||||
|
@Override public synchronized void actionPerformed( final ActionEvent ev ) {
|
||||||
|
MenuItem source = ( MenuItem ) ev.getSource();
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater( new Runnable() {
|
||||||
|
@Override public void run() {
|
||||||
|
actions.process( ev );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
if (source.equals(MenuItem.EDIT)) {
|
||||||
|
|
||||||
|
} else if (source.equals(MenuItem.RESIZE_DEFAULT)) {
|
||||||
|
setPreferredSize(null);
|
||||||
|
pack();
|
||||||
|
|
||||||
|
} else if (source.equals(MenuItem.RESIZE_PREFERRED)) {
|
||||||
|
setPreferredSize(preferredSize);
|
||||||
|
pack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the persistent behavior of the application and its components.
|
||||||
|
*
|
||||||
|
* @throws IllegalStateException if JNativeHook cannot be registered.
|
||||||
|
*/
|
||||||
|
private void setBehavior() {
|
||||||
|
try {
|
||||||
|
GlobalScreen.registerNativeHook();
|
||||||
|
} catch (NativeHookException e) {
|
||||||
|
throw new IllegalStateException("cannot register native hook");
|
||||||
|
}
|
||||||
|
setAlwaysOnTop(Settings.GNR_ATOP.get());
|
||||||
|
addWindowListener(this);
|
||||||
|
addMouseWheelListener(this);
|
||||||
|
Settings.addPropertyChangeListener(this);
|
||||||
|
GlobalScreen.getInstance().addNativeKeyListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the right-click context menu.
|
||||||
|
*/
|
||||||
|
private void setMenu() {
|
||||||
|
popupMenu = MenuItem.getPopupMenu();
|
||||||
|
MenuItem.addActionListener( this );
|
||||||
|
MenuItem.populateRecentlyOpened();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
package org.fenix.llanfair;
|
package org.fenix.llanfair;
|
||||||
|
|
||||||
|
import org.fenix.llanfair.Run.State;
|
||||||
|
import org.fenix.llanfair.config.Settings;
|
||||||
|
import org.fenix.utils.locale.LocaleEvent;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.event.EventListenerList;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.Icon;
|
|
||||||
import javax.swing.JMenu;
|
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import javax.swing.JPopupMenu;
|
|
||||||
import javax.swing.JSeparator;
|
|
||||||
import javax.swing.event.EventListenerList;
|
|
||||||
import org.fenix.utils.locale.LocaleEvent;
|
|
||||||
import org.fenix.llanfair.Run.State;
|
|
||||||
import org.fenix.llanfair.config.Settings;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumerates the menu items available in the right-click context menu of
|
* Enumerates the menu items available in the right-click context menu of
|
||||||
|
@ -25,207 +22,207 @@ import org.fenix.llanfair.config.Settings;
|
||||||
*/
|
*/
|
||||||
enum MenuItem implements ActionListener {
|
enum MenuItem implements ActionListener {
|
||||||
|
|
||||||
EDIT( false, State.NULL, State.READY ),
|
EDIT( false, State.NULL, State.READY ),
|
||||||
NEW( true, State.NULL, State.READY, State.STOPPED ),
|
NEW( true, State.NULL, State.READY, State.STOPPED ),
|
||||||
OPEN( false, State.NULL, State.READY, State.STOPPED ),
|
OPEN( false, State.NULL, State.READY, State.STOPPED ),
|
||||||
OPEN_RECENT( false, State.NULL, State.READY, State.STOPPED ),
|
OPEN_RECENT( false, State.NULL, State.READY, State.STOPPED ),
|
||||||
IMPORT( false, State.NULL, State.READY, State.STOPPED ),
|
IMPORT( false, State.NULL, State.READY, State.STOPPED ),
|
||||||
SAVE( false, State.READY, State.STOPPED ),
|
SAVE( false, State.READY, State.STOPPED ),
|
||||||
SAVE_AS( true, State.READY ),
|
SAVE_AS( true, State.READY ),
|
||||||
RESET( true, State.ONGOING, State.STOPPED, State.PAUSED ),
|
RESET( true, State.ONGOING, State.STOPPED, State.PAUSED ),
|
||||||
LOCK( false, State.NULL, State.READY, State.STOPPED, State.ONGOING ),
|
LOCK( false, State.NULL, State.READY, State.STOPPED, State.ONGOING ),
|
||||||
UNLOCK( false, State.NULL, State.READY, State.STOPPED, State.ONGOING ),
|
UNLOCK( false, State.NULL, State.READY, State.STOPPED, State.ONGOING ),
|
||||||
RESIZE_DEFAULT( false, State.NULL, State.READY ),
|
RESIZE_DEFAULT( false, State.NULL, State.READY ),
|
||||||
RESIZE_PREFERRED( true, State.NULL, State.READY ),
|
RESIZE_PREFERRED( true, State.NULL, State.READY ),
|
||||||
SETTINGS( true, State.NULL, State.READY, State.STOPPED ),
|
SETTINGS( true, State.NULL, State.READY, State.STOPPED ),
|
||||||
ABOUT( true, State.NULL, State.READY, State.STOPPED, State.ONGOING ),
|
ABOUT( true, State.NULL, State.READY, State.STOPPED, State.ONGOING ),
|
||||||
EXIT( false, State.NULL, State.READY, State.STOPPED, State.ONGOING );
|
EXIT( false, State.NULL, State.READY, State.STOPPED, State.ONGOING );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Static list of listeners that listen to all the menu items. Whenever
|
* Static list of listeners that listen to all the menu items. Whenever
|
||||||
* one item fires an {@code ActionEvent}, the type statically fires an
|
* one item fires an {@code ActionEvent}, the type statically fires an
|
||||||
* other {@code ActionEvent} with the {@code MenuItem} enumerate as the
|
* other {@code ActionEvent} with the {@code MenuItem} enumerate as the
|
||||||
* source component.
|
* source component.
|
||||||
*/
|
*/
|
||||||
private static EventListenerList listeners = new EventListenerList();
|
private static EventListenerList listeners = new EventListenerList();
|
||||||
|
|
||||||
private static final int MAX_FILES = 5;
|
private static final int MAX_FILES = 5;
|
||||||
private static final int TRUNCATE = 30;
|
private static final int TRUNCATE = 30;
|
||||||
|
|
||||||
private boolean isEndOfGroup;
|
|
||||||
private List<State> activeStates;
|
|
||||||
private JMenuItem menuItem;
|
|
||||||
|
|
||||||
/**
|
private boolean isEndOfGroup;
|
||||||
* Internal constructor used to set the attributes. Only called by the
|
private List<State> activeStates;
|
||||||
* enum type itself.
|
private JMenuItem menuItem;
|
||||||
*
|
|
||||||
* @param isEndOfGroup indicates if this item is a group ender
|
|
||||||
* @param activeStates list of active run states of this item
|
|
||||||
*/
|
|
||||||
private MenuItem( boolean isEndOfGroup, Run.State... activeStates ) {
|
|
||||||
this.isEndOfGroup = isEndOfGroup;
|
|
||||||
this.activeStates = Arrays.asList( activeStates );
|
|
||||||
|
|
||||||
if ( name().equals( "OPEN_RECENT" ) ) {
|
/**
|
||||||
menuItem = new JMenu( toString() );
|
* Internal constructor used to set the attributes. Only called by the
|
||||||
} else {
|
* enum type itself.
|
||||||
menuItem = new JMenuItem( toString() );
|
*
|
||||||
}
|
* @param isEndOfGroup indicates if this item is a group ender
|
||||||
Icon icon = Llanfair.getResources().getIcon( "jmi/" + name() + ".png" );
|
* @param activeStates list of active run states of this item
|
||||||
menuItem.setIcon( icon );
|
*/
|
||||||
menuItem.addActionListener( this );
|
MenuItem(boolean isEndOfGroup, Run.State... activeStates) {
|
||||||
// LOCK & UNLOCK mask each other and Llanfair always start unlocked
|
this.isEndOfGroup = isEndOfGroup;
|
||||||
if ( name().equals( "UNLOCK" ) ) {
|
this.activeStates = Arrays.asList( activeStates );
|
||||||
menuItem.setVisible( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a popup menu composed of all the menu items. A separator is
|
|
||||||
* inserted after each item which are indicated as end of their group.
|
|
||||||
*
|
|
||||||
* @return a popup menu containing every menu item
|
|
||||||
*/
|
|
||||||
static JPopupMenu getPopupMenu() {
|
|
||||||
JPopupMenu menu = new JPopupMenu();
|
|
||||||
for ( MenuItem item : values() ) {
|
|
||||||
menu.add( item.menuItem );
|
|
||||||
if ( item.isEndOfGroup ) {
|
|
||||||
menu.add( new JSeparator() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return menu;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
if ( name().equals( "OPEN_RECENT" ) ) {
|
||||||
* Enables or disables every menu items depending on the given run state.
|
menuItem = new JMenu( toString() );
|
||||||
* If this state is present in the list of active states for an item, then
|
} else {
|
||||||
* its GUI component is enabled, else it is disabled.
|
menuItem = new JMenuItem( toString() );
|
||||||
*
|
}
|
||||||
* @param state the current run state, cannot be {@code null}
|
Icon icon = Llanfair.getResources().getIcon( "jmi/" + name() + ".png" );
|
||||||
*/
|
menuItem.setIcon( icon );
|
||||||
static void setActiveState( Run.State state ) {
|
menuItem.addActionListener( this );
|
||||||
if ( state == null ) {
|
// LOCK & UNLOCK mask each other and Llanfair always start unlocked
|
||||||
throw new IllegalArgumentException( "Null run state" );
|
if ( name().equals( "UNLOCK" ) ) {
|
||||||
}
|
menuItem.setVisible( false );
|
||||||
for ( MenuItem item : values() ) {
|
}
|
||||||
item.menuItem.setEnabled( item.activeStates.contains( state ) );
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers the given {@code ActionListener} to the list of listeners
|
* Returns a popup menu composed of all the menu items. A separator is
|
||||||
* interested in capturing events from every menu items.
|
* inserted after each item which are indicated as end of their group.
|
||||||
*
|
*
|
||||||
* @param listener the action listener to register
|
* @return a popup menu containing every menu item
|
||||||
*/
|
*/
|
||||||
static void addActionListener( ActionListener listener ) {
|
static JPopupMenu getPopupMenu() {
|
||||||
listeners.add( ActionListener.class, listener );
|
JPopupMenu menu = new JPopupMenu();
|
||||||
}
|
for ( MenuItem item : values() ) {
|
||||||
|
menu.add( item.menuItem );
|
||||||
/**
|
if ( item.isEndOfGroup ) {
|
||||||
* Callback to invoke whenever a file is opened. This method will sort the
|
menu.add( new JSeparator() );
|
||||||
* recent files menu to put the recently opened file at the top.
|
}
|
||||||
*
|
}
|
||||||
* @param path the name of the recently opened file
|
return menu;
|
||||||
*/
|
}
|
||||||
static void recentlyOpened( String path ) {
|
|
||||||
assert ( path != null );
|
|
||||||
List<String> recentFiles = Settings.GNR_RCNT.get();
|
|
||||||
|
|
||||||
if ( recentFiles.contains( path ) ) {
|
|
||||||
recentFiles.remove( path );
|
|
||||||
}
|
|
||||||
recentFiles.add( 0, path );
|
|
||||||
|
|
||||||
if ( recentFiles.size() > MAX_FILES ) {
|
/**
|
||||||
recentFiles.remove( MAX_FILES );
|
* Enables or disables every menu items depending on the given run state.
|
||||||
}
|
* If this state is present in the list of active states for an item, then
|
||||||
Settings.GNR_RCNT.set( recentFiles );
|
* its GUI component is enabled, else it is disabled.
|
||||||
populateRecentlyOpened();
|
*
|
||||||
}
|
* @param state the current run state, cannot be {@code null}
|
||||||
|
*/
|
||||||
/**
|
static void setActiveState( Run.State state ) {
|
||||||
* Fills the {@code OPEN_RECENT} item with the list of recently opened
|
if ( state == null ) {
|
||||||
* files. If {@code MAX_FILES} is somehow lower than the recent files list
|
throw new IllegalArgumentException( "Null run state" );
|
||||||
* length, the overflowing files are removed.
|
}
|
||||||
*/
|
for ( MenuItem item : values() ) {
|
||||||
static void populateRecentlyOpened() {
|
item.menuItem.setEnabled( item.activeStates.contains( state ) );
|
||||||
List<String> recentFiles = Settings.GNR_RCNT.get();
|
}
|
||||||
for ( int i = MAX_FILES; i < recentFiles.size(); i++ ) {
|
}
|
||||||
recentFiles.remove( i - 1 );
|
|
||||||
}
|
|
||||||
OPEN_RECENT.menuItem.removeAll();
|
|
||||||
for ( String fileName : Settings.GNR_RCNT.get() ) {
|
|
||||||
String text = fileName;
|
|
||||||
int index = text.lastIndexOf( File.separatorChar );
|
|
||||||
if ( index == -1 ) {
|
|
||||||
int length = text.length();
|
|
||||||
int start = length - Math.min( length, TRUNCATE );
|
|
||||||
text = text.substring( start );
|
|
||||||
if ( start == 0 ) {
|
|
||||||
text = "[...]" + text;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
text = text.substring( index + 1 );
|
|
||||||
}
|
|
||||||
JMenuItem jmi = new JMenuItem( text );
|
|
||||||
jmi.setName( "RECENT" + fileName );
|
|
||||||
jmi.addActionListener( OPEN_RECENT );
|
|
||||||
OPEN_RECENT.menuItem.add( jmi );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the localized name of this menu item.
|
|
||||||
*/
|
|
||||||
@Override public String toString() {
|
|
||||||
return Language.valueOf( "menuItem_" + name().toLowerCase() ).get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When a GUI component fires an action event, capture it and fire it
|
* Registers the given {@code ActionListener} to the list of listeners
|
||||||
* back, setting the source as the enumerate value instead of the GUI
|
* interested in capturing events from every menu items.
|
||||||
* component.
|
*
|
||||||
*/
|
* @param listener the action listener to register
|
||||||
@Override public void actionPerformed( ActionEvent event ) {
|
*/
|
||||||
Object source = event.getSource();
|
static void addActionListener( ActionListener listener ) {
|
||||||
|
listeners.add( ActionListener.class, listener );
|
||||||
if ( source.equals( LOCK.menuItem ) ) {
|
}
|
||||||
LOCK.menuItem.setVisible( false );
|
|
||||||
UNLOCK.menuItem.setVisible( true );
|
|
||||||
} else if ( source.equals( UNLOCK.menuItem ) ) {
|
|
||||||
LOCK.menuItem.setVisible( true );
|
|
||||||
UNLOCK.menuItem.setVisible( false );
|
|
||||||
}
|
|
||||||
|
|
||||||
JMenuItem jmi = ( JMenuItem ) source;
|
/**
|
||||||
String name = jmi.getName();
|
* Callback to invoke whenever a file is opened. This method will sort the
|
||||||
ActionListener[] als = listeners.getListeners( ActionListener.class );
|
* recent files menu to put the recently opened file at the top.
|
||||||
|
*
|
||||||
if ( name != null && name.startsWith( "RECENT" ) ) {
|
* @param path the name of the recently opened file
|
||||||
event = new ActionEvent(
|
*/
|
||||||
this, ActionEvent.ACTION_PERFORMED, name.substring( 6 )
|
static void recentlyOpened( String path ) {
|
||||||
);
|
assert ( path != null );
|
||||||
} else {
|
List<String> recentFiles = Settings.GNR_RCNT.get();
|
||||||
event = new ActionEvent(
|
|
||||||
this, ActionEvent.ACTION_PERFORMED, jmi.getText()
|
if ( recentFiles.contains( path ) ) {
|
||||||
);
|
recentFiles.remove( path );
|
||||||
}
|
}
|
||||||
for ( ActionListener al : als ) {
|
recentFiles.add( 0, path );
|
||||||
al.actionPerformed( event );
|
|
||||||
}
|
if ( recentFiles.size() > MAX_FILES ) {
|
||||||
}
|
recentFiles.remove( MAX_FILES );
|
||||||
|
}
|
||||||
|
Settings.GNR_RCNT.set( recentFiles );
|
||||||
|
populateRecentlyOpened();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills the {@code OPEN_RECENT} item with the list of recently opened
|
||||||
|
* files. If {@code MAX_FILES} is somehow lower than the recent files list
|
||||||
|
* length, the overflowing files are removed.
|
||||||
|
*/
|
||||||
|
static void populateRecentlyOpened() {
|
||||||
|
List<String> recentFiles = Settings.GNR_RCNT.get();
|
||||||
|
for ( int i = MAX_FILES; i < recentFiles.size(); i++ ) {
|
||||||
|
recentFiles.remove( i - 1 );
|
||||||
|
}
|
||||||
|
OPEN_RECENT.menuItem.removeAll();
|
||||||
|
for ( String fileName : Settings.GNR_RCNT.get() ) {
|
||||||
|
String text = fileName;
|
||||||
|
int index = text.lastIndexOf( File.separatorChar );
|
||||||
|
if ( index == -1 ) {
|
||||||
|
int length = text.length();
|
||||||
|
int start = length - Math.min( length, TRUNCATE );
|
||||||
|
text = text.substring( start );
|
||||||
|
if ( start == 0 ) {
|
||||||
|
text = "[...]" + text;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
text = text.substring( index + 1 );
|
||||||
|
}
|
||||||
|
JMenuItem jmi = new JMenuItem( text );
|
||||||
|
jmi.setName( "RECENT" + fileName );
|
||||||
|
jmi.addActionListener( OPEN_RECENT );
|
||||||
|
OPEN_RECENT.menuItem.add( jmi );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the localized name of this menu item.
|
||||||
|
*/
|
||||||
|
@Override public String toString() {
|
||||||
|
return Language.valueOf( "menuItem_" + name().toLowerCase() ).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a GUI component fires an action event, capture it and fire it
|
||||||
|
* back, setting the source as the enumerate value instead of the GUI
|
||||||
|
* component.
|
||||||
|
*/
|
||||||
|
@Override public void actionPerformed( ActionEvent event ) {
|
||||||
|
Object source = event.getSource();
|
||||||
|
|
||||||
|
if ( source.equals( LOCK.menuItem ) ) {
|
||||||
|
LOCK.menuItem.setVisible( false );
|
||||||
|
UNLOCK.menuItem.setVisible( true );
|
||||||
|
} else if ( source.equals( UNLOCK.menuItem ) ) {
|
||||||
|
LOCK.menuItem.setVisible( true );
|
||||||
|
UNLOCK.menuItem.setVisible( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
JMenuItem jmi = ( JMenuItem ) source;
|
||||||
|
String name = jmi.getName();
|
||||||
|
ActionListener[] als = listeners.getListeners( ActionListener.class );
|
||||||
|
|
||||||
|
if ( name != null && name.startsWith( "RECENT" ) ) {
|
||||||
|
event = new ActionEvent(
|
||||||
|
this, ActionEvent.ACTION_PERFORMED, name.substring( 6 )
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
event = new ActionEvent(
|
||||||
|
this, ActionEvent.ACTION_PERFORMED, jmi.getText()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for ( ActionListener al : als ) {
|
||||||
|
al.actionPerformed( event );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the locale changes, every menu item must be updated to enforce the
|
||||||
|
* new locale setting.
|
||||||
|
*/
|
||||||
|
public static void localeChanged( LocaleEvent event ) {
|
||||||
|
for ( MenuItem item : values() ) {
|
||||||
|
item.menuItem.setText( "" + item );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* When the locale changes, every menu item must be updated to enforce the
|
|
||||||
* new locale setting.
|
|
||||||
*/
|
|
||||||
public static void localeChanged( LocaleEvent event ) {
|
|
||||||
for ( MenuItem item : values() ) {
|
|
||||||
item.menuItem.setText( "" + item );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,311 +17,311 @@ import java.io.Serializable;
|
||||||
*/
|
*/
|
||||||
public class Segment implements Cloneable, Serializable {
|
public class Segment implements Cloneable, Serializable {
|
||||||
|
|
||||||
// -------------------------------------------------------------- CONSTANTS
|
// -------------------------------------------------------------- CONSTANTS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The serial version identifier used to determine the compatibility of the
|
* The serial version identifier used to determine the compatibility of the
|
||||||
* different serialized versions of this type. This identifier must change
|
* different serialized versions of this type. This identifier must change
|
||||||
* when modifications that break backward-compatibility are made to the
|
* when modifications that break backward-compatibility are made to the
|
||||||
* type.
|
* type.
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 1001L;
|
private static final long serialVersionUID = 1001L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of legit display sizes for the segments’ icons.
|
* Array of legit display sizes for the segments’ icons.
|
||||||
*/
|
*/
|
||||||
public static final Integer[] ICON_SIZES = new Integer[] {
|
public static final Integer[] ICON_SIZES = new Integer[] {
|
||||||
16, 24, 32, 40, 48, 56, 64
|
16, 24, 32, 40, 48, 56, 64
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum size allowed for the segment’s icons. When setting an icon for
|
* Maximum size allowed for the segment’s icons. When setting an icon for
|
||||||
* a segment, it will be scaled down to that size if it’s bigger, but will
|
* a segment, it will be scaled down to that size if it’s bigger, but will
|
||||||
* not be scaled up if it’s smaller.
|
* not be scaled up if it’s smaller.
|
||||||
*/
|
*/
|
||||||
public static final int ICON_MAX_SIZE = ICON_SIZES[ICON_SIZES.length - 1];
|
public static final int ICON_MAX_SIZE = ICON_SIZES[ICON_SIZES.length - 1];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifier for the time of the segment as defined by the currently set
|
* Identifier for the time of the segment as defined by the currently set
|
||||||
* compare method.
|
* compare method.
|
||||||
*/
|
*/
|
||||||
public static final int SET = 0;
|
public static final int SET = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifier for the registered time of the segment.
|
* Identifier for the registered time of the segment.
|
||||||
*/
|
*/
|
||||||
public static final int RUN = 1;
|
public static final int RUN = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifier for the best ever registered time of the segment.
|
* Identifier for the best ever registered time of the segment.
|
||||||
*/
|
*/
|
||||||
public static final int BEST = 2;
|
public static final int BEST = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifier for the live time realized on this segment.
|
* Identifier for the live time realized on this segment.
|
||||||
*/
|
*/
|
||||||
public static final int LIVE = 3;
|
public static final int LIVE = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifier for the delta between the live time and the time as defined
|
* Identifier for the delta between the live time and the time as defined
|
||||||
* by the currently set compare method, i.e. {@code LIVE - SET}.
|
* by the currently set compare method, i.e. {@code LIVE - SET}.
|
||||||
*/
|
*/
|
||||||
public static final int DELTA = 4;
|
public static final int DELTA = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifier for the delta between the live time and the registered time
|
* Identifier for the delta between the live time and the registered time
|
||||||
* of the segment, i.e. {@code LIVE - RUN}.
|
* of the segment, i.e. {@code LIVE - RUN}.
|
||||||
*/
|
*/
|
||||||
public static final int DELTA_RUN = 5;
|
public static final int DELTA_RUN = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifier for the delta between the live time and the best ever
|
* Identifier for the delta between the live time and the best ever
|
||||||
* registered time of the segment, i.e. {@code LIVE - BEST}.
|
* registered time of the segment, i.e. {@code LIVE - BEST}.
|
||||||
*/
|
*/
|
||||||
public static final int DELTA_BEST = 6;
|
public static final int DELTA_BEST = 6;
|
||||||
|
|
||||||
// ------------------------------------------------------------- ATTRIBUTES
|
// ------------------------------------------------------------- ATTRIBUTES
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Name of the segment.
|
* Name of the segment.
|
||||||
*/
|
*/
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Icon associated with this segment. Can be {@code null} if no icon is to
|
* Icon associated with this segment. Can be {@code null} if no icon is to
|
||||||
* be displayed.
|
* be displayed.
|
||||||
*/
|
*/
|
||||||
private Icon icon;
|
private Icon icon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registered time for this segment during the best run.
|
* Registered time for this segment during the best run.
|
||||||
*/
|
*/
|
||||||
private Time runTime;
|
private Time runTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Best time ever registered for this segment.
|
* Best time ever registered for this segment.
|
||||||
*/
|
*/
|
||||||
private Time bestTime;
|
private Time bestTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Live time realized on this segment during a run. This value is never
|
* Live time realized on this segment during a run. This value is never
|
||||||
* saved as is but can overwrite {@code runTime} or {@code bestTime}.
|
* saved as is but can overwrite {@code runTime} or {@code bestTime}.
|
||||||
*/
|
*/
|
||||||
private transient Time liveTime;
|
private transient Time liveTime;
|
||||||
|
|
||||||
/**
|
|
||||||
* Number of milliseconds on the clock when the segment started.
|
|
||||||
*/
|
|
||||||
private transient long startTime;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------- CONSTRUCTORS
|
/**
|
||||||
|
* Number of milliseconds on the clock when the segment started.
|
||||||
|
*/
|
||||||
|
private transient long startTime;
|
||||||
|
|
||||||
/**
|
// ----------------------------------------------------------- CONSTRUCTORS
|
||||||
* Creates a new segment of given name and undefined times.
|
|
||||||
*
|
|
||||||
* @param name - the name of the segment.
|
|
||||||
*/
|
|
||||||
public Segment(String name) {
|
|
||||||
if (name == null) {
|
|
||||||
throw new NullPointerException("null segment name");
|
|
||||||
}
|
|
||||||
this.name = name;
|
|
||||||
icon = null;
|
|
||||||
runTime = null;
|
|
||||||
bestTime = null;
|
|
||||||
initializeTransients();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a default segment with a default name and undefined times.
|
|
||||||
*/
|
|
||||||
public Segment() {
|
|
||||||
this("" + Language.UNTITLED);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------- GETTERS
|
/**
|
||||||
|
* Creates a new segment of given name and undefined times.
|
||||||
|
*
|
||||||
|
* @param name - the name of the segment.
|
||||||
|
*/
|
||||||
|
public Segment(String name) {
|
||||||
|
if (name == null) {
|
||||||
|
throw new NullPointerException("null segment name");
|
||||||
|
}
|
||||||
|
this.name = name;
|
||||||
|
icon = null;
|
||||||
|
runTime = null;
|
||||||
|
bestTime = null;
|
||||||
|
initializeTransients();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the name of the segment.
|
* Creates a default segment with a default name and undefined times.
|
||||||
*
|
*/
|
||||||
* @return the name of the segment.
|
public Segment() {
|
||||||
*/
|
this("" + Language.UNTITLED);
|
||||||
public String getName() {
|
}
|
||||||
return name;
|
|
||||||
}
|
// ---------------------------------------------------------------- GETTERS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the icon associated with this segment. Can be {@code null}.
|
* Returns the name of the segment.
|
||||||
*
|
*
|
||||||
* @return the icon of the segment or {@code null}.
|
* @return the name of the segment.
|
||||||
*/
|
*/
|
||||||
public Icon getIcon() {
|
public String getName() {
|
||||||
return icon;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of milliseconds on the clock when the segment started.
|
* Returns the icon associated with this segment. Can be {@code null}.
|
||||||
*
|
*
|
||||||
* @return the start time of this segment.
|
* @return the icon of the segment or {@code null}.
|
||||||
*/
|
*/
|
||||||
public long getStartTime() {
|
public Icon getIcon() {
|
||||||
return startTime;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the given type of time for this segment.
|
* Returns the number of milliseconds on the clock when the segment started.
|
||||||
*
|
*
|
||||||
* @param type - one of the type identifier.
|
* @return the start time of this segment.
|
||||||
* @return the segment time of given type.
|
*/
|
||||||
*/
|
public long getStartTime() {
|
||||||
public Time getTime(int type) {
|
return startTime;
|
||||||
switch (type) {
|
}
|
||||||
case BEST:
|
|
||||||
return bestTime;
|
/**
|
||||||
|
* Returns the given type of time for this segment.
|
||||||
case LIVE:
|
*
|
||||||
return liveTime;
|
* @param type - one of the type identifier.
|
||||||
|
* @return the segment time of given type.
|
||||||
case RUN:
|
*/
|
||||||
return runTime;
|
public Time getTime(int type) {
|
||||||
|
switch (type) {
|
||||||
case DELTA_RUN:
|
case BEST:
|
||||||
if (runTime == null) {
|
return bestTime;
|
||||||
return null;
|
|
||||||
}
|
case LIVE:
|
||||||
return Time.getDelta(liveTime, runTime);
|
return liveTime;
|
||||||
|
|
||||||
case DELTA_BEST:
|
case RUN:
|
||||||
if (bestTime == null) {
|
return runTime;
|
||||||
return null;
|
|
||||||
}
|
case DELTA_RUN:
|
||||||
return Time.getDelta(liveTime, bestTime);
|
if (runTime == null) {
|
||||||
|
return null;
|
||||||
case DELTA:
|
}
|
||||||
Time time = getTime();
|
return Time.getDelta(liveTime, runTime);
|
||||||
return (time == null ? null : Time.getDelta(liveTime, time));
|
|
||||||
|
case DELTA_BEST:
|
||||||
default:
|
if (bestTime == null) {
|
||||||
return getTime();
|
return null;
|
||||||
}
|
}
|
||||||
}
|
return Time.getDelta(liveTime, bestTime);
|
||||||
|
|
||||||
/**
|
case DELTA:
|
||||||
* As specified by {@code Cloneable}, returns a deep copy of the segment.
|
Time time = getTime();
|
||||||
*/
|
return (time == null ? null : Time.getDelta(liveTime, time));
|
||||||
public Segment clone() {
|
|
||||||
Segment segment = new Segment(name);
|
default:
|
||||||
segment.icon = icon;
|
return getTime();
|
||||||
segment.runTime = (runTime == null ? null : runTime.clone());
|
}
|
||||||
segment.bestTime = (bestTime == null ? null : bestTime.clone());
|
}
|
||||||
segment.liveTime = (liveTime == null ? null : liveTime.clone());
|
|
||||||
segment.startTime = startTime;
|
/**
|
||||||
return segment;
|
* As specified by {@code Cloneable}, returns a deep copy of the segment.
|
||||||
}
|
*/
|
||||||
|
public Segment clone() {
|
||||||
// ---------------------------------------------------------------- SETTERS
|
Segment segment = new Segment(name);
|
||||||
|
segment.icon = icon;
|
||||||
/**
|
segment.runTime = (runTime == null ? null : runTime.clone());
|
||||||
* Sets the name of the segment to the given string.
|
segment.bestTime = (bestTime == null ? null : bestTime.clone());
|
||||||
*
|
segment.liveTime = (liveTime == null ? null : liveTime.clone());
|
||||||
* @param name - the new name of the segment.
|
segment.startTime = startTime;
|
||||||
*/
|
return segment;
|
||||||
public void setName(String name) {
|
}
|
||||||
if (name == null) {
|
|
||||||
throw new NullPointerException("null name");
|
// ---------------------------------------------------------------- SETTERS
|
||||||
}
|
|
||||||
this.name = name;
|
/**
|
||||||
}
|
* Sets the name of the segment to the given string.
|
||||||
|
*
|
||||||
/**
|
* @param name - the new name of the segment.
|
||||||
* Sets the current icon of this segment. Can be {@code null} to remove
|
*/
|
||||||
* the current icon or indicate that no icon should be used. The icon wil
|
public void setName(String name) {
|
||||||
* be scale down to {@code ICON_MAX_SIZE} if it’s bigger.
|
if (name == null) {
|
||||||
*
|
throw new NullPointerException("null name");
|
||||||
* @param icon - the new icon for this segment.
|
}
|
||||||
*/
|
this.name = name;
|
||||||
public void setIcon(Icon icon) {
|
}
|
||||||
if (icon == null) {
|
|
||||||
this.icon = null;
|
/**
|
||||||
} else {
|
* Sets the current icon of this segment. Can be {@code null} to remove
|
||||||
this.icon = Images.rescale(icon, ICON_MAX_SIZE);
|
* the current icon or indicate that no icon should be used. The icon wil
|
||||||
}
|
* be scale down to {@code ICON_MAX_SIZE} if it’s bigger.
|
||||||
}
|
*
|
||||||
|
* @param icon - the new icon for this segment.
|
||||||
/**
|
*/
|
||||||
* Sets the number of milliseconds on the clock when the segment started.
|
public void setIcon(Icon icon) {
|
||||||
* Should only be called by the run owning this segment.
|
if (icon == null) {
|
||||||
*
|
this.icon = null;
|
||||||
* @param startTime - the starting time of this segment.
|
} else {
|
||||||
* @throws IllegalArgumentException if the time is negative.
|
this.icon = Images.rescale(icon, ICON_MAX_SIZE);
|
||||||
*/
|
}
|
||||||
void setStartTime(long startTime) {
|
}
|
||||||
if (startTime < 0L) {
|
|
||||||
throw new IllegalArgumentException("negative start time");
|
/**
|
||||||
}
|
* Sets the number of milliseconds on the clock when the segment started.
|
||||||
this.startTime = startTime;
|
* Should only be called by the run owning this segment.
|
||||||
}
|
*
|
||||||
|
* @param startTime - the starting time of this segment.
|
||||||
/**
|
* @throws IllegalArgumentException if the time is negative.
|
||||||
* Sets the given type of time to the new value. Note that some type of
|
*/
|
||||||
* times cannot be set (such as {@code DELTA}s.) The new value can be
|
void setStartTime(long startTime) {
|
||||||
* {@code null} to indicate undefined times.
|
if (startTime < 0L) {
|
||||||
*
|
throw new IllegalArgumentException("negative start time");
|
||||||
* @param time - the new time value for the given type.
|
}
|
||||||
* @param type - one of the type identifier.
|
this.startTime = startTime;
|
||||||
* @throws IllegalArgumentException if the new time value is lower than or
|
}
|
||||||
* equal to zero.
|
|
||||||
*/
|
/**
|
||||||
public void setTime(Time time, int type, boolean bypass) {
|
* Sets the given type of time to the new value. Note that some type of
|
||||||
if (!bypass) {
|
* times cannot be set (such as {@code DELTA}s.) The new value can be
|
||||||
if (time != null && time.compareTo(Time.ZERO) <= 0) {
|
* {@code null} to indicate undefined times.
|
||||||
throw new IllegalArgumentException("" + Language.ILLEGAL_TIME);
|
*
|
||||||
}
|
* @param time - the new time value for the given type.
|
||||||
}
|
* @param type - one of the type identifier.
|
||||||
switch (type) {
|
* @throws IllegalArgumentException if the new time value is lower than or
|
||||||
case BEST: bestTime = time; break;
|
* equal to zero.
|
||||||
case LIVE: liveTime = time; break;
|
*/
|
||||||
case RUN: runTime = time; break;
|
public void setTime(Time time, int type, boolean bypass) {
|
||||||
}
|
if (!bypass) {
|
||||||
}
|
if (time != null && time.compareTo(Time.ZERO) <= 0) {
|
||||||
|
throw new IllegalArgumentException("" + Language.ILLEGAL_TIME);
|
||||||
public void setTime(Time time, int type) {
|
}
|
||||||
setTime(time, type, false);
|
}
|
||||||
}
|
switch (type) {
|
||||||
|
case BEST: bestTime = time; break;
|
||||||
|
case LIVE: liveTime = time; break;
|
||||||
|
case RUN: runTime = time; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTime(Time time, int type) {
|
||||||
|
setTime(time, type, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------- UTILITIES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all transient fields.
|
||||||
|
*/
|
||||||
|
private void initializeTransients() {
|
||||||
|
liveTime = null;
|
||||||
|
startTime = 0L;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the time of this segment as specified by the currently set
|
||||||
|
* compare method.
|
||||||
|
*
|
||||||
|
* @return the time as defined by the current compare method.
|
||||||
|
*/
|
||||||
|
private Time getTime() {
|
||||||
|
switch (Settings.GNR_COMP.get()) {
|
||||||
|
case BEST_OVERALL_RUN: return runTime;
|
||||||
|
case SUM_OF_BEST_SEGMENTS: return bestTime;
|
||||||
|
}
|
||||||
|
// Should not be reached.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------- UTILITIES
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize all transient fields.
|
|
||||||
*/
|
|
||||||
private void initializeTransients() {
|
|
||||||
liveTime = null;
|
|
||||||
startTime = 0L;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the time of this segment as specified by the currently set
|
|
||||||
* compare method.
|
|
||||||
*
|
|
||||||
* @return the time as defined by the current compare method.
|
|
||||||
*/
|
|
||||||
private Time getTime() {
|
|
||||||
switch (Settings.GNR_COMP.get()) {
|
|
||||||
case BEST_OVERALL_RUN: return runTime;
|
|
||||||
case SUM_OF_BEST_SEGMENTS: return bestTime;
|
|
||||||
}
|
|
||||||
// Should not be reached.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserialization process. Redefined to initialize transients fields upon
|
* Deserialization process. Redefined to initialize transients fields upon
|
||||||
* deserialization.
|
* deserialization.
|
||||||
*/
|
*/
|
||||||
private void readObject(ObjectInputStream in)
|
private void readObject(ObjectInputStream in)
|
||||||
throws IOException, ClassNotFoundException {
|
throws IOException, ClassNotFoundException {
|
||||||
in.defaultReadObject();
|
in.defaultReadObject();
|
||||||
initializeTransients();
|
initializeTransients();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,276 +23,276 @@ import org.fenix.llanfair.config.Settings;
|
||||||
* @version 1.1
|
* @version 1.1
|
||||||
*/
|
*/
|
||||||
public class Time implements Cloneable, Comparable<Time>, Serializable {
|
public class Time implements Cloneable, Comparable<Time>, Serializable {
|
||||||
|
|
||||||
/**
|
|
||||||
* A time of zero milliseconds. This constant can be used for comparisons
|
|
||||||
* with other times and nothing else.
|
|
||||||
*/
|
|
||||||
public static final Time ZERO = new Time();
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1000L;
|
/**
|
||||||
|
* A time of zero milliseconds. This constant can be used for comparisons
|
||||||
|
* with other times and nothing else.
|
||||||
|
*/
|
||||||
|
public static final Time ZERO = new Time();
|
||||||
|
|
||||||
private long milliseconds;
|
private static final long serialVersionUID = 1000L;
|
||||||
|
|
||||||
/**
|
private long milliseconds;
|
||||||
* Creates a default time of zero milliseconds.
|
|
||||||
*/
|
|
||||||
public Time() {
|
|
||||||
milliseconds = 0L;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a time representing a given number of milliseconds. This number
|
* Creates a default time of zero milliseconds.
|
||||||
* is truncated to the milliseconds to prevent discrepencies resulting from
|
*/
|
||||||
* successive calls to {@link System.currentTimeMillis()} and thus ensures
|
public Time() {
|
||||||
* that the compare method remains accurate.
|
milliseconds = 0L;
|
||||||
*
|
}
|
||||||
* @param ms the number of milliseconds to represent
|
|
||||||
*/
|
|
||||||
public Time(long ms) {
|
|
||||||
milliseconds = (ms / 10L) * 10L;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a time representing the given decimal number of seconds. This
|
|
||||||
* number is truncated to the milliseconds to prevent discrepencies
|
|
||||||
* resulting from successive calls to {@link System.currentTimeMillis()}
|
|
||||||
* and thus ensures that the compare method remains accurate.
|
|
||||||
*
|
|
||||||
* @param seconds the number of seconds to represent
|
|
||||||
*/
|
|
||||||
public Time(double seconds) {
|
|
||||||
this((long) (seconds * 1000.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a time representing the given time-stamp. The time-stamp is a
|
* Creates a time representing a given number of milliseconds. This number
|
||||||
* string describing the time in a format understandable by the user. The
|
* is truncated to the milliseconds to prevent discrepencies resulting from
|
||||||
* time-stamp must be formatted according to the following:
|
* successive calls to {@link System.currentTimeMillis()} and thus ensures
|
||||||
*
|
* that the compare method remains accurate.
|
||||||
* <pre>((H)H:)((M)M:)(S)S(.T(H(M)))</pre>
|
*
|
||||||
*
|
* @param ms the number of milliseconds to represent
|
||||||
* Where a letter represents a digit and parenthesis indicate optionality.
|
*/
|
||||||
* H stands for hours, M for minutes, S for seconds, T for tenths, H for
|
public Time(long ms) {
|
||||||
* hundredth and M for milliseconds.
|
milliseconds = (ms / 10L) * 10L;
|
||||||
*
|
}
|
||||||
* @param timestamp a string representation of the time to parse
|
|
||||||
* @throws IllegalArgumentException if the timestamp cannot be parsed
|
|
||||||
*/
|
|
||||||
public Time(String timeStamp) {
|
|
||||||
try {
|
|
||||||
milliseconds = parseTimeStamp(timeStamp);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
Language.INVALID_TIME_STAMP.get(timeStamp)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the delta of time between two times. The returned time is
|
* Creates a time representing the given decimal number of seconds. This
|
||||||
* equivalent to, but more convenient than, the following code:
|
* number is truncated to the milliseconds to prevent discrepencies
|
||||||
* {@code new Time(t1.getMilliseconds() - t2.getMilliseconds())}.
|
* resulting from successive calls to {@link System.currentTimeMillis()}
|
||||||
*
|
* and thus ensures that the compare method remains accurate.
|
||||||
* @param t1 the first time
|
*
|
||||||
* @param t2 the time to substract from the first
|
* @param seconds the number of seconds to represent
|
||||||
* @return the delta of time between the two times
|
*/
|
||||||
*/
|
public Time(double seconds) {
|
||||||
public static Time getDelta(Time t1, Time t2) {
|
this((long) (seconds * 1000.0));
|
||||||
if (t1 == null) {
|
}
|
||||||
t1 = new Time();
|
|
||||||
} else if (t2 == null) {
|
|
||||||
t2 = new Time();
|
|
||||||
}
|
|
||||||
return new Time(t1.milliseconds - t2.milliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the number of milliseconds represented by that time.
|
* Creates a time representing the given time-stamp. The time-stamp is a
|
||||||
*
|
* string describing the time in a format understandable by the user. The
|
||||||
* @return the number of milliseconds represented by that time
|
* time-stamp must be formatted according to the following:
|
||||||
*/
|
*
|
||||||
public long getMilliseconds() {
|
* <pre>((H)H:)((M)M:)(S)S(.T(H(M)))</pre>
|
||||||
return milliseconds;
|
*
|
||||||
}
|
* Where a letter represents a digit and parenthesis indicate optionality.
|
||||||
|
* H stands for hours, M for minutes, S for seconds, T for tenths, H for
|
||||||
/**
|
* hundredth and M for milliseconds.
|
||||||
* Adds the given time to this time. The number of milliseconds
|
*
|
||||||
* represented by this time object is now equals to:
|
* @param timestamp a string representation of the time to parse
|
||||||
* {@code getMilliseconds() + time.getMilliseconds()}
|
* @throws IllegalArgumentException if the timestamp cannot be parsed
|
||||||
*
|
*/
|
||||||
* @param time the time object to add to this time
|
public Time(String timeStamp) {
|
||||||
*/
|
try {
|
||||||
public void add(Time time) {
|
milliseconds = parseTimeStamp(timeStamp);
|
||||||
milliseconds += (time == null ? 0L : time.milliseconds);
|
} catch (Exception ex) {
|
||||||
}
|
throw new IllegalArgumentException(
|
||||||
|
Language.INVALID_TIME_STAMP.get(timeStamp)
|
||||||
public String toString(boolean signed, Accuracy accuracy) {
|
);
|
||||||
if (signed) {
|
}
|
||||||
return (milliseconds > 0L ? "+" : "-") + toString(false, accuracy);
|
}
|
||||||
}
|
|
||||||
long time = Math.abs(milliseconds);
|
|
||||||
long cen = (time % 1000L) / 10L;
|
|
||||||
long sec;
|
|
||||||
|
|
||||||
// Round to the nearest tenth.
|
|
||||||
if (accuracy == Accuracy.TENTH) {
|
|
||||||
cen = Math.round((double) cen / 10L);
|
|
||||||
if (cen == 10L) {
|
|
||||||
cen = 0L;
|
|
||||||
time = time + 1000L;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Round to the nearest second.
|
|
||||||
if (accuracy == Accuracy.SECONDS) {
|
|
||||||
sec = Math.round((double) time / 1000);
|
|
||||||
} else {
|
|
||||||
sec = time / 1000L;
|
|
||||||
}
|
|
||||||
long min = sec / 60L;
|
|
||||||
sec = sec % 60L;
|
|
||||||
long hou = min / 60L;
|
|
||||||
min = min % 60L;
|
|
||||||
|
|
||||||
if (hou == 0L) {
|
/**
|
||||||
if (min == 0L) {
|
* Returns the delta of time between two times. The returned time is
|
||||||
switch (accuracy) {
|
* equivalent to, but more convenient than, the following code:
|
||||||
case HUNDREDTH:
|
* {@code new Time(t1.getMilliseconds() - t2.getMilliseconds())}.
|
||||||
return String.format("%d.%02d", sec, cen);
|
*
|
||||||
case TENTH:
|
* @param t1 the first time
|
||||||
return String.format("%d.%d", sec, cen);
|
* @param t2 the time to substract from the first
|
||||||
case SECONDS:
|
* @return the delta of time between the two times
|
||||||
return String.format("%d", sec);
|
*/
|
||||||
}
|
public static Time getDelta(Time t1, Time t2) {
|
||||||
}
|
if (t1 == null) {
|
||||||
switch (accuracy) {
|
t1 = new Time();
|
||||||
case HUNDREDTH:
|
} else if (t2 == null) {
|
||||||
return String.format("%d:%02d.%02d", min, sec, cen);
|
t2 = new Time();
|
||||||
case TENTH:
|
}
|
||||||
return String.format("%d:%02d.%d", min, sec, cen);
|
return new Time(t1.milliseconds - t2.milliseconds);
|
||||||
case SECONDS:
|
}
|
||||||
return String.format("%d:%02d", min, sec);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch (accuracy) {
|
|
||||||
case HUNDREDTH:
|
|
||||||
return String.format("%d:%02d:%02d.%02d", hou, min, sec, cen);
|
|
||||||
case TENTH:
|
|
||||||
return String.format("%d:%02d:%02d.%d", hou, min, sec, cen);
|
|
||||||
case SECONDS:
|
|
||||||
return String.format("%d:%02d:%02d", hou, min, sec);
|
|
||||||
}
|
|
||||||
// Should not be reachable.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A time represents itself as a string using the traditional format
|
|
||||||
* {@code H:M:S}. The global accuracy determines the presence of tenths
|
|
||||||
* or hundredths of a second and if the get should be rounded. Every digit
|
|
||||||
* of higher-order than a second is only displayed if necessary. The sign
|
|
||||||
* parameter determines if the string should be preceded by a plus or minus
|
|
||||||
* sign depending on the number of milliseconds. If not, only the absolute
|
|
||||||
* number is used.
|
|
||||||
*
|
|
||||||
* @param signed if this time is to be displayed as a delta of time
|
|
||||||
* @return a string representation of this time object
|
|
||||||
*/
|
|
||||||
public String toString(boolean signed) {
|
|
||||||
return toString(signed, Settings.GNR_ACCY.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A time represents itself as a string using the traditional format
|
|
||||||
* {@code H:M:S}. The accuracy parameter determines the presence of tenths
|
|
||||||
* or hundredths of a second and if the get should be rounded. Every digit
|
|
||||||
* of higher-order than a second is only displayed if necessary.
|
|
||||||
*
|
|
||||||
* @param accuracy the target accuracy to display this time in
|
|
||||||
* @return a string representation of this time object
|
|
||||||
*/
|
|
||||||
public String toString(Accuracy accuracy) {
|
|
||||||
return toString(false, accuracy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A time represents itself as a string using the traditional format
|
|
||||||
* {@code H:M:S}. The accuracy setting determines the presence of tenths
|
|
||||||
* or hundredths of a second and if the get should be rounded. Every digit
|
|
||||||
* of higher-order than a second is only displayed if necessary.
|
|
||||||
*
|
|
||||||
* @return a string representation of this time object
|
|
||||||
*/
|
|
||||||
@Override public String toString() {
|
|
||||||
return toString(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc} Returns a deep-copy of this time object.
|
|
||||||
*/
|
|
||||||
@Override public Time clone() {
|
|
||||||
return new Time(milliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc} Two time objects are equal if and only if they represent
|
* Returns the number of milliseconds represented by that time.
|
||||||
* the same amount of milliseconds.
|
*
|
||||||
*/
|
* @return the number of milliseconds represented by that time
|
||||||
@Override public boolean equals(Object obj) {
|
*/
|
||||||
if (!(obj instanceof Time)) {
|
public long getMilliseconds() {
|
||||||
return false;
|
return milliseconds;
|
||||||
}
|
}
|
||||||
Time time = (Time) obj;
|
|
||||||
return (milliseconds == time.milliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc} The hash code of a time object is its number of
|
* Adds the given time to this time. The number of milliseconds
|
||||||
* milliseconds cast into an integer get. As such, the load factor of a
|
* represented by this time object is now equals to:
|
||||||
* table storing time objects is floored by {@code Integer#MAX_VALUE}.
|
* {@code getMilliseconds() + time.getMilliseconds()}
|
||||||
*/
|
*
|
||||||
@Override public int hashCode() {
|
* @param time the time object to add to this time
|
||||||
return (int) milliseconds;
|
*/
|
||||||
}
|
public void add(Time time) {
|
||||||
|
milliseconds += (time == null ? 0L : time.milliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
public String toString(boolean signed, Accuracy accuracy) {
|
||||||
* {@inheritDoc} Time objects are compared using their amount of
|
if (signed) {
|
||||||
* milliseconds
|
return (milliseconds > 0L ? "+" : "-") + toString(false, accuracy);
|
||||||
*/
|
}
|
||||||
@Override public int compareTo(Time time) {
|
long time = Math.abs(milliseconds);
|
||||||
if (time == null) {
|
long cen = (time % 1000L) / 10L;
|
||||||
return -1;
|
long sec;
|
||||||
}
|
|
||||||
return ((Long) milliseconds).compareTo(time.milliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Round to the nearest tenth.
|
||||||
* Parses a given time-stamp and converts it to a number of milliseconds.
|
if (accuracy == Accuracy.TENTH) {
|
||||||
*
|
cen = Math.round((double) cen / 10L);
|
||||||
* @param timestamp the timestamp to parse
|
if (cen == 10L) {
|
||||||
* @return the number of milliseconds represented by the stamp
|
cen = 0L;
|
||||||
*/
|
time = time + 1000L;
|
||||||
private long parseTimeStamp(String timestamp) {
|
}
|
||||||
String seconds = timestamp;
|
}
|
||||||
long millis = 0L;
|
|
||||||
|
|
||||||
// Hours or minutes in the stamp.
|
// Round to the nearest second.
|
||||||
if (timestamp.contains(":")) {
|
if (accuracy == Accuracy.SECONDS) {
|
||||||
String[] split = timestamp.split(":");
|
sec = Math.round((double) time / 1000);
|
||||||
if (split.length > 3) {
|
} else {
|
||||||
throw new IllegalArgumentException();
|
sec = time / 1000L;
|
||||||
}
|
}
|
||||||
// We keep the number of seconds and lower for later.
|
long min = sec / 60L;
|
||||||
seconds = split[split.length - 1];
|
sec = sec % 60L;
|
||||||
|
long hou = min / 60L;
|
||||||
|
min = min % 60L;
|
||||||
|
|
||||||
for (int i = 0; i < split.length - 1; i++) {
|
if (hou == 0L) {
|
||||||
long power = (long) Math.pow(60, split.length - i - 1);
|
if (min == 0L) {
|
||||||
millis += Long.valueOf(split[i]) * power * 1000L;
|
switch (accuracy) {
|
||||||
}
|
case HUNDREDTH:
|
||||||
}
|
return String.format("%d.%02d", sec, cen);
|
||||||
double value = Double.parseDouble(seconds);
|
case TENTH:
|
||||||
return (millis + (long) (value * 1000.0));
|
return String.format("%d.%d", sec, cen);
|
||||||
}
|
case SECONDS:
|
||||||
|
return String.format("%d", sec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (accuracy) {
|
||||||
|
case HUNDREDTH:
|
||||||
|
return String.format("%d:%02d.%02d", min, sec, cen);
|
||||||
|
case TENTH:
|
||||||
|
return String.format("%d:%02d.%d", min, sec, cen);
|
||||||
|
case SECONDS:
|
||||||
|
return String.format("%d:%02d", min, sec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (accuracy) {
|
||||||
|
case HUNDREDTH:
|
||||||
|
return String.format("%d:%02d:%02d.%02d", hou, min, sec, cen);
|
||||||
|
case TENTH:
|
||||||
|
return String.format("%d:%02d:%02d.%d", hou, min, sec, cen);
|
||||||
|
case SECONDS:
|
||||||
|
return String.format("%d:%02d:%02d", hou, min, sec);
|
||||||
|
}
|
||||||
|
// Should not be reachable.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A time represents itself as a string using the traditional format
|
||||||
|
* {@code H:M:S}. The global accuracy determines the presence of tenths
|
||||||
|
* or hundredths of a second and if the get should be rounded. Every digit
|
||||||
|
* of higher-order than a second is only displayed if necessary. The sign
|
||||||
|
* parameter determines if the string should be preceded by a plus or minus
|
||||||
|
* sign depending on the number of milliseconds. If not, only the absolute
|
||||||
|
* number is used.
|
||||||
|
*
|
||||||
|
* @param signed if this time is to be displayed as a delta of time
|
||||||
|
* @return a string representation of this time object
|
||||||
|
*/
|
||||||
|
public String toString(boolean signed) {
|
||||||
|
return toString(signed, Settings.GNR_ACCY.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A time represents itself as a string using the traditional format
|
||||||
|
* {@code H:M:S}. The accuracy parameter determines the presence of tenths
|
||||||
|
* or hundredths of a second and if the get should be rounded. Every digit
|
||||||
|
* of higher-order than a second is only displayed if necessary.
|
||||||
|
*
|
||||||
|
* @param accuracy the target accuracy to display this time in
|
||||||
|
* @return a string representation of this time object
|
||||||
|
*/
|
||||||
|
public String toString(Accuracy accuracy) {
|
||||||
|
return toString(false, accuracy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A time represents itself as a string using the traditional format
|
||||||
|
* {@code H:M:S}. The accuracy setting determines the presence of tenths
|
||||||
|
* or hundredths of a second and if the get should be rounded. Every digit
|
||||||
|
* of higher-order than a second is only displayed if necessary.
|
||||||
|
*
|
||||||
|
* @return a string representation of this time object
|
||||||
|
*/
|
||||||
|
@Override public String toString() {
|
||||||
|
return toString(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc} Returns a deep-copy of this time object.
|
||||||
|
*/
|
||||||
|
@Override public Time clone() {
|
||||||
|
return new Time(milliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc} Two time objects are equal if and only if they represent
|
||||||
|
* the same amount of milliseconds.
|
||||||
|
*/
|
||||||
|
@Override public boolean equals(Object obj) {
|
||||||
|
if (!(obj instanceof Time)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Time time = (Time) obj;
|
||||||
|
return (milliseconds == time.milliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc} The hash code of a time object is its number of
|
||||||
|
* milliseconds cast into an integer get. As such, the load factor of a
|
||||||
|
* table storing time objects is floored by {@code Integer#MAX_VALUE}.
|
||||||
|
*/
|
||||||
|
@Override public int hashCode() {
|
||||||
|
return (int) milliseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc} Time objects are compared using their amount of
|
||||||
|
* milliseconds
|
||||||
|
*/
|
||||||
|
@Override public int compareTo(Time time) {
|
||||||
|
if (time == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ((Long) milliseconds).compareTo(time.milliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a given time-stamp and converts it to a number of milliseconds.
|
||||||
|
*
|
||||||
|
* @param timestamp the timestamp to parse
|
||||||
|
* @return the number of milliseconds represented by the stamp
|
||||||
|
*/
|
||||||
|
private long parseTimeStamp(String timestamp) {
|
||||||
|
String seconds = timestamp;
|
||||||
|
long millis = 0L;
|
||||||
|
|
||||||
|
// Hours or minutes in the stamp.
|
||||||
|
if (timestamp.contains(":")) {
|
||||||
|
String[] split = timestamp.split(":");
|
||||||
|
if (split.length > 3) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
// We keep the number of seconds and lower for later.
|
||||||
|
seconds = split[split.length - 1];
|
||||||
|
|
||||||
|
for (int i = 0; i < split.length - 1; i++) {
|
||||||
|
long power = (long) Math.pow(60, split.length - i - 1);
|
||||||
|
millis += Long.valueOf(split[i]) * power * 1000L;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double value = Double.parseDouble(seconds);
|
||||||
|
return (millis + (long) (value * 1000.0));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,21 @@
|
||||||
package org.fenix.llanfair.config;
|
package org.fenix.llanfair.config;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import org.fenix.llanfair.Language;
|
import org.fenix.llanfair.Language;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
|
||||||
public enum Accuracy implements Serializable {
|
public enum Accuracy implements Serializable {
|
||||||
|
|
||||||
SECONDS,
|
|
||||||
TENTH,
|
|
||||||
HUNDREDTH;
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1000L;
|
|
||||||
|
|
||||||
@Override public String toString() {
|
SECONDS,
|
||||||
return Language.valueOf("accuracy_" + name().toLowerCase()).get();
|
TENTH,
|
||||||
}
|
HUNDREDTH;
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1000L;
|
||||||
|
|
||||||
|
@Override public String toString() {
|
||||||
|
return Language.valueOf("accuracy_" + name().toLowerCase()).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,23 @@
|
||||||
package org.fenix.llanfair.config;
|
package org.fenix.llanfair.config;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import org.fenix.llanfair.Language;
|
import org.fenix.llanfair.Language;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Xavier
|
* @author Xavier
|
||||||
*/
|
*/
|
||||||
public enum Compare implements Serializable {
|
public enum Compare implements Serializable {
|
||||||
|
|
||||||
BEST_OVERALL_RUN,
|
BEST_OVERALL_RUN,
|
||||||
SUM_OF_BEST_SEGMENTS;
|
SUM_OF_BEST_SEGMENTS;
|
||||||
|
|
||||||
private static final long serialVersionUID = 1000L;
|
private static final long serialVersionUID = 1000L;
|
||||||
|
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
return Language.valueOf(
|
return Language.valueOf(
|
||||||
"compare_" + name().toLowerCase().replaceAll("\\.", "_")
|
"compare_" + name().toLowerCase().replaceAll("\\.", "_")
|
||||||
).get();
|
).get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,22 @@
|
||||||
package org.fenix.llanfair.config;
|
package org.fenix.llanfair.config;
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import org.fenix.llanfair.Language;
|
import org.fenix.llanfair.Language;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Xavier
|
* @author Xavier
|
||||||
*/
|
*/
|
||||||
public enum Merge implements Serializable {
|
public enum Merge implements Serializable {
|
||||||
|
|
||||||
NONE,
|
NONE,
|
||||||
LIVE,
|
LIVE,
|
||||||
DELTA;
|
DELTA;
|
||||||
|
|
||||||
private static final long serialVersionUID = 1000L;
|
private static final long serialVersionUID = 1000L;
|
||||||
|
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
return Language.valueOf("merge_" + name().toLowerCase()).get();
|
return Language.valueOf("merge_" + name().toLowerCase()).get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,403 +26,403 @@ import org.fenix.utils.config.Configuration;
|
||||||
* @version 1.3
|
* @version 1.3
|
||||||
*/
|
*/
|
||||||
public class Settings {
|
public class Settings {
|
||||||
|
|
||||||
/* GENERIC properties */
|
|
||||||
|
|
||||||
public static final Property<Boolean> GNR_ATOP =
|
|
||||||
new Property<Boolean>( "alwaysOnTop" );
|
|
||||||
public static final Property<Locale> GNR_LANG =
|
|
||||||
new Property<Locale>( "language" );
|
|
||||||
public static final Property<Locale> GNR_VLNG =
|
|
||||||
new Property<Locale>( "viewerLanguage" );
|
|
||||||
public static final Property<List<String>> GNR_RCNT =
|
|
||||||
new Property<List<String>>( "recentFiles" );
|
|
||||||
public static final Property<Point> GNR_COOR =
|
|
||||||
new Property<Point>( "coordinates" );
|
|
||||||
public static final Property<Dimension> GNR_SIZE =
|
|
||||||
new Property<Dimension>( "dimension" );
|
|
||||||
public static final Property<Compare> GNR_COMP =
|
|
||||||
new Property<Compare>( "compareMethod" );
|
|
||||||
public static final Property<Accuracy> GNR_ACCY =
|
|
||||||
new Property<Accuracy>( "accuracy" );
|
|
||||||
public static final Property<Boolean> GNR_WARN =
|
|
||||||
new Property<Boolean>( "warnOnReset" );
|
|
||||||
|
|
||||||
/* COLOR properties */
|
|
||||||
|
|
||||||
public static final Property<Color> CLR_BACK =
|
|
||||||
new Property<Color>( "color.background" );
|
|
||||||
public static final Property<Color> CLR_FORE =
|
|
||||||
new Property<Color>( "color.foreground" );
|
|
||||||
public static final Property<Color> CLR_TIME =
|
|
||||||
new Property<Color>( "color.time" );
|
|
||||||
public static final Property<Color> CLR_TIMR =
|
|
||||||
new Property<Color>( "color.timer" );
|
|
||||||
public static final Property<Color> CLR_GAIN =
|
|
||||||
new Property<Color>( "color.timeGained" );
|
|
||||||
public static final Property<Color> CLR_LOST =
|
|
||||||
new Property<Color>( "color.timeLost" );
|
|
||||||
public static final Property<Color> CLR_RCRD =
|
|
||||||
new Property<Color>( "color.newRecord" );
|
|
||||||
public static final Property<Color> CLR_TITL =
|
|
||||||
new Property<Color>( "color.title" );
|
|
||||||
public static final Property<Color> CLR_HIGH =
|
|
||||||
new Property<Color>( "color.highlight" );
|
|
||||||
public static final Property<Color> CLR_SPRT =
|
|
||||||
new Property<Color>( "color.separators" );
|
|
||||||
|
|
||||||
/* HOTKEY properties */
|
|
||||||
|
|
||||||
public static final Property<Integer> KEY_SPLT =
|
|
||||||
new Property<Integer>( "hotkey.split" );
|
|
||||||
public static final Property<Integer> KEY_USPL =
|
|
||||||
new Property<Integer>( "hotkey.unsplit" );
|
|
||||||
public static final Property<Integer> KEY_SKIP =
|
|
||||||
new Property<Integer>( "hotkey.skip" );
|
|
||||||
public static final Property<Integer> KEY_RSET =
|
|
||||||
new Property<Integer>( "hotkey.reset" );
|
|
||||||
public static final Property<Integer> KEY_STOP =
|
|
||||||
new Property<Integer>( "hotkey.stop" );
|
|
||||||
public static final Property<Integer> KEY_PAUS =
|
|
||||||
new Property<Integer>( "hotkey.pause" );
|
|
||||||
public static final Property<Integer> KEY_LOCK =
|
|
||||||
new Property<Integer>( "hotkey.lock" );
|
|
||||||
|
|
||||||
/* HEADER properties */
|
|
||||||
|
|
||||||
public static final Property<Boolean> HDR_TTLE =
|
|
||||||
new Property<Boolean>( "header.goal" );
|
|
||||||
public static final Property<Boolean> HDR_GOAL =
|
|
||||||
new Property<Boolean>( "header.title" );
|
|
||||||
|
|
||||||
/* HISTORY properties */
|
|
||||||
|
|
||||||
public static final Property<Integer> HST_ROWS =
|
|
||||||
new Property<Integer>( "history.rowCount" );
|
|
||||||
public static final Property<Boolean> HST_TABL =
|
|
||||||
new Property<Boolean>( "history.tabular" );
|
|
||||||
public static final Property<Boolean> HST_BLNK =
|
|
||||||
new Property<Boolean>( "history.blankRows" );
|
|
||||||
public static final Property<Boolean> HST_LINE =
|
|
||||||
new Property<Boolean>( "history.multiline" );
|
|
||||||
public static final Property<Merge> HST_MERG =
|
|
||||||
new Property<Merge>( "history.merge" );
|
|
||||||
public static final Property<Boolean> HST_LIVE =
|
|
||||||
new Property<Boolean>( "history.liveTimes" );
|
|
||||||
public static final Property<Boolean> HST_DLTA =
|
|
||||||
new Property<Boolean>( "history.deltas" );
|
|
||||||
public static final Property<Boolean> HST_ICON =
|
|
||||||
new Property<Boolean>( "history.icons" );
|
|
||||||
public static final Property<Integer> HST_ICSZ =
|
|
||||||
new Property<Integer>( "history.iconSize" );
|
|
||||||
public static final Property<Integer> HST_OFFS =
|
|
||||||
new Property<Integer>( "history.offset" );
|
|
||||||
public static final Property<Boolean> HST_LAST =
|
|
||||||
new Property<Boolean>( "history.alwaysShowLast" );
|
|
||||||
public static final Property<Font> HST_SFNT =
|
|
||||||
new Property<Font>( "history.segmentFont" );
|
|
||||||
public static final Property<Font> HST_TFNT =
|
|
||||||
new Property<Font>( "history.timeFont" );
|
|
||||||
|
|
||||||
/* CORE properties */
|
|
||||||
|
|
||||||
public static final Property<Accuracy> COR_ACCY =
|
|
||||||
new Property<Accuracy>( "core.accuracy" );
|
|
||||||
public static final Property<Boolean> COR_ICON =
|
|
||||||
new Property<Boolean>( "core.icons" );
|
|
||||||
public static final Property<Integer> COR_ICSZ =
|
|
||||||
new Property<Integer>( "core.iconSize" );
|
|
||||||
public static final Property<Boolean> COR_NAME =
|
|
||||||
new Property<Boolean>( "core.segmentName" );
|
|
||||||
public static final Property<Boolean> COR_SPLT =
|
|
||||||
new Property<Boolean>( "core.splitTime" );
|
|
||||||
public static final Property<Boolean> COR_SEGM =
|
|
||||||
new Property<Boolean>( "core.segmentTime" );
|
|
||||||
public static final Property<Boolean> COR_BEST =
|
|
||||||
new Property<Boolean>( "core.bestTime" );
|
|
||||||
public static final Property<Boolean> COR_STMR =
|
|
||||||
new Property<Boolean>( "core.segmentTimer" );
|
|
||||||
public static final Property<Font> COR_TFNT =
|
|
||||||
new Property<Font>( "core.timerFont" );
|
|
||||||
public static final Property<Font> COR_SFNT =
|
|
||||||
new Property<Font>( "core.segmentTimerFont" );
|
|
||||||
|
|
||||||
/* GRAPH properties */
|
|
||||||
|
|
||||||
public static final Property<Boolean> GPH_SHOW =
|
|
||||||
new Property<Boolean>( "graph.display" );
|
|
||||||
public static final Property<Float> GPH_SCAL =
|
|
||||||
new Property<Float>( "graph.scale" );
|
|
||||||
|
|
||||||
/* FOOTER properties */
|
|
||||||
|
|
||||||
public static final Property<Boolean> FOO_SHOW =
|
|
||||||
new Property<Boolean>( "footer.display" );
|
|
||||||
public static final Property<Boolean> FOO_SPLT =
|
|
||||||
new Property<Boolean>( "footer.useSplitData" );
|
|
||||||
public static final Property<Boolean> FOO_VERB =
|
|
||||||
new Property<Boolean>( "footer.verbose" );
|
|
||||||
public static final Property<Boolean> FOO_BEST =
|
|
||||||
new Property<Boolean>( "footer.bestTime" );
|
|
||||||
public static final Property<Boolean> FOO_LINE =
|
|
||||||
new Property<Boolean>( "footer.multiline" );
|
|
||||||
public static final Property<Boolean> FOO_DLBL =
|
|
||||||
new Property<Boolean>( "footer.deltaLabels" );
|
|
||||||
|
|
||||||
private static Configuration global = null;
|
/* GENERIC properties */
|
||||||
private static Run run = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the currently opened run. The run will be asked for its local
|
|
||||||
* configuration first when retrieving a property. If the run does not have
|
|
||||||
* the given property its value will be taken from the global configuration.
|
|
||||||
*
|
|
||||||
* @param run the run currently viewed by Llanfair, cannot be {@code null}
|
|
||||||
*/
|
|
||||||
public static void setRun( Run run ) {
|
|
||||||
if ( run == null ) {
|
|
||||||
throw new NullPointerException( "Null run" );
|
|
||||||
}
|
|
||||||
Settings.run = run;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
public static final Property<Boolean> GNR_ATOP =
|
||||||
* Returns a list of all the properties whose key starts with the given
|
new Property<Boolean>( "alwaysOnTop" );
|
||||||
* prefix. If given an empty string, every properties are returned.
|
public static final Property<Locale> GNR_LANG =
|
||||||
*
|
new Property<Locale>( "language" );
|
||||||
* @param prefix the prefix for which a list of property is asked
|
public static final Property<Locale> GNR_VLNG =
|
||||||
* @return the list of all properties whose key starts with the prefix
|
new Property<Locale>( "viewerLanguage" );
|
||||||
*/
|
public static final Property<List<String>> GNR_RCNT =
|
||||||
public static List<Property<?>> getAll( String prefix ) {
|
new Property<List<String>>( "recentFiles" );
|
||||||
if ( prefix == null ) {
|
public static final Property<Point> GNR_COOR =
|
||||||
throw new NullPointerException( "Null prefix string" );
|
new Property<Point>( "coordinates" );
|
||||||
}
|
public static final Property<Dimension> GNR_SIZE =
|
||||||
List<Property<?>> list = new ArrayList<Property<?>>();
|
new Property<Dimension>( "dimension" );
|
||||||
for ( Property<?> property : Property.P ) {
|
public static final Property<Compare> GNR_COMP =
|
||||||
if ( property.key.startsWith( prefix ) ) {
|
new Property<Compare>( "compareMethod" );
|
||||||
list.add( property );
|
public static final Property<Accuracy> GNR_ACCY =
|
||||||
}
|
new Property<Accuracy>( "accuracy" );
|
||||||
}
|
public static final Property<Boolean> GNR_WARN =
|
||||||
return list;
|
new Property<Boolean>( "warnOnReset" );
|
||||||
}
|
|
||||||
|
/* COLOR properties */
|
||||||
|
|
||||||
|
public static final Property<Color> CLR_BACK =
|
||||||
|
new Property<Color>( "color.background" );
|
||||||
|
public static final Property<Color> CLR_FORE =
|
||||||
|
new Property<Color>( "color.foreground" );
|
||||||
|
public static final Property<Color> CLR_TIME =
|
||||||
|
new Property<Color>( "color.time" );
|
||||||
|
public static final Property<Color> CLR_TIMR =
|
||||||
|
new Property<Color>( "color.timer" );
|
||||||
|
public static final Property<Color> CLR_GAIN =
|
||||||
|
new Property<Color>( "color.timeGained" );
|
||||||
|
public static final Property<Color> CLR_LOST =
|
||||||
|
new Property<Color>( "color.timeLost" );
|
||||||
|
public static final Property<Color> CLR_RCRD =
|
||||||
|
new Property<Color>( "color.newRecord" );
|
||||||
|
public static final Property<Color> CLR_TITL =
|
||||||
|
new Property<Color>( "color.title" );
|
||||||
|
public static final Property<Color> CLR_HIGH =
|
||||||
|
new Property<Color>( "color.highlight" );
|
||||||
|
public static final Property<Color> CLR_SPRT =
|
||||||
|
new Property<Color>( "color.separators" );
|
||||||
|
|
||||||
|
/* HOTKEY properties */
|
||||||
|
|
||||||
|
public static final Property<Integer> KEY_SPLT =
|
||||||
|
new Property<Integer>( "hotkey.split" );
|
||||||
|
public static final Property<Integer> KEY_USPL =
|
||||||
|
new Property<Integer>( "hotkey.unsplit" );
|
||||||
|
public static final Property<Integer> KEY_SKIP =
|
||||||
|
new Property<Integer>( "hotkey.skip" );
|
||||||
|
public static final Property<Integer> KEY_RSET =
|
||||||
|
new Property<Integer>( "hotkey.reset" );
|
||||||
|
public static final Property<Integer> KEY_STOP =
|
||||||
|
new Property<Integer>( "hotkey.stop" );
|
||||||
|
public static final Property<Integer> KEY_PAUS =
|
||||||
|
new Property<Integer>( "hotkey.pause" );
|
||||||
|
public static final Property<Integer> KEY_LOCK =
|
||||||
|
new Property<Integer>( "hotkey.lock" );
|
||||||
|
|
||||||
|
/* HEADER properties */
|
||||||
|
|
||||||
|
public static final Property<Boolean> HDR_TTLE =
|
||||||
|
new Property<Boolean>( "header.goal" );
|
||||||
|
public static final Property<Boolean> HDR_GOAL =
|
||||||
|
new Property<Boolean>( "header.title" );
|
||||||
|
|
||||||
|
/* HISTORY properties */
|
||||||
|
|
||||||
|
public static final Property<Integer> HST_ROWS =
|
||||||
|
new Property<Integer>( "history.rowCount" );
|
||||||
|
public static final Property<Boolean> HST_TABL =
|
||||||
|
new Property<Boolean>( "history.tabular" );
|
||||||
|
public static final Property<Boolean> HST_BLNK =
|
||||||
|
new Property<Boolean>( "history.blankRows" );
|
||||||
|
public static final Property<Boolean> HST_LINE =
|
||||||
|
new Property<Boolean>( "history.multiline" );
|
||||||
|
public static final Property<Merge> HST_MERG =
|
||||||
|
new Property<Merge>( "history.merge" );
|
||||||
|
public static final Property<Boolean> HST_LIVE =
|
||||||
|
new Property<Boolean>( "history.liveTimes" );
|
||||||
|
public static final Property<Boolean> HST_DLTA =
|
||||||
|
new Property<Boolean>( "history.deltas" );
|
||||||
|
public static final Property<Boolean> HST_ICON =
|
||||||
|
new Property<Boolean>( "history.icons" );
|
||||||
|
public static final Property<Integer> HST_ICSZ =
|
||||||
|
new Property<Integer>( "history.iconSize" );
|
||||||
|
public static final Property<Integer> HST_OFFS =
|
||||||
|
new Property<Integer>( "history.offset" );
|
||||||
|
public static final Property<Boolean> HST_LAST =
|
||||||
|
new Property<Boolean>( "history.alwaysShowLast" );
|
||||||
|
public static final Property<Font> HST_SFNT =
|
||||||
|
new Property<Font>( "history.segmentFont" );
|
||||||
|
public static final Property<Font> HST_TFNT =
|
||||||
|
new Property<Font>( "history.timeFont" );
|
||||||
|
|
||||||
|
/* CORE properties */
|
||||||
|
|
||||||
|
public static final Property<Accuracy> COR_ACCY =
|
||||||
|
new Property<Accuracy>( "core.accuracy" );
|
||||||
|
public static final Property<Boolean> COR_ICON =
|
||||||
|
new Property<Boolean>( "core.icons" );
|
||||||
|
public static final Property<Integer> COR_ICSZ =
|
||||||
|
new Property<Integer>( "core.iconSize" );
|
||||||
|
public static final Property<Boolean> COR_NAME =
|
||||||
|
new Property<Boolean>( "core.segmentName" );
|
||||||
|
public static final Property<Boolean> COR_SPLT =
|
||||||
|
new Property<Boolean>( "core.splitTime" );
|
||||||
|
public static final Property<Boolean> COR_SEGM =
|
||||||
|
new Property<Boolean>( "core.segmentTime" );
|
||||||
|
public static final Property<Boolean> COR_BEST =
|
||||||
|
new Property<Boolean>( "core.bestTime" );
|
||||||
|
public static final Property<Boolean> COR_STMR =
|
||||||
|
new Property<Boolean>( "core.segmentTimer" );
|
||||||
|
public static final Property<Font> COR_TFNT =
|
||||||
|
new Property<Font>( "core.timerFont" );
|
||||||
|
public static final Property<Font> COR_SFNT =
|
||||||
|
new Property<Font>( "core.segmentTimerFont" );
|
||||||
|
|
||||||
|
/* GRAPH properties */
|
||||||
|
|
||||||
|
public static final Property<Boolean> GPH_SHOW =
|
||||||
|
new Property<Boolean>( "graph.display" );
|
||||||
|
public static final Property<Float> GPH_SCAL =
|
||||||
|
new Property<Float>( "graph.scale" );
|
||||||
|
|
||||||
|
/* FOOTER properties */
|
||||||
|
|
||||||
|
public static final Property<Boolean> FOO_SHOW =
|
||||||
|
new Property<Boolean>( "footer.display" );
|
||||||
|
public static final Property<Boolean> FOO_SPLT =
|
||||||
|
new Property<Boolean>( "footer.useSplitData" );
|
||||||
|
public static final Property<Boolean> FOO_VERB =
|
||||||
|
new Property<Boolean>( "footer.verbose" );
|
||||||
|
public static final Property<Boolean> FOO_BEST =
|
||||||
|
new Property<Boolean>( "footer.bestTime" );
|
||||||
|
public static final Property<Boolean> FOO_LINE =
|
||||||
|
new Property<Boolean>( "footer.multiline" );
|
||||||
|
public static final Property<Boolean> FOO_DLBL =
|
||||||
|
new Property<Boolean>( "footer.deltaLabels" );
|
||||||
|
|
||||||
|
private static Configuration global = null;
|
||||||
|
private static Run run = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the currently opened run. The run will be asked for its local
|
||||||
|
* configuration first when retrieving a property. If the run does not have
|
||||||
|
* the given property its value will be taken from the global configuration.
|
||||||
|
*
|
||||||
|
* @param run the run currently viewed by Llanfair, cannot be {@code null}
|
||||||
|
*/
|
||||||
|
public static void setRun( Run run ) {
|
||||||
|
if ( run == null ) {
|
||||||
|
throw new NullPointerException( "Null run" );
|
||||||
|
}
|
||||||
|
Settings.run = run;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of all the properties whose key starts with the given
|
||||||
|
* prefix. If given an empty string, every properties are returned.
|
||||||
|
*
|
||||||
|
* @param prefix the prefix for which a list of property is asked
|
||||||
|
* @return the list of all properties whose key starts with the prefix
|
||||||
|
*/
|
||||||
|
public static List<Property<?>> getAll( String prefix ) {
|
||||||
|
if ( prefix == null ) {
|
||||||
|
throw new NullPointerException( "Null prefix string" );
|
||||||
|
}
|
||||||
|
List<Property<?>> list = new ArrayList<Property<?>>();
|
||||||
|
for ( Property<?> property : Property.P ) {
|
||||||
|
if ( property.key.startsWith( prefix ) ) {
|
||||||
|
list.add( property );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a new {@code PropertyChangeListener} with the settings.
|
* Registers a new {@code PropertyChangeListener} with the settings.
|
||||||
* Whenever a property sees its value updated globally or locally, listeners
|
* Whenever a property sees its value updated globally or locally, listeners
|
||||||
* are warned of the update.
|
* are warned of the update.
|
||||||
*
|
*
|
||||||
* @param pcl the listener to register with the settings
|
* @param pcl the listener to register with the settings
|
||||||
*/
|
*/
|
||||||
public static void addPropertyChangeListener( PropertyChangeListener pcl ) {
|
public static void addPropertyChangeListener( PropertyChangeListener pcl ) {
|
||||||
if ( pcl == null ) {
|
if ( pcl == null ) {
|
||||||
throw new NullPointerException( "Null property listener" );
|
throw new NullPointerException( "Null property listener" );
|
||||||
}
|
}
|
||||||
global.addPropertyChangeListener( pcl );
|
global.addPropertyChangeListener( pcl );
|
||||||
if ( run != null ) {
|
if ( run != null ) {
|
||||||
run.addSettingChangeListener( pcl );
|
run.addSettingChangeListener( pcl );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves the global configuration in {@code llanfair.xml} in the working
|
* Saves the global configuration in {@code llanfair.xml} in the working
|
||||||
* directory. If such a file does not exist, it is created.
|
* directory. If such a file does not exist, it is created.
|
||||||
*/
|
*/
|
||||||
public static void save() {
|
public static void save() {
|
||||||
global.serialize();
|
global.serialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the configuration of Llanfair. The configuration is read from
|
|
||||||
* {@code llanfair.xml} placed in the working directory. If such a file
|
|
||||||
* cannot be found, a default configuration is loaded. No local
|
|
||||||
* configuration is loaded here, a call to {@code setRun} is required to
|
|
||||||
* do just that. This method is lenient and called by the first property
|
|
||||||
* whose value is requested.
|
|
||||||
*/
|
|
||||||
private static void retrieve() {
|
|
||||||
global = Configuration.newInstance( new File( "./llanfair.xml" ) );
|
|
||||||
if ( global.isEmpty() ) {
|
|
||||||
setDefaultValues();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fills the global configuration with every property, assigning them their
|
* Retrieves the configuration of Llanfair. The configuration is read from
|
||||||
* default value. This method can be called even when the global
|
* {@code llanfair.xml} placed in the working directory. If such a file
|
||||||
* configuration is not empty, and will thus function as a reset.
|
* cannot be found, a default configuration is loaded. No local
|
||||||
*/
|
* configuration is loaded here, a call to {@code setRun} is required to
|
||||||
private static void setDefaultValues() {
|
* do just that. This method is lenient and called by the first property
|
||||||
global.put( GNR_ATOP.key, true );
|
* whose value is requested.
|
||||||
global.put( GNR_LANG.key, Locale.ENGLISH );
|
*/
|
||||||
global.put( GNR_VLNG.key, Locale.ENGLISH );
|
private static void retrieve() {
|
||||||
global.put( GNR_RCNT.key, new ArrayList<String>() );
|
global = Configuration.newInstance( new File( "./llanfair.xml" ) );
|
||||||
global.put( GNR_COOR.key, null );
|
if ( global.isEmpty() ) {
|
||||||
global.put( GNR_SIZE.key, null );
|
setDefaultValues();
|
||||||
global.put( GNR_COMP.key, Compare.BEST_OVERALL_RUN );
|
}
|
||||||
global.put( GNR_ACCY.key, Accuracy.TENTH );
|
}
|
||||||
global.put( GNR_WARN.key, true );
|
|
||||||
|
|
||||||
global.put( CLR_BACK.key, Color.decode( "0x000000" ) );
|
|
||||||
global.put( CLR_FORE.key, Color.decode( "0xc0c0c0" ) );
|
|
||||||
global.put( CLR_TIME.key, Color.decode( "0xffffff" ) );
|
|
||||||
global.put( CLR_TIMR.key, Color.decode( "0x22cc22" ) );
|
|
||||||
global.put( CLR_GAIN.key, Color.decode( "0x6295fc" ) );
|
|
||||||
global.put( CLR_LOST.key, Color.decode( "0xe82323" ) );
|
|
||||||
global.put( CLR_RCRD.key, Color.decode( "0xf0b012" ) );
|
|
||||||
global.put( CLR_TITL.key, Color.decode( "0xf0b012" ) );
|
|
||||||
global.put( CLR_HIGH.key, Color.decode( "0xffffff" ) );
|
|
||||||
global.put( CLR_SPRT.key, Color.decode( "0x666666" ) );
|
|
||||||
|
|
||||||
global.put( KEY_SPLT.key, -1 );
|
|
||||||
global.put( KEY_USPL.key, -1 );
|
|
||||||
global.put( KEY_SKIP.key, -1 );
|
|
||||||
global.put( KEY_RSET.key, -1 );
|
|
||||||
global.put( KEY_STOP.key, -1 );
|
|
||||||
global.put( KEY_PAUS.key, -1 );
|
|
||||||
global.put( KEY_LOCK.key, -1 );
|
|
||||||
|
|
||||||
global.put( HDR_TTLE.key, true );
|
|
||||||
global.put( HDR_GOAL.key, true );
|
|
||||||
|
|
||||||
global.put( HST_ROWS.key, 8 );
|
|
||||||
global.put( HST_TABL.key, true );
|
|
||||||
global.put( HST_BLNK.key, false );
|
|
||||||
global.put( HST_LINE.key, false );
|
|
||||||
global.put( HST_MERG.key, Merge.LIVE );
|
|
||||||
global.put( HST_LIVE.key, true );
|
|
||||||
global.put( HST_DLTA.key, true );
|
|
||||||
global.put( HST_ICON.key, true );
|
|
||||||
global.put( HST_ICSZ.key, 16 );
|
|
||||||
global.put( HST_OFFS.key, 0 );
|
|
||||||
global.put( HST_LAST.key, true );
|
|
||||||
global.put( HST_SFNT.key, Font.decode( "Arial-12" ) );
|
|
||||||
global.put( HST_TFNT.key, Font.decode( "Arial-11" ) );
|
|
||||||
|
|
||||||
global.put( COR_ACCY.key, Accuracy.HUNDREDTH );
|
|
||||||
global.put( COR_ICON.key, true );
|
|
||||||
global.put( COR_ICSZ.key, 40 );
|
|
||||||
global.put( COR_NAME.key, true );
|
|
||||||
global.put( COR_SPLT.key, false );
|
|
||||||
global.put( COR_SEGM.key, true );
|
|
||||||
global.put( COR_BEST.key, true );
|
|
||||||
global.put( COR_STMR.key, true );
|
|
||||||
global.put( COR_TFNT.key, Font.decode( "Digitalism-32" ) );
|
|
||||||
global.put( COR_SFNT.key, Font.decode( "Digitalism-18" ) );
|
|
||||||
|
|
||||||
global.put( GPH_SHOW.key, true );
|
|
||||||
global.put( GPH_SCAL.key, 3.0F );
|
|
||||||
|
|
||||||
global.put( FOO_SHOW.key, true );
|
|
||||||
global.put( FOO_VERB.key, true );
|
|
||||||
global.put( FOO_SPLT.key, false );
|
|
||||||
global.put( FOO_BEST.key, true );
|
|
||||||
global.put( FOO_LINE.key, true );
|
|
||||||
global.put( FOO_DLBL.key, true );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Polymorphic property object. It is merely a string identifying the
|
|
||||||
* property and serving as an interface to the configuration. When asked
|
|
||||||
* for its value, the property will return the global value unless a local
|
|
||||||
* value has been defined. Will return a statically typecasted value.
|
|
||||||
*
|
|
||||||
* @param <T> the type of the values of the property
|
|
||||||
* @author Xavier "Xunkar" Sencert
|
|
||||||
* @version 1.0
|
|
||||||
*/
|
|
||||||
public static class Property<T> {
|
|
||||||
|
|
||||||
private static final List<Property<?>> P = new ArrayList<Property<?>>();
|
|
||||||
|
|
||||||
private String key;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new property of given key. If the key contains a dot, the
|
|
||||||
* property name is interpreted as {@code section.key} allowing callers
|
|
||||||
* to grab a submap of the configuration with all properties starting
|
|
||||||
* with {@code section}.
|
|
||||||
*
|
|
||||||
* @param fullKey the name of the property
|
|
||||||
*/
|
|
||||||
private Property( String fullKey ) {
|
|
||||||
this.key = fullKey;
|
|
||||||
P.add( this );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the key string of this property.
|
* Fills the global configuration with every property, assigning them their
|
||||||
*
|
* default value. This method can be called even when the global
|
||||||
* @return the key string of this property
|
* configuration is not empty, and will thus function as a reset.
|
||||||
*/
|
*/
|
||||||
public String getKey() {
|
private static void setDefaultValues() {
|
||||||
return key;
|
global.put( GNR_ATOP.key, true );
|
||||||
}
|
global.put( GNR_LANG.key, Locale.ENGLISH );
|
||||||
|
global.put( GNR_VLNG.key, Locale.ENGLISH );
|
||||||
/**
|
global.put( GNR_RCNT.key, new ArrayList<String>() );
|
||||||
* Returns the value assigned to this property. The value will be first
|
global.put( GNR_COOR.key, null );
|
||||||
* read from the local configuration, and if no value has been defined
|
global.put( GNR_SIZE.key, null );
|
||||||
* for this property, it will be read from the global configuration. The
|
global.put( GNR_COMP.key, Compare.BEST_OVERALL_RUN );
|
||||||
* first property to call this method will trigger the global
|
global.put( GNR_ACCY.key, Accuracy.TENTH );
|
||||||
* configuration to be read and loaded in memory.
|
global.put( GNR_WARN.key, true );
|
||||||
*
|
|
||||||
* @return the local value of this property, or the global one if there
|
|
||||||
* isn't a locally defined value
|
|
||||||
*/
|
|
||||||
public T get() {
|
|
||||||
if ( global == null ) {
|
|
||||||
retrieve();
|
|
||||||
}
|
|
||||||
if ( run != null && run.containsSetting( key ) ) {
|
|
||||||
return run.<T>getSetting( key );
|
|
||||||
}
|
|
||||||
return global.<T>get( key );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
global.put( CLR_BACK.key, Color.decode( "0x000000" ) );
|
||||||
* Sets the value of this property in the global configuration.
|
global.put( CLR_FORE.key, Color.decode( "0xc0c0c0" ) );
|
||||||
*
|
global.put( CLR_TIME.key, Color.decode( "0xffffff" ) );
|
||||||
* @param value the value to assign to this property
|
global.put( CLR_TIMR.key, Color.decode( "0x22cc22" ) );
|
||||||
*/
|
global.put( CLR_GAIN.key, Color.decode( "0x6295fc" ) );
|
||||||
public void set( T value ) {
|
global.put( CLR_LOST.key, Color.decode( "0xe82323" ) );
|
||||||
set( value, false );
|
global.put( CLR_RCRD.key, Color.decode( "0xf0b012" ) );
|
||||||
}
|
global.put( CLR_TITL.key, Color.decode( "0xf0b012" ) );
|
||||||
|
global.put( CLR_HIGH.key, Color.decode( "0xffffff" ) );
|
||||||
/**
|
global.put( CLR_SPRT.key, Color.decode( "0x666666" ) );
|
||||||
* Sets the value of this property. The value of {@code locally}
|
|
||||||
* determines if the value must be stored in the local or global
|
|
||||||
* configuration.
|
|
||||||
*
|
|
||||||
* @param valuethe value to assign to this property
|
|
||||||
* @param locally if the value must be stored in the local configuration
|
|
||||||
*/
|
|
||||||
public void set( T value, boolean locally ) {
|
|
||||||
if ( locally ) {
|
|
||||||
run.putSetting( key, value );
|
|
||||||
} else {
|
|
||||||
global.put( key, value );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares a property to a given string. This property is equal to
|
|
||||||
* the given string if and only if the string is equal to the full key
|
|
||||||
* of this property.
|
|
||||||
*
|
|
||||||
* @param str the string to compare this property against
|
|
||||||
* @return {@code true} if the string equals this property full key
|
|
||||||
*/
|
|
||||||
public boolean equals( String str ) {
|
|
||||||
return key.equals( str );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
global.put( KEY_SPLT.key, -1 );
|
||||||
* Returns the localized name of this property.
|
global.put( KEY_USPL.key, -1 );
|
||||||
*/
|
global.put( KEY_SKIP.key, -1 );
|
||||||
@Override public String toString() {
|
global.put( KEY_RSET.key, -1 );
|
||||||
return Language.valueOf(
|
global.put( KEY_STOP.key, -1 );
|
||||||
"setting_" + key.replaceAll( "\\.", "_" )
|
global.put( KEY_PAUS.key, -1 );
|
||||||
).get();
|
global.put( KEY_LOCK.key, -1 );
|
||||||
}
|
|
||||||
|
global.put( HDR_TTLE.key, true );
|
||||||
}
|
global.put( HDR_GOAL.key, true );
|
||||||
|
|
||||||
|
global.put( HST_ROWS.key, 8 );
|
||||||
|
global.put( HST_TABL.key, true );
|
||||||
|
global.put( HST_BLNK.key, false );
|
||||||
|
global.put( HST_LINE.key, false );
|
||||||
|
global.put( HST_MERG.key, Merge.LIVE );
|
||||||
|
global.put( HST_LIVE.key, true );
|
||||||
|
global.put( HST_DLTA.key, true );
|
||||||
|
global.put( HST_ICON.key, true );
|
||||||
|
global.put( HST_ICSZ.key, 16 );
|
||||||
|
global.put( HST_OFFS.key, 0 );
|
||||||
|
global.put( HST_LAST.key, true );
|
||||||
|
global.put( HST_SFNT.key, Font.decode( "Arial-12" ) );
|
||||||
|
global.put( HST_TFNT.key, Font.decode( "Arial-11" ) );
|
||||||
|
|
||||||
|
global.put( COR_ACCY.key, Accuracy.HUNDREDTH );
|
||||||
|
global.put( COR_ICON.key, true );
|
||||||
|
global.put( COR_ICSZ.key, 40 );
|
||||||
|
global.put( COR_NAME.key, true );
|
||||||
|
global.put( COR_SPLT.key, false );
|
||||||
|
global.put( COR_SEGM.key, true );
|
||||||
|
global.put( COR_BEST.key, true );
|
||||||
|
global.put( COR_STMR.key, true );
|
||||||
|
global.put( COR_TFNT.key, Font.decode( "Digitalism-32" ) );
|
||||||
|
global.put( COR_SFNT.key, Font.decode( "Digitalism-18" ) );
|
||||||
|
|
||||||
|
global.put( GPH_SHOW.key, true );
|
||||||
|
global.put( GPH_SCAL.key, 3.0F );
|
||||||
|
|
||||||
|
global.put( FOO_SHOW.key, true );
|
||||||
|
global.put( FOO_VERB.key, true );
|
||||||
|
global.put( FOO_SPLT.key, false );
|
||||||
|
global.put( FOO_BEST.key, true );
|
||||||
|
global.put( FOO_LINE.key, true );
|
||||||
|
global.put( FOO_DLBL.key, true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Polymorphic property object. It is merely a string identifying the
|
||||||
|
* property and serving as an interface to the configuration. When asked
|
||||||
|
* for its value, the property will return the global value unless a local
|
||||||
|
* value has been defined. Will return a statically typecasted value.
|
||||||
|
*
|
||||||
|
* @param <T> the type of the values of the property
|
||||||
|
* @author Xavier "Xunkar" Sencert
|
||||||
|
* @version 1.0
|
||||||
|
*/
|
||||||
|
public static class Property<T> {
|
||||||
|
|
||||||
|
private static final List<Property<?>> P = new ArrayList<Property<?>>();
|
||||||
|
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new property of given key. If the key contains a dot, the
|
||||||
|
* property name is interpreted as {@code section.key} allowing callers
|
||||||
|
* to grab a submap of the configuration with all properties starting
|
||||||
|
* with {@code section}.
|
||||||
|
*
|
||||||
|
* @param fullKey the name of the property
|
||||||
|
*/
|
||||||
|
private Property( String fullKey ) {
|
||||||
|
this.key = fullKey;
|
||||||
|
P.add( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the key string of this property.
|
||||||
|
*
|
||||||
|
* @return the key string of this property
|
||||||
|
*/
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the value assigned to this property. The value will be first
|
||||||
|
* read from the local configuration, and if no value has been defined
|
||||||
|
* for this property, it will be read from the global configuration. The
|
||||||
|
* first property to call this method will trigger the global
|
||||||
|
* configuration to be read and loaded in memory.
|
||||||
|
*
|
||||||
|
* @return the local value of this property, or the global one if there
|
||||||
|
* isn't a locally defined value
|
||||||
|
*/
|
||||||
|
public T get() {
|
||||||
|
if ( global == null ) {
|
||||||
|
retrieve();
|
||||||
|
}
|
||||||
|
if ( run != null && run.containsSetting( key ) ) {
|
||||||
|
return run.getSetting(key);
|
||||||
|
}
|
||||||
|
return global.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of this property in the global configuration.
|
||||||
|
*
|
||||||
|
* @param value the value to assign to this property
|
||||||
|
*/
|
||||||
|
public void set( T value ) {
|
||||||
|
set( value, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of this property. The value of {@code locally}
|
||||||
|
* determines if the value must be stored in the local or global
|
||||||
|
* configuration.
|
||||||
|
*
|
||||||
|
* @param valuethe value to assign to this property
|
||||||
|
* @param locally if the value must be stored in the local configuration
|
||||||
|
*/
|
||||||
|
public void set( T value, boolean locally ) {
|
||||||
|
if ( locally ) {
|
||||||
|
run.putSetting( key, value );
|
||||||
|
} else {
|
||||||
|
global.put( key, value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares a property to a given string. This property is equal to
|
||||||
|
* the given string if and only if the string is equal to the full key
|
||||||
|
* of this property.
|
||||||
|
*
|
||||||
|
* @param str the string to compare this property against
|
||||||
|
* @return {@code true} if the string equals this property full key
|
||||||
|
*/
|
||||||
|
public boolean equals( String str ) {
|
||||||
|
return key.equals( str );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the localized name of this property.
|
||||||
|
*/
|
||||||
|
@Override public String toString() {
|
||||||
|
return Language.valueOf(
|
||||||
|
"setting_" + key.replaceAll( "\\.", "_" )
|
||||||
|
).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,463 +50,463 @@ import org.fenix.utils.gui.GBC;
|
||||||
public class EditRun extends LlanfairDialog
|
public class EditRun extends LlanfairDialog
|
||||||
implements ActionListener, ListSelectionListener {
|
implements ActionListener, ListSelectionListener {
|
||||||
|
|
||||||
// ------------------------------------------------------------- CONSTANTES
|
// ------------------------------------------------------------- CONSTANTES
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Largeurs en pixels des colonnes de la table d’édition des segments. Les
|
* Largeurs en pixels des colonnes de la table d’édition des segments. Les
|
||||||
* largeurs sont données dans l’odre du modèle.
|
* largeurs sont données dans l’odre du modèle.
|
||||||
*/
|
*/
|
||||||
private static final int[] TABLE_COLUMN_WIDTHS = new int[] {
|
private static final int[] TABLE_COLUMN_WIDTHS = new int[] {
|
||||||
Segment.ICON_MAX_SIZE, 130, 100, 100, 100
|
Segment.ICON_MAX_SIZE, 130, 100, 100, 100
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dimension d’un petit bouton dont l’étiquette n’est qu’un caractère.
|
* Dimension d’un petit bouton dont l’étiquette n’est qu’un caractère.
|
||||||
*/
|
*/
|
||||||
private static final Dimension SMALL_BUTTON_SIZE = new Dimension(40, 25);
|
private static final Dimension SMALL_BUTTON_SIZE = new Dimension(40, 25);
|
||||||
|
|
||||||
// -------------------------------------------------------------- ATTRIBUTS
|
// -------------------------------------------------------------- ATTRIBUTS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Course éditée par cette boîte de dialogue.
|
* Course éditée par cette boîte de dialogue.
|
||||||
*/
|
*/
|
||||||
private Run run;
|
private Run run;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zone d’édition du titre de la course.
|
* Zone d’édition du titre de la course.
|
||||||
*/
|
*/
|
||||||
private JTextField runTitle;
|
private JTextField runTitle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Étiquette du {@link runTitle}.
|
* Étiquette du {@link runTitle}.
|
||||||
*/
|
*/
|
||||||
private JLabel runTitleLabel;
|
private JLabel runTitleLabel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table d’édition des segments de la course.
|
* Table d’édition des segments de la course.
|
||||||
*/
|
*/
|
||||||
private JTable segments;
|
private JTable segments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Panneau avec ascenseur dans lequel est inséré la table {@link segments}.
|
* Panneau avec ascenseur dans lequel est inséré la table {@link segments}.
|
||||||
*/
|
*/
|
||||||
private JScrollPane scrollPane;
|
private JScrollPane scrollPane;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Étiquette de {@code segments}.
|
* Étiquette de {@code segments}.
|
||||||
*/
|
*/
|
||||||
private JLabel segmentsLabel;
|
private JLabel segmentsLabel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bouton permettant d’insérer un nouveau segment.
|
* Bouton permettant d’insérer un nouveau segment.
|
||||||
*/
|
*/
|
||||||
private JButton addSegment;
|
private JButton addSegment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bouton permettant de supprimer un segment.
|
* Bouton permettant de supprimer un segment.
|
||||||
*/
|
*/
|
||||||
private JButton remSegment;
|
private JButton remSegment;
|
||||||
|
|
||||||
private JCheckBox segmented;
|
|
||||||
|
|
||||||
/**
|
private JCheckBox segmented;
|
||||||
* Bouton permettant d’enregistrer l’édition et de quitter le dialogue.
|
|
||||||
*/
|
|
||||||
private JButton save;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bouton permettant de quitter le dialogue sans modifier la course.
|
* Bouton permettant d’enregistrer l’édition et de quitter le dialogue.
|
||||||
*/
|
*/
|
||||||
private JButton cancel;
|
private JButton save;
|
||||||
|
|
||||||
/**
|
|
||||||
* Button moving the currently selected segment one position up.
|
|
||||||
*/
|
|
||||||
private JButton moveUp;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Button moving the currently selected segment one position down.
|
|
||||||
*/
|
|
||||||
private JButton moveDown;
|
|
||||||
|
|
||||||
private JTextField runGoal;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------- CONSTRUCTEURS
|
/**
|
||||||
|
* Bouton permettant de quitter le dialogue sans modifier la course.
|
||||||
|
*/
|
||||||
|
private JButton cancel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Création d’une boîte de dialogue permettant d’éditer la course fournie.
|
* Button moving the currently selected segment one position up.
|
||||||
*
|
*/
|
||||||
* @param run - la course a éditer.
|
private JButton moveUp;
|
||||||
*/
|
|
||||||
public EditRun(Run run) {
|
|
||||||
super();
|
|
||||||
if (run == null) {
|
|
||||||
throw new NullPointerException("EditDialog.EditDialog(): null run");
|
|
||||||
}
|
|
||||||
this.run = run;
|
|
||||||
run.saveBackup();
|
|
||||||
|
|
||||||
setTitle(Language.EDITING.get());
|
/**
|
||||||
|
* Button moving the currently selected segment one position down.
|
||||||
|
*/
|
||||||
|
private JButton moveDown;
|
||||||
|
|
||||||
runTitle = new JTextField(run.getName(), 61);
|
private JTextField runGoal;
|
||||||
runTitleLabel = new JLabel(Language.RUN_TITLE.get());
|
|
||||||
runGoal = new JTextField(run.getGoal(), 48);
|
|
||||||
segments = new JTable(run) {
|
|
||||||
@Override protected JTableHeader createDefaultTableHeader() {
|
|
||||||
return new JTableHeader(columnModel) {
|
|
||||||
@Override public String getToolTipText(MouseEvent event) {
|
|
||||||
int col = columnModel.getColumnIndexAtX(event.getX());
|
|
||||||
int ind = columnModel.getColumn(col).getModelIndex();
|
|
||||||
switch (ind) {
|
|
||||||
case Run.COLUMN_BEST:
|
|
||||||
return "" + Language.TT_COLUMN_BEST;
|
|
||||||
case Run.COLUMN_SEGMENT:
|
|
||||||
return "" + Language.TT_COLUMN_SEGMENT;
|
|
||||||
case Run.COLUMN_TIME:
|
|
||||||
return "" + Language.TT_COLUMN_TIME;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
segmentsLabel = new JLabel("" + Language.SEGMENTS);
|
|
||||||
addSegment = new JButton(Llanfair.getResources().getIcon("PLUS"));
|
|
||||||
remSegment = new JButton(Llanfair.getResources().getIcon("MINUS"));
|
|
||||||
save = new JButton("" + Language.menuItem_save);
|
|
||||||
cancel = new JButton("" + Language.CANCEL);
|
|
||||||
scrollPane = new JScrollPane(segments);
|
|
||||||
moveUp = new JButton(Llanfair.getResources().getIcon("ARROW_UP"));
|
|
||||||
moveDown = new JButton(Llanfair.getResources().getIcon("ARROW_DOWN"));
|
|
||||||
segmented = new JCheckBox("" + Language.ED_SEGMENTED, run.isSegmented());
|
|
||||||
|
|
||||||
placeComponents();
|
// ----------------------------------------------------------- CONSTRUCTEURS
|
||||||
setBehavior();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------- MÉTHODES
|
/**
|
||||||
|
* Création d’une boîte de dialogue permettant d’éditer la course fournie.
|
||||||
|
*
|
||||||
|
* @param run - la course a éditer.
|
||||||
|
*/
|
||||||
|
public EditRun(Run run) {
|
||||||
|
super();
|
||||||
|
if (run == null) {
|
||||||
|
throw new NullPointerException("EditDialog.EditDialog(): null run");
|
||||||
|
}
|
||||||
|
this.run = run;
|
||||||
|
run.saveBackup();
|
||||||
|
|
||||||
/**
|
setTitle(Language.EDITING.get());
|
||||||
* Dispose les sous-composants au sein de la boîte de dialogue.
|
|
||||||
*/
|
|
||||||
private void placeComponents() {
|
|
||||||
setLayout(new GridBagLayout());
|
|
||||||
add(runTitleLabel, GBC.grid(0, 0).insets(4, 4, 0, 4));
|
|
||||||
add(runTitle, GBC.grid(1, 0, 3, 1).insets(4, 0, 0, 4).anchor(GBC.LS));
|
|
||||||
add(new JLabel("" + Language.LB_GOAL), GBC.grid(0, 1).insets(4, 4, 0, 4));
|
|
||||||
add(runGoal, GBC.grid(1, 1).insets(4, 0, 0, 4).anchor(GBC.LS));
|
|
||||||
add(segmented, GBC.grid(2, 1, 2, 1).insets(4, 0, 0, 4).anchor(GBC.LS));
|
|
||||||
add(segmentsLabel, GBC.grid(0, 2, 4, 1).insets(5, 4, 4, 0)
|
|
||||||
.anchor(GBC.BL));
|
|
||||||
add(scrollPane, GBC.grid(0, 3, 3, 4).insets(0, 4, 0, 0));
|
|
||||||
add(addSegment, GBC.grid(3, 3).insets(0, 4).anchor(GBC.FLS));
|
|
||||||
add(remSegment, GBC.grid(3, 4).insets(4, 4).anchor(GBC.FLS));
|
|
||||||
add(moveUp, GBC.grid(3, 5).insets(0, 4).anchor(GBC.FLS));
|
|
||||||
add(moveDown, GBC.grid(3, 6).insets(4, 4).anchor(GBC.FLS));
|
|
||||||
|
|
||||||
JPanel controls = new JPanel();
|
|
||||||
controls.add(save);
|
|
||||||
controls.add(cancel);
|
|
||||||
add(controls, GBC.grid(0, 7, 4, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
runTitle = new JTextField(run.getName(), 61);
|
||||||
* Définit le comportement des sous-composants du dialogue.
|
runTitleLabel = new JLabel(Language.RUN_TITLE.get());
|
||||||
*/
|
runGoal = new JTextField(run.getGoal(), 48);
|
||||||
private void setBehavior() {
|
segments = new JTable(run) {
|
||||||
// Ne pas permettre la fermeture du dialogue par la croix pour forcer
|
@Override protected JTableHeader createDefaultTableHeader() {
|
||||||
// l’utilisateur à utiliser les boutons save et cancel.
|
return new JTableHeader(columnModel) {
|
||||||
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
@Override public String getToolTipText(MouseEvent event) {
|
||||||
|
int col = columnModel.getColumnIndexAtX(event.getX());
|
||||||
|
int ind = columnModel.getColumn(col).getModelIndex();
|
||||||
|
switch (ind) {
|
||||||
|
case Run.COLUMN_BEST:
|
||||||
|
return "" + Language.TT_COLUMN_BEST;
|
||||||
|
case Run.COLUMN_SEGMENT:
|
||||||
|
return "" + Language.TT_COLUMN_SEGMENT;
|
||||||
|
case Run.COLUMN_TIME:
|
||||||
|
return "" + Language.TT_COLUMN_TIME;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
segmentsLabel = new JLabel("" + Language.SEGMENTS);
|
||||||
|
addSegment = new JButton(Llanfair.getResources().getIcon("PLUS"));
|
||||||
|
remSegment = new JButton(Llanfair.getResources().getIcon("MINUS"));
|
||||||
|
save = new JButton("" + Language.menuItem_save);
|
||||||
|
cancel = new JButton("" + Language.CANCEL);
|
||||||
|
scrollPane = new JScrollPane(segments);
|
||||||
|
moveUp = new JButton(Llanfair.getResources().getIcon("ARROW_UP"));
|
||||||
|
moveDown = new JButton(Llanfair.getResources().getIcon("ARROW_DOWN"));
|
||||||
|
segmented = new JCheckBox("" + Language.ED_SEGMENTED, run.isSegmented());
|
||||||
|
|
||||||
// Définir les dimensions des composants.
|
placeComponents();
|
||||||
setResizable(false);
|
setBehavior();
|
||||||
addSegment.setPreferredSize(SMALL_BUTTON_SIZE);
|
}
|
||||||
remSegment.setPreferredSize(SMALL_BUTTON_SIZE);
|
|
||||||
moveUp.setPreferredSize(SMALL_BUTTON_SIZE);
|
|
||||||
moveDown.setPreferredSize(SMALL_BUTTON_SIZE);
|
|
||||||
|
|
||||||
segments.setRowHeight(Segment.ICON_MAX_SIZE);
|
// ---------------------------------------------------------------- MÉTHODES
|
||||||
for (int i = 0; i < run.getColumnCount(); i++) {
|
|
||||||
TableColumn column = segments.getColumnModel().getColumn(i);
|
|
||||||
column.setPreferredWidth(TABLE_COLUMN_WIDTHS[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
int totalWidth = 0;
|
/**
|
||||||
for (int width : TABLE_COLUMN_WIDTHS) {
|
* Dispose les sous-composants au sein de la boîte de dialogue.
|
||||||
totalWidth += width;
|
*/
|
||||||
}
|
private void placeComponents() {
|
||||||
Dimension size = new Dimension(totalWidth, Segment.ICON_MAX_SIZE * 5);
|
setLayout(new GridBagLayout());
|
||||||
segments.setPreferredScrollableViewportSize(size);
|
add(runTitleLabel, GBC.grid(0, 0).insets(4, 4, 0, 4));
|
||||||
|
add(runTitle, GBC.grid(1, 0, 3, 1).insets(4, 0, 0, 4).anchor(GBC.LS));
|
||||||
|
add(new JLabel("" + Language.LB_GOAL), GBC.grid(0, 1).insets(4, 4, 0, 4));
|
||||||
|
add(runGoal, GBC.grid(1, 1).insets(4, 0, 0, 4).anchor(GBC.LS));
|
||||||
|
add(segmented, GBC.grid(2, 1, 2, 1).insets(4, 0, 0, 4).anchor(GBC.LS));
|
||||||
|
add(segmentsLabel, GBC.grid(0, 2, 4, 1).insets(5, 4, 4, 0)
|
||||||
|
.anchor(GBC.BL));
|
||||||
|
add(scrollPane, GBC.grid(0, 3, 3, 4).insets(0, 4, 0, 0));
|
||||||
|
add(addSegment, GBC.grid(3, 3).insets(0, 4).anchor(GBC.FLS));
|
||||||
|
add(remSegment, GBC.grid(3, 4).insets(4, 4).anchor(GBC.FLS));
|
||||||
|
add(moveUp, GBC.grid(3, 5).insets(0, 4).anchor(GBC.FLS));
|
||||||
|
add(moveDown, GBC.grid(3, 6).insets(4, 4).anchor(GBC.FLS));
|
||||||
|
|
||||||
// Enregistrement des écouteurs des composants.
|
JPanel controls = new JPanel();
|
||||||
addSegment.addActionListener(this);
|
controls.add(save);
|
||||||
remSegment.addActionListener(this);
|
controls.add(cancel);
|
||||||
moveUp.addActionListener(this);
|
add(controls, GBC.grid(0, 7, 4, 1));
|
||||||
moveDown.addActionListener(this);
|
}
|
||||||
cancel.addActionListener(this);
|
|
||||||
save.addActionListener(this);
|
|
||||||
|
|
||||||
// Insertion des délégués de rendus et d’édition.
|
/**
|
||||||
segments.setDefaultRenderer(Icon.class, new IconRenderer());
|
* Définit le comportement des sous-composants du dialogue.
|
||||||
segments.setDefaultEditor(Icon.class, new FileChooserEditor(this));
|
*/
|
||||||
segments.setDefaultEditor(Time.class, new TimeEditor());
|
private void setBehavior() {
|
||||||
|
// Ne pas permettre la fermeture du dialogue par la croix pour forcer
|
||||||
|
// l’utilisateur à utiliser les boutons save et cancel.
|
||||||
|
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
|
||||||
|
|
||||||
// Ajuster le comportement de la table.
|
// Définir les dimensions des composants.
|
||||||
segments.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
|
setResizable(false);
|
||||||
segments.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
|
addSegment.setPreferredSize(SMALL_BUTTON_SIZE);
|
||||||
segments.getSelectionModel().addListSelectionListener(this);
|
remSegment.setPreferredSize(SMALL_BUTTON_SIZE);
|
||||||
|
moveUp.setPreferredSize(SMALL_BUTTON_SIZE);
|
||||||
|
moveDown.setPreferredSize(SMALL_BUTTON_SIZE);
|
||||||
|
|
||||||
addSegment.setToolTipText("" + Language.TT_ADD_SEGMENT);
|
segments.setRowHeight(Segment.ICON_MAX_SIZE);
|
||||||
remSegment.setToolTipText("" + Language.TT_REMOVE_SEGMENT);
|
for (int i = 0; i < run.getColumnCount(); i++) {
|
||||||
moveDown.setToolTipText("" + Language.TT_MOVE_SEGMENT_DOWN);
|
TableColumn column = segments.getColumnModel().getColumn(i);
|
||||||
moveUp.setToolTipText("" + Language.TT_MOVE_SEGMENT_UP);
|
column.setPreferredWidth(TABLE_COLUMN_WIDTHS[i]);
|
||||||
segmented.setToolTipText("" + Language.TT_ED_SEGMENTED);
|
}
|
||||||
|
|
||||||
updateButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
int totalWidth = 0;
|
||||||
* Procédure à invoquer lorsque ce composant réalise une action. Sont donc
|
for (int width : TABLE_COLUMN_WIDTHS) {
|
||||||
* capturés ici, tous les évènements d’action des sous-composants, comme
|
totalWidth += width;
|
||||||
* l’appui sur un bouton.
|
}
|
||||||
*
|
Dimension size = new Dimension(totalWidth, Segment.ICON_MAX_SIZE * 5);
|
||||||
* @param event - l’évènement d’action.
|
segments.setPreferredScrollableViewportSize(size);
|
||||||
* @see ActionListener
|
|
||||||
*/
|
|
||||||
@Override public void actionPerformed(ActionEvent event) {
|
|
||||||
Object source = event.getSource();
|
|
||||||
if (source.equals(addSegment)) {
|
|
||||||
run.addSegment(new Segment());
|
|
||||||
Rectangle rect = segments.getCellRect(run.getRowCount() - 1, 0, true);
|
|
||||||
segments.scrollRectToVisible(rect);
|
|
||||||
updateButtons();
|
|
||||||
|
|
||||||
} else if (source.equals(remSegment)) {
|
|
||||||
run.removeSegment(segments.getSelectedRow());
|
|
||||||
updateButtons();
|
|
||||||
|
|
||||||
} else if (source.equals(save)) {
|
// Enregistrement des écouteurs des composants.
|
||||||
run.setName(runTitle.getText());
|
addSegment.addActionListener(this);
|
||||||
run.setGoal(runGoal.getText());
|
remSegment.addActionListener(this);
|
||||||
run.setSegmented(segmented.isSelected());
|
moveUp.addActionListener(this);
|
||||||
dispose();
|
moveDown.addActionListener(this);
|
||||||
|
cancel.addActionListener(this);
|
||||||
|
save.addActionListener(this);
|
||||||
|
|
||||||
} else if (source.equals(cancel)) {
|
// Insertion des délégués de rendus et d’édition.
|
||||||
if (!segments.isEditing()) {
|
segments.setDefaultRenderer(Icon.class, new IconRenderer());
|
||||||
run.loadBackup();
|
segments.setDefaultEditor(Icon.class, new FileChooserEditor(this));
|
||||||
dispose();
|
segments.setDefaultEditor(Time.class, new TimeEditor());
|
||||||
}
|
|
||||||
} else if (source.equals(moveUp)) {
|
|
||||||
int selected = segments.getSelectedRow();
|
|
||||||
run.moveSegmentUp(selected);
|
|
||||||
segments.setRowSelectionInterval(selected - 1, selected - 1);
|
|
||||||
|
|
||||||
} else if (source.equals(moveDown)) {
|
|
||||||
int selected = segments.getSelectedRow();
|
|
||||||
run.moveSegmentDown(selected);
|
|
||||||
segments.setRowSelectionInterval(selected + 1, selected + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// Ajuster le comportement de la table.
|
||||||
* Méthode invoquée lors d’un changement de sélection dans la table.
|
segments.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
|
||||||
*
|
segments.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
|
||||||
* @param event - l’évènement de sélection.
|
segments.getSelectionModel().addListSelectionListener(this);
|
||||||
*/
|
|
||||||
public void valueChanged(ListSelectionEvent event) {
|
|
||||||
if (!event.getValueIsAdjusting()) {
|
|
||||||
updateButtons();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateButtons() {
|
|
||||||
int selected = segments.getSelectedRow();
|
|
||||||
boolean enabled = (selected >= 0);
|
|
||||||
remSegment.setEnabled(enabled);
|
|
||||||
moveUp.setEnabled(enabled && selected > 0);
|
|
||||||
moveDown.setEnabled(enabled && selected < run.getRowCount() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------- CLASSE INTERNE
|
addSegment.setToolTipText("" + Language.TT_ADD_SEGMENT);
|
||||||
|
remSegment.setToolTipText("" + Language.TT_REMOVE_SEGMENT);
|
||||||
|
moveDown.setToolTipText("" + Language.TT_MOVE_SEGMENT_DOWN);
|
||||||
|
moveUp.setToolTipText("" + Language.TT_MOVE_SEGMENT_UP);
|
||||||
|
segmented.setToolTipText("" + Language.TT_ED_SEGMENTED);
|
||||||
|
|
||||||
/**
|
updateButtons();
|
||||||
* Gestionnaire de rendu capable d’afficher une valeur de type {@link Icon}
|
}
|
||||||
* au sein d’une table.
|
|
||||||
*
|
|
||||||
* @author Xavier Sencert
|
|
||||||
* @see TableCellRenderer
|
|
||||||
*/
|
|
||||||
private class IconRenderer extends DefaultTableCellRenderer {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construction d’un gestionnaire de rendu d’icônes.
|
* Procédure à invoquer lorsque ce composant réalise une action. Sont donc
|
||||||
*/
|
* capturés ici, tous les évènements d’action des sous-composants, comme
|
||||||
public IconRenderer() {
|
* l’appui sur un bouton.
|
||||||
super();
|
*
|
||||||
}
|
* @param event - l’évènement d’action.
|
||||||
|
* @see ActionListener
|
||||||
|
*/
|
||||||
|
@Override public void actionPerformed(ActionEvent event) {
|
||||||
|
Object source = event.getSource();
|
||||||
|
if (source.equals(addSegment)) {
|
||||||
|
run.addSegment(new Segment());
|
||||||
|
Rectangle rect = segments.getCellRect(run.getRowCount() - 1, 0, true);
|
||||||
|
segments.scrollRectToVisible(rect);
|
||||||
|
updateButtons();
|
||||||
|
|
||||||
/**
|
} else if (source.equals(remSegment)) {
|
||||||
* Retourne le composant de rendu à afficher dans la table. Le composant
|
run.removeSegment(segments.getSelectedRow());
|
||||||
* est ici préparé selon la valeur de la cellule et différentes
|
updateButtons();
|
||||||
* informations sur l’état du composant.
|
|
||||||
*/
|
|
||||||
@Override public Component getTableCellRendererComponent(JTable table,
|
|
||||||
Object value, boolean isSelected, boolean hasFocus, int row,
|
|
||||||
int column) {
|
|
||||||
// Préparer le label comme un label par défaut.
|
|
||||||
JLabel label = (JLabel) super.getTableCellRendererComponent(
|
|
||||||
table, value, isSelected, hasFocus, row, column);
|
|
||||||
// Modifier l’icône du label par celle de la valeur.
|
|
||||||
label.setIcon((value == null) ? null : (Icon) value);
|
|
||||||
label.setText("");
|
|
||||||
label.setHorizontalAlignment(JLabel.CENTER);
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------- CLASSE INTERNE
|
} else if (source.equals(save)) {
|
||||||
|
run.setName(runTitle.getText());
|
||||||
|
run.setGoal(runGoal.getText());
|
||||||
|
run.setSegmented(segmented.isSelected());
|
||||||
|
dispose();
|
||||||
|
|
||||||
/**
|
} else if (source.equals(cancel)) {
|
||||||
* Délégué d’édition des temps de course et de segments. Cette classe permet
|
if (!segments.isEditing()) {
|
||||||
* de récupérer les exceptions potentiellement levés lorsque l’édition se
|
run.loadBackup();
|
||||||
* termine et que la valeur est modifié dans la table des segments.
|
dispose();
|
||||||
*
|
}
|
||||||
* @author Xavier "Xunkar" Sencert
|
} else if (source.equals(moveUp)) {
|
||||||
*/
|
int selected = segments.getSelectedRow();
|
||||||
private class TimeEditor extends DefaultCellEditor {
|
run.moveSegmentUp(selected);
|
||||||
|
segments.setRowSelectionInterval(selected - 1, selected - 1);
|
||||||
|
|
||||||
/**
|
} else if (source.equals(moveDown)) {
|
||||||
* Composant d’édition. Conservé ici en doublon pour éviter de devoir le
|
int selected = segments.getSelectedRow();
|
||||||
* caster à chaque fois.
|
run.moveSegmentDown(selected);
|
||||||
*/
|
segments.setRowSelectionInterval(selected + 1, selected + 1);
|
||||||
private JTextField editor;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construction d’un délégué par défaut.
|
* Méthode invoquée lors d’un changement de sélection dans la table.
|
||||||
*/
|
*
|
||||||
public TimeEditor() {
|
* @param event - l’évènement de sélection.
|
||||||
super(new JTextField());
|
*/
|
||||||
editor = (JTextField) getComponent();
|
public void valueChanged(ListSelectionEvent event) {
|
||||||
}
|
if (!event.getValueIsAdjusting()) {
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
private void updateButtons() {
|
||||||
* Retourne la valeur entrée par l’utilisateur.
|
int selected = segments.getSelectedRow();
|
||||||
*
|
boolean enabled = (selected >= 0);
|
||||||
* @return la valeur entrée par l’utilisateur.
|
remSegment.setEnabled(enabled);
|
||||||
*/
|
moveUp.setEnabled(enabled && selected > 0);
|
||||||
public Object getCellEditorValue() {
|
moveDown.setEnabled(enabled && selected < run.getRowCount() - 1);
|
||||||
String text = editor.getText();
|
}
|
||||||
return text.equals("") ? null : new Time(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// ---------------------------------------------------------- CLASSE INTERNE
|
||||||
* Retourne le composant d’édition, formatté comme il se doit selon les
|
|
||||||
* informations de la table et de la cellule.
|
|
||||||
*
|
|
||||||
* @param table - la table source demandant l’édition.
|
|
||||||
* @param get - la valeur actuellement présente à représenter.
|
|
||||||
* @param isSelected - indique si la ligne est sélectionnée.
|
|
||||||
* @param row - indice de ligne la cellule éditée.
|
|
||||||
* @param column - indice de colonne de la cellule éditée.
|
|
||||||
* @return le composant d’édition.
|
|
||||||
*/
|
|
||||||
public Component getTableCellEditorComponent(JTable table, Object value,
|
|
||||||
boolean isSelected, int row, int column) {
|
|
||||||
editor.setText(value == null ? "" : value.toString());
|
|
||||||
editor.selectAll();
|
|
||||||
return editor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Arrête l’édition de la cellule. Le délégué récupère ici les exceptions
|
* Gestionnaire de rendu capable d’afficher une valeur de type {@link Icon}
|
||||||
* levées et les remonte à l’utilisateur. Tant que l’édition est en erreur
|
* au sein d’une table.
|
||||||
* l’édition persiste.
|
*
|
||||||
*
|
* @author Xavier Sencert
|
||||||
* @return {@code true} si l’édition s’est arrêtée.
|
* @see TableCellRenderer
|
||||||
*/
|
*/
|
||||||
public boolean stopCellEditing() {
|
private class IconRenderer extends DefaultTableCellRenderer {
|
||||||
try {
|
|
||||||
return super.stopCellEditing();
|
|
||||||
} catch (Exception e) {
|
|
||||||
JOptionPane.showMessageDialog(editor, e.getMessage(),
|
|
||||||
Language.ERROR.get(), JOptionPane.ERROR_MESSAGE);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* Construction d’un gestionnaire de rendu d’icônes.
|
||||||
|
*/
|
||||||
|
public IconRenderer() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------- CLASSE INTERNE
|
/**
|
||||||
|
* Retourne le composant de rendu à afficher dans la table. Le composant
|
||||||
|
* est ici préparé selon la valeur de la cellule et différentes
|
||||||
|
* informations sur l’état du composant.
|
||||||
|
*/
|
||||||
|
@Override public Component getTableCellRendererComponent(JTable table,
|
||||||
|
Object value, boolean isSelected, boolean hasFocus, int row,
|
||||||
|
int column) {
|
||||||
|
// Préparer le label comme un label par défaut.
|
||||||
|
JLabel label = (JLabel) super.getTableCellRendererComponent(
|
||||||
|
table, value, isSelected, hasFocus, row, column);
|
||||||
|
// Modifier l’icône du label par celle de la valeur.
|
||||||
|
label.setIcon((value == null) ? null : (Icon) value);
|
||||||
|
label.setText("");
|
||||||
|
label.setHorizontalAlignment(JLabel.CENTER);
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
// ---------------------------------------------------------- CLASSE INTERNE
|
||||||
* Éditeur de cellules permettant de sélectionner un fichier via un
|
|
||||||
* {@code JFileChooser}.
|
|
||||||
*
|
|
||||||
* @author Xavier Sencert
|
|
||||||
* @see TableCellEditor
|
|
||||||
* @see ActionListener
|
|
||||||
*/
|
|
||||||
private class FileChooserEditor extends AbstractCellEditor
|
|
||||||
implements TableCellEditor, ActionListener {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gestionnaire de sélection de fichier.
|
* Délégué d’édition des temps de course et de segments. Cette classe permet
|
||||||
*/
|
* de récupérer les exceptions potentiellement levés lorsque l’édition se
|
||||||
private JFileChooser chooser;
|
* termine et que la valeur est modifié dans la table des segments.
|
||||||
|
*
|
||||||
|
* @author Xavier "Xunkar" Sencert
|
||||||
|
*/
|
||||||
|
private class TimeEditor extends DefaultCellEditor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Composant d’édition de l’éditeur. Il s’agit d’un {@code JButton}
|
* Composant d’édition. Conservé ici en doublon pour éviter de devoir le
|
||||||
* ce qui permet de capturer le clic de l’utilisateur et ainsi d’ouvrir
|
* caster à chaque fois.
|
||||||
* le gestionnaire de sélection de fichier.
|
*/
|
||||||
*/
|
private JTextField editor;
|
||||||
private JButton editor;
|
|
||||||
|
|
||||||
private Window owner;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Création d’un éditeur par défaut.
|
* Construction d’un délégué par défaut.
|
||||||
*/
|
*/
|
||||||
public FileChooserEditor(Window owner) {
|
public TimeEditor() {
|
||||||
super();
|
super(new JTextField());
|
||||||
this.owner = owner;
|
editor = (JTextField) getComponent();
|
||||||
chooser = new JFileChooser(".");
|
}
|
||||||
editor = new JButton();
|
|
||||||
|
|
||||||
chooser.setFileFilter(new FileNameExtensionFilter(
|
|
||||||
"" + Language.IMAGE, "gif", "jpg", "jpeg", "png"));
|
|
||||||
editor.addActionListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retourne le composant d’édition à afficher au sein de la table, il
|
* Retourne la valeur entrée par l’utilisateur.
|
||||||
* s’agit donc du bouton {@link #editor}.
|
*
|
||||||
*/
|
* @return la valeur entrée par l’utilisateur.
|
||||||
public Component getTableCellEditorComponent(JTable table, Object value,
|
*/
|
||||||
boolean isSelected, int row, int column) {
|
public Object getCellEditorValue() {
|
||||||
return editor;
|
String text = editor.getText();
|
||||||
}
|
return text.equals("") ? null : new Time(text);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retourne la valeur stockée par l’éditeur à savoir le fichier
|
* Retourne le composant d’édition, formatté comme il se doit selon les
|
||||||
* sélectionner par l’utilisateur s’il y en a un.
|
* informations de la table et de la cellule.
|
||||||
*/
|
*
|
||||||
public Object getCellEditorValue() {
|
* @param table - la table source demandant l’édition.
|
||||||
if (chooser.getSelectedFile() == null) {
|
* @param get - la valeur actuellement présente à représenter.
|
||||||
return null;
|
* @param isSelected - indique si la ligne est sélectionnée.
|
||||||
}
|
* @param row - indice de ligne la cellule éditée.
|
||||||
return new ImageIcon(chooser.getSelectedFile().getPath());
|
* @param column - indice de colonne de la cellule éditée.
|
||||||
}
|
* @return le composant d’édition.
|
||||||
|
*/
|
||||||
|
public Component getTableCellEditorComponent(JTable table, Object value,
|
||||||
|
boolean isSelected, int row, int column) {
|
||||||
|
editor.setText(value == null ? "" : value.toString());
|
||||||
|
editor.selectAll();
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lors du clic de l’utilisateur sur le bouton, on affiche le
|
* Arrête l’édition de la cellule. Le délégué récupère ici les exceptions
|
||||||
* gestionnaire de sélection de fichier puis l’on force la fin de
|
* levées et les remonte à l’utilisateur. Tant que l’édition est en erreur
|
||||||
* l’édition lorsque celui-ci retourne.
|
* l’édition persiste.
|
||||||
*/
|
*
|
||||||
@Override public void actionPerformed(ActionEvent e) {
|
* @return {@code true} si l’édition s’est arrêtée.
|
||||||
chooser.showOpenDialog(owner);
|
*/
|
||||||
fireEditingStopped();
|
public boolean stopCellEditing() {
|
||||||
}
|
try {
|
||||||
|
return super.stopCellEditing();
|
||||||
|
} catch (Exception e) {
|
||||||
|
JOptionPane.showMessageDialog(editor, e.getMessage(),
|
||||||
|
Language.ERROR.get(), JOptionPane.ERROR_MESSAGE);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------- CLASSE INTERNE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Éditeur de cellules permettant de sélectionner un fichier via un
|
||||||
|
* {@code JFileChooser}.
|
||||||
|
*
|
||||||
|
* @author Xavier Sencert
|
||||||
|
* @see TableCellEditor
|
||||||
|
* @see ActionListener
|
||||||
|
*/
|
||||||
|
private class FileChooserEditor extends AbstractCellEditor
|
||||||
|
implements TableCellEditor, ActionListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gestionnaire de sélection de fichier.
|
||||||
|
*/
|
||||||
|
private JFileChooser chooser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composant d’édition de l’éditeur. Il s’agit d’un {@code JButton}
|
||||||
|
* ce qui permet de capturer le clic de l’utilisateur et ainsi d’ouvrir
|
||||||
|
* le gestionnaire de sélection de fichier.
|
||||||
|
*/
|
||||||
|
private JButton editor;
|
||||||
|
|
||||||
|
private Window owner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Création d’un éditeur par défaut.
|
||||||
|
*/
|
||||||
|
public FileChooserEditor(Window owner) {
|
||||||
|
super();
|
||||||
|
this.owner = owner;
|
||||||
|
chooser = new JFileChooser(".");
|
||||||
|
editor = new JButton();
|
||||||
|
|
||||||
|
chooser.setFileFilter(new FileNameExtensionFilter(
|
||||||
|
"" + Language.IMAGE, "gif", "jpg", "jpeg", "png"));
|
||||||
|
editor.addActionListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne le composant d’édition à afficher au sein de la table, il
|
||||||
|
* s’agit donc du bouton {@link #editor}.
|
||||||
|
*/
|
||||||
|
public Component getTableCellEditorComponent(JTable table, Object value,
|
||||||
|
boolean isSelected, int row, int column) {
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retourne la valeur stockée par l’éditeur à savoir le fichier
|
||||||
|
* sélectionner par l’utilisateur s’il y en a un.
|
||||||
|
*/
|
||||||
|
public Object getCellEditorValue() {
|
||||||
|
if (chooser.getSelectedFile() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new ImageIcon(chooser.getSelectedFile().getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lors du clic de l’utilisateur sur le bouton, on affiche le
|
||||||
|
* gestionnaire de sélection de fichier puis l’on force la fin de
|
||||||
|
* l’édition lorsque celui-ci retourne.
|
||||||
|
*/
|
||||||
|
@Override public void actionPerformed(ActionEvent e) {
|
||||||
|
chooser.showOpenDialog(owner);
|
||||||
|
fireEditingStopped();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,127 +27,127 @@ import org.fenix.utils.locale.LocaleListener;
|
||||||
* @date 22 juil. 2012
|
* @date 22 juil. 2012
|
||||||
*/
|
*/
|
||||||
public class EditSettings extends LlanfairDialog
|
public class EditSettings extends LlanfairDialog
|
||||||
implements ActionListener, LocaleListener, WindowListener {
|
implements ActionListener, LocaleListener, WindowListener {
|
||||||
|
|
||||||
// ATTRIBUTS
|
// ATTRIBUTS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bouton permettant de valider et de fermer la boîte de dialogue.
|
* Bouton permettant de valider et de fermer la boîte de dialogue.
|
||||||
*/
|
*/
|
||||||
private JButton actionOK;
|
private JButton actionOK;
|
||||||
|
|
||||||
private JButton reset;
|
private JButton reset;
|
||||||
|
|
||||||
private List<SettingsTab> settingsTabs;
|
private List<SettingsTab> settingsTabs;
|
||||||
|
|
||||||
// CONSTRUCTEURS
|
// CONSTRUCTEURS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construction d’une boîte de dialogue d’édition de paramètres.
|
* Construction d’une boîte de dialogue d’édition de paramètres.
|
||||||
*/
|
*/
|
||||||
public EditSettings() {
|
public EditSettings() {
|
||||||
settingsTabs = new ArrayList<SettingsTab>();
|
settingsTabs = new ArrayList<SettingsTab>();
|
||||||
settingsTabs.add(new TabGeneral());
|
settingsTabs.add(new TabGeneral());
|
||||||
settingsTabs.add(new TabLook());
|
settingsTabs.add(new TabLook());
|
||||||
settingsTabs.add(new TabHotkeys());
|
settingsTabs.add(new TabHotkeys());
|
||||||
settingsTabs.add(new TabHistory());
|
settingsTabs.add(new TabHistory());
|
||||||
settingsTabs.add(new TabComponents());
|
settingsTabs.add(new TabComponents());
|
||||||
|
|
||||||
createResources();
|
createResources();
|
||||||
placeComponents();
|
placeComponents();
|
||||||
setPersistentBehavior();
|
setPersistentBehavior();
|
||||||
|
|
||||||
LocaleDelegate.addLocaleListener(this);
|
LocaleDelegate.addLocaleListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void localeChanged(LocaleEvent event) {
|
@Override public void localeChanged(LocaleEvent event) {
|
||||||
// for (SettingsTab tab : settingsTabs) {
|
// for (SettingsTab tab : settingsTabs) {
|
||||||
// tab.processLocaleEvent(event);
|
// tab.processLocaleEvent(event);
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// MÉTHODES
|
// MÉTHODES
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instanciation des sous-composants utilisés par cette boîte de dialogue.
|
* Instanciation des sous-composants utilisés par cette boîte de dialogue.
|
||||||
*/
|
*/
|
||||||
private void createResources() {
|
private void createResources() {
|
||||||
reset = new JButton("" + Language.setting_hotkey_reset);
|
reset = new JButton("" + Language.setting_hotkey_reset);
|
||||||
actionOK = new JButton(Language.ACCEPT.get());
|
actionOK = new JButton(Language.ACCEPT.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dispose les sous-composants au sein de ce panneau. Les sous-composants
|
* Dispose les sous-composants au sein de ce panneau. Les sous-composants
|
||||||
* sont placés à l’aide d’un {@link GridBagLayout} dont l’accès est
|
* sont placés à l’aide d’un {@link GridBagLayout} dont l’accès est
|
||||||
* simplifié par la classe-proxy {@link GBC}.
|
* simplifié par la classe-proxy {@link GBC}.
|
||||||
*/
|
*/
|
||||||
private void placeComponents() {
|
private void placeComponents() {
|
||||||
setLayout(new GridBagLayout());
|
setLayout(new GridBagLayout());
|
||||||
|
|
||||||
JTabbedPane tabPane = new JTabbedPane(); {
|
|
||||||
for (SettingsTab tab : settingsTabs) {
|
|
||||||
tabPane.add(tab.toString(), tab);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
JPanel controls = new JPanel(); {
|
|
||||||
controls.add(actionOK);
|
|
||||||
controls.add(reset);
|
|
||||||
}
|
|
||||||
add(tabPane, GBC.grid(0, 0));
|
|
||||||
add(controls, GBC.grid(0, 1).insets(6, 0, 4, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
JTabbedPane tabPane = new JTabbedPane(); {
|
||||||
* Définit le comportement persistant (non sujet aux variations d’états du
|
for (SettingsTab tab : settingsTabs) {
|
||||||
* modèle ou de la configuration de l’application) pour ce composant et
|
tabPane.add(tab.toString(), tab);
|
||||||
* ses sous-composants.
|
}
|
||||||
*/
|
}
|
||||||
private void setPersistentBehavior() {
|
JPanel controls = new JPanel(); {
|
||||||
setResizable(false);
|
controls.add(actionOK);
|
||||||
setTitle(Language.menuItem_settings.get());
|
controls.add(reset);
|
||||||
actionOK.addActionListener(this);
|
}
|
||||||
reset.addActionListener(this);
|
add(tabPane, GBC.grid(0, 0));
|
||||||
addWindowListener(this);
|
add(controls, GBC.grid(0, 1).insets(6, 0, 4, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Définit le comportement persistant (non sujet aux variations d’états du
|
||||||
|
* modèle ou de la configuration de l’application) pour ce composant et
|
||||||
|
* ses sous-composants.
|
||||||
|
*/
|
||||||
|
private void setPersistentBehavior() {
|
||||||
|
setResizable(false);
|
||||||
|
setTitle(Language.menuItem_settings.get());
|
||||||
|
actionOK.addActionListener(this);
|
||||||
|
reset.addActionListener(this);
|
||||||
|
addWindowListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Procédure à invoquer lorsqu’un sous-composant réalise une action. Cela
|
* Procédure à invoquer lorsqu’un sous-composant réalise une action. Cela
|
||||||
* signifie pour nous que l’utilisateur à effectuer un réglage de paramètre.
|
* signifie pour nous que l’utilisateur à effectuer un réglage de paramètre.
|
||||||
*
|
*
|
||||||
* @param evt - l’évènement d’action.
|
* @param evt - l’évènement d’action.
|
||||||
* @see ActionListener
|
* @see ActionListener
|
||||||
*/
|
*/
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
Object source = e.getSource();
|
Object source = e.getSource();
|
||||||
if (source.equals(actionOK)) {
|
if (source.equals(actionOK)) {
|
||||||
for (SettingsTab tab : settingsTabs) {
|
for (SettingsTab tab : settingsTabs) {
|
||||||
tab.doDelayedSettingChange();
|
tab.doDelayedSettingChange();
|
||||||
}
|
}
|
||||||
dispose();
|
dispose();
|
||||||
} else if (source.equals(reset)) {
|
} else if (source.equals(reset)) {
|
||||||
int option = JOptionPane.showConfirmDialog(this,
|
int option = JOptionPane.showConfirmDialog(this,
|
||||||
"" + Language.WARN_RESET_SETTINGS);
|
"" + Language.WARN_RESET_SETTINGS);
|
||||||
if (option == JOptionPane.YES_OPTION) {
|
if (option == JOptionPane.YES_OPTION) {
|
||||||
// Settings.reset();
|
// Settings.reset();
|
||||||
dispose();
|
dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void windowActivated(WindowEvent e) {}
|
@Override public void windowActivated(WindowEvent e) {}
|
||||||
@Override public void windowClosed(WindowEvent e) {}
|
@Override public void windowClosed(WindowEvent e) {}
|
||||||
@Override public void windowDeactivated(WindowEvent e) {}
|
@Override public void windowDeactivated(WindowEvent e) {}
|
||||||
@Override public void windowDeiconified(WindowEvent e) {}
|
@Override public void windowDeiconified(WindowEvent e) {}
|
||||||
@Override public void windowIconified(WindowEvent e) {}
|
@Override public void windowIconified(WindowEvent e) {}
|
||||||
@Override public void windowOpened(WindowEvent e) {}
|
@Override public void windowOpened(WindowEvent e) {}
|
||||||
|
|
||||||
@Override public void windowClosing(WindowEvent e) {
|
@Override public void windowClosing(WindowEvent e) {
|
||||||
for (SettingsTab tab : settingsTabs) {
|
for (SettingsTab tab : settingsTabs) {
|
||||||
tab.doDelayedSettingChange();
|
tab.doDelayedSettingChange();
|
||||||
}
|
}
|
||||||
dispose();
|
dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
package org.fenix.llanfair.dialog;
|
package org.fenix.llanfair.dialog;
|
||||||
|
|
||||||
|
import org.fenix.llanfair.Llanfair;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
import java.awt.event.WindowAdapter;
|
import java.awt.event.WindowAdapter;
|
||||||
import java.awt.event.WindowEvent;
|
import java.awt.event.WindowEvent;
|
||||||
|
|
||||||
import javax.swing.JDialog;
|
|
||||||
|
|
||||||
import org.fenix.llanfair.Llanfair;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LlanfairDialog
|
* LlanfairDialog
|
||||||
*
|
*
|
||||||
|
@ -15,22 +14,22 @@ import org.fenix.llanfair.Llanfair;
|
||||||
*/
|
*/
|
||||||
public class LlanfairDialog extends JDialog {
|
public class LlanfairDialog extends JDialog {
|
||||||
|
|
||||||
// ATTRIBUTS
|
// ATTRIBUTS
|
||||||
|
|
||||||
public void display(boolean lockNativeInputs, final Llanfair llanfair) {
|
public void display(boolean lockNativeInputs, final Llanfair llanfair) {
|
||||||
if (lockNativeInputs) {
|
if (lockNativeInputs) {
|
||||||
llanfair.setIgnoreNativeInputs(true);
|
llanfair.setIgnoreNativeInputs(true);
|
||||||
addWindowListener(new WindowAdapter() {
|
addWindowListener(new WindowAdapter() {
|
||||||
@Override public void windowClosed(WindowEvent e) {
|
@Override public void windowClosed(WindowEvent e) {
|
||||||
llanfair.setIgnoreNativeInputs(false);
|
llanfair.setIgnoreNativeInputs(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
setAlwaysOnTop(true);
|
setAlwaysOnTop(true);
|
||||||
setModalityType(ModalityType.APPLICATION_MODAL);
|
setModalityType(ModalityType.APPLICATION_MODAL);
|
||||||
pack();
|
pack();
|
||||||
setLocationRelativeTo(getOwner());
|
setLocationRelativeTo(getOwner());
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +1,43 @@
|
||||||
package org.fenix.llanfair.dialog;
|
package org.fenix.llanfair.dialog;
|
||||||
|
|
||||||
|
import org.fenix.llanfair.config.Settings;
|
||||||
|
import org.fenix.utils.gui.LinkedCheckBox;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
import java.awt.event.ItemEvent;
|
import java.awt.event.ItemEvent;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.swing.JPanel;
|
|
||||||
import org.fenix.llanfair.Language;
|
|
||||||
import org.fenix.llanfair.config.Settings;
|
|
||||||
import org.fenix.utils.gui.LinkedCheckBox;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Xavier "Xunkar" Sencert
|
* @author Xavier "Xunkar" Sencert
|
||||||
*/
|
*/
|
||||||
abstract class SettingsTab extends JPanel {
|
abstract class SettingsTab extends JPanel {
|
||||||
|
|
||||||
protected Map<String, SCheckBox> checkBoxes;
|
|
||||||
|
|
||||||
protected SettingsTab() {
|
|
||||||
checkBoxes = new HashMap<String, SCheckBox>();
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract void doDelayedSettingChange();
|
|
||||||
|
|
||||||
protected class SCheckBox extends LinkedCheckBox {
|
|
||||||
|
|
||||||
private Settings.Property<Boolean> setting;
|
|
||||||
|
|
||||||
SCheckBox(Settings.Property<Boolean> setting) {
|
|
||||||
super();
|
|
||||||
this.setting = setting;
|
|
||||||
setText("" + setting);
|
|
||||||
setSelected(setting.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void itemStateChanged(ItemEvent e) {
|
protected Map<String, SCheckBox> checkBoxes;
|
||||||
super.itemStateChanged(e);
|
|
||||||
setting.set(isSelected());
|
protected SettingsTab() {
|
||||||
}
|
checkBoxes = new HashMap<String, SCheckBox>();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
abstract void doDelayedSettingChange();
|
||||||
|
|
||||||
|
protected class SCheckBox extends LinkedCheckBox {
|
||||||
|
|
||||||
|
private Settings.Property<Boolean> setting;
|
||||||
|
|
||||||
|
SCheckBox(Settings.Property<Boolean> setting) {
|
||||||
|
super();
|
||||||
|
this.setting = setting;
|
||||||
|
setText("" + setting);
|
||||||
|
setSelected(setting.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void itemStateChanged(ItemEvent e) {
|
||||||
|
super.itemStateChanged(e);
|
||||||
|
setting.set(isSelected());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,242 +1,232 @@
|
||||||
package org.fenix.llanfair.dialog;
|
package org.fenix.llanfair.dialog;
|
||||||
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.Font;
|
|
||||||
import java.awt.GraphicsEnvironment;
|
|
||||||
import java.awt.GridBagLayout;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JComboBox;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JSpinner;
|
|
||||||
import javax.swing.SpinnerNumberModel;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
|
|
||||||
import org.fenix.llanfair.Language;
|
import org.fenix.llanfair.Language;
|
||||||
import org.fenix.llanfair.Segment;
|
import org.fenix.llanfair.Segment;
|
||||||
import org.fenix.llanfair.config.Settings;
|
import org.fenix.llanfair.config.Settings;
|
||||||
import org.fenix.utils.gui.GBC;
|
import org.fenix.utils.gui.GBC;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.event.ChangeEvent;
|
||||||
|
import javax.swing.event.ChangeListener;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Xavier "Xunkar" Sencert
|
* @author Xavier "Xunkar" Sencert
|
||||||
*/
|
*/
|
||||||
public class TabComponents extends SettingsTab
|
public class TabComponents extends SettingsTab
|
||||||
implements ActionListener, ChangeListener {
|
implements ActionListener, ChangeListener {
|
||||||
|
|
||||||
private static final List<Settings.Property<Boolean>> SCB_SETTINGS
|
|
||||||
= new ArrayList<Settings.Property<Boolean>>();
|
|
||||||
static {
|
|
||||||
SCB_SETTINGS.add(Settings.FOO_SHOW);
|
|
||||||
SCB_SETTINGS.add(Settings.FOO_SPLT);
|
|
||||||
SCB_SETTINGS.add(Settings.FOO_DLBL);
|
|
||||||
SCB_SETTINGS.add(Settings.FOO_BEST);
|
|
||||||
SCB_SETTINGS.add(Settings.FOO_LINE);
|
|
||||||
SCB_SETTINGS.add(Settings.FOO_VERB);
|
|
||||||
SCB_SETTINGS.add(Settings.COR_NAME);
|
|
||||||
SCB_SETTINGS.add(Settings.COR_SPLT);
|
|
||||||
SCB_SETTINGS.add(Settings.COR_SEGM);
|
|
||||||
SCB_SETTINGS.add(Settings.COR_BEST);
|
|
||||||
SCB_SETTINGS.add(Settings.HDR_GOAL);
|
|
||||||
SCB_SETTINGS.add(Settings.GPH_SHOW);
|
|
||||||
SCB_SETTINGS.add(Settings.COR_STMR);
|
|
||||||
SCB_SETTINGS.add(Settings.COR_ICON);
|
|
||||||
SCB_SETTINGS.add(Settings.HDR_TTLE);
|
|
||||||
};
|
|
||||||
|
|
||||||
private JComboBox iconSizes;
|
|
||||||
|
|
||||||
private JComboBox timerFont;
|
|
||||||
|
|
||||||
private JSpinner timerSize;
|
|
||||||
|
|
||||||
private JComboBox timerSegFont;
|
|
||||||
|
|
||||||
private JSpinner timerSegSize;
|
|
||||||
|
|
||||||
private JCheckBox timerSameFont;
|
|
||||||
|
|
||||||
TabComponents() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
for (Settings.Property<Boolean> setting : SCB_SETTINGS) {
|
|
||||||
checkBoxes.put(setting.getKey(), new SCheckBox(setting));
|
|
||||||
}
|
|
||||||
// Checkboxes side effects
|
|
||||||
checkBoxes.get(Settings.FOO_SPLT.getKey()).deactivates(
|
|
||||||
checkBoxes.get(Settings.FOO_BEST.getKey())
|
|
||||||
);
|
|
||||||
// Checkboxes requirements
|
|
||||||
checkBoxes.get(Settings.FOO_BEST.getKey()).requires(
|
|
||||||
checkBoxes.get(Settings.FOO_SPLT.getKey()), false
|
|
||||||
);
|
|
||||||
checkBoxes.get(Settings.FOO_LINE.getKey()).requires(
|
|
||||||
checkBoxes.get(Settings.FOO_BEST.getKey()), true
|
|
||||||
);
|
|
||||||
|
|
||||||
iconSizes = new JComboBox(Segment.ICON_SIZES);
|
|
||||||
iconSizes.setSelectedItem(Settings.COR_ICSZ.get());
|
|
||||||
iconSizes.addActionListener(this);
|
|
||||||
|
|
||||||
GraphicsEnvironment gEnv = GraphicsEnvironment
|
private static final List<Settings.Property<Boolean>> SCB_SETTINGS
|
||||||
.getLocalGraphicsEnvironment();
|
= new ArrayList<Settings.Property<Boolean>>();
|
||||||
String mainFont = Settings.COR_TFNT.get().getName();
|
static {
|
||||||
timerFont = new JComboBox(gEnv.getAvailableFontFamilyNames());
|
SCB_SETTINGS.add(Settings.FOO_SHOW);
|
||||||
timerFont.setSelectedItem(mainFont);
|
SCB_SETTINGS.add(Settings.FOO_SPLT);
|
||||||
timerFont.setPreferredSize(new Dimension(130, 22));
|
SCB_SETTINGS.add(Settings.FOO_DLBL);
|
||||||
timerFont.addActionListener(this);
|
SCB_SETTINGS.add(Settings.FOO_BEST);
|
||||||
|
SCB_SETTINGS.add(Settings.FOO_LINE);
|
||||||
String segFont = Settings.COR_SFNT.get().getName();
|
SCB_SETTINGS.add(Settings.FOO_VERB);
|
||||||
timerSegFont = new JComboBox(gEnv.getAvailableFontFamilyNames());
|
SCB_SETTINGS.add(Settings.COR_NAME);
|
||||||
timerSegFont.setSelectedItem(segFont);
|
SCB_SETTINGS.add(Settings.COR_SPLT);
|
||||||
timerSegFont.setPreferredSize(new Dimension(130, 22));
|
SCB_SETTINGS.add(Settings.COR_SEGM);
|
||||||
timerSegFont.addActionListener(this);
|
SCB_SETTINGS.add(Settings.COR_BEST);
|
||||||
|
SCB_SETTINGS.add(Settings.HDR_GOAL);
|
||||||
timerSize = new JSpinner(new SpinnerNumberModel(
|
SCB_SETTINGS.add(Settings.GPH_SHOW);
|
||||||
Settings.COR_TFNT.get().getSize(), 8, 240, 1)
|
SCB_SETTINGS.add(Settings.COR_STMR);
|
||||||
);
|
SCB_SETTINGS.add(Settings.COR_ICON);
|
||||||
timerSize.addChangeListener(this);
|
SCB_SETTINGS.add(Settings.HDR_TTLE);
|
||||||
|
}
|
||||||
timerSegSize = new JSpinner(new SpinnerNumberModel(
|
|
||||||
Settings.COR_SFNT.get().getSize(), 8, 240, 1)
|
private JComboBox iconSizes;
|
||||||
);
|
|
||||||
timerSegSize.addChangeListener(this);
|
private JComboBox timerFont;
|
||||||
|
|
||||||
timerSameFont = new JCheckBox("" + Language.USE_MAIN_FONT);
|
private JSpinner timerSize;
|
||||||
timerSameFont.setSelected(segFont.equals(mainFont));
|
|
||||||
timerSegFont.setEnabled(!timerSameFont.isSelected());
|
private JComboBox timerSegFont;
|
||||||
timerSameFont.addActionListener(this);
|
|
||||||
|
private JSpinner timerSegSize;
|
||||||
place();
|
|
||||||
}
|
private JCheckBox timerSameFont;
|
||||||
|
|
||||||
// -------------------------------------------------------------- CALLBACKS
|
TabComponents() {
|
||||||
|
super();
|
||||||
@Override public void actionPerformed(ActionEvent event) {
|
|
||||||
Object source = event.getSource();
|
for (Settings.Property<Boolean> setting : SCB_SETTINGS) {
|
||||||
if (source.equals(iconSizes)) {
|
checkBoxes.put(setting.getKey(), new SCheckBox(setting));
|
||||||
Settings.COR_ICSZ.set((Integer) iconSizes.getSelectedItem());
|
}
|
||||||
} else if (source.equals(timerFont)) {
|
// Checkboxes side effects
|
||||||
String fontName = timerFont.getSelectedItem().toString();
|
checkBoxes.get(Settings.FOO_SPLT.getKey()).deactivates(
|
||||||
Font font = Font.decode(fontName).deriveFont(
|
checkBoxes.get(Settings.FOO_BEST.getKey())
|
||||||
(float) Settings.COR_TFNT.get().getSize()
|
);
|
||||||
);
|
// Checkboxes requirements
|
||||||
Settings.COR_TFNT.set(font);
|
checkBoxes.get(Settings.FOO_BEST.getKey()).requires(
|
||||||
if (timerSameFont.isSelected()) {
|
checkBoxes.get(Settings.FOO_SPLT.getKey()), false
|
||||||
timerSegFont.setSelectedItem(fontName);
|
);
|
||||||
}
|
checkBoxes.get(Settings.FOO_LINE.getKey()).requires(
|
||||||
} else if (source.equals(timerSegFont)) {
|
checkBoxes.get(Settings.FOO_BEST.getKey()), true
|
||||||
String fontName = timerSegFont.getSelectedItem().toString();
|
);
|
||||||
Font font = Font.decode(fontName).deriveFont(
|
|
||||||
(float) Settings.COR_SFNT.get().getSize()
|
iconSizes = new JComboBox(Segment.ICON_SIZES);
|
||||||
);
|
iconSizes.setSelectedItem(Settings.COR_ICSZ.get());
|
||||||
Settings.COR_SFNT.set(font);
|
iconSizes.addActionListener(this);
|
||||||
} else if (source.equals(timerSameFont)) {
|
|
||||||
timerSegFont.setEnabled(!timerSameFont.isSelected());
|
GraphicsEnvironment gEnv = GraphicsEnvironment
|
||||||
if (timerSameFont.isSelected()) {
|
.getLocalGraphicsEnvironment();
|
||||||
int size = (Integer) timerSegSize.getValue();
|
String mainFont = Settings.COR_TFNT.get().getName();
|
||||||
Settings.COR_SFNT.set(
|
timerFont = new JComboBox(gEnv.getAvailableFontFamilyNames());
|
||||||
Settings.COR_TFNT.get().deriveFont((float) size)
|
timerFont.setSelectedItem(mainFont);
|
||||||
);
|
timerFont.setPreferredSize(new Dimension(130, 22));
|
||||||
}
|
timerFont.addActionListener(this);
|
||||||
}
|
|
||||||
}
|
String segFont = Settings.COR_SFNT.get().getName();
|
||||||
|
timerSegFont = new JComboBox(gEnv.getAvailableFontFamilyNames());
|
||||||
@Override public void stateChanged(ChangeEvent event) {
|
timerSegFont.setSelectedItem(segFont);
|
||||||
Object source = event.getSource();
|
timerSegFont.setPreferredSize(new Dimension(130, 22));
|
||||||
if (source.equals(timerSize)) {
|
timerSegFont.addActionListener(this);
|
||||||
int size = (Integer) timerSize.getValue();
|
|
||||||
Settings.COR_TFNT.set(
|
timerSize = new JSpinner(new SpinnerNumberModel(
|
||||||
Settings.COR_TFNT.get().deriveFont((float) size)
|
Settings.COR_TFNT.get().getSize(), 8, 240, 1)
|
||||||
);
|
);
|
||||||
} else if (source.equals(timerSegSize)) {
|
timerSize.addChangeListener(this);
|
||||||
int size = (Integer) timerSegSize.getValue();
|
|
||||||
Settings.COR_SFNT.set(
|
timerSegSize = new JSpinner(new SpinnerNumberModel(
|
||||||
Settings.COR_SFNT.get().deriveFont((float) size)
|
Settings.COR_SFNT.get().getSize(), 8, 240, 1)
|
||||||
);
|
);
|
||||||
}
|
timerSegSize.addChangeListener(this);
|
||||||
}
|
|
||||||
|
timerSameFont = new JCheckBox("" + Language.USE_MAIN_FONT);
|
||||||
// -------------------------------------------------------------- INHERITED
|
timerSameFont.setSelected(segFont.equals(mainFont));
|
||||||
|
timerSegFont.setEnabled(!timerSameFont.isSelected());
|
||||||
@Override void doDelayedSettingChange() {}
|
timerSameFont.addActionListener(this);
|
||||||
|
|
||||||
@Override public String toString() {
|
place();
|
||||||
return "" + Language.COMPONENTS;
|
}
|
||||||
}
|
|
||||||
|
// -------------------------------------------------------------- CALLBACKS
|
||||||
// -------------------------------------------------------------- UTILITIES
|
|
||||||
|
@Override public void actionPerformed(ActionEvent event) {
|
||||||
private void place() {
|
Object source = event.getSource();
|
||||||
setLayout(new GridBagLayout());
|
if (source.equals(iconSizes)) {
|
||||||
|
Settings.COR_ICSZ.set((Integer) iconSizes.getSelectedItem());
|
||||||
JPanel fontPanel = new JPanel(new GridBagLayout()); {
|
} else if (source.equals(timerFont)) {
|
||||||
fontPanel.add(
|
String fontName = timerFont.getSelectedItem().toString();
|
||||||
new JLabel("" + Language.setting_core_timerFont),
|
Font font = Font.decode(fontName).deriveFont(
|
||||||
GBC.grid(0, 0).anchor(GBC.LS).insets(0, 5)
|
(float) Settings.COR_TFNT.get().getSize()
|
||||||
);
|
);
|
||||||
fontPanel.add(timerFont, GBC.grid(1, 0));
|
Settings.COR_TFNT.set(font);
|
||||||
fontPanel.add(timerSize, GBC.grid(2, 0).insets(0, 5));
|
if (timerSameFont.isSelected()) {
|
||||||
fontPanel.add(
|
timerSegFont.setSelectedItem(fontName);
|
||||||
new JLabel("" + Language.setting_core_segmentTimerFont),
|
}
|
||||||
GBC.grid(0, 1).anchor(GBC.LS).insets(3, 5)
|
} else if (source.equals(timerSegFont)) {
|
||||||
);
|
String fontName = timerSegFont.getSelectedItem().toString();
|
||||||
fontPanel.add(
|
Font font = Font.decode(fontName).deriveFont(
|
||||||
timerSameFont,
|
(float) Settings.COR_SFNT.get().getSize()
|
||||||
GBC.grid(1, 1, 2, 1).anchor(GBC.LS).insets(3, 0)
|
);
|
||||||
);
|
Settings.COR_SFNT.set(font);
|
||||||
fontPanel.add(timerSegFont, GBC.grid(1, 2));
|
} else if (source.equals(timerSameFont)) {
|
||||||
fontPanel.add(timerSegSize, GBC.grid(2, 2).insets(0, 5));
|
timerSegFont.setEnabled(!timerSameFont.isSelected());
|
||||||
fontPanel.setBorder(
|
if (timerSameFont.isSelected()) {
|
||||||
BorderFactory.createTitledBorder("" + Language.PN_FONTS)
|
int size = (Integer) timerSegSize.getValue();
|
||||||
);
|
Settings.COR_SFNT.set(
|
||||||
}
|
Settings.COR_TFNT.get().deriveFont((float) size)
|
||||||
JPanel timerPanel = new JPanel(new GridBagLayout()); {
|
);
|
||||||
timerPanel.add(
|
}
|
||||||
new JLabel("" + Language.setting_core_iconSize),
|
}
|
||||||
GBC.grid(0, 1).anchor(GBC.LE).insets(5, 5)
|
}
|
||||||
);
|
|
||||||
timerPanel.add(iconSizes, GBC.grid(1, 1).insets(5, 5));
|
@Override public void stateChanged(ChangeEvent event) {
|
||||||
timerPanel.add(checkBoxes.get(Settings.COR_ICON.getKey()), GBC.grid(0, 2, 2, 1).anchor(GBC.LS));
|
Object source = event.getSource();
|
||||||
timerPanel.add(checkBoxes.get(Settings.COR_NAME.getKey()), GBC.grid(0, 3, 2, 1).anchor(GBC.LS));
|
if (source.equals(timerSize)) {
|
||||||
timerPanel.add(checkBoxes.get(Settings.COR_SPLT.getKey()), GBC.grid(0, 4, 2, 1).anchor(GBC.LS));
|
int size = (Integer) timerSize.getValue();
|
||||||
timerPanel.add(checkBoxes.get(Settings.COR_SEGM.getKey()), GBC.grid(0, 5, 2, 1).anchor(GBC.LS));
|
Settings.COR_TFNT.set(
|
||||||
timerPanel.add(checkBoxes.get(Settings.COR_BEST.getKey()), GBC.grid(0, 6, 2, 1).anchor(GBC.LS));
|
Settings.COR_TFNT.get().deriveFont((float) size)
|
||||||
timerPanel.add(checkBoxes.get(Settings.COR_STMR.getKey()), GBC.grid(0, 7, 2, 1).anchor(GBC.LS));
|
);
|
||||||
timerPanel.setBorder(
|
} else if (source.equals(timerSegSize)) {
|
||||||
BorderFactory.createTitledBorder("" + Language.TIMER)
|
int size = (Integer) timerSegSize.getValue();
|
||||||
);
|
Settings.COR_SFNT.set(
|
||||||
}
|
Settings.COR_SFNT.get().deriveFont((float) size)
|
||||||
JPanel footerPanel = new JPanel(new GridBagLayout()); {
|
);
|
||||||
footerPanel.add(checkBoxes.get(Settings.FOO_SHOW.getKey()), GBC.grid(0, 0).anchor(GBC.LS));
|
}
|
||||||
footerPanel.add(checkBoxes.get(Settings.FOO_SPLT.getKey()), GBC.grid(0, 1).anchor(GBC.LS));
|
}
|
||||||
footerPanel.add(checkBoxes.get(Settings.FOO_VERB.getKey()), GBC.grid(0, 2).anchor(GBC.LS));
|
|
||||||
footerPanel.add(checkBoxes.get(Settings.FOO_DLBL.getKey()), GBC.grid(1, 0).anchor(GBC.LS));
|
// -------------------------------------------------------------- INHERITED
|
||||||
footerPanel.add(checkBoxes.get(Settings.FOO_BEST.getKey()), GBC.grid(1, 1).anchor(GBC.LS));
|
|
||||||
footerPanel.add(checkBoxes.get(Settings.FOO_LINE.getKey()), GBC.grid(1, 2).anchor(GBC.LS));
|
@Override void doDelayedSettingChange() {}
|
||||||
footerPanel.setBorder(
|
|
||||||
BorderFactory.createTitledBorder("" + Language.FOOTER)
|
@Override public String toString() {
|
||||||
);
|
return "" + Language.COMPONENTS;
|
||||||
}
|
}
|
||||||
JPanel miscPanel = new JPanel(new GridBagLayout()); {
|
|
||||||
miscPanel.add(checkBoxes.get(Settings.HDR_TTLE.getKey()), GBC.grid(0, 0).anchor(GBC.LS));
|
// -------------------------------------------------------------- UTILITIES
|
||||||
miscPanel.add(checkBoxes.get(Settings.HDR_GOAL.getKey()), GBC.grid(0, 1).anchor(GBC.LS));
|
|
||||||
miscPanel.add(checkBoxes.get(Settings.GPH_SHOW.getKey()), GBC.grid(0, 2).anchor(GBC.LS));
|
private void place() {
|
||||||
miscPanel.setBorder(
|
setLayout(new GridBagLayout());
|
||||||
BorderFactory.createTitledBorder("" + Language.MISC)
|
|
||||||
);
|
JPanel fontPanel = new JPanel(new GridBagLayout()); {
|
||||||
}
|
fontPanel.add(
|
||||||
add(fontPanel, GBC.grid(0, 0, 2, 1).fill(GBC.B).anchor(GBC.FLS));
|
new JLabel("" + Language.setting_core_timerFont),
|
||||||
add(timerPanel, GBC.grid(2, 0, 1, 2).fill(GBC.B).anchor(GBC.FLS));
|
GBC.grid(0, 0).anchor(GBC.LS).insets(0, 5)
|
||||||
add(footerPanel, GBC.grid(0, 1).fill(GBC.B).anchor(GBC.FLS));
|
);
|
||||||
add(miscPanel, GBC.grid(1, 1).fill(GBC.B).anchor(GBC.FLS));
|
fontPanel.add(timerFont, GBC.grid(1, 0));
|
||||||
}
|
fontPanel.add(timerSize, GBC.grid(2, 0).insets(0, 5));
|
||||||
|
fontPanel.add(
|
||||||
|
new JLabel("" + Language.setting_core_segmentTimerFont),
|
||||||
|
GBC.grid(0, 1).anchor(GBC.LS).insets(3, 5)
|
||||||
|
);
|
||||||
|
fontPanel.add(
|
||||||
|
timerSameFont,
|
||||||
|
GBC.grid(1, 1, 2, 1).anchor(GBC.LS).insets(3, 0)
|
||||||
|
);
|
||||||
|
fontPanel.add(timerSegFont, GBC.grid(1, 2));
|
||||||
|
fontPanel.add(timerSegSize, GBC.grid(2, 2).insets(0, 5));
|
||||||
|
fontPanel.setBorder(
|
||||||
|
BorderFactory.createTitledBorder("" + Language.PN_FONTS)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
JPanel timerPanel = new JPanel(new GridBagLayout()); {
|
||||||
|
timerPanel.add(
|
||||||
|
new JLabel("" + Language.setting_core_iconSize),
|
||||||
|
GBC.grid(0, 1).anchor(GBC.LE).insets(5, 5)
|
||||||
|
);
|
||||||
|
timerPanel.add(iconSizes, GBC.grid(1, 1).insets(5, 5));
|
||||||
|
timerPanel.add(checkBoxes.get(Settings.COR_ICON.getKey()), GBC.grid(0, 2, 2, 1).anchor(GBC.LS));
|
||||||
|
timerPanel.add(checkBoxes.get(Settings.COR_NAME.getKey()), GBC.grid(0, 3, 2, 1).anchor(GBC.LS));
|
||||||
|
timerPanel.add(checkBoxes.get(Settings.COR_SPLT.getKey()), GBC.grid(0, 4, 2, 1).anchor(GBC.LS));
|
||||||
|
timerPanel.add(checkBoxes.get(Settings.COR_SEGM.getKey()), GBC.grid(0, 5, 2, 1).anchor(GBC.LS));
|
||||||
|
timerPanel.add(checkBoxes.get(Settings.COR_BEST.getKey()), GBC.grid(0, 6, 2, 1).anchor(GBC.LS));
|
||||||
|
timerPanel.add(checkBoxes.get(Settings.COR_STMR.getKey()), GBC.grid(0, 7, 2, 1).anchor(GBC.LS));
|
||||||
|
timerPanel.setBorder(
|
||||||
|
BorderFactory.createTitledBorder("" + Language.TIMER)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
JPanel footerPanel = new JPanel(new GridBagLayout()); {
|
||||||
|
footerPanel.add(checkBoxes.get(Settings.FOO_SHOW.getKey()), GBC.grid(0, 0).anchor(GBC.LS));
|
||||||
|
footerPanel.add(checkBoxes.get(Settings.FOO_SPLT.getKey()), GBC.grid(0, 1).anchor(GBC.LS));
|
||||||
|
footerPanel.add(checkBoxes.get(Settings.FOO_VERB.getKey()), GBC.grid(0, 2).anchor(GBC.LS));
|
||||||
|
footerPanel.add(checkBoxes.get(Settings.FOO_DLBL.getKey()), GBC.grid(1, 0).anchor(GBC.LS));
|
||||||
|
footerPanel.add(checkBoxes.get(Settings.FOO_BEST.getKey()), GBC.grid(1, 1).anchor(GBC.LS));
|
||||||
|
footerPanel.add(checkBoxes.get(Settings.FOO_LINE.getKey()), GBC.grid(1, 2).anchor(GBC.LS));
|
||||||
|
footerPanel.setBorder(
|
||||||
|
BorderFactory.createTitledBorder("" + Language.FOOTER)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
JPanel miscPanel = new JPanel(new GridBagLayout()); {
|
||||||
|
miscPanel.add(checkBoxes.get(Settings.HDR_TTLE.getKey()), GBC.grid(0, 0).anchor(GBC.LS));
|
||||||
|
miscPanel.add(checkBoxes.get(Settings.HDR_GOAL.getKey()), GBC.grid(0, 1).anchor(GBC.LS));
|
||||||
|
miscPanel.add(checkBoxes.get(Settings.GPH_SHOW.getKey()), GBC.grid(0, 2).anchor(GBC.LS));
|
||||||
|
miscPanel.setBorder(
|
||||||
|
BorderFactory.createTitledBorder("" + Language.MISC)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
add(fontPanel, GBC.grid(0, 0, 2, 1).fill(GBC.B).anchor(GBC.FLS));
|
||||||
|
add(timerPanel, GBC.grid(2, 0, 1, 2).fill(GBC.B).anchor(GBC.FLS));
|
||||||
|
add(footerPanel, GBC.grid(0, 1).fill(GBC.B).anchor(GBC.FLS));
|
||||||
|
add(miscPanel, GBC.grid(1, 1).fill(GBC.B).anchor(GBC.FLS));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,191 +1,179 @@
|
||||||
package org.fenix.llanfair.dialog;
|
package org.fenix.llanfair.dialog;
|
||||||
|
|
||||||
import java.awt.Component;
|
import org.fenix.llanfair.Language;
|
||||||
import java.awt.GridBagLayout;
|
import org.fenix.llanfair.Llanfair;
|
||||||
import java.awt.GridLayout;
|
import org.fenix.llanfair.config.Accuracy;
|
||||||
|
import org.fenix.llanfair.config.Compare;
|
||||||
|
import org.fenix.llanfair.config.Settings;
|
||||||
|
import org.fenix.utils.gui.GBC;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import javax.swing.AbstractButton;
|
|
||||||
import javax.swing.ButtonGroup;
|
|
||||||
import javax.swing.DefaultListCellRenderer;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JComboBox;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JList;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JRadioButton;
|
|
||||||
|
|
||||||
import org.fenix.llanfair.Language;
|
|
||||||
import org.fenix.llanfair.Llanfair;
|
|
||||||
import org.fenix.llanfair.config.Settings;
|
|
||||||
import org.fenix.llanfair.config.Compare;
|
|
||||||
import org.fenix.llanfair.config.Accuracy;
|
|
||||||
import org.fenix.utils.gui.GBC;
|
|
||||||
import org.fenix.utils.Resources;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Xavier "Xunkar" Sencert
|
* @author Xavier "Xunkar" Sencert
|
||||||
*/
|
*/
|
||||||
public class TabGeneral extends SettingsTab implements ActionListener {
|
public class TabGeneral extends SettingsTab implements ActionListener {
|
||||||
|
|
||||||
// ------------------------------------------------------------- ATTRIBUTES
|
// ------------------------------------------------------------- ATTRIBUTES
|
||||||
|
|
||||||
private JComboBox language;
|
private JComboBox language;
|
||||||
|
|
||||||
private JLabel languageText;
|
private JLabel languageText;
|
||||||
|
|
||||||
private JCheckBox alwaysOnTop;
|
private JCheckBox alwaysOnTop;
|
||||||
|
|
||||||
private JLabel alwaysOnTopText;
|
private JLabel alwaysOnTopText;
|
||||||
|
|
||||||
private ButtonGroup compare;
|
private ButtonGroup compare;
|
||||||
|
|
||||||
private JLabel compareText;
|
private JLabel compareText;
|
||||||
|
|
||||||
private ButtonGroup accuracy;
|
private ButtonGroup accuracy;
|
||||||
|
|
||||||
private JLabel accuracyText;
|
private JLabel accuracyText;
|
||||||
|
|
||||||
private JCheckBox warnOnReset;
|
private JCheckBox warnOnReset;
|
||||||
|
|
||||||
// ----------------------------------------------------------- CONSTRUCTORS
|
// ----------------------------------------------------------- CONSTRUCTORS
|
||||||
|
|
||||||
TabGeneral() {
|
TabGeneral() {
|
||||||
language = new JComboBox(Language.LANGUAGES);
|
language = new JComboBox(Language.LANGUAGES);
|
||||||
language.setRenderer(new LocaleListRenderer());
|
language.setRenderer(new LocaleListRenderer());
|
||||||
language.setSelectedItem(Settings.GNR_LANG.get());
|
language.setSelectedItem(Settings.GNR_LANG.get());
|
||||||
language.addActionListener(this);
|
language.addActionListener(this);
|
||||||
|
|
||||||
alwaysOnTop = new JCheckBox("" + Language.setting_alwaysOnTop);
|
alwaysOnTop = new JCheckBox("" + Language.setting_alwaysOnTop);
|
||||||
alwaysOnTop.setSelected(Settings.GNR_ATOP.get());
|
alwaysOnTop.setSelected(Settings.GNR_ATOP.get());
|
||||||
|
|
||||||
compare = new ButtonGroup();
|
compare = new ButtonGroup();
|
||||||
Compare setCmp = Settings.GNR_COMP.get();
|
Compare setCmp = Settings.GNR_COMP.get();
|
||||||
for (Compare method : Compare.values()) {
|
for (Compare method : Compare.values()) {
|
||||||
JRadioButton radio = new JRadioButton("" + method);
|
JRadioButton radio = new JRadioButton("" + method);
|
||||||
radio.setName(method.name());
|
radio.setName(method.name());
|
||||||
radio.setSelected(setCmp == method);
|
radio.setSelected(setCmp == method);
|
||||||
radio.addActionListener(this);
|
radio.addActionListener(this);
|
||||||
compare.add(radio);
|
compare.add(radio);
|
||||||
}
|
}
|
||||||
|
|
||||||
accuracy = new ButtonGroup();
|
accuracy = new ButtonGroup();
|
||||||
Accuracy setAcc = Settings.GNR_ACCY.get();
|
Accuracy setAcc = Settings.GNR_ACCY.get();
|
||||||
for (Accuracy value : Accuracy.values()) {
|
for (Accuracy value : Accuracy.values()) {
|
||||||
JRadioButton radio = new JRadioButton("" + value);
|
JRadioButton radio = new JRadioButton("" + value);
|
||||||
radio.setName(value.name());
|
radio.setName(value.name());
|
||||||
radio.setSelected(setAcc == value);
|
radio.setSelected(setAcc == value);
|
||||||
radio.addActionListener(this);
|
radio.addActionListener(this);
|
||||||
accuracy.add(radio);
|
accuracy.add(radio);
|
||||||
}
|
}
|
||||||
|
|
||||||
warnOnReset = new JCheckBox("" + Language.setting_warnOnReset);
|
warnOnReset = new JCheckBox("" + Language.setting_warnOnReset);
|
||||||
warnOnReset.setSelected(Settings.GNR_WARN.get());
|
warnOnReset.setSelected(Settings.GNR_WARN.get());
|
||||||
warnOnReset.addActionListener(this);
|
warnOnReset.addActionListener(this);
|
||||||
|
|
||||||
languageText = new JLabel("" + Language.setting_language);
|
languageText = new JLabel("" + Language.setting_language);
|
||||||
alwaysOnTopText = new JLabel("" + Language.APPLICATION);
|
alwaysOnTopText = new JLabel("" + Language.APPLICATION);
|
||||||
compareText = new JLabel("" + Language.COMPARE_METHOD);
|
compareText = new JLabel("" + Language.COMPARE_METHOD);
|
||||||
accuracyText = new JLabel("" + Language.ACCURACY);
|
accuracyText = new JLabel("" + Language.ACCURACY);
|
||||||
|
|
||||||
place();
|
place();
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------- CALLBACKS
|
// -------------------------------------------------------------- CALLBACKS
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent event) {
|
public void actionPerformed(ActionEvent event) {
|
||||||
Object source = event.getSource();
|
Object source = event.getSource();
|
||||||
if (source.equals(language)) {
|
if (source.equals(language)) {
|
||||||
Settings.GNR_LANG.set((Locale) language.getSelectedItem());
|
Settings.GNR_LANG.set((Locale) language.getSelectedItem());
|
||||||
} else if (source instanceof JRadioButton) {
|
} else if (source instanceof JRadioButton) {
|
||||||
JRadioButton radio = (JRadioButton) source;
|
JRadioButton radio = (JRadioButton) source;
|
||||||
try {
|
try {
|
||||||
Settings.GNR_COMP.set(
|
Settings.GNR_COMP.set(
|
||||||
Compare.valueOf(radio.getName())
|
Compare.valueOf(radio.getName())
|
||||||
);
|
);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Settings.GNR_ACCY.set(Accuracy.valueOf(radio.getName()));
|
Settings.GNR_ACCY.set(Accuracy.valueOf(radio.getName()));
|
||||||
}
|
}
|
||||||
} else if (source.equals(warnOnReset)) {
|
} else if (source.equals(warnOnReset)) {
|
||||||
Settings.GNR_WARN.set(warnOnReset.isSelected());
|
Settings.GNR_WARN.set(warnOnReset.isSelected());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------- INHERITED
|
// -------------------------------------------------------------- INHERITED
|
||||||
|
|
||||||
void doDelayedSettingChange() {
|
void doDelayedSettingChange() {
|
||||||
Settings.GNR_ATOP.set(alwaysOnTop.isSelected());
|
Settings.GNR_ATOP.set(alwaysOnTop.isSelected());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the localized name of this tab.
|
* Returns the localized name of this tab.
|
||||||
*/
|
*/
|
||||||
@Override public String toString() {
|
@Override public String toString() {
|
||||||
return "" + Language.GENERAL;
|
return "" + Language.GENERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------- UTILITIES
|
// -------------------------------------------------------------- UTILITIES
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Places all sub-components within this panel.
|
* Places all sub-components within this panel.
|
||||||
*/
|
*/
|
||||||
private void place() {
|
private void place() {
|
||||||
setLayout(new GridBagLayout());
|
setLayout(new GridBagLayout());
|
||||||
|
|
||||||
add(
|
add(
|
||||||
alwaysOnTopText, GBC.grid(0, 0).anchor(GBC.LE).insets(5, 10)
|
alwaysOnTopText, GBC.grid(0, 0).anchor(GBC.LE).insets(5, 10)
|
||||||
);
|
);
|
||||||
add(alwaysOnTop, GBC.grid(1, 0).anchor(GBC.LS));
|
add(alwaysOnTop, GBC.grid(1, 0).anchor(GBC.LS));
|
||||||
add(warnOnReset, GBC.grid(1, 1).anchor(GBC.LS));
|
add(warnOnReset, GBC.grid(1, 1).anchor(GBC.LS));
|
||||||
|
|
||||||
add(languageText, GBC.grid(0, 2).anchor(GBC.LE).insets(10, 10));
|
add(languageText, GBC.grid(0, 2).anchor(GBC.LE).insets(10, 10));
|
||||||
add(language, GBC.grid(1, 2).fill(GBC.H));
|
add(language, GBC.grid(1, 2).fill(GBC.H));
|
||||||
|
|
||||||
JPanel comparePanel = new JPanel(new GridLayout(0, 1)); {
|
JPanel comparePanel = new JPanel(new GridLayout(0, 1)); {
|
||||||
Enumeration<AbstractButton> buttons = compare.getElements();
|
Enumeration<AbstractButton> buttons = compare.getElements();
|
||||||
while (buttons.hasMoreElements()) {
|
while (buttons.hasMoreElements()) {
|
||||||
comparePanel.add(buttons.nextElement());
|
comparePanel.add(buttons.nextElement());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
add(compareText, GBC.grid(0, 3).anchor(GBC.FLE).insets(14, 10));
|
add(compareText, GBC.grid(0, 3).anchor(GBC.FLE).insets(14, 10));
|
||||||
add(comparePanel, GBC.grid(1, 3).fill(GBC.H).insets(10, 0, 0, 0));
|
add(comparePanel, GBC.grid(1, 3).fill(GBC.H).insets(10, 0, 0, 0));
|
||||||
|
|
||||||
JPanel accuracyPanel = new JPanel(new GridLayout(0, 1)); {
|
JPanel accuracyPanel = new JPanel(new GridLayout(0, 1)); {
|
||||||
Enumeration<AbstractButton> buttons = accuracy.getElements();
|
Enumeration<AbstractButton> buttons = accuracy.getElements();
|
||||||
while (buttons.hasMoreElements()) {
|
while (buttons.hasMoreElements()) {
|
||||||
accuracyPanel.add(buttons.nextElement());
|
accuracyPanel.add(buttons.nextElement());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
add(accuracyText, GBC.grid(0, 4).anchor(GBC.FLE).insets(14, 10));
|
add(accuracyText, GBC.grid(0, 4).anchor(GBC.FLE).insets(14, 10));
|
||||||
add(accuracyPanel, GBC.grid(1, 4).fill(GBC.H).insets(10, 0));
|
add(accuracyPanel, GBC.grid(1, 4).fill(GBC.H).insets(10, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------- INTERNAL TYPES
|
// --------------------------------------------------------- INTERNAL TYPES
|
||||||
|
|
||||||
class LocaleListRenderer extends DefaultListCellRenderer {
|
class LocaleListRenderer extends DefaultListCellRenderer {
|
||||||
|
|
||||||
public LocaleListRenderer() {
|
public LocaleListRenderer() {
|
||||||
setVerticalAlignment(CENTER);
|
setVerticalAlignment(CENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public Component getListCellRendererComponent(
|
@Override public Component getListCellRendererComponent(
|
||||||
JList list, Object value, int index, boolean isSelected,
|
JList list, Object value, int index, boolean isSelected,
|
||||||
boolean cellHasFocus
|
boolean cellHasFocus
|
||||||
) {
|
) {
|
||||||
super.getListCellRendererComponent(
|
super.getListCellRendererComponent(
|
||||||
list, value, index, isSelected, cellHasFocus
|
list, value, index, isSelected, cellHasFocus
|
||||||
);
|
);
|
||||||
Locale selected = (Locale) value;
|
Locale selected = (Locale) value;
|
||||||
|
|
||||||
setIcon(Llanfair.getResources().getIcon("" + selected));
|
setIcon(Llanfair.getResources().getIcon("" + selected));
|
||||||
setText(Language.LOCALE_NAMES.get("" + selected));
|
setText(Language.LOCALE_NAMES.get("" + selected));
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,348 +1,337 @@
|
||||||
package org.fenix.llanfair.dialog;
|
package org.fenix.llanfair.dialog;
|
||||||
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.Font;
|
|
||||||
import java.awt.GraphicsEnvironment;
|
|
||||||
import java.awt.GridBagLayout;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JComboBox;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JSpinner;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.SpinnerNumberModel;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
|
|
||||||
import org.fenix.llanfair.Language;
|
import org.fenix.llanfair.Language;
|
||||||
import org.fenix.llanfair.Segment;
|
import org.fenix.llanfair.Segment;
|
||||||
import org.fenix.llanfair.config.Settings;
|
|
||||||
import org.fenix.llanfair.config.Merge;
|
import org.fenix.llanfair.config.Merge;
|
||||||
|
import org.fenix.llanfair.config.Settings;
|
||||||
import org.fenix.utils.gui.GBC;
|
import org.fenix.utils.gui.GBC;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.event.ChangeEvent;
|
||||||
|
import javax.swing.event.ChangeListener;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
class TabHistory extends SettingsTab implements ActionListener, ChangeListener {
|
class TabHistory extends SettingsTab implements ActionListener, ChangeListener {
|
||||||
|
|
||||||
// ------------------------------------------------------------- ATTRIBUTES
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Text field allowing the user to edit the height of the history. The
|
|
||||||
* height is provided as a number of segments to display.
|
|
||||||
*/
|
|
||||||
private JTextField rows;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Label displaying the name of the text field {@code height}.
|
|
||||||
*/
|
|
||||||
private JLabel heightText;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Label displaying the unit of the value of the text field {@code height}.
|
|
||||||
*/
|
|
||||||
private JLabel heightUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Combox box displaying the available merging methods, determining which,
|
|
||||||
* if any, column should be merged.
|
|
||||||
*/
|
|
||||||
private JComboBox merge;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check box determining wether or not the history should display the
|
|
||||||
* delta column.
|
|
||||||
*/
|
|
||||||
private JCheckBox deltas;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check box determining wether or not the history should display the
|
|
||||||
* live times column.
|
|
||||||
*/
|
|
||||||
private JCheckBox lives;
|
|
||||||
|
|
||||||
private JCheckBox blankRows;
|
|
||||||
|
|
||||||
private JCheckBox icons;
|
|
||||||
|
|
||||||
private JComboBox iconSize;
|
|
||||||
|
|
||||||
private JCheckBox showLast;
|
|
||||||
|
|
||||||
private JSpinner offset;
|
|
||||||
|
|
||||||
private JLabel offsetHelper;
|
|
||||||
|
|
||||||
private JCheckBox twoLines;
|
|
||||||
|
|
||||||
private JCheckBox tabular;
|
|
||||||
|
|
||||||
private JComboBox nameFont;
|
|
||||||
|
|
||||||
private JSpinner nameSize;
|
|
||||||
|
|
||||||
private JComboBox timeFont;
|
|
||||||
|
|
||||||
private JSpinner timeSize;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------- CONSTRUCTORS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the "History" settings tab. Only called by {@link EditSettings}.
|
|
||||||
*/
|
|
||||||
TabHistory() {
|
|
||||||
rows = new JTextField();
|
|
||||||
rows.setHorizontalAlignment(JTextField.TRAILING);
|
|
||||||
rows.setText("" + Settings.HST_ROWS.get());
|
|
||||||
|
|
||||||
deltas = new JCheckBox("" + Language.setting_history_deltas);
|
|
||||||
deltas.setSelected(Settings.HST_DLTA.get());
|
|
||||||
deltas.addActionListener(this);
|
|
||||||
|
|
||||||
lives = new JCheckBox("" + Language.setting_history_liveTimes);
|
|
||||||
lives.setSelected(Settings.HST_LIVE.get());
|
|
||||||
lives.addActionListener(this);
|
|
||||||
|
|
||||||
twoLines = new JCheckBox("" + Language.setting_history_multiline);
|
|
||||||
twoLines.setSelected(Settings.HST_LINE.get());
|
|
||||||
twoLines.addActionListener(this);
|
|
||||||
|
|
||||||
blankRows = new JCheckBox("" + Language.setting_history_blankRows);
|
|
||||||
blankRows.setSelected(Settings.HST_BLNK.get());
|
|
||||||
blankRows.addActionListener(this);
|
|
||||||
|
|
||||||
icons = new JCheckBox("" + Language.setting_history_icons);
|
|
||||||
icons.setSelected(Settings.HST_ICON.get());
|
|
||||||
icons.addActionListener(this);
|
|
||||||
|
|
||||||
tabular = new JCheckBox("" + Language.setting_history_tabular);
|
|
||||||
tabular.setSelected(Settings.HST_TABL.get());
|
|
||||||
tabular.addActionListener(this);
|
|
||||||
|
|
||||||
showLast = new JCheckBox("" + Language.setting_history_alwaysShowLast);
|
|
||||||
showLast.setSelected(Settings.HST_LAST.get());
|
|
||||||
showLast.addActionListener(this);
|
|
||||||
|
|
||||||
merge = new JComboBox(Merge.values());
|
|
||||||
merge.setSelectedItem(Settings.HST_MERG.get());
|
|
||||||
merge.addActionListener(this);
|
|
||||||
|
|
||||||
iconSize = new JComboBox(Segment.ICON_SIZES);
|
|
||||||
iconSize.setSelectedItem(Settings.HST_ICSZ.get());
|
|
||||||
iconSize.addActionListener(this);
|
|
||||||
|
|
||||||
offset = new JSpinner(new SpinnerNumberModel(
|
|
||||||
(int) Settings.HST_OFFS.get(), -5, 5, 1)
|
|
||||||
);
|
|
||||||
offset.addChangeListener(this);
|
|
||||||
|
|
||||||
offsetHelper = new JLabel("<html>[<a href=''>?</a>]</html>");
|
|
||||||
offsetHelper.setToolTipText(
|
|
||||||
"<html><div width=200>" + Language.TT_HS_OFFSET + "</div></html>"
|
|
||||||
);
|
|
||||||
|
|
||||||
GraphicsEnvironment gEnv = GraphicsEnvironment
|
|
||||||
.getLocalGraphicsEnvironment();
|
|
||||||
String mainFont = Settings.HST_SFNT.get().getName();
|
|
||||||
nameFont = new JComboBox(gEnv.getAvailableFontFamilyNames());
|
|
||||||
nameFont.setSelectedItem(mainFont);
|
|
||||||
nameFont.setPreferredSize(new Dimension(130, 22));
|
|
||||||
nameFont.addActionListener(this);
|
|
||||||
|
|
||||||
String font = Settings.HST_TFNT.get().getName();
|
|
||||||
timeFont = new JComboBox(gEnv.getAvailableFontFamilyNames());
|
|
||||||
timeFont.setSelectedItem(font);
|
|
||||||
timeFont.setPreferredSize(new Dimension(130, 22));
|
|
||||||
timeFont.addActionListener(this);
|
|
||||||
|
|
||||||
nameSize = new JSpinner(new SpinnerNumberModel(
|
|
||||||
Settings.HST_SFNT.get().getSize(), 8, 240, 1)
|
|
||||||
);
|
|
||||||
nameSize.addChangeListener(this);
|
|
||||||
|
|
||||||
timeSize = new JSpinner(new SpinnerNumberModel(
|
|
||||||
Settings.HST_TFNT.get().getSize(), 8, 240, 1)
|
|
||||||
);
|
|
||||||
timeSize.addChangeListener(this);
|
|
||||||
|
|
||||||
place();
|
// ------------------------------------------------------------- ATTRIBUTES
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- CALLBACKS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the settings with the user input when he validates.
|
|
||||||
*/
|
|
||||||
@Override public void actionPerformed(ActionEvent event) {
|
|
||||||
Object source = event.getSource();
|
|
||||||
if (source.equals(merge)) {
|
|
||||||
Merge value = (Merge) merge.getSelectedItem();
|
|
||||||
Settings.HST_MERG.set(value);
|
|
||||||
if (value == Merge.DELTA) {
|
|
||||||
Settings.HST_DLTA.set(false);
|
|
||||||
deltas.setSelected(false);
|
|
||||||
} else if (value == Merge.LIVE) {
|
|
||||||
Settings.HST_LIVE.set(false);
|
|
||||||
lives.setSelected(false);
|
|
||||||
}
|
|
||||||
} else if (source.equals(deltas)) {
|
|
||||||
Settings.HST_DLTA.set(deltas.isSelected());
|
|
||||||
} else if (source.equals(lives)) {
|
|
||||||
Settings.HST_LIVE.set(lives.isSelected());
|
|
||||||
} else if (source.equals(blankRows)) {
|
|
||||||
Settings.HST_BLNK.set(blankRows.isSelected());
|
|
||||||
} else if (source.equals(icons)) {
|
|
||||||
Settings.HST_ICON.set(icons.isSelected());
|
|
||||||
} else if (source.equals(showLast)) {
|
|
||||||
Settings.HST_LAST.set(showLast.isSelected());
|
|
||||||
} else if (source.equals(twoLines)) {
|
|
||||||
Settings.HST_LINE.set(twoLines.isSelected());
|
|
||||||
} else if (source.equals(tabular)) {
|
|
||||||
Settings.HST_TABL.set(tabular.isSelected());
|
|
||||||
} else if (source.equals(iconSize)) {
|
|
||||||
Settings.HST_ICSZ.set(
|
|
||||||
(Integer) iconSize.getSelectedItem()
|
|
||||||
);
|
|
||||||
} else if (source.equals(nameFont)) {
|
|
||||||
String fontName = nameFont.getSelectedItem().toString();
|
|
||||||
Font font = Font.decode(fontName).deriveFont(
|
|
||||||
(float) Settings.HST_SFNT.get().getSize()
|
|
||||||
);
|
|
||||||
Settings.HST_SFNT.set(font);
|
|
||||||
} else if (source.equals(timeFont)) {
|
|
||||||
String fontName = timeFont.getSelectedItem().toString();
|
|
||||||
Font font = Font.decode(fontName).deriveFont(
|
|
||||||
(float) Settings.HST_TFNT.get().getSize()
|
|
||||||
);
|
|
||||||
Settings.HST_TFNT.set(font);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stateChanged(ChangeEvent event) {
|
|
||||||
Object source = event.getSource();
|
|
||||||
if (source.equals(offset)) {
|
|
||||||
int size = (Integer) offset.getValue();
|
|
||||||
Settings.HST_OFFS.set(size);
|
|
||||||
} else if (source.equals(nameSize)) {
|
|
||||||
int size = (Integer) nameSize.getValue();
|
|
||||||
Settings.HST_SFNT.set(
|
|
||||||
Settings.HST_SFNT.get().deriveFont((float) size)
|
|
||||||
);
|
|
||||||
} else if (source.equals(timeSize)) {
|
|
||||||
int size = (Integer) timeSize.getValue();
|
|
||||||
Settings.HST_TFNT.set(
|
|
||||||
Settings.HST_TFNT.get().deriveFont((float) size)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- INHERITED
|
|
||||||
|
|
||||||
@Override void doDelayedSettingChange() {
|
/**
|
||||||
int input = 0;
|
* Text field allowing the user to edit the height of the history. The
|
||||||
try {
|
* height is provided as a number of segments to display.
|
||||||
input = Integer.parseInt(rows.getText());
|
*/
|
||||||
} catch (Exception e) {
|
private JTextField rows;
|
||||||
//$FALL-THROUGH$
|
|
||||||
} finally {
|
/**
|
||||||
if (input <= 0) {
|
* Label displaying the name of the text field {@code height}.
|
||||||
input = 0;
|
*/
|
||||||
rows.setText("0");
|
private JLabel heightText;
|
||||||
}
|
|
||||||
Settings.HST_ROWS.set(input);
|
/**
|
||||||
}
|
* Label displaying the unit of the value of the text field {@code height}.
|
||||||
}
|
*/
|
||||||
|
private JLabel heightUnit;
|
||||||
/**
|
|
||||||
* Returns the localized name of this tab.
|
/**
|
||||||
*/
|
* Combox box displaying the available merging methods, determining which,
|
||||||
@Override public String toString() {
|
* if any, column should be merged.
|
||||||
return "" + Language.HISTORY;
|
*/
|
||||||
}
|
private JComboBox merge;
|
||||||
|
|
||||||
// -------------------------------------------------------------- UTILITIES
|
/**
|
||||||
|
* Check box determining wether or not the history should display the
|
||||||
/**
|
* delta column.
|
||||||
* Places all sub-components within this panel.
|
*/
|
||||||
*/
|
private JCheckBox deltas;
|
||||||
private void place() {
|
|
||||||
setLayout(new GridBagLayout());
|
/**
|
||||||
// Set Components Orientation
|
* Check box determining wether or not the history should display the
|
||||||
rows.setHorizontalAlignment(JLabel.CENTER);
|
* live times column.
|
||||||
twoLines.setHorizontalTextPosition(JLabel.LEADING);
|
*/
|
||||||
blankRows.setHorizontalTextPosition(JLabel.LEADING);
|
private JCheckBox lives;
|
||||||
showLast.setHorizontalTextPosition(JLabel.LEADING);
|
|
||||||
// Display
|
private JCheckBox blankRows;
|
||||||
JPanel display = new JPanel(new GridBagLayout()); {
|
|
||||||
display.add(icons , GBC.grid(0, 0).anchor(GBC.LS));
|
private JCheckBox icons;
|
||||||
display.add(lives , GBC.grid(0, 1).anchor(GBC.LS));
|
|
||||||
display.add(deltas, GBC.grid(0, 2).anchor(GBC.LS));
|
private JComboBox iconSize;
|
||||||
|
|
||||||
|
private JCheckBox showLast;
|
||||||
|
|
||||||
|
private JSpinner offset;
|
||||||
|
|
||||||
|
private JLabel offsetHelper;
|
||||||
|
|
||||||
|
private JCheckBox twoLines;
|
||||||
|
|
||||||
|
private JCheckBox tabular;
|
||||||
|
|
||||||
|
private JComboBox nameFont;
|
||||||
|
|
||||||
|
private JSpinner nameSize;
|
||||||
|
|
||||||
|
private JComboBox timeFont;
|
||||||
|
|
||||||
|
private JSpinner timeSize;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------- CONSTRUCTORS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the "History" settings tab. Only called by {@link EditSettings}.
|
||||||
|
*/
|
||||||
|
TabHistory() {
|
||||||
|
rows = new JTextField();
|
||||||
|
rows.setHorizontalAlignment(JTextField.TRAILING);
|
||||||
|
rows.setText("" + Settings.HST_ROWS.get());
|
||||||
|
|
||||||
|
deltas = new JCheckBox("" + Language.setting_history_deltas);
|
||||||
|
deltas.setSelected(Settings.HST_DLTA.get());
|
||||||
|
deltas.addActionListener(this);
|
||||||
|
|
||||||
|
lives = new JCheckBox("" + Language.setting_history_liveTimes);
|
||||||
|
lives.setSelected(Settings.HST_LIVE.get());
|
||||||
|
lives.addActionListener(this);
|
||||||
|
|
||||||
|
twoLines = new JCheckBox("" + Language.setting_history_multiline);
|
||||||
|
twoLines.setSelected(Settings.HST_LINE.get());
|
||||||
|
twoLines.addActionListener(this);
|
||||||
|
|
||||||
|
blankRows = new JCheckBox("" + Language.setting_history_blankRows);
|
||||||
|
blankRows.setSelected(Settings.HST_BLNK.get());
|
||||||
|
blankRows.addActionListener(this);
|
||||||
|
|
||||||
|
icons = new JCheckBox("" + Language.setting_history_icons);
|
||||||
|
icons.setSelected(Settings.HST_ICON.get());
|
||||||
|
icons.addActionListener(this);
|
||||||
|
|
||||||
|
tabular = new JCheckBox("" + Language.setting_history_tabular);
|
||||||
|
tabular.setSelected(Settings.HST_TABL.get());
|
||||||
|
tabular.addActionListener(this);
|
||||||
|
|
||||||
|
showLast = new JCheckBox("" + Language.setting_history_alwaysShowLast);
|
||||||
|
showLast.setSelected(Settings.HST_LAST.get());
|
||||||
|
showLast.addActionListener(this);
|
||||||
|
|
||||||
|
merge = new JComboBox(Merge.values());
|
||||||
|
merge.setSelectedItem(Settings.HST_MERG.get());
|
||||||
|
merge.addActionListener(this);
|
||||||
|
|
||||||
|
iconSize = new JComboBox(Segment.ICON_SIZES);
|
||||||
|
iconSize.setSelectedItem(Settings.HST_ICSZ.get());
|
||||||
|
iconSize.addActionListener(this);
|
||||||
|
|
||||||
|
offset = new JSpinner(new SpinnerNumberModel(
|
||||||
|
(int) Settings.HST_OFFS.get(), -5, 5, 1)
|
||||||
|
);
|
||||||
|
offset.addChangeListener(this);
|
||||||
|
|
||||||
|
offsetHelper = new JLabel("<html>[<a href=''>?</a>]</html>");
|
||||||
|
offsetHelper.setToolTipText(
|
||||||
|
"<html><div width=200>" + Language.TT_HS_OFFSET + "</div></html>"
|
||||||
|
);
|
||||||
|
|
||||||
|
GraphicsEnvironment gEnv = GraphicsEnvironment
|
||||||
|
.getLocalGraphicsEnvironment();
|
||||||
|
String mainFont = Settings.HST_SFNT.get().getName();
|
||||||
|
nameFont = new JComboBox(gEnv.getAvailableFontFamilyNames());
|
||||||
|
nameFont.setSelectedItem(mainFont);
|
||||||
|
nameFont.setPreferredSize(new Dimension(130, 22));
|
||||||
|
nameFont.addActionListener(this);
|
||||||
|
|
||||||
|
String font = Settings.HST_TFNT.get().getName();
|
||||||
|
timeFont = new JComboBox(gEnv.getAvailableFontFamilyNames());
|
||||||
|
timeFont.setSelectedItem(font);
|
||||||
|
timeFont.setPreferredSize(new Dimension(130, 22));
|
||||||
|
timeFont.addActionListener(this);
|
||||||
|
|
||||||
|
nameSize = new JSpinner(new SpinnerNumberModel(
|
||||||
|
Settings.HST_SFNT.get().getSize(), 8, 240, 1)
|
||||||
|
);
|
||||||
|
nameSize.addChangeListener(this);
|
||||||
|
|
||||||
|
timeSize = new JSpinner(new SpinnerNumberModel(
|
||||||
|
Settings.HST_TFNT.get().getSize(), 8, 240, 1)
|
||||||
|
);
|
||||||
|
timeSize.addChangeListener(this);
|
||||||
|
|
||||||
|
place();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------- CALLBACKS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the settings with the user input when he validates.
|
||||||
|
*/
|
||||||
|
@Override public void actionPerformed(ActionEvent event) {
|
||||||
|
Object source = event.getSource();
|
||||||
|
if (source.equals(merge)) {
|
||||||
|
Merge value = (Merge) merge.getSelectedItem();
|
||||||
|
Settings.HST_MERG.set(value);
|
||||||
|
if (value == Merge.DELTA) {
|
||||||
|
Settings.HST_DLTA.set(false);
|
||||||
|
deltas.setSelected(false);
|
||||||
|
} else if (value == Merge.LIVE) {
|
||||||
|
Settings.HST_LIVE.set(false);
|
||||||
|
lives.setSelected(false);
|
||||||
|
}
|
||||||
|
} else if (source.equals(deltas)) {
|
||||||
|
Settings.HST_DLTA.set(deltas.isSelected());
|
||||||
|
} else if (source.equals(lives)) {
|
||||||
|
Settings.HST_LIVE.set(lives.isSelected());
|
||||||
|
} else if (source.equals(blankRows)) {
|
||||||
|
Settings.HST_BLNK.set(blankRows.isSelected());
|
||||||
|
} else if (source.equals(icons)) {
|
||||||
|
Settings.HST_ICON.set(icons.isSelected());
|
||||||
|
} else if (source.equals(showLast)) {
|
||||||
|
Settings.HST_LAST.set(showLast.isSelected());
|
||||||
|
} else if (source.equals(twoLines)) {
|
||||||
|
Settings.HST_LINE.set(twoLines.isSelected());
|
||||||
|
} else if (source.equals(tabular)) {
|
||||||
|
Settings.HST_TABL.set(tabular.isSelected());
|
||||||
|
} else if (source.equals(iconSize)) {
|
||||||
|
Settings.HST_ICSZ.set(
|
||||||
|
(Integer) iconSize.getSelectedItem()
|
||||||
|
);
|
||||||
|
} else if (source.equals(nameFont)) {
|
||||||
|
String fontName = nameFont.getSelectedItem().toString();
|
||||||
|
Font font = Font.decode(fontName).deriveFont(
|
||||||
|
(float) Settings.HST_SFNT.get().getSize()
|
||||||
|
);
|
||||||
|
Settings.HST_SFNT.set(font);
|
||||||
|
} else if (source.equals(timeFont)) {
|
||||||
|
String fontName = timeFont.getSelectedItem().toString();
|
||||||
|
Font font = Font.decode(fontName).deriveFont(
|
||||||
|
(float) Settings.HST_TFNT.get().getSize()
|
||||||
|
);
|
||||||
|
Settings.HST_TFNT.set(font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stateChanged(ChangeEvent event) {
|
||||||
|
Object source = event.getSource();
|
||||||
|
if (source.equals(offset)) {
|
||||||
|
int size = (Integer) offset.getValue();
|
||||||
|
Settings.HST_OFFS.set(size);
|
||||||
|
} else if (source.equals(nameSize)) {
|
||||||
|
int size = (Integer) nameSize.getValue();
|
||||||
|
Settings.HST_SFNT.set(
|
||||||
|
Settings.HST_SFNT.get().deriveFont((float) size)
|
||||||
|
);
|
||||||
|
} else if (source.equals(timeSize)) {
|
||||||
|
int size = (Integer) timeSize.getValue();
|
||||||
|
Settings.HST_TFNT.set(
|
||||||
|
Settings.HST_TFNT.get().deriveFont((float) size)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------- INHERITED
|
||||||
|
|
||||||
|
@Override void doDelayedSettingChange() {
|
||||||
|
int input = 0;
|
||||||
|
try {
|
||||||
|
input = Integer.parseInt(rows.getText());
|
||||||
|
} catch (Exception e) {
|
||||||
|
//$FALL-THROUGH$
|
||||||
|
} finally {
|
||||||
|
if (input <= 0) {
|
||||||
|
input = 0;
|
||||||
|
rows.setText("0");
|
||||||
|
}
|
||||||
|
Settings.HST_ROWS.set(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the localized name of this tab.
|
||||||
|
*/
|
||||||
|
@Override public String toString() {
|
||||||
|
return "" + Language.HISTORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------- UTILITIES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Places all sub-components within this panel.
|
||||||
|
*/
|
||||||
|
private void place() {
|
||||||
|
setLayout(new GridBagLayout());
|
||||||
|
// Set Components Orientation
|
||||||
|
rows.setHorizontalAlignment(JLabel.CENTER);
|
||||||
|
twoLines.setHorizontalTextPosition(JLabel.LEADING);
|
||||||
|
blankRows.setHorizontalTextPosition(JLabel.LEADING);
|
||||||
|
showLast.setHorizontalTextPosition(JLabel.LEADING);
|
||||||
|
// Display
|
||||||
|
JPanel display = new JPanel(new GridBagLayout()); {
|
||||||
|
display.add(icons , GBC.grid(0, 0).anchor(GBC.LS));
|
||||||
|
display.add(lives , GBC.grid(0, 1).anchor(GBC.LS));
|
||||||
|
display.add(deltas, GBC.grid(0, 2).anchor(GBC.LS));
|
||||||
// display.add(tabular, GBC.grid(0, 3).anchor(GBC.LS));
|
// display.add(tabular, GBC.grid(0, 3).anchor(GBC.LS));
|
||||||
display.add(merge , GBC.grid(0, 4).anchor(GBC.LS));
|
display.add(merge , GBC.grid(0, 4).anchor(GBC.LS));
|
||||||
display.setBorder(
|
display.setBorder(
|
||||||
BorderFactory.createTitledBorder("" + Language.PN_DISPLAY)
|
BorderFactory.createTitledBorder("" + Language.PN_DISPLAY)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Dimension
|
// Dimension
|
||||||
JPanel dimension = new JPanel(new GridBagLayout()); {
|
JPanel dimension = new JPanel(new GridBagLayout()); {
|
||||||
dimension.add(
|
dimension.add(
|
||||||
new JLabel("" + Language.setting_history_iconSize),
|
new JLabel("" + Language.setting_history_iconSize),
|
||||||
GBC.grid(0, 0).anchor(GBC.LE)
|
GBC.grid(0, 0).anchor(GBC.LE)
|
||||||
);
|
);
|
||||||
dimension.add(iconSize, GBC.grid(1, 0).anchor(GBC.LE).insets(2, 3));
|
dimension.add(iconSize, GBC.grid(1, 0).anchor(GBC.LE).insets(2, 3));
|
||||||
dimension.add(
|
dimension.add(
|
||||||
new JLabel("" + Language.setting_history_rowCount),
|
new JLabel("" + Language.setting_history_rowCount),
|
||||||
GBC.grid(0, 1).anchor(GBC.LE)
|
GBC.grid(0, 1).anchor(GBC.LE)
|
||||||
);
|
);
|
||||||
dimension.add(
|
dimension.add(
|
||||||
rows, GBC.grid(1, 1).anchor(GBC.LE).fill(GBC.H).insets(2, 3)
|
rows, GBC.grid(1, 1).anchor(GBC.LE).fill(GBC.H).insets(2, 3)
|
||||||
);
|
);
|
||||||
dimension.add(blankRows, GBC.grid(0, 2, 2, 1).anchor(GBC.LE));
|
dimension.add(blankRows, GBC.grid(0, 2, 2, 1).anchor(GBC.LE));
|
||||||
dimension.add(
|
dimension.add(
|
||||||
twoLines , GBC.grid(0, 3, 2, 1).anchor(GBC.LE).insets(0, 1)
|
twoLines , GBC.grid(0, 3, 2, 1).anchor(GBC.LE).insets(0, 1)
|
||||||
);
|
);
|
||||||
dimension.setBorder(
|
dimension.setBorder(
|
||||||
BorderFactory.createTitledBorder("" + Language.PN_DIMENSION)
|
BorderFactory.createTitledBorder("" + Language.PN_DIMENSION)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Fonts
|
// Fonts
|
||||||
JPanel fonts = new JPanel(new GridBagLayout()); {
|
JPanel fonts = new JPanel(new GridBagLayout()); {
|
||||||
fonts.add(
|
fonts.add(
|
||||||
new JLabel("" + Language.setting_history_segmentFont),
|
new JLabel("" + Language.setting_history_segmentFont),
|
||||||
GBC.grid(0, 0).anchor(GBC.LE)
|
GBC.grid(0, 0).anchor(GBC.LE)
|
||||||
);
|
);
|
||||||
fonts.add(nameFont, GBC.grid(1, 0).anchor(GBC.LS).insets(5, 5));
|
fonts.add(nameFont, GBC.grid(1, 0).anchor(GBC.LS).insets(5, 5));
|
||||||
fonts.add(nameSize, GBC.grid(2, 0).anchor(GBC.LS));
|
fonts.add(nameSize, GBC.grid(2, 0).anchor(GBC.LS));
|
||||||
fonts.add(
|
fonts.add(
|
||||||
new JLabel("" + Language.setting_history_timeFont),
|
new JLabel("" + Language.setting_history_timeFont),
|
||||||
GBC.grid(0, 1).anchor(GBC.LE)
|
GBC.grid(0, 1).anchor(GBC.LE)
|
||||||
);
|
);
|
||||||
fonts.add(timeFont, GBC.grid(1, 1).anchor(GBC.LS).insets(5, 5));
|
fonts.add(timeFont, GBC.grid(1, 1).anchor(GBC.LS).insets(5, 5));
|
||||||
fonts.add(timeSize, GBC.grid(2, 1).anchor(GBC.LS));
|
fonts.add(timeSize, GBC.grid(2, 1).anchor(GBC.LS));
|
||||||
fonts.setBorder(
|
fonts.setBorder(
|
||||||
BorderFactory.createTitledBorder("" + Language.PN_FONTS)
|
BorderFactory.createTitledBorder("" + Language.PN_FONTS)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// Scrolling
|
// Scrolling
|
||||||
JPanel scrolling = new JPanel(new GridBagLayout()); {
|
JPanel scrolling = new JPanel(new GridBagLayout()); {
|
||||||
scrolling.add(
|
scrolling.add(
|
||||||
offsetHelper, GBC.grid(0, 0).anchor(GBC.LE).insets(0, 8)
|
offsetHelper, GBC.grid(0, 0).anchor(GBC.LE).insets(0, 8)
|
||||||
);
|
);
|
||||||
scrolling.add(
|
scrolling.add(
|
||||||
new JLabel("" + Language.setting_history_offset),
|
new JLabel("" + Language.setting_history_offset),
|
||||||
GBC.grid(1, 0).anchor(GBC.LE)
|
GBC.grid(1, 0).anchor(GBC.LE)
|
||||||
);
|
);
|
||||||
scrolling.add(offset , GBC.grid(2, 0).anchor(GBC.LE));
|
scrolling.add(offset , GBC.grid(2, 0).anchor(GBC.LE));
|
||||||
scrolling.add(showLast, GBC.grid(0, 1, 3, 1).anchor(GBC.LE));
|
scrolling.add(showLast, GBC.grid(0, 1, 3, 1).anchor(GBC.LE));
|
||||||
scrolling.setBorder(
|
scrolling.setBorder(
|
||||||
BorderFactory.createTitledBorder("" + Language.PN_SCROLLING)
|
BorderFactory.createTitledBorder("" + Language.PN_SCROLLING)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
add(fonts , GBC.grid(0, 0).fill(GBC.B).padding(10, 10));
|
add(fonts , GBC.grid(0, 0).fill(GBC.B).padding(10, 10));
|
||||||
add(dimension, GBC.grid(1, 0).fill(GBC.B).padding(10, 10));
|
add(dimension, GBC.grid(1, 0).fill(GBC.B).padding(10, 10));
|
||||||
add(display , GBC.grid(0, 1).fill(GBC.B).padding(10, 10));
|
add(display , GBC.grid(0, 1).fill(GBC.B).padding(10, 10));
|
||||||
add(scrolling, GBC.grid(1, 1).fill(GBC.B).padding(10, 10));
|
add(scrolling, GBC.grid(1, 1).fill(GBC.B).padding(10, 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,5 @@
|
||||||
package org.fenix.llanfair.dialog;
|
package org.fenix.llanfair.dialog;
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.GridBagLayout;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.awt.event.MouseListener;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
|
|
||||||
import org.fenix.llanfair.Language;
|
import org.fenix.llanfair.Language;
|
||||||
import org.fenix.llanfair.config.Settings;
|
import org.fenix.llanfair.config.Settings;
|
||||||
import org.fenix.utils.gui.GBC;
|
import org.fenix.utils.gui.GBC;
|
||||||
|
@ -18,194 +7,201 @@ import org.jnativehook.GlobalScreen;
|
||||||
import org.jnativehook.keyboard.NativeKeyEvent;
|
import org.jnativehook.keyboard.NativeKeyEvent;
|
||||||
import org.jnativehook.keyboard.NativeKeyListener;
|
import org.jnativehook.keyboard.NativeKeyListener;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.MouseListener;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author Xavier "Xunkar" Sencert
|
* @author Xavier "Xunkar" Sencert
|
||||||
*/
|
*/
|
||||||
class TabHotkeys extends SettingsTab {
|
class TabHotkeys extends SettingsTab {
|
||||||
|
|
||||||
// ------------------------------------------------------------- ATTRIBUTES
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of all key fields customizable by the user.
|
|
||||||
*/
|
|
||||||
private List<KeyField> keyFields;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of labels displaying the name of each key field.
|
|
||||||
*/
|
|
||||||
private List<JLabel> keyLabels;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------- CONSTRUCTORS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the "Hotkeys" settings tab. Only called by {@link EditSettings}.
|
|
||||||
*/
|
|
||||||
TabHotkeys() {
|
|
||||||
keyFields = new ArrayList<KeyField>();
|
|
||||||
keyLabels = new ArrayList<JLabel>();
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
for (Settings.Property<?> setting : Settings.getAll("hotkey")) {
|
|
||||||
keyFields.add(new KeyField(
|
|
||||||
index, (Settings.Property<Integer>) setting)
|
|
||||||
);
|
|
||||||
keyLabels.add(new JLabel("" + setting));
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
place();
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- INHERITED
|
|
||||||
|
|
||||||
@Override void doDelayedSettingChange() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the localized name of this tab.
|
|
||||||
*/
|
|
||||||
@Override public String toString() {
|
|
||||||
return "" + Language.INPUTS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- UTILITIES
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Places all sub-components within this panel.
|
|
||||||
*/
|
|
||||||
private void place() {
|
|
||||||
setLayout(new GridBagLayout());
|
|
||||||
|
|
||||||
for (int row = 0; row < keyFields.size(); row++) {
|
|
||||||
add(
|
|
||||||
keyLabels.get(row),
|
|
||||||
GBC.grid(0, row).insets(10, 0, 10, 10).anchor(GBC.LE)
|
|
||||||
);
|
|
||||||
add(keyFields.get(row), GBC.grid(1, row));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------------- INTERNAL TYPES
|
|
||||||
|
|
||||||
/**
|
// ------------------------------------------------------------- ATTRIBUTES
|
||||||
* A text field representing a hotkey setting. Clicking such field allows
|
|
||||||
* the user to define a key for this particular setting, using the tables
|
|
||||||
* from {@code JNativeHook}.
|
|
||||||
*
|
|
||||||
* @author Xavier "Xunkar" Sencert
|
|
||||||
*/
|
|
||||||
static class KeyField extends JTextField
|
|
||||||
implements MouseListener, NativeKeyListener {
|
|
||||||
|
|
||||||
// ----------------------------------------------------- CONSTANTS
|
/**
|
||||||
|
* List of all key fields customizable by the user.
|
||||||
/**
|
*/
|
||||||
* Preferred dimension of a text field.
|
private List<KeyField> keyFields;
|
||||||
*/
|
|
||||||
private static final Dimension SIZE = new Dimension(85, 20);
|
/**
|
||||||
|
* List of labels displaying the name of each key field.
|
||||||
// ---------------------------------------------------- ATTRIBUTES
|
*/
|
||||||
|
private List<JLabel> keyLabels;
|
||||||
private static boolean isEditing = false;
|
|
||||||
|
// ----------------------------------------------------------- CONSTRUCTORS
|
||||||
/**
|
|
||||||
* Internal index of this field, used by the superclass.
|
/**
|
||||||
*/
|
* Creates the "Hotkeys" settings tab. Only called by {@link EditSettings}.
|
||||||
private int index;
|
*/
|
||||||
|
TabHotkeys() {
|
||||||
/**
|
keyFields = new ArrayList<KeyField>();
|
||||||
* Setting represented by this key field.
|
keyLabels = new ArrayList<JLabel>();
|
||||||
*/
|
|
||||||
private Settings.Property<Integer> setting;
|
int index = 0;
|
||||||
|
for (Settings.Property<?> setting : Settings.getAll("hotkey")) {
|
||||||
// -------------------------------------------------- CONSTRUCTORS
|
keyFields.add(new KeyField(
|
||||||
|
index, (Settings.Property<Integer>) setting)
|
||||||
/**
|
);
|
||||||
* Creates a new key field for the given setting. Only called by
|
keyLabels.add(new JLabel("" + setting));
|
||||||
* {@link TabHotkeys}.
|
index++;
|
||||||
*
|
}
|
||||||
* @param index - internal index to identify this field.
|
|
||||||
* @param setting - setting represented by this field.
|
place();
|
||||||
*/
|
}
|
||||||
KeyField(int index, Settings.Property<Integer> setting) {
|
|
||||||
this.index = index;
|
// -------------------------------------------------------------- INHERITED
|
||||||
this.setting = setting;
|
|
||||||
|
@Override void doDelayedSettingChange() {}
|
||||||
setEditable(false);
|
|
||||||
setName(setting.getKey());
|
/**
|
||||||
setPreferredSize(SIZE);
|
* Returns the localized name of this tab.
|
||||||
setHorizontalAlignment(CENTER);
|
*/
|
||||||
String text = NativeKeyEvent.getKeyText(setting.get());
|
@Override public String toString() {
|
||||||
setText(setting.get() == -1 ? "" + Language.DISABLED : text);
|
return "" + Language.INPUTS;
|
||||||
|
}
|
||||||
addMouseListener(this);
|
|
||||||
}
|
// -------------------------------------------------------------- UTILITIES
|
||||||
|
|
||||||
// ------------------------------------------------------- GETTERS
|
/**
|
||||||
|
* Places all sub-components within this panel.
|
||||||
/**
|
*/
|
||||||
* Returns the setting represented by this key field.
|
private void place() {
|
||||||
*/
|
setLayout(new GridBagLayout());
|
||||||
public Settings.Property<Integer> getSetting() {
|
|
||||||
return setting;
|
for (int row = 0; row < keyFields.size(); row++) {
|
||||||
}
|
add(
|
||||||
|
keyLabels.get(row),
|
||||||
// ----------------------------------------------------- CALLBACKS
|
GBC.grid(0, row).insets(10, 0, 10, 10).anchor(GBC.LE)
|
||||||
|
);
|
||||||
/**
|
add(keyFields.get(row), GBC.grid(1, row));
|
||||||
* When a key field is clicked, we register ourselves as native key
|
}
|
||||||
* listener to capture the new key setting. The background adorns a
|
}
|
||||||
* new color to signify that this field is now listening.
|
|
||||||
*/
|
// --------------------------------------------------------- INTERNAL TYPES
|
||||||
public void mouseClicked(MouseEvent event) {
|
|
||||||
if (!isEditing) {
|
/**
|
||||||
setBackground(Color.YELLOW);
|
* A text field representing a hotkey setting. Clicking such field allows
|
||||||
GlobalScreen.getInstance().addNativeKeyListener(this);
|
* the user to define a key for this particular setting, using the tables
|
||||||
isEditing = true;
|
* from {@code JNativeHook}.
|
||||||
}
|
*
|
||||||
}
|
* @author Xavier "Xunkar" Sencert
|
||||||
|
*/
|
||||||
// $UNUSED$
|
static class KeyField extends JTextField
|
||||||
public void mouseEntered(MouseEvent event) {}
|
implements MouseListener, NativeKeyListener {
|
||||||
|
|
||||||
// $UNUSED$
|
// ----------------------------------------------------- CONSTANTS
|
||||||
public void mouseExited(MouseEvent event) {}
|
|
||||||
|
/**
|
||||||
// $UNUSED$
|
* Preferred dimension of a text field.
|
||||||
public void mousePressed(MouseEvent event) {}
|
*/
|
||||||
|
private static final Dimension SIZE = new Dimension(85, 20);
|
||||||
// $UNUSED$
|
|
||||||
public void mouseReleased(MouseEvent event) {}
|
// ---------------------------------------------------- ATTRIBUTES
|
||||||
|
|
||||||
/**
|
private static boolean isEditing = false;
|
||||||
* When a key is pressed we set the captured key as the new value
|
|
||||||
* for the setting we represent. If escape is pressed, the hotkey
|
/**
|
||||||
* becomes disabled. After registering the update, we no longer
|
* Internal index of this field, used by the superclass.
|
||||||
* listen for native key events.
|
*/
|
||||||
*/
|
private int index;
|
||||||
public void nativeKeyPressed(NativeKeyEvent event) {
|
|
||||||
int code = event.getKeyCode();
|
/**
|
||||||
String text = null;
|
* Setting represented by this key field.
|
||||||
|
*/
|
||||||
if (code == NativeKeyEvent.VK_ESCAPE) {
|
private Settings.Property<Integer> setting;
|
||||||
code = -1;
|
|
||||||
text = "" + Language.DISABLED;
|
// -------------------------------------------------- CONSTRUCTORS
|
||||||
} else {
|
|
||||||
text = NativeKeyEvent.getKeyText(code);
|
/**
|
||||||
}
|
* Creates a new key field for the given setting. Only called by
|
||||||
setText(text);
|
* {@link TabHotkeys}.
|
||||||
setting.set(code);
|
*
|
||||||
|
* @param index - internal index to identify this field.
|
||||||
setBackground(Color.GREEN);
|
* @param setting - setting represented by this field.
|
||||||
GlobalScreen.getInstance().removeNativeKeyListener(this);
|
*/
|
||||||
isEditing = false;
|
KeyField(int index, Settings.Property<Integer> setting) {
|
||||||
}
|
this.index = index;
|
||||||
|
this.setting = setting;
|
||||||
// $UNUSED$
|
|
||||||
public void nativeKeyReleased(NativeKeyEvent event) {}
|
setEditable(false);
|
||||||
|
setName(setting.getKey());
|
||||||
// $UNUSED$
|
setPreferredSize(SIZE);
|
||||||
public void nativeKeyTyped(NativeKeyEvent event) {}
|
setHorizontalAlignment(CENTER);
|
||||||
|
String text = NativeKeyEvent.getKeyText(setting.get());
|
||||||
}
|
setText(setting.get() == -1 ? "" + Language.DISABLED : text);
|
||||||
|
|
||||||
|
addMouseListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------- GETTERS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the setting represented by this key field.
|
||||||
|
*/
|
||||||
|
public Settings.Property<Integer> getSetting() {
|
||||||
|
return setting;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------- CALLBACKS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a key field is clicked, we register ourselves as native key
|
||||||
|
* listener to capture the new key setting. The background adorns a
|
||||||
|
* new color to signify that this field is now listening.
|
||||||
|
*/
|
||||||
|
public void mouseClicked(MouseEvent event) {
|
||||||
|
if (!isEditing) {
|
||||||
|
setBackground(Color.YELLOW);
|
||||||
|
GlobalScreen.getInstance().addNativeKeyListener(this);
|
||||||
|
isEditing = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// $UNUSED$
|
||||||
|
public void mouseEntered(MouseEvent event) {}
|
||||||
|
|
||||||
|
// $UNUSED$
|
||||||
|
public void mouseExited(MouseEvent event) {}
|
||||||
|
|
||||||
|
// $UNUSED$
|
||||||
|
public void mousePressed(MouseEvent event) {}
|
||||||
|
|
||||||
|
// $UNUSED$
|
||||||
|
public void mouseReleased(MouseEvent event) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a key is pressed we set the captured key as the new value
|
||||||
|
* for the setting we represent. If escape is pressed, the hotkey
|
||||||
|
* becomes disabled. After registering the update, we no longer
|
||||||
|
* listen for native key events.
|
||||||
|
*/
|
||||||
|
public void nativeKeyPressed(NativeKeyEvent event) {
|
||||||
|
int code = event.getKeyCode();
|
||||||
|
String text = null;
|
||||||
|
|
||||||
|
if (code == NativeKeyEvent.VK_ESCAPE) {
|
||||||
|
code = -1;
|
||||||
|
text = "" + Language.DISABLED;
|
||||||
|
} else {
|
||||||
|
text = NativeKeyEvent.getKeyText(code);
|
||||||
|
}
|
||||||
|
setText(text);
|
||||||
|
setting.set(code);
|
||||||
|
|
||||||
|
setBackground(Color.GREEN);
|
||||||
|
GlobalScreen.getInstance().removeNativeKeyListener(this);
|
||||||
|
isEditing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// $UNUSED$
|
||||||
|
public void nativeKeyReleased(NativeKeyEvent event) {}
|
||||||
|
|
||||||
|
// $UNUSED$
|
||||||
|
public void nativeKeyTyped(NativeKeyEvent event) {}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,296 +28,296 @@ import org.fenix.utils.gui.GBC;
|
||||||
* @author Xavier "Xunkar" Sencert
|
* @author Xavier "Xunkar" Sencert
|
||||||
*/
|
*/
|
||||||
class TabLook extends SettingsTab implements ActionListener, ChangeListener {
|
class TabLook extends SettingsTab implements ActionListener, ChangeListener {
|
||||||
|
|
||||||
// -------------------------------------------------------------- CONSTANTS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dimension of the revert button.
|
|
||||||
*/
|
|
||||||
private static final Dimension REVERT_SIZE = new Dimension(18, 18);
|
|
||||||
|
|
||||||
// ------------------------------------------------------------- ATTRIBUTES
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of all color buttons, inserted in the order of their name.
|
|
||||||
*/
|
|
||||||
private List<ColorButton> colorButtons;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List of labels displaying the name of the color button.
|
|
||||||
*/
|
|
||||||
private List<JLabel> colorTexts;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Panel allowing the user to select a color.
|
|
||||||
*/
|
|
||||||
private JColorChooser colorChooser;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The index of the currently selected color button. Any color change will
|
|
||||||
* be made to this button.
|
|
||||||
*/
|
|
||||||
private int selected;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Label displaying a text explaining to the user that he must first
|
|
||||||
* select a color button before editing its color.
|
|
||||||
*/
|
|
||||||
private JLabel helperText;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Panel listing the color buttons and their name label.
|
|
||||||
*/
|
|
||||||
private JPanel colorPanel;
|
|
||||||
|
|
||||||
/**
|
// -------------------------------------------------------------- CONSTANTS
|
||||||
* Small button displayed next to the selected color button and resetting
|
|
||||||
* its color to its original value.
|
|
||||||
*/
|
|
||||||
private JButton revert;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invisible panel the size of the revert button used to take up space when
|
|
||||||
* the button is not showing.
|
|
||||||
*/
|
|
||||||
private JPanel placeHolder;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------- CONSTRUCTORS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates the "Look" settings tab. Only called by {@link EditSettings}.
|
|
||||||
*/
|
|
||||||
TabLook() {
|
|
||||||
selected = -1;
|
|
||||||
helperText = new JLabel("" + Language.TT_COLOR_PICK);
|
|
||||||
colorTexts = new ArrayList<JLabel>();
|
|
||||||
colorButtons = new ArrayList<ColorButton>();
|
|
||||||
|
|
||||||
int index = 0;
|
/**
|
||||||
for (Settings.Property<?> colorSetting : Settings.getAll("color")) {
|
* Dimension of the revert button.
|
||||||
ColorButton colorButton = new ColorButton(
|
*/
|
||||||
index, (Settings.Property<Color>) colorSetting
|
private static final Dimension REVERT_SIZE = new Dimension(18, 18);
|
||||||
);
|
|
||||||
colorButton.addActionListener(this);
|
|
||||||
colorButtons.add(colorButton);
|
|
||||||
colorTexts.add(new JLabel("" + colorSetting));
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
colorChooser = new JColorChooser();
|
|
||||||
colorChooser.setPreviewPanel(new JPanel());
|
|
||||||
colorChooser.getSelectionModel().addChangeListener(this);
|
|
||||||
colorChooser.setEnabled(false);
|
|
||||||
|
|
||||||
revert = new JButton(Llanfair.getResources().getIcon("REVERT"));
|
|
||||||
revert.setPreferredSize(REVERT_SIZE);
|
|
||||||
revert.addActionListener(this);
|
|
||||||
|
|
||||||
placeHolder = new JPanel();
|
|
||||||
placeHolder.setPreferredSize(REVERT_SIZE);
|
|
||||||
|
|
||||||
place();
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- CALLBACKS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When a color button is pressed, we bring up the color chooser and
|
|
||||||
* change the color of the text indicate it’s been selected. We also
|
|
||||||
* display the revert button next to the selected color. If the event
|
|
||||||
* emanates from a revert button, we revert its associated color.
|
|
||||||
*/
|
|
||||||
public void actionPerformed(ActionEvent event) {
|
|
||||||
Object source = event.getSource();
|
|
||||||
if (source.equals(revert)) {
|
|
||||||
colorButtons.get(selected).resetColor();
|
|
||||||
} else {
|
|
||||||
if (selected != -1) {
|
|
||||||
colorTexts.get(selected).setForeground(Color.BLACK);
|
|
||||||
colorPanel.remove(revert);
|
|
||||||
} else {
|
|
||||||
colorPanel.remove(placeHolder);
|
|
||||||
colorChooser.setEnabled(true);
|
|
||||||
}
|
|
||||||
selected = ((ColorButton) source).getIndex();
|
|
||||||
colorTexts.get(selected).setForeground(Color.RED);
|
|
||||||
colorPanel.add(revert, GBC.grid(2, selected).insets(0, 2));
|
|
||||||
colorChooser.setColor(colorButtons.get(selected).getColor());
|
|
||||||
revalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When a color is selected in the color chooser, update the selected
|
|
||||||
* color button (if any.)
|
|
||||||
*/
|
|
||||||
public void stateChanged(ChangeEvent event) {
|
|
||||||
if (selected != -1) {
|
|
||||||
colorButtons.get(selected).setColor(colorChooser.getColor());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- INHERITED
|
|
||||||
|
|
||||||
@Override void doDelayedSettingChange() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the localized name of this tab.
|
|
||||||
*/
|
|
||||||
@Override public String toString() {
|
|
||||||
return "" + Language.COLORS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- UTILITIES
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Places all sub-components within this panel.
|
|
||||||
*/
|
|
||||||
private void place() {
|
|
||||||
setLayout(new GridBagLayout());
|
|
||||||
|
|
||||||
colorPanel = new JPanel(new GridBagLayout()); {
|
|
||||||
for (int row = 0; row < colorButtons.size(); row++) {
|
|
||||||
colorPanel.add(
|
|
||||||
colorTexts.get(row),
|
|
||||||
GBC.grid(0, row).anchor(GBC.LE).insets(1, 4)
|
|
||||||
);
|
|
||||||
colorPanel.add(
|
|
||||||
colorButtons.get(row), GBC.grid(1, row).insets(2, 0)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
colorPanel.add(placeHolder, GBC.grid(2, 0).insets(0, 2));
|
|
||||||
}
|
|
||||||
JPanel swatchPanel = new JPanel(new GridBagLayout()); {
|
|
||||||
swatchPanel.add(colorChooser, GBC.grid(0, 0));
|
|
||||||
swatchPanel.add(helperText, GBC.grid(0, 1));
|
|
||||||
}
|
|
||||||
add(colorPanel, GBC.grid(0, 0).fill(GBC.B));
|
|
||||||
add(swatchPanel, GBC.grid(1, 0).fill(GBC.B));
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------------------------- INTERNAL TYPES
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A kind of {@code JButton} that displays a color setting by painting
|
|
||||||
* itself in that color. When the color is programatically set, the color
|
|
||||||
* setting is automatically updated by the button. Each button stores an
|
|
||||||
* index only valid in the owning view’s context and the initial value it
|
|
||||||
* was constructed with, allowing for a reset.
|
|
||||||
*
|
|
||||||
* @author Xavier "Xunkar" Sencert
|
|
||||||
*/
|
|
||||||
class ColorButton extends JButton implements Comparable<ColorButton> {
|
|
||||||
|
|
||||||
// ---------------------------------------------------- ATTRIBUTES
|
// ------------------------------------------------------------- ATTRIBUTES
|
||||||
|
|
||||||
/**
|
|
||||||
* Index of this color button in the englobing model.
|
|
||||||
*/
|
|
||||||
private int index;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Color currently represented by this button.
|
* List of all color buttons, inserted in the order of their name.
|
||||||
*/
|
*/
|
||||||
private Color color;
|
private List<ColorButton> colorButtons;
|
||||||
|
|
||||||
/**
|
|
||||||
* Color initially represented by this button. Used to revert to the
|
|
||||||
* setting initial state.
|
|
||||||
*/
|
|
||||||
private Color initialColor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Color setting that this button represent. When the user selectes
|
|
||||||
* a new color, this setting is updated with the user's choice.
|
|
||||||
*/
|
|
||||||
private Settings.Property<Color> setting;
|
|
||||||
|
|
||||||
// -------------------------------------------------- CONSTRUCTORS
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a button representing the given setting. An index must be
|
* List of labels displaying the name of the color button.
|
||||||
* supplied to identify this button. The name of the setting becomes
|
*/
|
||||||
* the name of the button.
|
private List<JLabel> colorTexts;
|
||||||
*
|
|
||||||
* @param index - the index of this button.
|
|
||||||
* @param setting - the setting represented by this button.
|
|
||||||
*/
|
|
||||||
ColorButton(int index, Settings.Property<Color> setting) {
|
|
||||||
super(".");
|
|
||||||
|
|
||||||
color = setting.get();
|
|
||||||
initialColor = color;
|
|
||||||
this.index = index;
|
|
||||||
this.setting = setting;
|
|
||||||
|
|
||||||
setName(setting.getKey());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------- GETTERS
|
/**
|
||||||
|
* Panel allowing the user to select a color.
|
||||||
|
*/
|
||||||
|
private JColorChooser colorChooser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current color of this button.
|
* The index of the currently selected color button. Any color change will
|
||||||
*
|
* be made to this button.
|
||||||
* @return the current color.
|
*/
|
||||||
*/
|
private int selected;
|
||||||
Color getColor() {
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the index of this button.
|
|
||||||
*
|
|
||||||
* @return the index of this button.
|
|
||||||
*/
|
|
||||||
int getIndex() {
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------- SETTERS
|
/**
|
||||||
|
* Label displaying a text explaining to the user that he must first
|
||||||
|
* select a color button before editing its color.
|
||||||
|
*/
|
||||||
|
private JLabel helperText;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the color that this button should display. Updates the setting
|
* Panel listing the color buttons and their name label.
|
||||||
* and repaints itself.
|
*/
|
||||||
*
|
private JPanel colorPanel;
|
||||||
* @param color - the new color to display.
|
|
||||||
*/
|
|
||||||
void setColor(Color color) {
|
|
||||||
this.color = color;
|
|
||||||
setting.set(color);
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the color to be displayed by this button to the initial
|
|
||||||
* color it was constructed with.
|
|
||||||
*/
|
|
||||||
void resetColor() {
|
|
||||||
setColor(initialColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------- INHERITED
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Two {@code ColorButton}s are compared using the lexicographic
|
|
||||||
* comparison of their name.
|
|
||||||
*/
|
|
||||||
public int compareTo(ColorButton o) {
|
|
||||||
if (o == null) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return getName().compareTo(o.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@code ColorButton} paints itself in the color he should
|
* Small button displayed next to the selected color button and resetting
|
||||||
* display and does not display any string of text.
|
* its color to its original value.
|
||||||
*/
|
*/
|
||||||
@Override protected void paintComponent(Graphics g) {
|
private JButton revert;
|
||||||
super.paintComponent(g);
|
|
||||||
g.setColor(color);
|
/**
|
||||||
g.fillRect(0, 0, getWidth(), getHeight());
|
* Invisible panel the size of the revert button used to take up space when
|
||||||
}
|
* the button is not showing.
|
||||||
}
|
*/
|
||||||
|
private JPanel placeHolder;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------- CONSTRUCTORS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the "Look" settings tab. Only called by {@link EditSettings}.
|
||||||
|
*/
|
||||||
|
TabLook() {
|
||||||
|
selected = -1;
|
||||||
|
helperText = new JLabel("" + Language.TT_COLOR_PICK);
|
||||||
|
colorTexts = new ArrayList<JLabel>();
|
||||||
|
colorButtons = new ArrayList<ColorButton>();
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
for (Settings.Property<?> colorSetting : Settings.getAll("color")) {
|
||||||
|
ColorButton colorButton = new ColorButton(
|
||||||
|
index, (Settings.Property<Color>) colorSetting
|
||||||
|
);
|
||||||
|
colorButton.addActionListener(this);
|
||||||
|
colorButtons.add(colorButton);
|
||||||
|
colorTexts.add(new JLabel("" + colorSetting));
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
colorChooser = new JColorChooser();
|
||||||
|
colorChooser.setPreviewPanel(new JPanel());
|
||||||
|
colorChooser.getSelectionModel().addChangeListener(this);
|
||||||
|
colorChooser.setEnabled(false);
|
||||||
|
|
||||||
|
revert = new JButton(Llanfair.getResources().getIcon("REVERT"));
|
||||||
|
revert.setPreferredSize(REVERT_SIZE);
|
||||||
|
revert.addActionListener(this);
|
||||||
|
|
||||||
|
placeHolder = new JPanel();
|
||||||
|
placeHolder.setPreferredSize(REVERT_SIZE);
|
||||||
|
|
||||||
|
place();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------- CALLBACKS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a color button is pressed, we bring up the color chooser and
|
||||||
|
* change the color of the text indicate it’s been selected. We also
|
||||||
|
* display the revert button next to the selected color. If the event
|
||||||
|
* emanates from a revert button, we revert its associated color.
|
||||||
|
*/
|
||||||
|
public void actionPerformed(ActionEvent event) {
|
||||||
|
Object source = event.getSource();
|
||||||
|
if (source.equals(revert)) {
|
||||||
|
colorButtons.get(selected).resetColor();
|
||||||
|
} else {
|
||||||
|
if (selected != -1) {
|
||||||
|
colorTexts.get(selected).setForeground(Color.BLACK);
|
||||||
|
colorPanel.remove(revert);
|
||||||
|
} else {
|
||||||
|
colorPanel.remove(placeHolder);
|
||||||
|
colorChooser.setEnabled(true);
|
||||||
|
}
|
||||||
|
selected = ((ColorButton) source).getIndex();
|
||||||
|
colorTexts.get(selected).setForeground(Color.RED);
|
||||||
|
colorPanel.add(revert, GBC.grid(2, selected).insets(0, 2));
|
||||||
|
colorChooser.setColor(colorButtons.get(selected).getColor());
|
||||||
|
revalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a color is selected in the color chooser, update the selected
|
||||||
|
* color button (if any.)
|
||||||
|
*/
|
||||||
|
public void stateChanged(ChangeEvent event) {
|
||||||
|
if (selected != -1) {
|
||||||
|
colorButtons.get(selected).setColor(colorChooser.getColor());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------- INHERITED
|
||||||
|
|
||||||
|
@Override void doDelayedSettingChange() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the localized name of this tab.
|
||||||
|
*/
|
||||||
|
@Override public String toString() {
|
||||||
|
return "" + Language.COLORS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------- UTILITIES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Places all sub-components within this panel.
|
||||||
|
*/
|
||||||
|
private void place() {
|
||||||
|
setLayout(new GridBagLayout());
|
||||||
|
|
||||||
|
colorPanel = new JPanel(new GridBagLayout()); {
|
||||||
|
for (int row = 0; row < colorButtons.size(); row++) {
|
||||||
|
colorPanel.add(
|
||||||
|
colorTexts.get(row),
|
||||||
|
GBC.grid(0, row).anchor(GBC.LE).insets(1, 4)
|
||||||
|
);
|
||||||
|
colorPanel.add(
|
||||||
|
colorButtons.get(row), GBC.grid(1, row).insets(2, 0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
colorPanel.add(placeHolder, GBC.grid(2, 0).insets(0, 2));
|
||||||
|
}
|
||||||
|
JPanel swatchPanel = new JPanel(new GridBagLayout()); {
|
||||||
|
swatchPanel.add(colorChooser, GBC.grid(0, 0));
|
||||||
|
swatchPanel.add(helperText, GBC.grid(0, 1));
|
||||||
|
}
|
||||||
|
add(colorPanel, GBC.grid(0, 0).fill(GBC.B));
|
||||||
|
add(swatchPanel, GBC.grid(1, 0).fill(GBC.B));
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------- INTERNAL TYPES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A kind of {@code JButton} that displays a color setting by painting
|
||||||
|
* itself in that color. When the color is programatically set, the color
|
||||||
|
* setting is automatically updated by the button. Each button stores an
|
||||||
|
* index only valid in the owning view’s context and the initial value it
|
||||||
|
* was constructed with, allowing for a reset.
|
||||||
|
*
|
||||||
|
* @author Xavier "Xunkar" Sencert
|
||||||
|
*/
|
||||||
|
class ColorButton extends JButton implements Comparable<ColorButton> {
|
||||||
|
|
||||||
|
// ---------------------------------------------------- ATTRIBUTES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Index of this color button in the englobing model.
|
||||||
|
*/
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Color currently represented by this button.
|
||||||
|
*/
|
||||||
|
private Color color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Color initially represented by this button. Used to revert to the
|
||||||
|
* setting initial state.
|
||||||
|
*/
|
||||||
|
private Color initialColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Color setting that this button represent. When the user selectes
|
||||||
|
* a new color, this setting is updated with the user's choice.
|
||||||
|
*/
|
||||||
|
private Settings.Property<Color> setting;
|
||||||
|
|
||||||
|
// -------------------------------------------------- CONSTRUCTORS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a button representing the given setting. An index must be
|
||||||
|
* supplied to identify this button. The name of the setting becomes
|
||||||
|
* the name of the button.
|
||||||
|
*
|
||||||
|
* @param index - the index of this button.
|
||||||
|
* @param setting - the setting represented by this button.
|
||||||
|
*/
|
||||||
|
ColorButton(int index, Settings.Property<Color> setting) {
|
||||||
|
super(".");
|
||||||
|
|
||||||
|
color = setting.get();
|
||||||
|
initialColor = color;
|
||||||
|
this.index = index;
|
||||||
|
this.setting = setting;
|
||||||
|
|
||||||
|
setName(setting.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------- GETTERS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current color of this button.
|
||||||
|
*
|
||||||
|
* @return the current color.
|
||||||
|
*/
|
||||||
|
Color getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the index of this button.
|
||||||
|
*
|
||||||
|
* @return the index of this button.
|
||||||
|
*/
|
||||||
|
int getIndex() {
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------- SETTERS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the color that this button should display. Updates the setting
|
||||||
|
* and repaints itself.
|
||||||
|
*
|
||||||
|
* @param color - the new color to display.
|
||||||
|
*/
|
||||||
|
void setColor(Color color) {
|
||||||
|
this.color = color;
|
||||||
|
setting.set(color);
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the color to be displayed by this button to the initial
|
||||||
|
* color it was constructed with.
|
||||||
|
*/
|
||||||
|
void resetColor() {
|
||||||
|
setColor(initialColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------- INHERITED
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two {@code ColorButton}s are compared using the lexicographic
|
||||||
|
* comparison of their name.
|
||||||
|
*/
|
||||||
|
public int compareTo(ColorButton o) {
|
||||||
|
if (o == null) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return getName().compareTo(o.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@code ColorButton} paints itself in the color he should
|
||||||
|
* display and does not display any string of text.
|
||||||
|
*/
|
||||||
|
@Override protected void paintComponent(Graphics g) {
|
||||||
|
super.paintComponent(g);
|
||||||
|
g.setColor(color);
|
||||||
|
g.fillRect(0, 0, getWidth(), getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
187
src/main/java/org/fenix/llanfair/extern/WSplit.java
vendored
187
src/main/java/org/fenix/llanfair/extern/WSplit.java
vendored
|
@ -1,13 +1,14 @@
|
||||||
package org.fenix.llanfair.extern;
|
package org.fenix.llanfair.extern;
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import javax.swing.ImageIcon;
|
|
||||||
import org.fenix.llanfair.Llanfair;
|
import org.fenix.llanfair.Llanfair;
|
||||||
import org.fenix.llanfair.Run;
|
import org.fenix.llanfair.Run;
|
||||||
import org.fenix.llanfair.Segment;
|
import org.fenix.llanfair.Segment;
|
||||||
import org.fenix.llanfair.Time;
|
import org.fenix.llanfair.Time;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class that provides method to interface with WSplit.
|
* Utility class that provides method to interface with WSplit.
|
||||||
*
|
*
|
||||||
|
@ -15,95 +16,95 @@ import org.fenix.llanfair.Time;
|
||||||
* @version 1.1
|
* @version 1.1
|
||||||
*/
|
*/
|
||||||
public class WSplit {
|
public class WSplit {
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the given stream opened on a WSplit run file and sets it as
|
|
||||||
* the currently opened run in Llanfair.
|
|
||||||
*
|
|
||||||
* @param master the Llanfair instance calling the parser
|
|
||||||
* @param in an opened stream on a WSplit run file
|
|
||||||
* @throws Exception if the reading operation cannot complete
|
|
||||||
*/
|
|
||||||
public static void parse( Llanfair master, BufferedReader in )
|
|
||||||
throws Exception {
|
|
||||||
if ( master == null ) {
|
|
||||||
throw new NullPointerException( "Null Llanfair instance" );
|
|
||||||
}
|
|
||||||
if ( in == null ) {
|
|
||||||
throw new NullPointerException( "Null file reader" );
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
// Title
|
|
||||||
String line = in.readLine();
|
|
||||||
Run run = new Run( line.split( "=" )[1] );
|
|
||||||
// Attempts, Offset, Size
|
|
||||||
in.readLine();
|
|
||||||
in.readLine();
|
|
||||||
in.readLine();
|
|
||||||
// Segment List
|
|
||||||
line = parseSegments( in, run );
|
|
||||||
// Segment Icons
|
|
||||||
parseIcons( line, run );
|
|
||||||
master.setRun( run );
|
|
||||||
} catch ( Exception ex ) {
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the list of segment in a WSplit run file. The segment list is
|
|
||||||
* formatted like this: each segment is on one line and comprised of the
|
|
||||||
* following information: Name, Old Time, Best Time, Best Segment
|
|
||||||
* comma-separated.
|
|
||||||
*
|
|
||||||
* @param in the opened stream on a WSplit run file
|
|
||||||
* @param run the run currently built by the parser
|
|
||||||
* @return the currently read line marker
|
|
||||||
* @throws IOException if reading operations fail
|
|
||||||
*/
|
|
||||||
private static String parseSegments( BufferedReader in, Run run )
|
|
||||||
throws IOException {
|
|
||||||
String line;
|
|
||||||
while ( !( line = in.readLine() ).startsWith( "Icons" ) ) {
|
|
||||||
String[] args = line.split( "," );
|
|
||||||
Segment segment = new Segment( args[0] );
|
|
||||||
run.addSegment( segment );
|
|
||||||
|
|
||||||
double parsed = Double.parseDouble( args[2] );
|
/**
|
||||||
run.setValueAt(
|
* Parses the given stream opened on a WSplit run file and sets it as
|
||||||
parsed == 0.0 ? null : new Time( parsed ),
|
* the currently opened run in Llanfair.
|
||||||
run.getRowCount() - 1, Run.COLUMN_TIME
|
*
|
||||||
);
|
* @param master the Llanfair instance calling the parser
|
||||||
parsed = Double.parseDouble( args[3] );
|
* @param in an opened stream on a WSplit run file
|
||||||
segment.setTime(
|
* @throws Exception if the reading operation cannot complete
|
||||||
parsed == 0.0 ? null : new Time(parsed), Segment.BEST
|
*/
|
||||||
);
|
public static void parse( Llanfair master, BufferedReader in )
|
||||||
}
|
throws Exception {
|
||||||
return line;
|
if ( master == null ) {
|
||||||
}
|
throw new NullPointerException( "Null Llanfair instance" );
|
||||||
|
}
|
||||||
/**
|
if ( in == null ) {
|
||||||
* Parses the list of segment icons in a WSplit run file. The list is a
|
throw new NullPointerException( "Null file reader" );
|
||||||
* single line, listing the icons in the segment order and formatted as
|
}
|
||||||
* follows: Icons="icon1","icon2",...,"iconN"
|
try {
|
||||||
*
|
// Title
|
||||||
* @param line the line containing the icon list
|
String line = in.readLine();
|
||||||
* @param run the run currently built by the parser
|
Run run = new Run( line.split( "=" )[1] );
|
||||||
* @throws IOException if reading operations fail
|
// Attempts, Offset, Size
|
||||||
*/
|
in.readLine();
|
||||||
private static void parseIcons( String line, Run run ) throws IOException {
|
in.readLine();
|
||||||
line = line.substring( line.indexOf( "=" ) + 1 );
|
in.readLine();
|
||||||
String[] args = line.split( "," );
|
// Segment List
|
||||||
|
line = parseSegments( in, run );
|
||||||
for ( int i = 0; i < args.length; i++ ) {
|
// Segment Icons
|
||||||
ImageIcon icon = null;
|
parseIcons( line, run );
|
||||||
String[] lst = args[i].split( "\\\"" );
|
master.setRun( run );
|
||||||
|
} catch ( Exception ex ) {
|
||||||
if ( lst.length > 0 && !lst[1].equals( "" ) ) {
|
throw ex;
|
||||||
icon = new ImageIcon( lst[1] );
|
}
|
||||||
}
|
}
|
||||||
run.getSegment( i ).setIcon( icon );
|
|
||||||
}
|
/**
|
||||||
}
|
* Parses the list of segment in a WSplit run file. The segment list is
|
||||||
|
* formatted like this: each segment is on one line and comprised of the
|
||||||
|
* following information: Name, Old Time, Best Time, Best Segment
|
||||||
|
* comma-separated.
|
||||||
|
*
|
||||||
|
* @param in the opened stream on a WSplit run file
|
||||||
|
* @param run the run currently built by the parser
|
||||||
|
* @return the currently read line marker
|
||||||
|
* @throws IOException if reading operations fail
|
||||||
|
*/
|
||||||
|
private static String parseSegments( BufferedReader in, Run run )
|
||||||
|
throws IOException {
|
||||||
|
String line;
|
||||||
|
while ( !( line = in.readLine() ).startsWith( "Icons" ) ) {
|
||||||
|
String[] args = line.split( "," );
|
||||||
|
Segment segment = new Segment( args[0] );
|
||||||
|
run.addSegment( segment );
|
||||||
|
|
||||||
|
double parsed = Double.parseDouble( args[2] );
|
||||||
|
run.setValueAt(
|
||||||
|
parsed == 0.0 ? null : new Time( parsed ),
|
||||||
|
run.getRowCount() - 1, Run.COLUMN_TIME
|
||||||
|
);
|
||||||
|
parsed = Double.parseDouble( args[3] );
|
||||||
|
segment.setTime(
|
||||||
|
parsed == 0.0 ? null : new Time(parsed), Segment.BEST
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the list of segment icons in a WSplit run file. The list is a
|
||||||
|
* single line, listing the icons in the segment order and formatted as
|
||||||
|
* follows: Icons="icon1","icon2",...,"iconN"
|
||||||
|
*
|
||||||
|
* @param line the line containing the icon list
|
||||||
|
* @param run the run currently built by the parser
|
||||||
|
* @throws IOException if reading operations fail
|
||||||
|
*/
|
||||||
|
private static void parseIcons( String line, Run run ) throws IOException {
|
||||||
|
line = line.substring( line.indexOf( "=" ) + 1 );
|
||||||
|
String[] args = line.split( "," );
|
||||||
|
|
||||||
|
for ( int i = 0; i < args.length; i++ ) {
|
||||||
|
ImageIcon icon = null;
|
||||||
|
String[] lst = args[i].split( "\\\"" );
|
||||||
|
|
||||||
|
if ( lst.length > 0 && !lst[1].equals( "" ) ) {
|
||||||
|
icon = new ImageIcon( lst[1] );
|
||||||
|
}
|
||||||
|
run.getSegment( i ).setIcon( icon );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -29,464 +29,464 @@ import org.fenix.utils.locale.LocaleEvent;
|
||||||
*/
|
*/
|
||||||
class Footer extends JPanel {
|
class Footer extends JPanel {
|
||||||
|
|
||||||
private static final int ALL = 0xff;
|
private static final int ALL = 0xff;
|
||||||
private static final int TIME = 0x01;
|
private static final int TIME = 0x01;
|
||||||
private static final int DELTA = 0x02;
|
private static final int DELTA = 0x02;
|
||||||
private static final int TEXT = 0x04;
|
private static final int TEXT = 0x04;
|
||||||
private static final int BEST = 0x08;
|
private static final int BEST = 0x08;
|
||||||
private static final int VERBOSE = 0x10;
|
private static final int VERBOSE = 0x10;
|
||||||
|
|
||||||
private static final int INSET = 3;
|
private static final int INSET = 3;
|
||||||
|
|
||||||
|
|
||||||
private Run run;
|
private Run run;
|
||||||
private Time tmDlta;
|
private Time tmDlta;
|
||||||
|
|
||||||
private JLabel labelPrev; // P.Se:
|
|
||||||
private JLabel liveL; // Left-hand Live Time
|
|
||||||
private JLabel liveR; // Right-hand Live Time
|
|
||||||
private JLabel time; // Segment Set Time
|
|
||||||
|
|
||||||
private JLabel labelDelta; // Delta:
|
|
||||||
private JLabel labelLive; // Live:
|
|
||||||
private JLabel delta; // Delta Segment Set/Live Time
|
|
||||||
|
|
||||||
private JLabel labelBest; // P.Be:
|
|
||||||
private JLabel best; // Segment Best Time
|
|
||||||
private JLabel inlineBest; // Segment Best Time (inline)
|
|
||||||
|
|
||||||
private JLabel labelDeltaBest; // B.Delta:
|
|
||||||
private JLabel deltaBest; // Delta Segment Best/Live Time
|
|
||||||
private JLabel inlineDeltaBest; // Delta Segment Best/Live Time (inline)
|
|
||||||
|
|
||||||
private JPanel panelBest; // labelBest + best
|
private JLabel labelPrev; // P.Se:
|
||||||
private JPanel panelDeltaBest; // labelDeltaBest + deltaBest
|
private JLabel liveL; // Left-hand Live Time
|
||||||
|
private JLabel liveR; // Right-hand Live Time
|
||||||
private boolean resize;
|
private JLabel time; // Segment Set Time
|
||||||
private Dimension preferredSize;
|
|
||||||
|
|
||||||
/**
|
private JLabel labelDelta; // Delta:
|
||||||
* Creates a default panel displaying informations for the given run.
|
private JLabel labelLive; // Live:
|
||||||
*
|
private JLabel delta; // Delta Segment Set/Live Time
|
||||||
* @param run - the run to represent.
|
|
||||||
*/
|
|
||||||
Footer(Run run) {
|
|
||||||
time = new JLabel();
|
|
||||||
liveL = new JLabel();
|
|
||||||
liveR = new JLabel();
|
|
||||||
delta = new JLabel();
|
|
||||||
best = new JLabel();
|
|
||||||
deltaBest = new JLabel();
|
|
||||||
inlineBest = new JLabel();
|
|
||||||
inlineDeltaBest = new JLabel();
|
|
||||||
|
|
||||||
labelLive = new JLabel();
|
|
||||||
labelPrev = new JLabel();
|
|
||||||
labelBest = new JLabel();
|
|
||||||
labelDelta = new JLabel();
|
|
||||||
labelDeltaBest = new JLabel();
|
|
||||||
|
|
||||||
preferredSize = null;
|
|
||||||
resize = false;
|
|
||||||
|
|
||||||
setRun(run);
|
|
||||||
setOpaque(false);
|
|
||||||
|
|
||||||
placeComponents();
|
|
||||||
updateValues(TEXT);
|
|
||||||
updateColors(ALL);
|
|
||||||
updateVisibility(ALL);
|
|
||||||
forceResize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public Dimension getPreferredSize() {
|
private JLabel labelBest; // P.Be:
|
||||||
Graphics graphics = getGraphics();
|
private JLabel best; // Segment Best Time
|
||||||
if (resize && (graphics != null)) {
|
private JLabel inlineBest; // Segment Best Time (inline)
|
||||||
FontMetrics metrics = graphics.getFontMetrics();
|
|
||||||
|
private JLabel labelDeltaBest; // B.Delta:
|
||||||
int timeW;
|
private JLabel deltaBest; // Delta Segment Best/Live Time
|
||||||
int timeH = metrics.getHeight();
|
private JLabel inlineDeltaBest; // Delta Segment Best/Live Time (inline)
|
||||||
int smtmW;
|
|
||||||
if (run.getRowCount() > 0) {
|
private JPanel panelBest; // labelBest + best
|
||||||
Time segmentTime = run.getSegment(0).getTime(Segment.RUN);
|
private JPanel panelDeltaBest; // labelDeltaBest + deltaBest
|
||||||
Time tenthTime = new Time(segmentTime.getMilliseconds() / 10L);
|
|
||||||
timeW = metrics.stringWidth("" + segmentTime);
|
private boolean resize;
|
||||||
smtmW = metrics.stringWidth("" + tenthTime);
|
private Dimension preferredSize;
|
||||||
} else {
|
|
||||||
timeW = metrics.stringWidth("" + Time.ZERO);
|
/**
|
||||||
smtmW = timeW;
|
* Creates a default panel displaying informations for the given run.
|
||||||
}
|
*
|
||||||
|
* @param run - the run to represent.
|
||||||
|
*/
|
||||||
|
Footer(Run run) {
|
||||||
|
time = new JLabel();
|
||||||
|
liveL = new JLabel();
|
||||||
|
liveR = new JLabel();
|
||||||
|
delta = new JLabel();
|
||||||
|
best = new JLabel();
|
||||||
|
deltaBest = new JLabel();
|
||||||
|
inlineBest = new JLabel();
|
||||||
|
inlineDeltaBest = new JLabel();
|
||||||
|
|
||||||
|
labelLive = new JLabel();
|
||||||
|
labelPrev = new JLabel();
|
||||||
|
labelBest = new JLabel();
|
||||||
|
labelDelta = new JLabel();
|
||||||
|
labelDeltaBest = new JLabel();
|
||||||
|
|
||||||
|
preferredSize = null;
|
||||||
|
resize = false;
|
||||||
|
|
||||||
|
setRun(run);
|
||||||
|
setOpaque(false);
|
||||||
|
|
||||||
|
placeComponents();
|
||||||
|
updateValues(TEXT);
|
||||||
|
updateColors(ALL);
|
||||||
|
updateVisibility(ALL);
|
||||||
|
forceResize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public Dimension getPreferredSize() {
|
||||||
|
Graphics graphics = getGraphics();
|
||||||
|
if (resize && (graphics != null)) {
|
||||||
|
FontMetrics metrics = graphics.getFontMetrics();
|
||||||
|
|
||||||
|
int timeW;
|
||||||
|
int timeH = metrics.getHeight();
|
||||||
|
int smtmW;
|
||||||
|
if (run.getRowCount() > 0) {
|
||||||
|
Time segmentTime = run.getSegment(0).getTime(Segment.RUN);
|
||||||
|
Time tenthTime = new Time(segmentTime.getMilliseconds() / 10L);
|
||||||
|
timeW = metrics.stringWidth("" + segmentTime);
|
||||||
|
smtmW = metrics.stringWidth("" + tenthTime);
|
||||||
|
} else {
|
||||||
|
timeW = metrics.stringWidth("" + Time.ZERO);
|
||||||
|
smtmW = timeW;
|
||||||
|
}
|
||||||
|
|
||||||
int liveW = metrics.stringWidth("" + Language.LB_FT_LIVE);
|
int liveW = metrics.stringWidth("" + Language.LB_FT_LIVE);
|
||||||
int prevW = metrics.stringWidth("" + Language.LB_FT_SEGMENT);
|
int prevW = metrics.stringWidth("" + Language.LB_FT_SEGMENT);
|
||||||
int bestW = metrics.stringWidth("" + Language.LB_FT_BEST);
|
int bestW = metrics.stringWidth("" + Language.LB_FT_BEST);
|
||||||
int dltaW = metrics.stringWidth("" + Language.LB_FT_DELTA);
|
int dltaW = metrics.stringWidth("" + Language.LB_FT_DELTA);
|
||||||
int dltbW = metrics.stringWidth("" + Language.LB_FT_DELTA_BEST);
|
int dltbW = metrics.stringWidth("" + Language.LB_FT_DELTA_BEST);
|
||||||
|
|
||||||
boolean ftBest = Settings.FOO_BEST.get();
|
|
||||||
boolean ftLabels = Settings.FOO_DLBL.get();
|
|
||||||
boolean ftVerbose = Settings.FOO_VERB.get();
|
|
||||||
boolean ftTwoLines = Settings.FOO_LINE.get();
|
|
||||||
|
|
||||||
int height = timeH;
|
|
||||||
int width = prevW + timeW + smtmW + INSET * 2;
|
|
||||||
if (ftLabels) {
|
|
||||||
width += dltaW;
|
|
||||||
}
|
|
||||||
if (ftVerbose) {
|
|
||||||
width += timeW + liveW - (ftLabels ? 0 : dltaW)
|
|
||||||
+ metrics.stringWidth(" []");
|
|
||||||
}
|
|
||||||
if (ftBest) {
|
|
||||||
if (ftTwoLines) {
|
|
||||||
height *= 2;
|
|
||||||
int breakW = bestW + timeW + smtmW + (ftLabels ? dltbW : 0);
|
|
||||||
width = Math.max(width, breakW);
|
|
||||||
} else {
|
|
||||||
width += timeW + smtmW + metrics.stringWidth("| ");
|
|
||||||
}
|
|
||||||
if (ftVerbose) {
|
|
||||||
width += 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
preferredSize = new Dimension(width, height);
|
|
||||||
setMinimumSize(new Dimension(50, height));
|
|
||||||
resize = false;
|
|
||||||
}
|
|
||||||
return (preferredSize == null ? getMinimumSize() : preferredSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the run to represent. All components are resetted to their initial
|
|
||||||
* state.
|
|
||||||
*
|
|
||||||
* @param run - the new run to represent.
|
|
||||||
*/
|
|
||||||
final void setRun(Run run) {
|
|
||||||
this.run = run;
|
|
||||||
updateValues(ALL & ~TEXT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- CALLBACKS
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback invoked by the parent when the run or the application's
|
|
||||||
* settings have seen one of their properties updated.
|
|
||||||
*
|
|
||||||
* @param event - the event describing the update.
|
|
||||||
*/
|
|
||||||
void processPropertyChangeEvent(PropertyChangeEvent event) {
|
|
||||||
String property = event.getPropertyName();
|
|
||||||
|
|
||||||
if (Run.CURRENT_SEGMENT_PROPERTY.equals(property)) {
|
|
||||||
updateValues(ALL & ~TEXT);
|
|
||||||
updateColors(TIME | DELTA);
|
|
||||||
updateVisibility(ALL);
|
|
||||||
} else if (Settings.CLR_LOST.equals(property)
|
|
||||||
|| Settings.CLR_GAIN.equals(property)) {
|
|
||||||
updateColors(DELTA);
|
|
||||||
|
|
||||||
} else if (Settings.CLR_TIME.equals(property)
|
|
||||||
|| Settings.CLR_RCRD.equals(property)) {
|
|
||||||
updateColors(TIME | DELTA);
|
|
||||||
|
|
||||||
} else if (Settings.CLR_FORE.equals(property)) {
|
|
||||||
updateColors(TEXT);
|
|
||||||
|
|
||||||
} else if (Settings.GNR_ACCY.equals(property)
|
|
||||||
|| Settings.GNR_COMP.equals(property)) {
|
|
||||||
updateValues(ALL & ~TEXT);
|
|
||||||
forceResize();
|
|
||||||
|
|
||||||
} else if (Run.STATE_PROPERTY.equals(property)) {
|
|
||||||
if (run.getState() == State.NULL || run.getState() == State.READY) {
|
|
||||||
updateValues(ALL & ~TEXT);
|
|
||||||
}
|
|
||||||
updateVisibility(ALL);
|
|
||||||
} else if (Settings.FOO_SPLT.equals(property)) {
|
|
||||||
updateValues(ALL);
|
|
||||||
} else if (Settings.FOO_BEST.equals(property)
|
|
||||||
|| Settings.FOO_LINE.equals(property)) {
|
|
||||||
|
|
||||||
updateVisibility(BEST);
|
|
||||||
forceResize();
|
|
||||||
} else if (Settings.FOO_DLBL.equals(property)) {
|
|
||||||
updateVisibility(TEXT);
|
|
||||||
forceResize();
|
|
||||||
} else if (Settings.FOO_VERB.equals(property)) {
|
|
||||||
updateValues(DELTA);
|
|
||||||
updateVisibility(VERBOSE);
|
|
||||||
forceResize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void forceResize() {
|
|
||||||
resize = true;
|
|
||||||
revalidate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback invoked by the parent when default local for this instance of
|
|
||||||
* the JVM has changed.
|
|
||||||
*
|
|
||||||
* @param event - the event describing the update.
|
|
||||||
*/
|
|
||||||
void processLocaleEvent(LocaleEvent event) {
|
|
||||||
updateValues(TEXT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- UTILITIES
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Places the sub-components within this component.
|
|
||||||
*/
|
|
||||||
private void placeComponents() {
|
|
||||||
setLayout(new GridBagLayout());
|
|
||||||
|
|
||||||
JPanel timePanel = new JPanel(new GridBagLayout()); {
|
boolean ftBest = Settings.FOO_BEST.get();
|
||||||
timePanel.add(
|
boolean ftLabels = Settings.FOO_DLBL.get();
|
||||||
labelPrev,
|
boolean ftVerbose = Settings.FOO_VERB.get();
|
||||||
GBC.grid(0, 0).anchor(GBC.LS).insets(0, 0, 0, INSET)
|
boolean ftTwoLines = Settings.FOO_LINE.get();
|
||||||
);
|
|
||||||
timePanel.add(liveL, GBC.grid(1, 0).anchor(GBC.LS));
|
int height = timeH;
|
||||||
timePanel.add(time, GBC.grid(2, 0).anchor(GBC.LS));
|
int width = prevW + timeW + smtmW + INSET * 2;
|
||||||
timePanel.add(
|
if (ftLabels) {
|
||||||
inlineBest,
|
width += dltaW;
|
||||||
GBC.grid(3, 0).anchor(GBC.LS).insets(0, INSET, 0, 0)
|
}
|
||||||
);
|
if (ftVerbose) {
|
||||||
timePanel.setOpaque(false);
|
width += timeW + liveW - (ftLabels ? 0 : dltaW)
|
||||||
}
|
+ metrics.stringWidth(" []");
|
||||||
JPanel deltaPanel = new JPanel(new GridBagLayout()); {
|
}
|
||||||
deltaPanel.add(
|
if (ftBest) {
|
||||||
labelDelta,
|
if (ftTwoLines) {
|
||||||
GBC.grid(0, 0).anchor(GBC.LE).insets(0, 0, 0, INSET)
|
height *= 2;
|
||||||
);
|
int breakW = bestW + timeW + smtmW + (ftLabels ? dltbW : 0);
|
||||||
deltaPanel.add(
|
width = Math.max(width, breakW);
|
||||||
labelLive,
|
} else {
|
||||||
GBC.grid(1, 0).anchor(GBC.LE).insets(0, 0, 0, INSET)
|
width += timeW + smtmW + metrics.stringWidth("| ");
|
||||||
);
|
}
|
||||||
deltaPanel.add(
|
if (ftVerbose) {
|
||||||
liveR, GBC.grid(2, 0).anchor(GBC.LE).insets(0, 0, 0, INSET)
|
width += 5;
|
||||||
);
|
}
|
||||||
deltaPanel.add(delta, GBC.grid(3, 0).anchor(GBC.LE));
|
}
|
||||||
deltaPanel.add(
|
preferredSize = new Dimension(width, height);
|
||||||
inlineDeltaBest,
|
setMinimumSize(new Dimension(50, height));
|
||||||
GBC.grid(4, 0).anchor(GBC.LE).insets(0, INSET, 0, 0)
|
resize = false;
|
||||||
);
|
}
|
||||||
deltaPanel.setOpaque(false);
|
return (preferredSize == null ? getMinimumSize() : preferredSize);
|
||||||
}
|
}
|
||||||
panelBest = new JPanel(new GridBagLayout()); {
|
|
||||||
panelBest.add(
|
|
||||||
labelBest,
|
|
||||||
GBC.grid(0, 0).anchor(GBC.LS).insets(0, 0, 0, INSET)
|
/**
|
||||||
);
|
* Sets the run to represent. All components are resetted to their initial
|
||||||
panelBest.add(best, GBC.grid(1, 0).anchor(GBC.LS));
|
* state.
|
||||||
panelBest.setOpaque(false);
|
*
|
||||||
}
|
* @param run - the new run to represent.
|
||||||
panelDeltaBest = new JPanel(new GridBagLayout()); {
|
*/
|
||||||
panelDeltaBest.add(
|
final void setRun(Run run) {
|
||||||
labelDeltaBest,
|
this.run = run;
|
||||||
GBC.grid(0, 0).anchor(GBC.LE).insets(0, 0, 0, INSET)
|
updateValues(ALL & ~TEXT);
|
||||||
);
|
}
|
||||||
panelDeltaBest.add(deltaBest, GBC.grid(1, 0).anchor(GBC.LE));
|
|
||||||
panelDeltaBest.setOpaque(false);
|
// -------------------------------------------------------------- CALLBACKS
|
||||||
}
|
|
||||||
add(timePanel, GBC.grid(0, 0).anchor(GBC.LS).weight(0.5, 0.0));
|
/**
|
||||||
add(deltaPanel, GBC.grid(1, 0).anchor(GBC.LE).weight(0.5, 0.0));
|
* Callback invoked by the parent when the run or the application's
|
||||||
add(panelBest, GBC.grid(0, 1).anchor(GBC.LS).weight(0.5, 0.0));
|
* settings have seen one of their properties updated.
|
||||||
add(panelDeltaBest, GBC.grid(1, 1).anchor(GBC.LE).weight(0.5, 0.0));
|
*
|
||||||
}
|
* @param event - the event describing the update.
|
||||||
|
*/
|
||||||
private void updateVisibility(int identifier) {
|
void processPropertyChangeEvent(PropertyChangeEvent event) {
|
||||||
if ((identifier & BEST) == BEST) {
|
String property = event.getPropertyName();
|
||||||
boolean ftTwoLines = Settings.FOO_LINE.get();
|
|
||||||
boolean ftBest = Settings.FOO_BEST.get();
|
if (Run.CURRENT_SEGMENT_PROPERTY.equals(property)) {
|
||||||
panelBest.setVisible(ftTwoLines);
|
updateValues(ALL & ~TEXT);
|
||||||
panelDeltaBest.setVisible(ftTwoLines);
|
updateColors(TIME | DELTA);
|
||||||
inlineBest.setVisible(!ftTwoLines && ftBest);
|
updateVisibility(ALL);
|
||||||
inlineDeltaBest.setVisible(!ftTwoLines && ftBest);
|
} else if (Settings.CLR_LOST.equals(property)
|
||||||
}
|
|| Settings.CLR_GAIN.equals(property)) {
|
||||||
if ((identifier & TEXT) == TEXT) {
|
updateColors(DELTA);
|
||||||
boolean ftLabels = Settings.FOO_DLBL.get();
|
|
||||||
boolean ftVerbose = Settings.FOO_VERB.get();
|
} else if (Settings.CLR_TIME.equals(property)
|
||||||
labelLive.setVisible(ftLabels && ftVerbose);
|
|| Settings.CLR_RCRD.equals(property)) {
|
||||||
labelDelta.setVisible(ftLabels && !ftVerbose);
|
updateColors(TIME | DELTA);
|
||||||
labelDeltaBest.setVisible(ftLabels);
|
|
||||||
}
|
} else if (Settings.CLR_FORE.equals(property)) {
|
||||||
if ((identifier & VERBOSE) == VERBOSE) {
|
updateColors(TEXT);
|
||||||
boolean ftVerbose = Settings.FOO_VERB.get();
|
|
||||||
boolean ftLabels = Settings.FOO_DLBL.get();
|
} else if (Settings.GNR_ACCY.equals(property)
|
||||||
labelLive.setVisible(ftVerbose && ftLabels);
|
|| Settings.GNR_COMP.equals(property)) {
|
||||||
labelDelta.setVisible(!ftVerbose && ftLabels);
|
updateValues(ALL & ~TEXT);
|
||||||
time.setVisible(ftVerbose);
|
forceResize();
|
||||||
liveL.setVisible(!ftVerbose);
|
|
||||||
liveR.setVisible(ftVerbose);
|
} else if (Run.STATE_PROPERTY.equals(property)) {
|
||||||
}
|
if (run.getState() == State.NULL || run.getState() == State.READY) {
|
||||||
}
|
updateValues(ALL & ~TEXT);
|
||||||
|
}
|
||||||
/**
|
updateVisibility(ALL);
|
||||||
* Updates the colors of the group of components specified by the
|
} else if (Settings.FOO_SPLT.equals(property)) {
|
||||||
* identifier.
|
updateValues(ALL);
|
||||||
*
|
} else if (Settings.FOO_BEST.equals(property)
|
||||||
* @param identifier - one of the constant update identifier.
|
|| Settings.FOO_LINE.equals(property)) {
|
||||||
*/
|
|
||||||
private void updateColors(int identifier) {
|
updateVisibility(BEST);
|
||||||
if ((identifier & TIME) == TIME) {
|
forceResize();
|
||||||
Color colorTM = Settings.CLR_TIME.get();
|
} else if (Settings.FOO_DLBL.equals(property)) {
|
||||||
Color colorNR = Settings.CLR_RCRD.get();
|
updateVisibility(TEXT);
|
||||||
if (run.hasPreviousSegment() && run.isBestSegment(run.getPrevious())) {
|
forceResize();
|
||||||
liveL.setForeground(colorNR);
|
} else if (Settings.FOO_VERB.equals(property)) {
|
||||||
liveR.setForeground(colorNR);
|
updateValues(DELTA);
|
||||||
} else {
|
updateVisibility(VERBOSE);
|
||||||
liveL.setForeground(colorTM);
|
forceResize();
|
||||||
liveR.setForeground(colorTM);
|
}
|
||||||
}
|
}
|
||||||
time.setForeground(colorTM);
|
|
||||||
best.setForeground(colorTM);
|
private void forceResize() {
|
||||||
inlineBest.setForeground(colorTM);
|
resize = true;
|
||||||
}
|
revalidate();
|
||||||
if ((identifier & DELTA) == DELTA) {
|
}
|
||||||
if (run.hasPreviousSegment()) {
|
|
||||||
Color colorTM = Settings.CLR_TIME.get();
|
/**
|
||||||
deltaBest.setForeground(colorTM);
|
* Callback invoked by the parent when default local for this instance of
|
||||||
inlineDeltaBest.setForeground(colorTM);
|
* the JVM has changed.
|
||||||
if (delta.getText().equals("--")) {
|
*
|
||||||
delta.setForeground(colorTM);
|
* @param event - the event describing the update.
|
||||||
} else if (run.isBestSegment(run.getPrevious())){
|
*/
|
||||||
Color colorNR = Settings.CLR_RCRD.get();
|
void processLocaleEvent(LocaleEvent event) {
|
||||||
delta.setForeground(colorNR);
|
updateValues(TEXT);
|
||||||
deltaBest.setForeground(colorNR);
|
}
|
||||||
inlineDeltaBest.setForeground(colorNR);
|
|
||||||
} else {
|
// -------------------------------------------------------------- UTILITIES
|
||||||
int compare = tmDlta.compareTo(Time.ZERO);
|
|
||||||
if (compare > 0) {
|
/**
|
||||||
delta.setForeground(Settings.CLR_LOST.get());
|
* Places the sub-components within this component.
|
||||||
} else {
|
*/
|
||||||
delta.setForeground(Settings.CLR_GAIN.get());
|
private void placeComponents() {
|
||||||
}
|
setLayout(new GridBagLayout());
|
||||||
}
|
|
||||||
}
|
JPanel timePanel = new JPanel(new GridBagLayout()); {
|
||||||
}
|
timePanel.add(
|
||||||
if ((identifier & TEXT) == TEXT) {
|
labelPrev,
|
||||||
Color color = Settings.CLR_FORE.get();
|
GBC.grid(0, 0).anchor(GBC.LS).insets(0, 0, 0, INSET)
|
||||||
labelPrev.setForeground(color);
|
);
|
||||||
labelDelta.setForeground(color);
|
timePanel.add(liveL, GBC.grid(1, 0).anchor(GBC.LS));
|
||||||
labelLive.setForeground(color);
|
timePanel.add(time, GBC.grid(2, 0).anchor(GBC.LS));
|
||||||
labelBest.setForeground(color);
|
timePanel.add(
|
||||||
labelDeltaBest.setForeground(color);
|
inlineBest,
|
||||||
}
|
GBC.grid(3, 0).anchor(GBC.LS).insets(0, INSET, 0, 0)
|
||||||
}
|
);
|
||||||
|
timePanel.setOpaque(false);
|
||||||
/**
|
}
|
||||||
* Updates the values of the group of components specified by the
|
JPanel deltaPanel = new JPanel(new GridBagLayout()); {
|
||||||
* identifier.
|
deltaPanel.add(
|
||||||
*
|
labelDelta,
|
||||||
* @param identifier - one of the constant update identifier.
|
GBC.grid(0, 0).anchor(GBC.LE).insets(0, 0, 0, INSET)
|
||||||
*/
|
);
|
||||||
private void updateValues(int identifier) {
|
deltaPanel.add(
|
||||||
boolean useSplit = Settings.FOO_SPLT.get();
|
labelLive,
|
||||||
boolean hasPrevious = run.hasPreviousSegment();
|
GBC.grid(1, 0).anchor(GBC.LE).insets(0, 0, 0, INSET)
|
||||||
int pIndex = run.getPrevious();
|
);
|
||||||
Segment pSegment = null;
|
deltaPanel.add(
|
||||||
Time live;
|
liveR, GBC.grid(2, 0).anchor(GBC.LE).insets(0, 0, 0, INSET)
|
||||||
|
);
|
||||||
|
deltaPanel.add(delta, GBC.grid(3, 0).anchor(GBC.LE));
|
||||||
|
deltaPanel.add(
|
||||||
|
inlineDeltaBest,
|
||||||
|
GBC.grid(4, 0).anchor(GBC.LE).insets(0, INSET, 0, 0)
|
||||||
|
);
|
||||||
|
deltaPanel.setOpaque(false);
|
||||||
|
}
|
||||||
|
panelBest = new JPanel(new GridBagLayout()); {
|
||||||
|
panelBest.add(
|
||||||
|
labelBest,
|
||||||
|
GBC.grid(0, 0).anchor(GBC.LS).insets(0, 0, 0, INSET)
|
||||||
|
);
|
||||||
|
panelBest.add(best, GBC.grid(1, 0).anchor(GBC.LS));
|
||||||
|
panelBest.setOpaque(false);
|
||||||
|
}
|
||||||
|
panelDeltaBest = new JPanel(new GridBagLayout()); {
|
||||||
|
panelDeltaBest.add(
|
||||||
|
labelDeltaBest,
|
||||||
|
GBC.grid(0, 0).anchor(GBC.LE).insets(0, 0, 0, INSET)
|
||||||
|
);
|
||||||
|
panelDeltaBest.add(deltaBest, GBC.grid(1, 0).anchor(GBC.LE));
|
||||||
|
panelDeltaBest.setOpaque(false);
|
||||||
|
}
|
||||||
|
add(timePanel, GBC.grid(0, 0).anchor(GBC.LS).weight(0.5, 0.0));
|
||||||
|
add(deltaPanel, GBC.grid(1, 0).anchor(GBC.LE).weight(0.5, 0.0));
|
||||||
|
add(panelBest, GBC.grid(0, 1).anchor(GBC.LS).weight(0.5, 0.0));
|
||||||
|
add(panelDeltaBest, GBC.grid(1, 1).anchor(GBC.LE).weight(0.5, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateVisibility(int identifier) {
|
||||||
|
if ((identifier & BEST) == BEST) {
|
||||||
|
boolean ftTwoLines = Settings.FOO_LINE.get();
|
||||||
|
boolean ftBest = Settings.FOO_BEST.get();
|
||||||
|
panelBest.setVisible(ftTwoLines);
|
||||||
|
panelDeltaBest.setVisible(ftTwoLines);
|
||||||
|
inlineBest.setVisible(!ftTwoLines && ftBest);
|
||||||
|
inlineDeltaBest.setVisible(!ftTwoLines && ftBest);
|
||||||
|
}
|
||||||
|
if ((identifier & TEXT) == TEXT) {
|
||||||
|
boolean ftLabels = Settings.FOO_DLBL.get();
|
||||||
|
boolean ftVerbose = Settings.FOO_VERB.get();
|
||||||
|
labelLive.setVisible(ftLabels && ftVerbose);
|
||||||
|
labelDelta.setVisible(ftLabels && !ftVerbose);
|
||||||
|
labelDeltaBest.setVisible(ftLabels);
|
||||||
|
}
|
||||||
|
if ((identifier & VERBOSE) == VERBOSE) {
|
||||||
|
boolean ftVerbose = Settings.FOO_VERB.get();
|
||||||
|
boolean ftLabels = Settings.FOO_DLBL.get();
|
||||||
|
labelLive.setVisible(ftVerbose && ftLabels);
|
||||||
|
labelDelta.setVisible(!ftVerbose && ftLabels);
|
||||||
|
time.setVisible(ftVerbose);
|
||||||
|
liveL.setVisible(!ftVerbose);
|
||||||
|
liveR.setVisible(ftVerbose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the colors of the group of components specified by the
|
||||||
|
* identifier.
|
||||||
|
*
|
||||||
|
* @param identifier - one of the constant update identifier.
|
||||||
|
*/
|
||||||
|
private void updateColors(int identifier) {
|
||||||
|
if ((identifier & TIME) == TIME) {
|
||||||
|
Color colorTM = Settings.CLR_TIME.get();
|
||||||
|
Color colorNR = Settings.CLR_RCRD.get();
|
||||||
|
if (run.hasPreviousSegment() && run.isBestSegment(run.getPrevious())) {
|
||||||
|
liveL.setForeground(colorNR);
|
||||||
|
liveR.setForeground(colorNR);
|
||||||
|
} else {
|
||||||
|
liveL.setForeground(colorTM);
|
||||||
|
liveR.setForeground(colorTM);
|
||||||
|
}
|
||||||
|
time.setForeground(colorTM);
|
||||||
|
best.setForeground(colorTM);
|
||||||
|
inlineBest.setForeground(colorTM);
|
||||||
|
}
|
||||||
|
if ((identifier & DELTA) == DELTA) {
|
||||||
|
if (run.hasPreviousSegment()) {
|
||||||
|
Color colorTM = Settings.CLR_TIME.get();
|
||||||
|
deltaBest.setForeground(colorTM);
|
||||||
|
inlineDeltaBest.setForeground(colorTM);
|
||||||
|
if (delta.getText().equals("--")) {
|
||||||
|
delta.setForeground(colorTM);
|
||||||
|
} else if (run.isBestSegment(run.getPrevious())){
|
||||||
|
Color colorNR = Settings.CLR_RCRD.get();
|
||||||
|
delta.setForeground(colorNR);
|
||||||
|
deltaBest.setForeground(colorNR);
|
||||||
|
inlineDeltaBest.setForeground(colorNR);
|
||||||
|
} else {
|
||||||
|
int compare = tmDlta.compareTo(Time.ZERO);
|
||||||
|
if (compare > 0) {
|
||||||
|
delta.setForeground(Settings.CLR_LOST.get());
|
||||||
|
} else {
|
||||||
|
delta.setForeground(Settings.CLR_GAIN.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((identifier & TEXT) == TEXT) {
|
||||||
|
Color color = Settings.CLR_FORE.get();
|
||||||
|
labelPrev.setForeground(color);
|
||||||
|
labelDelta.setForeground(color);
|
||||||
|
labelLive.setForeground(color);
|
||||||
|
labelBest.setForeground(color);
|
||||||
|
labelDeltaBest.setForeground(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the values of the group of components specified by the
|
||||||
|
* identifier.
|
||||||
|
*
|
||||||
|
* @param identifier - one of the constant update identifier.
|
||||||
|
*/
|
||||||
|
private void updateValues(int identifier) {
|
||||||
|
boolean useSplit = Settings.FOO_SPLT.get();
|
||||||
|
boolean hasPrevious = run.hasPreviousSegment();
|
||||||
|
int pIndex = run.getPrevious();
|
||||||
|
Segment pSegment = null;
|
||||||
|
Time live;
|
||||||
|
|
||||||
if (hasPrevious) {
|
if (hasPrevious) {
|
||||||
pSegment = run.getSegment(pIndex);
|
pSegment = run.getSegment(pIndex);
|
||||||
}
|
}
|
||||||
if ((identifier & TIME) == TIME) {
|
if ((identifier & TIME) == TIME) {
|
||||||
Time set;
|
Time set;
|
||||||
if (hasPrevious) {
|
if (hasPrevious) {
|
||||||
if (useSplit) {
|
if (useSplit) {
|
||||||
live = run.getTime(pIndex, Segment.LIVE);
|
live = run.getTime(pIndex, Segment.LIVE);
|
||||||
set = run.getTime(pIndex, Segment.SET);
|
set = run.getTime(pIndex, Segment.SET);
|
||||||
} else {
|
} else {
|
||||||
live = pSegment.getTime(Segment.LIVE);
|
live = pSegment.getTime(Segment.LIVE);
|
||||||
set = pSegment.getTime(Segment.SET);
|
set = pSegment.getTime(Segment.SET);
|
||||||
}
|
}
|
||||||
time.setText("" + (set == null ? "--" : set));
|
time.setText("" + (set == null ? "--" : set));
|
||||||
liveL.setText("" + (live == null ? "--" : live));
|
liveL.setText("" + (live == null ? "--" : live));
|
||||||
liveR.setText(liveL.getText());
|
liveR.setText(liveL.getText());
|
||||||
Time bTime = pSegment.getTime(Segment.BEST);
|
Time bTime = pSegment.getTime(Segment.BEST);
|
||||||
inlineBest.setText("| " + (bTime == null ? "--" : bTime));
|
inlineBest.setText("| " + (bTime == null ? "--" : bTime));
|
||||||
best.setText("" + (bTime == null ? "--" : bTime));
|
best.setText("" + (bTime == null ? "--" : bTime));
|
||||||
} else {
|
} else {
|
||||||
time.setText("");
|
time.setText("");
|
||||||
liveL.setText("");
|
liveL.setText("");
|
||||||
liveR.setText("");
|
liveR.setText("");
|
||||||
best.setText("");
|
best.setText("");
|
||||||
inlineBest.setText("");
|
inlineBest.setText("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((identifier & DELTA) == DELTA) {
|
if ((identifier & DELTA) == DELTA) {
|
||||||
if (hasPrevious) {
|
if (hasPrevious) {
|
||||||
if (useSplit) {
|
if (useSplit) {
|
||||||
tmDlta = run.getTime(pIndex, Segment.DELTA);
|
tmDlta = run.getTime(pIndex, Segment.DELTA);
|
||||||
live = run.getTime(pIndex, Segment.LIVE);
|
live = run.getTime(pIndex, Segment.LIVE);
|
||||||
|
|
||||||
if (tmDlta == null || live == null) {
|
if (tmDlta == null || live == null) {
|
||||||
delta.setText("--");
|
delta.setText("--");
|
||||||
} else {
|
} else {
|
||||||
delta.setText(tmDlta.toString(true));
|
delta.setText(tmDlta.toString(true));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tmDlta = pSegment.getTime(Segment.DELTA);
|
tmDlta = pSegment.getTime(Segment.DELTA);
|
||||||
live = pSegment.getTime(Segment.LIVE);
|
live = pSegment.getTime(Segment.LIVE);
|
||||||
Time set = pSegment.getTime(Segment.SET);
|
Time set = pSegment.getTime(Segment.SET);
|
||||||
|
|
||||||
Time dBst = pSegment.getTime(Segment.DELTA_BEST);
|
Time dBst = pSegment.getTime(Segment.DELTA_BEST);
|
||||||
inlineDeltaBest.setText("| " + (dBst == null ? "--" : dBst.toString(true)));
|
inlineDeltaBest.setText("| " + (dBst == null ? "--" : dBst.toString(true)));
|
||||||
deltaBest.setText("" + (dBst == null ? "--" : dBst.toString(true)));
|
deltaBest.setText("" + (dBst == null ? "--" : dBst.toString(true)));
|
||||||
|
|
||||||
if (set != null && pIndex > 1) {
|
if (set != null && pIndex > 1) {
|
||||||
set = set.clone();
|
set = set.clone();
|
||||||
for (int i = pIndex - 1; i >= 0; i--) {
|
for (int i = pIndex - 1; i >= 0; i--) {
|
||||||
Segment pSeg = run.getSegment(i);
|
Segment pSeg = run.getSegment(i);
|
||||||
Time ante = pSeg.getTime(Segment.LIVE);
|
Time ante = pSeg.getTime(Segment.LIVE);
|
||||||
if (ante == null) {
|
if (ante == null) {
|
||||||
set.add(pSeg.getTime(Segment.SET));
|
set.add(pSeg.getTime(Segment.SET));
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tmDlta = Time.getDelta(live, set);
|
tmDlta = Time.getDelta(live, set);
|
||||||
}
|
}
|
||||||
if (tmDlta == null || live == null) {
|
if (tmDlta == null || live == null) {
|
||||||
delta.setText("--");
|
delta.setText("--");
|
||||||
inlineDeltaBest.setText("| --");
|
inlineDeltaBest.setText("| --");
|
||||||
deltaBest.setText("--");
|
deltaBest.setText("--");
|
||||||
} else {
|
} else {
|
||||||
delta.setText(tmDlta.toString(true));
|
delta.setText(tmDlta.toString(true));
|
||||||
}
|
}
|
||||||
if (pIndex > 0) {
|
if (pIndex > 0) {
|
||||||
Time sTime = run.getSegment(pIndex - 1)
|
Time sTime = run.getSegment(pIndex - 1)
|
||||||
.getTime(Segment.SET);
|
.getTime(Segment.SET);
|
||||||
if (sTime == null) {
|
if (sTime == null) {
|
||||||
delta.setText("--");
|
delta.setText("--");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Settings.FOO_VERB.get()) {
|
if (Settings.FOO_VERB.get()) {
|
||||||
delta.setText("[" + delta.getText() + "]");
|
delta.setText("[" + delta.getText() + "]");
|
||||||
}
|
}
|
||||||
updateColors(DELTA);
|
updateColors(DELTA);
|
||||||
} else {
|
} else {
|
||||||
delta.setText("");
|
delta.setText("");
|
||||||
inlineDeltaBest.setText("");
|
inlineDeltaBest.setText("");
|
||||||
deltaBest.setText("");
|
deltaBest.setText("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((identifier & TEXT) == TEXT) {
|
if ((identifier & TEXT) == TEXT) {
|
||||||
if (useSplit) {
|
if (useSplit) {
|
||||||
labelPrev.setText("" + Language.LB_FT_SPLIT);
|
labelPrev.setText("" + Language.LB_FT_SPLIT);
|
||||||
} else {
|
} else {
|
||||||
labelPrev.setText("" + Language.LB_FT_SEGMENT);
|
labelPrev.setText("" + Language.LB_FT_SEGMENT);
|
||||||
}
|
}
|
||||||
labelLive.setText("" + Language.LB_FT_LIVE);
|
labelLive.setText("" + Language.LB_FT_LIVE);
|
||||||
labelBest.setText("" + Language.LB_FT_BEST);
|
labelBest.setText("" + Language.LB_FT_BEST);
|
||||||
labelDelta.setText("" + Language.LB_FT_DELTA);
|
labelDelta.setText("" + Language.LB_FT_DELTA);
|
||||||
labelDeltaBest.setText("" + Language.LB_FT_DELTA_BEST);
|
labelDeltaBest.setText("" + Language.LB_FT_DELTA_BEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,331 +32,331 @@ import org.fenix.utils.locale.LocaleEvent;
|
||||||
*/
|
*/
|
||||||
class Graph extends JPanel {
|
class Graph extends JPanel {
|
||||||
|
|
||||||
// -------------------------------------------------------------- CONSTANTS
|
// -------------------------------------------------------------- CONSTANTS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Half the thickness of the stroke used to paint the graph. This value is
|
* Half the thickness of the stroke used to paint the graph. This value is
|
||||||
* used to make sure the stroke retains its full thickness when reaching
|
* used to make sure the stroke retains its full thickness when reaching
|
||||||
* the top or the bottom of the canvas.
|
* the top or the bottom of the canvas.
|
||||||
*/
|
*/
|
||||||
protected static final int HALF_THICKNESS = 1;
|
protected static final int HALF_THICKNESS = 1;
|
||||||
|
|
||||||
/**
|
|
||||||
* The stroke used to paint the graph in itself (i.e. the lines connecting
|
|
||||||
* the vertices.)
|
|
||||||
*/
|
|
||||||
protected static final Stroke GRAPH_STROKE = new BasicStroke(2.0F);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The dashed stroke used to paint the projection of the vertices.
|
|
||||||
*/
|
|
||||||
protected static final Stroke DASHED_STROKE = new BasicStroke(
|
|
||||||
1.0F, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1.0F,
|
|
||||||
new float[] { 2.0F }, 0.0F );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update identifier for every category.
|
|
||||||
*/
|
|
||||||
private static final int ALL = 0xff;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update identifier for text variables.
|
|
||||||
*/
|
|
||||||
private static final int TEXT = 0x01;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update identifier for time variables.
|
|
||||||
*/
|
|
||||||
private static final int TIME = 0x02;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minimum width in pixels of this component.
|
|
||||||
*/
|
|
||||||
private static final int PACK_WIDTH = 50;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Minimum height in pixels of this component.
|
|
||||||
*/
|
|
||||||
private static final int PACK_HEIGHT = 50;
|
|
||||||
|
|
||||||
// ------------------------------------------------------------- ATTRIBUTES
|
/**
|
||||||
|
* The stroke used to paint the graph in itself (i.e. the lines connecting
|
||||||
|
* the vertices.)
|
||||||
|
*/
|
||||||
|
protected static final Stroke GRAPH_STROKE = new BasicStroke(2.0F);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run instance represented by this component.
|
* The dashed stroke used to paint the projection of the vertices.
|
||||||
*/
|
*/
|
||||||
protected Run run;
|
protected static final Stroke DASHED_STROKE = new BasicStroke(
|
||||||
|
1.0F, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1.0F,
|
||||||
/**
|
new float[] { 2.0F }, 0.0F );
|
||||||
* Canvas where the graph will be drawn.
|
|
||||||
*/
|
|
||||||
private Canvas canvas;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Label displaying the current scale of the graph. The scale actually
|
|
||||||
* displays the time represented by the maximum ordinate.
|
|
||||||
*/
|
|
||||||
private JLabel scale;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Label describing the scale value being displayed.
|
|
||||||
*/
|
|
||||||
private JLabel scaleText;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------- CONSTRUCTORS
|
/**
|
||||||
|
* Update identifier for every category.
|
||||||
|
*/
|
||||||
|
private static final int ALL = 0xff;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a default graph panel representing the given run.
|
* Update identifier for text variables.
|
||||||
*
|
*/
|
||||||
* @param run - the run to represent.
|
private static final int TEXT = 0x01;
|
||||||
*/
|
|
||||||
Graph(Run run) {
|
|
||||||
canvas = new Canvas();
|
|
||||||
scale = new JLabel();
|
|
||||||
scaleText = new JLabel();
|
|
||||||
|
|
||||||
setRun(run);
|
/**
|
||||||
setOpaque(false);
|
* Update identifier for time variables.
|
||||||
|
*/
|
||||||
updateValues(TEXT);
|
private static final int TIME = 0x02;
|
||||||
updateColors(ALL);
|
|
||||||
placeComponents();
|
|
||||||
|
|
||||||
Dimension size = new Dimension(PACK_WIDTH, PACK_HEIGHT);
|
|
||||||
setPreferredSize(size);
|
|
||||||
setMinimumSize(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- INTERFACE
|
/**
|
||||||
|
* Minimum width in pixels of this component.
|
||||||
|
*/
|
||||||
|
private static final int PACK_WIDTH = 50;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the new run to represent.
|
* Minimum height in pixels of this component.
|
||||||
*
|
*/
|
||||||
* @param run - the new run to represent.
|
private static final int PACK_HEIGHT = 50;
|
||||||
*/
|
|
||||||
void setRun(Run run) {
|
|
||||||
this.run = run;
|
|
||||||
updateValues(TIME);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// ------------------------------------------------------------- ATTRIBUTES
|
||||||
* Callback invoked by the parent when the run or the application's
|
|
||||||
* settings have seen one of their properties updated.
|
|
||||||
*
|
|
||||||
* @param event - the event describing the update.
|
|
||||||
*/
|
|
||||||
void processPropertyChangeEvent(PropertyChangeEvent event) {
|
|
||||||
String property = event.getPropertyName();
|
|
||||||
// Settings.COLOR_FOREGROUND
|
|
||||||
if (Settings.CLR_FORE.equals(property)) {
|
|
||||||
updateColors(TEXT);
|
|
||||||
canvas.repaint();
|
|
||||||
// Settings.COLOR_TIME
|
|
||||||
} else if (Settings.CLR_TIME.equals(property)) {
|
|
||||||
updateColors(TIME);
|
|
||||||
// Settings.COLOR_BACKGROUND, COLOR_TIME_LOST, COLOR_TIME_GAINED
|
|
||||||
// or Run.CURRENT_SEGMENT_PROPERTY
|
|
||||||
} else if (Settings.CLR_BACK.equals(property)
|
|
||||||
|| Settings.CLR_LOST.equals(property)
|
|
||||||
|| Settings.CLR_GAIN.equals(property)
|
|
||||||
|| Settings.CLR_RCRD.equals(property)
|
|
||||||
|| Run.CURRENT_SEGMENT_PROPERTY.equals(property)) {
|
|
||||||
canvas.repaint();
|
|
||||||
// Settings.COMPARE_PERCENT or Settings.COMPARE_METHOD
|
|
||||||
} else if (Settings.GPH_SCAL.equals(property)
|
|
||||||
|| Settings.GNR_COMP.equals(property)) {
|
|
||||||
updateValues(TIME);
|
|
||||||
canvas.repaint();
|
|
||||||
// Settings.ACCURACY
|
|
||||||
} else if (Settings.GNR_ACCY.equals(property)) {
|
|
||||||
updateValues(TIME);
|
|
||||||
// Run.STATE_PROPERTY
|
|
||||||
} else if (Run.STATE_PROPERTY.equals(property)) {
|
|
||||||
if (run.getState() == State.READY) {
|
|
||||||
canvas.repaint();
|
|
||||||
} else if (run.getState() == State.NULL) {
|
|
||||||
updateValues(TIME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback invoked by the parent when the run table of segments is
|
|
||||||
* updated.
|
|
||||||
*
|
|
||||||
* @param event - the event describing the update.
|
|
||||||
*/
|
|
||||||
void processTableModelEvent(TableModelEvent event) {
|
|
||||||
int type = event.getType();
|
|
||||||
int column = event.getColumn();
|
|
||||||
if (type != TableModelEvent.UPDATE
|
|
||||||
|| column == TableModelEvent.ALL_COLUMNS
|
|
||||||
|| column == Run.COLUMN_BEST
|
|
||||||
|| column == Run.COLUMN_SEGMENT
|
|
||||||
|| column == Run.COLUMN_TIME) {
|
|
||||||
updateValues(TIME);
|
|
||||||
canvas.repaint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback invoked by the parent when default local for this instance of
|
|
||||||
* the JVM has changed.
|
|
||||||
*
|
|
||||||
* @param event - the event describing the update.
|
|
||||||
*/
|
|
||||||
void processLocaleEvent(LocaleEvent event) {
|
|
||||||
updateValues(TEXT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- UTILITIES
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a percent representing the delta split time of the segment of
|
|
||||||
* given index in relation to a set fraction of the whole run given by
|
|
||||||
* {@link Run#getCompareTime()}.
|
|
||||||
*
|
|
||||||
* @param index - the index of the segment to compare.
|
|
||||||
* @return the percent of the segment delta split time and the run’s
|
|
||||||
* compare time.
|
|
||||||
*/
|
|
||||||
protected long getCompareTimePercent(int index) {
|
|
||||||
long compare = run.getCompareTime().getMilliseconds();
|
|
||||||
long delta = run.getTime(index, Segment.DELTA).getMilliseconds();
|
|
||||||
|
|
||||||
return (delta * 100L) / compare;
|
/**
|
||||||
}
|
* Run instance represented by this component.
|
||||||
|
*/
|
||||||
/**
|
protected Run run;
|
||||||
* Places the sub-components within this component.
|
|
||||||
*/
|
|
||||||
private void placeComponents() {
|
|
||||||
setLayout(new GridBagLayout());
|
|
||||||
JPanel scalePanel = new JPanel(); {
|
|
||||||
scalePanel.add(scaleText);
|
|
||||||
scalePanel.add(scale);
|
|
||||||
scalePanel.setOpaque(false);
|
|
||||||
}
|
|
||||||
add(scalePanel, GBC.grid(0, 0).anchor(GBC.LS));
|
|
||||||
add(canvas, GBC.grid(0, 1).fill(GBC.B).weight(1.0, 1.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the values of the group of components specified by the
|
|
||||||
* identifier.
|
|
||||||
*
|
|
||||||
* @param identifier - one of the constant update identifier.
|
|
||||||
*/
|
|
||||||
private void updateValues(int identifier) {
|
|
||||||
// TIME
|
|
||||||
if ((identifier & TIME) == TIME) {
|
|
||||||
Time time = run.getCompareTime();
|
|
||||||
scale.setText("" + (time == null ? "???" : time));
|
|
||||||
}
|
|
||||||
// TEXT
|
|
||||||
if ((identifier & TEXT) == TEXT) {
|
|
||||||
scaleText.setText("" + Language.MAX_ORDINATE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the colors of the group of components specified by the
|
|
||||||
* identifier.
|
|
||||||
*
|
|
||||||
* @param identifier - one of the constant update identifier.
|
|
||||||
*/
|
|
||||||
private void updateColors(int identifier) {
|
|
||||||
// TIME
|
|
||||||
if ((identifier & TIME) == TIME) {
|
|
||||||
scale.setForeground(Settings.CLR_TIME.get());
|
|
||||||
}
|
|
||||||
// TEXT
|
|
||||||
if ((identifier & TEXT) == TEXT) {
|
|
||||||
scaleText.setForeground(Settings.CLR_FORE.get());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------- INTERNAL TYPE
|
/**
|
||||||
|
* Canvas where the graph will be drawn.
|
||||||
|
*/
|
||||||
|
private Canvas canvas;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple panel whose paint method has been overriden to draw the graph.
|
* Label displaying the current scale of the graph. The scale actually
|
||||||
*
|
* displays the time represented by the maximum ordinate.
|
||||||
* @author Xavier "Xunkar" Sencert
|
*/
|
||||||
*/
|
private JLabel scale;
|
||||||
protected class Canvas extends JPanel {
|
|
||||||
|
|
||||||
// ----------------------------------------------------- INTERFACE
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draws the graph onto the canvas.
|
* Label describing the scale value being displayed.
|
||||||
*/
|
*/
|
||||||
@Override protected void paintComponent(Graphics g) {
|
private JLabel scaleText;
|
||||||
Graphics2D g2 = (Graphics2D) g;
|
|
||||||
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
|
||||||
RenderingHints.VALUE_ANTIALIAS_ON);
|
|
||||||
|
|
||||||
int clipH = getHeight();
|
// ----------------------------------------------------------- CONSTRUCTORS
|
||||||
int clipW = getWidth();
|
|
||||||
int halfH = clipH / 2;
|
|
||||||
|
|
||||||
g2.setColor(Settings.CLR_BACK.get());
|
/**
|
||||||
g2.fillRect(0, 0, clipW, clipH);
|
* Creates a default graph panel representing the given run.
|
||||||
|
*
|
||||||
|
* @param run - the run to represent.
|
||||||
|
*/
|
||||||
|
Graph(Run run) {
|
||||||
|
canvas = new Canvas();
|
||||||
|
scale = new JLabel();
|
||||||
|
scaleText = new JLabel();
|
||||||
|
|
||||||
|
setRun(run);
|
||||||
|
setOpaque(false);
|
||||||
|
|
||||||
|
updateValues(TEXT);
|
||||||
|
updateColors(ALL);
|
||||||
|
placeComponents();
|
||||||
|
|
||||||
|
Dimension size = new Dimension(PACK_WIDTH, PACK_HEIGHT);
|
||||||
|
setPreferredSize(size);
|
||||||
|
setMinimumSize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------- INTERFACE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the new run to represent.
|
||||||
|
*
|
||||||
|
* @param run - the new run to represent.
|
||||||
|
*/
|
||||||
|
void setRun(Run run) {
|
||||||
|
this.run = run;
|
||||||
|
updateValues(TIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback invoked by the parent when the run or the application's
|
||||||
|
* settings have seen one of their properties updated.
|
||||||
|
*
|
||||||
|
* @param event - the event describing the update.
|
||||||
|
*/
|
||||||
|
void processPropertyChangeEvent(PropertyChangeEvent event) {
|
||||||
|
String property = event.getPropertyName();
|
||||||
|
// Settings.COLOR_FOREGROUND
|
||||||
|
if (Settings.CLR_FORE.equals(property)) {
|
||||||
|
updateColors(TEXT);
|
||||||
|
canvas.repaint();
|
||||||
|
// Settings.COLOR_TIME
|
||||||
|
} else if (Settings.CLR_TIME.equals(property)) {
|
||||||
|
updateColors(TIME);
|
||||||
|
// Settings.COLOR_BACKGROUND, COLOR_TIME_LOST, COLOR_TIME_GAINED
|
||||||
|
// or Run.CURRENT_SEGMENT_PROPERTY
|
||||||
|
} else if (Settings.CLR_BACK.equals(property)
|
||||||
|
|| Settings.CLR_LOST.equals(property)
|
||||||
|
|| Settings.CLR_GAIN.equals(property)
|
||||||
|
|| Settings.CLR_RCRD.equals(property)
|
||||||
|
|| Run.CURRENT_SEGMENT_PROPERTY.equals(property)) {
|
||||||
|
canvas.repaint();
|
||||||
|
// Settings.COMPARE_PERCENT or Settings.COMPARE_METHOD
|
||||||
|
} else if (Settings.GPH_SCAL.equals(property)
|
||||||
|
|| Settings.GNR_COMP.equals(property)) {
|
||||||
|
updateValues(TIME);
|
||||||
|
canvas.repaint();
|
||||||
|
// Settings.ACCURACY
|
||||||
|
} else if (Settings.GNR_ACCY.equals(property)) {
|
||||||
|
updateValues(TIME);
|
||||||
|
// Run.STATE_PROPERTY
|
||||||
|
} else if (Run.STATE_PROPERTY.equals(property)) {
|
||||||
|
if (run.getState() == State.READY) {
|
||||||
|
canvas.repaint();
|
||||||
|
} else if (run.getState() == State.NULL) {
|
||||||
|
updateValues(TIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback invoked by the parent when the run table of segments is
|
||||||
|
* updated.
|
||||||
|
*
|
||||||
|
* @param event - the event describing the update.
|
||||||
|
*/
|
||||||
|
void processTableModelEvent(TableModelEvent event) {
|
||||||
|
int type = event.getType();
|
||||||
|
int column = event.getColumn();
|
||||||
|
if (type != TableModelEvent.UPDATE
|
||||||
|
|| column == TableModelEvent.ALL_COLUMNS
|
||||||
|
|| column == Run.COLUMN_BEST
|
||||||
|
|| column == Run.COLUMN_SEGMENT
|
||||||
|
|| column == Run.COLUMN_TIME) {
|
||||||
|
updateValues(TIME);
|
||||||
|
canvas.repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback invoked by the parent when default local for this instance of
|
||||||
|
* the JVM has changed.
|
||||||
|
*
|
||||||
|
* @param event - the event describing the update.
|
||||||
|
*/
|
||||||
|
void processLocaleEvent(LocaleEvent event) {
|
||||||
|
updateValues(TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------- UTILITIES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a percent representing the delta split time of the segment of
|
||||||
|
* given index in relation to a set fraction of the whole run given by
|
||||||
|
* {@link Run#getCompareTime()}.
|
||||||
|
*
|
||||||
|
* @param index - the index of the segment to compare.
|
||||||
|
* @return the percent of the segment delta split time and the run’s
|
||||||
|
* compare time.
|
||||||
|
*/
|
||||||
|
protected long getCompareTimePercent(int index) {
|
||||||
|
long compare = run.getCompareTime().getMilliseconds();
|
||||||
|
long delta = run.getTime(index, Segment.DELTA).getMilliseconds();
|
||||||
|
|
||||||
|
return (delta * 100L) / compare;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Places the sub-components within this component.
|
||||||
|
*/
|
||||||
|
private void placeComponents() {
|
||||||
|
setLayout(new GridBagLayout());
|
||||||
|
JPanel scalePanel = new JPanel(); {
|
||||||
|
scalePanel.add(scaleText);
|
||||||
|
scalePanel.add(scale);
|
||||||
|
scalePanel.setOpaque(false);
|
||||||
|
}
|
||||||
|
add(scalePanel, GBC.grid(0, 0).anchor(GBC.LS));
|
||||||
|
add(canvas, GBC.grid(0, 1).fill(GBC.B).weight(1.0, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the values of the group of components specified by the
|
||||||
|
* identifier.
|
||||||
|
*
|
||||||
|
* @param identifier - one of the constant update identifier.
|
||||||
|
*/
|
||||||
|
private void updateValues(int identifier) {
|
||||||
|
// TIME
|
||||||
|
if ((identifier & TIME) == TIME) {
|
||||||
|
Time time = run.getCompareTime();
|
||||||
|
scale.setText("" + (time == null ? "???" : time));
|
||||||
|
}
|
||||||
|
// TEXT
|
||||||
|
if ((identifier & TEXT) == TEXT) {
|
||||||
|
scaleText.setText("" + Language.MAX_ORDINATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the colors of the group of components specified by the
|
||||||
|
* identifier.
|
||||||
|
*
|
||||||
|
* @param identifier - one of the constant update identifier.
|
||||||
|
*/
|
||||||
|
private void updateColors(int identifier) {
|
||||||
|
// TIME
|
||||||
|
if ((identifier & TIME) == TIME) {
|
||||||
|
scale.setForeground(Settings.CLR_TIME.get());
|
||||||
|
}
|
||||||
|
// TEXT
|
||||||
|
if ((identifier & TEXT) == TEXT) {
|
||||||
|
scaleText.setForeground(Settings.CLR_FORE.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------- INTERNAL TYPE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple panel whose paint method has been overriden to draw the graph.
|
||||||
|
*
|
||||||
|
* @author Xavier "Xunkar" Sencert
|
||||||
|
*/
|
||||||
|
protected class Canvas extends JPanel {
|
||||||
|
|
||||||
|
// ----------------------------------------------------- INTERFACE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws the graph onto the canvas.
|
||||||
|
*/
|
||||||
|
@Override protected void paintComponent(Graphics g) {
|
||||||
|
Graphics2D g2 = (Graphics2D) g;
|
||||||
|
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
|
||||||
|
RenderingHints.VALUE_ANTIALIAS_ON);
|
||||||
|
|
||||||
|
int clipH = getHeight();
|
||||||
|
int clipW = getWidth();
|
||||||
|
int halfH = clipH / 2;
|
||||||
|
|
||||||
|
g2.setColor(Settings.CLR_BACK.get());
|
||||||
|
g2.fillRect(0, 0, clipW, clipH);
|
||||||
|
|
||||||
Color colorFG = Settings.CLR_FORE.get();
|
Color colorFG = Settings.CLR_FORE.get();
|
||||||
Color colorTG = Settings.CLR_GAIN.get();
|
Color colorTG = Settings.CLR_GAIN.get();
|
||||||
Color colorTL = Settings.CLR_LOST.get();
|
Color colorTL = Settings.CLR_LOST.get();
|
||||||
Color colorRC = Settings.CLR_RCRD.get();
|
Color colorRC = Settings.CLR_RCRD.get();
|
||||||
|
|
||||||
// Draw the axis.
|
// Draw the axis.
|
||||||
g2.setColor(colorFG);
|
g2.setColor(colorFG);
|
||||||
g2.drawLine(0, halfH, clipW, halfH);
|
g2.drawLine(0, halfH, clipW, halfH);
|
||||||
|
|
||||||
if (run.getState() != State.NULL) {
|
if (run.getState() != State.NULL) {
|
||||||
int segCnt = run.getRowCount();
|
int segCnt = run.getRowCount();
|
||||||
double segGap = (double) clipW / segCnt;
|
double segGap = (double) clipW / segCnt;
|
||||||
|
|
||||||
if (run.hasPreviousSegment()) {
|
if (run.hasPreviousSegment()) {
|
||||||
// Coordinates of the last drawn vertex.
|
// Coordinates of the last drawn vertex.
|
||||||
int prevX = 0;
|
int prevX = 0;
|
||||||
int prevY = halfH;
|
int prevY = halfH;
|
||||||
|
|
||||||
for (int i = 0; i < run.getCurrent(); i++) {
|
for (int i = 0; i < run.getCurrent(); i++) {
|
||||||
Time delta = run.getTime(i, Segment.DELTA);
|
Time delta = run.getTime(i, Segment.DELTA);
|
||||||
Time live = run.getTime(i, Segment.LIVE);
|
Time live = run.getTime(i, Segment.LIVE);
|
||||||
if (delta != null && live != null) {
|
if (delta != null && live != null) {
|
||||||
int percent = (int) getCompareTimePercent(i);
|
int percent = (int) getCompareTimePercent(i);
|
||||||
g2.setColor(run.isBetterSegment(i) ? colorTG : colorTL);
|
g2.setColor(run.isBetterSegment(i) ? colorTG : colorTL);
|
||||||
if (run.isBestSegment(i)) {
|
if (run.isBestSegment(i)) {
|
||||||
g2.setColor(colorRC);
|
g2.setColor(colorRC);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Coordinates of this segment’s vertex.
|
|
||||||
int coordY = halfH - ((percent * halfH) / 100);
|
|
||||||
coordY = Math.min(clipH - HALF_THICKNESS, coordY);
|
|
||||||
coordY = Math.max(HALF_THICKNESS, coordY);
|
|
||||||
int coordX = (int) ((i + 1) * segGap);
|
|
||||||
|
|
||||||
// Set the brush depending on the delta.
|
|
||||||
g2.setStroke(GRAPH_STROKE);
|
|
||||||
|
|
||||||
// Make sure the last vertex reaches the pane’s end.
|
|
||||||
if (i == segCnt - 1) {
|
|
||||||
coordX = Math.min(coordX - 1, clipW);
|
|
||||||
}
|
|
||||||
g2.drawLine(prevX, prevY, coordX, coordY);
|
|
||||||
|
|
||||||
// Projection along the x axis.
|
|
||||||
g2.setColor(colorFG);
|
|
||||||
g2.setStroke(DASHED_STROKE);
|
|
||||||
g2.drawLine(coordX, halfH, coordX, coordY);
|
|
||||||
|
|
||||||
prevY = coordY;
|
|
||||||
prevX = coordX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
// Coordinates of this segment’s vertex.
|
||||||
|
int coordY = halfH - ((percent * halfH) / 100);
|
||||||
|
coordY = Math.min(clipH - HALF_THICKNESS, coordY);
|
||||||
|
coordY = Math.max(HALF_THICKNESS, coordY);
|
||||||
|
int coordX = (int) ((i + 1) * segGap);
|
||||||
|
|
||||||
|
// Set the brush depending on the delta.
|
||||||
|
g2.setStroke(GRAPH_STROKE);
|
||||||
|
|
||||||
|
// Make sure the last vertex reaches the pane’s end.
|
||||||
|
if (i == segCnt - 1) {
|
||||||
|
coordX = Math.min(coordX - 1, clipW);
|
||||||
|
}
|
||||||
|
g2.drawLine(prevX, prevY, coordX, coordY);
|
||||||
|
|
||||||
|
// Projection along the x axis.
|
||||||
|
g2.setColor(colorFG);
|
||||||
|
g2.setStroke(DASHED_STROKE);
|
||||||
|
g2.drawLine(coordX, halfH, coordX, coordY);
|
||||||
|
|
||||||
|
prevY = coordY;
|
||||||
|
prevX = coordX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -30,378 +30,378 @@ import org.fenix.utils.locale.LocaleEvent;
|
||||||
*/
|
*/
|
||||||
public class RunPane extends JPanel {
|
public class RunPane extends JPanel {
|
||||||
|
|
||||||
// -------------------------------------------------------------- CONSTANTS
|
// -------------------------------------------------------------- CONSTANTS
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Font used to render the title of the run.
|
* Font used to render the title of the run.
|
||||||
*/
|
*/
|
||||||
private static final Font RUN_TITLE_FONT = Font.decode("Arial-12-BOLD");
|
private static final Font RUN_TITLE_FONT = Font.decode("Arial-12-BOLD");
|
||||||
|
|
||||||
/**
|
|
||||||
* Update identifier for every category.
|
|
||||||
*/
|
|
||||||
private static final int ALL = 0xff;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update identifier for time variables.
|
|
||||||
*/
|
|
||||||
private static final int GOAL = 0x01;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update identifier for separator variables.
|
|
||||||
*/
|
|
||||||
private static final int SEPARATOR = 0x02;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update identifier for text variables.
|
|
||||||
*/
|
|
||||||
private static final int TEXT = 0x04;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update identifier for title variables.
|
|
||||||
*/
|
|
||||||
private static final int TITLE = 0x08;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update identifier for background variables.
|
|
||||||
*/
|
|
||||||
private static final int BACKGROUND = 0x10;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update identifier for the graph component.
|
|
||||||
*/
|
|
||||||
private static final int GRAPH = 0x20;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update identifier for the footer component.
|
|
||||||
*/
|
|
||||||
private static final int FOOTER = 0x40;
|
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------- ATTRIBUTES
|
/**
|
||||||
|
* Update identifier for every category.
|
||||||
|
*/
|
||||||
|
private static final int ALL = 0xff;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run instance represented by this component.
|
* Update identifier for time variables.
|
||||||
*/
|
*/
|
||||||
private Run run;
|
private static final int GOAL = 0x01;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Label displaying the title of the current run.
|
* Update identifier for separator variables.
|
||||||
*/
|
*/
|
||||||
private JLabel title;
|
private static final int SEPARATOR = 0x02;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Label displaying the current goal of run. By default it’s the time of
|
* Update identifier for text variables.
|
||||||
* the run we’re comparing against, but it can be a customized string.
|
*/
|
||||||
*/
|
private static final int TEXT = 0x04;
|
||||||
private JLabel goal;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Label describing the goal value being displayed.
|
* Update identifier for title variables.
|
||||||
*/
|
*/
|
||||||
private JLabel goalText;
|
private static final int TITLE = 0x08;
|
||||||
|
|
||||||
/**
|
|
||||||
* Panel containing both goal value and text.
|
|
||||||
*/
|
|
||||||
private JPanel goalPane;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A list containing empty labels serving as separators.
|
|
||||||
*/
|
|
||||||
private List<JLabel> separators;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple footer displaying information on the previous segment if any.
|
* Update identifier for background variables.
|
||||||
* Is only visible if {@link Settings#FOOTER_DISPLAY} is {@code true}.
|
*/
|
||||||
*/
|
private static final int BACKGROUND = 0x10;
|
||||||
private Footer footer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Panel displaying the core information like the current segment and the
|
* Update identifier for the graph component.
|
||||||
* necessary timers.
|
*/
|
||||||
*/
|
private static final int GRAPH = 0x20;
|
||||||
private Core core;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Panel representing the current run as a graph.
|
* Update identifier for the footer component.
|
||||||
*/
|
*/
|
||||||
private Graph graph;
|
private static final int FOOTER = 0x40;
|
||||||
|
|
||||||
/**
|
|
||||||
* Scrolling panel displaying information regarding every segment of the
|
|
||||||
* run up to the last segment or {@link Settings#DISPLAYED_SEGMENTS}.
|
|
||||||
*/
|
|
||||||
private History history;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------- CONSTRUCTORS
|
// ------------------------------------------------------------- ATTRIBUTES
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a default panel representing the given run.
|
* Run instance represented by this component.
|
||||||
*
|
*/
|
||||||
* @param run - the run to represent.
|
private Run run;
|
||||||
*/
|
|
||||||
public RunPane(Run run) {
|
|
||||||
super(new GridBagLayout());
|
|
||||||
if (run == null) {
|
|
||||||
throw new NullPointerException("null run");
|
|
||||||
}
|
|
||||||
title = new JLabel();
|
|
||||||
goal = new JLabel();
|
|
||||||
goalText = new JLabel();
|
|
||||||
core = new Core(run);
|
|
||||||
graph = new Graph(run);
|
|
||||||
history = new History(run);
|
|
||||||
footer = new Footer(run);
|
|
||||||
separators = new ArrayList<JLabel>();
|
|
||||||
|
|
||||||
placeComponents();
|
|
||||||
setRun(run);
|
|
||||||
|
|
||||||
updateValues(TEXT);
|
|
||||||
updateColors(ALL);
|
|
||||||
updateVisibility(ALL);
|
|
||||||
|
|
||||||
title.setFont(RUN_TITLE_FONT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- INTERFACE
|
/**
|
||||||
|
* Label displaying the title of the current run.
|
||||||
|
*/
|
||||||
|
private JLabel title;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the new run to represent.
|
* Label displaying the current goal of run. By default it’s the time of
|
||||||
*
|
* the run we’re comparing against, but it can be a customized string.
|
||||||
* @param run - the new run to represent.
|
*/
|
||||||
*/
|
private JLabel goal;
|
||||||
public final void setRun(Run run) {
|
|
||||||
if (run == null) {
|
|
||||||
throw new NullPointerException("null run");
|
|
||||||
}
|
|
||||||
this.run = run;
|
|
||||||
core.setRun(run);
|
|
||||||
graph.setRun(run);
|
|
||||||
history.setRun(run);
|
|
||||||
footer.setRun(run);
|
|
||||||
|
|
||||||
updateValues(ALL & ~TEXT);
|
/**
|
||||||
}
|
* Label describing the goal value being displayed.
|
||||||
|
*/
|
||||||
// -------------------------------------------------------------- CALLBACKS
|
private JLabel goalText;
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback invoked by the parent when default local for this instance of
|
|
||||||
* the JVM has changed.
|
|
||||||
*
|
|
||||||
* @param event - the event describing the update.
|
|
||||||
*/
|
|
||||||
public void processLocaleEvent(LocaleEvent event) {
|
|
||||||
core.processLocaleEvent(event);
|
|
||||||
graph.processLocaleEvent(event);
|
|
||||||
footer.processLocaleEvent(event);
|
|
||||||
|
|
||||||
updateValues(TEXT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback invoked by the parent when the run or the application's
|
|
||||||
* settings have seen one of their properties updated.
|
|
||||||
*
|
|
||||||
* @param event - the event describing the update.
|
|
||||||
*/
|
|
||||||
public void processPropertyChangeEvent(PropertyChangeEvent event) {
|
|
||||||
core.processPropertyChangeEvent(event);
|
|
||||||
graph.processPropertyChangeEvent(event);
|
|
||||||
history.processPropertyChangeEvent(event);
|
|
||||||
footer.processPropertyChangeEvent(event);
|
|
||||||
|
|
||||||
String property = event.getPropertyName();
|
/**
|
||||||
if (Run.STATE_PROPERTY.equals(property)) {
|
* Panel containing both goal value and text.
|
||||||
if (run.getState() == State.READY
|
*/
|
||||||
|| run.getState() == State.NULL) {
|
private JPanel goalPane;
|
||||||
updateValues(GOAL | SEPARATOR);
|
|
||||||
}
|
|
||||||
} else if (Run.NAME_PROPERTY.equals(property)) {
|
|
||||||
updateValues(TITLE);
|
|
||||||
} else if (Settings.CLR_BACK.equals(property)) {
|
|
||||||
updateColors(BACKGROUND);
|
|
||||||
} else if (Settings.CLR_FORE.equals(property)) {
|
|
||||||
updateColors(TEXT);
|
|
||||||
} else if (Settings.CLR_SPRT.equals(property)) {
|
|
||||||
updateColors(SEPARATOR);
|
|
||||||
} else if (Settings.HST_ROWS.equals(property)) {
|
|
||||||
updateValues(SEPARATOR);
|
|
||||||
} else if (Settings.CLR_TIME.equals(property)) {
|
|
||||||
updateColors(GOAL);
|
|
||||||
} else if (Settings.CLR_TITL.equals(property)) {
|
|
||||||
updateColors(TITLE);
|
|
||||||
} else if (Settings.GNR_COMP.equals(property)) {
|
|
||||||
updateValues(GOAL);
|
|
||||||
} else if (Settings.GPH_SHOW.equals(property)) {
|
|
||||||
updateVisibility(GRAPH);
|
|
||||||
} else if (Settings.FOO_SHOW.equals(property)) {
|
|
||||||
updateVisibility(FOOTER);
|
|
||||||
} else if (Settings.HDR_GOAL.equals(property)) {
|
|
||||||
updateVisibility(GOAL);
|
|
||||||
updateValues(SEPARATOR);
|
|
||||||
} else if (Settings.HDR_TTLE.equals(property)) {
|
|
||||||
updateVisibility(TITLE | GOAL);
|
|
||||||
updateValues(SEPARATOR);
|
|
||||||
} else if (Settings.GNR_ACCY.equals(property)
|
|
||||||
|| Run.GOAL_PROPERTY.equals(property)) {
|
|
||||||
updateValues(GOAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback invoked by the parent when the run table of segments is
|
|
||||||
* updated.
|
|
||||||
*
|
|
||||||
* @param event - the event describing the update.
|
|
||||||
*/
|
|
||||||
public void processTableModelEvent(TableModelEvent event) {
|
|
||||||
core.processTableModelEvent(event);
|
|
||||||
graph.processTableModelEvent(event);
|
|
||||||
history.processTableModelEvent(event);
|
|
||||||
if (event.getType() == TableModelEvent.INSERT
|
|
||||||
|| event.getType() == TableModelEvent.DELETE
|
|
||||||
|| event.getType() == TableModelEvent.UPDATE) {
|
|
||||||
updateValues(GOAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------- UTILITIES
|
/**
|
||||||
|
* A list containing empty labels serving as separators.
|
||||||
|
*/
|
||||||
|
private List<JLabel> separators;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new separator to the list of separators used by the component
|
* Simple footer displaying information on the previous segment if any.
|
||||||
* and returns it.
|
* Is only visible if {@link Settings#FOOTER_DISPLAY} is {@code true}.
|
||||||
*
|
*/
|
||||||
* @param a new separator.
|
private Footer footer;
|
||||||
*/
|
|
||||||
private JLabel createSeparator() {
|
|
||||||
JLabel label = new JLabel();
|
|
||||||
separators.add(label);
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Places the sub-components within this component.
|
* Panel displaying the core information like the current segment and the
|
||||||
*/
|
* necessary timers.
|
||||||
private void placeComponents() {
|
*/
|
||||||
goalPane = new JPanel(new GridBagLayout()); {
|
private Core core;
|
||||||
goalPane.add(goalText, GBC.grid(0, 0));
|
|
||||||
goalPane.add(goal, GBC.grid(1, 0).insets(0, 3, 0, 0));
|
|
||||||
goalPane.setOpaque(false);
|
|
||||||
}
|
|
||||||
add(title,GBC.grid(0, 0).insets(3, 0, 1, 0));
|
|
||||||
add(createSeparator(), GBC.grid(0, 2).insets(3, 0).fill(GBC.H));
|
|
||||||
add(history, GBC.grid(0, 3).fill(GBC.H).insets(0, 5));
|
|
||||||
add(createSeparator(), GBC.grid(0, 4).insets(3, 0).fill(GBC.H));
|
|
||||||
add(createSeparator(), GBC.grid(0, 6).insets(3, 0, 0, 0).fill(GBC.H));
|
|
||||||
|
|
||||||
updateVisibility(ALL);
|
/**
|
||||||
}
|
* Panel representing the current run as a graph.
|
||||||
|
*/
|
||||||
/**
|
private Graph graph;
|
||||||
* Updates the values of the group of components specified by the
|
|
||||||
* identifier.
|
|
||||||
*
|
|
||||||
* @param identifier - one of the constant update identifier.
|
|
||||||
*/
|
|
||||||
private void updateValues(int identifier) {
|
|
||||||
if ((identifier & GOAL) == GOAL) {
|
|
||||||
if (run.getGoal() == null || run.getGoal().equals("")) {
|
|
||||||
Time time = run.getTime(Segment.SET);
|
|
||||||
goal.setText("" + (time == null ? "???" : time));
|
|
||||||
} else {
|
|
||||||
goal.setText(run.getGoal());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((identifier & TEXT) == TEXT) {
|
|
||||||
goalText.setText("" + Language.GOAL);
|
|
||||||
}
|
|
||||||
if ((identifier & TITLE) == TITLE) {
|
|
||||||
title.setText("" + run.getName());
|
|
||||||
}
|
|
||||||
if ((identifier & SEPARATOR) == SEPARATOR) {
|
|
||||||
boolean hdTitle = Settings.HDR_TTLE.get();
|
|
||||||
boolean hdGoal = Settings.HDR_GOAL.get();
|
|
||||||
boolean hsRows = history.getRowCount() > 0;
|
|
||||||
|
|
||||||
separators.get(0).setVisible(hdTitle || hdGoal);
|
/**
|
||||||
separators.get(1).setVisible(hsRows);
|
* Scrolling panel displaying information regarding every segment of the
|
||||||
}
|
* run up to the last segment or {@link Settings#DISPLAYED_SEGMENTS}.
|
||||||
}
|
*/
|
||||||
|
private History history;
|
||||||
/**
|
|
||||||
* Updates the colors of the group of components specified by the
|
// ----------------------------------------------------------- CONSTRUCTORS
|
||||||
* identifier.
|
|
||||||
*
|
/**
|
||||||
* @param identifier - one of the constant update identifier.
|
* Creates a default panel representing the given run.
|
||||||
*/
|
*
|
||||||
private void updateColors(int identifier) {
|
* @param run - the run to represent.
|
||||||
if ((identifier & GOAL) == GOAL) {
|
*/
|
||||||
goal.setForeground(Settings.CLR_TIME.get());
|
public RunPane(Run run) {
|
||||||
}
|
super(new GridBagLayout());
|
||||||
if ((identifier & TEXT) == TEXT) {
|
if (run == null) {
|
||||||
goalText.setForeground(Settings.CLR_FORE.get());
|
throw new NullPointerException("null run");
|
||||||
}
|
}
|
||||||
if ((identifier & TITLE) == TITLE) {
|
title = new JLabel();
|
||||||
title.setForeground(Settings.CLR_TITL.get());
|
goal = new JLabel();
|
||||||
}
|
goalText = new JLabel();
|
||||||
if ((identifier & BACKGROUND) == BACKGROUND) {
|
core = new Core(run);
|
||||||
setBackground(Settings.CLR_BACK.get());
|
graph = new Graph(run);
|
||||||
}
|
history = new History(run);
|
||||||
if ((identifier & SEPARATOR) == SEPARATOR) {
|
footer = new Footer(run);
|
||||||
Color color = Settings.CLR_SPRT.get();
|
separators = new ArrayList<JLabel>();
|
||||||
for (JLabel separator : separators) {
|
|
||||||
separator.setBorder(
|
placeComponents();
|
||||||
BorderFactory.createMatteBorder(1, 0, 0, 0, color));
|
setRun(run);
|
||||||
}
|
|
||||||
}
|
updateValues(TEXT);
|
||||||
}
|
updateColors(ALL);
|
||||||
|
updateVisibility(ALL);
|
||||||
/**
|
|
||||||
* Updates the visibility of the components specified by the
|
title.setFont(RUN_TITLE_FONT);
|
||||||
* identifier.
|
}
|
||||||
*
|
|
||||||
* @param identifier - one of the constant update identifier.
|
// -------------------------------------------------------------- INTERFACE
|
||||||
*/
|
|
||||||
private void updateVisibility(int identifier) {
|
/**
|
||||||
if ((identifier & GRAPH) == GRAPH) {
|
* Sets the new run to represent.
|
||||||
if (Settings.GPH_SHOW.get()) {
|
*
|
||||||
remove(core);
|
* @param run - the new run to represent.
|
||||||
add(core, GBC.grid(0, 5).insets(0, 5).fill(GBC.H));
|
*/
|
||||||
add(graph, GBC.grid(0, 7).fill(GBC.B).insets(0, 0, 3, 0)
|
public final void setRun(Run run) {
|
||||||
.weight(1.0, 1.0));
|
if (run == null) {
|
||||||
} else {
|
throw new NullPointerException("null run");
|
||||||
remove(graph);
|
}
|
||||||
remove(core);
|
this.run = run;
|
||||||
add(core, GBC.grid(0, 5).insets(0, 5).fill(GBC.H)
|
core.setRun(run);
|
||||||
.weight(1.0, 1.0));
|
graph.setRun(run);
|
||||||
}
|
history.setRun(run);
|
||||||
}
|
footer.setRun(run);
|
||||||
if ((identifier & FOOTER) == FOOTER) {
|
|
||||||
if (Settings.FOO_SHOW.get()) {
|
updateValues(ALL & ~TEXT);
|
||||||
add(footer, GBC.grid(0, 8).insets(0, 3).fill(GBC.H));
|
}
|
||||||
} else {
|
|
||||||
remove(footer);
|
// -------------------------------------------------------------- CALLBACKS
|
||||||
}
|
|
||||||
}
|
/**
|
||||||
if ((identifier & GOAL) == GOAL) {
|
* Callback invoked by the parent when default local for this instance of
|
||||||
if (Settings.HDR_GOAL.get()) {
|
* the JVM has changed.
|
||||||
if (Settings.HDR_TTLE.get()) {
|
*
|
||||||
add(goalPane, GBC.grid(0, 1));
|
* @param event - the event describing the update.
|
||||||
} else {
|
*/
|
||||||
add(goalPane, GBC.grid(0, 1).insets(3, 0, 0, 0));
|
public void processLocaleEvent(LocaleEvent event) {
|
||||||
}
|
core.processLocaleEvent(event);
|
||||||
} else {
|
graph.processLocaleEvent(event);
|
||||||
remove(goalPane);
|
footer.processLocaleEvent(event);
|
||||||
}
|
|
||||||
}
|
updateValues(TEXT);
|
||||||
if ((identifier & TITLE) == TITLE) {
|
}
|
||||||
title.setVisible(Settings.HDR_TTLE.get());
|
|
||||||
}
|
/**
|
||||||
revalidate();
|
* Callback invoked by the parent when the run or the application's
|
||||||
repaint();
|
* settings have seen one of their properties updated.
|
||||||
}
|
*
|
||||||
|
* @param event - the event describing the update.
|
||||||
|
*/
|
||||||
|
public void processPropertyChangeEvent(PropertyChangeEvent event) {
|
||||||
|
core.processPropertyChangeEvent(event);
|
||||||
|
graph.processPropertyChangeEvent(event);
|
||||||
|
history.processPropertyChangeEvent(event);
|
||||||
|
footer.processPropertyChangeEvent(event);
|
||||||
|
|
||||||
|
String property = event.getPropertyName();
|
||||||
|
if (Run.STATE_PROPERTY.equals(property)) {
|
||||||
|
if (run.getState() == State.READY
|
||||||
|
|| run.getState() == State.NULL) {
|
||||||
|
updateValues(GOAL | SEPARATOR);
|
||||||
|
}
|
||||||
|
} else if (Run.NAME_PROPERTY.equals(property)) {
|
||||||
|
updateValues(TITLE);
|
||||||
|
} else if (Settings.CLR_BACK.equals(property)) {
|
||||||
|
updateColors(BACKGROUND);
|
||||||
|
} else if (Settings.CLR_FORE.equals(property)) {
|
||||||
|
updateColors(TEXT);
|
||||||
|
} else if (Settings.CLR_SPRT.equals(property)) {
|
||||||
|
updateColors(SEPARATOR);
|
||||||
|
} else if (Settings.HST_ROWS.equals(property)) {
|
||||||
|
updateValues(SEPARATOR);
|
||||||
|
} else if (Settings.CLR_TIME.equals(property)) {
|
||||||
|
updateColors(GOAL);
|
||||||
|
} else if (Settings.CLR_TITL.equals(property)) {
|
||||||
|
updateColors(TITLE);
|
||||||
|
} else if (Settings.GNR_COMP.equals(property)) {
|
||||||
|
updateValues(GOAL);
|
||||||
|
} else if (Settings.GPH_SHOW.equals(property)) {
|
||||||
|
updateVisibility(GRAPH);
|
||||||
|
} else if (Settings.FOO_SHOW.equals(property)) {
|
||||||
|
updateVisibility(FOOTER);
|
||||||
|
} else if (Settings.HDR_GOAL.equals(property)) {
|
||||||
|
updateVisibility(GOAL);
|
||||||
|
updateValues(SEPARATOR);
|
||||||
|
} else if (Settings.HDR_TTLE.equals(property)) {
|
||||||
|
updateVisibility(TITLE | GOAL);
|
||||||
|
updateValues(SEPARATOR);
|
||||||
|
} else if (Settings.GNR_ACCY.equals(property)
|
||||||
|
|| Run.GOAL_PROPERTY.equals(property)) {
|
||||||
|
updateValues(GOAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback invoked by the parent when the run table of segments is
|
||||||
|
* updated.
|
||||||
|
*
|
||||||
|
* @param event - the event describing the update.
|
||||||
|
*/
|
||||||
|
public void processTableModelEvent(TableModelEvent event) {
|
||||||
|
core.processTableModelEvent(event);
|
||||||
|
graph.processTableModelEvent(event);
|
||||||
|
history.processTableModelEvent(event);
|
||||||
|
if (event.getType() == TableModelEvent.INSERT
|
||||||
|
|| event.getType() == TableModelEvent.DELETE
|
||||||
|
|| event.getType() == TableModelEvent.UPDATE) {
|
||||||
|
updateValues(GOAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------- UTILITIES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new separator to the list of separators used by the component
|
||||||
|
* and returns it.
|
||||||
|
*
|
||||||
|
* @param a new separator.
|
||||||
|
*/
|
||||||
|
private JLabel createSeparator() {
|
||||||
|
JLabel label = new JLabel();
|
||||||
|
separators.add(label);
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Places the sub-components within this component.
|
||||||
|
*/
|
||||||
|
private void placeComponents() {
|
||||||
|
goalPane = new JPanel(new GridBagLayout()); {
|
||||||
|
goalPane.add(goalText, GBC.grid(0, 0));
|
||||||
|
goalPane.add(goal, GBC.grid(1, 0).insets(0, 3, 0, 0));
|
||||||
|
goalPane.setOpaque(false);
|
||||||
|
}
|
||||||
|
add(title,GBC.grid(0, 0).insets(3, 0, 1, 0));
|
||||||
|
add(createSeparator(), GBC.grid(0, 2).insets(3, 0).fill(GBC.H));
|
||||||
|
add(history, GBC.grid(0, 3).fill(GBC.H).insets(0, 5));
|
||||||
|
add(createSeparator(), GBC.grid(0, 4).insets(3, 0).fill(GBC.H));
|
||||||
|
add(createSeparator(), GBC.grid(0, 6).insets(3, 0, 0, 0).fill(GBC.H));
|
||||||
|
|
||||||
|
updateVisibility(ALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the values of the group of components specified by the
|
||||||
|
* identifier.
|
||||||
|
*
|
||||||
|
* @param identifier - one of the constant update identifier.
|
||||||
|
*/
|
||||||
|
private void updateValues(int identifier) {
|
||||||
|
if ((identifier & GOAL) == GOAL) {
|
||||||
|
if (run.getGoal() == null || run.getGoal().equals("")) {
|
||||||
|
Time time = run.getTime(Segment.SET);
|
||||||
|
goal.setText("" + (time == null ? "???" : time));
|
||||||
|
} else {
|
||||||
|
goal.setText(run.getGoal());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((identifier & TEXT) == TEXT) {
|
||||||
|
goalText.setText("" + Language.GOAL);
|
||||||
|
}
|
||||||
|
if ((identifier & TITLE) == TITLE) {
|
||||||
|
title.setText("" + run.getName());
|
||||||
|
}
|
||||||
|
if ((identifier & SEPARATOR) == SEPARATOR) {
|
||||||
|
boolean hdTitle = Settings.HDR_TTLE.get();
|
||||||
|
boolean hdGoal = Settings.HDR_GOAL.get();
|
||||||
|
boolean hsRows = history.getRowCount() > 0;
|
||||||
|
|
||||||
|
separators.get(0).setVisible(hdTitle || hdGoal);
|
||||||
|
separators.get(1).setVisible(hsRows);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the colors of the group of components specified by the
|
||||||
|
* identifier.
|
||||||
|
*
|
||||||
|
* @param identifier - one of the constant update identifier.
|
||||||
|
*/
|
||||||
|
private void updateColors(int identifier) {
|
||||||
|
if ((identifier & GOAL) == GOAL) {
|
||||||
|
goal.setForeground(Settings.CLR_TIME.get());
|
||||||
|
}
|
||||||
|
if ((identifier & TEXT) == TEXT) {
|
||||||
|
goalText.setForeground(Settings.CLR_FORE.get());
|
||||||
|
}
|
||||||
|
if ((identifier & TITLE) == TITLE) {
|
||||||
|
title.setForeground(Settings.CLR_TITL.get());
|
||||||
|
}
|
||||||
|
if ((identifier & BACKGROUND) == BACKGROUND) {
|
||||||
|
setBackground(Settings.CLR_BACK.get());
|
||||||
|
}
|
||||||
|
if ((identifier & SEPARATOR) == SEPARATOR) {
|
||||||
|
Color color = Settings.CLR_SPRT.get();
|
||||||
|
for (JLabel separator : separators) {
|
||||||
|
separator.setBorder(
|
||||||
|
BorderFactory.createMatteBorder(1, 0, 0, 0, color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the visibility of the components specified by the
|
||||||
|
* identifier.
|
||||||
|
*
|
||||||
|
* @param identifier - one of the constant update identifier.
|
||||||
|
*/
|
||||||
|
private void updateVisibility(int identifier) {
|
||||||
|
if ((identifier & GRAPH) == GRAPH) {
|
||||||
|
if (Settings.GPH_SHOW.get()) {
|
||||||
|
remove(core);
|
||||||
|
add(core, GBC.grid(0, 5).insets(0, 5).fill(GBC.H));
|
||||||
|
add(graph, GBC.grid(0, 7).fill(GBC.B).insets(0, 0, 3, 0)
|
||||||
|
.weight(1.0, 1.0));
|
||||||
|
} else {
|
||||||
|
remove(graph);
|
||||||
|
remove(core);
|
||||||
|
add(core, GBC.grid(0, 5).insets(0, 5).fill(GBC.H)
|
||||||
|
.weight(1.0, 1.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((identifier & FOOTER) == FOOTER) {
|
||||||
|
if (Settings.FOO_SHOW.get()) {
|
||||||
|
add(footer, GBC.grid(0, 8).insets(0, 3).fill(GBC.H));
|
||||||
|
} else {
|
||||||
|
remove(footer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((identifier & GOAL) == GOAL) {
|
||||||
|
if (Settings.HDR_GOAL.get()) {
|
||||||
|
if (Settings.HDR_TTLE.get()) {
|
||||||
|
add(goalPane, GBC.grid(0, 1));
|
||||||
|
} else {
|
||||||
|
add(goalPane, GBC.grid(0, 1).insets(3, 0, 0, 0));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
remove(goalPane);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((identifier & TITLE) == TITLE) {
|
||||||
|
title.setVisible(Settings.HDR_TTLE.get());
|
||||||
|
}
|
||||||
|
revalidate();
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class Images {
|
||||||
|
|
||||||
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||||
g2.scale(scale, scale);
|
g2.scale(scale, scale);
|
||||||
icon.paintIcon((Component)null, g2, 0, 0);
|
icon.paintIcon(null, g2, 0, 0);
|
||||||
g2.dispose();
|
g2.dispose();
|
||||||
return new ImageIcon(buffer);
|
return new ImageIcon(buffer);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ public class TableModelSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fire(TableModelEvent event) {
|
private void fire(TableModelEvent event) {
|
||||||
TableModelListener[] tableListeners = (TableModelListener[])this.listeners.getListeners(TableModelListener.class);
|
TableModelListener[] tableListeners = this.listeners.getListeners(TableModelListener.class);
|
||||||
TableModelListener[] arr$ = tableListeners;
|
TableModelListener[] arr$ = tableListeners;
|
||||||
int len$ = tableListeners.length;
|
int len$ = tableListeners.length;
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,8 @@ import java.net.URL;
|
||||||
public class AboutDialog extends JDialog implements ActionListener {
|
public class AboutDialog extends JDialog implements ActionListener {
|
||||||
private JLabel icon = new JLabel();
|
private JLabel icon = new JLabel();
|
||||||
private JLabel message;
|
private JLabel message;
|
||||||
private HyperLabel website;
|
private org.fenix.utils.about.HyperLabel website;
|
||||||
private HyperLabel donate;
|
private org.fenix.utils.about.HyperLabel donate;
|
||||||
private JButton okButton;
|
private JButton okButton;
|
||||||
|
|
||||||
public AboutDialog(Window owner, String title) {
|
public AboutDialog(Window owner, String title) {
|
||||||
|
@ -64,12 +64,12 @@ public class AboutDialog extends JDialog implements ActionListener {
|
||||||
if(url == null) {
|
if(url == null) {
|
||||||
throw new NullPointerException("Donate URL is null");
|
throw new NullPointerException("Donate URL is null");
|
||||||
} else {
|
} else {
|
||||||
this.donate = new HyperLabel(url, icon);
|
this.donate = new org.fenix.utils.about.HyperLabel(url, icon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWebsite(URL url) {
|
public void setWebsite(URL url) {
|
||||||
this.setWebsite(url, (String)null);
|
this.setWebsite(url, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWebsite(URL url, String text) {
|
public void setWebsite(URL url, String text) {
|
||||||
|
@ -80,7 +80,7 @@ public class AboutDialog extends JDialog implements ActionListener {
|
||||||
text = url.toString();
|
text = url.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.website = new HyperLabel(url, text);
|
this.website = new org.fenix.utils.about.HyperLabel(url, text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -171,7 +171,6 @@ public class Configuration implements Serializable {
|
||||||
try {
|
try {
|
||||||
stream.close();
|
stream.close();
|
||||||
} catch (Exception var11) {
|
} catch (Exception var11) {
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ public class LocaleDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void fireLocalChanged(Locale oldLocale, Locale newLocale) {
|
private static void fireLocalChanged(Locale oldLocale, Locale newLocale) {
|
||||||
LocaleListener[] arr$ = (LocaleListener[])listeners.getListeners(LocaleListener.class);
|
LocaleListener[] arr$ = listeners.getListeners(LocaleListener.class);
|
||||||
int len$ = arr$.length;
|
int len$ = arr$.length;
|
||||||
|
|
||||||
for(int i$ = 0; i$ < len$; ++i$) {
|
for(int i$ = 0; i$ < len$; ++i$) {
|
||||||
|
|
Reference in a new issue