All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.vectorpublish.desktop.vp.impl.AskDialog Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2016, Peter Rader. All rights reserved.
 *  ___ ___               __                 ______         __     __  __         __
 * |   |   |.-----..----.|  |_ .-----..----.|   __ \.--.--.|  |--.|  ||__|.-----.|  |--.
 * |   |   ||  -__||  __||   _||  _  ||   _||    __/|  |  ||  _  ||  ||  ||__ --||     |
 *  \_____/ |_____||____||____||_____||__|  |___|   |_____||_____||__||__||_____||__|__|
 *
 * http://www.gnu.org/licenses/gpl-3.0.html
 */
package net.vectorpublish.desktop.vp.impl;

import java.awt.Color;
import java.awt.Container;
import java.awt.Dialog.ModalExclusionType;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;

import net.vectorpublish.desktop.vp.system.LayoutAdapter;

public class AskDialog extends JFrame {
	public final static int SPACING_BETWEEN_COMPONENTS = 5;
	public final static int BUTTON_HEIGHT = 36;
	public final static int COLOR_CHOOSER_HEIGHT = 200;
	public static final int FILTER_MINIMUM_SIZE = 8;

	private final class LayoutAskDialog extends LayoutAdapter {

		@Override
		public void layoutContainer(final Container parent) {
			if (parent == scrollablePanel) {
				parent.setSize(getContentPane().getWidth(), 10);
			}
			final int width = parent.getWidth();
			final int height = parent.getHeight();
			final int halfWidth = (width - SPACING_BETWEEN_COMPONENTS * 3) / 2;
			if (parent == scrollablePanel) {
				int yPos = 0;
				final int minusWidth = scroll.getVerticalScrollBar().getWidth() + 20;
				Iterator iterator = rows.iterator();
				while (iterator.hasNext()) {
					AskDialog.Row row = (AskDialog.Row) iterator.next();
					if (row == filterRow) {
						if (!showFilter()) {
							continue;
						}
					}
					int rowHeight = BUTTON_HEIGHT;
					if (row.component instanceof JColorChooser) {
						rowHeight = COLOR_CHOOSER_HEIGHT;
					}
					row.label.setBounds(SPACING_BETWEEN_COMPONENTS, yPos, halfWidth, rowHeight);
					row.component.setBounds(SPACING_BETWEEN_COMPONENTS * 2 + halfWidth, yPos, halfWidth - minusWidth,
							rowHeight);
					yPos += rowHeight + SPACING_BETWEEN_COMPONENTS;
				}
				scroll.setBounds(0, 0, contentPane.getWidth(), contentPane.getHeight() - BUTTON_HEIGHT);
				final Dimension s = new Dimension(getContentPane().getWidth() - minusWidth, yPos);
				parent.setSize(s);
				parent.setPreferredSize(s);
			} else {

				cancel.setBounds(SPACING_BETWEEN_COMPONENTS, height - SPACING_BETWEEN_COMPONENTS - BUTTON_HEIGHT,
						halfWidth, BUTTON_HEIGHT);
				ok.setBounds(width - halfWidth - SPACING_BETWEEN_COMPONENTS,
						height - SPACING_BETWEEN_COMPONENTS - BUTTON_HEIGHT, halfWidth, BUTTON_HEIGHT);

			}
		}
	}

	private class Row {
		protected final JLabel label;

		protected final T component;

		public final String question;

		private Row(final String ask, final T comp) {
			question = ask;
			component = comp;
			label = new JLabel(question);
			label.setVerticalAlignment(SwingConstants.CENTER);
			label.setHorizontalTextPosition(SwingConstants.RIGHT);
			scrollablePanel.add(label);
			scrollablePanel.add(comp);
		}

		public R getValue() {
			if (component instanceof JSpinner) {
				final JSpinner number = (JSpinner) component;
				return (R) number.getValue();
			} else if (component instanceof JTextArea) {
				final JTextArea text = (JTextArea) component;
				return (R) text.getText();
			} else if (component instanceof JCheckBox) {
				final JCheckBox check = (JCheckBox) component;
				return (R) (Boolean) check.isSelected();
			} else if (component instanceof JColorChooser) {
				final JColorChooser color = (JColorChooser) component;
				return (R) color.getColor();
			} else if (component instanceof JComboBox) {
				final JComboBox box = (JComboBox) component;
				return (R) box.getSelectedItem();
			} else
				return null;
		}

		protected void unregister() {
			scrollablePanel.remove(label);
			scrollablePanel.remove(component);
		}
	}

	private class RegexFilterRow extends Row implements DocumentListener {
		public RegexFilterRow() {
			super("Filter", new JTextArea());
			component.setHighlighter(new DefaultHighlighter());
			component.getBackground();
			component.getDocument().addDocumentListener(this);
		}

		@Override
		@Deprecated
		protected void unregister() {
			super.unregister();
		}

