/*
* SleepArchiver - cross-platform data manager for Sleeptracker-series watches.
* Copyright (C) 2009-2011 Pavel Fatin <http://pavelfatin.com>
*
* This program 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.
*
* This program 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 com.pavelfatin.sleeparchiver.gui.conditions;
import com.pavelfatin.sleeparchiver.gui.editor.EditorDialog;
import com.pavelfatin.sleeparchiver.lang.Utilities;
import com.pavelfatin.sleeparchiver.model.Night;
import com.pavelfatin.sleeparchiver.swing.Builder;
import com.pavelfatin.sleeparchiver.swing.ListPopupHandler;
import com.pavelfatin.sleeparchiver.swing.MyDialog;
import com.pavelfatin.sleeparchiver.swing.MySelectionModel;
import org.jdesktop.application.Action;
import org.jdesktop.application.Application;
import org.jdesktop.application.SingleFrameApplication;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;
import java.util.List;
public class ConditionsDialog extends MyDialog {
private static final Dimension DEFAULT_SIZE = new Dimension(380, 280);
private JList _list;
private DefaultListModel _model;
private MySelectionModel _selection;
private boolean _editEnabled;
private boolean _removeEnabled;
private List<Night> _nights;
private List<Night> _originals;
public ConditionsDialog(JFrame owner, List<Night> nights) {
super(owner, "dialogConditions", true);
setPreferredSize(DEFAULT_SIZE);
_originals = Collections.unmodifiableList(nights);
setContent(createUI());
Utilities.registerAction(_list, getAction("edit"), "ACTION_EDIT");
Utilities.registerAction(_list, getAction("remove"), "ACTION_REMOVE");
setNights(nights);
}
protected JPanel createUI() {
Builder b = new Builder("default:grow",
"fill:default:grow");
b.add(createManager(), 1, 1);
return b.getPanel();
}
private JPanel createManager() {
Builder b = new Builder("default:grow, $lcgap, default",
"fill:default:grow");
_list = createList();
b.add(new JScrollPane(_list), 1, 1);
b.add(createButtons(), 3, 1);
return b.getPanel();
}
private JList createList() {
_model = new DefaultListModel();
_selection = new MySelectionModel();
_selection.addListSelectionListener(new SelectionListener());
JList list = Builder.createList("listConditions");
list.setModel(_model);
list.setSelectionModel(_selection);
list.addMouseListener(new ListClickListener());
PopupMenu menu = new PopupMenu(getActions());
list.addMouseListener(new ListPopupHandler(list, menu));
return list;
}
private JPanel createButtons() {
Builder b = new Builder("default",
"default, $lgap, default");
b.add(b.createButton(getAction("edit")), 1, 1);
b.add(b.createButton(getAction("remove")), 1, 3);
return b.getPanel();
}
private void setNights(List<Night> nights) {
_nights = new ArrayList<Night>(nights);
List<String> conditions = conditionsOf(nights);
setStrings(conditions);
setModified(isDataChanged());
}
private List<String> conditionsOf(List<Night> nights) {
Set<String> unique = new HashSet<String>();
for (Night night : nights) {
unique.addAll(night.getConditions());
}
List<String> list = new ArrayList<String>(unique);
Collections.sort(list);
return list;
}
private void setStrings(List<String> list) {
_model.clear();
for (String s : list) {
_model.addElement(s);
}
_list.setSelectedIndex(list.isEmpty() ? -1 : 0);
}
protected boolean isDataChanged() {
return !_originals.equals(_nights);
}
@Action(enabledProperty = "editEnabled")
public void edit() {
EditorDialog editor = new EditorDialog(this, getResources().getString("titleEditCondition"));
String condition = (String) _list.getSelectedValue();
editor.setText(condition);
((SingleFrameApplication) Application.getInstance()).show(editor);
if (editor.isAccepted()) {
String replacement = editor.getText();
if (isSafeToReplace(condition, replacement)) {
List<Night> data = doEdit(_nights, condition, replacement);
setNights(data);
_list.setSelectedValue(replacement, true);
}
}
}
private boolean isSafeToReplace(String condition, String replacement) {
if (conditionsOf(_nights).contains(replacement)) {
String format = getResources().getString("messageConditionExists");
int result = JOptionPane.showConfirmDialog(this,
String.format(format, condition, replacement),
getResources().getString("titleConditionExists"),
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
return result == JOptionPane.YES_OPTION;
}
return true;
}
private List<Night> doEdit(List<Night> nights, String condition, String replacement) {
List<Night> result = new ArrayList<Night>();
for (Night night : nights) {
List<String> conditions = new ArrayList<String>(night.getConditions());
if (conditions.contains(condition)) {
conditions.set(conditions.indexOf(condition), replacement);
}
Collections.sort(conditions);
result.add(night.with(conditions));
}
return result;
}
@Action(enabledProperty = "removeEnabled")
public void remove() {
Object[] values = _list.getSelectedValues();
int selection = _list.getSelectedIndex();
List<Night> data = doRemove(_nights, values);
setNights(data);
int size = _list.getModel().getSize();
_list.setSelectedIndex(selection < size ? selection : size - 1);
}
private List<Night> doRemove(List<Night> nights, Object[] conditions) {
List<Night> result = new ArrayList<Night>();
for (Night night : nights) {
List<String> copy = new ArrayList<String>(night.getConditions());
for (Object condition : conditions) {
copy.remove(condition);
}
result.add(night.with(copy));
}
return result;
}
public boolean isEditEnabled() {
return _editEnabled;
}
private void setEditEnabled(boolean enabled) {
boolean previous = _editEnabled;
_editEnabled = enabled;
firePropertyChange("editEnabled", previous, enabled);
}
public boolean isRemoveEnabled() {
return _removeEnabled;
}
private void setRemoveEnabled(boolean enabled) {
boolean previous = _removeEnabled;
_removeEnabled = enabled;
firePropertyChange("removeEnabled", previous, enabled);
}
private void updateListActions() {
setEditEnabled(_selection.isSelectionSingle());
setRemoveEnabled(_selection.isSelectionExists());
}
public List<Night> getData() {
return Collections.unmodifiableList(_nights);
}
private class SelectionListener implements ListSelectionListener {
public void valueChanged(ListSelectionEvent e) {
updateListActions();
}
}
private class ListClickListener extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() > 1) {
if (isEditEnabled()) {
getActions().get("edit").actionPerformed(new ActionEvent(ConditionsDialog.this, 0, null));
}
}
}
}
}