/**************************************************************************
OmegaT - Computer Assisted Translation (CAT) tool
with fuzzy matching, translation memory, keyword search,
glossaries, and translation leveraging into updated projects.
Copyright (C) 2014 Briac Pilpre
2015 Aaron Madlon-Kay
2016 Aaron Madlon-Kay
Home page: http://www.omegat.org/
Support center: http://groups.yahoo.com/group/OmegaT/
This file is part of OmegaT.
OmegaT is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OmegaT is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/
package org.omegat.gui.preferences.view;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.EnumMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import javax.swing.Icon;
import javax.swing.JColorChooser;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JSlider;
import javax.swing.JSpinner;
import javax.swing.colorchooser.AbstractColorChooserPanel;
import javax.swing.table.AbstractTableModel;
import org.omegat.gui.preferences.BasePreferencesController;
import org.omegat.util.OStrings;
import org.omegat.util.gui.Styles.EditorColor;
/**
* @author Briac Pilpre
* @author Aaron Madlon-Kay
*/
public class CustomColorSelectionController extends BasePreferencesController {
private static final int MAX_ROW_COUNT = 10;
private final Map<EditorColor, Color> temporaryPreferences = new EnumMap<>(EditorColor.class);
private ColorIcon icon;
private CustomColorSelectionPanel panel;
private boolean listenerEnabled = true;
@Override
public JComponent getGui() {
if (panel == null) {
initGui();
initFromPrefs();
}
return panel;
}
@Override
public String toString() {
return OStrings.getString("PREFS_TITLE_COLORS");
}
private void initGui() {
panel = new CustomColorSelectionPanel();
try {
removeTransparencySlider(panel.colorChooser);
} catch (Exception e) {
// Ignore
}
panel.colorChooser.getSelectionModel().addChangeListener(e -> {
if (listenerEnabled) {
recordTemporaryPreference();
}
});
panel.colorStylesTable.getSelectionModel().addListSelectionListener(e -> onSelectionChanged());
Dimension tableSize = panel.colorStylesTable.getPreferredSize();
panel.colorStylesTable.setPreferredScrollableViewportSize(
new Dimension(tableSize.width, panel.colorStylesTable.getRowHeight() * MAX_ROW_COUNT));
panel.colorStylesTable.setModel(new ColorTableModel());
icon = new ColorIcon(panel.colorStylesTable.getRowHeight());
panel.resetCurrentColorButton.addActionListener(e -> resetCurrentColor());
}
private Optional<EditorColor> getSelection() {
int row = panel.colorStylesTable.getSelectedRow();
if (row < 0) {
return Optional.empty();
} else {
ColorTableModel model = ((ColorTableModel) panel.colorStylesTable.getModel());
return Optional.of(model.getEditorColorAtRow(row));
}
}
private void recordTemporaryPreference() {
getSelection().ifPresent(style -> {
temporaryPreferences.put(style, panel.colorChooser.getColor());
setRestartRequired(hasChanges());
updateSelectionIcon();
});
}
private void updateSelectionIcon() {
int row = panel.colorStylesTable.getSelectedRow();
if (row >= 0) {
((ColorTableModel) panel.colorStylesTable.getModel()).fireTableRowsUpdated(row, row);
}
}
// Hide the Transparency Slider.
// From: http://stackoverflow.com/a/22608885
private static void removeTransparencySlider(JColorChooser jc) throws Exception {
AbstractColorChooserPanel[] colorPanels = jc.getChooserPanels();
for (int i = 1; i < colorPanels.length; i++) {
AbstractColorChooserPanel cp = colorPanels[i];
Field f = cp.getClass().getDeclaredField("panel");
f.setAccessible(true);
Object colorPanel = f.get(cp);
Field f2 = colorPanel.getClass().getDeclaredField("spinners");
f2.setAccessible(true);
Object spinners = f2.get(colorPanel);
Object transpSlispinner = Array.get(spinners, 3);
if (i == colorPanels.length - 1) {
transpSlispinner = Array.get(spinners, 4);
}
Field f3 = transpSlispinner.getClass().getDeclaredField("slider");
f3.setAccessible(true);
JSlider slider = (JSlider) f3.get(transpSlispinner);
slider.setEnabled(false);
slider.setVisible(false);
Field f4 = transpSlispinner.getClass().getDeclaredField("spinner");
f4.setAccessible(true);
JSpinner spinner = (JSpinner) f4.get(transpSlispinner);
spinner.setEnabled(false);
spinner.setVisible(false);
Field f5 = transpSlispinner.getClass().getDeclaredField("label");
f5.setAccessible(true);
JLabel label = (JLabel) f5.get(transpSlispinner);
label.setVisible(false);
}
}
private void setColorChooserWithoutNotifying(Color color) {
listenerEnabled = false;
panel.colorChooser.setColor(color == null ? Color.BLACK : color);
listenerEnabled = true;
}
private void onSelectionChanged() {
Optional<EditorColor> selection = getSelection();
boolean enabled = selection.isPresent();
panel.colorChooser.setEnabled(enabled);
panel.resetCurrentColorButton.setEnabled(enabled);
selection.ifPresent(style -> {
Color color = temporaryPreferences.getOrDefault(style, style.getColor());
setColorChooserWithoutNotifying(color);
});
}
private void resetCurrentColor() {
getSelection().ifPresent(style -> {
Color defaultColor = style.getDefault();
if (defaultColor == null) {
setColorChooserWithoutNotifying(Color.BLACK);
temporaryPreferences.put(style, null);
} else {
panel.colorChooser.setColor(defaultColor);
}
setRestartRequired(hasChanges());
updateSelectionIcon();
});
}
private boolean hasChanges() {
return !temporaryPreferences.entrySet().stream()
.allMatch(e -> Objects.equals(e.getKey().getColor(), e.getValue()));
}
@Override
public void restoreDefaults() {
for (EditorColor style : EditorColor.values()) {
temporaryPreferences.put(style, style.getDefault());
}
panel.colorStylesTable.repaint();
panel.colorStylesTable.clearSelection();
onSelectionChanged();
setRestartRequired(hasChanges());
}
@Override
protected void initFromPrefs() {
temporaryPreferences.clear();
panel.colorStylesTable.repaint();
panel.colorStylesTable.clearSelection();
onSelectionChanged();
}
@Override
public void persist() {
temporaryPreferences.entrySet().forEach(e -> e.getKey().setColor(e.getValue()));
}
enum ColorColumns {
NAME(String.class), ICON(Icon.class);
private final Class<?> clss;
private ColorColumns(Class<?> clss) {
this.clss = clss;
}
static ColorColumns get(int index) {
return values()[index];
}
}
static class ColorIcon implements Icon {
private final int size;
private Color color;
public ColorIcon(int size) {
this.size = size;
}
public ColorIcon setColor(Color color) {
this.color = color;
return this;
}
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
if (color != null) {
g.setColor(color);
g.fillRect(x, y, size, size);
} else {
g.setColor(Color.RED);
g.drawLine(x, y, x + size, y + size);
}
}
@Override
public int getIconWidth() {
return size;
}
@Override
public int getIconHeight() {
return size;
}
}
@SuppressWarnings("serial")
class ColorTableModel extends AbstractTableModel {
@Override
public int getRowCount() {
return EditorColor.values().length;
}
@Override
public int getColumnCount() {
return ColorColumns.values().length;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
EditorColor style = getEditorColorAtRow(rowIndex);
switch(ColorColumns.get(columnIndex)) {
case NAME:
return style.getDisplayName();
case ICON:
Color color = temporaryPreferences.getOrDefault(style, style.getColor());
return icon.setColor(color);
}
throw new IllegalArgumentException();
}
@Override
public Class<?> getColumnClass(int columnIndex) {
return ColorColumns.get(columnIndex).clss;
}
public EditorColor getEditorColorAtRow(int row) {
return EditorColor.values()[row];
}
}
}