/* * 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.spell; import com.trollworks.gcs.character.GURPSCharacter; import com.trollworks.gcs.prereq.PrereqsPanel; import com.trollworks.gcs.skill.SkillAttribute; import com.trollworks.gcs.skill.SkillDifficulty; import com.trollworks.gcs.skill.SkillLevel; import com.trollworks.gcs.weapon.MeleeWeaponEditor; import com.trollworks.gcs.weapon.RangedWeaponEditor; import com.trollworks.gcs.weapon.WeaponStats; import com.trollworks.gcs.widgets.outline.RowEditor; import com.trollworks.toolkit.annotation.Localize; import com.trollworks.toolkit.ui.UIUtilities; import com.trollworks.toolkit.ui.layout.ColumnLayout; import com.trollworks.toolkit.ui.widget.LinkedLabel; import com.trollworks.toolkit.ui.widget.outline.OutlineModel; import com.trollworks.toolkit.utility.Localization; import com.trollworks.toolkit.utility.text.NumberFilter; import com.trollworks.toolkit.utility.text.Numbers; import com.trollworks.toolkit.utility.text.Text; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JTextField; import javax.swing.SwingConstants; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.Document; /** The detailed editor for {@link Spell}s. */ public class SpellEditor extends RowEditor<Spell> implements ActionListener, DocumentListener { @Localize("Name") @Localize(locale = "de", value = "Name") @Localize(locale = "ru", value = "Название") @Localize(locale = "es", value = "Nombre") private static String NAME; @Localize("The name of the spell, without any notes") @Localize(locale = "de", value = "Der Name des Zaubers ohne Anmerkungen") @Localize(locale = "ru", value = "Название заклинания без заметок") @Localize(locale = "es", value = "Nombre del sortilegio, sin notas ni otra información") private static String NAME_TOOLTIP; @Localize("The name field may not be empty") @Localize(locale = "de", value = "Der Name darf nicht leer sein") @Localize(locale = "ru", value = "Поле \"Название\" не может быть пустым") @Localize(locale = "es", value = "El nombre no puede estar en blanco") private static String NAME_CANNOT_BE_EMPTY; @Localize("Tech Level") @Localize(locale = "de", value = "Techlevel") @Localize(locale = "ru", value = "Технологический уровень") @Localize(locale = "es", value = "Nivel Tecnológico") private static String TECH_LEVEL; @Localize("Whether this spell requires tech level specialization, and, if so, at what tech level it was learned") @Localize(locale = "de", value = "Ob dieser Zauber auf einen bestimmten Techlevel spezialisiert ist und wenn, mit welchem Techlevel er gelernt wurde") @Localize(locale = "ru", value = "Для заклинания необходима специализация с технологическим уровнем с указанием уровня изучения") @Localize(locale = "es", value = "Si el sortilegio requiere especialización por nivel tecnológico, este es para el que se ha aprendido") private static String TECH_LEVEL_TOOLTIP; @Localize("Tech Level Required") @Localize(locale = "de", value = "Techlevel benötigt") @Localize(locale = "ru", value = "Необходимый технологический уровень") @Localize(locale = "es", value = "Nivel tecnologíco requerido") private static String TECH_LEVEL_REQUIRED; @Localize("Whether this spell requires tech level specialization") @Localize(locale = "de", value = "Ob dieser Zauber auf einen bestimmten Techlevel spezialisiert ist") @Localize(locale = "ru", value = "Для заклинания необходима специализация с технологическим уровнем") @Localize(locale = "es", value = "Este sortilegio requiere especializarse por nivel tecnológico") private static String TECH_LEVEL_REQUIRED_TOOLTIP; @Localize("College") @Localize(locale = "de", value = "Schule") @Localize(locale = "ru", value = "Школа") @Localize(locale = "es", value = "Escuela") private static String COLLEGE; @Localize("The college the spell belongs to") @Localize(locale = "de", value = "Die Schule, die dieser Zauber angehört") @Localize(locale = "ru", value = "Школа, к которой относится заклинание") @Localize(locale = "es", value = "Escuela a la que pertenece el sortilegio") private static String COLLEGE_TOOLTIP; @Localize("Power Source") @Localize(locale = "de", value = "Energiequelle") @Localize(locale = "ru", value = "Источник силы") @Localize(locale = "es", value = "Fuente de Poder") private static String POWER_SOURCE; @Localize("The source of power for the spell") @Localize(locale = "de", value = "Die Quelle der Energie für den Zauber") @Localize(locale = "ru", value = "Источник силы для заклинания") @Localize(locale = "es", value = "Fuente de Poder para el sortilegio") private static String POWER_SOURCE_TOOLTIP; @Localize("Class") @Localize(locale = "de", value = "Klasse") @Localize(locale = "ru", value = "Класс") @Localize(locale = "es", value = "Tipo") private static String CLASS; @Localize("The class of spell (Area, Missile, etc.)") @Localize(locale = "de", value = "Die Klasse des Zaubers (Gebiet, Geschoss, usw.)") @Localize(locale = "ru", value = "Класс заклинания (областные, метательные и т.д.)") @Localize(locale = "es", value = "Tipo de sortilegio (Área, Proyectil, etc.)") private static String CLASS_ONLY_TOOLTIP; @Localize("The class field may not be empty") @Localize(locale = "de", value = "Die Klasse darf nicht leer sein") @Localize(locale = "ru", value = "Поле \"Класс\" не может быть пустым") @Localize(locale = "es", value = "El tipo no puede estar en blanco") private static String CLASS_CANNOT_BE_EMPTY; @Localize("Casting Cost") @Localize(locale = "de", value = "Zauberkosten") @Localize(locale = "ru", value = "Стоимость заклинания") @Localize(locale = "es", value = "Coste de lanzamiento") private static String CASTING_COST; @Localize("The casting cost of the spell") @Localize(locale = "de", value = "Die Kosten, um den Zauber zu wirken") @Localize(locale = "ru", value = "Стоимость сотворения заклинания") @Localize(locale = "es", value = "Coste de lanzar el sertilegio") private static String CASTING_COST_TOOLTIP; @Localize("The casting cost field may not be empty") @Localize(locale = "de", value = "Die Zauberkosten dürfen nicht leer sein") @Localize(locale = "ru", value = "Поле \"Мана-Стоимость\" не может быть пустым") @Localize(locale = "es", value = "El coste de mantenimiento no puede estar en blanco") private static String CASTING_COST_CANNOT_BE_EMPTY; @Localize("Maintenance Cost") @Localize(locale = "de", value = "Erhaltungskosten") @Localize(locale = "ru", value = "Стоимость обслуживания") @Localize(locale = "es", value = "Coste de mantenimiento") private static String MAINTENANCE_COST; @Localize("The cost to maintain a spell after its initial duration") @Localize(locale = "de", value = "Die Kosten, um den Zauber aufrecht zu erhalten") @Localize(locale = "ru", value = "Стоимость поддержки заклинания свыше исходной длительности") @Localize(locale = "es", value = "Coste para manterner el sortilegio superada la duración inicial") private static String MAINTENANCE_COST_TOOLTIP; @Localize("Casting Time") @Localize(locale = "de", value = "Zauberzeit") @Localize(locale = "ru", value = "Время сотворения") @Localize(locale = "es", value = "Tiempo para lanzar") private static String CASTING_TIME; @Localize("The casting time of the spell") @Localize(locale = "de", value = "Die Zeit, um den Zauber zu wirken") @Localize(locale = "ru", value = "Время сотворения заклинания") @Localize(locale = "es", value = "Tiempo necesario para lanzar el sortilegi") private static String CASTING_TIME_TOOLTIP; @Localize("The casting time field may not be empty") @Localize(locale = "de", value = "Die Zauberzeit darf nicht leer sein") @Localize(locale = "ru", value = "Поле \"Время сотворения\" не может быть пустым") @Localize(locale = "es", value = "El tiempo necesario para lanzar el sotilegio no puede estar en blanco") private static String CASTING_TIME_CANNOT_BE_EMPTY; @Localize("Duration") @Localize(locale = "de", value = "Dauer") @Localize(locale = "ru", value = "Длительность") @Localize(locale = "es", value = "Duración") private static String DURATION; @Localize("The duration of the spell once its cast") @Localize(locale = "de", value = "Die Dauer des Zaubers, nachdem er gewirkt wurde") @Localize(locale = "ru", value = "Длительность заклинания после сотворения") @Localize(locale = "es", value = "Duración del sortilegio una vez lanzado") private static String DURATION_TOOLTIP; @Localize("The duration field may not be empty") @Localize(locale = "de", value = "Die Dauer darf nicht leer sein") @Localize(locale = "ru", value = "Поле \"Длительность\" не может быть пустым") @Localize(locale = "es", value = "La duración no puede estar en blanco") private static String DURATION_CANNOT_BE_EMPTY; @Localize("Categories") @Localize(locale = "de", value = "Kategorie") @Localize(locale = "ru", value = "Категории") @Localize(locale = "es", value = "Categorías") private static String CATEGORIES; @Localize("The category or categories the spell belongs to (separate multiple categories with a comma)") @Localize(locale = "de", value = "Die Kategorie oder Kategorien, denen dieser Zauber angehört (trenne mehrere Kategorien mit einem Komma)") @Localize(locale = "ru", value = "Категория или категории, к которым относится заклинание (перечислить через запятую)") @Localize(locale = "es", value = "Categoría o categorías a las que pertenece el sortilegio (separa categorías multiples con una coma)") private static String CATEGORIES_TOOLTIP; @Localize("Notes") @Localize(locale = "de", value = "Anmerkungen") @Localize(locale = "ru", value = "Заметка") @Localize(locale = "es", value = "Notas") private static String NOTES; @Localize("Any notes that you would like to show up in the list along with this spell") @Localize(locale = "de", value = "Anmerkungen, die in der Liste neben dem Zauber erscheinen sollen") @Localize(locale = "ru", value = "Заметки, которые показываются в списке рядом с заклинанием") @Localize(locale = "es", value = "Cualquier nota que te gustaría que se mostrara junto al sortilegio") private static String NOTES_TOOLTIP; @Localize("Points") @Localize(locale = "de", value = "Punkte") @Localize(locale = "ru", value = "Очки") @Localize(locale = "es", value = "Puntos") private static String EDITOR_POINTS; @Localize("The number of points spent on this spell") @Localize(locale = "de", value = "Die Punkte, die für diesen Zauber aufgewendet wurden") @Localize(locale = "ru", value = "Потрачено на заклинание количество очков") @Localize(locale = "es", value = "Puntos consumidos en el sortilegio") private static String EDITOR_POINTS_TOOLTIP; @Localize("Level") @Localize(locale = "de", value = "Fertigkeitswert") @Localize(locale = "ru", value = "Уровень") @Localize(locale = "es", value = "Nivel") private static String EDITOR_LEVEL; @Localize("The spell level and relative spell level to roll against") @Localize(locale = "de", value = "Der Fertigkeitswert und relativer Fertigkeitswert des Zaubers, gegen die gewürfelt werden muss") @Localize(locale = "ru", value = "Уровень заклинания и относительный уровень заклинания для повторного броска") @Localize(locale = "es", value = "Nivel y nivel relativo del sortilegio a superar con la tirada") private static String EDITOR_LEVEL_TOOLTIP; @Localize("The attribute this spell is based on") private static String ATTRIBUTE_POPUP_TOOLTIP; @Localize("Difficulty") @Localize(locale = "de", value = "Schwierigkeit") @Localize(locale = "ru", value = "Сложность") @Localize(locale = "es", value = "Dificultad") private static String DIFFICULTY; @Localize("The difficulty of the spell") @Localize(locale = "de", value = "Die Schwierigkeit des Zaubers") @Localize(locale = "ru", value = "Сложность заклинания") @Localize(locale = "es", value = "Dificultad del sortilegio") private static String DIFFICULTY_TOOLTIP; @Localize("Page Reference") @Localize(locale = "de", value = "Seitenangabe") @Localize(locale = "ru", value = "Ссылка на страницу") @Localize(locale = "es", value = "Página de referencia") private static String EDITOR_REFERENCE; @Localize("A reference to the book and page this spell appears on (e.g. B22 would refer to \"Basic Set\", page 22)") @Localize(locale = "de", value = "Eine Referenz auf das Buch und die Seite, auf der dieser Zauber beschrieben wird (z.B. B22 würde auf \"Basic Set\" Seite 22 verweisen)") @Localize(locale = "ru", value = "Ссылка на страницу и книгу, описывающая заклинание (например B22 - книга \"Базовые правила\", страница 22)") @Localize(locale = "es", value = "Referencia al libro y página en donde se menciona el sortilegio (p.e. B22 se refiere al \"Manual Básico\", página 22)") private static String REFERENCE_TOOLTIP; static { Localization.initialize(); } private JTextField mNameField; private JTextField mCollegeField; private JTextField mPowerSourceField; private JTextField mClassField; private JTextField mCastingCostField; private JTextField mMaintenanceField; private JTextField mCastingTimeField; private JTextField mDurationField; private JComboBox<Object> mAttributePopup; private JComboBox<Object> mDifficultyCombo; private JTextField mNotesField; private JTextField mCategoriesField; private JTextField mPointsField; private JTextField mLevelField; private JTextField mReferenceField; private JTabbedPane mTabPanel; private PrereqsPanel mPrereqs; private JCheckBox mHasTechLevel; private JTextField mTechLevel; private String mSavedTechLevel; private MeleeWeaponEditor mMeleeWeapons; private RangedWeaponEditor mRangedWeapons; /** * Creates a new {@link Spell} editor. * * @param spell The {@link Spell} to edit. */ public SpellEditor(Spell spell) { super(spell); boolean notContainer = !spell.canHaveChildren(); Container content = new JPanel(new ColumnLayout(2)); Container fields = new JPanel(new ColumnLayout()); Container wrapper1 = new JPanel(new ColumnLayout(notContainer ? 3 : 2)); Container wrapper2 = new JPanel(new ColumnLayout(4)); Container wrapper3 = new JPanel(new ColumnLayout(2)); Container noGapWrapper = new JPanel(new ColumnLayout(2, 0, 0)); Container ptsPanel = null; JLabel icon = new JLabel(spell.getIcon(true)); Dimension size = new Dimension(); Container refParent = wrapper3; mNameField = createCorrectableField(wrapper1, wrapper1, NAME, spell.getName(), NAME_TOOLTIP); fields.add(wrapper1); if (notContainer) { createTechLevelFields(wrapper1); mCollegeField = createField(wrapper2, wrapper2, COLLEGE, spell.getCollege(), COLLEGE_TOOLTIP, 0); mPowerSourceField = createField(wrapper2, wrapper2, POWER_SOURCE, spell.getPowerSource(), POWER_SOURCE_TOOLTIP, 0); mClassField = createCorrectableField(wrapper2, wrapper2, CLASS, spell.getSpellClass(), CLASS_ONLY_TOOLTIP); mCastingCostField = createCorrectableField(wrapper2, wrapper2, CASTING_COST, spell.getCastingCost(), CASTING_COST_TOOLTIP); mMaintenanceField = createField(wrapper2, wrapper2, MAINTENANCE_COST, spell.getMaintenance(), MAINTENANCE_COST_TOOLTIP, 0); mCastingTimeField = createCorrectableField(wrapper2, wrapper2, CASTING_TIME, spell.getCastingTime(), CASTING_TIME_TOOLTIP); mDurationField = createCorrectableField(wrapper2, wrapper2, DURATION, spell.getDuration(), DURATION_TOOLTIP); fields.add(wrapper2); ptsPanel = createPointsFields(); fields.add(ptsPanel); refParent = ptsPanel; } mNotesField = createField(wrapper3, wrapper3, NOTES, spell.getNotes(), NOTES_TOOLTIP, 0); mCategoriesField = createField(wrapper3, wrapper3, CATEGORIES, spell.getCategoriesAsString(), CATEGORIES_TOOLTIP, 0); mReferenceField = createField(refParent, noGapWrapper, EDITOR_REFERENCE, mRow.getReference(), REFERENCE_TOOLTIP, 6); noGapWrapper.add(new JPanel()); refParent.add(noGapWrapper); fields.add(wrapper3); determineLargest(wrapper1, 2, size); determineLargest(wrapper2, 4, size); if (ptsPanel != null) { determineLargest(ptsPanel, 100, size); } determineLargest(wrapper3, 2, size); applySize(wrapper1, 2, size); applySize(wrapper2, 4, size); if (ptsPanel != null) { applySize(ptsPanel, 100, size); } applySize(wrapper3, 2, size); icon.setVerticalAlignment(SwingConstants.TOP); icon.setAlignmentY(-1f); content.add(icon); content.add(fields); add(content); if (notContainer) { mTabPanel = new JTabbedPane(); mPrereqs = new PrereqsPanel(mRow, mRow.getPrereqs()); mMeleeWeapons = MeleeWeaponEditor.createEditor(mRow); mRangedWeapons = RangedWeaponEditor.createEditor(mRow); Component panel = embedEditor(mPrereqs); mTabPanel.addTab(panel.getName(), panel); mTabPanel.addTab(mMeleeWeapons.getName(), mMeleeWeapons); mTabPanel.addTab(mRangedWeapons.getName(), mRangedWeapons); if (!mIsEditable) { UIUtilities.disableControls(mMeleeWeapons); UIUtilities.disableControls(mRangedWeapons); } UIUtilities.selectTab(mTabPanel, getLastTabName()); add(mTabPanel); } } private static void determineLargest(Container panel, int every, Dimension size) { int count = panel.getComponentCount(); for (int i = 0; i < count; i += every) { Dimension oneSize = panel.getComponent(i).getPreferredSize(); if (oneSize.width > size.width) { size.width = oneSize.width; } if (oneSize.height > size.height) { size.height = oneSize.height; } } } private static void applySize(Container panel, int every, Dimension size) { int count = panel.getComponentCount(); for (int i = 0; i < count; i += every) { UIUtilities.setOnlySize(panel.getComponent(i), size); } } private JScrollPane embedEditor(Component editor) { JScrollPane scrollPanel = new JScrollPane(editor); scrollPanel.setMinimumSize(new Dimension(500, 120)); scrollPanel.setName(editor.toString()); if (!mIsEditable) { UIUtilities.disableControls(editor); } return scrollPanel; } private void createTechLevelFields(Container parent) { OutlineModel owner = mRow.getOwner(); GURPSCharacter character = mRow.getCharacter(); boolean enabled = !owner.isLocked(); boolean hasTL; mSavedTechLevel = mRow.getTechLevel(); hasTL = mSavedTechLevel != null; if (!hasTL) { mSavedTechLevel = ""; //$NON-NLS-1$ } if (character != null) { JPanel wrapper = new JPanel(new ColumnLayout(2)); mHasTechLevel = new JCheckBox(TECH_LEVEL, hasTL); mHasTechLevel.setToolTipText(Text.wrapPlainTextForToolTip(TECH_LEVEL_TOOLTIP)); mHasTechLevel.setEnabled(enabled); mHasTechLevel.addActionListener(this); wrapper.add(mHasTechLevel); mTechLevel = new JTextField("9999"); //$NON-NLS-1$ UIUtilities.setOnlySize(mTechLevel, mTechLevel.getPreferredSize()); mTechLevel.setText(mSavedTechLevel); mTechLevel.setToolTipText(Text.wrapPlainTextForToolTip(TECH_LEVEL_TOOLTIP)); mTechLevel.setEnabled(enabled && hasTL); wrapper.add(mTechLevel); parent.add(wrapper); if (!hasTL) { mSavedTechLevel = character.getDescription().getTechLevel(); } } else { mTechLevel = new JTextField(mSavedTechLevel); mHasTechLevel = new JCheckBox(TECH_LEVEL_REQUIRED, hasTL); mHasTechLevel.setToolTipText(Text.wrapPlainTextForToolTip(TECH_LEVEL_REQUIRED_TOOLTIP)); mHasTechLevel.setEnabled(enabled); mHasTechLevel.addActionListener(this); parent.add(mHasTechLevel); } } @SuppressWarnings("unused") private Container createPointsFields() { boolean forCharacter = mRow.getCharacter() != null; boolean forTemplate = mRow.getTemplate() != null; JPanel panel = new JPanel(new ColumnLayout(forCharacter ? 10 : forTemplate ? 8 : 6)); JLabel label = new JLabel(DIFFICULTY, SwingConstants.RIGHT); label.setToolTipText(Text.wrapPlainTextForToolTip(DIFFICULTY_TOOLTIP)); panel.add(label); mAttributePopup = createComboBox(panel, SkillAttribute.values(), mRow.getAttribute(), ATTRIBUTE_POPUP_TOOLTIP); panel.add(new JLabel(" /")); //$NON-NLS-1$ mDifficultyCombo = createComboBox(panel, new Object[] { SkillDifficulty.H, SkillDifficulty.VH }, mRow.isVeryHard() ? SkillDifficulty.VH : SkillDifficulty.H, DIFFICULTY_TOOLTIP); if (forCharacter || forTemplate) { mPointsField = createField(panel, panel, EDITOR_POINTS, Integer.toString(mRow.getPoints()), EDITOR_POINTS_TOOLTIP, 4); new NumberFilter(mPointsField, false, false, false, 4); mPointsField.addActionListener(this); if (forCharacter) { mLevelField = createField(panel, panel, EDITOR_LEVEL, getDisplayLevel(mRow.getAttribute(), mRow.getLevel(), mRow.getRelativeLevel()), EDITOR_LEVEL_TOOLTIP, 7); mLevelField.setEnabled(false); } } return panel; } private JComboBox<Object> createComboBox(Container parent, Object[] items, Object selection, String tooltip) { JComboBox<Object> combo = new JComboBox<>(items); combo.setToolTipText(Text.wrapPlainTextForToolTip(tooltip)); combo.setSelectedItem(selection); combo.addActionListener(this); combo.setMaximumRowCount(items.length); UIUtilities.setOnlySize(combo, combo.getPreferredSize()); combo.setEnabled(mIsEditable); parent.add(combo); return combo; } private static String getDisplayLevel(SkillAttribute attribute, int level, int relativeLevel) { if (level < 0) { return "-"; //$NON-NLS-1$ } return Numbers.format(level) + "/" + attribute + Numbers.formatWithForcedSign(relativeLevel); //$NON-NLS-1$ } private JTextField createCorrectableField(Container labelParent, Container fieldParent, String title, String text, String tooltip) { JTextField field = new JTextField(text); field.setToolTipText(Text.wrapPlainTextForToolTip(tooltip)); field.setEnabled(mIsEditable); field.getDocument().addDocumentListener(this); LinkedLabel label = new LinkedLabel(title); label.setLink(field); labelParent.add(label); fieldParent.add(field); return field; } private JTextField createField(Container labelParent, Container fieldParent, String title, String text, String tooltip, int maxChars) { JTextField field = new JTextField(maxChars > 0 ? Text.makeFiller(maxChars, 'M') : text); if (maxChars > 0) { UIUtilities.setOnlySize(field, field.getPreferredSize()); field.setText(text); } field.setToolTipText(Text.wrapPlainTextForToolTip(tooltip)); field.setEnabled(mIsEditable); labelParent.add(new LinkedLabel(title, field)); fieldParent.add(field); return field; } @Override public boolean applyChangesSelf() { boolean modified = mRow.setName(mNameField.getText()); boolean notContainer = !mRow.canHaveChildren(); modified |= mRow.setReference(mReferenceField.getText()); if (notContainer) { if (mHasTechLevel != null) { modified |= mRow.setTechLevel(mHasTechLevel.isSelected() ? mTechLevel.getText() : null); } modified |= mRow.setCollege(mCollegeField.getText()); modified |= mRow.setPowerSource(mPowerSourceField.getText()); modified |= mRow.setSpellClass(mClassField.getText()); modified |= mRow.setCastingCost(mCastingCostField.getText()); modified |= mRow.setMaintenance(mMaintenanceField.getText()); modified |= mRow.setCastingTime(mCastingTimeField.getText()); modified |= mRow.setDuration(mDurationField.getText()); modified |= mRow.setDifficulty(getAttribute(), isVeryHard()); if (mRow.getCharacter() != null || mRow.getTemplate() != null) { modified |= mRow.setPoints(getSpellPoints()); } } modified |= mRow.setNotes(mNotesField.getText()); modified |= mRow.setCategories(mCategoriesField.getText()); if (mPrereqs != null) { modified |= mRow.setPrereqs(mPrereqs.getPrereqList()); } if (mMeleeWeapons != null) { ArrayList<WeaponStats> list = new ArrayList<>(mMeleeWeapons.getWeapons()); list.addAll(mRangedWeapons.getWeapons()); modified |= mRow.setWeapons(list); } return modified; } @Override public void finished() { if (mTabPanel != null) { updateLastTabName(mTabPanel.getTitleAt(mTabPanel.getSelectedIndex())); } } @Override public void actionPerformed(ActionEvent event) { Object src = event.getSource(); if (src == mHasTechLevel) { boolean enabled = mHasTechLevel.isSelected(); mTechLevel.setEnabled(enabled); if (enabled) { mTechLevel.setText(mSavedTechLevel); mTechLevel.requestFocus(); } else { mSavedTechLevel = mTechLevel.getText(); mTechLevel.setText(""); //$NON-NLS-1$ } } else if (src == mPointsField || src == mAttributePopup || src == mDifficultyCombo) { recalculateLevel(); } } private void recalculateLevel() { if (mLevelField != null) { SkillAttribute attribute = getAttribute(); SkillLevel level = Spell.calculateLevel(mRow.getCharacter(), getSpellPoints(), attribute, isVeryHard(), mCollegeField.getText(), mPowerSourceField.getText(), mNameField.getText()); mLevelField.setText(getDisplayLevel(attribute, level.mLevel, level.mRelativeLevel)); } } private int getSpellPoints() { return Numbers.extractInteger(mPointsField.getText(), 0, true); } private SkillAttribute getAttribute() { return (SkillAttribute) mAttributePopup.getSelectedItem(); } private boolean isVeryHard() { return mDifficultyCombo.getSelectedItem() == SkillDifficulty.VH; } @Override public void changedUpdate(DocumentEvent event) { Document doc = event.getDocument(); if (doc == mNameField.getDocument()) { LinkedLabel.setErrorMessage(mNameField, mNameField.getText().trim().length() != 0 ? null : NAME_CANNOT_BE_EMPTY); } else if (doc == mClassField.getDocument()) { LinkedLabel.setErrorMessage(mClassField, mClassField.getText().trim().length() != 0 ? null : CLASS_CANNOT_BE_EMPTY); } else if (doc == mClassField.getDocument()) { LinkedLabel.setErrorMessage(mCastingCostField, mCastingCostField.getText().trim().length() != 0 ? null : CASTING_COST_CANNOT_BE_EMPTY); } else if (doc == mClassField.getDocument()) { LinkedLabel.setErrorMessage(mCastingTimeField, mCastingTimeField.getText().trim().length() != 0 ? null : CASTING_TIME_CANNOT_BE_EMPTY); } else if (doc == mClassField.getDocument()) { LinkedLabel.setErrorMessage(mDurationField, mDurationField.getText().trim().length() != 0 ? null : DURATION_CANNOT_BE_EMPTY); } } @Override public void insertUpdate(DocumentEvent event) { changedUpdate(event); } @Override public void removeUpdate(DocumentEvent event) { changedUpdate(event); } }