001package jmri.jmrit.operations; 002 003import java.awt.*; 004import java.awt.event.ActionEvent; 005import java.util.Optional; 006 007import javax.swing.*; 008import javax.swing.colorchooser.AbstractColorChooserPanel; 009import javax.swing.event.ChangeEvent; 010import javax.swing.table.TableModel; 011import javax.swing.table.TableRowSorter; 012 013import org.slf4j.Logger; 014import org.slf4j.LoggerFactory; 015 016import jmri.InstanceManager; 017import jmri.jmrit.operations.rollingstock.cars.CarTypes; 018import jmri.jmrit.operations.trains.TrainCommon; 019import jmri.swing.JTablePersistenceManager; 020import jmri.util.JmriJFrame; 021import jmri.util.swing.SplitButtonColorChooserPanel; 022 023/** 024 * Panel for operations 025 * 026 * @author Dan Boudreau Copyright (C) 2008, 2012 027 */ 028public class OperationsPanel extends JPanel { 029 030 public static final String NEW_LINE = "\n"; // NOI18N 031 public static final String NONE = ""; // NOI18N 032 033 public OperationsPanel() { 034 super(); 035 } 036 037 public void dispose() { 038 // The default method does nothing. 039 } 040 041 protected void addItem(JComponent c, int x, int y) { 042 GridBagConstraints gc = new GridBagConstraints(); 043 gc.gridx = x; 044 gc.gridy = y; 045 gc.weightx = 100.0; 046 gc.weighty = 100.0; 047 this.add(c, gc); 048 } 049 050 protected void addItem(JPanel p, JComponent c, int x, int y) { 051 GridBagConstraints gc = new GridBagConstraints(); 052 gc.gridx = x; 053 gc.gridy = y; 054 gc.weightx = 100.0; 055 gc.weighty = 100.0; 056 p.add(c, gc); 057 } 058 059 protected void addItemLeft(JPanel p, JComponent c, int x, int y) { 060 GridBagConstraints gc = new GridBagConstraints(); 061 gc.gridx = x; 062 gc.gridy = y; 063 gc.weightx = 100.0; 064 gc.weighty = 100.0; 065 gc.anchor = GridBagConstraints.WEST; 066 p.add(c, gc); 067 } 068 069 protected void addItemTop(JPanel p, JComponent c, int x, int y) { 070 GridBagConstraints gc = new GridBagConstraints(); 071 gc.gridx = x; 072 gc.gridy = y; 073 gc.weightx = 100; 074 gc.weighty = 100; 075 gc.anchor = GridBagConstraints.NORTH; 076 p.add(c, gc); 077 } 078 079 protected void addItemWidth(JPanel p, JComponent c, int width, int x, int y) { 080 GridBagConstraints gc = new GridBagConstraints(); 081 gc.gridx = x; 082 gc.gridy = y; 083 gc.gridwidth = width; 084 gc.weightx = 100.0; 085 gc.weighty = 100.0; 086 gc.anchor = GridBagConstraints.WEST; 087 p.add(c, gc); 088 } 089 090 private static final int MIN_CHECKBOXES = 5; 091 private static final int MAX_CHECKBOXES = 11; 092 093 protected int getNumberOfCheckboxesPerLine(Dimension size) { 094 if (size == null) { 095 return MIN_CHECKBOXES; // default is 6 checkboxes per row 096 } 097 StringBuilder padding = new StringBuilder("X"); 098 for (int i = 0; i < InstanceManager.getDefault(CarTypes.class).getMaxFullNameLength(); i++) { 099 padding.append("X"); 100 } 101 102 JCheckBox box = new JCheckBox(padding.toString()); 103 int number = size.width / (box.getPreferredSize().width); 104 if (number < MIN_CHECKBOXES) { 105 number = MIN_CHECKBOXES; 106 } 107 if (number > MAX_CHECKBOXES) { 108 number = MAX_CHECKBOXES; 109 } 110 return number; 111 } 112 113 protected void addButtonAction(JButton b) { 114 b.addActionListener((ActionEvent e) -> { 115 buttonActionPerformed(e); 116 }); 117 } 118 119 protected void buttonActionPerformed(ActionEvent ae) { 120 log.debug("button action not overridden"); 121 } 122 123 protected void addRadioButtonAction(JRadioButton b) { 124 b.addActionListener((ActionEvent e) -> { 125 radioButtonActionPerformed(e); 126 }); 127 } 128 129 protected void radioButtonActionPerformed(ActionEvent ae) { 130 log.debug("radio button action not overridden"); 131 } 132 133 protected void addCheckBoxAction(JCheckBox b) { 134 b.addActionListener((ActionEvent e) -> { 135 checkBoxActionPerformed(e); 136 }); 137 } 138 139 protected void checkBoxActionPerformed(ActionEvent ae) { 140 log.debug("check box action not overridden"); 141 } 142 143 protected void addSpinnerChangeListerner(JSpinner s) { 144 s.addChangeListener((ChangeEvent e) -> { 145 spinnerChangeEvent(e); 146 }); 147 } 148 149 protected void spinnerChangeEvent(javax.swing.event.ChangeEvent ae) { 150 log.debug("spinner action not overridden"); 151 } 152 153 protected void addComboBoxAction(JComboBox<?> b) { 154 b.addActionListener((ActionEvent e) -> { 155 comboBoxActionPerformed(e); 156 }); 157 } 158 159 protected void comboBoxActionPerformed(ActionEvent ae) { 160 log.debug("combobox action not overridden"); 161 } 162 163 protected void selectNextItemComboBox(JComboBox<?> b) { 164 int newIndex = b.getSelectedIndex() + 1; 165 if (newIndex < b.getItemCount()) { 166 b.setSelectedIndex(newIndex); 167 } 168 } 169 170 /** 171 * Will modify the character column width of a TextArea box to 90% of a 172 * panels width. ScrollPane is set to 95% of panel width. 173 * 174 * @param scrollPane the pane containing the textArea 175 * @param textArea the textArea to adjust 176 * @param size the preferred size 177 */ 178 protected void adjustTextAreaColumnWidth(JScrollPane scrollPane, JTextArea textArea, Dimension size) { 179 FontMetrics metrics = getFontMetrics(textArea.getFont()); 180 int columnWidth = metrics.charWidth('m'); 181 int width = size.width; 182 int columns = width / columnWidth * 90 / 100; // make text area 90% of the panel width 183 if (columns > textArea.getColumns()) { 184 log.debug("Increasing text area character width to {} columns", columns); 185 textArea.setColumns(columns); 186 } 187 scrollPane.setMinimumSize(new Dimension(width * 95 / 100, 60)); 188 } 189 190 /** 191 * Load the table width, position, and sorting status from the user 192 * preferences file. 193 * 194 * @param table The table to be adjusted. 195 */ 196 public void loadTableDetails(JTable table) { 197 loadTableDetails(table, getWindowFrameRef()); 198 persist(table); 199 } 200 201 public static void loadTableDetails(JTable table, String name) { 202 if (table.getRowSorter() == null) { 203 TableRowSorter<? extends TableModel> sorter = new TableRowSorter<>(table.getModel()); 204 table.setRowSorter(sorter); 205 // only sort on columns that are String, Integer or Boolean (check boxes) 206 for (int i = 0; i < table.getColumnCount(); i++) { 207 if (table.getColumnClass(i) == String.class || 208 table.getColumnClass(i) == Integer.class || 209 table.getColumnClass(i) == Boolean.class) { 210 continue; // allow sorting 211 } 212 sorter.setSortable(i, false); 213 } 214 } 215 // set row height 216 table.setRowHeight(new JComboBox<>().getPreferredSize().height); 217 // have to shut off autoResizeMode to get horizontal scroll to work (JavaSwing p 541) 218 table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 219 // give each cell a bit of space between the vertical lines and text 220 table.setIntercellSpacing(new Dimension(3, 1)); 221 // table must have a name 222 table.setName(name + ":table"); // NOI18N 223 Optional<JTablePersistenceManager> manager = InstanceManager.getOptionalDefault(JTablePersistenceManager.class); 224 if (manager.isPresent()) { 225 manager.get().resetState(table); 226 } 227 } 228 229 public static void persist(JTable table) { 230 Optional<JTablePersistenceManager> manager = InstanceManager.getOptionalDefault(JTablePersistenceManager.class); 231 if (manager.isPresent()) { 232 manager.get().persist(table); 233 } 234 } 235 236 public static void cacheState(JTable table) { 237 Optional<JTablePersistenceManager> manager = InstanceManager.getOptionalDefault(JTablePersistenceManager.class); 238 if (manager.isPresent()) { 239 manager.get().cacheState(table); 240 } 241 } 242 243 public static void saveTableState() { 244 Optional<JTablePersistenceManager> manager = InstanceManager.getOptionalDefault(JTablePersistenceManager.class); 245 if (manager.isPresent()) { 246 manager.get().setPaused(false); // cheater way to save preferences. 247 } 248 } 249 250 protected void clearTableSort(JTable table) { 251 if (table.getRowSorter() != null) { 252 table.getRowSorter().setSortKeys(null); 253 } 254 } 255 256 protected void storeValues() { 257 OperationsXml.save(); 258 } 259 260/* 261 * Kludge fix for horizontal scrollbar encroaching buttons at bottom of a scrollable window. 262 */ 263 protected void addHorizontalScrollBarKludgeFix(JScrollPane pane, JPanel panel) { 264 JPanel pad = new JPanel(); // kludge fix for horizontal scrollbar 265 pad.add(new JLabel(" ")); 266 panel.add(pad); 267 268 // make sure control panel is the right size 269 pane.setMinimumSize(new Dimension(500, 130)); 270 pane.setMaximumSize(new Dimension(2000, 170)); 271 pane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); 272 } 273 274 protected String getWindowFrameRef() { 275 Container c = this.getTopLevelAncestor(); 276 if (c instanceof JmriJFrame) { 277 return ((JmriJFrame) c).getWindowFrameRef(); 278 } 279 return null; 280 } 281 public static JPanel getColorChooserPanel(String text, JColorChooser chooser) { 282 return getColorChooserPanel(Bundle.getMessage("TextColor"), TrainCommon.getTextColor(text), chooser); 283 } 284 285 public static JPanel getColorChooserPanel(String title, Color color, JColorChooser chooser) { 286 JPanel pTextColorPanel = new JPanel(); 287 pTextColorPanel.setBorder(BorderFactory.createTitledBorder(title)); 288 chooser.setColor(color); 289 AbstractColorChooserPanel commentColorPanels[] = {new SplitButtonColorChooserPanel()}; 290 chooser.setChooserPanels(commentColorPanels); 291 chooser.setPreviewPanel(new JPanel()); 292 pTextColorPanel.add(chooser); 293 return pTextColorPanel; 294 } 295 296 public static void loadFontSizeComboBox(JComboBox<Integer> box) { 297 // load font sizes 7 through 18 298 for (int i = 7; i < 19; i++) { 299 box.addItem(i); 300 } 301 Dimension size = box.getPreferredSize(); 302 size = new Dimension(size.width + 10, size.height); 303 box.setPreferredSize(size); 304 } 305 306 private final static Logger log = LoggerFactory.getLogger(OperationsPanel.class); 307}