2
0

User preferences.

This commit is contained in:
Maarten Billemont 2018-07-23 23:34:32 -04:00
parent 16cdcda94b
commit 8f7faa9e4e
7 changed files with 180 additions and 64 deletions

View File

@ -41,7 +41,7 @@ public enum MPResultType {
/** /**
* 16: pg^VMAUBk5x3p%HP%i4= * 16: pg^VMAUBk5x3p%HP%i4=
*/ */
GeneratedMaximum( "maximum", "20 characters, contains symbols.", // GeneratedMaximum( "maximum", "Maximum Security", "pg^VMAUBk5x3p%HP%i4=", "20 characters, contains symbols.", //
ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ), ImmutableList.of( new MPTemplate( "anoxxxxxxxxxxxxxxxxx" ),
new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), // new MPTemplate( "axxxxxxxxxxxxxxxxxno" ) ), //
MPResultTypeClass.Template, 0x0 ), MPResultTypeClass.Template, 0x0 ),
@ -49,7 +49,7 @@ public enum MPResultType {
/** /**
* 17: BiroYena8:Kixa * 17: BiroYena8:Kixa
*/ */
GeneratedLong( "long", "Copy-friendly, 14 characters, contains symbols.", // GeneratedLong( "long", "Long Password", "BiroYena8:Kixa", "Copy-friendly, 14 characters, contains symbols.", //
ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ), ImmutableList.of( new MPTemplate( "CvcvnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvnoCvcv" ),
new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ), new MPTemplate( "CvcvCvcvCvcvno" ), new MPTemplate( "CvccnoCvcvCvcv" ),
new MPTemplate( "CvccCvcvnoCvcv" ), new MPTemplate( "CvccCvcvCvcvno" ), new MPTemplate( "CvccCvcvnoCvcv" ), new MPTemplate( "CvccCvcvCvcvno" ),
@ -66,7 +66,7 @@ public enum MPResultType {
/** /**
* 18: BirSuj0- * 18: BirSuj0-
*/ */
GeneratedMedium( "medium", "Copy-friendly, 8 characters, contains symbols.", // GeneratedMedium( "medium", "Medium Password", "BirSuj0-", "Copy-friendly, 8 characters, contains symbols.", //
ImmutableList.of( new MPTemplate( "CvcnoCvc" ), ImmutableList.of( new MPTemplate( "CvcnoCvc" ),
new MPTemplate( "CvcCvcno" ) ), // new MPTemplate( "CvcCvcno" ) ), //
MPResultTypeClass.Template, 0x2 ), MPResultTypeClass.Template, 0x2 ),
@ -74,14 +74,14 @@ public enum MPResultType {
/** /**
* 19: Bir8 * 19: Bir8
*/ */
GeneratedShort( "short", "Copy-friendly, 4 characters, no symbols.", // GeneratedShort( "short", "Short Password", "Bir8", "Copy-friendly, 4 characters, no symbols.", //
ImmutableList.of( new MPTemplate( "Cvcn" ) ), // ImmutableList.of( new MPTemplate( "Cvcn" ) ), //
MPResultTypeClass.Template, 0x3 ), MPResultTypeClass.Template, 0x3 ),
/** /**
* 20: pO98MoD0 * 20: pO98MoD0
*/ */
GeneratedBasic( "basic", "8 characters, no symbols.", // GeneratedBasic( "basic", "Basic Password", "pO98MoD0", "8 characters, no symbols.", //
ImmutableList.of( new MPTemplate( "aaanaaan" ), ImmutableList.of( new MPTemplate( "aaanaaan" ),
new MPTemplate( "aannaaan" ), new MPTemplate( "aannaaan" ),
new MPTemplate( "aaannaaa" ) ), // new MPTemplate( "aaannaaa" ) ), //
@ -90,21 +90,21 @@ public enum MPResultType {
/** /**
* 21: 2798 * 21: 2798
*/ */
GeneratedPIN( "pin", "4 numbers.", // GeneratedPIN( "pin", "PIN Code", "2798", "4 numbers.", //
ImmutableList.of( new MPTemplate( "nnnn" ) ), // ImmutableList.of( new MPTemplate( "nnnn" ) ), //
MPResultTypeClass.Template, 0x5 ), MPResultTypeClass.Template, 0x5 ),
/** /**
* 30: birsujano * 30: birsujano
*/ */
GeneratedName( "name", "9 letter name.", // GeneratedName( "name", "Name", "birsujano", "9 letter name.", //
ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), // ImmutableList.of( new MPTemplate( "cvccvcvcv" ) ), //
MPResultTypeClass.Template, 0xE ), MPResultTypeClass.Template, 0xE ),
/** /**
* 31: bir yennoquce fefi * 31: bir yennoquce fefi
*/ */
GeneratedPhrase( "phrase", "20 character sentence.", // GeneratedPhrase( "phrase", "Phrase", "bir yennoquce fefi", "20 character sentence.", //
ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ), ImmutableList.of( new MPTemplate( "cvcc cvc cvccvcv cvc" ),
new MPTemplate( "cvc cvccvcvcv cvcv" ), new MPTemplate( "cvc cvccvcvcv cvcv" ),
new MPTemplate( "cv cvccv cvc cvcvccv" ) ), // new MPTemplate( "cv cvccv cvc cvcvccv" ) ), //
@ -113,37 +113,44 @@ public enum MPResultType {
/** /**
* 1056: Custom saved password. * 1056: Custom saved password.
*/ */
StoredPersonal( "personal", "AES-encrypted, exportable.", // StoredPersonal( "personal", "Saved Password", null, "AES-encrypted, exportable.", //
ImmutableList.<MPTemplate>of(), // ImmutableList.<MPTemplate>of(), //
MPResultTypeClass.Stateful, 0x0, MPSiteFeature.ExportContent ), MPResultTypeClass.Stateful, 0x0, MPSiteFeature.ExportContent ),
/** /**
* 2081: Custom saved password that should not be exported from the device. * 2081: Custom saved password that should not be exported from the device.
*/ */
StoredDevicePrivate( "device", "AES-encrypted, not exported.", // StoredDevicePrivate( "device", "Private Password", null, "AES-encrypted, not exported.", //
ImmutableList.<MPTemplate>of(), // ImmutableList.<MPTemplate>of(), //
MPResultTypeClass.Stateful, 0x1, MPSiteFeature.DevicePrivate ), MPResultTypeClass.Stateful, 0x1, MPSiteFeature.DevicePrivate ),
/** /**
* 4160: Derive a unique binary key. * 4160: Derive a unique binary key.
*/ */
DeriveKey( "key", "Encryption key.", // DeriveKey( "key", "Binary Key", null, "Encryption key.", //
ImmutableList.<MPTemplate>of(), // ImmutableList.<MPTemplate>of(), //
MPResultTypeClass.Derive, 0x0, MPSiteFeature.Alternative ); MPResultTypeClass.Derive, 0x0, MPSiteFeature.Alternative );
static final Logger logger = Logger.get( MPResultType.class ); static final Logger logger = Logger.get( MPResultType.class );
private final String shortName; private final String shortName;
private final String longName;
@Nullable
private final String sample;
private final String description; private final String description;
private final List<MPTemplate> templates; private final List<MPTemplate> templates;
private final MPResultTypeClass typeClass; private final MPResultTypeClass typeClass;
private final int typeIndex; private final int typeIndex;
private final ImmutableSet<MPSiteFeature> typeFeatures; private final ImmutableSet<MPSiteFeature> typeFeatures;
MPResultType(final String shortName, final String description, final List<MPTemplate> templates, MPResultType(final String shortName, final String longName, @Nullable final String sample, final String description,
final List<MPTemplate> templates,
final MPResultTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) { final MPResultTypeClass typeClass, final int typeIndex, final MPSiteFeature... typeFeatures) {
this.shortName = shortName; this.shortName = shortName;
this.longName = longName;
this.sample = sample;
this.description = description; this.description = description;
this.templates = templates; this.templates = templates;
this.typeClass = typeClass; this.typeClass = typeClass;
@ -160,6 +167,15 @@ public enum MPResultType {
return shortName; return shortName;
} }
public String getLongName() {
return longName;
}
@Nullable
public String getSample() {
return sample;
}
public String getDescription() { public String getDescription() {
return description; return description;

View File

@ -2,6 +2,7 @@ package com.lyndir.masterpassword.gui.util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import java.util.*; import java.util.*;
import java.util.function.Consumer;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionEvent;
@ -14,17 +15,24 @@ import javax.swing.event.ListSelectionListener;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class CollectionListModel<E> extends AbstractListModel<E> implements ComboBoxModel<E>, ListSelectionListener { public class CollectionListModel<E> extends AbstractListModel<E> implements ComboBoxModel<E>, ListSelectionListener {
private final List<E> model = new LinkedList<>(); private final List<E> model = new LinkedList<>();
@Nullable @Nullable
private E selectedItem; private E selectedItem;
private JList<E> list; private JList<E> list;
@Nullable
private Consumer<E> selectionConsumer;
public CollectionListModel() { @SafeVarargs
public static <E> CollectionListModel<E> copy(final E... elements) {
return copy( Arrays.asList( elements ) );
} }
public CollectionListModel(final Collection<E> model) { public static <E> CollectionListModel<E> copy(final Collection<E> elements) {
this.model.addAll( model ); CollectionListModel<E> model = new CollectionListModel<>();
fireIntervalAdded( this, 0, model.size() ); model.model.addAll( elements );
model.fireIntervalAdded( model, 0, model.model.size() );
return model;
} }
@Override @Override
@ -79,11 +87,14 @@ public class CollectionListModel<E> extends AbstractListModel<E> implements Comb
public synchronized void setSelectedItem(@Nullable final Object newSelectedItem) { public synchronized void setSelectedItem(@Nullable final Object newSelectedItem) {
if (!Objects.equals( selectedItem, newSelectedItem ) && model.contains( newSelectedItem )) { if (!Objects.equals( selectedItem, newSelectedItem ) && model.contains( newSelectedItem )) {
selectedItem = (E) newSelectedItem; selectedItem = (E) newSelectedItem;
fireContentsChanged( this, -1, -1 );
fireContentsChanged( this, -1, -1 );
//noinspection ObjectEquality //noinspection ObjectEquality
if ((list != null) && (list.getModel() == this)) if ((list != null) && (list.getModel() == this))
list.setSelectedValue( selectedItem, true ); list.setSelectedValue( selectedItem, true );
if (selectionConsumer != null)
selectionConsumer.accept( selectedItem );
} }
} }
@ -103,6 +114,17 @@ public class CollectionListModel<E> extends AbstractListModel<E> implements Comb
this.list.setModel( this ); this.list.setModel( this );
} }
public CollectionListModel<E> selection(@Nullable final E selectedItem, @Nullable final Consumer<E> selectionConsumer) {
this.selectionConsumer = null;
setSelectedItem( selectedItem );
this.selectionConsumer = selectionConsumer;
if (this.selectionConsumer != null)
this.selectionConsumer.accept( selectedItem );
return this;
}
@Override @Override
public synchronized void valueChanged(final ListSelectionEvent event) { public synchronized void valueChanged(final ListSelectionEvent event) {
//noinspection ObjectEquality //noinspection ObjectEquality

View File

@ -20,6 +20,8 @@ package com.lyndir.masterpassword.gui.util;
import com.lyndir.masterpassword.gui.Res; import com.lyndir.masterpassword.gui.Res;
import java.awt.*; import java.awt.*;
import java.util.Collection;
import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.swing.*; import javax.swing.*;
@ -30,15 +32,20 @@ import javax.swing.border.CompoundBorder;
/** /**
* @author lhunath, 2014-06-08 * @author lhunath, 2014-06-08
*/ */
@SuppressWarnings("SerializableStoresNonSerializable")
public abstract class Components { public abstract class Components {
public static final float TEXT_SIZE_HEADING = 19f; public static final float TEXT_SIZE_HEADING = 19f;
public static final float TEXT_SIZE_CONTROL = 13f; public static final float TEXT_SIZE_CONTROL = 13f;
public static final int SIZE_MARGIN = 20; public static final int SIZE_MARGIN = 12;
public static final int SIZE_PADDING = 8; public static final int SIZE_PADDING = 8;
public static GradientPanel boxPanel(final int axis, final Component... components) { public static GradientPanel panel(final int axis, final Component... components) {
GradientPanel container = gradientPanel( null, null ); return panel( axis, null, components );
}
public static GradientPanel panel(final int axis, @Nullable final Color background, final Component... components) {
GradientPanel container = gradientPanel( background, null );
container.setLayout( new BoxLayout( container, axis ) ); container.setLayout( new BoxLayout( container, axis ) );
for (final Component component : components) for (final Component component : components)
container.add( component ); container.add( component );
@ -46,20 +53,24 @@ public abstract class Components {
return container; return container;
} }
public static GradientPanel borderPanel(@Nullable final Border border, final Component... components) { public static GradientPanel borderPanel(final int axis, final Component... components) {
return borderPanel( border, null, components ); return borderPanel( marginBorder(), null, axis, components );
} }
public static GradientPanel borderPanel(@Nullable final Border border, @Nullable final Color background, public static GradientPanel borderPanel(@Nullable final Border border, final int axis, final Component... components) {
final Component... components) { return borderPanel( border, null, axis, components );
GradientPanel box = boxPanel( BoxLayout.LINE_AXIS, components ); }
public static GradientPanel borderPanel(@Nullable final Color background, final int axis, final Component... components) {
return borderPanel( marginBorder(), background, axis, components );
}
public static GradientPanel borderPanel(@Nullable final Border border, @Nullable final Color background, final int axis,
final Component... components) {
GradientPanel box = panel( axis, background, components );
if (border != null) if (border != null)
box.setBorder( border ); box.setBorder( border );
if (background != null)
box.setBackground( background );
return box; return box;
} }
@ -69,11 +80,39 @@ public abstract class Components {
setOpaque( color != null ); setOpaque( color != null );
setBackground( color ); setBackground( color );
setAlignmentX( LEFT_ALIGNMENT ); setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
} }
}; };
} }
public static JDialog showDialog(@Nullable final Component owner, @Nullable final String title, final JOptionPane pane) {
JDialog dialog = pane.createDialog( owner, title );
dialog.setModalityType( Dialog.ModalityType.DOCUMENT_MODAL );
return showDialog( dialog );
}
public static JDialog showDialog(@Nullable final Component owner, @Nullable final String title, final Container content) {
JDialog dialog = new JDialog( (owner != null)? SwingUtilities.windowForComponent( owner ): null,
title, Dialog.ModalityType.DOCUMENT_MODAL );
dialog.setMinimumSize( new Dimension( 320, 0 ) );
dialog.setLocationRelativeTo( owner );
dialog.setLocationByPlatform( true );
dialog.setContentPane( content );
return showDialog( dialog );
}
private static JDialog showDialog(final JDialog dialog) {
// OpenJDK does not correctly implement this setting in native code.
dialog.getRootPane().putClientProperty( "apple.awt.documentModalSheet", Boolean.TRUE );
dialog.getRootPane().putClientProperty( "Window.style", "small" );
dialog.pack();
dialog.setVisible( true );
return dialog;
}
public static JTextField textField() { public static JTextField textField() {
return new JTextField() { return new JTextField() {
{ {
@ -81,7 +120,6 @@ public abstract class Components {
BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ) ); BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ) );
setFont( Res.fonts().valueFont( TEXT_SIZE_CONTROL ) ); setFont( Res.fonts().valueFont( TEXT_SIZE_CONTROL ) );
setAlignmentX( LEFT_ALIGNMENT ); setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
} }
@Override @Override
@ -97,7 +135,6 @@ public abstract class Components {
setBorder( BorderFactory.createCompoundBorder( BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ), setBorder( BorderFactory.createCompoundBorder( BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ),
BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ) ); BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ) );
setAlignmentX( LEFT_ALIGNMENT ); setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
} }
@Override @Override
@ -126,7 +163,6 @@ public abstract class Components {
} }
} ); } );
setAlignmentX( LEFT_ALIGNMENT ); setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
} }
@Override @Override
@ -141,22 +177,21 @@ public abstract class Components {
{ {
setBorder( BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ) ); setBorder( BorderFactory.createLineBorder( Res.colors().controlBorder(), 1, true ) );
setAlignmentX( LEFT_ALIGNMENT ); setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
} }
}; };
} }
public static JButton button(final String label) { public static JButton button(final String label) {
return button( label, null );
}
public static JButton button(final String label, @Nullable final Action action) {
return new JButton( label ) { return new JButton( label ) {
{ {
setFont( Res.fonts().controlFont( TEXT_SIZE_CONTROL ) ); setFont( Res.fonts().controlFont( TEXT_SIZE_CONTROL ) );
setAlignmentX( LEFT_ALIGNMENT ); setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT ); if (action != null)
} setAction( action );
@Override
public Dimension getMaximumSize() {
return new Dimension( 20, getPreferredSize().height );
} }
}; };
} }
@ -169,7 +204,6 @@ public abstract class Components {
Dimension studDimension = new Dimension( size, size ); Dimension studDimension = new Dimension( size, size );
Box.Filler rigidArea = new Box.Filler( studDimension, studDimension, studDimension ); Box.Filler rigidArea = new Box.Filler( studDimension, studDimension, studDimension );
rigidArea.setAlignmentX( Component.LEFT_ALIGNMENT ); rigidArea.setAlignmentX( Component.LEFT_ALIGNMENT );
rigidArea.setAlignmentY( Component.BOTTOM_ALIGNMENT );
rigidArea.setBackground( Color.red ); rigidArea.setBackground( Color.red );
return rigidArea; return rigidArea;
} }
@ -194,7 +228,6 @@ public abstract class Components {
BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) ); BorderFactory.createEmptyBorder( 4, 4, 4, 4 ) );
((DefaultEditor) getEditor()).getTextField().setBorder( editorBorder ); ((DefaultEditor) getEditor()).getTextField().setBorder( editorBorder );
setAlignmentX( LEFT_ALIGNMENT ); setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
setBorder( null ); setBorder( null );
} }
@ -231,7 +264,6 @@ public abstract class Components {
{ {
setFont( Res.fonts().controlFont( TEXT_SIZE_HEADING ).deriveFont( Font.BOLD ) ); setFont( Res.fonts().controlFont( TEXT_SIZE_HEADING ).deriveFont( Font.BOLD ) );
setAlignmentX( LEFT_ALIGNMENT ); setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
} }
@Override @Override
@ -267,7 +299,6 @@ public abstract class Components {
{ {
setFont( Res.fonts().controlFont( TEXT_SIZE_CONTROL ) ); setFont( Res.fonts().controlFont( TEXT_SIZE_CONTROL ) );
setAlignmentX( LEFT_ALIGNMENT ); setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
} }
@Override @Override
@ -283,7 +314,6 @@ public abstract class Components {
setFont( Res.fonts().controlFont( TEXT_SIZE_CONTROL ) ); setFont( Res.fonts().controlFont( TEXT_SIZE_CONTROL ) );
setBackground( null ); setBackground( null );
setAlignmentX( LEFT_ALIGNMENT ); setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
} }
}; };
} }
@ -293,6 +323,16 @@ public abstract class Components {
return comboBox( new DefaultComboBoxModel<>( values ), valueTransformer ); return comboBox( new DefaultComboBoxModel<>( values ), valueTransformer );
} }
public static <E> JComboBox<E> comboBox(final E[] values, final Function<E, String> valueTransformer, final E selectedItem,
@Nullable final Consumer<E> selectionConsumer) {
return comboBox( CollectionListModel.copy( values ).selection( selectedItem, selectionConsumer ), valueTransformer );
}
public static <E> JComboBox<E> comboBox(final Collection<E> values, final Function<E, String> valueTransformer, final E selectedItem,
@Nullable final Consumer<E> selectionConsumer) {
return comboBox( CollectionListModel.copy( values ).selection( selectedItem, selectionConsumer ), valueTransformer );
}
public static <E> JComboBox<E> comboBox(final ComboBoxModel<E> model, final Function<E, String> valueTransformer) { public static <E> JComboBox<E> comboBox(final ComboBoxModel<E> model, final Function<E, String> valueTransformer) {
return new JComboBox<E>( model ) { return new JComboBox<E>( model ) {
{ {
@ -311,8 +351,8 @@ public abstract class Components {
list, valueTransformer.apply( (E) value ), index, isSelected, cellHasFocus ); list, valueTransformer.apply( (E) value ), index, isSelected, cellHasFocus );
} }
} ); } );
putClientProperty( "JComboBox.isPopDown", Boolean.TRUE );
setAlignmentX( LEFT_ALIGNMENT ); setAlignmentX( LEFT_ALIGNMENT );
setAlignmentY( BOTTOM_ALIGNMENT );
} }
@Override @Override

