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.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.dialog.EditRun;
|
||||
import org.fenix.llanfair.dialog.EditSettings;
|
||||
|
@ -26,6 +9,14 @@ import org.fenix.llanfair.extern.WSplit;
|
|||
import org.fenix.utils.about.AboutDialog;
|
||||
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.
|
||||
* All inputs and menu items callbacks are processed by this delegate to
|
||||
|
@ -35,410 +26,410 @@ import org.jnativehook.keyboard.NativeKeyEvent;
|
|||
* @version 1.0
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Creates a new delegate. This constructor is package private since it
|
||||
* 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 static final long GHOST_DELAY = 300L;
|
||||
private static ResourceBundle BUNDLE = null;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
private Llanfair master;
|
||||
|
||||
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();
|
||||
}
|
||||
private File file;
|
||||
private JFileChooser fileChooser;
|
||||
|
||||
private volatile long lastUnsplit;
|
||||
private volatile long lastSkip;
|
||||
|
||||
/**
|
||||
* Creates a new delegate. This constructor is package private since it
|
||||
* 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" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
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;
|
||||
|
||||
import org.fenix.utils.TableModelSupport;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.TableModelListener;
|
||||
import javax.swing.table.TableModel;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
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
|
||||
*/
|
||||
public class Counters implements TableModel, Serializable {
|
||||
|
||||
// -------------------------------------------------------------- CONSTANTES
|
||||
|
||||
public static final long serialVersionUID = 1000L;
|
||||
|
||||
public static final int COLUMN_ICON = 0;
|
||||
|
||||
public static final int COLUMN_NAME = 1;
|
||||
|
||||
public static final int COLUMN_START = 2;
|
||||
|
||||
public static final int COLUMN_INCREMENT = 3;
|
||||
|
||||
public static final int COLUMN_COUNT = 4;
|
||||
|
||||
// -------------------------------------------------------------- ATTRIBUTS
|
||||
|
||||
private List<Counter> data;
|
||||
|
||||
private TableModelSupport tmSupport;
|
||||
|
||||
// ---------------------------------------------------------- CONSTRUCTEURS
|
||||
|
||||
public Counters() {
|
||||
data = new ArrayList<Counter>();
|
||||
tmSupport = new TableModelSupport(this);
|
||||
}
|
||||
|
||||
public int getColumnCount() {
|
||||
return COLUMN_COUNT;
|
||||
}
|
||||
|
||||
public int getRowCount() {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
if (rowIndex < 0 || rowIndex >= data.size()) {
|
||||
throw new IllegalArgumentException("illegal counter id " + rowIndex);
|
||||
}
|
||||
return data.get(rowIndex).get(columnIndex);
|
||||
}
|
||||
|
||||
public String getColumnName(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case COLUMN_ICON: return "" + Language.ICON;
|
||||
case COLUMN_INCREMENT: return "" + Language.INCREMENT;
|
||||
case COLUMN_NAME: return "" + Language.NAME;
|
||||
case COLUMN_START: return "" + Language.START_VALUE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case COLUMN_ICON: return Icon.class;
|
||||
case COLUMN_INCREMENT: return Integer.class;
|
||||
case COLUMN_NAME: return String.class;
|
||||
case COLUMN_START: return Integer.class;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
||||
if (rowIndex < 0 || rowIndex >= data.size()) {
|
||||
throw new IllegalArgumentException("illegal counter id " + rowIndex);
|
||||
}
|
||||
data.get(rowIndex).set(columnIndex, aValue);
|
||||
}
|
||||
|
||||
public void addTableModelListener(TableModelListener l) {
|
||||
tmSupport.addTableModelListener(l);
|
||||
}
|
||||
|
||||
public void removeTableModelListener(TableModelListener l) {
|
||||
tmSupport.removeTableModelListener(l);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------- CLASSES
|
||||
|
||||
public static class Counter implements Serializable {
|
||||
|
||||
public static final long serialVersionUID = 1000L;
|
||||
|
||||
private String name;
|
||||
|
||||
private Icon icon;
|
||||
|
||||
private int increment;
|
||||
|
||||
private int start;
|
||||
|
||||
private int saved;
|
||||
|
||||
private int live;
|
||||
|
||||
public Counter() {
|
||||
name = "" + Language.UNTITLED;
|
||||
icon = null;
|
||||
start = 0;
|
||||
live = 0;
|
||||
increment = 1;
|
||||
}
|
||||
|
||||
public Object get(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case COLUMN_ICON: return icon;
|
||||
case COLUMN_INCREMENT: return increment;
|
||||
case COLUMN_NAME: return name;
|
||||
case COLUMN_START: return start;
|
||||
default: return name;
|
||||
}
|
||||
}
|
||||
|
||||
public void set(int columnIndex, Object value) {
|
||||
switch (columnIndex) {
|
||||
case COLUMN_ICON: icon = (Icon) value; break;
|
||||
case COLUMN_INCREMENT: increment = (Integer) value; break;
|
||||
case COLUMN_NAME: name = (String) value; break;
|
||||
case COLUMN_START: start = (Integer) value; break;
|
||||
}
|
||||
}
|
||||
|
||||
public Icon getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getLive() {
|
||||
return live;
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public int getSaved() {
|
||||
return saved;
|
||||
}
|
||||
|
||||
public void nextStep() {
|
||||
live += increment;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- CONSTANTES
|
||||
|
||||
public static final long serialVersionUID = 1000L;
|
||||
|
||||
public static final int COLUMN_ICON = 0;
|
||||
|
||||
public static final int COLUMN_NAME = 1;
|
||||
|
||||
public static final int COLUMN_START = 2;
|
||||
|
||||
public static final int COLUMN_INCREMENT = 3;
|
||||
|
||||
public static final int COLUMN_COUNT = 4;
|
||||
|
||||
// -------------------------------------------------------------- ATTRIBUTS
|
||||
|
||||
private List<Counter> data;
|
||||
|
||||
private TableModelSupport tmSupport;
|
||||
|
||||
// ---------------------------------------------------------- CONSTRUCTEURS
|
||||
|
||||
public Counters() {
|
||||
data = new ArrayList<Counter>();
|
||||
tmSupport = new TableModelSupport(this);
|
||||
}
|
||||
|
||||
public int getColumnCount() {
|
||||
return COLUMN_COUNT;
|
||||
}
|
||||
|
||||
public int getRowCount() {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
public Object getValueAt(int rowIndex, int columnIndex) {
|
||||
if (rowIndex < 0 || rowIndex >= data.size()) {
|
||||
throw new IllegalArgumentException("illegal counter id " + rowIndex);
|
||||
}
|
||||
return data.get(rowIndex).get(columnIndex);
|
||||
}
|
||||
|
||||
public String getColumnName(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case COLUMN_ICON: return "" + Language.ICON;
|
||||
case COLUMN_INCREMENT: return "" + Language.INCREMENT;
|
||||
case COLUMN_NAME: return "" + Language.NAME;
|
||||
case COLUMN_START: return "" + Language.START_VALUE;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case COLUMN_ICON: return Icon.class;
|
||||
case COLUMN_INCREMENT: return Integer.class;
|
||||
case COLUMN_NAME: return String.class;
|
||||
case COLUMN_START: return Integer.class;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
|
||||
if (rowIndex < 0 || rowIndex >= data.size()) {
|
||||
throw new IllegalArgumentException("illegal counter id " + rowIndex);
|
||||
}
|
||||
data.get(rowIndex).set(columnIndex, aValue);
|
||||
}
|
||||
|
||||
public void addTableModelListener(TableModelListener l) {
|
||||
tmSupport.addTableModelListener(l);
|
||||
}
|
||||
|
||||
public void removeTableModelListener(TableModelListener l) {
|
||||
tmSupport.removeTableModelListener(l);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------- CLASSES
|
||||
|
||||
public static class Counter implements Serializable {
|
||||
|
||||
public static final long serialVersionUID = 1000L;
|
||||
|
||||
private String name;
|
||||
|
||||
private Icon icon;
|
||||
|
||||
private int increment;
|
||||
|
||||
private int start;
|
||||
|
||||
private int saved;
|
||||
|
||||
private int live;
|
||||
|
||||
public Counter() {
|
||||
name = "" + Language.UNTITLED;
|
||||
icon = null;
|
||||
start = 0;
|
||||
live = 0;
|
||||
increment = 1;
|
||||
}
|
||||
|
||||
public Object get(int columnIndex) {
|
||||
switch (columnIndex) {
|
||||
case COLUMN_ICON: return icon;
|
||||
case COLUMN_INCREMENT: return increment;
|
||||
case COLUMN_NAME: return name;
|
||||
case COLUMN_START: return start;
|
||||
default: return name;
|
||||
}
|
||||
}
|
||||
|
||||
public void set(int columnIndex, Object value) {
|
||||
switch (columnIndex) {
|
||||
case COLUMN_ICON: icon = (Icon) value; break;
|
||||
case COLUMN_INCREMENT: increment = (Integer) value; break;
|
||||
case COLUMN_NAME: name = (String) value; break;
|
||||
case COLUMN_START: start = (Integer) value; break;
|
||||
}
|
||||
}
|
||||
|
||||
public Icon getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getLive() {
|
||||
return live;
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public int getSaved() {
|
||||
return saved;
|
||||
}
|
||||
|
||||
public void nextStep() {
|
||||
live += increment;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package org.fenix.llanfair;
|
||||
|
||||
import org.fenix.utils.Resources;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import org.fenix.utils.Resources;
|
||||
|
||||
/**
|
||||
* Enumeration of all externalized strings used by {@code Llanfair}. While it is
|
||||
|
@ -15,278 +16,278 @@ import org.fenix.utils.Resources;
|
|||
* @see Resources
|
||||
*/
|
||||
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,
|
||||
|
||||
/*
|
||||
* Run.State enumeration.
|
||||
*/
|
||||
RUN_NULL,
|
||||
RUN_OVER,
|
||||
RUN_READY,
|
||||
RUN_STOPPED,
|
||||
// Settings > Generic
|
||||
setting_alwaysOnTop,
|
||||
setting_language,
|
||||
setting_viewerLanguage,
|
||||
setting_recentFiles,
|
||||
setting_coordinates,
|
||||
setting_dimension,
|
||||
setting_compareMethod,
|
||||
setting_accuracy,
|
||||
setting_locked,
|
||||
setting_warnOnReset,
|
||||
|
||||
/*
|
||||
* Time.Accuracy enumeration.
|
||||
*/
|
||||
ACCURACY,
|
||||
// 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,
|
||||
|
||||
/*
|
||||
* Run.State enumeration.
|
||||
*/
|
||||
RUN_NULL,
|
||||
RUN_OVER,
|
||||
RUN_READY,
|
||||
RUN_STOPPED,
|
||||
|
||||
/*
|
||||
* Time.Accuracy enumeration.
|
||||
*/
|
||||
ACCURACY,
|
||||
|
||||
/*
|
||||
* Miscellaneous tokens.
|
||||
*/
|
||||
ACCEPT,
|
||||
APPLICATION,
|
||||
BEST,
|
||||
CANCEL,
|
||||
COMPARE_METHOD,
|
||||
COMPONENTS,
|
||||
DISABLED,
|
||||
EDITING,
|
||||
ERROR,
|
||||
GOAL,
|
||||
IMAGE,
|
||||
INPUTS,
|
||||
MAX_ORDINATE,
|
||||
NAME,
|
||||
RUN_TITLE,
|
||||
SEGMENT,
|
||||
SEGMENTS,
|
||||
SPLIT,
|
||||
TIME,
|
||||
UNTITLED,
|
||||
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");
|
||||
}
|
||||
/*
|
||||
* Miscellaneous tokens.
|
||||
*/
|
||||
ACCEPT,
|
||||
APPLICATION,
|
||||
BEST,
|
||||
CANCEL,
|
||||
COMPARE_METHOD,
|
||||
COMPONENTS,
|
||||
DISABLED,
|
||||
EDITING,
|
||||
ERROR,
|
||||
GOAL,
|
||||
IMAGE,
|
||||
INPUTS,
|
||||
MAX_ORDINATE,
|
||||
NAME,
|
||||
RUN_TITLE,
|
||||
SEGMENT,
|
||||
SEGMENTS,
|
||||
SPLIT,
|
||||
TIME,
|
||||
UNTITLED,
|
||||
WARNING,
|
||||
|
||||
// -------------------------------------------------------------- INTERFACE
|
||||
/*
|
||||
* 1.4
|
||||
*/
|
||||
INCREMENT,
|
||||
START_VALUE;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
public static final Locale[] LANGUAGES = new Locale[] {
|
||||
Locale.ENGLISH,
|
||||
Locale.FRENCH,
|
||||
Locale.GERMAN,
|
||||
new Locale("nl"),
|
||||
new Locale("sv")
|
||||
};
|
||||
|
||||
/**
|
||||
* The string representation of an enumerate is the localized string
|
||||
* corresponding to its name.
|
||||
*/
|
||||
@Override public String toString() {
|
||||
return get();
|
||||
}
|
||||
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
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public class Llanfair extends BorderlessFrame implements TableModelListener,
|
||||
LocaleListener, MouseWheelListener, ActionListener, NativeKeyListener,
|
||||
PropertyChangeListener, WindowListener {
|
||||
LocaleListener, MouseWheelListener, ActionListener, NativeKeyListener,
|
||||
PropertyChangeListener, WindowListener {
|
||||
|
||||
private static Resources RESOURCES = null;
|
||||
|
||||
|
||||
static {
|
||||
ToolTipManager.sharedInstance().setInitialDelay( 1000 );
|
||||
ToolTipManager.sharedInstance().setDismissDelay( 7000 );
|
||||
ToolTipManager.sharedInstance().setReshowDelay( 0 );
|
||||
}
|
||||
private static Resources RESOURCES = null;
|
||||
|
||||
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 Dimension preferredSize;
|
||||
private Run run;
|
||||
private RunPane runPane;
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
private Actions actions;
|
||||
|
||||
//ResourceBundle b = ResourceBundle.getBundle("language");
|
||||
|
||||
RESOURCES = new Resources();
|
||||
registerFonts();
|
||||
setLookAndFeel();
|
||||
private JPopupMenu popupMenu;
|
||||
|
||||
run = new Run();
|
||||
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 volatile boolean ignoreNativeInputs;
|
||||
|
||||
/**
|
||||
* 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$
|
||||
}
|
||||
}
|
||||
private Dimension preferredSize;
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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 );
|
||||
|
||||
@Override public void nativeKeyReleased( NativeKeyEvent event ) {}
|
||||
//ResourceBundle b = ResourceBundle.getBundle("language");
|
||||
|
||||
@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();
|
||||
RESOURCES = new Resources();
|
||||
registerFonts();
|
||||
setLookAndFeel();
|
||||
|
||||
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 );
|
||||
}
|
||||
run = new Run();
|
||||
runPane = null;
|
||||
ignoreNativeInputs = false;
|
||||
preferredSize = null;
|
||||
actions = new Actions( this );
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
setMenu();
|
||||
setBehavior();
|
||||
setRun( run );
|
||||
|
||||
@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) {}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
setPreferredSize( preferredSize );
|
||||
pack();
|
||||
|
||||
SwingUtilities.invokeLater( new Runnable() {
|
||||
@Override public void run() {
|
||||
actions.process( ev );
|
||||
}
|
||||
} );
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
pack();
|
||||
|
||||
} else if (source.equals(MenuItem.RESIZE_PREFERRED)) {
|
||||
setPreferredSize(preferredSize);
|
||||
pack();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the right-click context menu.
|
||||
*/
|
||||
private void setMenu() {
|
||||
popupMenu = MenuItem.getPopupMenu();
|
||||
MenuItem.addActionListener( this );
|
||||
MenuItem.populateRecentlyOpened();
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
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.ActionListener;
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
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
|
||||
|
@ -25,207 +22,207 @@ import org.fenix.llanfair.config.Settings;
|
|||
*/
|
||||
enum MenuItem implements ActionListener {
|
||||
|
||||
EDIT( false, State.NULL, State.READY ),
|
||||
NEW( true, State.NULL, State.READY, State.STOPPED ),
|
||||
OPEN( false, State.NULL, State.READY, State.STOPPED ),
|
||||
OPEN_RECENT( false, State.NULL, State.READY, State.STOPPED ),
|
||||
IMPORT( false, State.NULL, State.READY, State.STOPPED ),
|
||||
SAVE( false, State.READY, State.STOPPED ),
|
||||
SAVE_AS( true, State.READY ),
|
||||
RESET( true, State.ONGOING, State.STOPPED, State.PAUSED ),
|
||||
LOCK( 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_PREFERRED( true, State.NULL, State.READY ),
|
||||
SETTINGS( true, State.NULL, State.READY, State.STOPPED ),
|
||||
ABOUT( true, State.NULL, State.READY, State.STOPPED, State.ONGOING ),
|
||||
EXIT( false, State.NULL, State.READY, State.STOPPED, State.ONGOING );
|
||||
EDIT( false, State.NULL, State.READY ),
|
||||
NEW( true, State.NULL, State.READY, State.STOPPED ),
|
||||
OPEN( false, State.NULL, State.READY, State.STOPPED ),
|
||||
OPEN_RECENT( false, State.NULL, State.READY, State.STOPPED ),
|
||||
IMPORT( false, State.NULL, State.READY, State.STOPPED ),
|
||||
SAVE( false, State.READY, State.STOPPED ),
|
||||
SAVE_AS( true, State.READY ),
|
||||
RESET( true, State.ONGOING, State.STOPPED, State.PAUSED ),
|
||||
LOCK( 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_PREFERRED( true, State.NULL, State.READY ),
|
||||
SETTINGS( true, State.NULL, State.READY, State.STOPPED ),
|
||||
ABOUT( true, 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
|
||||
* one item fires an {@code ActionEvent}, the type statically fires an
|
||||
* other {@code ActionEvent} with the {@code MenuItem} enumerate as the
|
||||
* source component.
|
||||
*/
|
||||
private static EventListenerList listeners = new EventListenerList();
|
||||
/**
|
||||
* Static list of listeners that listen to all the menu items. Whenever
|
||||
* one item fires an {@code ActionEvent}, the type statically fires an
|
||||
* other {@code ActionEvent} with the {@code MenuItem} enumerate as the
|
||||
* source component.
|
||||
*/
|
||||
private static EventListenerList listeners = new EventListenerList();
|
||||
|
||||
private static final int MAX_FILES = 5;
|
||||
private static final int TRUNCATE = 30;
|
||||
|
||||
private boolean isEndOfGroup;
|
||||
private List<State> activeStates;
|
||||
private JMenuItem menuItem;
|
||||
private static final int MAX_FILES = 5;
|
||||
private static final int TRUNCATE = 30;
|
||||
|
||||
/**
|
||||
* Internal constructor used to set the attributes. Only called by the
|
||||
* enum type itself.
|
||||
*
|
||||
* @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 );
|
||||
private boolean isEndOfGroup;
|
||||
private List<State> activeStates;
|
||||
private JMenuItem menuItem;
|
||||
|
||||
if ( name().equals( "OPEN_RECENT" ) ) {
|
||||
menuItem = new JMenu( toString() );
|
||||
} else {
|
||||
menuItem = new JMenuItem( toString() );
|
||||
}
|
||||
Icon icon = Llanfair.getResources().getIcon( "jmi/" + name() + ".png" );
|
||||
menuItem.setIcon( icon );
|
||||
menuItem.addActionListener( this );
|
||||
// LOCK & UNLOCK mask each other and Llanfair always start unlocked
|
||||
if ( name().equals( "UNLOCK" ) ) {
|
||||
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;
|
||||
}
|
||||
/**
|
||||
* Internal constructor used to set the attributes. Only called by the
|
||||
* enum type itself.
|
||||
*
|
||||
* @param isEndOfGroup indicates if this item is a group ender
|
||||
* @param activeStates list of active run states of this item
|
||||
*/
|
||||
MenuItem(boolean isEndOfGroup, Run.State... activeStates) {
|
||||
this.isEndOfGroup = isEndOfGroup;
|
||||
this.activeStates = Arrays.asList( activeStates );
|
||||
|
||||
/**
|
||||
* 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
|
||||
* its GUI component is enabled, else it is disabled.
|
||||
*
|
||||
* @param state the current run state, cannot be {@code null}
|
||||
*/
|
||||
static void setActiveState( Run.State state ) {
|
||||
if ( state == null ) {
|
||||
throw new IllegalArgumentException( "Null run state" );
|
||||
}
|
||||
for ( MenuItem item : values() ) {
|
||||
item.menuItem.setEnabled( item.activeStates.contains( state ) );
|
||||
}
|
||||
}
|
||||
if ( name().equals( "OPEN_RECENT" ) ) {
|
||||
menuItem = new JMenu( toString() );
|
||||
} else {
|
||||
menuItem = new JMenuItem( toString() );
|
||||
}
|
||||
Icon icon = Llanfair.getResources().getIcon( "jmi/" + name() + ".png" );
|
||||
menuItem.setIcon( icon );
|
||||
menuItem.addActionListener( this );
|
||||
// LOCK & UNLOCK mask each other and Llanfair always start unlocked
|
||||
if ( name().equals( "UNLOCK" ) ) {
|
||||
menuItem.setVisible( false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given {@code ActionListener} to the list of listeners
|
||||
* interested in capturing events from every menu items.
|
||||
*
|
||||
* @param listener the action listener to register
|
||||
*/
|
||||
static void addActionListener( ActionListener listener ) {
|
||||
listeners.add( ActionListener.class, listener );
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to invoke whenever a file is opened. This method will sort the
|
||||
* recent files menu to put the recently opened file at the top.
|
||||
*
|
||||
* @param path the name of the recently opened file
|
||||
*/
|
||||
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 );
|
||||
/**
|
||||
* 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 ( 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();
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
* its GUI component is enabled, else it is disabled.
|
||||
*
|
||||
* @param state the current run state, cannot be {@code null}
|
||||
*/
|
||||
static void setActiveState( Run.State state ) {
|
||||
if ( state == null ) {
|
||||
throw new IllegalArgumentException( "Null run state" );
|
||||
}
|
||||
for ( MenuItem item : values() ) {
|
||||
item.menuItem.setEnabled( item.activeStates.contains( state ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
}
|
||||
/**
|
||||
* Registers the given {@code ActionListener} to the list of listeners
|
||||
* interested in capturing events from every menu items.
|
||||
*
|
||||
* @param listener the action listener to register
|
||||
*/
|
||||
static void addActionListener( ActionListener listener ) {
|
||||
listeners.add( ActionListener.class, listener );
|
||||
}
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Callback to invoke whenever a file is opened. This method will sort the
|
||||
* recent files menu to put the recently opened file at the top.
|
||||
*
|
||||
* @param path the name of the recently opened file
|
||||
*/
|
||||
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 );
|
||||
}
|
||||
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 {
|
||||
|
||||
// -------------------------------------------------------------- CONSTANTS
|
||||
// -------------------------------------------------------------- CONSTANTS
|
||||
|
||||
/**
|
||||
* The serial version identifier used to determine the compatibility of the
|
||||
* different serialized versions of this type. This identifier must change
|
||||
* when modifications that break backward-compatibility are made to the
|
||||
* type.
|
||||
*/
|
||||
private static final long serialVersionUID = 1001L;
|
||||
/**
|
||||
* The serial version identifier used to determine the compatibility of the
|
||||
* different serialized versions of this type. This identifier must change
|
||||
* when modifications that break backward-compatibility are made to the
|
||||
* type.
|
||||
*/
|
||||
private static final long serialVersionUID = 1001L;
|
||||
|
||||
/**
|
||||
* Array of legit display sizes for the segments’ icons.
|
||||
*/
|
||||
public static final Integer[] ICON_SIZES = new Integer[] {
|
||||
16, 24, 32, 40, 48, 56, 64
|
||||
};
|
||||
/**
|
||||
* Array of legit display sizes for the segments’ icons.
|
||||
*/
|
||||
public static final Integer[] ICON_SIZES = new Integer[] {
|
||||
16, 24, 32, 40, 48, 56, 64
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
* not be scaled up if it’s smaller.
|
||||
*/
|
||||
public static final int ICON_MAX_SIZE = ICON_SIZES[ICON_SIZES.length - 1];
|
||||
/**
|
||||
* 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
|
||||
* not be scaled up if it’s smaller.
|
||||
*/
|
||||
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
|
||||
* compare method.
|
||||
*/
|
||||
public static final int SET = 0;
|
||||
/**
|
||||
* Identifier for the time of the segment as defined by the currently set
|
||||
* compare method.
|
||||
*/
|
||||
public static final int SET = 0;
|
||||
|
||||
/**
|
||||
* Identifier for the registered time of the segment.
|
||||
*/
|
||||
public static final int RUN = 1;
|
||||
/**
|
||||
* Identifier for the registered time of the segment.
|
||||
*/
|
||||
public static final int RUN = 1;
|
||||
|
||||
/**
|
||||
* Identifier for the best ever registered time of the segment.
|
||||
*/
|
||||
public static final int BEST = 2;
|
||||
/**
|
||||
* Identifier for the best ever registered time of the segment.
|
||||
*/
|
||||
public static final int BEST = 2;
|
||||
|
||||
/**
|
||||
* Identifier for the live time realized on this segment.
|
||||
*/
|
||||
public static final int LIVE = 3;
|
||||
/**
|
||||
* Identifier for the live time realized on this segment.
|
||||
*/
|
||||
public static final int LIVE = 3;
|
||||
|
||||
/**
|
||||
* Identifier for the delta between the live time and the time as defined
|
||||
* by the currently set compare method, i.e. {@code LIVE - SET}.
|
||||
*/
|
||||
public static final int DELTA = 4;
|
||||
/**
|
||||
* Identifier for the delta between the live time and the time as defined
|
||||
* by the currently set compare method, i.e. {@code LIVE - SET}.
|
||||
*/
|
||||
public static final int DELTA = 4;
|
||||
|
||||
/**
|
||||
* Identifier for the delta between the live time and the registered time
|
||||
* of the segment, i.e. {@code LIVE - RUN}.
|
||||
*/
|
||||
public static final int DELTA_RUN = 5;
|
||||
/**
|
||||
* Identifier for the delta between the live time and the registered time
|
||||
* of the segment, i.e. {@code LIVE - RUN}.
|
||||
*/
|
||||
public static final int DELTA_RUN = 5;
|
||||
|
||||
/**
|
||||
* Identifier for the delta between the live time and the best ever
|
||||
* registered time of the segment, i.e. {@code LIVE - BEST}.
|
||||
*/
|
||||
public static final int DELTA_BEST = 6;
|
||||
/**
|
||||
* Identifier for the delta between the live time and the best ever
|
||||
* registered time of the segment, i.e. {@code LIVE - BEST}.
|
||||
*/
|
||||
public static final int DELTA_BEST = 6;
|
||||
|
||||
// ------------------------------------------------------------- ATTRIBUTES
|
||||
// ------------------------------------------------------------- ATTRIBUTES
|
||||
|
||||
/**
|
||||
* Name of the segment.
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* Name of the segment.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Icon associated with this segment. Can be {@code null} if no icon is to
|
||||
* be displayed.
|
||||
*/
|
||||
private Icon icon;
|
||||
/**
|
||||
* Icon associated with this segment. Can be {@code null} if no icon is to
|
||||
* be displayed.
|
||||
*/
|
||||
private Icon icon;
|
||||
|
||||
/**
|
||||
* Registered time for this segment during the best run.
|
||||
*/
|
||||
private Time runTime;
|
||||
/**
|
||||
* Registered time for this segment during the best run.
|
||||
*/
|
||||
private Time runTime;
|
||||
|
||||
/**
|
||||
* Best time ever registered for this segment.
|
||||
*/
|
||||
private Time bestTime;
|
||||
/**
|
||||
* Best time ever registered for this segment.
|
||||
*/
|
||||
private Time bestTime;
|
||||
|
||||
/**
|
||||
* Live time realized on this segment during a run. This value is never
|
||||
* saved as is but can overwrite {@code runTime} or {@code bestTime}.
|
||||
*/
|
||||
private transient Time liveTime;
|
||||
|
||||
/**
|
||||
* Number of milliseconds on the clock when the segment started.
|
||||
*/
|
||||
private transient long startTime;
|
||||
/**
|
||||
* Live time realized on this segment during a run. This value is never
|
||||
* saved as is but can overwrite {@code runTime} or {@code bestTime}.
|
||||
*/
|
||||
private transient Time liveTime;
|
||||
|
||||
// ----------------------------------------------------------- CONSTRUCTORS
|
||||
/**
|
||||
* Number of milliseconds on the clock when the segment started.
|
||||
*/
|
||||
private transient long startTime;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
// ----------------------------------------------------------- CONSTRUCTORS
|
||||
|
||||
// ---------------------------------------------------------------- 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.
|
||||
*
|
||||
* @return the name of the segment.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the icon associated with this segment. Can be {@code null}.
|
||||
*
|
||||
* @return the icon of the segment or {@code null}.
|
||||
*/
|
||||
public Icon getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of milliseconds on the clock when the segment started.
|
||||
*
|
||||
* @return the start time of this segment.
|
||||
*/
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given type of time for this segment.
|
||||
*
|
||||
* @param type - one of the type identifier.
|
||||
* @return the segment time of given type.
|
||||
*/
|
||||
public Time getTime(int type) {
|
||||
switch (type) {
|
||||
case BEST:
|
||||
return bestTime;
|
||||
|
||||
case LIVE:
|
||||
return liveTime;
|
||||
|
||||
case RUN:
|
||||
return runTime;
|
||||
|
||||
case DELTA_RUN:
|
||||
if (runTime == null) {
|
||||
return null;
|
||||
}
|
||||
return Time.getDelta(liveTime, runTime);
|
||||
|
||||
case DELTA_BEST:
|
||||
if (bestTime == null) {
|
||||
return null;
|
||||
}
|
||||
return Time.getDelta(liveTime, bestTime);
|
||||
|
||||
case DELTA:
|
||||
Time time = getTime();
|
||||
return (time == null ? null : Time.getDelta(liveTime, time));
|
||||
|
||||
default:
|
||||
return getTime();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* As specified by {@code Cloneable}, returns a deep copy of the segment.
|
||||
*/
|
||||
public Segment clone() {
|
||||
Segment segment = new Segment(name);
|
||||
segment.icon = icon;
|
||||
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;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- SETTERS
|
||||
|
||||
/**
|
||||
* Sets the name of the segment to the given string.
|
||||
*
|
||||
* @param name - the new name of the segment.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("null name");
|
||||
}
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* be scale down to {@code ICON_MAX_SIZE} if it’s bigger.
|
||||
*
|
||||
* @param icon - the new icon for this segment.
|
||||
*/
|
||||
public void setIcon(Icon icon) {
|
||||
if (icon == null) {
|
||||
this.icon = null;
|
||||
} else {
|
||||
this.icon = Images.rescale(icon, ICON_MAX_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of milliseconds on the clock when the segment started.
|
||||
* 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.
|
||||
*/
|
||||
void setStartTime(long startTime) {
|
||||
if (startTime < 0L) {
|
||||
throw new IllegalArgumentException("negative start time");
|
||||
}
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* {@code null} to indicate undefined times.
|
||||
*
|
||||
* @param time - the new time value for the given type.
|
||||
* @param type - one of the type identifier.
|
||||
* @throws IllegalArgumentException if the new time value is lower than or
|
||||
* equal to zero.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
/**
|
||||
* Creates a default segment with a default name and undefined times.
|
||||
*/
|
||||
public Segment() {
|
||||
this("" + Language.UNTITLED);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- GETTERS
|
||||
|
||||
/**
|
||||
* Returns the name of the segment.
|
||||
*
|
||||
* @return the name of the segment.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the icon associated with this segment. Can be {@code null}.
|
||||
*
|
||||
* @return the icon of the segment or {@code null}.
|
||||
*/
|
||||
public Icon getIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of milliseconds on the clock when the segment started.
|
||||
*
|
||||
* @return the start time of this segment.
|
||||
*/
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given type of time for this segment.
|
||||
*
|
||||
* @param type - one of the type identifier.
|
||||
* @return the segment time of given type.
|
||||
*/
|
||||
public Time getTime(int type) {
|
||||
switch (type) {
|
||||
case BEST:
|
||||
return bestTime;
|
||||
|
||||
case LIVE:
|
||||
return liveTime;
|
||||
|
||||
case RUN:
|
||||
return runTime;
|
||||
|
||||
case DELTA_RUN:
|
||||
if (runTime == null) {
|
||||
return null;
|
||||
}
|
||||
return Time.getDelta(liveTime, runTime);
|
||||
|
||||
case DELTA_BEST:
|
||||
if (bestTime == null) {
|
||||
return null;
|
||||
}
|
||||
return Time.getDelta(liveTime, bestTime);
|
||||
|
||||
case DELTA:
|
||||
Time time = getTime();
|
||||
return (time == null ? null : Time.getDelta(liveTime, time));
|
||||
|
||||
default:
|
||||
return getTime();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* As specified by {@code Cloneable}, returns a deep copy of the segment.
|
||||
*/
|
||||
public Segment clone() {
|
||||
Segment segment = new Segment(name);
|
||||
segment.icon = icon;
|
||||
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;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- SETTERS
|
||||
|
||||
/**
|
||||
* Sets the name of the segment to the given string.
|
||||
*
|
||||
* @param name - the new name of the segment.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("null name");
|
||||
}
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* be scale down to {@code ICON_MAX_SIZE} if it’s bigger.
|
||||
*
|
||||
* @param icon - the new icon for this segment.
|
||||
*/
|
||||
public void setIcon(Icon icon) {
|
||||
if (icon == null) {
|
||||
this.icon = null;
|
||||
} else {
|
||||
this.icon = Images.rescale(icon, ICON_MAX_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of milliseconds on the clock when the segment started.
|
||||
* 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.
|
||||
*/
|
||||
void setStartTime(long startTime) {
|
||||
if (startTime < 0L) {
|
||||
throw new IllegalArgumentException("negative start time");
|
||||
}
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* {@code null} to indicate undefined times.
|
||||
*
|
||||
* @param time - the new time value for the given type.
|
||||
* @param type - one of the type identifier.
|
||||
* @throws IllegalArgumentException if the new time value is lower than or
|
||||
* equal to zero.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
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.
|
||||
*/
|
||||
* Deserialization process. Redefined to initialize transients fields upon
|
||||
* deserialization.
|
||||
*/
|
||||
private void readObject(ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException {
|
||||
in.defaultReadObject();
|
||||
initializeTransients();
|
||||
throws IOException, ClassNotFoundException {
|
||||
in.defaultReadObject();
|
||||
initializeTransients();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,276 +23,276 @@ import org.fenix.llanfair.config.Settings;
|
|||
* @version 1.1
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Creates a default time of zero milliseconds.
|
||||
*/
|
||||
public Time() {
|
||||
milliseconds = 0L;
|
||||
}
|
||||
private long milliseconds;
|
||||
|
||||
/**
|
||||
* Creates a time representing a given number of milliseconds. 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 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 default time of zero milliseconds.
|
||||
*/
|
||||
public Time() {
|
||||
milliseconds = 0L;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* time-stamp must be formatted according to the following:
|
||||
*
|
||||
* <pre>((H)H:)((M)M:)(S)S(.T(H(M)))</pre>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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)
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates a time representing a given number of milliseconds. 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 ms the number of milliseconds to represent
|
||||
*/
|
||||
public Time(long ms) {
|
||||
milliseconds = (ms / 10L) * 10L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the delta of time between two times. The returned time is
|
||||
* equivalent to, but more convenient than, the following code:
|
||||
* {@code new Time(t1.getMilliseconds() - t2.getMilliseconds())}.
|
||||
*
|
||||
* @param t1 the first time
|
||||
* @param t2 the time to substract from the first
|
||||
* @return the delta of time between the two times
|
||||
*/
|
||||
public static Time getDelta(Time t1, Time t2) {
|
||||
if (t1 == null) {
|
||||
t1 = new Time();
|
||||
} else if (t2 == null) {
|
||||
t2 = new Time();
|
||||
}
|
||||
return new Time(t1.milliseconds - t2.milliseconds);
|
||||
}
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of milliseconds represented by that time.
|
||||
*
|
||||
* @return the number of milliseconds represented by that time
|
||||
*/
|
||||
public long getMilliseconds() {
|
||||
return milliseconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given time to this time. The number of milliseconds
|
||||
* represented by this time object is now equals to:
|
||||
* {@code getMilliseconds() + time.getMilliseconds()}
|
||||
*
|
||||
* @param time the time object to add to this time
|
||||
*/
|
||||
public void add(Time time) {
|
||||
milliseconds += (time == null ? 0L : time.milliseconds);
|
||||
}
|
||||
|
||||
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;
|
||||
/**
|
||||
* 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
|
||||
* time-stamp must be formatted according to the following:
|
||||
*
|
||||
* <pre>((H)H:)((M)M:)(S)S(.T(H(M)))</pre>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (hou == 0L) {
|
||||
if (min == 0L) {
|
||||
switch (accuracy) {
|
||||
case HUNDREDTH:
|
||||
return String.format("%d.%02d", sec, cen);
|
||||
case TENTH:
|
||||
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);
|
||||
}
|
||||
/**
|
||||
* Returns the delta of time between two times. The returned time is
|
||||
* equivalent to, but more convenient than, the following code:
|
||||
* {@code new Time(t1.getMilliseconds() - t2.getMilliseconds())}.
|
||||
*
|
||||
* @param t1 the first time
|
||||
* @param t2 the time to substract from the first
|
||||
* @return the delta of time between the two times
|
||||
*/
|
||||
public static Time getDelta(Time t1, Time t2) {
|
||||
if (t1 == null) {
|
||||
t1 = new Time();
|
||||
} else if (t2 == null) {
|
||||
t2 = new Time();
|
||||
}
|
||||
return new Time(t1.milliseconds - t2.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);
|
||||
}
|
||||
/**
|
||||
* Returns the number of milliseconds represented by that time.
|
||||
*
|
||||
* @return the number of milliseconds represented by that time
|
||||
*/
|
||||
public long getMilliseconds() {
|
||||
return 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;
|
||||
}
|
||||
/**
|
||||
* Adds the given time to this time. The number of milliseconds
|
||||
* represented by this time object is now equals to:
|
||||
* {@code getMilliseconds() + time.getMilliseconds()}
|
||||
*
|
||||
* @param time the time object to add to this time
|
||||
*/
|
||||
public void add(Time time) {
|
||||
milliseconds += (time == null ? 0L : time.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);
|
||||
}
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
// Round to the nearest tenth.
|
||||
if (accuracy == Accuracy.TENTH) {
|
||||
cen = Math.round((double) cen / 10L);
|
||||
if (cen == 10L) {
|
||||
cen = 0L;
|
||||
time = time + 1000L;
|
||||
}
|
||||
}
|
||||
|
||||
// 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];
|
||||
// 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;
|
||||
|
||||
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));
|
||||
}
|
||||
if (hou == 0L) {
|
||||
if (min == 0L) {
|
||||
switch (accuracy) {
|
||||
case HUNDREDTH:
|
||||
return String.format("%d.%02d", sec, cen);
|
||||
case TENTH:
|
||||
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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.fenix.llanfair.Language;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
public enum Accuracy implements Serializable {
|
||||
|
||||
SECONDS,
|
||||
TENTH,
|
||||
HUNDREDTH;
|
||||
|
||||
private static final long serialVersionUID = 1000L;
|
||||
|
||||
@Override public String toString() {
|
||||
return Language.valueOf("accuracy_" + name().toLowerCase()).get();
|
||||
}
|
||||
SECONDS,
|
||||
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;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.fenix.llanfair.Language;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Xavier
|
||||
*/
|
||||
public enum Compare implements Serializable {
|
||||
|
||||
BEST_OVERALL_RUN,
|
||||
SUM_OF_BEST_SEGMENTS;
|
||||
|
||||
private static final long serialVersionUID = 1000L;
|
||||
|
||||
@Override public String toString() {
|
||||
return Language.valueOf(
|
||||
"compare_" + name().toLowerCase().replaceAll("\\.", "_")
|
||||
).get();
|
||||
}
|
||||
|
||||
BEST_OVERALL_RUN,
|
||||
SUM_OF_BEST_SEGMENTS;
|
||||
|
||||
private static final long serialVersionUID = 1000L;
|
||||
|
||||
@Override public String toString() {
|
||||
return Language.valueOf(
|
||||
"compare_" + name().toLowerCase().replaceAll("\\.", "_")
|
||||
).get();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
package org.fenix.llanfair.config;
|
||||
|
||||
import java.io.Serializable;
|
||||
import org.fenix.llanfair.Language;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Xavier
|
||||
*/
|
||||
public enum Merge implements Serializable {
|
||||
|
||||
NONE,
|
||||
LIVE,
|
||||
DELTA;
|
||||
|
||||
private static final long serialVersionUID = 1000L;
|
||||
|
||||
@Override public String toString() {
|
||||
return Language.valueOf("merge_" + name().toLowerCase()).get();
|
||||
}
|
||||
|
||||
NONE,
|
||||
LIVE,
|
||||
DELTA;
|
||||
|
||||
private static final long serialVersionUID = 1000L;
|
||||
|
||||
@Override public String toString() {
|
||||
return Language.valueOf("merge_" + name().toLowerCase()).get();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,403 +26,403 @@ import org.fenix.utils.config.Configuration;
|
|||
* @version 1.3
|
||||
*/
|
||||
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;
|
||||
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;
|
||||
}
|
||||
/* GENERIC properties */
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
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;
|
||||
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.
|
||||
* Whenever a property sees its value updated globally or locally, listeners
|
||||
* are warned of the update.
|
||||
*
|
||||
* @param pcl the listener to register with the settings
|
||||
*/
|
||||
public static void addPropertyChangeListener( PropertyChangeListener pcl ) {
|
||||
if ( pcl == null ) {
|
||||
throw new NullPointerException( "Null property listener" );
|
||||
}
|
||||
global.addPropertyChangeListener( pcl );
|
||||
if ( run != null ) {
|
||||
run.addSettingChangeListener( pcl );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Registers a new {@code PropertyChangeListener} with the settings.
|
||||
* Whenever a property sees its value updated globally or locally, listeners
|
||||
* are warned of the update.
|
||||
*
|
||||
* @param pcl the listener to register with the settings
|
||||
*/
|
||||
public static void addPropertyChangeListener( PropertyChangeListener pcl ) {
|
||||
if ( pcl == null ) {
|
||||
throw new NullPointerException( "Null property listener" );
|
||||
}
|
||||
global.addPropertyChangeListener( pcl );
|
||||
if ( run != null ) {
|
||||
run.addSettingChangeListener( pcl );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the global configuration in {@code llanfair.xml} in the working
|
||||
* directory. If such a file does not exist, it is created.
|
||||
*/
|
||||
public static void save() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Saves the global configuration in {@code llanfair.xml} in the working
|
||||
* directory. If such a file does not exist, it is created.
|
||||
*/
|
||||
public static void save() {
|
||||
global.serialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the global configuration with every property, assigning them their
|
||||
* default value. This method can be called even when the global
|
||||
* configuration is not empty, and will thus function as a reset.
|
||||
*/
|
||||
private static void setDefaultValues() {
|
||||
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>() );
|
||||
global.put( GNR_COOR.key, null );
|
||||
global.put( GNR_SIZE.key, null );
|
||||
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 );
|
||||
}
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.<T>getSetting( key );
|
||||
}
|
||||
return global.<T>get( key );
|
||||
}
|
||||
/**
|
||||
* Fills the global configuration with every property, assigning them their
|
||||
* default value. This method can be called even when the global
|
||||
* configuration is not empty, and will thus function as a reset.
|
||||
*/
|
||||
private static void setDefaultValues() {
|
||||
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>() );
|
||||
global.put( GNR_COOR.key, null );
|
||||
global.put( GNR_SIZE.key, null );
|
||||
global.put( GNR_COMP.key, Compare.BEST_OVERALL_RUN );
|
||||
global.put( GNR_ACCY.key, Accuracy.TENTH );
|
||||
global.put( GNR_WARN.key, true );
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
}
|
||||
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" ) );
|
||||
|
||||
/**
|
||||
* Returns the localized name of this property.
|
||||
*/
|
||||
@Override public String toString() {
|
||||
return Language.valueOf(
|
||||
"setting_" + key.replaceAll( "\\.", "_" )
|
||||
).get();
|
||||
}
|
||||
|
||||
}
|
||||
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.
|
||||
*
|
||||
* @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
|
||||
implements ActionListener, ListSelectionListener {
|
||||
|
||||
// ------------------------------------------------------------- CONSTANTES
|
||||
// ------------------------------------------------------------- CONSTANTES
|
||||
|
||||
/**
|
||||
* Largeurs en pixels des colonnes de la table d’édition des segments. Les
|
||||
* largeurs sont données dans l’odre du modèle.
|
||||
*/
|
||||
private static final int[] TABLE_COLUMN_WIDTHS = new int[] {
|
||||
Segment.ICON_MAX_SIZE, 130, 100, 100, 100
|
||||
};
|
||||
/**
|
||||
* Largeurs en pixels des colonnes de la table d’édition des segments. Les
|
||||
* largeurs sont données dans l’odre du modèle.
|
||||
*/
|
||||
private static final int[] TABLE_COLUMN_WIDTHS = new int[] {
|
||||
Segment.ICON_MAX_SIZE, 130, 100, 100, 100
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
/**
|
||||
* 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);
|
||||
|
||||
// -------------------------------------------------------------- ATTRIBUTS
|
||||
// -------------------------------------------------------------- ATTRIBUTS
|
||||
|
||||
/**
|
||||
* Course éditée par cette boîte de dialogue.
|
||||
*/
|
||||
private Run run;
|
||||
/**
|
||||
* Course éditée par cette boîte de dialogue.
|
||||
*/
|
||||
private Run run;
|
||||
|
||||
/**
|
||||
* Zone d’édition du titre de la course.
|
||||
*/
|
||||
private JTextField runTitle;
|
||||
/**
|
||||
* Zone d’édition du titre de la course.
|
||||
*/
|
||||
private JTextField runTitle;
|
||||
|
||||
/**
|
||||
* Étiquette du {@link runTitle}.
|
||||
*/
|
||||
private JLabel runTitleLabel;
|
||||
/**
|
||||
* Étiquette du {@link runTitle}.
|
||||
*/
|
||||
private JLabel runTitleLabel;
|
||||
|
||||
/**
|
||||
* Table d’édition des segments de la course.
|
||||
*/
|
||||
private JTable segments;
|
||||
/**
|
||||
* Table d’édition des segments de la course.
|
||||
*/
|
||||
private JTable segments;
|
||||
|
||||
/**
|
||||
* Panneau avec ascenseur dans lequel est inséré la table {@link segments}.
|
||||
*/
|
||||
private JScrollPane scrollPane;
|
||||
/**
|
||||
* Panneau avec ascenseur dans lequel est inséré la table {@link segments}.
|
||||
*/
|
||||
private JScrollPane scrollPane;
|
||||
|
||||
/**
|
||||
* Étiquette de {@code segments}.
|
||||
*/
|
||||
private JLabel segmentsLabel;
|
||||
/**
|
||||
* Étiquette de {@code segments}.
|
||||
*/
|
||||
private JLabel segmentsLabel;
|
||||
|
||||
/**
|
||||
* Bouton permettant d’insérer un nouveau segment.
|
||||
*/
|
||||
private JButton addSegment;
|
||||
/**
|
||||
* Bouton permettant d’insérer un nouveau segment.
|
||||
*/
|
||||
private JButton addSegment;
|
||||
|
||||
/**
|
||||
* Bouton permettant de supprimer un segment.
|
||||
*/
|
||||
private JButton remSegment;
|
||||
|
||||
private JCheckBox segmented;
|
||||
/**
|
||||
* Bouton permettant de supprimer un segment.
|
||||
*/
|
||||
private JButton remSegment;
|
||||
|
||||
/**
|
||||
* Bouton permettant d’enregistrer l’édition et de quitter le dialogue.
|
||||
*/
|
||||
private JButton save;
|
||||
private JCheckBox segmented;
|
||||
|
||||
/**
|
||||
* Bouton permettant de quitter le dialogue sans modifier la course.
|
||||
*/
|
||||
private JButton cancel;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* Bouton permettant d’enregistrer l’édition et de quitter le dialogue.
|
||||
*/
|
||||
private JButton save;
|
||||
|
||||
// ----------------------------------------------------------- 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.
|
||||
*
|
||||
* @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();
|
||||
/**
|
||||
* Button moving the currently selected segment one position up.
|
||||
*/
|
||||
private JButton moveUp;
|
||||
|
||||
setTitle(Language.EDITING.get());
|
||||
/**
|
||||
* Button moving the currently selected segment one position down.
|
||||
*/
|
||||
private JButton moveDown;
|
||||
|
||||
runTitle = new JTextField(run.getName(), 61);
|
||||
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());
|
||||
private JTextField runGoal;
|
||||
|
||||
placeComponents();
|
||||
setBehavior();
|
||||
}
|
||||
// ----------------------------------------------------------- CONSTRUCTEURS
|
||||
|
||||
// ---------------------------------------------------------------- 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();
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
setTitle(Language.EDITING.get());
|
||||
|
||||
/**
|
||||
* Définit le comportement des sous-composants du dialogue.
|
||||
*/
|
||||
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);
|
||||
runTitle = new JTextField(run.getName(), 61);
|
||||
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());
|
||||
|
||||
// Définir les dimensions des composants.
|
||||
setResizable(false);
|
||||
addSegment.setPreferredSize(SMALL_BUTTON_SIZE);
|
||||
remSegment.setPreferredSize(SMALL_BUTTON_SIZE);
|
||||
moveUp.setPreferredSize(SMALL_BUTTON_SIZE);
|
||||
moveDown.setPreferredSize(SMALL_BUTTON_SIZE);
|
||||
placeComponents();
|
||||
setBehavior();
|
||||
}
|
||||
|
||||
segments.setRowHeight(Segment.ICON_MAX_SIZE);
|
||||
for (int i = 0; i < run.getColumnCount(); i++) {
|
||||
TableColumn column = segments.getColumnModel().getColumn(i);
|
||||
column.setPreferredWidth(TABLE_COLUMN_WIDTHS[i]);
|
||||
}
|
||||
// ---------------------------------------------------------------- MÉTHODES
|
||||
|
||||
int totalWidth = 0;
|
||||
for (int width : TABLE_COLUMN_WIDTHS) {
|
||||
totalWidth += width;
|
||||
}
|
||||
Dimension size = new Dimension(totalWidth, Segment.ICON_MAX_SIZE * 5);
|
||||
segments.setPreferredScrollableViewportSize(size);
|
||||
/**
|
||||
* 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));
|
||||
|
||||
// Enregistrement des écouteurs des composants.
|
||||
addSegment.addActionListener(this);
|
||||
remSegment.addActionListener(this);
|
||||
moveUp.addActionListener(this);
|
||||
moveDown.addActionListener(this);
|
||||
cancel.addActionListener(this);
|
||||
save.addActionListener(this);
|
||||
JPanel controls = new JPanel();
|
||||
controls.add(save);
|
||||
controls.add(cancel);
|
||||
add(controls, GBC.grid(0, 7, 4, 1));
|
||||
}
|
||||
|
||||
// Insertion des délégués de rendus et d’édition.
|
||||
segments.setDefaultRenderer(Icon.class, new IconRenderer());
|
||||
segments.setDefaultEditor(Icon.class, new FileChooserEditor(this));
|
||||
segments.setDefaultEditor(Time.class, new TimeEditor());
|
||||
/**
|
||||
* Définit le comportement des sous-composants du dialogue.
|
||||
*/
|
||||
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.
|
||||
segments.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
|
||||
segments.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
|
||||
segments.getSelectionModel().addListSelectionListener(this);
|
||||
// Définir les dimensions des composants.
|
||||
setResizable(false);
|
||||
addSegment.setPreferredSize(SMALL_BUTTON_SIZE);
|
||||
remSegment.setPreferredSize(SMALL_BUTTON_SIZE);
|
||||
moveUp.setPreferredSize(SMALL_BUTTON_SIZE);
|
||||
moveDown.setPreferredSize(SMALL_BUTTON_SIZE);
|
||||
|
||||
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();
|
||||
}
|
||||
segments.setRowHeight(Segment.ICON_MAX_SIZE);
|
||||
for (int i = 0; i < run.getColumnCount(); i++) {
|
||||
TableColumn column = segments.getColumnModel().getColumn(i);
|
||||
column.setPreferredWidth(TABLE_COLUMN_WIDTHS[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* l’appui sur un bouton.
|
||||
*
|
||||
* @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)) {
|
||||
run.removeSegment(segments.getSelectedRow());
|
||||
updateButtons();
|
||||
int totalWidth = 0;
|
||||
for (int width : TABLE_COLUMN_WIDTHS) {
|
||||
totalWidth += width;
|
||||
}
|
||||
Dimension size = new Dimension(totalWidth, Segment.ICON_MAX_SIZE * 5);
|
||||
segments.setPreferredScrollableViewportSize(size);
|
||||
|
||||
} else if (source.equals(save)) {
|
||||
run.setName(runTitle.getText());
|
||||
run.setGoal(runGoal.getText());
|
||||
run.setSegmented(segmented.isSelected());
|
||||
dispose();
|
||||
// Enregistrement des écouteurs des composants.
|
||||
addSegment.addActionListener(this);
|
||||
remSegment.addActionListener(this);
|
||||
moveUp.addActionListener(this);
|
||||
moveDown.addActionListener(this);
|
||||
cancel.addActionListener(this);
|
||||
save.addActionListener(this);
|
||||
|
||||
} else if (source.equals(cancel)) {
|
||||
if (!segments.isEditing()) {
|
||||
run.loadBackup();
|
||||
dispose();
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
// Insertion des délégués de rendus et d’édition.
|
||||
segments.setDefaultRenderer(Icon.class, new IconRenderer());
|
||||
segments.setDefaultEditor(Icon.class, new FileChooserEditor(this));
|
||||
segments.setDefaultEditor(Time.class, new TimeEditor());
|
||||
|
||||
/**
|
||||
* Méthode invoquée lors d’un changement de sélection dans la table.
|
||||
*
|
||||
* @param event - l’évènement de sélection.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
// Ajuster le comportement de la table.
|
||||
segments.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
|
||||
segments.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
|
||||
segments.getSelectionModel().addListSelectionListener(this);
|
||||
|
||||
// ---------------------------------------------------------- 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);
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction d’un gestionnaire de rendu d’icônes.
|
||||
*/
|
||||
public IconRenderer() {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
* l’appui sur un bouton.
|
||||
*
|
||||
* @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();
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
} else if (source.equals(remSegment)) {
|
||||
run.removeSegment(segments.getSelectedRow());
|
||||
updateButtons();
|
||||
|
||||
// ---------------------------------------------------------- CLASSE INTERNE
|
||||
} else if (source.equals(save)) {
|
||||
run.setName(runTitle.getText());
|
||||
run.setGoal(runGoal.getText());
|
||||
run.setSegmented(segmented.isSelected());
|
||||
dispose();
|
||||
|
||||
/**
|
||||
* 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
|
||||
* termine et que la valeur est modifié dans la table des segments.
|
||||
*
|
||||
* @author Xavier "Xunkar" Sencert
|
||||
*/
|
||||
private class TimeEditor extends DefaultCellEditor {
|
||||
} else if (source.equals(cancel)) {
|
||||
if (!segments.isEditing()) {
|
||||
run.loadBackup();
|
||||
dispose();
|
||||
}
|
||||
} else if (source.equals(moveUp)) {
|
||||
int selected = segments.getSelectedRow();
|
||||
run.moveSegmentUp(selected);
|
||||
segments.setRowSelectionInterval(selected - 1, selected - 1);
|
||||
|
||||
/**
|
||||
* Composant d’édition. Conservé ici en doublon pour éviter de devoir le
|
||||
* caster à chaque fois.
|
||||
*/
|
||||
private JTextField editor;
|
||||
} else if (source.equals(moveDown)) {
|
||||
int selected = segments.getSelectedRow();
|
||||
run.moveSegmentDown(selected);
|
||||
segments.setRowSelectionInterval(selected + 1, selected + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction d’un délégué par défaut.
|
||||
*/
|
||||
public TimeEditor() {
|
||||
super(new JTextField());
|
||||
editor = (JTextField) getComponent();
|
||||
}
|
||||
/**
|
||||
* Méthode invoquée lors d’un changement de sélection dans la table.
|
||||
*
|
||||
* @param event - l’évènement de sélection.
|
||||
*/
|
||||
public void valueChanged(ListSelectionEvent event) {
|
||||
if (!event.getValueIsAdjusting()) {
|
||||
updateButtons();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne la valeur entrée par l’utilisateur.
|
||||
*
|
||||
* @return la valeur entrée par l’utilisateur.
|
||||
*/
|
||||
public Object getCellEditorValue() {
|
||||
String text = editor.getText();
|
||||
return text.equals("") ? null : new Time(text);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
// ---------------------------------------------------------- CLASSE INTERNE
|
||||
|
||||
/**
|
||||
* Arrête l’édition de la cellule. Le délégué récupère ici les exceptions
|
||||
* levées et les remonte à l’utilisateur. Tant que l’édition est en erreur
|
||||
* l’édition persiste.
|
||||
*
|
||||
* @return {@code true} si l’édition s’est arrêtée.
|
||||
*/
|
||||
public boolean stopCellEditing() {
|
||||
try {
|
||||
return super.stopCellEditing();
|
||||
} catch (Exception e) {
|
||||
JOptionPane.showMessageDialog(editor, e.getMessage(),
|
||||
Language.ERROR.get(), JOptionPane.ERROR_MESSAGE);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* É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 {
|
||||
// ---------------------------------------------------------- CLASSE INTERNE
|
||||
|
||||
/**
|
||||
* Gestionnaire de sélection de fichier.
|
||||
*/
|
||||
private JFileChooser chooser;
|
||||
/**
|
||||
* 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
|
||||
* 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}
|
||||
* 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;
|
||||
/**
|
||||
* Composant d’édition. Conservé ici en doublon pour éviter de devoir le
|
||||
* caster à chaque fois.
|
||||
*/
|
||||
private JTextField editor;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
/**
|
||||
* Construction d’un délégué par défaut.
|
||||
*/
|
||||
public TimeEditor() {
|
||||
super(new JTextField());
|
||||
editor = (JTextField) getComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 entrée par l’utilisateur.
|
||||
*
|
||||
* @return la valeur entrée par l’utilisateur.
|
||||
*/
|
||||
public Object getCellEditorValue() {
|
||||
String text = editor.getText();
|
||||
return text.equals("") ? null : new Time(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
}
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
/**
|
||||
* Arrête l’édition de la cellule. Le délégué récupère ici les exceptions
|
||||
* levées et les remonte à l’utilisateur. Tant que l’édition est en erreur
|
||||
* l’édition persiste.
|
||||
*
|
||||
* @return {@code true} si l’édition s’est arrêtée.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
private JButton actionOK;
|
||||
/**
|
||||
* Bouton permettant de valider et de fermer la boîte de dialogue.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
public EditSettings() {
|
||||
settingsTabs = new ArrayList<SettingsTab>();
|
||||
settingsTabs.add(new TabGeneral());
|
||||
settingsTabs.add(new TabLook());
|
||||
settingsTabs.add(new TabHotkeys());
|
||||
settingsTabs.add(new TabHistory());
|
||||
settingsTabs.add(new TabComponents());
|
||||
|
||||
createResources();
|
||||
placeComponents();
|
||||
setPersistentBehavior();
|
||||
|
||||
LocaleDelegate.addLocaleListener(this);
|
||||
}
|
||||
|
||||
@Override public void localeChanged(LocaleEvent event) {
|
||||
/**
|
||||
* Construction d’une boîte de dialogue d’édition de paramètres.
|
||||
*/
|
||||
public EditSettings() {
|
||||
settingsTabs = new ArrayList<SettingsTab>();
|
||||
settingsTabs.add(new TabGeneral());
|
||||
settingsTabs.add(new TabLook());
|
||||
settingsTabs.add(new TabHotkeys());
|
||||
settingsTabs.add(new TabHistory());
|
||||
settingsTabs.add(new TabComponents());
|
||||
|
||||
createResources();
|
||||
placeComponents();
|
||||
setPersistentBehavior();
|
||||
|
||||
LocaleDelegate.addLocaleListener(this);
|
||||
}
|
||||
|
||||
@Override public void localeChanged(LocaleEvent event) {
|
||||
// for (SettingsTab tab : settingsTabs) {
|
||||
// tab.processLocaleEvent(event);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
// MÉTHODES
|
||||
// MÉTHODES
|
||||
|
||||
/**
|
||||
* Instanciation des sous-composants utilisés par cette boîte de dialogue.
|
||||
*/
|
||||
private void createResources() {
|
||||
reset = new JButton("" + Language.setting_hotkey_reset);
|
||||
actionOK = new JButton(Language.ACCEPT.get());
|
||||
}
|
||||
/**
|
||||
* Instanciation des sous-composants utilisés par cette boîte de dialogue.
|
||||
*/
|
||||
private void createResources() {
|
||||
reset = new JButton("" + Language.setting_hotkey_reset);
|
||||
actionOK = new JButton(Language.ACCEPT.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* simplifié par la classe-proxy {@link GBC}.
|
||||
*/
|
||||
private void placeComponents() {
|
||||
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));
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
* simplifié par la classe-proxy {@link GBC}.
|
||||
*/
|
||||
private void placeComponents() {
|
||||
setLayout(new GridBagLayout());
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* signifie pour nous que l’utilisateur à effectuer un réglage de paramètre.
|
||||
*
|
||||
* @param evt - l’évènement d’action.
|
||||
* @see ActionListener
|
||||
*/
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Object source = e.getSource();
|
||||
if (source.equals(actionOK)) {
|
||||
for (SettingsTab tab : settingsTabs) {
|
||||
tab.doDelayedSettingChange();
|
||||
}
|
||||
dispose();
|
||||
} else if (source.equals(reset)) {
|
||||
int option = JOptionPane.showConfirmDialog(this,
|
||||
"" + Language.WARN_RESET_SETTINGS);
|
||||
if (option == JOptionPane.YES_OPTION) {
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param evt - l’évènement d’action.
|
||||
* @see ActionListener
|
||||
*/
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
Object source = e.getSource();
|
||||
if (source.equals(actionOK)) {
|
||||
for (SettingsTab tab : settingsTabs) {
|
||||
tab.doDelayedSettingChange();
|
||||
}
|
||||
dispose();
|
||||
} else if (source.equals(reset)) {
|
||||
int option = JOptionPane.showConfirmDialog(this,
|
||||
"" + Language.WARN_RESET_SETTINGS);
|
||||
if (option == JOptionPane.YES_OPTION) {
|
||||
// Settings.reset();
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override public void windowActivated(WindowEvent e) {}
|
||||
@Override public void windowClosed(WindowEvent e) {}
|
||||
@Override public void windowDeactivated(WindowEvent e) {}
|
||||
@Override public void windowDeiconified(WindowEvent e) {}
|
||||
@Override public void windowIconified(WindowEvent e) {}
|
||||
@Override public void windowOpened(WindowEvent e) {}
|
||||
|
||||
@Override public void windowClosing(WindowEvent e) {
|
||||
for (SettingsTab tab : settingsTabs) {
|
||||
tab.doDelayedSettingChange();
|
||||
}
|
||||
dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void windowActivated(WindowEvent e) {}
|
||||
@Override public void windowClosed(WindowEvent e) {}
|
||||
@Override public void windowDeactivated(WindowEvent e) {}
|
||||
@Override public void windowDeiconified(WindowEvent e) {}
|
||||
@Override public void windowIconified(WindowEvent e) {}
|
||||
@Override public void windowOpened(WindowEvent e) {}
|
||||
|
||||
@Override public void windowClosing(WindowEvent e) {
|
||||
for (SettingsTab tab : settingsTabs) {
|
||||
tab.doDelayedSettingChange();
|
||||
}
|
||||
dispose();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package org.fenix.llanfair.dialog;
|
||||
|
||||
import org.fenix.llanfair.Llanfair;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
|
||||
import javax.swing.JDialog;
|
||||
|
||||
import org.fenix.llanfair.Llanfair;
|
||||
|
||||
/**
|
||||
* LlanfairDialog
|
||||
*
|
||||
|
@ -15,22 +14,22 @@ import org.fenix.llanfair.Llanfair;
|
|||
*/
|
||||
public class LlanfairDialog extends JDialog {
|
||||
|
||||
// ATTRIBUTS
|
||||
|
||||
public void display(boolean lockNativeInputs, final Llanfair llanfair) {
|
||||
if (lockNativeInputs) {
|
||||
llanfair.setIgnoreNativeInputs(true);
|
||||
addWindowListener(new WindowAdapter() {
|
||||
@Override public void windowClosed(WindowEvent e) {
|
||||
llanfair.setIgnoreNativeInputs(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
setAlwaysOnTop(true);
|
||||
setModalityType(ModalityType.APPLICATION_MODAL);
|
||||
pack();
|
||||
setLocationRelativeTo(getOwner());
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
// ATTRIBUTS
|
||||
|
||||
public void display(boolean lockNativeInputs, final Llanfair llanfair) {
|
||||
if (lockNativeInputs) {
|
||||
llanfair.setIgnoreNativeInputs(true);
|
||||
addWindowListener(new WindowAdapter() {
|
||||
@Override public void windowClosed(WindowEvent e) {
|
||||
llanfair.setIgnoreNativeInputs(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
setAlwaysOnTop(true);
|
||||
setModalityType(ModalityType.APPLICATION_MODAL);
|
||||
pack();
|
||||
setLocationRelativeTo(getOwner());
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,43 +1,43 @@
|
|||
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.util.HashMap;
|
||||
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
|
||||
*/
|
||||
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) {
|
||||
super.itemStateChanged(e);
|
||||
setting.set(isSelected());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
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) {
|
||||
super.itemStateChanged(e);
|
||||
setting.set(isSelected());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,242 +1,232 @@
|
|||
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.Segment;
|
||||
import org.fenix.llanfair.config.Settings;
|
||||
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
|
||||
*/
|
||||
public class TabComponents extends SettingsTab
|
||||
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);
|
||||
implements ActionListener, ChangeListener {
|
||||
|
||||
GraphicsEnvironment gEnv = GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment();
|
||||
String mainFont = Settings.COR_TFNT.get().getName();
|
||||
timerFont = new JComboBox(gEnv.getAvailableFontFamilyNames());
|
||||
timerFont.setSelectedItem(mainFont);
|
||||
timerFont.setPreferredSize(new Dimension(130, 22));
|
||||
timerFont.addActionListener(this);
|
||||
|
||||
String segFont = Settings.COR_SFNT.get().getName();
|
||||
timerSegFont = new JComboBox(gEnv.getAvailableFontFamilyNames());
|
||||
timerSegFont.setSelectedItem(segFont);
|
||||
timerSegFont.setPreferredSize(new Dimension(130, 22));
|
||||
timerSegFont.addActionListener(this);
|
||||
|
||||
timerSize = new JSpinner(new SpinnerNumberModel(
|
||||
Settings.COR_TFNT.get().getSize(), 8, 240, 1)
|
||||
);
|
||||
timerSize.addChangeListener(this);
|
||||
|
||||
timerSegSize = new JSpinner(new SpinnerNumberModel(
|
||||
Settings.COR_SFNT.get().getSize(), 8, 240, 1)
|
||||
);
|
||||
timerSegSize.addChangeListener(this);
|
||||
|
||||
timerSameFont = new JCheckBox("" + Language.USE_MAIN_FONT);
|
||||
timerSameFont.setSelected(segFont.equals(mainFont));
|
||||
timerSegFont.setEnabled(!timerSameFont.isSelected());
|
||||
timerSameFont.addActionListener(this);
|
||||
|
||||
place();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- CALLBACKS
|
||||
|
||||
@Override public void actionPerformed(ActionEvent event) {
|
||||
Object source = event.getSource();
|
||||
if (source.equals(iconSizes)) {
|
||||
Settings.COR_ICSZ.set((Integer) iconSizes.getSelectedItem());
|
||||
} else if (source.equals(timerFont)) {
|
||||
String fontName = timerFont.getSelectedItem().toString();
|
||||
Font font = Font.decode(fontName).deriveFont(
|
||||
(float) Settings.COR_TFNT.get().getSize()
|
||||
);
|
||||
Settings.COR_TFNT.set(font);
|
||||
if (timerSameFont.isSelected()) {
|
||||
timerSegFont.setSelectedItem(fontName);
|
||||
}
|
||||
} else if (source.equals(timerSegFont)) {
|
||||
String fontName = timerSegFont.getSelectedItem().toString();
|
||||
Font font = Font.decode(fontName).deriveFont(
|
||||
(float) Settings.COR_SFNT.get().getSize()
|
||||
);
|
||||
Settings.COR_SFNT.set(font);
|
||||
} else if (source.equals(timerSameFont)) {
|
||||
timerSegFont.setEnabled(!timerSameFont.isSelected());
|
||||
if (timerSameFont.isSelected()) {
|
||||
int size = (Integer) timerSegSize.getValue();
|
||||
Settings.COR_SFNT.set(
|
||||
Settings.COR_TFNT.get().deriveFont((float) size)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void stateChanged(ChangeEvent event) {
|
||||
Object source = event.getSource();
|
||||
if (source.equals(timerSize)) {
|
||||
int size = (Integer) timerSize.getValue();
|
||||
Settings.COR_TFNT.set(
|
||||
Settings.COR_TFNT.get().deriveFont((float) size)
|
||||
);
|
||||
} else if (source.equals(timerSegSize)) {
|
||||
int size = (Integer) timerSegSize.getValue();
|
||||
Settings.COR_SFNT.set(
|
||||
Settings.COR_SFNT.get().deriveFont((float) size)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- INHERITED
|
||||
|
||||
@Override void doDelayedSettingChange() {}
|
||||
|
||||
@Override public String toString() {
|
||||
return "" + Language.COMPONENTS;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- UTILITIES
|
||||
|
||||
private void place() {
|
||||
setLayout(new GridBagLayout());
|
||||
|
||||
JPanel fontPanel = new JPanel(new GridBagLayout()); {
|
||||
fontPanel.add(
|
||||
new JLabel("" + Language.setting_core_timerFont),
|
||||
GBC.grid(0, 0).anchor(GBC.LS).insets(0, 5)
|
||||
);
|
||||
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));
|
||||
}
|
||||
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
|
||||
.getLocalGraphicsEnvironment();
|
||||
String mainFont = Settings.COR_TFNT.get().getName();
|
||||
timerFont = new JComboBox(gEnv.getAvailableFontFamilyNames());
|
||||
timerFont.setSelectedItem(mainFont);
|
||||
timerFont.setPreferredSize(new Dimension(130, 22));
|
||||
timerFont.addActionListener(this);
|
||||
|
||||
String segFont = Settings.COR_SFNT.get().getName();
|
||||
timerSegFont = new JComboBox(gEnv.getAvailableFontFamilyNames());
|
||||
timerSegFont.setSelectedItem(segFont);
|
||||
timerSegFont.setPreferredSize(new Dimension(130, 22));
|
||||
timerSegFont.addActionListener(this);
|
||||
|
||||
timerSize = new JSpinner(new SpinnerNumberModel(
|
||||
Settings.COR_TFNT.get().getSize(), 8, 240, 1)
|
||||
);
|
||||
timerSize.addChangeListener(this);
|
||||
|
||||
timerSegSize = new JSpinner(new SpinnerNumberModel(
|
||||
Settings.COR_SFNT.get().getSize(), 8, 240, 1)
|
||||
);
|
||||
timerSegSize.addChangeListener(this);
|
||||
|
||||
timerSameFont = new JCheckBox("" + Language.USE_MAIN_FONT);
|
||||
timerSameFont.setSelected(segFont.equals(mainFont));
|
||||
timerSegFont.setEnabled(!timerSameFont.isSelected());
|
||||
timerSameFont.addActionListener(this);
|
||||
|
||||
place();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- CALLBACKS
|
||||
|
||||
@Override public void actionPerformed(ActionEvent event) {
|
||||
Object source = event.getSource();
|
||||
if (source.equals(iconSizes)) {
|
||||
Settings.COR_ICSZ.set((Integer) iconSizes.getSelectedItem());
|
||||
} else if (source.equals(timerFont)) {
|
||||
String fontName = timerFont.getSelectedItem().toString();
|
||||
Font font = Font.decode(fontName).deriveFont(
|
||||
(float) Settings.COR_TFNT.get().getSize()
|
||||
);
|
||||
Settings.COR_TFNT.set(font);
|
||||
if (timerSameFont.isSelected()) {
|
||||
timerSegFont.setSelectedItem(fontName);
|
||||
}
|
||||
} else if (source.equals(timerSegFont)) {
|
||||
String fontName = timerSegFont.getSelectedItem().toString();
|
||||
Font font = Font.decode(fontName).deriveFont(
|
||||
(float) Settings.COR_SFNT.get().getSize()
|
||||
);
|
||||
Settings.COR_SFNT.set(font);
|
||||
} else if (source.equals(timerSameFont)) {
|
||||
timerSegFont.setEnabled(!timerSameFont.isSelected());
|
||||
if (timerSameFont.isSelected()) {
|
||||
int size = (Integer) timerSegSize.getValue();
|
||||
Settings.COR_SFNT.set(
|
||||
Settings.COR_TFNT.get().deriveFont((float) size)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void stateChanged(ChangeEvent event) {
|
||||
Object source = event.getSource();
|
||||
if (source.equals(timerSize)) {
|
||||
int size = (Integer) timerSize.getValue();
|
||||
Settings.COR_TFNT.set(
|
||||
Settings.COR_TFNT.get().deriveFont((float) size)
|
||||
);
|
||||
} else if (source.equals(timerSegSize)) {
|
||||
int size = (Integer) timerSegSize.getValue();
|
||||
Settings.COR_SFNT.set(
|
||||
Settings.COR_SFNT.get().deriveFont((float) size)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- INHERITED
|
||||
|
||||
@Override void doDelayedSettingChange() {}
|
||||
|
||||
@Override public String toString() {
|
||||
return "" + Language.COMPONENTS;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- UTILITIES
|
||||
|
||||
private void place() {
|
||||
setLayout(new GridBagLayout());
|
||||
|
||||
JPanel fontPanel = new JPanel(new GridBagLayout()); {
|
||||
fontPanel.add(
|
||||
new JLabel("" + Language.setting_core_timerFont),
|
||||
GBC.grid(0, 0).anchor(GBC.LS).insets(0, 5)
|
||||
);
|
||||
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;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.GridLayout;
|
||||
import org.fenix.llanfair.Language;
|
||||
import org.fenix.llanfair.Llanfair;
|
||||
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.ActionListener;
|
||||
import java.util.Enumeration;
|
||||
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
|
||||
*/
|
||||
public class TabGeneral extends SettingsTab implements ActionListener {
|
||||
|
||||
// ------------------------------------------------------------- ATTRIBUTES
|
||||
|
||||
private JComboBox language;
|
||||
|
||||
private JLabel languageText;
|
||||
|
||||
private JCheckBox alwaysOnTop;
|
||||
|
||||
private JLabel alwaysOnTopText;
|
||||
|
||||
private ButtonGroup compare;
|
||||
|
||||
private JLabel compareText;
|
||||
|
||||
private ButtonGroup accuracy;
|
||||
|
||||
private JLabel accuracyText;
|
||||
|
||||
private JCheckBox warnOnReset;
|
||||
|
||||
// ----------------------------------------------------------- CONSTRUCTORS
|
||||
|
||||
TabGeneral() {
|
||||
language = new JComboBox(Language.LANGUAGES);
|
||||
language.setRenderer(new LocaleListRenderer());
|
||||
language.setSelectedItem(Settings.GNR_LANG.get());
|
||||
language.addActionListener(this);
|
||||
|
||||
alwaysOnTop = new JCheckBox("" + Language.setting_alwaysOnTop);
|
||||
alwaysOnTop.setSelected(Settings.GNR_ATOP.get());
|
||||
|
||||
compare = new ButtonGroup();
|
||||
Compare setCmp = Settings.GNR_COMP.get();
|
||||
for (Compare method : Compare.values()) {
|
||||
JRadioButton radio = new JRadioButton("" + method);
|
||||
radio.setName(method.name());
|
||||
radio.setSelected(setCmp == method);
|
||||
radio.addActionListener(this);
|
||||
compare.add(radio);
|
||||
}
|
||||
|
||||
accuracy = new ButtonGroup();
|
||||
Accuracy setAcc = Settings.GNR_ACCY.get();
|
||||
for (Accuracy value : Accuracy.values()) {
|
||||
JRadioButton radio = new JRadioButton("" + value);
|
||||
radio.setName(value.name());
|
||||
radio.setSelected(setAcc == value);
|
||||
radio.addActionListener(this);
|
||||
accuracy.add(radio);
|
||||
}
|
||||
|
||||
warnOnReset = new JCheckBox("" + Language.setting_warnOnReset);
|
||||
warnOnReset.setSelected(Settings.GNR_WARN.get());
|
||||
warnOnReset.addActionListener(this);
|
||||
|
||||
languageText = new JLabel("" + Language.setting_language);
|
||||
alwaysOnTopText = new JLabel("" + Language.APPLICATION);
|
||||
compareText = new JLabel("" + Language.COMPARE_METHOD);
|
||||
accuracyText = new JLabel("" + Language.ACCURACY);
|
||||
|
||||
place();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- CALLBACKS
|
||||
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
Object source = event.getSource();
|
||||
if (source.equals(language)) {
|
||||
Settings.GNR_LANG.set((Locale) language.getSelectedItem());
|
||||
} else if (source instanceof JRadioButton) {
|
||||
JRadioButton radio = (JRadioButton) source;
|
||||
try {
|
||||
Settings.GNR_COMP.set(
|
||||
Compare.valueOf(radio.getName())
|
||||
);
|
||||
} catch (Exception e) {
|
||||
Settings.GNR_ACCY.set(Accuracy.valueOf(radio.getName()));
|
||||
}
|
||||
} else if (source.equals(warnOnReset)) {
|
||||
Settings.GNR_WARN.set(warnOnReset.isSelected());
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- INHERITED
|
||||
|
||||
void doDelayedSettingChange() {
|
||||
Settings.GNR_ATOP.set(alwaysOnTop.isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the localized name of this tab.
|
||||
*/
|
||||
@Override public String toString() {
|
||||
return "" + Language.GENERAL;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- UTILITIES
|
||||
|
||||
/**
|
||||
* Places all sub-components within this panel.
|
||||
*/
|
||||
private void place() {
|
||||
setLayout(new GridBagLayout());
|
||||
|
||||
add(
|
||||
alwaysOnTopText, GBC.grid(0, 0).anchor(GBC.LE).insets(5, 10)
|
||||
);
|
||||
add(alwaysOnTop, GBC.grid(1, 0).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(language, GBC.grid(1, 2).fill(GBC.H));
|
||||
|
||||
JPanel comparePanel = new JPanel(new GridLayout(0, 1)); {
|
||||
Enumeration<AbstractButton> buttons = compare.getElements();
|
||||
while (buttons.hasMoreElements()) {
|
||||
comparePanel.add(buttons.nextElement());
|
||||
}
|
||||
}
|
||||
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));
|
||||
|
||||
JPanel accuracyPanel = new JPanel(new GridLayout(0, 1)); {
|
||||
Enumeration<AbstractButton> buttons = accuracy.getElements();
|
||||
while (buttons.hasMoreElements()) {
|
||||
accuracyPanel.add(buttons.nextElement());
|
||||
}
|
||||
}
|
||||
add(accuracyText, GBC.grid(0, 4).anchor(GBC.FLE).insets(14, 10));
|
||||
add(accuracyPanel, GBC.grid(1, 4).fill(GBC.H).insets(10, 0));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------- INTERNAL TYPES
|
||||
|
||||
class LocaleListRenderer extends DefaultListCellRenderer {
|
||||
|
||||
public LocaleListRenderer() {
|
||||
setVerticalAlignment(CENTER);
|
||||
}
|
||||
|
||||
@Override public Component getListCellRendererComponent(
|
||||
JList list, Object value, int index, boolean isSelected,
|
||||
boolean cellHasFocus
|
||||
) {
|
||||
super.getListCellRendererComponent(
|
||||
list, value, index, isSelected, cellHasFocus
|
||||
);
|
||||
Locale selected = (Locale) value;
|
||||
|
||||
setIcon(Llanfair.getResources().getIcon("" + selected));
|
||||
setText(Language.LOCALE_NAMES.get("" + selected));
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------- ATTRIBUTES
|
||||
|
||||
private JComboBox language;
|
||||
|
||||
private JLabel languageText;
|
||||
|
||||
private JCheckBox alwaysOnTop;
|
||||
|
||||
private JLabel alwaysOnTopText;
|
||||
|
||||
private ButtonGroup compare;
|
||||
|
||||
private JLabel compareText;
|
||||
|
||||
private ButtonGroup accuracy;
|
||||
|
||||
private JLabel accuracyText;
|
||||
|
||||
private JCheckBox warnOnReset;
|
||||
|
||||
// ----------------------------------------------------------- CONSTRUCTORS
|
||||
|
||||
TabGeneral() {
|
||||
language = new JComboBox(Language.LANGUAGES);
|
||||
language.setRenderer(new LocaleListRenderer());
|
||||
language.setSelectedItem(Settings.GNR_LANG.get());
|
||||
language.addActionListener(this);
|
||||
|
||||
alwaysOnTop = new JCheckBox("" + Language.setting_alwaysOnTop);
|
||||
alwaysOnTop.setSelected(Settings.GNR_ATOP.get());
|
||||
|
||||
compare = new ButtonGroup();
|
||||
Compare setCmp = Settings.GNR_COMP.get();
|
||||
for (Compare method : Compare.values()) {
|
||||
JRadioButton radio = new JRadioButton("" + method);
|
||||
radio.setName(method.name());
|
||||
radio.setSelected(setCmp == method);
|
||||
radio.addActionListener(this);
|
||||
compare.add(radio);
|
||||
}
|
||||
|
||||
accuracy = new ButtonGroup();
|
||||
Accuracy setAcc = Settings.GNR_ACCY.get();
|
||||
for (Accuracy value : Accuracy.values()) {
|
||||
JRadioButton radio = new JRadioButton("" + value);
|
||||
radio.setName(value.name());
|
||||
radio.setSelected(setAcc == value);
|
||||
radio.addActionListener(this);
|
||||
accuracy.add(radio);
|
||||
}
|
||||
|
||||
warnOnReset = new JCheckBox("" + Language.setting_warnOnReset);
|
||||
warnOnReset.setSelected(Settings.GNR_WARN.get());
|
||||
warnOnReset.addActionListener(this);
|
||||
|
||||
languageText = new JLabel("" + Language.setting_language);
|
||||
alwaysOnTopText = new JLabel("" + Language.APPLICATION);
|
||||
compareText = new JLabel("" + Language.COMPARE_METHOD);
|
||||
accuracyText = new JLabel("" + Language.ACCURACY);
|
||||
|
||||
place();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- CALLBACKS
|
||||
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
Object source = event.getSource();
|
||||
if (source.equals(language)) {
|
||||
Settings.GNR_LANG.set((Locale) language.getSelectedItem());
|
||||
} else if (source instanceof JRadioButton) {
|
||||
JRadioButton radio = (JRadioButton) source;
|
||||
try {
|
||||
Settings.GNR_COMP.set(
|
||||
Compare.valueOf(radio.getName())
|
||||
);
|
||||
} catch (Exception e) {
|
||||
Settings.GNR_ACCY.set(Accuracy.valueOf(radio.getName()));
|
||||
}
|
||||
} else if (source.equals(warnOnReset)) {
|
||||
Settings.GNR_WARN.set(warnOnReset.isSelected());
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- INHERITED
|
||||
|
||||
void doDelayedSettingChange() {
|
||||
Settings.GNR_ATOP.set(alwaysOnTop.isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the localized name of this tab.
|
||||
*/
|
||||
@Override public String toString() {
|
||||
return "" + Language.GENERAL;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- UTILITIES
|
||||
|
||||
/**
|
||||
* Places all sub-components within this panel.
|
||||
*/
|
||||
private void place() {
|
||||
setLayout(new GridBagLayout());
|
||||
|
||||
add(
|
||||
alwaysOnTopText, GBC.grid(0, 0).anchor(GBC.LE).insets(5, 10)
|
||||
);
|
||||
add(alwaysOnTop, GBC.grid(1, 0).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(language, GBC.grid(1, 2).fill(GBC.H));
|
||||
|
||||
JPanel comparePanel = new JPanel(new GridLayout(0, 1)); {
|
||||
Enumeration<AbstractButton> buttons = compare.getElements();
|
||||
while (buttons.hasMoreElements()) {
|
||||
comparePanel.add(buttons.nextElement());
|
||||
}
|
||||
}
|
||||
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));
|
||||
|
||||
JPanel accuracyPanel = new JPanel(new GridLayout(0, 1)); {
|
||||
Enumeration<AbstractButton> buttons = accuracy.getElements();
|
||||
while (buttons.hasMoreElements()) {
|
||||
accuracyPanel.add(buttons.nextElement());
|
||||
}
|
||||
}
|
||||
add(accuracyText, GBC.grid(0, 4).anchor(GBC.FLE).insets(14, 10));
|
||||
add(accuracyPanel, GBC.grid(1, 4).fill(GBC.H).insets(10, 0));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------- INTERNAL TYPES
|
||||
|
||||
class LocaleListRenderer extends DefaultListCellRenderer {
|
||||
|
||||
public LocaleListRenderer() {
|
||||
setVerticalAlignment(CENTER);
|
||||
}
|
||||
|
||||
@Override public Component getListCellRendererComponent(
|
||||
JList list, Object value, int index, boolean isSelected,
|
||||
boolean cellHasFocus
|
||||
) {
|
||||
super.getListCellRendererComponent(
|
||||
list, value, index, isSelected, cellHasFocus
|
||||
);
|
||||
Locale selected = (Locale) value;
|
||||
|
||||
setIcon(Llanfair.getResources().getIcon("" + selected));
|
||||
setText(Language.LOCALE_NAMES.get("" + selected));
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,348 +1,337 @@
|
|||
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.Segment;
|
||||
import org.fenix.llanfair.config.Settings;
|
||||
import org.fenix.llanfair.config.Merge;
|
||||
import org.fenix.llanfair.config.Settings;
|
||||
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 {
|
||||
|
||||
// ------------------------------------------------------------- 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();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- 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
|
||||
// ------------------------------------------------------------- ATTRIBUTES
|
||||
|
||||
@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));
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- 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(merge , GBC.grid(0, 4).anchor(GBC.LS));
|
||||
display.setBorder(
|
||||
BorderFactory.createTitledBorder("" + Language.PN_DISPLAY)
|
||||
);
|
||||
}
|
||||
// Dimension
|
||||
JPanel dimension = new JPanel(new GridBagLayout()); {
|
||||
dimension.add(
|
||||
new JLabel("" + Language.setting_history_iconSize),
|
||||
GBC.grid(0, 0).anchor(GBC.LE)
|
||||
);
|
||||
dimension.add(iconSize, GBC.grid(1, 0).anchor(GBC.LE).insets(2, 3));
|
||||
dimension.add(
|
||||
new JLabel("" + Language.setting_history_rowCount),
|
||||
GBC.grid(0, 1).anchor(GBC.LE)
|
||||
);
|
||||
dimension.add(
|
||||
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(
|
||||
twoLines , GBC.grid(0, 3, 2, 1).anchor(GBC.LE).insets(0, 1)
|
||||
);
|
||||
dimension.setBorder(
|
||||
BorderFactory.createTitledBorder("" + Language.PN_DIMENSION)
|
||||
);
|
||||
}
|
||||
// Fonts
|
||||
JPanel fonts = new JPanel(new GridBagLayout()); {
|
||||
fonts.add(
|
||||
new JLabel("" + Language.setting_history_segmentFont),
|
||||
GBC.grid(0, 0).anchor(GBC.LE)
|
||||
);
|
||||
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(
|
||||
new JLabel("" + Language.setting_history_timeFont),
|
||||
GBC.grid(0, 1).anchor(GBC.LE)
|
||||
);
|
||||
fonts.add(timeFont, GBC.grid(1, 1).anchor(GBC.LS).insets(5, 5));
|
||||
fonts.add(timeSize, GBC.grid(2, 1).anchor(GBC.LS));
|
||||
fonts.setBorder(
|
||||
BorderFactory.createTitledBorder("" + Language.PN_FONTS)
|
||||
);
|
||||
}
|
||||
// Scrolling
|
||||
JPanel scrolling = new JPanel(new GridBagLayout()); {
|
||||
scrolling.add(
|
||||
offsetHelper, GBC.grid(0, 0).anchor(GBC.LE).insets(0, 8)
|
||||
);
|
||||
scrolling.add(
|
||||
new JLabel("" + Language.setting_history_offset),
|
||||
GBC.grid(1, 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.setBorder(
|
||||
BorderFactory.createTitledBorder("" + Language.PN_SCROLLING)
|
||||
);
|
||||
}
|
||||
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(display , GBC.grid(0, 1).fill(GBC.B).padding(10, 10));
|
||||
add(scrolling, GBC.grid(1, 1).fill(GBC.B).padding(10, 10));
|
||||
}
|
||||
display.add(merge , GBC.grid(0, 4).anchor(GBC.LS));
|
||||
display.setBorder(
|
||||
BorderFactory.createTitledBorder("" + Language.PN_DISPLAY)
|
||||
);
|
||||
}
|
||||
// Dimension
|
||||
JPanel dimension = new JPanel(new GridBagLayout()); {
|
||||
dimension.add(
|
||||
new JLabel("" + Language.setting_history_iconSize),
|
||||
GBC.grid(0, 0).anchor(GBC.LE)
|
||||
);
|
||||
dimension.add(iconSize, GBC.grid(1, 0).anchor(GBC.LE).insets(2, 3));
|
||||
dimension.add(
|
||||
new JLabel("" + Language.setting_history_rowCount),
|
||||
GBC.grid(0, 1).anchor(GBC.LE)
|
||||
);
|
||||
dimension.add(
|
||||
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(
|
||||
twoLines , GBC.grid(0, 3, 2, 1).anchor(GBC.LE).insets(0, 1)
|
||||
);
|
||||
dimension.setBorder(
|
||||
BorderFactory.createTitledBorder("" + Language.PN_DIMENSION)
|
||||
);
|
||||
}
|
||||
// Fonts
|
||||
JPanel fonts = new JPanel(new GridBagLayout()); {
|
||||
fonts.add(
|
||||
new JLabel("" + Language.setting_history_segmentFont),
|
||||
GBC.grid(0, 0).anchor(GBC.LE)
|
||||
);
|
||||
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(
|
||||
new JLabel("" + Language.setting_history_timeFont),
|
||||
GBC.grid(0, 1).anchor(GBC.LE)
|
||||
);
|
||||
fonts.add(timeFont, GBC.grid(1, 1).anchor(GBC.LS).insets(5, 5));
|
||||
fonts.add(timeSize, GBC.grid(2, 1).anchor(GBC.LS));
|
||||
fonts.setBorder(
|
||||
BorderFactory.createTitledBorder("" + Language.PN_FONTS)
|
||||
);
|
||||
}
|
||||
// Scrolling
|
||||
JPanel scrolling = new JPanel(new GridBagLayout()); {
|
||||
scrolling.add(
|
||||
offsetHelper, GBC.grid(0, 0).anchor(GBC.LE).insets(0, 8)
|
||||
);
|
||||
scrolling.add(
|
||||
new JLabel("" + Language.setting_history_offset),
|
||||
GBC.grid(1, 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.setBorder(
|
||||
BorderFactory.createTitledBorder("" + Language.PN_SCROLLING)
|
||||
);
|
||||
}
|
||||
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(display , GBC.grid(0, 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;
|
||||
|
||||
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.config.Settings;
|
||||
import org.fenix.utils.gui.GBC;
|
||||
|
@ -18,194 +7,201 @@ import org.jnativehook.GlobalScreen;
|
|||
import org.jnativehook.keyboard.NativeKeyEvent;
|
||||
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
|
||||
*/
|
||||
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
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
// ------------------------------------------------------------- ATTRIBUTES
|
||||
|
||||
// ----------------------------------------------------- CONSTANTS
|
||||
|
||||
/**
|
||||
* Preferred dimension of a text field.
|
||||
*/
|
||||
private static final Dimension SIZE = new Dimension(85, 20);
|
||||
|
||||
// ---------------------------------------------------- ATTRIBUTES
|
||||
|
||||
private static boolean isEditing = false;
|
||||
|
||||
/**
|
||||
* Internal index of this field, used by the superclass.
|
||||
*/
|
||||
private int index;
|
||||
|
||||
/**
|
||||
* Setting represented by this key field.
|
||||
*/
|
||||
private Settings.Property<Integer> setting;
|
||||
|
||||
// -------------------------------------------------- CONSTRUCTORS
|
||||
|
||||
/**
|
||||
* Creates a new key field for the given setting. Only called by
|
||||
* {@link TabHotkeys}.
|
||||
*
|
||||
* @param index - internal index to identify this field.
|
||||
* @param setting - setting represented by this field.
|
||||
*/
|
||||
KeyField(int index, Settings.Property<Integer> setting) {
|
||||
this.index = index;
|
||||
this.setting = setting;
|
||||
|
||||
setEditable(false);
|
||||
setName(setting.getKey());
|
||||
setPreferredSize(SIZE);
|
||||
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) {}
|
||||
|
||||
}
|
||||
/**
|
||||
* 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
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
/**
|
||||
* Preferred dimension of a text field.
|
||||
*/
|
||||
private static final Dimension SIZE = new Dimension(85, 20);
|
||||
|
||||
// ---------------------------------------------------- ATTRIBUTES
|
||||
|
||||
private static boolean isEditing = false;
|
||||
|
||||
/**
|
||||
* Internal index of this field, used by the superclass.
|
||||
*/
|
||||
private int index;
|
||||
|
||||
/**
|
||||
* Setting represented by this key field.
|
||||
*/
|
||||
private Settings.Property<Integer> setting;
|
||||
|
||||
// -------------------------------------------------- CONSTRUCTORS
|
||||
|
||||
/**
|
||||
* Creates a new key field for the given setting. Only called by
|
||||
* {@link TabHotkeys}.
|
||||
*
|
||||
* @param index - internal index to identify this field.
|
||||
* @param setting - setting represented by this field.
|
||||
*/
|
||||
KeyField(int index, Settings.Property<Integer> setting) {
|
||||
this.index = index;
|
||||
this.setting = setting;
|
||||
|
||||
setEditable(false);
|
||||
setName(setting.getKey());
|
||||
setPreferredSize(SIZE);
|
||||
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
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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>();
|
||||
// -------------------------------------------------------------- CONSTANTS
|
||||
|
||||
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> {
|
||||
/**
|
||||
* Dimension of the revert button.
|
||||
*/
|
||||
private static final Dimension REVERT_SIZE = new Dimension(18, 18);
|
||||
|
||||
// ---------------------------------------------------- ATTRIBUTES
|
||||
|
||||
/**
|
||||
* Index of this color button in the englobing model.
|
||||
*/
|
||||
private int index;
|
||||
// ------------------------------------------------------------- ATTRIBUTES
|
||||
|
||||
/**
|
||||
* 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
|
||||
/**
|
||||
* List of all color buttons, inserted in the order of their name.
|
||||
*/
|
||||
private List<ColorButton> colorButtons;
|
||||
|
||||
/**
|
||||
* 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());
|
||||
}
|
||||
/**
|
||||
* List of labels displaying the name of the color button.
|
||||
*/
|
||||
private List<JLabel> colorTexts;
|
||||
|
||||
// ------------------------------------------------------- GETTERS
|
||||
/**
|
||||
* Panel allowing the user to select a color.
|
||||
*/
|
||||
private JColorChooser colorChooser;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
/**
|
||||
* The index of the currently selected color button. Any color change will
|
||||
* be made to this button.
|
||||
*/
|
||||
private int selected;
|
||||
|
||||
// ------------------------------------------------------- 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
|
||||
* 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());
|
||||
}
|
||||
/**
|
||||
* Panel listing the color buttons and their name label.
|
||||
*/
|
||||
private JPanel colorPanel;
|
||||
|
||||
/**
|
||||
* 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());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 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")) {
|
||||
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;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import javax.swing.ImageIcon;
|
||||
import org.fenix.llanfair.Llanfair;
|
||||
import org.fenix.llanfair.Run;
|
||||
import org.fenix.llanfair.Segment;
|
||||
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.
|
||||
*
|
||||
|
@ -15,95 +16,95 @@ import org.fenix.llanfair.Time;
|
|||
* @version 1.1
|
||||
*/
|
||||
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(
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(
|
||||
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 {
|
||||
|
||||
private static final int ALL = 0xff;
|
||||
private static final int TIME = 0x01;
|
||||
private static final int DELTA = 0x02;
|
||||
private static final int TEXT = 0x04;
|
||||
private static final int BEST = 0x08;
|
||||
private static final int VERBOSE = 0x10;
|
||||
|
||||
private static final int INSET = 3;
|
||||
private static final int ALL = 0xff;
|
||||
private static final int TIME = 0x01;
|
||||
private static final int DELTA = 0x02;
|
||||
private static final int TEXT = 0x04;
|
||||
private static final int BEST = 0x08;
|
||||
private static final int VERBOSE = 0x10;
|
||||
|
||||
private static final int INSET = 3;
|
||||
|
||||
|
||||
private Run run;
|
||||
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 Run run;
|
||||
private Time tmDlta;
|
||||
|
||||
private JPanel panelBest; // labelBest + best
|
||||
private JPanel panelDeltaBest; // labelDeltaBest + deltaBest
|
||||
|
||||
private boolean resize;
|
||||
private Dimension preferredSize;
|
||||
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
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
private JLabel labelDelta; // Delta:
|
||||
private JLabel labelLive; // Live:
|
||||
private JLabel delta; // Delta Segment Set/Live Time
|
||||
|
||||
@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;
|
||||
}
|
||||
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 JPanel panelDeltaBest; // labelDeltaBest + deltaBest
|
||||
|
||||
private boolean resize;
|
||||
private Dimension preferredSize;
|
||||
|
||||
/**
|
||||
* 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 prevW = metrics.stringWidth("" + Language.LB_FT_SEGMENT);
|
||||
int bestW = metrics.stringWidth("" + Language.LB_FT_BEST);
|
||||
int dltaW = metrics.stringWidth("" + Language.LB_FT_DELTA);
|
||||
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());
|
||||
int liveW = metrics.stringWidth("" + Language.LB_FT_LIVE);
|
||||
int prevW = metrics.stringWidth("" + Language.LB_FT_SEGMENT);
|
||||
int bestW = metrics.stringWidth("" + Language.LB_FT_BEST);
|
||||
int dltaW = metrics.stringWidth("" + Language.LB_FT_DELTA);
|
||||
int dltbW = metrics.stringWidth("" + Language.LB_FT_DELTA_BEST);
|
||||
|
||||
JPanel timePanel = new JPanel(new GridBagLayout()); {
|
||||
timePanel.add(
|
||||
labelPrev,
|
||||
GBC.grid(0, 0).anchor(GBC.LS).insets(0, 0, 0, INSET)
|
||||
);
|
||||
timePanel.add(liveL, GBC.grid(1, 0).anchor(GBC.LS));
|
||||
timePanel.add(time, GBC.grid(2, 0).anchor(GBC.LS));
|
||||
timePanel.add(
|
||||
inlineBest,
|
||||
GBC.grid(3, 0).anchor(GBC.LS).insets(0, INSET, 0, 0)
|
||||
);
|
||||
timePanel.setOpaque(false);
|
||||
}
|
||||
JPanel deltaPanel = new JPanel(new GridBagLayout()); {
|
||||
deltaPanel.add(
|
||||
labelDelta,
|
||||
GBC.grid(0, 0).anchor(GBC.LE).insets(0, 0, 0, INSET)
|
||||
);
|
||||
deltaPanel.add(
|
||||
labelLive,
|
||||
GBC.grid(1, 0).anchor(GBC.LE).insets(0, 0, 0, INSET)
|
||||
);
|
||||
deltaPanel.add(
|
||||
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;
|
||||
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()); {
|
||||
timePanel.add(
|
||||
labelPrev,
|
||||
GBC.grid(0, 0).anchor(GBC.LS).insets(0, 0, 0, INSET)
|
||||
);
|
||||
timePanel.add(liveL, GBC.grid(1, 0).anchor(GBC.LS));
|
||||
timePanel.add(time, GBC.grid(2, 0).anchor(GBC.LS));
|
||||
timePanel.add(
|
||||
inlineBest,
|
||||
GBC.grid(3, 0).anchor(GBC.LS).insets(0, INSET, 0, 0)
|
||||
);
|
||||
timePanel.setOpaque(false);
|
||||
}
|
||||
JPanel deltaPanel = new JPanel(new GridBagLayout()); {
|
||||
deltaPanel.add(
|
||||
labelDelta,
|
||||
GBC.grid(0, 0).anchor(GBC.LE).insets(0, 0, 0, INSET)
|
||||
);
|
||||
deltaPanel.add(
|
||||
labelLive,
|
||||
GBC.grid(1, 0).anchor(GBC.LE).insets(0, 0, 0, INSET)
|
||||
);
|
||||
deltaPanel.add(
|
||||
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) {
|
||||
pSegment = run.getSegment(pIndex);
|
||||
}
|
||||
if ((identifier & TIME) == TIME) {
|
||||
Time set;
|
||||
if (hasPrevious) {
|
||||
if (useSplit) {
|
||||
live = run.getTime(pIndex, Segment.LIVE);
|
||||
set = run.getTime(pIndex, Segment.SET);
|
||||
} else {
|
||||
live = pSegment.getTime(Segment.LIVE);
|
||||
set = pSegment.getTime(Segment.SET);
|
||||
}
|
||||
time.setText("" + (set == null ? "--" : set));
|
||||
liveL.setText("" + (live == null ? "--" : live));
|
||||
liveR.setText(liveL.getText());
|
||||
Time bTime = pSegment.getTime(Segment.BEST);
|
||||
inlineBest.setText("| " + (bTime == null ? "--" : bTime));
|
||||
best.setText("" + (bTime == null ? "--" : bTime));
|
||||
} else {
|
||||
time.setText("");
|
||||
liveL.setText("");
|
||||
liveR.setText("");
|
||||
best.setText("");
|
||||
inlineBest.setText("");
|
||||
}
|
||||
}
|
||||
if ((identifier & DELTA) == DELTA) {
|
||||
if (hasPrevious) {
|
||||
if (useSplit) {
|
||||
tmDlta = run.getTime(pIndex, Segment.DELTA);
|
||||
live = run.getTime(pIndex, Segment.LIVE);
|
||||
|
||||
if (tmDlta == null || live == null) {
|
||||
delta.setText("--");
|
||||
} else {
|
||||
delta.setText(tmDlta.toString(true));
|
||||
}
|
||||
} else {
|
||||
tmDlta = pSegment.getTime(Segment.DELTA);
|
||||
live = pSegment.getTime(Segment.LIVE);
|
||||
Time set = pSegment.getTime(Segment.SET);
|
||||
|
||||
Time dBst = pSegment.getTime(Segment.DELTA_BEST);
|
||||
inlineDeltaBest.setText("| " + (dBst == null ? "--" : dBst.toString(true)));
|
||||
deltaBest.setText("" + (dBst == null ? "--" : dBst.toString(true)));
|
||||
|
||||
if (set != null && pIndex > 1) {
|
||||
set = set.clone();
|
||||
for (int i = pIndex - 1; i >= 0; i--) {
|
||||
Segment pSeg = run.getSegment(i);
|
||||
Time ante = pSeg.getTime(Segment.LIVE);
|
||||
if (ante == null) {
|
||||
set.add(pSeg.getTime(Segment.SET));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tmDlta = Time.getDelta(live, set);
|
||||
}
|
||||
if (tmDlta == null || live == null) {
|
||||
delta.setText("--");
|
||||
inlineDeltaBest.setText("| --");
|
||||
deltaBest.setText("--");
|
||||
} else {
|
||||
delta.setText(tmDlta.toString(true));
|
||||
}
|
||||
if (pIndex > 0) {
|
||||
Time sTime = run.getSegment(pIndex - 1)
|
||||
.getTime(Segment.SET);
|
||||
if (sTime == null) {
|
||||
delta.setText("--");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Settings.FOO_VERB.get()) {
|
||||
delta.setText("[" + delta.getText() + "]");
|
||||
}
|
||||
updateColors(DELTA);
|
||||
} else {
|
||||
delta.setText("");
|
||||
inlineDeltaBest.setText("");
|
||||
deltaBest.setText("");
|
||||
}
|
||||
}
|
||||
if ((identifier & TEXT) == TEXT) {
|
||||
if (useSplit) {
|
||||
labelPrev.setText("" + Language.LB_FT_SPLIT);
|
||||
} else {
|
||||
labelPrev.setText("" + Language.LB_FT_SEGMENT);
|
||||
}
|
||||
labelLive.setText("" + Language.LB_FT_LIVE);
|
||||
labelBest.setText("" + Language.LB_FT_BEST);
|
||||
labelDelta.setText("" + Language.LB_FT_DELTA);
|
||||
labelDeltaBest.setText("" + Language.LB_FT_DELTA_BEST);
|
||||
}
|
||||
}
|
||||
if (hasPrevious) {
|
||||
pSegment = run.getSegment(pIndex);
|
||||
}
|
||||
if ((identifier & TIME) == TIME) {
|
||||
Time set;
|
||||
if (hasPrevious) {
|
||||
if (useSplit) {
|
||||
live = run.getTime(pIndex, Segment.LIVE);
|
||||
set = run.getTime(pIndex, Segment.SET);
|
||||
} else {
|
||||
live = pSegment.getTime(Segment.LIVE);
|
||||
set = pSegment.getTime(Segment.SET);
|
||||
}
|
||||
time.setText("" + (set == null ? "--" : set));
|
||||
liveL.setText("" + (live == null ? "--" : live));
|
||||
liveR.setText(liveL.getText());
|
||||
Time bTime = pSegment.getTime(Segment.BEST);
|
||||
inlineBest.setText("| " + (bTime == null ? "--" : bTime));
|
||||
best.setText("" + (bTime == null ? "--" : bTime));
|
||||
} else {
|
||||
time.setText("");
|
||||
liveL.setText("");
|
||||
liveR.setText("");
|
||||
best.setText("");
|
||||
inlineBest.setText("");
|
||||
}
|
||||
}
|
||||
if ((identifier & DELTA) == DELTA) {
|
||||
if (hasPrevious) {
|
||||
if (useSplit) {
|
||||
tmDlta = run.getTime(pIndex, Segment.DELTA);
|
||||
live = run.getTime(pIndex, Segment.LIVE);
|
||||
|
||||
if (tmDlta == null || live == null) {
|
||||
delta.setText("--");
|
||||
} else {
|
||||
delta.setText(tmDlta.toString(true));
|
||||
}
|
||||
} else {
|
||||
tmDlta = pSegment.getTime(Segment.DELTA);
|
||||
live = pSegment.getTime(Segment.LIVE);
|
||||
Time set = pSegment.getTime(Segment.SET);
|
||||
|
||||
Time dBst = pSegment.getTime(Segment.DELTA_BEST);
|
||||
inlineDeltaBest.setText("| " + (dBst == null ? "--" : dBst.toString(true)));
|
||||
deltaBest.setText("" + (dBst == null ? "--" : dBst.toString(true)));
|
||||
|
||||
if (set != null && pIndex > 1) {
|
||||
set = set.clone();
|
||||
for (int i = pIndex - 1; i >= 0; i--) {
|
||||
Segment pSeg = run.getSegment(i);
|
||||
Time ante = pSeg.getTime(Segment.LIVE);
|
||||
if (ante == null) {
|
||||
set.add(pSeg.getTime(Segment.SET));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
tmDlta = Time.getDelta(live, set);
|
||||
}
|
||||
if (tmDlta == null || live == null) {
|
||||
delta.setText("--");
|
||||
inlineDeltaBest.setText("| --");
|
||||
deltaBest.setText("--");
|
||||
} else {
|
||||
delta.setText(tmDlta.toString(true));
|
||||
}
|
||||
if (pIndex > 0) {
|
||||
Time sTime = run.getSegment(pIndex - 1)
|
||||
.getTime(Segment.SET);
|
||||
if (sTime == null) {
|
||||
delta.setText("--");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Settings.FOO_VERB.get()) {
|
||||
delta.setText("[" + delta.getText() + "]");
|
||||
}
|
||||
updateColors(DELTA);
|
||||
} else {
|
||||
delta.setText("");
|
||||
inlineDeltaBest.setText("");
|
||||
deltaBest.setText("");
|
||||
}
|
||||
}
|
||||
if ((identifier & TEXT) == TEXT) {
|
||||
if (useSplit) {
|
||||
labelPrev.setText("" + Language.LB_FT_SPLIT);
|
||||
} else {
|
||||
labelPrev.setText("" + Language.LB_FT_SEGMENT);
|
||||
}
|
||||
labelLive.setText("" + Language.LB_FT_LIVE);
|
||||
labelBest.setText("" + Language.LB_FT_BEST);
|
||||
labelDelta.setText("" + Language.LB_FT_DELTA);
|
||||
labelDeltaBest.setText("" + Language.LB_FT_DELTA_BEST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,331 +32,331 @@ import org.fenix.utils.locale.LocaleEvent;
|
|||
*/
|
||||
class Graph extends JPanel {
|
||||
|
||||
// -------------------------------------------------------------- CONSTANTS
|
||||
// -------------------------------------------------------------- CONSTANTS
|
||||
|
||||
/**
|
||||
* 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
|
||||
* the top or the bottom of the canvas.
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
* 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
|
||||
* the top or the bottom of the canvas.
|
||||
*/
|
||||
protected static final int HALF_THICKNESS = 1;
|
||||
|
||||
// ------------------------------------------------------------- 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.
|
||||
*/
|
||||
protected Run run;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* 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 );
|
||||
|
||||
// ----------------------------------------------------------- CONSTRUCTORS
|
||||
/**
|
||||
* Update identifier for every category.
|
||||
*/
|
||||
private static final int ALL = 0xff;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
/**
|
||||
* Update identifier for text variables.
|
||||
*/
|
||||
private static final int TEXT = 0x01;
|
||||
|
||||
setRun(run);
|
||||
setOpaque(false);
|
||||
|
||||
updateValues(TEXT);
|
||||
updateColors(ALL);
|
||||
placeComponents();
|
||||
|
||||
Dimension size = new Dimension(PACK_WIDTH, PACK_HEIGHT);
|
||||
setPreferredSize(size);
|
||||
setMinimumSize(size);
|
||||
}
|
||||
/**
|
||||
* Update identifier for time variables.
|
||||
*/
|
||||
private static final int TIME = 0x02;
|
||||
|
||||
// -------------------------------------------------------------- INTERFACE
|
||||
/**
|
||||
* Minimum width in pixels of this component.
|
||||
*/
|
||||
private static final int PACK_WIDTH = 50;
|
||||
|
||||
/**
|
||||
* Sets the new run to represent.
|
||||
*
|
||||
* @param run - the new run to represent.
|
||||
*/
|
||||
void setRun(Run run) {
|
||||
this.run = run;
|
||||
updateValues(TIME);
|
||||
}
|
||||
/**
|
||||
* Minimum height in pixels of this component.
|
||||
*/
|
||||
private static final int PACK_HEIGHT = 50;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
// ------------------------------------------------------------- ATTRIBUTES
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Run instance represented by this component.
|
||||
*/
|
||||
protected Run run;
|
||||
|
||||
// ---------------------------------------------------------- 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.
|
||||
*
|
||||
* @author Xavier "Xunkar" Sencert
|
||||
*/
|
||||
protected class Canvas extends JPanel {
|
||||
|
||||
// ----------------------------------------------------- INTERFACE
|
||||
/**
|
||||
* Label displaying the current scale of the graph. The scale actually
|
||||
* displays the time represented by the maximum ordinate.
|
||||
*/
|
||||
private JLabel scale;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
/**
|
||||
* Label describing the scale value being displayed.
|
||||
*/
|
||||
private JLabel scaleText;
|
||||
|
||||
int clipH = getHeight();
|
||||
int clipW = getWidth();
|
||||
int halfH = clipH / 2;
|
||||
// ----------------------------------------------------------- CONSTRUCTORS
|
||||
|
||||
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 colorTG = Settings.CLR_GAIN.get();
|
||||
Color colorTL = Settings.CLR_LOST.get();
|
||||
Color colorRC = Settings.CLR_RCRD.get();
|
||||
Color colorFG = Settings.CLR_FORE.get();
|
||||
Color colorTG = Settings.CLR_GAIN.get();
|
||||
Color colorTL = Settings.CLR_LOST.get();
|
||||
Color colorRC = Settings.CLR_RCRD.get();
|
||||
|
||||
// Draw the axis.
|
||||
g2.setColor(colorFG);
|
||||
g2.drawLine(0, halfH, clipW, halfH);
|
||||
// Draw the axis.
|
||||
g2.setColor(colorFG);
|
||||
g2.drawLine(0, halfH, clipW, halfH);
|
||||
|
||||
if (run.getState() != State.NULL) {
|
||||
int segCnt = run.getRowCount();
|
||||
double segGap = (double) clipW / segCnt;
|
||||
if (run.getState() != State.NULL) {
|
||||
int segCnt = run.getRowCount();
|
||||
double segGap = (double) clipW / segCnt;
|
||||
|
||||
if (run.hasPreviousSegment()) {
|
||||
// Coordinates of the last drawn vertex.
|
||||
int prevX = 0;
|
||||
int prevY = halfH;
|
||||
if (run.hasPreviousSegment()) {
|
||||
// Coordinates of the last drawn vertex.
|
||||
int prevX = 0;
|
||||
int prevY = halfH;
|
||||
|
||||
for (int i = 0; i < run.getCurrent(); i++) {
|
||||
Time delta = run.getTime(i, Segment.DELTA);
|
||||
Time live = run.getTime(i, Segment.LIVE);
|
||||
if (delta != null && live != null) {
|
||||
int percent = (int) getCompareTimePercent(i);
|
||||
g2.setColor(run.isBetterSegment(i) ? colorTG : colorTL);
|
||||
if (run.isBestSegment(i)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < run.getCurrent(); i++) {
|
||||
Time delta = run.getTime(i, Segment.DELTA);
|
||||
Time live = run.getTime(i, Segment.LIVE);
|
||||
if (delta != null && live != null) {
|
||||
int percent = (int) getCompareTimePercent(i);
|
||||
g2.setColor(run.isBetterSegment(i) ? colorTG : colorTL);
|
||||
if (run.isBestSegment(i)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
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 {
|
||||
|
||||
// -------------------------------------------------------------- CONSTANTS
|
||||
// -------------------------------------------------------------- CONSTANTS
|
||||
|
||||
/**
|
||||
* Font used to render the title of the run.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Font used to render the title of the run.
|
||||
*/
|
||||
private static final Font RUN_TITLE_FONT = Font.decode("Arial-12-BOLD");
|
||||
|
||||
// ------------------------------------------------------------- ATTRIBUTES
|
||||
/**
|
||||
* Update identifier for every category.
|
||||
*/
|
||||
private static final int ALL = 0xff;
|
||||
|
||||
/**
|
||||
* Run instance represented by this component.
|
||||
*/
|
||||
private Run run;
|
||||
/**
|
||||
* Update identifier for time variables.
|
||||
*/
|
||||
private static final int GOAL = 0x01;
|
||||
|
||||
/**
|
||||
* Label displaying the title of the current run.
|
||||
*/
|
||||
private JLabel title;
|
||||
/**
|
||||
* Update identifier for separator variables.
|
||||
*/
|
||||
private static final int SEPARATOR = 0x02;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private JLabel goal;
|
||||
/**
|
||||
* Update identifier for text variables.
|
||||
*/
|
||||
private static final int TEXT = 0x04;
|
||||
|
||||
/**
|
||||
* Label describing the goal value being displayed.
|
||||
*/
|
||||
private JLabel goalText;
|
||||
|
||||
/**
|
||||
* Panel containing both goal value and text.
|
||||
*/
|
||||
private JPanel goalPane;
|
||||
|
||||
/**
|
||||
* A list containing empty labels serving as separators.
|
||||
*/
|
||||
private List<JLabel> separators;
|
||||
/**
|
||||
* Update identifier for title variables.
|
||||
*/
|
||||
private static final int TITLE = 0x08;
|
||||
|
||||
/**
|
||||
* Simple footer displaying information on the previous segment if any.
|
||||
* Is only visible if {@link Settings#FOOTER_DISPLAY} is {@code true}.
|
||||
*/
|
||||
private Footer footer;
|
||||
/**
|
||||
* Update identifier for background variables.
|
||||
*/
|
||||
private static final int BACKGROUND = 0x10;
|
||||
|
||||
/**
|
||||
* Panel displaying the core information like the current segment and the
|
||||
* necessary timers.
|
||||
*/
|
||||
private Core core;
|
||||
/**
|
||||
* Update identifier for the graph component.
|
||||
*/
|
||||
private static final int GRAPH = 0x20;
|
||||
|
||||
/**
|
||||
* Panel representing the current run as a graph.
|
||||
*/
|
||||
private Graph graph;
|
||||
/**
|
||||
* Update identifier for the footer component.
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param run - the run to represent.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
/**
|
||||
* Run instance represented by this component.
|
||||
*/
|
||||
private Run run;
|
||||
|
||||
// -------------------------------------------------------------- INTERFACE
|
||||
/**
|
||||
* Label displaying the title of the current run.
|
||||
*/
|
||||
private JLabel title;
|
||||
|
||||
/**
|
||||
* Sets the new run to represent.
|
||||
*
|
||||
* @param run - the new run to represent.
|
||||
*/
|
||||
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);
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private JLabel goal;
|
||||
|
||||
updateValues(ALL & ~TEXT);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- CALLBACKS
|
||||
|
||||
/**
|
||||
* 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);
|
||||
/**
|
||||
* Label describing the goal value being displayed.
|
||||
*/
|
||||
private JLabel goalText;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Panel containing both goal value and text.
|
||||
*/
|
||||
private JPanel goalPane;
|
||||
|
||||
// -------------------------------------------------------------- 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
|
||||
* and returns it.
|
||||
*
|
||||
* @param a new separator.
|
||||
*/
|
||||
private JLabel createSeparator() {
|
||||
JLabel label = new JLabel();
|
||||
separators.add(label);
|
||||
return label;
|
||||
}
|
||||
/**
|
||||
* Simple footer displaying information on the previous segment if any.
|
||||
* Is only visible if {@link Settings#FOOTER_DISPLAY} is {@code true}.
|
||||
*/
|
||||
private Footer footer;
|
||||
|
||||
/**
|
||||
* 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));
|
||||
/**
|
||||
* Panel displaying the core information like the current segment and the
|
||||
* necessary timers.
|
||||
*/
|
||||
private Core core;
|
||||
|
||||
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;
|
||||
/**
|
||||
* Panel representing the current run as a graph.
|
||||
*/
|
||||
private Graph graph;
|
||||
|
||||
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();
|
||||
}
|
||||
/**
|
||||
* Scrolling panel displaying information regarding every segment of the
|
||||
* run up to the last segment or {@link Settings#DISPLAYED_SEGMENTS}.
|
||||
*/
|
||||
private History history;
|
||||
|
||||
// ----------------------------------------------------------- CONSTRUCTORS
|
||||
|
||||
/**
|
||||
* Creates a default panel representing the given run.
|
||||
*
|
||||
* @param run - the run to represent.
|
||||
*/
|
||||
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
|
||||
|
||||
/**
|
||||
* Sets the new run to represent.
|
||||
*
|
||||
* @param run - the new run to represent.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------- CALLBACKS
|
||||
|
||||
/**
|
||||
* 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)) {
|
||||
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.scale(scale, scale);
|
||||
icon.paintIcon((Component)null, g2, 0, 0);
|
||||
icon.paintIcon(null, g2, 0, 0);
|
||||
g2.dispose();
|
||||
return new ImageIcon(buffer);
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ public class TableModelSupport {
|
|||
}
|
||||
|
||||
private void fire(TableModelEvent event) {
|
||||
TableModelListener[] tableListeners = (TableModelListener[])this.listeners.getListeners(TableModelListener.class);
|
||||
TableModelListener[] tableListeners = this.listeners.getListeners(TableModelListener.class);
|
||||
TableModelListener[] arr$ = tableListeners;
|
||||
int len$ = tableListeners.length;
|
||||
|
||||
|
|
|
@ -16,8 +16,8 @@ import java.net.URL;
|
|||
public class AboutDialog extends JDialog implements ActionListener {
|
||||
private JLabel icon = new JLabel();
|
||||
private JLabel message;
|
||||
private HyperLabel website;
|
||||
private HyperLabel donate;
|
||||
private org.fenix.utils.about.HyperLabel website;
|
||||
private org.fenix.utils.about.HyperLabel donate;
|
||||
private JButton okButton;
|
||||
|
||||
public AboutDialog(Window owner, String title) {
|
||||
|
@ -64,12 +64,12 @@ public class AboutDialog extends JDialog implements ActionListener {
|
|||
if(url == null) {
|
||||
throw new NullPointerException("Donate URL is null");
|
||||
} else {
|
||||
this.donate = new HyperLabel(url, icon);
|
||||
this.donate = new org.fenix.utils.about.HyperLabel(url, icon);
|
||||
}
|
||||
}
|
||||
|
||||
public void setWebsite(URL url) {
|
||||
this.setWebsite(url, (String)null);
|
||||
this.setWebsite(url, null);
|
||||
}
|
||||
|
||||
public void setWebsite(URL url, String text) {
|
||||
|
@ -80,7 +80,7 @@ public class AboutDialog extends JDialog implements ActionListener {
|
|||
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 {
|
||||
stream.close();
|
||||
} catch (Exception var11) {
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class LocaleDelegate {
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
for(int i$ = 0; i$ < len$; ++i$) {
|
||||
|
|
Reference in a new issue