package org.seqcode.projects.seqview.paintable; import java.awt.*; import java.util.*; import java.util.regex.Pattern; import java.util.regex.Matcher; import org.seqcode.genome.location.Region; import org.seqcode.genome.sequence.SequenceUtils; import org.seqcode.gseutils.*; import org.seqcode.projects.seqview.model.RegionMapperModel; import org.seqcode.viz.colors.ColorSet; public class RegexMatchPainter extends RegionPaintable { private RegionMapperModel<String> model; private ColorSet cs; private RegexMatchProperties props; public RegexMatchPainter(RegionMapperModel<String> model) { super(); this.model = model; model.addEventListener(this); cs = new ColorSet(); props = new RegexMatchProperties(10); } public RegexMatchProperties getProperties() {return props;} public void cleanup() { super.cleanup(); model.removeEventListener(this); } public void addRegex(String r) { props.addRegex(r); } public void addRegex(String label, String regex) { props.addRegex(label,regex); } public void removeEventListener(Listener<EventObject> l) { super.removeEventListener(l); if (!hasListeners()) { model.removeEventListener(this); } } public synchronized void eventRegistered(EventObject e) { if (e.getSource() == model && model.isReady()) { setCanPaint(true); setWantsPaint(true); notifyListeners(); } } public int getMaxVertSpace() { return 40; } public int getMinVertSpace() { return 40; } public void paintItem(Graphics2D g, int x1, int y1, int x2, int y2) { if (!canPaint()) { return; } int w = x2 - x1; int h = y2 - y1; Region region = getRegion(); int regionstart = region.getStart(), regionend = region.getEnd(); int regionwidth = regionend - regionstart; String wholestring = model.getResults(); char[] chararray = wholestring.toCharArray(); int length = chararray.length; SequenceUtils.reverseComplement(chararray); String revcomp = new String(chararray); if (wholestring == null) { return; } cs.reset(); clearLabels(); ArrayList<RegexHit> hits = new ArrayList<RegexHit>(); for (int i = 0; i < props.expressions.length; i++) { if (props.expressions[i] == null) { continue; } if (props.expressions[i].length() == 0) { continue; } String label = props.labels[i]; Pattern pattern = Pattern.compile(props.expressions[i]); if (pattern == null) {continue;} Matcher matcher = pattern.matcher(wholestring); while (matcher.find()) { String chars = matcher.group(); int start = matcher.start(); int end = matcher.end(); RegexHit hit = new RegexHit(start,end,label,true,false,cs.getColor(chars)); hit.labels.add(chars); if (hits.contains(hit)) { hits.get(hits.indexOf(hit)).combine(hit); } else { hits.add(hit); } } matcher = pattern.matcher(revcomp); while (matcher.find()) { String chars = matcher.group(); int end = length - matcher.start(); int start = length - matcher.end(); RegexHit hit = new RegexHit(start,end,label,false,true,cs.getColor(chars)); hit.labels.add(chars); if (hits.contains(hit)) { hits.get(hits.indexOf(hit)).combine(hit); } else { hits.add(hit); } } } for (RegexHit hit : hits) { int startx = getXPos(hit.start, 0, regionwidth, x1, x2); int endx = getXPos(hit.end, 0, regionwidth, x1, x2); g.setColor(hit.color); g.drawRect(startx, y1+1, Math.max(endx - startx,1), h-2); if (hit.plus) { g.drawLine(startx,y1+1, endx, y1 + h/2); g.drawLine(startx,y1+h, endx, y1 + h/2); } if (hit.minus) { g.drawLine(startx, y1 + h/2, endx, y1+1); g.drawLine(startx, y1 + h/2, endx, y1+h); } for (String l : hit.labels) { addLabel(startx, y1, endx - startx, h, l); } } } } class RegexHit { boolean plus, minus; public int start, end; public Set<String> labels; public Color color; public RegexHit (int start, int end, String label, boolean plus, boolean minus, Color color) { this.labels = new HashSet<String>(); this.labels.add(label); this.start = start; this.end = end; this.plus = plus; this.minus = minus; this.color = color; } public int Hashcode() { return start * 5 + end * 6; } public void combine(RegexHit other) { plus = plus || other.plus; minus = minus || other.minus; labels.addAll(other.labels); } public boolean equals(Object o) { if (o instanceof RegexHit) { RegexHit r = (RegexHit) o; return r.start == start && r.end == end; } return false; } }