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