View File

@ -1,13 +1,16 @@
package com.lyndir.masterpassword.gui.view; package com.lyndir.masterpassword.gui.view;
import com.google.common.collect.ImmutableList;
import com.lyndir.masterpassword.MPAlgorithm;
import com.lyndir.masterpassword.MPResultType;
import com.lyndir.masterpassword.gui.Res; import com.lyndir.masterpassword.gui.Res;
import com.lyndir.masterpassword.gui.util.CollectionListModel; import com.lyndir.masterpassword.gui.util.CollectionListModel;
import com.lyndir.masterpassword.gui.util.Components; import com.lyndir.masterpassword.gui.util.Components;
import com.lyndir.masterpassword.model.MPUser; import com.lyndir.masterpassword.model.MPUser;
import com.lyndir.masterpassword.model.impl.MPFileUser;
import com.lyndir.masterpassword.model.impl.MPFileUserManager; import com.lyndir.masterpassword.model.impl.MPFileUserManager;
import java.awt.*; import java.awt.*;
import java.awt.event.ItemEvent; import java.awt.event.*;
import java.awt.event.ItemListener;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -17,14 +20,16 @@ import javax.swing.*;
/** /**
* @author lhunath, 2018-07-14 * @author lhunath, 2018-07-14
*/ */
@SuppressWarnings("serial")
public class FilesPanel extends JPanel implements ItemListener { public class FilesPanel extends JPanel implements ItemListener {
private final Collection<Listener> listeners = new CopyOnWriteArraySet<>(); private final Collection<Listener> listeners = new CopyOnWriteArraySet<>();
private final JLabel avatarLabel = new JLabel(); private final JLabel avatarLabel = new JLabel();
private final CollectionListModel<MPUser<?>> usersModel = new CollectionListModel<>(); private final CollectionListModel<MPUser<?>> usersModel = new CollectionListModel<>();
private final JComboBox<MPUser<?>> userField = private final JComboBox<MPUser<?>> userField =
Components.comboBox( usersModel, user -> (user != null)? user.getFullName(): null ); Components.comboBox( usersModel, user -> (user != null)? user.getFullName(): null );
private final JButton preferencesButton = Components.button( "..." );
protected FilesPanel() { protected FilesPanel() {
setOpaque( false ); setOpaque( false );
@ -41,10 +46,34 @@ public class FilesPanel extends JPanel implements ItemListener {
avatarLabel.setToolTipText( "The avatar for your user. Click to change it." ); avatarLabel.setToolTipText( "The avatar for your user. Click to change it." );
// - // -
add( Components.strut( 20 ) ); add( Components.strut( Components.margin() ) );
// User Selection // User Selection
add( userField ); add( Components.panel( BoxLayout.LINE_AXIS, userField, preferencesButton ) );
preferencesButton.setAction( new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
MPUser<?> user = usersModel.getSelectedItem();
if (user == null)
return;
MPFileUser fileUser = (user instanceof MPFileUser)? (MPFileUser) user: null;
ImmutableList.Builder<Component> components = ImmutableList.builder();
if (fileUser != null)
components.add( Components.label( "Default Password Type:" ),
Components.comboBox( MPResultType.values(), MPResultType::getLongName,
fileUser.getDefaultType(), fileUser::setDefaultType ),
Components.strut() );
components.add( Components.label( "Default Algorithm:" ),
Components.comboBox( MPAlgorithm.Version.values(), MPAlgorithm.Version::name,
user.getAlgorithm().version(),
version -> user.setAlgorithm( version.getAlgorithm() ) ) );
Components.showDialog( preferencesButton, user.getFullName(), new JOptionPane( Components.panel(
BoxLayout.PAGE_AXIS, components.build().toArray( new Component[0] ) ) ) );
}
} );
userField.addItemListener( this ); userField.addItemListener( this );
} }

View File

@ -9,6 +9,7 @@ import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener; import java.awt.event.ComponentListener;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.BevelBorder;
/** /**
@ -29,24 +30,23 @@ public class MasterPasswordFrame extends JFrame implements FilesPanel.Listener,
super( "Master Password" ); super( "Master Password" );
setDefaultCloseOperation( DISPOSE_ON_CLOSE ); setDefaultCloseOperation( DISPOSE_ON_CLOSE );
setContentPane( root = Components.gradientPanel( Res.colors().frameBg(), new FlowLayout() ) ); setContentPane( root = Components.borderPanel( Res.colors().frameBg(), BoxLayout.PAGE_AXIS ) );
root.setLayout( new BoxLayout( root, BoxLayout.PAGE_AXIS ) );
root.setBorder( Components.marginBorder() );
root.add( filesPanel ); root.add( filesPanel );
root.add( new JSeparator( SwingConstants.HORIZONTAL ) ); root.add( new JSeparator( SwingConstants.HORIZONTAL ) );
root.add( Components.strut() ); root.add( Components.strut() );
root.add( Components.borderPanel( BorderFactory.createRaisedBevelBorder(), Res.colors().controlBg(), userPanel ) ); root.add( Components.borderPanel(
BorderFactory.createBevelBorder( BevelBorder.RAISED, Res.colors().controlBorder(), Res.colors().frameBg() ),
Res.colors().controlBg(), BoxLayout.PAGE_AXIS, userPanel ) );
filesPanel.addListener( this ); filesPanel.addListener( this );
filesPanel.reload(); filesPanel.reload();
addComponentListener(this ); addComponentListener( this );
setPreferredSize( new Dimension( 640, 480 ) ); setPreferredSize( new Dimension( 640, 480 ) );
pack(); pack();
setLocationByPlatform( true );
setLocationRelativeTo( null ); setLocationRelativeTo( null );
setLocationByPlatform( true );
} }
@Override @Override

View File

@ -10,6 +10,8 @@ import com.lyndir.masterpassword.gui.Res;
import com.lyndir.masterpassword.gui.util.CollectionListModel; import com.lyndir.masterpassword.gui.util.CollectionListModel;
import com.lyndir.masterpassword.gui.util.Components; import com.lyndir.masterpassword.gui.util.Components;
import com.lyndir.masterpassword.model.*; import com.lyndir.masterpassword.model.*;
import com.lyndir.masterpassword.model.impl.MPFileSite;
import com.lyndir.masterpassword.model.impl.MPFileUser;
import java.awt.*; import java.awt.*;
import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable; import java.awt.datatransfer.Transferable;
@ -129,7 +131,7 @@ public class UserPanel extends Components.GradientPanel implements MPUser.Listen
@Override @Override
public void actionPerformed(final ActionEvent event) { public void actionPerformed(final ActionEvent event) {
updateIdenticon(); updateIdenticon();
char[] masterPassword = masterPasswordField.getPassword(); char[] masterPassword = masterPasswordField.getPassword();
Res.job( () -> { Res.job( () -> {
try { try {
@ -223,6 +225,7 @@ public class UserPanel extends Components.GradientPanel implements MPUser.Listen
add( queryLabel ); add( queryLabel );
queryLabel.setText( strf( "%s's password for:", user.getFullName() ) ); queryLabel.setText( strf( "%s's password for:", user.getFullName() ) );
add( queryField ); add( queryField );
queryField.putClientProperty( "JTextField.variant", "search" );
queryField.addActionListener( this ); queryField.addActionListener( this );
queryField.addKeyListener( this ); queryField.addKeyListener( this );
queryField.getDocument().addDocumentListener( this ); queryField.getDocument().addDocumentListener( this );
@ -236,10 +239,14 @@ public class UserPanel extends Components.GradientPanel implements MPUser.Listen
@Override @Override
public void actionPerformed(final ActionEvent event) { public void actionPerformed(final ActionEvent event) {
showSiteResult( sitesList.getSelectedValue(), result -> { MPSite<?> site = sitesList.getSelectedValue();
showSiteResult( site, result -> {
if (result == null) if (result == null)
return; return;
if (site instanceof MPFileSite)
((MPFileSite) site).use();
Transferable clipboardContents = new StringSelection( result ); Transferable clipboardContents = new StringSelection( result );
Toolkit.getDefaultToolkit().getSystemClipboard().setContents( clipboardContents, null ); Toolkit.getDefaultToolkit().getSystemClipboard().setContents( clipboardContents, null );

View File

@ -95,6 +95,8 @@ public class MPFileSite extends MPBasicSite<MPFileQuestion> {
uses++; uses++;
lastUsed = new Instant(); lastUsed = new Instant();
user.use(); user.use();
setChanged();
} }
public String getResult() public String getResult()