From: gmungoc Date: Mon, 22 May 2017 14:16:40 +0000 (+0100) Subject: Merge branch 'develop' into features/JAL-2446NCList X-Git-Tag: Release_2_10_3b1~252 X-Git-Url: http://source.jalview.org/gitweb/?a=commitdiff_plain;h=691e7f3e04f4ddc3ae858257f063a0b01be265fc;p=jalview.git Merge branch 'develop' into features/JAL-2446NCList Conflicts: src/jalview/analysis/AlignmentSorter.java src/jalview/appletgui/FeatureSettings.java src/jalview/appletgui/SeqPanel.java src/jalview/gui/FeatureRenderer.java src/jalview/gui/FeatureSettings.java src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java test/jalview/analysis/AlignmentSorterTest.java --- 691e7f3e04f4ddc3ae858257f063a0b01be265fc diff --cc src/jalview/appletgui/FeatureSettings.java index 68881b2,9d2f601..b0bb372 --- a/src/jalview/appletgui/FeatureSettings.java +++ b/src/jalview/appletgui/FeatureSettings.java @@@ -371,35 -370,43 +369,43 @@@ public class FeatureSettings extends Pa // Group selection states void resetTable(boolean groupsChanged) { - SequenceFeature[] tmpfeatures; - String group = null, type; - Vector visibleChecks = new Vector(); + List displayableTypes = new ArrayList(); + Set foundGroups = new HashSet(); ++ AlignmentI alignment = av.getAlignment(); + for (int i = 0; i < alignment.getHeight(); i++) { - if (alignment.getSequenceAt(i).getSequenceFeatures() == null) - { - continue; - } + SequenceI seq = alignment.getSequenceAt(i); - tmpfeatures = alignment.getSequenceAt(i).getSequenceFeatures(); - int index = 0; - while (index < tmpfeatures.length) + /* + * get the sequence's groups for positional features + * and keep track of which groups are visible + */ + Set groups = seq.getFeatures().getFeatureGroups(true); + Set visibleGroups = new HashSet(); + for (String group : groups) { - group = tmpfeatures[index].featureGroup; - foundGroups.add(group); - - if (group == null || checkGroupState(group)) + if (group == null || fr.checkGroupVisibility(group, true)) { - type = tmpfeatures[index].getType(); - if (!visibleChecks.contains(type)) - { - visibleChecks.addElement(type); - } + visibleGroups.add(group); } - index++; } + + /* + * get distinct feature types for visible groups + * record distinct visible types + */ + Set types = seq.getFeatures().getFeatureTypesForGroups(true, + visibleGroups.toArray(new String[visibleGroups.size()])); + displayableTypes.addAll(types); } + /* + * remove any checkboxes for groups not present + */ + pruneGroups(foundGroups); + Component[] comps; int cSize = featurePanel.getComponentCount(); MyCheckbox check; diff --cc src/jalview/appletgui/SeqPanel.java index 02dc848,d46cc34..c10038f --- a/src/jalview/appletgui/SeqPanel.java +++ b/src/jalview/appletgui/SeqPanel.java @@@ -563,20 -562,20 +563,19 @@@ public class SeqPanel extends Panel imp av.setSelectionGroup(null); } - SequenceFeature[] features = findFeaturesAtRes(sequence, + List features = findFeaturesAtRes(sequence, sequence.findPosition(findRes(evt))); - if (features != null && features.length > 0) + if (!features.isEmpty()) { SearchResultsI highlight = new SearchResults(); - highlight.addResult(sequence, features[0].getBegin(), - features[0].getEnd()); + highlight.addResult(sequence, features.get(0).getBegin(), features + .get(0).getEnd()); seqCanvas.highlightSearchResults(highlight); - } - if (features != null && features.length > 0) - { + SequenceFeature[] featuresArray = features + .toArray(new SequenceFeature[features.size()]); seqCanvas.getFeatureRenderer().amendFeatures( - new SequenceI[] { sequence }, featuresArray, false, ap, - null); - new SequenceI[] { sequence }, features, false, ap); ++ new SequenceI[] { sequence }, featuresArray, false, ap); seqCanvas.highlightSearchResults(null); } diff --cc src/jalview/gui/CutAndPasteTransfer.java index a5aa9eb,a5aa9eb..3eced2f --- a/src/jalview/gui/CutAndPasteTransfer.java +++ b/src/jalview/gui/CutAndPasteTransfer.java @@@ -298,6 -298,6 +298,7 @@@ public class CutAndPasteTransfer extend AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); af.getViewport().setShowSequenceFeatures(showSeqFeatures); af.getViewport().setFeaturesDisplayed(fd); ++ af.setMenusForViewport(); ColourSchemeI cs = ColourSchemeMapper.getJalviewColourScheme( colourSchemeName, al); if (cs != null) diff --cc src/jalview/gui/FeatureRenderer.java index b33ada2,2f12eef..0779760 --- a/src/jalview/gui/FeatureRenderer.java +++ b/src/jalview/gui/FeatureRenderer.java @@@ -405,53 -420,29 +421,55 @@@ public class FeatureRenderer extend { /* * YES_OPTION corresponds to the Amend button + * need to refresh Feature Settings if type, group or colour changed */ - boolean typeChanged = !lastFeatureAdded.equals(sf.type); - String newType = lastFeatureAdded; - String newFeatureGroup = lastFeatureGroupAdded; - String newDescription = lastDescriptionAdded; - - sf.type = name.getText().trim(); - sf.featureGroup = group.getText().trim(); - sf.description = description.getText().replaceAll("\n", " "); ++ String newType = name.getText().trim(); ++ String newFeatureGroup = group.getText().trim(); ++ String newDescription = description.getText().replaceAll("\n", " "); + boolean refreshSettings = (!featureType.equals(sf.type) || !featureGroup + .equals(sf.featureGroup)); + refreshSettings |= (fcol != oldcol); - - setColour(sf.type, fcol); - + setColour(newType, fcol); - getFeaturesDisplayed().setVisible(newType); ++/*?*/ getFeaturesDisplayed().setVisible(newType); + int newBegin = sf.begin; + int newEnd = sf.end; try { - sf.begin = ((Integer) start.getValue()).intValue(); - sf.end = ((Integer) end.getValue()).intValue(); + newBegin = ((Integer) start.getValue()).intValue(); + newEnd = ((Integer) end.getValue()).intValue(); } catch (NumberFormatException ex) { + // JSpinner doesn't accept invalid format data :-) + } + + /* + * replace the feature by deleting it and adding a new one + * (to ensure integrity of SequenceFeatures data store) + */ + sequences.get(0).deleteFeature(sf); + SequenceFeature newSf = new SequenceFeature(newType, + newDescription, newBegin, newEnd, sf.getScore(), + newFeatureGroup); + // ensure any additional properties are copied + if (sf.otherDetails != null) + { + newSf.otherDetails = new HashMap(sf.otherDetails); + } + ffile.parseDescriptionHTML(newSf, false); + // add any additional links not parsed from description + if (sf.links != null) + { + for (String link : sf.links) + { + newSf.addLink(link); + } } + // amend features only gets one sequence to act on + sequences.get(0).addSequenceFeature(newSf); - if (typeChanged) - ffile.parseDescriptionHTML(sf, false); + if (refreshSettings) { - findAllFeatures(); + featuresAdded(); } } } diff --cc src/jalview/gui/FeatureSettings.java index 419cb34,34f0b4a..45b6b0d --- a/src/jalview/gui/FeatureSettings.java +++ b/src/jalview/gui/FeatureSettings.java @@@ -563,53 -580,66 +556,55 @@@ public class FeatureSettings extends JP typeWidth = new Hashtable(); // TODO: change avWidth calculation to 'per-sequence' average and use long // rather than float - float[] avWidth = null; - SequenceFeature[] tmpfeatures; - String group = null, type; - Vector visibleChecks = new Vector(); + + Set displayableTypes = new HashSet(); + Set foundGroups = new HashSet(); - // Find out which features should be visible depending on which groups - // are selected / deselected - // and recompute average width ordering + /* + * determine which feature types may be visible depending on + * which groups are selected, and recompute average width data + */ for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++) { - tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i) - .getSequenceFeatures(); - if (tmpfeatures == null) - { - continue; - } + SequenceI seq = af.getViewport().getAlignment().getSequenceAt(i); - int index = 0; - while (index < tmpfeatures.length) + /* + * get the sequence's groups for positional features + * and keep track of which groups are visible + */ + Set groups = seq.getFeatures().getFeatureGroups(true); + Set visibleGroups = new HashSet(); + for (String group : groups) { - group = tmpfeatures[index].featureGroup; - foundGroups.add(group); - - if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0) - { - index++; - continue; - } - if (group == null || checkGroupState(group)) { - type = tmpfeatures[index].getType(); - if (!visibleChecks.contains(type)) - { - visibleChecks.addElement(type); - } - } - if (!typeWidth.containsKey(tmpfeatures[index].getType())) - { - typeWidth.put(tmpfeatures[index].getType(), - avWidth = new float[3]); + visibleGroups.add(group); } - else - { - avWidth = typeWidth.get(tmpfeatures[index].getType()); - } - avWidth[0]++; - if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd()) - { - avWidth[1] += 1 + tmpfeatures[index].getBegin() - - tmpfeatures[index].getEnd(); - } - else + } ++ foundGroups.addAll(groups); + + /* + * get distinct feature types for visible groups + * record distinct visible types, and their count and total length + */ + Set types = seq.getFeatures().getFeatureTypesForGroups(true, + visibleGroups.toArray(new String[visibleGroups.size()])); + for (String type : types) + { + displayableTypes.add(type); + float[] avWidth = typeWidth.get(type); + if (avWidth == null) { - avWidth[1] += 1 + tmpfeatures[index].getEnd() - - tmpfeatures[index].getBegin(); + avWidth = new float[2]; + typeWidth.put(type, avWidth); } - index++; + // todo this could include features with a non-visible group + // - do we greatly care? + // todo should we include non-displayable features here, and only + // update when features are added? + avWidth[0] += seq.getFeatures().getFeatureCount(true, type); + avWidth[1] += seq.getFeatures().getTotalFeatureLength(type); } } diff --cc src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java index 5bbdbec,f6addb8..284ee4f --- a/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java +++ b/src/jalview/viewmodel/seqfeatures/FeatureRendererModel.java @@@ -330,62 -341,101 +330,96 @@@ public abstract class FeatureRendererMo } } } - - if (minmax == null) - { - minmax = new Hashtable(); - } - - Set oldGroups = new HashSet(featureGroups.keySet()); ++ // <<<<<<< HEAD ++ // ++ // ======= ++ // if (minmax == null) ++ // { ++ // minmax = new Hashtable(); ++ // } ++ // ++ // Set oldGroups = new HashSet(featureGroups.keySet()); ++ // >>>>>>> refs/heads/develop AlignmentI alignment = av.getAlignment(); + List allfeatures = new ArrayList(); // or HashSet? + for (int i = 0; i < alignment.getHeight(); i++) { SequenceI asq = alignment.getSequenceAt(i); - SequenceFeature[] features = asq.getSequenceFeatures(); - - if (features == null) + for (String group : asq.getFeatures().getFeatureGroups(true)) { - continue; - } - - int index = 0; - while (index < features.length) - { - String fgrp = features[index].getFeatureGroup(); - oldGroups.remove(fgrp); - if (!featuresDisplayed.isRegistered(features[index].getType())) ++ // <<<<<<< HEAD + /* + * features in null group are always displayed; other groups + * keep their current visibility; new groups as 'newMadeVisible' + */ + boolean groupDisplayed = true; + if (group != null) ++ // ======= ++ // continue; ++ // } ++ // ++ // int index = 0; ++ // while (index < features.length) ++ // { ++ // String fgrp = features[index].getFeatureGroup(); ++ // oldGroups.remove(fgrp); ++ // if (!featuresDisplayed.isRegistered(features[index].getType())) ++ // >>>>>>> refs/heads/develop { - if (fgrp != null) ++ // <<<<<<< HEAD + if (featureGroups.containsKey(group)) ++ // ======= ++ // if (fgrp != null) ++ // >>>>>>> refs/heads/develop { - Boolean groupDisplayed = featureGroups.get(fgrp); - if (groupDisplayed == null) - { - groupDisplayed = Boolean.valueOf(newMadeVisible); - featureGroups.put(fgrp, groupDisplayed); - } - if (!groupDisplayed.booleanValue()) - { - index++; - continue; - } + groupDisplayed = featureGroups.get(group); } - if (!(features[index].begin == 0 && features[index].end == 0)) + else { - // If beginning and end are 0, the feature is for the whole sequence - // and we don't want to render the feature in the normal way - - if (newMadeVisible - && !oldfeatures.contains(features[index].getType())) - { - // this is a new feature type on the alignment. Mark it for - // display. - featuresDisplayed.setVisible(features[index].getType()); - setOrder(features[index].getType(), 0); - } + groupDisplayed = newMadeVisible; + featureGroups.put(group, groupDisplayed); } } - if (!allfeatures.contains(features[index].getType())) + if (groupDisplayed) { - allfeatures.add(features[index].getType()); - } - if (!Float.isNaN(features[index].score)) - { - int nonpos = features[index].getBegin() >= 1 ? 0 : 1; - float[][] mm = minmax.get(features[index].getType()); - if (mm == null) - { - mm = new float[][] { null, null }; - minmax.put(features[index].getType(), mm); - } - if (mm[nonpos] == null) - { - mm[nonpos] = new float[] { features[index].score, - features[index].score }; - - } - else + Set types = asq.getFeatures().getFeatureTypesForGroups( + true, group); + for (String type : types) { - if (mm[nonpos][0] > features[index].score) - { - mm[nonpos][0] = features[index].score; - } - if (mm[nonpos][1] < features[index].score) + if (!allfeatures.contains(type)) // or use HashSet and no test? { - mm[nonpos][1] = features[index].score; + allfeatures.add(type); } + updateMinMax(asq, type, true); // todo: for all features? } } - index++; } } /* - * oldGroups now consists of groups that no longer - * have any feature in them - remove these ++ //<<<<<<< HEAD + * mark any new feature types as visible */ - for (String grp : oldGroups) + Collections.sort(allfeatures, String.CASE_INSENSITIVE_ORDER); + if (newMadeVisible) { - featureGroups.remove(grp); + for (String type : allfeatures) + { + if (!oldfeatures.contains(type)) + { + featuresDisplayed.setVisible(type); + setOrder(type, 0); + } + } ++ // ======= ++ // * oldGroups now consists of groups that no longer ++ // * have any feature in them - remove these ++ // */ ++ // for (String grp : oldGroups) ++ // { ++ // featureGroups.remove(grp); ++ // >>>>>>> refs/heads/develop } updateRenderOrder(allfeatures);