/******************************************************************************* * Breakout Cave Survey Visualizer * * Copyright (C) 2014 James Edwards * * jedwards8 at fastmail dot fm * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *******************************************************************************/ package org.breakout; import java.math.BigDecimal; import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.RowFilter; import javax.swing.table.TableModel; import org.andork.q.QObject; import org.breakout.model.SurveyTableModel; import org.breakout.model.SurveyTableModel.Row; public class SurveyDesignationFilter extends RowFilter<TableModel, Integer> { private static class Segment { String designation; BigDecimal lowerBound; BigDecimal upperBound; public Segment(String s) { Matcher m = SEGMENT_PATTERN.matcher(s); if (!m.find()) { throw new IllegalArgumentException("Not a valid segment: " + s); } designation = m.group(1); if (m.group(2) != null) { lowerBound = upperBound = new BigDecimal(m.group(3)); } if (m.group(5) != null) { if (m.group(5).equals("+")) { upperBound = null; } else { upperBound = new BigDecimal(m.group(7)); } } } protected void checkBound(String s, BigDecimal bound) throws Exception { BigDecimal number = new BigDecimal(s); if (bound == lowerBound && number.compareTo(bound) < 0) { throw new RuntimeException("number out of bounds"); } if (bound == upperBound && number.compareTo(bound) > 0) { throw new RuntimeException("number out of bounds"); } } public boolean include(String from) { int index = from.indexOf(designation); // allow something to come before the designation as long as it's // not another letter if (index < 0 || index > 0 && Character.isLetter(from.charAt(index - 1))) { return false; } if (from.length() > index + designation.length() && Character.isLetter(from.charAt(index + designation.length()))) { return false; } try { if (lowerBound != null) { checkBound(from.substring(index + designation.length()).trim(), lowerBound); } if (upperBound != null) { checkBound(from.substring(index + designation.length()).trim(), upperBound); } } catch (Exception ex) { return false; } return true; } } private static final Pattern SEGMENT_PATTERN = Pattern .compile("\\s*(\\D+)\\s*((\\d+(\\.\\d+)?)\\s*(\\+|(-\\s*(\\d+(\\.\\d+)?)))?)?\\s*"); Segment[] segments; public SurveyDesignationFilter(String designation) { // this.designation = designation; String[] split = designation.split("[,;]"); segments = new Segment[split.length]; int k = 0; for (String s : split) { try { segments[k] = new Segment(s); k++; } catch (Exception ex) { } } segments = Arrays.copyOf(segments, k); } @Override public boolean include(javax.swing.RowFilter.Entry<? extends TableModel, ? extends Integer> entry) { QObject<Row> row = ((SurveyTableModel) entry.getModel()).getRow(entry.getIdentifier()); if (row == null) { return false; } boolean foundFrom = false; boolean foundTo = false; String from = row.get(Row.from); String to = row.get(Row.to); for (Segment segment : segments) { if (!foundFrom && from != null && segment.include(from)) { foundFrom = true; if (foundTo) { return true; } } if (!foundTo && to != null && segment.include(to)) { foundTo = true; if (foundFrom) { return true; } } } return false; } }