Avatar configuration & move preferences into user panel.
This commit is contained in:
parent
7c83a62f91
commit
e639137304
@ -24,7 +24,7 @@
|
||||
</value>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="false" project-jdk-name="10" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
@ -0,0 +1,25 @@
|
||||
package com.lyndir.masterpassword.util;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
/**
|
||||
* @author lhunath, 2018-07-25
|
||||
*/
|
||||
public final class Utilities {
|
||||
|
||||
@Nullable
|
||||
public static <T, R> R ifNotNull(@Nullable final T value, final Function<T, R> consumer) {
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
return consumer.apply( value );
|
||||
}
|
||||
|
||||
public static <T> void ifNotNullDo(@Nullable final T value, final Consumer<T> consumer) {
|
||||
if (value != null)
|
||||
consumer.accept( value );
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
/**
|
||||
* @author lhunath, 2018-07-25
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
package com.lyndir.masterpassword.util;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
@ -24,6 +24,7 @@ import com.google.common.base.Charsets;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import com.lyndir.lhunath.opal.system.util.TypeUtils;
|
||||
import com.lyndir.masterpassword.gui.util.Res;
|
||||
import com.lyndir.masterpassword.gui.view.MasterPasswordFrame;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -16,7 +16,7 @@
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword.gui.platform.mac;
|
||||
package com.lyndir.masterpassword.gui.platform.macos;
|
||||
|
||||
import com.apple.eawt.*;
|
||||
import com.google.common.base.Preconditions;
|
@ -20,6 +20,6 @@
|
||||
* @author lhunath, 2018-04-26
|
||||
*/
|
||||
@ParametersAreNonnullByDefault
|
||||
package com.lyndir.masterpassword.gui.platform.mac;
|
||||
package com.lyndir.masterpassword.gui.platform.macos;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
@ -27,12 +27,15 @@ public class CollectionListModel<E> extends AbstractListModel<E> implements Comb
|
||||
return copy( Arrays.asList( elements ) );
|
||||
}
|
||||
|
||||
public static <E> CollectionListModel<E> copy(final Collection<E> elements) {
|
||||
public static <E> CollectionListModel<E> copy(final Collection<? extends E> elements) {
|
||||
CollectionListModel<E> model = new CollectionListModel<>();
|
||||
model.model.addAll( elements );
|
||||
model.fireIntervalAdded( model, 0, model.model.size() );
|
||||
synchronized (model) {
|
||||
model.model.addAll( elements );
|
||||
model.selectedItem = model.getElementAt( 0 );
|
||||
model.fireIntervalAdded( model, 0, model.model.size() );
|
||||
|
||||
return model;
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -41,8 +44,9 @@ public class CollectionListModel<E> extends AbstractListModel<E> implements Comb
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public synchronized E getElementAt(final int index) {
|
||||
return model.get( index );
|
||||
return (index < model.size())? model.get( index ): null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,10 +80,8 @@ public class CollectionListModel<E> extends AbstractListModel<E> implements Comb
|
||||
}
|
||||
}
|
||||
|
||||
if ((selectedItem == null) && !model.isEmpty())
|
||||
setSelectedItem( model.get( 0 ) );
|
||||
else if (!model.contains( selectedItem ))
|
||||
setSelectedItem( null );
|
||||
if ((selectedItem == null) || !model.contains( selectedItem ))
|
||||
setSelectedItem( getElementAt( 0 ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -114,15 +116,19 @@ public class CollectionListModel<E> extends AbstractListModel<E> implements Comb
|
||||
this.list.setModel( this );
|
||||
}
|
||||
|
||||
public CollectionListModel<E> selection(@Nullable final E selectedItem, @Nullable final Consumer<E> selectionConsumer) {
|
||||
public synchronized CollectionListModel<E> selection(@Nullable final Consumer<E> selectionConsumer) {
|
||||
this.selectionConsumer = selectionConsumer;
|
||||
if (selectionConsumer != null)
|
||||
selectionConsumer.accept( selectedItem );
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized 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;
|
||||
return selection( selectionConsumer );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -18,8 +18,9 @@
|
||||
|
||||
package com.lyndir.masterpassword.gui.util;
|
||||
|
||||
import com.lyndir.masterpassword.gui.Res;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.Collection;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
@ -32,7 +33,7 @@ import javax.swing.border.CompoundBorder;
|
||||
/**
|
||||
* @author lhunath, 2014-06-08
|
||||
*/
|
||||
@SuppressWarnings("SerializableStoresNonSerializable")
|
||||
@SuppressWarnings({ "SerializableStoresNonSerializable", "serial" })
|
||||
public abstract class Components {
|
||||
|
||||
public static final float TEXT_SIZE_HEADING = 19f;
|
||||
@ -45,7 +46,7 @@ public abstract class Components {
|
||||
}
|
||||
|
||||
public static GradientPanel panel(final int axis, @Nullable final Color background, final Component... components) {
|
||||
GradientPanel container = gradientPanel( background, null );
|
||||
GradientPanel container = panel( null, background );
|
||||
container.setLayout( new BoxLayout( container, axis ) );
|
||||
for (final Component component : components)
|
||||
container.add( component );
|
||||
@ -74,14 +75,8 @@ public abstract class Components {
|
||||
return box;
|
||||
}
|
||||
|
||||
public static GradientPanel gradientPanel(@Nullable final Color color, @Nullable final LayoutManager layout) {
|
||||
return new GradientPanel( layout, color ) {
|
||||
{
|
||||
setOpaque( color != null );
|
||||
setBackground( color );
|
||||
setAlignmentX( LEFT_ALIGNMENT );
|
||||
}
|
||||
};
|
||||
public static GradientPanel panel(@Nullable final LayoutManager layout, @Nullable final Color color) {
|
||||
return new GradientPanel( layout, color );
|
||||
}
|
||||
|
||||
public static JDialog showDialog(@Nullable final Component owner, @Nullable final String title, final JOptionPane pane) {
|
||||
@ -181,17 +176,40 @@ public abstract class Components {
|
||||
};
|
||||
}
|
||||
|
||||
public static JButton button(final String label) {
|
||||
return button( label, null );
|
||||
public static JButton button(final String label, @Nullable final ActionListener actionListener) {
|
||||
return button( new AbstractAction( label ) {
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
if (actionListener != null)
|
||||
actionListener.actionPerformed( e );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public static JButton button(final String label, @Nullable final Action action) {
|
||||
return new JButton( label ) {
|
||||
public static JButton button(final Icon icon, @Nullable final ActionListener actionListener) {
|
||||
JButton iconButton = button( new AbstractAction( null, icon ) {
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent e) {
|
||||
if (actionListener != null)
|
||||
actionListener.actionPerformed( e );
|
||||
}
|
||||
} );
|
||||
iconButton.setFocusable( false );
|
||||
|
||||
return iconButton;
|
||||
}
|
||||
|
||||
public static JButton button(final Action action) {
|
||||
return new JButton( action ) {
|
||||
{
|
||||
setFont( Res.fonts().controlFont( TEXT_SIZE_CONTROL ) );
|
||||
setAlignmentX( LEFT_ALIGNMENT );
|
||||
if (action != null)
|
||||
setAction( action );
|
||||
|
||||
if (getText() == null) {
|
||||
setContentAreaFilled( false );
|
||||
setBorderPainted( false );
|
||||
setOpaque( false );
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -323,13 +341,18 @@ public abstract class Components {
|
||||
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) {
|
||||
public static <E> JComboBox<E> comboBox(final E[] values, final Function<E, String> valueTransformer,
|
||||
@Nullable 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,
|
||||
public static <E> JComboBox<E> comboBox(final Collection<E> values, final Function<E, String> valueTransformer,
|
||||
@Nullable final Consumer<E> selectionConsumer) {
|
||||
return comboBox( CollectionListModel.copy( values ).selection( selectionConsumer ), valueTransformer );
|
||||
}
|
||||
|
||||
public static <E> JComboBox<E> comboBox(final Collection<E> values, final Function<E, String> valueTransformer,
|
||||
@Nullable final E selectedItem, @Nullable final Consumer<E> selectionConsumer) {
|
||||
return comboBox( CollectionListModel.copy( values ).selection( selectedItem, selectionConsumer ), valueTransformer );
|
||||
}
|
||||
|
||||
@ -378,10 +401,15 @@ public abstract class Components {
|
||||
this( null, gradientColor );
|
||||
}
|
||||
|
||||
public GradientPanel(@Nullable final LayoutManager layout) {
|
||||
this( layout, null );
|
||||
}
|
||||
|
||||
public GradientPanel(@Nullable final LayoutManager layout, @Nullable final Color gradientColor) {
|
||||
super( layout );
|
||||
this.gradientColor = gradientColor;
|
||||
setBackground( null );
|
||||
setAlignmentX( LEFT_ALIGNMENT );
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -16,9 +16,8 @@
|
||||
// LICENSE file. Alternatively, see <http://www.gnu.org/licenses/>.
|
||||
//==============================================================================
|
||||
|
||||
package com.lyndir.masterpassword.gui;
|
||||
package com.lyndir.masterpassword.gui.util;
|
||||
|
||||
import static com.lyndir.lhunath.opal.system.util.ObjectUtils.*;
|
||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
@ -26,15 +25,13 @@ import com.google.common.io.Resources;
|
||||
import com.google.common.util.concurrent.*;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import com.lyndir.masterpassword.MPIdenticon;
|
||||
import com.lyndir.masterpassword.gui.SwingExecutorService;
|
||||
import java.awt.*;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.swing.*;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
|
||||
@ -42,7 +39,7 @@ import org.jetbrains.annotations.NonNls;
|
||||
/**
|
||||
* @author lhunath, 2014-06-11
|
||||
*/
|
||||
@SuppressWarnings({ "HardcodedFileSeparator", "MethodReturnAlwaysConstant", "SpellCheckingInspection" })
|
||||
@SuppressWarnings({ "HardcodedFileSeparator", "MethodReturnAlwaysConstant", "SpellCheckingInspection", "serial" })
|
||||
public abstract class Res {
|
||||
|
||||
private static final int AVATAR_COUNT = 19;
|
||||
@ -51,6 +48,7 @@ public abstract class Res {
|
||||
private static final Executor immediateUiExecutor = new SwingExecutorService( true );
|
||||
private static final Executor laterUiExecutor = new SwingExecutorService( false );
|
||||
private static final Logger logger = Logger.get( Res.class );
|
||||
private static final Icons icons = new Icons();
|
||||
private static final Fonts fonts = new Fonts();
|
||||
private static final Colors colors = new Colors();
|
||||
|
||||
@ -93,24 +91,8 @@ public abstract class Res {
|
||||
return immediate? immediateUiExecutor: laterUiExecutor;
|
||||
}
|
||||
|
||||
public static Icon iconAdd() {
|
||||
return new RetinaIcon( Resources.getResource( "media/icon_add@2x.png" ) );
|
||||
}
|
||||
|
||||
public static Icon iconDelete() {
|
||||
return new RetinaIcon( Resources.getResource( "media/icon_delete@2x.png" ) );
|
||||
}
|
||||
|
||||
public static Icon iconQuestion() {
|
||||
return new RetinaIcon( Resources.getResource( "media/icon_question@2x.png" ) );
|
||||
}
|
||||
|
||||
public static Icon avatar(final int index) {
|
||||
return new RetinaIcon( Resources.getResource( strf( "media/avatar-%d@2x.png", index % avatars() ) ) );
|
||||
}
|
||||
|
||||
public static int avatars() {
|
||||
return AVATAR_COUNT;
|
||||
public static Icons icons() {
|
||||
return icons;
|
||||
}
|
||||
|
||||
public static Fonts fonts() {
|
||||
@ -121,64 +103,39 @@ public abstract class Res {
|
||||
return colors;
|
||||
}
|
||||
|
||||
private static final class RetinaIcon extends ImageIcon {
|
||||
public static final class Icons {
|
||||
|
||||
private static final Pattern scalePattern = Pattern.compile( ".*@(\\d+)x.[^.]+$" );
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private final float scale;
|
||||
|
||||
private RetinaIcon(final URL url) {
|
||||
super( url );
|
||||
|
||||
Matcher scaleMatcher = scalePattern.matcher( url.getPath() );
|
||||
scale = scaleMatcher.matches()? Float.parseFloat( scaleMatcher.group( 1 ) ): 1;
|
||||
public Icon add() {
|
||||
return icon( "media/icon_add.png" );
|
||||
}
|
||||
|
||||
//private static URL retinaURL(final URL url) {
|
||||
// try {
|
||||
// final boolean[] isRetina = new boolean[1];
|
||||
// new apple.awt.CImage.HiDPIScaledImage(1,1, BufferedImage.TYPE_INT_ARGB) {
|
||||
// @Override
|
||||
// public void drawIntoImage(BufferedImage image, float v) {
|
||||
// isRetina[0] = v > 1;
|
||||
// }
|
||||
// };
|
||||
// return isRetina[0];
|
||||
// } catch (Throwable e) {
|
||||
// e.printStackTrace();
|
||||
// return url;
|
||||
// }
|
||||
//}
|
||||
|
||||
@Override
|
||||
public int getIconWidth() {
|
||||
return (int) (super.getIconWidth() / scale);
|
||||
public Icon delete() {
|
||||
return icon( "media/icon_delete.png" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIconHeight() {
|
||||
return (int) (super.getIconHeight() / scale);
|
||||
public Icon question() {
|
||||
return icon( "media/icon_question.png" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void paintIcon(final Component c, final Graphics g, final int x, final int y) {
|
||||
ImageObserver observer = ifNotNullElse( getImageObserver(), c );
|
||||
public Icon user() {
|
||||
return icon( "media/icon_user.png" );
|
||||
}
|
||||
|
||||
Image image = getImage();
|
||||
int width = image.getWidth( observer );
|
||||
int height = image.getHeight( observer );
|
||||
Graphics2D g2d = (Graphics2D) g.create( x, y, width, height );
|
||||
public Icon avatar(final int index) {
|
||||
return icon( strf( "media/avatar-%d.png", index % avatars() ) );
|
||||
}
|
||||
|
||||
g2d.scale( 1 / scale, 1 / scale );
|
||||
g2d.drawImage( image, 0, 0, observer );
|
||||
g2d.scale( 1, 1 );
|
||||
g2d.dispose();
|
||||
public int avatars() {
|
||||
return AVATAR_COUNT;
|
||||
}
|
||||
|
||||
private static Icon icon(@NonNls final String resourceName) {
|
||||
return new ImageIcon( Toolkit.getDefaultToolkit().getImage( Res.class.getClassLoader().getResource( resourceName ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Fonts {
|
||||
public static final class Fonts {
|
||||
|
||||
public Font emoticonsFont(final float size) {
|
||||
return emoticonsRegular().deriveFont( size );
|
||||
@ -266,7 +223,7 @@ public abstract class Res {
|
||||
}
|
||||
|
||||
|
||||
public static class Colors {
|
||||
public static final class Colors {
|
||||
|
||||
private final Color transparent = new Color( 0, 0, 0, 0 );
|
||||
private final Color frameBg = Color.decode( "#5A5D6B" );
|
@ -1,16 +1,13 @@
|
||||
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 static com.lyndir.masterpassword.util.Utilities.*;
|
||||
|
||||
import com.lyndir.masterpassword.gui.util.Res;
|
||||
import com.lyndir.masterpassword.gui.util.CollectionListModel;
|
||||
import com.lyndir.masterpassword.gui.util.Components;
|
||||
import com.lyndir.masterpassword.model.MPUser;
|
||||
import com.lyndir.masterpassword.model.impl.MPFileUser;
|
||||
import com.lyndir.masterpassword.model.impl.MPFileUserManager;
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import javax.annotation.Nullable;
|
||||
@ -21,15 +18,16 @@ import javax.swing.*;
|
||||
* @author lhunath, 2018-07-14
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class FilesPanel extends JPanel implements ItemListener {
|
||||
public class FilesPanel extends JPanel {
|
||||
|
||||
private final Collection<Listener> listeners = new CopyOnWriteArraySet<>();
|
||||
|
||||
private final JLabel avatarLabel = new JLabel();
|
||||
private final CollectionListModel<MPUser<?>> usersModel = new CollectionListModel<>();
|
||||
private final JComboBox<MPUser<?>> userField =
|
||||
Components.comboBox( usersModel, user -> (user != null)? user.getFullName(): null );
|
||||
private final JButton preferencesButton = Components.button( "..." );
|
||||
private final JButton avatarButton = Components.button( Res.icons().avatar( 0 ), event -> setAvatar() );
|
||||
|
||||
private final CollectionListModel<MPUser<?>> usersModel =
|
||||
CollectionListModel.<MPUser<?>>copy( MPFileUserManager.get().getFiles() ).selection( this::setUser );
|
||||
private final JComboBox<? extends MPUser<?>> userField =
|
||||
Components.comboBox( usersModel, user -> ifNotNull( user, MPUser::getFullName ) );
|
||||
|
||||
protected FilesPanel() {
|
||||
setOpaque( false );
|
||||
@ -40,66 +38,45 @@ public class FilesPanel extends JPanel implements ItemListener {
|
||||
add( Box.createVerticalGlue() );
|
||||
|
||||
// Avatar
|
||||
add( avatarLabel );
|
||||
avatarLabel.setHorizontalAlignment( SwingConstants.CENTER );
|
||||
avatarLabel.setMaximumSize( new Dimension( Integer.MAX_VALUE, 0 ) );
|
||||
avatarLabel.setToolTipText( "The avatar for your user. Click to change it." );
|
||||
add( avatarButton );
|
||||
avatarButton.setHorizontalAlignment( SwingConstants.CENTER );
|
||||
avatarButton.setMaximumSize( new Dimension( Integer.MAX_VALUE, 0 ) );
|
||||
avatarButton.setToolTipText( "The avatar for your user. Click to change it." );
|
||||
|
||||
// -
|
||||
add( Components.strut( Components.margin() ) );
|
||||
|
||||
// User Selection
|
||||
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 );
|
||||
add( userField );
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
MPFileUserManager.get().reload();
|
||||
usersModel.set( MPFileUserManager.get().getFiles() );
|
||||
// TODO: Should we use a listener here instead?
|
||||
usersModel.set( MPFileUserManager.get().reload() );
|
||||
}
|
||||
|
||||
public boolean addListener(final Listener listener) {
|
||||
return listeners.add( listener );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void itemStateChanged(final ItemEvent e) {
|
||||
if (e.getStateChange() != ItemEvent.SELECTED)
|
||||
private void setAvatar() {
|
||||
MPUser<?> selectedUser = usersModel.getSelectedItem();
|
||||
if (selectedUser == null)
|
||||
return;
|
||||
|
||||
MPUser<?> selectedUser = usersModel.getSelectedItem();
|
||||
avatarLabel.setIcon( Res.avatar( (selectedUser == null)? 0: selectedUser.getAvatar() ) );
|
||||
selectedUser.setAvatar( (selectedUser.getAvatar() + 1) % Res.icons().avatars() );
|
||||
avatarButton.setIcon( Res.icons().avatar( selectedUser.getAvatar() ) );
|
||||
}
|
||||
|
||||
public void setUser(@Nullable final MPUser<?> user) {
|
||||
avatarButton.setIcon( Res.icons().avatar( (user == null)? 0: user.getAvatar() ) );
|
||||
|
||||
for (final Listener listener : listeners)
|
||||
listener.onUserSelected( selectedUser );
|
||||
listener.onUserSelected( user );
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
|
||||
void onUserSelected(@Nullable MPUser<?> selectedUser);
|
||||
void onUserSelected(@Nullable MPUser<?> user);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package com.lyndir.masterpassword.gui.view;
|
||||
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import com.lyndir.masterpassword.gui.Res;
|
||||
import com.lyndir.masterpassword.gui.util.Res;
|
||||
import com.lyndir.masterpassword.gui.util.Components;
|
||||
import com.lyndir.masterpassword.model.MPUser;
|
||||
import java.awt.*;
|
||||
@ -50,8 +50,8 @@ public class MasterPasswordFrame extends JFrame implements FilesPanel.Listener,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserSelected(@Nullable final MPUser<?> selectedUser) {
|
||||
userPanel.setUser( selectedUser );
|
||||
public void onUserSelected(@Nullable final MPUser<?> user) {
|
||||
userPanel.setUser( user );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3,10 +3,11 @@ package com.lyndir.masterpassword.gui.view;
|
||||
import static com.lyndir.lhunath.opal.system.util.StringUtils.*;
|
||||
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.primitives.UnsignedInteger;
|
||||
import com.lyndir.lhunath.opal.system.logging.Logger;
|
||||
import com.lyndir.masterpassword.*;
|
||||
import com.lyndir.masterpassword.gui.Res;
|
||||
import com.lyndir.masterpassword.gui.util.Res;
|
||||
import com.lyndir.masterpassword.gui.util.CollectionListModel;
|
||||
import com.lyndir.masterpassword.gui.util.Components;
|
||||
import com.lyndir.masterpassword.model.*;
|
||||
@ -30,6 +31,7 @@ import javax.swing.event.*;
|
||||
/**
|
||||
* @author lhunath, 2018-07-14
|
||||
*/
|
||||
@SuppressWarnings("SerializableStoresNonSerializable")
|
||||
public class UserPanel extends Components.GradientPanel implements MPUser.Listener {
|
||||
|
||||
private static final Logger logger = Logger.get( UserPanel.class );
|
||||
@ -212,8 +214,12 @@ public class UserPanel extends Components.GradientPanel implements MPUser.Listen
|
||||
|
||||
this.user = user;
|
||||
|
||||
add( Components.heading( user.getFullName(), SwingConstants.CENTER ) );
|
||||
add( Components.strut() );
|
||||
add( new Components.GradientPanel( new BorderLayout() ) {
|
||||
{
|
||||
add( Components.heading( user.getFullName(), SwingConstants.CENTER ), BorderLayout.CENTER );
|
||||
add( Components.button( Res.icons().user(), event -> showPreferences() ), BorderLayout.LINE_END );
|
||||
}
|
||||
} );
|
||||
|
||||
add( passwordLabel );
|
||||
add( passwordField );
|
||||
@ -237,6 +243,25 @@ public class UserPanel extends Components.GradientPanel implements MPUser.Listen
|
||||
add( Box.createGlue() );
|
||||
}
|
||||
|
||||
public void showPreferences() {
|
||||
ImmutableList.Builder<Component> components = ImmutableList.builder();
|
||||
|
||||
MPFileUser fileUser = (user instanceof MPFileUser)? (MPFileUser) user: null;
|
||||
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( this, user.getFullName(), new JOptionPane( Components.panel(
|
||||
BoxLayout.PAGE_AXIS, components.build().toArray( new Component[0] ) ) ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(final ActionEvent event) {
|
||||
MPSite<?> site = sitesList.getSelectedValue();
|
||||
|
@ -67,13 +67,13 @@ public class MPFileUserManager {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
public ImmutableSortedSet<MPFileUser> reload() {
|
||||
userByName.clear();
|
||||
|
||||
File[] pathFiles;
|
||||
if ((!path.exists() && !path.mkdirs()) || ((pathFiles = path.listFiles()) == null)) {
|
||||
logger.err( "Couldn't create directory for user files: %s", path );
|
||||
return;
|
||||
return getFiles();
|
||||
}
|
||||
|
||||
for (final File file : pathFiles)
|
||||
@ -89,6 +89,8 @@ public class MPFileUserManager {
|
||||
catch (final IOException | MPMarshalException e) {
|
||||
logger.err( e, "Couldn't read user from: %s", file );
|
||||
}
|
||||
|
||||
return getFiles();
|
||||
}
|
||||
|
||||
public MPFileUser add(final String fullName) {
|
||||
|
Loading…
Reference in New Issue
Block a user