/* * Copyright (c) 1998-2017 by Richard A. Wilkes. All rights reserved. * * This Source Code Form is subject to the terms of the Mozilla Public * License, version 2.0. If a copy of the MPL was not distributed with * this file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This Source Code Form is "Incompatible With Secondary Licenses", as * defined by the Mozilla Public License, version 2.0. */ package com.trollworks.gcs.widgets.outline; import com.trollworks.toolkit.annotation.Localize; import com.trollworks.toolkit.ui.border.EmptyBorder; import com.trollworks.toolkit.ui.layout.ColumnLayout; import com.trollworks.toolkit.ui.layout.RowDistribution; import com.trollworks.toolkit.ui.widget.ActionPanel; import com.trollworks.toolkit.ui.widget.Commitable; import com.trollworks.toolkit.ui.widget.WindowUtils; import com.trollworks.toolkit.utility.Localization; import java.awt.BorderLayout; import java.awt.Component; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingConstants; /** * The base class for all row editors. * * @param <T> The row class being edited. */ public abstract class RowEditor<T extends ListRow> extends ActionPanel { @Localize("Edit {0}") @Localize(locale = "de", value = "Bearbeite {0}") @Localize(locale = "ru", value = "Изменить {0}") @Localize(locale = "es", value = "Editar {0}") private static String WINDOW_TITLE; @Localize("Cancel Remaining") @Localize(locale = "de", value = "Alles Abbrechen") @Localize(locale = "ru", value = "Пропустить остальные") @Localize(locale = "es", value = "Cancelar lo restante") private static String CANCEL_REST; @Localize("Cancel") @Localize(locale = "de", value = "Abbrechen") @Localize(locale = "ru", value = "Отмена") @Localize(locale = "es", value = "Cancelar") private static String CANCEL; @Localize("Apply") @Localize(locale = "de", value = "Anwenden") @Localize(locale = "ru", value = "Применить") @Localize(locale = "es", value = "Aplicar") private static String APPLY; @Localize("1 item remaining to be edited.") @Localize(locale = "de", value = "1 weiteres Element zu bearbeiten.") @Localize(locale = "ru", value = "осталось отредактировать 1 элемент.") @Localize(locale = "es", value = "Queda un elemento pendiente de editar") private static String ONE_REMAINING; @Localize("{0} items remaining to be edited.") @Localize(locale = "de", value = "{0} weitere Elemente zu bearbeiten.") @Localize(locale = "ru", value = "{0} элементов осталось отредактировать.") @Localize(locale = "es", value = "Quedan {0} elementos pendientes de editar") private static String REMAINING; static { Localization.initialize(); } private static HashMap<Class<?>, String> LAST_TAB_MAP = new HashMap<>(); /** Whether the underlying data should be editable. */ protected boolean mIsEditable; /** The row being edited. */ protected T mRow; /** * Brings up a modal detailed editor for each row in the list. * * @param owner The owning component. * @param list The rows to edit. * @return Whether anything was modified. */ @SuppressWarnings("unused") static public boolean edit(Component owner, List<? extends ListRow> list) { ArrayList<RowUndo> undos = new ArrayList<RowUndo>(); ListRow[] rows = list.toArray(new ListRow[0]); for (int i = 0; i < rows.length; i++) { boolean hasMore = i != rows.length - 1; ListRow row = rows[i]; RowEditor<? extends ListRow> editor = row.createEditor(); String title = MessageFormat.format(WINDOW_TITLE, row.getRowType()); JPanel wrapper = new JPanel(new BorderLayout()); if (hasMore) { int remaining = rows.length - i - 1; String msg = remaining == 1 ? ONE_REMAINING : MessageFormat.format(REMAINING, new Integer(remaining)); JLabel panel = new JLabel(msg, SwingConstants.CENTER); panel.setBorder(new EmptyBorder(0, 0, 10, 0)); wrapper.add(panel, BorderLayout.NORTH); } wrapper.add(editor, BorderLayout.CENTER); int type = hasMore ? JOptionPane.YES_NO_CANCEL_OPTION : JOptionPane.YES_NO_OPTION; String[] options = hasMore ? new String[] { APPLY, CANCEL, CANCEL_REST } : new String[] { APPLY, CANCEL }; switch (WindowUtils.showOptionDialog(owner, wrapper, title, true, type, JOptionPane.PLAIN_MESSAGE, null, options, APPLY)) { case JOptionPane.YES_OPTION: RowUndo undo = new RowUndo(row); if (editor.applyChanges()) { if (undo.finish()) { undos.add(undo); } } break; case JOptionPane.NO_OPTION: break; case JOptionPane.CANCEL_OPTION: case JOptionPane.CLOSED_OPTION: default: i = rows.length; break; } editor.finished(); } if (!undos.isEmpty()) { new MultipleRowUndo(undos); return true; } return false; } /** * Creates a new {@link RowEditor}. * * @param row The row being edited. */ protected RowEditor(T row) { super(new ColumnLayout(1, 0, 5, RowDistribution.GIVE_EXCESS_TO_LAST)); mRow = row; mIsEditable = !mRow.getOwner().isLocked(); } /** @return The last tab showing for this specific row editor class. */ public String getLastTabName() { return LAST_TAB_MAP.get(getClass()); } /** @param name The last tab showing for this specific row editor class. */ public void updateLastTabName(String name) { LAST_TAB_MAP.put(getClass(), name); } /** * Called to apply any changes that were made. * * @return Whether anything was modified. */ public final boolean applyChanges() { Commitable.sendCommitToFocusOwner(); boolean modified = applyChangesSelf(); if (modified) { mRow.getDataFile().setModified(true); } return modified; } /** * Called to apply any changes that were made. * * @return Whether anything was modified. */ protected abstract boolean applyChangesSelf(); /** Called when the editor is no longer needed. */ public abstract void finished(); }