Changeset 364

Show
Ignore:
Timestamp:
10-04-12 18:54:03 (2 years ago)
Author:
tim.te.beek@…
Message:

Transfer some change listeners to ParserSettingsModel? instead of ParsingTableModel?
Add initial implementation of assimilate() in PTM
Alter when what events are fired from parseFile
Update SaveableSettings? implementation to take an ParserSettingsModel? as argument
For persistence use ParsingTableModel? as argument rather than ParserSettingsModel?
Re-enable persistence tests

Location:
branches/alttableimport-model-rewrite
Files:
1 removed
11 modified

Legend:

Unmodified
Added
Removed
  • branches/alttableimport-model-rewrite/pom.xml

    r321 r364  
    3333                        <scope>provided</scope> 
    3434                </dependency> 
     35                <dependency> 
     36                        <groupId>commons-lang</groupId> 
     37                        <artifactId>commons-lang</artifactId> 
     38                        <version>2.4</version> 
     39                </dependency>            
    3540         
    3641                <!-- Actual packaged dependencies --> 
  • branches/alttableimport-model-rewrite/src/main/java/nl/nbic/brs/alttableimport/AlternativeTableImportPlugin.java

    r360 r364  
    2020import cytoscape.view.CyHelpBroker; 
    2121 
    22 import nl.nbic.brs.alttableimport.models.ParserSettingsModel; 
     22import nl.nbic.brs.alttableimport.models.ParsingTableModel; 
     23import nl.nbic.brs.alttableimport.persistence.SaveableSettings; 
    2324import nl.nbic.brs.alttableimport.persistence.SettingsPersistence; 
    2425import nl.nbic.brs.alttableimport.views.TableImportDialog; 
     
    7273                                                        if (profile != null && profile.canRead() && 0 < profile.length()) 
    7374                                                                try { 
    74                                                                         ParserSettingsModel settings = SettingsPersistence.loadSettings(profile); 
     75                                                                        SaveableSettings loadedSettings = SettingsPersistence.loadSettings(profile); 
    7576                                                                        // But only if we can read whatever file was used last: 
    7677                                                                        // we don't want to open the dialog with an error 
    77                                                                         if (settings.getTableFile().canRead()) { 
    78                                                                                 ;// TODO tableImportDialog.replaceSettings(settings); 
     78                                                                        if (loadedSettings.getTableFile().canRead()) { 
     79                                                                                tableImportDialog.getTableModel().assimilate(loadedSettings); 
    7980 
    8081                                                                                // Show LoggerDialog if any warnings were logged in setting the previous profile 
     
    122123                // Save current settings to a plugin specific settings file 
    123124                File profile = CytoscapeInit.getConfigFile(SETTINGS_PROFILE); 
    124                 ParserSettingsModel settings = tableImportDialog.getSettings(); 
     125                ParsingTableModel tableModel = tableImportDialog.getTableModel(); 
    125126                try { 
    126                         SettingsPersistence.saveSettings(profile, settings); 
     127                        SettingsPersistence.saveSettings(profile, tableModel); 
    127128                } 
    128129                catch (IOException e) { 
  • branches/alttableimport-model-rewrite/src/main/java/nl/nbic/brs/alttableimport/models/ParserSettingsModel.java

    r360 r364  
    11package nl.nbic.brs.alttableimport.models; 
    22 
     3import java.awt.event.ItemEvent; 
     4import java.awt.event.ItemListener; 
    35import java.io.File; 
    46import java.util.ArrayList; 
     
    1214import javax.swing.event.ChangeEvent; 
    1315import javax.swing.event.ChangeListener; 
     16import javax.swing.event.TableModelEvent; 
     17import javax.swing.table.AbstractTableModel; 
    1418 
    1519import lombok.Getter; 
     
    2428 */ 
    2529@Getter 
    26 public class ParserSettingsModel { 
     30public class ParserSettingsModel implements ChangeListener, ItemListener { 
    2731        private File                                                    tableFile                       = null; 
    2832        private SimplePlainDocument                             networkName                     = new SimplePlainDocument(); 
     
    5256                firstRowHeader.setSelected(true); 
    5357                guessDataTypes.setSelected(true); 
    54         } 
    55  
    56         /** 
    57          * Previously selected interactions, attributes and interpretations should be reset. 
     58 
     59                // Add ourself as listener to models to in turn notify our own listeners through a single unified interface 
     60 
     61                // Whenever the first line to parse or the number of lines to parse updates, we should reset rows & columnNames 
     62                startFrom.addChangeListener(this); 
     63                linesToParse.addChangeListener(this); 
     64                // Whenever comment character changes, we should reset rows & columnNames 
     65                comment.addDocumentListener(new DocumentListenerToChangableAdapter(this)); 
     66 
     67                // Whenever guessing of datatypes or first row as header are toggled, we should reset rows & columnNames 
     68                firstRowHeader.addItemListener(this); 
     69                guessDataTypes.addItemListener(this); 
     70                // When the delimiter changes, we reset rows & columnNames 
     71                delimiter.addItemListener(this); 
     72        } 
     73 
     74        /** 
     75         * Listen for startFrom, linesToParse and comment events. 
     76         */ 
     77        @Override 
     78        public void itemStateChanged(final ItemEvent e) { 
     79                fireSettingsChanged(); 
     80        } 
     81 
     82        /** 
     83         * Listen for firstRowHeader, guessDataTypes & delimiter events. 
     84         */ 
     85        @Override 
     86        public void stateChanged(final ChangeEvent e) { 
     87                fireSettingsChanged(); 
     88        } 
     89 
     90        List<ChangeListener>    listeners       = new ArrayList<ChangeListener>(); 
     91 
     92        public void addChangeListener(final ChangeListener listener) { 
     93                listeners.add(listener); 
     94        } 
     95 
     96        public void removeChangeListener(final ChangeListener listener) { 
     97                listeners.remove(listener); 
     98        } 
     99 
     100        /** 
     101         * {@code true} if the selection is undergoing a series of changes. 
     102         */ 
     103        private volatile boolean        valueAdjusting; 
     104 
     105        /** 
     106         * Calls {@link AbstractTableModel#fireTableChanged(TableModelEvent)} only if #valueAdjusting is false.<BR/> 
     107         * <BR/> 
     108         * This allows us to temporarily prevent listener notification while we are adjusting a lot of settings in one go. 
     109         */ 
     110        private void fireSettingsChanged() { 
     111                if (valueAdjusting) 
     112                        return; 
     113 
     114                ChangeEvent changeEvent = new ChangeEvent(this); 
     115                for (ChangeListener listener : listeners) 
     116                        listener.stateChanged(changeEvent); 
     117        } 
     118 
     119        /** 
     120         * Set {@link #valueAdjusting} to argument. NOOP if {@link #valueAdjusting} value matches argument. 
     121         * If argument is false {@link #fireTableStructureChanged()} is called to notify listeners. 
     122         *  
     123         * @param _valueAdjusting 
     124         */ 
     125        protected void setValueAdjusting(final boolean _valueAdjusting) { 
     126                if (valueAdjusting == _valueAdjusting) 
     127                        return; 
     128                valueAdjusting = _valueAdjusting; 
     129                if (!valueAdjusting) 
     130                        // Notify listeners now that we've completed changes 
     131                        fireSettingsChanged(); 
     132        } 
     133 
     134        // ----- Interpretation handling 
     135 
     136        /** 
     137         * Mark columnIndex for interpretation as clazz, using new Clazz(String value) constructor when retrieving values. 
     138         *  
     139         * @param columnIndex 
     140         * @param clazz 
     141         */ 
     142        public void addInterpretation(final Integer columnIndex, final Class<?> clazz) { 
     143                // XXX Use the return values of remove & put rather than checking preconditions 
     144                if (clazz == String.class) { 
     145                        // String is the default: Remove current interpretation from map 
     146                        interpretation.remove(columnIndex); 
     147                        fireSettingsChanged(); 
     148                        return; 
     149                } 
     150 
     151                // Assert clazz is of a valid type for Cytoscape attributes 
     152                if (clazz != Double.class && clazz != Integer.class && clazz != Boolean.class) 
     153                        throw new IllegalArgumentException(clazz.getCanonicalName()); 
     154 
     155                // Put interpretation only if it changes things 
     156                if (interpretation.get(columnIndex) != clazz) { 
     157                        interpretation.put(columnIndex, clazz); 
     158                        fireSettingsChanged(); 
     159                } 
     160        } 
     161 
     162        /** 
     163         * Method to retrieve interpretation for a certain column. 
     164         *  
     165         * @param columnIndex 
     166         * @return class used to interpret columnIndex (String by default) 
     167         */ 
     168        public Class<?> getInterpretation(final int columnIndex) { 
     169                if (interpretation.containsKey(columnIndex)) 
     170                        return interpretation.get(columnIndex); 
     171                return String.class; 
     172        } 
     173 
     174        /** 
     175         * Discourage anyone from using this map directly, as we need the fireSettingsChanged to trigger through the 
     176         * addInterpretation method. 
     177         *  
     178         * @return mapping of column indices to their Class interpretations 
     179         */ 
     180        @Deprecated 
     181        public Map<Integer, Class<?>> getInterpretation() { 
     182                return interpretation; 
     183        } 
     184 
     185        // ----- Table file handling 
     186 
     187        /** 
     188         * Setter for table file that also resets interactions, attributes and interpretations and also notifies listeners. 
    58189         *  
    59190         * @param tableFile 
    60191         */ 
    61         private void resetSettings() { 
     192        public void setTableFile(final File tableFile) { 
     193                if (this.tableFile == tableFile) 
     194                        return; 
     195                this.tableFile = tableFile; 
     196 
     197                // Batch events triggered by the below event by temporarily disabling listener notification 
     198                setValueAdjusting(true); 
     199                resetSettings(); 
     200                // Notify listeners now that we're done changing settings 
     201                setValueAdjusting(false); 
     202        } 
     203 
     204        /** 
     205         * Previously selected interactions, attributes and interpretations should be reset when a new file is loaded. 
     206         *  
     207         * @param tableFile 
     208         */ 
     209        protected void resetSettings() { 
    62210                // Initialize networkName to the name of the imported file, if available 
    63211                if (tableFile != null) 
    64212                        networkName.setText(tableFile.getName()); 
     213 
    65214                // Reset interactions, attributes and interpretations: These are unlikely to carry over between files 
    66215                sourceInteraction.setSelectedItem(null); 
     
    73222        } 
    74223 
    75         // Listener instances should remain private to this instance, and should not be accessible to the JSON serialization 
    76         List<ChangeListener>    listeners       = new ArrayList<ChangeListener>(); 
    77  
    78         public void addChangeListener(final ChangeListener listener) { 
    79                 listeners.add(listener); 
    80         } 
    81  
    82         public void removeChangeListener(final ChangeListener listener) { 
    83                 listeners.remove(listener); 
    84         } 
    85  
    86         private void fireSettingsChanged() { 
    87                 ChangeEvent changeEvent = new ChangeEvent(this); 
    88                 for (ChangeListener listener : listeners) 
    89                         listener.stateChanged(changeEvent); 
    90         } 
    91  
    92         /** 
    93          * Mark columnIndex for interpretation as clazz, using new Clazz(String value) constructor when retrieving values. 
    94          *  
    95          * @param columnIndex 
    96          * @param clazz 
    97          */ 
    98         public void addInterpretation(final Integer columnIndex, final Class<?> clazz) { 
    99                 if (clazz == String.class) { 
    100                         // String is the default: Remove current interpretation from map 
    101                         interpretation.remove(columnIndex); 
    102                         fireSettingsChanged(); 
    103                         return; 
    104                 } 
    105  
    106                 // Assert clazz is of a valid type for Cytoscape attributes 
    107                 if (clazz != Double.class && clazz != Integer.class && clazz != Boolean.class) 
    108                         throw new IllegalArgumentException(clazz.getCanonicalName()); 
    109  
    110                 // Put interpretation only if it changes things 
    111                 if (interpretation.get(columnIndex) != clazz) { 
    112                         interpretation.put(columnIndex, clazz); 
    113                         fireSettingsChanged(); 
    114                 } 
    115         } 
    116  
    117         /** 
    118          * Method to retrieve interpretation for a certain column. 
    119          *  
    120          * @param columnIndex 
    121          * @return class used to interpret columnIndex (String by default) 
    122          */ 
    123         public Class<?> getInterpretation(final int columnIndex) { 
    124                 if (interpretation.containsKey(columnIndex)) 
    125                         return interpretation.get(columnIndex); 
    126                 return String.class; 
    127         } 
    128  
    129         /** 
    130          * Discourage anyone from using this map directly, as we need the fireSettingsChanged to trigger through the 
    131          * addInterpretation method. 
    132          *  
    133          * @return mapping of column indices to their Class interpretations 
    134          */ 
    135         @Deprecated 
    136         public Map<Integer, Class<?>> getInterpretation() { 
    137                 return interpretation; 
    138         } 
    139  
    140         // ---- Setters that call fireSettingsChanged when changed 
    141  
    142         public void setTableFile(final File tableFile) { 
    143                 if (this.tableFile == tableFile) 
    144                         return; 
    145                 this.tableFile = tableFile; 
    146                 resetSettings(); 
    147                 fireSettingsChanged(); 
    148         } 
    149  
    150224        class GuessDatatypesModel extends ToggleButtonModel { 
    151225                @Override 
  • branches/alttableimport-model-rewrite/src/main/java/nl/nbic/brs/alttableimport/models/ParsingTableModel.java

    r361 r364  
    1010import java.util.ArrayList; 
    1111import java.util.Arrays; 
     12import java.util.Collection; 
    1213import java.util.Iterator; 
    1314import java.util.List; 
    1415import java.util.Map; 
     16import java.util.TreeSet; 
    1517import java.util.regex.Pattern; 
    1618 
     
    1820import javax.swing.event.ChangeEvent; 
    1921import javax.swing.event.ChangeListener; 
     22import javax.swing.event.ListDataEvent; 
     23import javax.swing.event.ListDataListener; 
    2024import javax.swing.table.AbstractTableModel; 
    2125 
    2226import lombok.Getter; 
     27 
     28import org.apache.commons.lang.ArrayUtils; 
     29 
    2330import au.com.bytecode.opencsv.CSVParser; 
    2431import au.com.bytecode.opencsv.CSVReader; 
     
    3239 * A TableModel that parses an underlying data file using a ParserSettingsModel instance to provide table contents. 
    3340 */ 
    34 public class ParsingTableModel extends AbstractTableModel implements ChangeListener, ItemListener { 
     41public class ParsingTableModel extends AbstractTableModel implements ChangeListener { 
    3542        @Getter 
    36         private ParserSettingsModel                     settings; 
     43        private ParserSettingsModel                     settings                = new ParserSettingsModel(); 
    3744 
    3845        private String[]                                        columnNames             = null; 
     
    4552        private TableColumnSelectionModel       selectionModel  = new TableColumnSelectionModel(); 
    4653 
    47         public ParsingTableModel(final ParserSettingsModel settings) { 
    48                 this.settings = settings; 
    49  
     54        public ParsingTableModel() { 
    5055                registerListeners(); 
    5156        } 
    5257 
    53         public void assimilate(final SaveableSettings saveableSettings) { 
    54                 // TODO Auto-generated method stub 
    55  
     58        /** 
     59         * Only intended to be used from NetworkCreator 
     60         *  
     61         * @param _settings 
     62         * @throws IOException 
     63         */ 
     64        public ParsingTableModel(final ParserSettingsModel _settings) throws IOException { 
     65                settings = _settings; 
     66                parseTableFile(); 
     67                registerListeners(); 
    5668        } 
    5769 
     
    6072                settings.addChangeListener(this); 
    6173 
    62                 // Whenever the first line to parse or the number of lines to parse updates, we should reset rows & columnNames 
    63                 settings.getStartFrom().addChangeListener(this); 
    64                 settings.getLinesToParse().addChangeListener(this); 
    65  
    66                 // Whenever guessing of datatypes or first row as header are toggled, we should reset rows & columnNames 
    67                 settings.getFirstRowHeader().addItemListener(this); 
    68                 settings.getGuessDataTypes().addItemListener(this); 
    69                 // When the delimiter changes, we reset rows & columnNames 
    70                 settings.getDelimiter().addItemListener(this); 
     74                // Some events in settings do not require a reparse of tableFile, but only a UI refresh. This handler does that 
     75                PassAlongEventHandler passAlongHandler = new PassAlongEventHandler() { 
     76                        @Override 
     77                        void handleEvent() { 
     78                                // FIXME we were triggering tableEvents in response to table events: That's a nice way to blow the stack 
     79                                // fireTableStructureChanged(); 
     80                        } 
     81                }; 
    7182 
    7283                // Whenever interactions change, we should notify our own listeners to update preview table colors 
    73                 settings.getSourceInteraction().addItemListener(this); 
    74                 settings.getEdgeInteraction().addItemListener(this); 
    75                 settings.getTargetInteraction().addItemListener(this); 
     84                settings.getSourceInteraction().addItemListener(passAlongHandler); 
     85                settings.getEdgeInteraction().addItemListener(passAlongHandler); 
     86                settings.getTargetInteraction().addItemListener(passAlongHandler); 
     87 
    7688                // Whenever additional attributes change, colors of columns in table preview should refresh 
    77                 settings.getSourceAttributes().addListDataListener(new ListDataListenerToChangableAdapter(this)); 
    78                 settings.getEdgeAttributes().addListDataListener(new ListDataListenerToChangableAdapter(this)); 
    79                 settings.getTargetAttributes().addListDataListener(new ListDataListenerToChangableAdapter(this)); 
    80  
    81                 // Whenever comment character changes, we should reset rows & columnNames 
    82                 settings.getComment().addDocumentListener(new DocumentListenerToChangableAdapter(this)); 
     89                settings.getSourceAttributes().addListDataListener(passAlongHandler); 
     90                settings.getEdgeAttributes().addListDataListener(passAlongHandler); 
     91                settings.getTargetAttributes().addListDataListener(passAlongHandler); 
    8392 
    8493                // When the number of columns or the column names change, the interaction comboboxes should be updated 
     
    92101        } 
    93102 
     103        @SuppressWarnings("unused") 
     104        // TODO remove suppressing of warnings 
     105        public void assimilate(final SaveableSettings saveableSettings) throws IOException { 
     106                // We're going to change a lot of values, but do not want to notify listeners for each individual change 
     107                settings.setValueAdjusting(true); 
     108 
     109                // Clear interactions, attributes & interpretations 
     110                settings.resetSettings(); 
     111 
     112                // Transfer values 
     113                settings.setTableFile(saveableSettings.getTableFile()); 
     114                settings.getNetworkName().setText(saveableSettings.getNetworkName()); 
     115 
     116                settings.getDelimiter().setCharacter(saveableSettings.getDelimiter()); 
     117                settings.getComment().setCharacter(saveableSettings.getComment()); 
     118                settings.getStartFrom().setValue(saveableSettings.getStartFrom()); 
     119                settings.getLinesToParse().setValue(saveableSettings.getLinesToParse()); 
     120                settings.getFirstRowHeader().setSelected(saveableSettings.isFirstRowHeader()); 
     121                settings.getGuessDataTypes().setSelected(saveableSettings.isGuessDataTypes()); 
     122 
     123                // Parse tableFile for the first time, to get the columnNames for conversion of column names to column indices 
     124                parseTableFile(); 
     125 
     126                // For interaction, attributes and interpretation: Convert column indices to column names to prevent shifting 
     127                // XXX ColumnName lookup can not handle duplicate column names well, so update help documentation to reflect 
     128                CyLogger logger = CyLogger.getLogger(AlternativeTableImportPlugin.class); 
     129 
     130                // Interactions 
     131                String sourceInteractionName = saveableSettings.getSourceInteraction(); 
     132                int sourceIntIndex = ArrayUtils.indexOf(columnNames, sourceInteractionName); 
     133                settings.getSourceInteraction().setSelectedItem(sourceIntIndex == ArrayUtils.INDEX_NOT_FOUND ? null : sourceIntIndex); 
     134 
     135                String edgeInteractionName = saveableSettings.getSourceInteraction(); 
     136                int edgeIntIndex = ArrayUtils.indexOf(columnNames, sourceInteractionName); 
     137                settings.getEdgeInteraction().setSelectedItem(edgeIntIndex == ArrayUtils.INDEX_NOT_FOUND ? null : edgeIntIndex); 
     138 
     139                String targetInteractionName = saveableSettings.getSourceInteraction(); 
     140                int targetIntIndex = ArrayUtils.indexOf(columnNames, sourceInteractionName); 
     141                settings.getTargetInteraction().setSelectedItem(targetIntIndex == ArrayUtils.INDEX_NOT_FOUND ? null : targetIntIndex); 
     142 
     143                // Additional attributes 
     144                Collection<Integer> sourceAttributeIndices = new TreeSet<Integer>(); 
     145                for (String columnName : saveableSettings.getSourceAttributes()) { 
     146                        int columnIndex = ArrayUtils.indexOf(columnNames, columnName); 
     147                        if (columnIndex != ArrayUtils.INDEX_NOT_FOUND) 
     148                                sourceAttributeIndices.add(columnIndex); 
     149                        else 
     150                                logger.warn("Could not find Additional Source attribute " + columnName); 
     151                } 
     152                settings.getSourceAttributes().addAll(sourceAttributeIndices); 
     153 
     154                Collection<Integer> edgeAttributeIndices = new TreeSet<Integer>(); 
     155                for (String columnName : saveableSettings.getEdgeAttributes()) { 
     156                        int columnIndex = ArrayUtils.indexOf(columnNames, columnName); 
     157                        if (columnIndex != ArrayUtils.INDEX_NOT_FOUND) 
     158                                edgeAttributeIndices.add(columnIndex); 
     159                        else 
     160                                logger.warn("Could not find Additional Edge attribute " + columnName); 
     161                } 
     162                settings.getEdgeAttributes().addAll(edgeAttributeIndices); 
     163 
     164                Collection<Integer> targetAttributeIndices = new TreeSet<Integer>(); 
     165                for (String columnName : saveableSettings.getTargetAttributes()) { 
     166                        int columnIndex = ArrayUtils.indexOf(columnNames, columnName); 
     167                        if (columnIndex != ArrayUtils.INDEX_NOT_FOUND) 
     168                                targetAttributeIndices.add(columnIndex); 
     169                        else 
     170                                logger.warn("Could not find Additional Target attribute " + columnName); 
     171                } 
     172                settings.getTargetAttributes().addAll(targetAttributeIndices); 
     173 
     174                // TODO Interpretation 
     175                Map<String, Class<?>> namedInterpretations = saveableSettings.getInterpretation(); 
     176                @SuppressWarnings("deprecation") 
     177                Map<Integer, Class<?>> indexInterpretations = settings.getInterpretation(); 
     178 
     179                // We're done changing settings: Notify listeners 
     180                settings.setValueAdjusting(false); 
     181        } 
     182 
    94183        /** 
    95          * Listen for changes in startFrom and linesToParse, comment document and additional attributes (through adapters). 
     184         * Listen for any change in settings. 
    96185         */ 
    97186        @Override 
     
    101190 
    102191        /** 
    103          * Listen for changes to firstRowAsHeader, guessDatatypes and interactions. 
     192         * Should only be called from EDT, as it shows a pop-up when any errors occur. 
    104193         */ 
    105         @Override 
    106         public void itemStateChanged(final ItemEvent e) { 
    107                 anyEventHandler(); 
    108         } 
    109  
    110         public void anyEventHandler() { 
     194        private void anyEventHandler() { 
    111195                try { 
    112196                        // XXX File parsing still happens on EDT 
     
    124208 
    125209        public void parseTableFile() throws IOException { 
     210                // TODO Remove printing when parsing a file 
     211                System.out.println("Parsing: " + settings.getTableFile()); 
     212 
    126213                // Save previous columnNames, so we can see if they changed and propagate accordingly 
    127214                String[] previousColumnNames = columnNames; 
     
    245332                        // Our underlying data structure changed: Notify listeners 
    246333                        fireTableStructureChanged(); 
    247                         fireTableDataChanged(); 
    248334 
    249335                        // Rethrow exception: Let the caller handle it 
     
    293379                        fireTableStructureChanged(); 
    294380                } 
    295                 // Regardless of whether the columns changed, the data will have changed 
    296                 fireTableDataChanged(); 
     381                else 
     382                        // Regardless of whether the columns changed, the data will have changed 
     383                        fireTableDataChanged(); 
    297384        } 
    298385 
     
    318405        @Override 
    319406        public Class<?> getColumnClass(final int columnIndex) { 
    320                 if (settings.interpretation.containsKey(columnIndex)) 
    321                         return settings.interpretation.get(columnIndex); 
     407                @SuppressWarnings("deprecation") 
     408                Map<Integer, Class<?>> interpretation = settings.getInterpretation(); 
     409                if (interpretation.containsKey(columnIndex)) 
     410                        return interpretation.get(columnIndex); 
    322411                return String.class; 
    323412        } 
     
    383472        } 
    384473} 
     474 
     475abstract class PassAlongEventHandler implements ItemListener, ListDataListener { 
     476        abstract void handleEvent(); 
     477 
     478        @Override 
     479        public void intervalAdded(final ListDataEvent e) { 
     480                handleEvent(); 
     481        } 
     482 
     483        @Override 
     484        public void intervalRemoved(final ListDataEvent e) { 
     485                handleEvent(); 
     486        } 
     487 
     488        @Override 
     489        public void contentsChanged(final ListDataEvent e) { 
     490                handleEvent(); 
     491        } 
     492 
     493        @Override 
     494        public void itemStateChanged(final ItemEvent e) { 
     495                handleEvent(); 
     496        } 
     497} 
  • branches/alttableimport-model-rewrite/src/main/java/nl/nbic/brs/alttableimport/NetworkCreator.java

    r360 r364  
    3434         */ 
    3535        public static CyNetwork createNetwork(final ParserSettingsModel settings) throws IOException { 
     36                // Parse file 
    3637                ParsingTableModel tableModel = new ParsingTableModel(settings); 
    37                 // Parse file 
    38                 tableModel.parseTableFile(); 
    3938 
    4039                // Create a new network named after the originating file 
  • branches/alttableimport-model-rewrite/src/main/java/nl/nbic/brs/alttableimport/persistence/SaveableSettings.java

    r360 r364  
    22 
    33import java.io.File; 
    4 import java.util.ArrayList; 
    5 import java.util.List; 
    64import java.util.Map; 
     5import java.util.Map.Entry; 
     6import java.util.Set; 
    77import java.util.SortedSet; 
    88import java.util.TreeMap; 
    99import java.util.TreeSet; 
    10  
    11 import javax.swing.event.ChangeEvent; 
    12 import javax.swing.event.ChangeListener; 
    1310 
    1411import lombok.AccessLevel; 
     
    1613import lombok.Setter; 
    1714 
    18 import org.codehaus.jackson.annotate.JsonIgnore; 
    1915import org.codehaus.jackson.map.annotate.JsonSerialize; 
    2016 
     17import nl.nbic.brs.alttableimport.models.ParserSettingsModel; 
     18import nl.nbic.brs.alttableimport.models.ParsingTableModel; 
     19 
    2120/** 
    22  * Settings for parsing a structured text table file, and methods to alter these settings. Notifies listeners upon any 
    23  * change that alters the way in which the text table file might be parsed. 
    24  *  
    25  * Includes some JSON serialization instructions. 
     21 * A settings class that includes JSON serialization instructions used when persisting or loading values. 
    2622 */ 
    2723@Data 
    28 // We need our setters to fireSettingsChanged(), so do not generate them automatically 
    2924@Setter(AccessLevel.NONE) 
    3025@SuppressWarnings("unused") 
    3126public class SaveableSettings implements Cloneable { 
    3227        @JsonSerialize(as = File.class) 
    33         private File                            tableFile                       = null; 
    34         private String                          networkName; 
     28        private File                                    tableFile; 
     29        private String                                  networkName; 
    3530 
    36         private char                            delimiter                       = ','; 
    37         private Character                       comment                         = null; 
    38         private int                                     startFrom                       = 0; 
    39         private int                                     linesToParse            = 30; 
    40         private boolean                         firstRowHeader          = true; 
    41         private boolean                         guessDataTypes          = true; 
     31        private char                                    delimiter; 
     32        private Character                               comment; 
     33        private int                                             startFrom; 
     34        private int                                             linesToParse; 
     35        private boolean                                 firstRowHeader; 
     36        private boolean                                 guessDataTypes; 
    4237 
    43         // Keep an index rather than name to handle firstRowHandle toggling 
    44         private Integer                         sourceInteraction       = null; 
    45         private Integer                         edgeInteraction         = null; 
    46         private Integer                         targetInteraction       = null; 
     38        // Store column names here to prevent shifting 
     39        private String                                  sourceInteraction; 
     40        private String                                  edgeInteraction; 
     41        private String                                  targetInteraction; 
    4742 
    4843        // Lists with additional attributes per source node, target node or edge 
    49         private SortedSet<Integer>      sourceAttributes        = new TreeSet<Integer>(); 
    50         private SortedSet<Integer>      edgeAttributes          = new TreeSet<Integer>(); 
    51         private SortedSet<Integer>      targetAttributes        = new TreeSet<Integer>(); 
     44        private SortedSet<String>               sourceAttributes        = new TreeSet<String>(); 
     45        private SortedSet<String>               edgeAttributes          = new TreeSet<String>(); 
     46        private SortedSet<String>               targetAttributes        = new TreeSet<String>(); 
    5247 
    53         // Do not grant access to the underlying map, so we can restrict addition to addInterpretation & fireSettingsChanged 
     48        // The datatypes for each of the columns, if not the standard String 
    5449        @JsonSerialize 
    55         Map<Integer, Class<?>>          interpretation          = new TreeMap<Integer, Class<?>>(); 
    56  
    57         // Listener instances should remain private to this instance, and should not be accessible to the JSON serialization 
    58         @JsonIgnore 
    59         List<ChangeListener>            listeners                       = new ArrayList<ChangeListener>(); 
    60  
    61         public void addChangeListener(final ChangeListener listener) { 
    62                 listeners.add(listener); 
    63         } 
    64  
    65         public void removeChangeListener(final ChangeListener listener) { 
    66                 listeners.remove(listener); 
    67         } 
    68  
    69         private void fireSettingsChanged() { 
    70                 ChangeEvent changeEvent = new ChangeEvent(this); 
    71                 ChangeListener[] safeArray = listeners.toArray(new ChangeListener[listeners.size()]); 
    72                 for (ChangeListener listener : safeArray) 
    73                         listener.stateChanged(changeEvent); 
    74         } 
     50        private Map<String, Class<?>>   interpretation          = new TreeMap<String, Class<?>>(); 
    7551 
    7652        /** 
    77          * Mark columnIndex for interpretation as clazz, using new Clazz(String value) constructor when retrieving values. 
    78          *  
    79          * @param columnIndex 
    80          * @param clazz 
     53         * Constructor only intended to be used by JSON serialization process. 
    8154         */ 
    82         public void addInterpretation(final Integer columnIndex, final Class<?> clazz) { 
    83                 if (clazz == String.class) { 
    84                         // String is the default: Remove current interpretation from map 
    85                         interpretation.remove(columnIndex); 
    86                         fireSettingsChanged(); 
    87                         return; 
    88                 } 
     55        @Deprecated 
     56        private SaveableSettings() {/* JSON Serialization only */} 
    8957 
    90                 // Assert clazz is of a valid type for Cytoscape attributes 
    91                 if (clazz != Double.class && clazz != Integer.class && clazz != Boolean.class) 
    92                         throw new IllegalArgumentException(clazz.getCanonicalName()); 
     58        public SaveableSettings(final ParsingTableModel parsingTableModel) { 
     59                ParserSettingsModel settings = parsingTableModel.getSettings(); 
     60                tableFile = settings.getTableFile(); 
     61                networkName = settings.getNetworkName().getText(); 
    9362 
    94                 // Put interpretation only if it changes things 
    95                 if (interpretation.get(columnIndex) != clazz) { 
    96                         interpretation.put(columnIndex, clazz); 
    97                         fireSettingsChanged(); 
     63                delimiter = settings.getDelimiter().getCharacter(); 
     64                comment = settings.getComment().getCharacter(); 
     65                startFrom = settings.getStartFrom().getNumber().intValue(); 
     66                linesToParse = settings.getLinesToParse().getNumber().intValue(); 
     67                firstRowHeader = settings.getFirstRowHeader().isSelected(); 
     68                guessDataTypes = settings.getGuessDataTypes().isSelected(); 
     69 
     70                // For interaction, attributes and interpretation: Convert column indices to column names to prevent shifting 
     71 
     72                // Interactions 
     73                Integer sourceIntIndex = settings.getSourceInteraction().getSelectedItem(); 
     74                sourceInteraction = sourceIntIndex == null ? null : parsingTableModel.getColumnName(sourceIntIndex); 
     75                Integer edgeIntIndex = settings.getEdgeInteraction().getSelectedItem(); 
     76                edgeInteraction = edgeIntIndex == null ? null : parsingTableModel.getColumnName(edgeIntIndex); 
     77                Integer targetIntIndex = settings.getTargetInteraction().getSelectedItem(); 
     78                targetInteraction = targetIntIndex == null ? null : parsingTableModel.getColumnName(targetIntIndex); 
     79 
     80                // Additional attributes 
     81                int[] sourceAttrIndices = settings.getSourceAttributes().getIndices(); 
     82                for (int columnIndex : sourceAttrIndices) 
     83                        sourceAttributes.add(parsingTableModel.getColumnName(columnIndex)); 
     84                int[] edgeAttrIndices = settings.getSourceAttributes().getIndices(); 
     85                for (int columnIndex : edgeAttrIndices) 
     86                        edgeAttributes.add(parsingTableModel.getColumnName(columnIndex)); 
     87                int[] targetAttrIndices = settings.getSourceAttributes().getIndices(); 
     88                for (int columnIndex : targetAttrIndices) 
     89                        targetAttributes.add(parsingTableModel.getColumnName(columnIndex)); 
     90 
     91                // Interpretation 
     92                @SuppressWarnings("deprecation") 
     93                Set<Entry<Integer, Class<?>>> interpretationKeyValueSet = settings.getInterpretation().entrySet(); 
     94                for (Entry<Integer, Class<?>> columnInterpretation : interpretationKeyValueSet) { 
     95                        String columnName = parsingTableModel.getColumnName(columnInterpretation.getKey()); 
     96                        interpretation.put(columnName, columnInterpretation.getValue()); 
    9897                } 
    9998        } 
    100  
    101         /** 
    102          * Method to retrieve interpretation for a certain column. 
    103          *  
    104          * @param columnIndex 
    105          * @return class used to interpret columnIndex (String by default) 
    106          */ 
    107         public Class<?> getInterpretation(final int columnIndex) { 
    108                 if (interpretation.containsKey(columnIndex)) 
    109                         return interpretation.get(columnIndex); 
    110                 return String.class; 
    111         } 
    112  
    113         /** 
    114          * JSON Serialization using Jackson requires a public getter method, but discourage anyone from using it directly 
    115          *  
    116          * @return mapping of column indices to their Class interpretations 
    117          */ 
    118         @Deprecated 
    119         public Map<Integer, Class<?>> getInterpretation() { 
    120                 return interpretation; 
    121         } 
    122  
    123         /** 
    124          * Support cloning of ParserSettingsModel to get an instance to change without notifying listeners. 
    125          */ 
    126         @Override 
    127         @SuppressWarnings("unchecked") 
    128         public SaveableSettings clone() throws CloneNotSupportedException { 
    129                 SaveableSettings clone = (SaveableSettings) super.clone(); 
    130                 // Do not copy listeners 
    131                 clone.listeners = new ArrayList<ChangeListener>(); 
    132                 return clone; 
    133         } 
    134  
    135         // ---- Setters that call fireSettingsChanged when changed 
    136  
    137         public void setTableFile(final File tableFile) { 
    138                 if (this.tableFile == tableFile) 
    139                         return; 
    140                 this.tableFile = tableFile; 
    141                 // Also set networkName 
    142                 networkName = tableFile.getName(); 
    143                 fireSettingsChanged(); 
    144         } 
    145  
    146         public void setNetworkName(final String networkName) { 
    147                 this.networkName = networkName; 
    148                 // Do not fire settings changed: Only called from UI element itself 
    149                 // Because setNetworkName is triggered when tableFile changes, fireSettingsChanged would trigger parsing twice 
    150         } 
    151  
    152         public void setDelimiter(final char delimiter) { 
    153                 if (this.delimiter == delimiter) 
    154                         return; 
    155                 this.delimiter = delimiter; 
    156                 fireSettingsChanged(); 
    157         } 
    158  
    159         public void setComment(final Character _comment) { 
    160                 // Bit more logic to allow for setting null 
    161                 if (_comment == null && comment == null) 
    162                         return; 
    163                 if (_comment != null && _comment.equals(comment)) 
    164                         return; 
    165                 comment = _comment; 
    166                 fireSettingsChanged(); 
    167         } 
    168  
    169         public void setStartFrom(final int startFrom) { 
    170                 if (this.startFrom == startFrom) 
    171                         return; 
    172                 this.startFrom = startFrom; 
    173                 fireSettingsChanged(); 
    174         } 
    175  
    176         public void setLinesToParse(final int linesToParse) { 
    177                 if (this.linesToParse == linesToParse) 
    178                         return; 
    179                 this.linesToParse = linesToParse; 
    180                 fireSettingsChanged(); 
    181         } 
    182  
    183         public void setFirstRowHeader(final boolean firstRowHeader) { 
    184                 if (this.firstRowHeader == firstRowHeader) 
    185                         return; 
    186                 this.firstRowHeader = firstRowHeader; 
    187                 fireSettingsChanged(); 
    188         } 
    189  
    190         public void setGuessDataTypes(final boolean guessDataTypes) { 
    191                 if (this.guessDataTypes == guessDataTypes) 
    192                         return; 
    193                 this.guessDataTypes = guessDataTypes; 
    194  
    195                 // Reset all interpretations so the previous guesses will not interfere with future manually set interpretations 
    196                 if (!guessDataTypes) 
    197                         interpretation.clear(); 
    198  
    199                 fireSettingsChanged(); 
    200         } 
    201  
    202         // Special extra step for source, edge and target attributes: They can only be Strings 
    203         public void setSourceInteraction(final Integer sourceAttrIndex) { 
    204                 // NOOP when value does not change 
    205                 if (sourceInteraction == null && sourceAttrIndex == null) 
    206                         return; 
    207                 if (sourceAttrIndex != null && sourceAttrIndex.equals(sourceInteraction)) 
    208                         return; 
    209  
    210                 // Assign new value 
    211                 sourceInteraction = sourceAttrIndex; 
    212                 fireSettingsChanged(); 
    213         } 
    214  
    215         public void setEdgeInteraction(final Integer edgeAttrIndex) { 
    216                 // NOOP when value does not change 
    217                 if (edgeInteraction == null && edgeAttrIndex == null) 
    218                         return; 
    219                 if (edgeAttrIndex != null && edgeAttrIndex.equals(edgeInteraction)) 
    220                         return; 
    221  
    222                 // Assign new value 
    223                 edgeInteraction = edgeAttrIndex; 
    224                 fireSettingsChanged(); 
    225         } 
    226  
    227         public void setTargetInteraction(final Integer targetAttrIndex) { 
    228                 // NOOP when value does not change 
    229                 if (targetInteraction == null && targetAttrIndex == null) 
    230                         return; 
    231                 if (targetAttrIndex != null && targetAttrIndex.equals(targetInteraction)) 
    232                         return; 
    233  
    234                 // Assign new value 
    235                 targetInteraction = targetAttrIndex; 
    236                 fireSettingsChanged(); 
    237         } 
    238  
    239         // Allow for externally modifiable collections here: There are no other developers to muck this up 
    240         public void setSourceAttributes(final SortedSet<Integer> sourceAttributes) { 
    241                 // When this method is called, one should really fireStructureChanged on the tableModel as well 
    242                 this.sourceAttributes = sourceAttributes; 
    243                 fireSettingsChanged(); 
    244         } 
    245  
    246         public void setEdgeAttributes(final SortedSet<Integer> edgeAttributes) { 
    247                 this.edgeAttributes = edgeAttributes; 
    248                 fireSettingsChanged(); 
    249         } 
    250  
    251         public void setTargetAttributes(final SortedSet<Integer> targetAttributes) { 
    252                 this.targetAttributes = targetAttributes; 
    253                 fireSettingsChanged(); 
    254         } 
    25599} 
  • branches/alttableimport-model-rewrite/src/main/java/nl/nbic/brs/alttableimport/persistence/SettingsPersistence.java

    r354 r364  
    1111import org.codehaus.jackson.map.ObjectWriter; 
    1212 
    13 import nl.nbic.brs.alttableimport.models.ParserSettingsModel; 
     13import nl.nbic.brs.alttableimport.models.ParsingTableModel; 
    1414 
    1515/** 
     
    1919        private static ObjectMapper     mapper                  = new ObjectMapper(); 
    2020        private static ObjectWriter     prettyWriter    = mapper.writerWithDefaultPrettyPrinter(); 
    21         private static ObjectReader     settingsReader  = mapper.reader(ParserSettingsModel.class); 
     21        private static ObjectReader     settingsReader  = mapper.reader(SaveableSettings.class); 
    2222 
    2323        /** 
     
    2525         *  
    2626         * @param file 
    27          * @param settings 
     27         * @param parsingTableModel 
    2828         * @throws JsonGenerationException 
    2929         * @throws JsonMappingException 
    3030         * @throws IOException 
    3131         */ 
    32         public static void saveSettings(final File file, final ParserSettingsModel settings) throws JsonGenerationException, JsonMappingException, IOException { 
    33                 // TODO Saving column numbers instead of names is fragile: columns can shift to break the indices and import 
    34                 prettyWriter.writeValue(file, settings); 
     32        public static void saveSettings(final File file, final ParsingTableModel parsingTableModel) throws JsonGenerationException, JsonMappingException, IOException { 
     33                SaveableSettings saveableSettings = new SaveableSettings(parsingTableModel); 
     34                prettyWriter.writeValue(file, saveableSettings); 
    3535        } 
    3636 
     
    4343         * @throws IOException 
    4444         */ 
    45         public static ParserSettingsModel loadSettings(final File file) throws JsonProcessingException, IOException { 
    46                 return settingsReader.readValue(file); 
     45        public static SaveableSettings loadSettings(final File file) throws JsonProcessingException, IOException { 
     46                SaveableSettings readValue = settingsReader.readValue(file); 
     47                return readValue; 
    4748        } 
    4849} 
  • branches/alttableimport-model-rewrite/src/main/java/nl/nbic/brs/alttableimport/views/ButtonPanel.java

    r360 r364  
    3333import nl.nbic.brs.alttableimport.models.ParserSettingsModel; 
    3434import nl.nbic.brs.alttableimport.models.ParsingTableModel; 
     35import nl.nbic.brs.alttableimport.persistence.SaveableSettings; 
    3536import nl.nbic.brs.alttableimport.persistence.SettingsPersistence; 
    3637 
     
    7273                                // Save settings to selected file 
    7374                                try { 
    74                                         SettingsPersistence.saveSettings(fileToSave, tableModel.getSettings()); 
     75                                        SettingsPersistence.saveSettings(fileToSave, tableModel); 
    7576                                } 
    7677                                catch (IOException ioe) { 
     
    9697                                        return; 
    9798 
    98                                 // Load settings from selected file 
    99                                 ParserSettingsModel loadedSettings = null; 
    10099                                try { 
    101                                         loadedSettings = SettingsPersistence.loadSettings(fileToLoad); 
     100                                        // Load settings from selected file 
     101                                        SaveableSettings saveableSettings = SettingsPersistence.loadSettings(fileToLoad); 
     102                                        tableModel.assimilate(saveableSettings); 
    102103                                } 
    103104                                catch (IOException ioe) { 
     
    107108                                        // Warn user 
    108109                                        String title = "Could not load settings from file"; 
    109                                         String msg = "Serializer reported: \"" + ioe.getMessage() + "\""; 
     110                                        String msg = "Deserializer reported: \"" + ioe.getMessage() + "\""; 
    110111                                        JOptionPane.showMessageDialog(null, msg, title, JOptionPane.ERROR_MESSAGE); 
    111112                                        return; 
    112113                                } 
    113  
    114                                 // Set new settings on tableModel 
    115                                 ;// TODO tableModel.replaceSettings(loadedSettings); 
    116114                        } 
    117115                }); 
  • branches/alttableimport-model-rewrite/src/main/java/nl/nbic/brs/alttableimport/views/TableImportDialog.java

    r360 r364  
    99import javax.swing.JDialog; 
    1010 
    11 import nl.nbic.brs.alttableimport.models.ParserSettingsModel; 
     11import lombok.Getter; 
     12 
    1213import nl.nbic.brs.alttableimport.models.ParsingTableModel; 
    1314 
     
    1718public class TableImportDialog extends JDialog { 
    1819        // Model 
    19         private ParsingTableModel       tableModel; 
     20        @Getter 
     21        private ParsingTableModel       tableModel      = new ParsingTableModel(); 
    2022 
    2123        // Panels 
     
    3436                super(parent); 
    3537 
    36                 // Create models 
    37                 ParserSettingsModel settings = new ParserSettingsModel(); 
    38                 tableModel = new ParsingTableModel(settings); 
    39  
    4038                // Create panels 
    4139                parseOptionsPanel = new ParseOptionsPanel(tableModel); 
     
    5149                // Layout components on page 
    5250                layoutComponents(); 
    53         } 
    54  
    55         /** 
    56          * @return settings stored within tableModel 
    57          */ 
    58         public ParserSettingsModel getSettings() { 
    59                 return tableModel.getSettings(); 
    6051        } 
    6152 
  • branches/alttableimport-model-rewrite/src/test/java/nl/nbic/brs/alttableimport/models/TestParsingTableModel.java

    r358 r364  
    99        @Test 
    1010        public void testParseFile() { 
    11                 ParserSettingsModel settings = new ParserSettingsModel(); 
    12                 settings.getDelimiter().getSemicolonButtonModel().setSelected(true); 
    13  
    1411                // Create table model with partial settings 
    15                 ParsingTableModel tableParser = new ParsingTableModel(settings); 
     12                ParsingTableModel tableParser = new ParsingTableModel(); 
     13                ParserSettingsModel settings = tableParser.getSettings(); 
    1614 
    1715                // Proof that we can update the settings later 
     16                settings.getDelimiter().getSemicolonButtonModel().setSelected(true); 
    1817                settings.addInterpretation(5, Double.class); 
    1918                settings.setTableFile(new File("src/test/resources/transacties_-345280419.csv")); 
  • branches/alttableimport-model-rewrite/src/test/java/nl/nbic/brs/alttableimport/models/TestSettingsPersistence.java

    r360 r364  
    77import java.util.Scanner; 
    88import java.util.TreeMap; 
    9 import java.util.TreeSet; 
    109 
    1110import org.junit.Assert; 
    12 import org.junit.Ignore; 
    1311import org.junit.Rule; 
    1412import org.junit.Test; 
    1513import org.junit.rules.TemporaryFolder; 
    1614 
     15import nl.nbic.brs.alttableimport.persistence.SaveableSettings; 
    1716import nl.nbic.brs.alttableimport.persistence.SettingsPersistence; 
    1817 
    19 @Ignore 
    20 // TODO Remove ignoring persistence tests 
    2118public class TestSettingsPersistence { 
    2219        @Rule 
     
    2926        @Test 
    3027        public void testSaving() throws Exception { 
     28                ParsingTableModel parsingTableModel = new ParsingTableModel(); 
    3129                // Build settings object 
    32                 ParserSettingsModel settings = new ParserSettingsModel(); 
     30                ParserSettingsModel settings = parsingTableModel.getSettings(); 
    3331                settings.setTableFile(transactionsTable); 
    3432                settings.getNetworkName().setText("MyFirstNetwork"); 
     
    4644                // Persist to temporary file 
    4745                File settingsFile = tempFolder.newFile("settings.json"); 
    48                 SettingsPersistence.saveSettings(settingsFile, settings); 
     46                SettingsPersistence.saveSettings(settingsFile, parsingTableModel); 
    4947 
    5048                // Compare contents 
     
    6967        public void testLoading() throws Exception { 
    7068                // Load 
    71                 ParserSettingsModel settings = SettingsPersistence.loadSettings(transactionsProfile); 
     69                SaveableSettings saveableSettings = SettingsPersistence.loadSettings(transactionsProfile); 
     70                ParsingTableModel parsingTableModel = new ParsingTableModel(); 
     71                ParserSettingsModel settings = parsingTableModel.getSettings(); 
     72                parsingTableModel.assimilate(saveableSettings); 
    7273 
    7374                // Check simple fields 
    74                 Assert.assertEquals(';', settings.getDelimiter()); 
     75                Assert.assertEquals(';', settings.getDelimiter().getCharacter()); 
    7576                Assert.assertEquals(null, settings.getComment().getCharacter()); 
    76                 Assert.assertEquals(0, settings.getStartFrom()); 
    77                 Assert.assertEquals(30, settings.getLinesToParse()); 
     77                Assert.assertEquals(0, settings.getStartFrom().getNumber().intValue()); 
     78                Assert.assertEquals(30, settings.getLinesToParse().getNumber().intValue()); 
    7879                Assert.assertEquals(true, settings.getFirstRowHeader().isSelected()); 
    7980                Assert.assertEquals(2, settings.getSourceInteraction().getSelectedItem().intValue()); 
    80                 Assert.assertEquals(null, settings.getEdgeInteraction()); 
     81                Assert.assertEquals(null, settings.getEdgeInteraction().getSelectedItem()); 
    8182                Assert.assertEquals(4, settings.getTargetInteraction().getSelectedItem().intValue()); 
    8283 
    8384                // Check collections 
    84                 Assert.assertEquals(new TreeSet<Integer>(Arrays.asList(2)), settings.getSourceAttributes()); 
    85                 Assert.assertEquals(new TreeSet<Integer>(Arrays.asList(0, 5)), settings.getEdgeAttributes()); 
    86                 Assert.assertEquals(new TreeSet<Integer>(Arrays.asList(4)), settings.getTargetAttributes()); 
     85                Assert.assertArrayEquals(new int[] { 2 }, settings.getSourceAttributes().getIndices()); 
     86                Assert.assertArrayEquals(new int[] { 0, 5 }, settings.getEdgeAttributes().getIndices()); 
     87                Assert.assertArrayEquals(new int[] { 4 }, settings.getTargetAttributes().getIndices()); 
    8788 
    8889                // Check interpretation 
     
    101102        @Test 
    102103        public void testRoundTripPersistence() throws Exception { 
    103                 ParserSettingsModel savedSettings = new ParserSettingsModel(); 
     104                ParsingTableModel savedTableModel = new ParsingTableModel(); 
     105                ParserSettingsModel savedSettings = savedTableModel.getSettings(); 
     106                // Store some settings 
    104107                savedSettings.getDelimiter().getSemicolonButtonModel().setSelected(true); 
    105  
    106                 // Create a table model that'll listen to these settings, to see how listeners are handled 
    107                 @SuppressWarnings("unused") 
    108                 ParsingTableModel parsingTableModel = new ParsingTableModel(savedSettings); 
    109  
    110                 // Add even more settings 
    111108                savedSettings.addInterpretation(5, Double.class); 
    112109                savedSettings.setTableFile(transactionsTable.getAbsoluteFile()); 
     
    115112                // Save settings to file 
    116113                File settingsFile = tempFolder.newFile("settings.json"); 
    117                 SettingsPersistence.saveSettings(settingsFile, savedSettings); 
     114                SettingsPersistence.saveSettings(settingsFile, savedTableModel); 
    118115 
    119116                // Some assertions after writing the file 
     
    126123 
    127124                // Load settings from file 
    128                 ParserSettingsModel loadedSettings = SettingsPersistence.loadSettings(settingsFile); 
     125                ParsingTableModel loadedTableModel = new ParsingTableModel(); 
     126                loadedTableModel.assimilate(SettingsPersistence.loadSettings(settingsFile)); 
    129127 
    130                 // Listeners are not persisted, so set listeners loadedSettings to savedSettings.listeners 
    131                 loadedSettings.listeners = savedSettings.listeners; 
    132128                // The instances should now be equal according to the generated equals method 
    133                 Assert.assertEquals(savedSettings, loadedSettings); 
     129                Assert.assertEquals(new SaveableSettings(savedTableModel), new SaveableSettings(loadedTableModel)); 
    134130 
    135131                // Assert tableFile is of type file 
    136                 Assert.assertEquals(File.class, loadedSettings.getTableFile().getClass()); 
     132                Assert.assertEquals(File.class, loadedTableModel.getSettings().getTableFile().getClass()); 
    137133        } 
    138134}