		public void revalidate() {
			synchronized (this) {
				boolean visible = showFilter();
				component.setVisible(visible);
				label.setVisible(visible);
			}
		}

		@Override
		public void insertUpdate(DocumentEvent e) {
			update();
		}

		private void update() {
			Pattern compile = null;
			try {
				compile = Pattern.compile(component.getText());
				component.getHighlighter().removeAllHighlights();
			} catch (PatternSyntaxException e) {
				try {
					component.getHighlighter().addHighlight(e.getIndex(), 1, DefaultHighlighter.DefaultPainter);
				} catch (BadLocationException range) {
					try {
						component.getHighlighter().addHighlight(0, 0, DefaultHighlighter.DefaultPainter);
					} catch (BadLocationException e2) {
						throw new RuntimeException(e2);
					}
				}
			}
			for (Row row : rows) {
				if (row == this) {
					continue;
				}
				if (compile != null) {
					boolean mark = compile.matcher(row.question).matches();
					row.label.setForeground(mark ? Color.BLACK : Color.LIGHT_GRAY);
				} else {
					row.label.setForeground(Color.BLACK);
				}
			}
			repaint();
		}

		@Override
		public void removeUpdate(DocumentEvent e) {
			update();
		}

		@Override
		public void changedUpdate(DocumentEvent e) {
			update();
		}

	}

	private boolean showFilter() {
		return rows.size() >= FILTER_MINIMUM_SIZE;
	}

	private final LinkedHashSet rows = new LinkedHashSet<>();

	private final JButton cancel = new JButton(new AbstractAction("Cancel") {
		@Override
		public void actionPerformed(ActionEvent event) {
			synchronized (rows) {
				Iterator rowIter = rows.iterator();
				while (rowIter.hasNext()) {
					Row row = rowIter.next();
					if (row != filterRow) {
						row.unregister();
						rowIter.remove();
					}
				}
				filterRow.revalidate();
			}
			setVisible(false);
			doLayout();
		}
	});
	private final JButton ok = new JButton(new AbstractAction("OK") {
		@Override
		public void actionPerformed(ActionEvent event) {
			setVisible(false);
		}
	});
	private final JPanel scrollablePanel = new JPanel();
	private final JScrollPane scroll = new JScrollPane(scrollablePanel);
	private final Container contentPane = getContentPane();
	private final RegexFilterRow filterRow = new RegexFilterRow();

	public AskDialog() {
		super();
		setAlwaysOnTop(true);
		final LayoutAskDialog layout = new LayoutAskDialog();
		contentPane.setLayout(layout);

		setModalExclusionType(ModalExclusionType.TOOLKIT_EXCLUDE);
		contentPane.add(cancel);
		contentPane.add(scroll);
		scrollablePanel.setLayout(layout);
		contentPane.add(ok);
		setBackground(Color.red);
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent closeEvent) {
				AskDialog.this.setVisible(false);
			}
		});
		rows.add(filterRow);
	}

	public synchronized  void addQuestion(final String title, final String question, A... values) {
		Objects.requireNonNull(question);
		final JLabel label = new JLabel(question, JLabel.RIGHT);
		label.setVerticalAlignment(SwingConstants.CENTER);
		final JComponent input;
		A proposal;
		if (values.length == 1) {
			proposal = values[0];
			if (proposal instanceof Double) {
				final double number = (Double) proposal;
				input = new JSpinner(new SpinnerNumberModel(number, Double.MIN_VALUE, Double.MAX_VALUE, 0.1));
			
			} else if (proposal instanceof Number) {
				final Number number = (Number) proposal;
				input = new JSpinner(
						new SpinnerNumberModel(number.intValue(), Integer.MIN_VALUE, Integer.MAX_VALUE, 1));
			} else if (proposal instanceof String) {
				input = new JTextArea(proposal + "");
			} else if (proposal instanceof Boolean) {
				input = new JCheckBox(title, (Boolean) proposal);
			} else if (proposal instanceof Color) {
				final JColorChooser chooser = new JColorChooser((Color) proposal);
				chooser.setPreviewPanel(new JPanel());
				input = chooser;
			} else {
				throw new RuntimeException("Type not supported yet:" + proposal.getClass());
			}
		} else if (values.length > 1) {
			final JComboBox box = new JComboBox(values);
			box.setEditable(false);
			input = box;
		} else {
			throw new RuntimeException("Size not supported:" + values.length);
		}
		synchronized (rows) {
			rows.add(new Row(question, input));
		}
		filterRow.revalidate();
		doLayout();
	}

	/**
	 * This method is threadsafe.
	 */
	@SuppressWarnings("unchecked")
	public  A removeResult(String question) {
		synchronized (rows) {
			for (final Row row : rows) {
				if (row.question.equals(question)) {
					final A value = (A) row.getValue();
					row.unregister();
					rows.remove(row);
					filterRow.revalidate();
					return value;
				}
			}
		}
		return null;
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy