resources/about.html000644 001750 001750 00000007071 13544613421 015406 0ustar00cyrilcyril000000 000000

SPVIEW

General Disclaimer

SPVIEW (SPectrum-VIEWer) allows to assign experimental high-resolution molecular spectra. The input elements are:

The data are plotted in the center of the window (data area) and the peaks and predicted lines are displayed as ticks in the upper part (pred/exp area). The peaks and/or predicted lines ticks can be associated to one of the data files so that they follow its drawing modifications (X shifts). The association is shown by a common color.

Each assignment is either of frequency or intensity type. Each type is specified by a mark which should be either a space (not assigned with this type), a '+' (to be fitted with this type) or a '-' (to be ignored in the fit with this type). Experimental ticks are topped by global frequency and intensity marks. Each global mark is either a space (if no assignment is of this type), a '+' or a '-' (if all assignments of this type have this mark) or a '?' (if assignments of this type do not have all the same mark).

A so-called EXASG string is associated to each assignment. It is used by the fit job to select the lines to be taken into account. The initial default value of this string for new assignments is 'SPVIEW_EXASG'. This default value can be modified.

The pred/exp area ticks can be selected with the mouse and in this way predicted lines can be assigned to each experimental peak (see Popup menus below). Once this is done, one can save the assignment file (Assignment menu).

Popup menus:

More help: by right-click (Command-click, ...) on active menu items and by tooltips for buttons.

Contact

Website

resources/JFSelPred/jmiaddassf.html000644 001750 001750 00000000315 13544613421 020151 0ustar00cyrilcyril000000 000000

Add pred assignment(s) to exp

Add the selected predictions as frequency assignments to the selected experimental peak.

resources/JFSelPred/jmipredno.html000644 001750 001750 00000000201 13544613421 020025 0ustar00cyrilcyril000000 000000

Select

Unselect all predictions in a list.

sources/org/spview/gui/JFCreatePeakFile.java000644 001750 001750 00000025605 13544613421 021641 0ustar00cyrilcyril000000 000000 package org.spview.gui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.geom.Point2D; import java.io.File; import java.util.ArrayList; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.filechooser.FileNameExtensionFilter; import org.spview.filehandler.FortranFormat; import org.spview.filehandler.DataFile; import org.spview.peakfinding.DigitalFilter; import java.awt.Toolkit; ///////////////////////////////////////////////////////////////////// /** * Window for peak file creation. */ public class JFCreatePeakFile extends JFrame implements ActionListener { /** * */ private static final long serialVersionUID = -7784282622048412967L; private String workd; // working directory DataFile dataf; // panels private JPanel pouest; private JPanel pcentre; private JPanel psud; // private JButton jbfile; // spectrum file choice private JLabel jlnfile; // show spectrum file name private JLabel jldwidth; // private JLabel jlthreshold; // show height threshold private JButton jbclose; // cancel button private JButton jbfind; // create button // variables private int filterWidth; // filter width private float threshold; // height threshold private String nfile; // spectrum full file name private Point2D uncert; // X and Y uncertainties private JTextField jftfwidth; // jftf for polynom degree private JTextField jtfthreshold; // jftf for height threshold private JCheckBox inverseButton; // private Component verticalGlue; private JLabel jtuncx; private JLabel jtuncy; private JTextField xuncvalue; private JTextField yuncvalue; ///////////////////////////////////////////////////////////////////// /** * Construct a new JFCreatePeakFile. * * @param cinit initial spectrum file name */ public JFCreatePeakFile(DataFile dataf) { super("Peak File Creation"); // main window setIconImage(Toolkit.getDefaultToolkit().getImage(JFCreatePeakFile.class.getResource("/pixmaps/spview.png"))); addWindowListener(new WindowAdapter() { // clean end public void windowClosing(WindowEvent e) { dispose(); // free window } }); workd = System.getProperty("user.dir"); // working directory this.dataf = dataf; nfile = this.dataf == null ? "" : this.dataf.getname(); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); setLocation(100, 100); // location setSize(405, 254); // size // panels getContentPane().setLayout(new BorderLayout()); JPanel jp = new JPanel(new BorderLayout()); jp.setBorder(null); getContentPane().add(jp, "Center"); pouest = new JPanel(new GridLayout(6, 1, 5, 5)); pcentre = new JPanel(new GridLayout(6, 1, 5, 5)); psud = new JPanel(); // spectrum file jbfile = new JButton("Spectrum file..."); jbfile.setToolTipText("Select the spectrum file to process"); jbfile.addActionListener(this); jlnfile = new JLabel(nfile); // polynom degree jldwidth = new JLabel("Filter Width:"); jftfwidth = new JTextField("7"); jftfwidth.setToolTipText("This is the filter width (in # of points) used for the convolution."); // height threshold jlthreshold = new JLabel("Height Threshold:"); jtfthreshold = new JTextField("0.0"); jtfthreshold.setToolTipText("This is the line height threshold above which lines are detected."); pouest.add(jbfile); pcentre.add(jlnfile); pouest.add(jldwidth); pcentre.add(jftfwidth); pouest.add(jlthreshold); pcentre.add(jtfthreshold); Box boxsud = Box.createHorizontalBox(); // add buttons to box jbfind = new JButton("Find Peaks"); boxsud.add(jbfind); jbfind.setToolTipText("Create peak file"); jbfind.addActionListener(this); boxsud.add(Box.createHorizontalStrut(15)); // south jbclose = new JButton("Close"); jbclose.setToolTipText("Cancel peak file creation"); jbclose.addActionListener(this); boxsud.add(jbclose); psud.add(boxsud); // insert panels jp.add(pouest, "West"); verticalGlue = Box.createVerticalGlue(); pouest.add(verticalGlue); jtuncx = new JLabel("X uncertainty"); pouest.add(jtuncx); jtuncy = new JLabel("Y uncertainty"); pouest.add(jtuncy); jp.add(pcentre, "Center"); inverseButton = new JCheckBox("Down"); inverseButton.setToolTipText("Check this option when spectrum is bottom oriented."); pcentre.add(inverseButton); xuncvalue = new JTextField("0.001000"); xuncvalue.setToolTipText("x uncertainties are written in the peak file output."); pcentre.add(xuncvalue); xuncvalue.setColumns(10); yuncvalue = new JTextField("10.0"); yuncvalue.setToolTipText("y uncertainties are written in the peak file output."); pcentre.add(yuncvalue); yuncvalue.setColumns(10); jp.add(psud, "South"); } private boolean checkValue() { if (dataf == null) { return false; } filterWidth = Integer.parseInt(jftfwidth.getText()); if (filterWidth <= 0) { JOptionPane.showMessageDialog(null, "Filter width has to be > 3"); return false; } // height threshold try { threshold = Float.parseFloat(jtfthreshold.getText()); } catch (NumberFormatException nfe) { // format error JOptionPane.showMessageDialog(null, "threshold is not valid"); jtfthreshold.setText("0.0"); return false; } if (threshold < 0.0) { JOptionPane.showMessageDialog(null, "Threshold has to be >= 0.0"); jtfthreshold.setText("0.0"); return false; } float xUncert, yUncert; try { xUncert = Float.parseFloat(xuncvalue.getText()); } catch (NumberFormatException nfe) { // format error JOptionPane.showMessageDialog(null, "X uncertainty is not valid"); xuncvalue.setText("0.001000"); return false; } if (xUncert < 0.0) { JOptionPane.showMessageDialog(null, "X uncertainty has to be >= 0.0"); xuncvalue.setText("0.001000"); return false; } try { yUncert = Float.parseFloat(yuncvalue.getText()); } catch (NumberFormatException nfe) { // format error JOptionPane.showMessageDialog(null, "Y uncertainty is not valid"); yuncvalue.setText("10.0"); return false; } if (yUncert < 0.0) { JOptionPane.showMessageDialog(null, "Y uncertainty has to be >= 0.0"); yuncvalue.setText("10.0"); return false; } uncert = new Point2D.Float(xUncert, yUncert); return true; } private static double getMinData(double[] data, int size) { double minData = Double.MAX_VALUE; for (int i = 0; i < size; i++) { minData = Math.min(minData, data[i]); } return minData; } private static double getMaxData(double[] data, int size) { double maxData = Double.MIN_VALUE; for (int i = 0; i < size; i++) { maxData = Math.max(maxData, data[i]); } return maxData; } private static String removeExtention(String filePath) { // These first few lines the same as Justin's File f = new File(filePath); // if it's a directory, don't remove the extention if (f.isDirectory()) return filePath; String name = f.getName(); // Now we know it's a file - don't need to do any special hidden // checking or contains() checking because of: final int lastPeriodPos = name.lastIndexOf('.'); if (lastPeriodPos <= 0) { // No period after first character - return name as it was passed in return filePath; } else { // Remove the last period and everything after it File renamed = new File(f.getParent(), name.substring(0, lastPeriodPos)); return renamed.getPath(); } } private File pickAFileName(String nameSuggestion) { // This method creates an XML File to save the file(s) added in the project. File selectedFile = null; // choose the project file JFileChooser jfcfile = new JFileChooser(nameSuggestion); // default choice directory FileNameExtensionFilter filter = new FileNameExtensionFilter("Peak list file (*.asg)", "asg"); // Only files // .spv jfcfile.setSize(400, 300); jfcfile.setFileSelectionMode(JFileChooser.FILES_ONLY); // files only jfcfile.setDialogTitle("Save Peak List"); jfcfile.addChoosableFileFilter(filter); // add the filter created above jfcfile.setAcceptAllFileFilterUsed(false); // All types of file are NOT accepted jfcfile.setSelectedFile(new File(nameSuggestion)); if (jfcfile.showSaveDialog(this.getParent()) == JFileChooser.APPROVE_OPTION) { selectedFile = jfcfile.getSelectedFile(); if (selectedFile.getAbsolutePath().endsWith(".asg") == false) { selectedFile = new File(jfcfile.getSelectedFile() + ".asg"); } if (!selectedFile.exists() || (selectedFile.exists() && JOptionPane.OK_OPTION == JOptionPane.showConfirmDialog(this.getParent(), "File " + selectedFile.getAbsolutePath() + " already exists! Overwrite?", "Save", JOptionPane.YES_NO_OPTION))) { return selectedFile; } } return null; } private boolean savePeakList(ArrayList peakPositions) { String newFilename = removeExtention(this.nfile); File pickedFile = pickAFileName(newFilename); if (pickedFile != null) { FortranFormat.printAssignmentFormattedOutput(peakPositions, uncert, pickedFile); return true; } return false; } ///////////////////////////////////////////////////////////////////// /** * Process events. */ public void actionPerformed(ActionEvent evt) { // Spectrum file if (evt.getSource() == jbfile) { JFileChooser jfcfile = new JFileChooser(workd); // default directory jfcfile.setSize(400, 300); jfcfile.setFileSelectionMode(JFileChooser.FILES_ONLY); // files only Container parent = jbfile.getParent(); int choice = jfcfile.showDialog(parent, "Select"); // Dialog, Select if (choice == JFileChooser.APPROVE_OPTION) { File f = jfcfile.getSelectedFile(); nfile = f.getAbsolutePath(); dataf = new DataFile(nfile); // full exp file name; dataf.setType("dataread"); dataf.read(); } else { nfile = ""; } jlnfile.setText(nfile); return; } // cancel if (evt.getSource() == jbclose) { dispose(); return; } // find peaks if (evt.getSource() == jbfind) { if (checkValue()) { int pt = inverseButton.isSelected() ? -1 : 1; if (inverseButton.isSelected()) { double yInv = getMaxData(this.dataf.getY(), this.dataf.getNbxy()) + getMinData(this.dataf.getY(), this.dataf.getNbxy()); threshold = (float) yInv - threshold; } ArrayList peakPositions = DigitalFilter.findPeaks(this.dataf.getX(), this.dataf.getY(), pt, threshold, filterWidth); if (peakPositions == null) { JOptionPane.showMessageDialog(null, "No peak detected!"); } else { JOptionPane.showMessageDialog(null, "Number of detected peaks: " + peakPositions.size()); if (peakPositions.size() > 0) { if (savePeakList(peakPositions)) { dispose(); } } } } } } } sources/org/spview/point/PredXPoint.java000644 001750 001750 00000003460 13544613421 021211 0ustar00cyrilcyril000000 000000 package org.spview.point; /** * This class allows to sort prediction file X data. */ public class PredXPoint implements Comparable { private double x; // frequency private double y; // intensity private String jsyn; // assignment /** * Construct a new PredXPoint. * * @param cx frequency * @param cy intensity * @param cjsyn prediction assignment */ public PredXPoint(double cx, double cy, String cjsyn) { x = cx; // frequency y = cy; // intensity jsyn = cjsyn; // assignment } ///////////////////////////////////////////////////////////////////// /** * Get frequency. */ public double getX() { return x; } /** * Get intensity. */ public double getY() { return y; } /** * Get prediction assignment string. */ public String getJsyn() { return jsyn; } /** * Compare frequencies only. * * @param cpxpt the PredXPoint to compare to */ public int compareTo(Object cpxpt) { if( ! (cpxpt instanceof PredXPoint) ) { // not the right object throw new ClassCastException(); } double delta = ((PredXPoint)cpxpt).getX() - x; // compare frequencies if ( delta < 0 ) { return 1; } else if( delta > 0 ) { return -1; } return 0; // equal } } resources/PanAff/jmidefexasg.html000644 001750 001750 00000000237 13544613421 017712 0ustar00cyrilcyril000000 000000

EXASG

Define the default EXASG string for new assignments from the list.

resources/000755 001750 001750 00000000000 13544613421 013401 5ustar00cyrilcyril000000 000000 sources/org/spview/000755 001750 001750 00000000000 13544613421 015156 5ustar00cyrilcyril000000 000000 resources/pixmaps/bottom.png000644 001750 001750 00000006115 13544613421 017077 0ustar00cyrilcyril000000 000000 PNG  IHDR szzzTXtRaw profile type exifxڭWY& 98b ro7I*5IZ7s?#JE%Ք.brn?:"wQcg@Ώr<*w}_/jYWFܟgWw9϶7ޞc_ G3p^TKq!J 1ع K/?mH2FNd%dԍ_ApBkbMo5}h+c3/\\*w`iL eNXB:k{`.pPhu|Ewy t3 \ 퓿2Q8#B<3  ȄLT7 iS4@Vɱ G̉3,)8(!9KYJ(pI%RjJ5qM5Zj"P*Z`HZlR˭ڤ#|zSϽe?nQL?J3NiYfk+xWYuɝ+kY5e,ں` o[x-'1geMU|)gW%$X 8=wțxsJSs_y(,TLPذ`"ړ fid~%:u=+SM8f$|lL}〈8RyГ(T݈xK͖XKc7?$~=Lj>vumah m ,a<-| :?0,G fܼ<C5`8zHx_,ؤ_u8 #^k2|`\ %E}l3aǬ[ YRCN$ZvK=BR[I혇>'lԞE;XOl^Txe]!&pia/H"7<sdI:OҶ-fUf 3P]4h륐ҠL>R p@ܫU448)uFGr g@a,P8X<@>j9U1C *n,Ҵ99 gM(J"N?F9\9`3; mj%$J,{!Ci檅/A9d9;&^u*YZ$WNd آ$VnJNe6[GTS_óLlt+ILCUn4vm5ݏ)Ia=}ibMZ J$ʁM5Է4hFE d ؅am{~6!r[vGwSon 'gIcv},ZKBMR IĨӊ|| u{?5m5u(Ļk&ޏ0C|р.ڔ<5uGmuy) /ȭ+ٯ"wd`X:O99SÙ(#H2zR||HG1sӒ`/=@WE'x~Y&]Z~Ag6hd"oCOgӎ! h/C f}f<gIhNgc]4AŁ+oN;NsF,uyl-C*קѝmE[N68FV *j'<)ZsB'POVJ=5~a  hBxxbKGD pHYs.#.#x?vtIME &.U IDATXåWk\U}oBtH1 MF4i -"V nvJ)A\*B…@KDJ$ԏEB7v,35cw߽Ǜ$w=;Wa OZȫ"2)""R"?DWAԛ-j"rRDR)$33"riFwyϊ!)@?3{5ftDO|#"ceDTKDuu"b@6]bfykywBp?DQu\xD8FGGID3RL KXY`)}^D^p.۷o?+e(`)Oa̯ ߬䜃q9囁ZT*89p!"B`3"RH8bB)n`93#cdY6yw%-}j߾}#y/iJi "nDEYk93(8,"E1A\<'MH)uX+[( "%wލ 0ThR:rFc͞ [E&l⇹9D!1uֆ^ ƕRJ e713=%'upMQJr40hStƍW10`eej,W?ԙbf8FZcuujuKEPJdDDƘI IR IgQRb"jZ\o*NoFN% csw=WHvݿ7mj5QAP*7vѰR{}w&?+JG!Iر nkye{?SSSU܏i4Mesضm8Xkq F|/xj7Z-;:::EsQXGeZk "/..njιڽ)HZ2`" ԝ;w.=&''cf~{9w 7J'6Mԗgbbb/3S̼s=<o4A KIENDB`resources/JobPlay/jmiyreverse.html000644 001750 001750 00000000216 13544613421 020172 0ustar00cyrilcyril000000 000000

Y-reverse

Reverse the Y-axis direction for a data file.

resources/JobPlay/jmiloadhitras.html000644 001750 001750 00000000305 13544613421 020457 0ustar00cyrilcyril000000 000000

Load (as stick) prediction file

Load a prediction file in HITRAN format to plot it as sticks in the data area.

resources/pixmaps/up.png000644 001750 001750 00000006044 13544613421 016220 0ustar00cyrilcyril000000 000000 PNG  IHDR szzzTXtRaw profile type exifxڭW[#) {@<3boߔ{fc].J_0삤K>|Ͼ>|~`<~?yWB ^.N> ګgy,y(1GSHbJ)j9d1sɵphaRbIRJpZt3jm| MZlVZO]z^z<@8yQ'MHi)34,.hmʫzg}a{谦m v"@`<)4+gWXSή( aF R`IJ݃oys7ĜSRw7j;7 /46Lr'}l#h~ q\RC.lutVpx8IcaB_,æ!+s,{3#n)e@$pB ]U\AGh3X4LPx('MrՉ`t*5se8 u: C54YUT>د$zp/Usnhj ):A~eRĊxn#x1YcƘb ÐӟCb2`8Oʤ[pbzF!4g8H!뢞Jb Qګ*Ģ1K4-)Q Vs'&wmh864lz8#Q%= [5'TlvtgpQTj뽖Y† ^EkRYIDQIVj:ulA1̡e30l;6AӘStC66tåhY35/ih?e\>\@f"~̪W)/v dʅj4+Z-UKVʩj>n<1т -uORy}TZ0H#%B>B_4aW0c(8DxDxݐ0B# c .k?OgIk#nh/b֎6RXφ󞌯c]vKFGC#h޶${h@Q)P(Fa HVm Y;&Ddp ÿ0Ί(dG]Y o40C/T4GS^pq7i5gHvC؉T _ݎ>sHv&HwqkINvN_nzJ#-|wα^ ;kq^NnbUacH;i@Fp{Ċi CauC&rX`O; LGbKGD pHYs.#.#x?vtIME 'l i5IDATXíWAk\Uι73LHBa 1qQm ҅EMH KеEDH nB44#2)޻fǝyssw. N4h323zoXtЄfi|`ND^8vaf03RZCk}G)߭#:Kܴsy9D"ch(`1ݻwo @0"("{ J)039kmqT*sM)rz cǎU$"gB9cEZ \1).eJZw;LNNș0r$I >~K1v]T*(7oP!r\n~,=k->NSSJ=no<^#"_3 ˲qA_0 -"eDkW>|bQ1BYAk]'ι&_&f/^DB ZXc? ,,,`rbbgۍ"LLL`n~@\l`=YD ({:~8fggwZtѹxy4}A}-"^'}KDp6Ȓ۹ "PJbDQ, !CDy[򥡵FeC;Y7ឤ&T>Q!M DHӴЍ=)nFyj-tMg񈨰"7T*!MӂHӴ\)\^__w/YSa@x[k*$;3oԄD%-A$E3&#^Yf[[[2AD^ Ax+4b;Bf׻wND<|ІuQ"򺈐o4ѫ0z,}FD=5fJ)uғ(tF {-fѣ[#N{13G=~%E"NǻKIDQjDh։h~t:3"jBIENDB`README.md000644 001750 001750 00000001754 13544613421 012655 0ustar00cyrilcyril000000 000000 SPVIEW ===== > Copyright © < 2015, Christian Wenger > Copyright © 2015-2019, Cyril Richard > <> Summary ------- SPVIEW is a multiplatform Java application that allows graphical assignment of high-resolution molecular spectra. It is possible to load, display and manipulate experimental and simulated spectra (XY ASCII format) as well as stick spectra in various formats (including HITRAN format). Lines can be assigned graphically using the mouse. Assignments can also be modified or removed. Local simulations can be performed in order, for instance, to help assignment in partly resolved line clusters. SPVIEW is also able to produce peak lists from an experimental spectrum. Contributors are welcome. Programming language is java. Source download --------------- You can get SPVIEW source code from the release archives on the latest version from git: git clone https://gitlab.com/lock042/spview.git resources/JobPlay/jmiloadexpf.html000644 001750 001750 00000000272 13544613421 020132 0ustar00cyrilcyril000000 000000

Load peak/experiment file

Load the experimental peak list to plot it as ticks in the pred/exp area.

resources/pixmaps/backward.png000644 001750 001750 00000002623 13544613421 017351 0ustar00cyrilcyril000000 000000 PNG  IHDR szzZIDATXW[hTGfKݤRC(^i. Z/mOEP>I-A>OҒ&$!.q7Ls pathlist = new ArrayList<>(); private ArrayList attrlist = new ArrayList<>(); private ArrayList AttributeOfFilelist = new ArrayList<>(); private ArrayList yReverseElement = new ArrayList<>(); private ArrayList hideElement = new ArrayList<>(); private ArrayList xShiftState = new ArrayList<>(); private ArrayList yShiftState = new ArrayList<>(); private String minX, maxX; private String minY, maxY; private String indexColorPred; private String indexColorExp; public FileParser(String filename) throws ParserConfigurationException, SAXException, IOException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); File fileXML = new File(filename); Document xml = builder.parse(fileXML); Element spvFile = xml.getDocumentElement(); getAttributeList(spvFile, this.AttributeOfFilelist, "File", "AttributeOfFile"); getAttributePath(spvFile, this.pathlist, this.attrlist); getTagValueList(spvFile, this.yReverseElement, "yReverse"); getTagValueList(spvFile, this.hideElement, "hide"); this.indexColorPred = getTagValue(spvFile, "indexColorPred", "0"); this.indexColorExp = getTagValue(spvFile, "indexColorExp", "0"); getTagValueList(spvFile, this.xShiftState, "xShiftState"); getTagValueList(spvFile, this.yShiftState, "yShiftState"); this.minX = getTagValue(spvFile, "xmin", "0.0"); this.maxX = getTagValue(spvFile, "xmax", "0.0"); this.minY = getTagValue(spvFile, "ymin", "0.0"); this.maxY = getTagValue(spvFile, "ymax", "0.0"); } private static void getAttributeList(Node n, ArrayList array, String string, String attribute) { if (n instanceof Element) { Element element = (Element) n; if (n.getNodeName().equals(string)) { array.add(element.getAttribute(attribute)); } // The child nodes of the current node are handled. int nbChild = n.getChildNodes().getLength(); // A list of these child nodes is retrieved NodeList list = n.getChildNodes(); // The program checks into the list for (int i = 0; i < nbChild; i++) { Node n2 = list.item(i); // if the child node is an Element, it is handled if (n2 instanceof Element) { // Recursive use of the method to handle the node and its children getAttributeList(n2, array, string, attribute); } } } } private static void getTagValueList(Node n, ArrayList array, String string) { if (n instanceof Element) { Element element = (Element) n; if (n.getNodeName().equals(string)) { array.add(element.getTextContent()); } // The child nodes of the current node are handled. int nbChild = n.getChildNodes().getLength(); // A list of these child nodes is retrieved NodeList list = n.getChildNodes(); // The program checks into the list for (int i = 0; i < nbChild; i++) { Node n2 = list.item(i); // if the child node is an Element, it is handled if (n2 instanceof Element) { // Recursive use of the method to handle the node and its children getTagValueList(n2, array, string); } } } } private static String getTagValue(Element eElement, String sTag, String defaultVal) { if (eElement.getElementsByTagName(sTag).item(0) == null) { return defaultVal; } NodeList nlList = eElement.getElementsByTagName(sTag).item(0).getChildNodes(); Node nValue = (Node) nlList.item(0); return nValue.getNodeValue(); } private static void getAttributePath(Node n, ArrayList pathlist, ArrayList attrlist) { String type = ""; if (n instanceof Element) { Element element = (Element) n; if (n.getNodeName().equals("path")) { pathlist.add(element); type = element.getAttribute("Type"); attrlist.add(type); } // The child nodes of the current node are handled. int nbChild = n.getChildNodes().getLength(); // A list of these child nodes is retrieved NodeList list = n.getChildNodes(); // The program checks into the list for (int i = 0; i < nbChild; i++) { Node n2 = list.item(i); // if the child node is an Element, it is handled if (n2 instanceof Element) { // Recursive use of the method to handle the node and its children getAttributePath(n2, pathlist, attrlist); } } } } /* getter and setter */ public ArrayList getAttributeOfFilelist() { return AttributeOfFilelist; } public ArrayList getPathlist() { return pathlist; } public ArrayList getAttrlist() { return attrlist; } public ArrayList getyReverseElementslist() { return yReverseElement; } public ArrayList getHideElementslist() { return hideElement; } public ArrayList getxShiftElementslist() { return xShiftState; } public ArrayList getyShiftElementslist() { return yShiftState; } public double getMinX() { return Double.parseDouble(this.minX); } public double getMinY() { return Double.parseDouble(this.minY); } public double getMaxX() { return Double.parseDouble(this.maxX); } public double getMaxY() { return Double.parseDouble(this.maxY); } public int getIndexColorPred() { return Integer.parseInt(indexColorPred); } public int getIndexColorExp() { return Integer.parseInt(indexColorExp); } }resources/JobPlay/jmihide.html000644 001750 001750 00000000155 13544613421 017241 0ustar00cyrilcyril000000 000000

Hide

Hide a data file.

resources/JobPlay/jmisaveproject.html000644 001750 001750 00000000354 13544613421 020656 0ustar00cyrilcyril000000 000000

Save Project

Create a new SVP project. This file contains all the file paths used in SPVIEW. It can be read while the files remain in the same place.

resources/PanAff/jmiexasg.html000644 001750 001750 00000000172 13544613421 017231 0ustar00cyrilcyril000000 000000

EXASG

Set EXASG string from a list.

sources/org/spview/filehandler/TDSFile.java000644 001750 001750 00000011722 13544613421 021533 0ustar00cyrilcyril000000 000000 package org.spview.filehandler; import java.awt.geom.Point2D; public class TDSFile { public static Point2D extractXY(String str) { double cx, cy; // TDS pred-as-stick // check line length if ((str.length() != 97) && // TDS with population (str.length() != 101) && // C3vsTDS with population (str.length() != 92)) { // D2hStark // length error return null; // skip it } // if (str.length() == 92) { // D2hStark if (!str.substring(18, 19).equals(" ") || !str.substring(28, 29).equals(" ") || !str.substring(32, 33).equals(" ") || !str.substring(36, 37).equals(" ") || !str.substring(40, 41).equals(" ") || !str.substring(44, 45).equals(" ") || !str.substring(48, 49).equals(" ") || !str.substring(52, 53).equals(" ") || !str.substring(56, 57).equals(" ") || !str.substring(60, 61).equals(" ") || !str.substring(76, 77).equals(" ") || !str.substring(80, 81).equals(" ") || !str.substring(84, 85).equals(" ") || !str.substring(88, 89).equals(" ")) { // format error return null; // skip the line } try { // read data cx = Double.valueOf(str.substring(0, 18)); // Double for X cy = Double.valueOf(str.substring(19, 28)); // Double for Y Integer.parseInt(str.substring(29, 32).trim()); // validity test Integer.parseInt(str.substring(33, 36).trim()); // validity test Integer.parseInt(str.substring(37, 40).trim()); // validity test Integer.parseInt(str.substring(41, 44).trim()); // validity test Integer.parseInt(str.substring(45, 48).trim()); // validity test Integer.parseInt(str.substring(49, 52).trim()); // validity test Integer.parseInt(str.substring(53, 56).trim()); // validity test Integer.parseInt(str.substring(57, 60).trim()); // validity test Double.valueOf(str.substring(61, 76)); // validity test Integer.parseInt(str.substring(77, 80).trim()); // validity test Integer.parseInt(str.substring(81, 84).trim()); // validity test Integer.parseInt(str.substring(85, 88).trim()); // validity test Integer.parseInt(str.substring(89, 92).trim()); // validity test } catch (NumberFormatException e) { // format error return null; // skip the line } } else if (str.length() == 101) { // C3vsTDS if (!str.substring(24, 26).equals(" ") || !str.substring(33, 34).equals(" ") || !str.substring(47, 49).equals("% ") || !str.substring(54, 55).equals(" ") || !str.substring(68, 70).equals("% ") || !str.substring(85, 86).equals(" ")) { // format error return null; // skip the line } try { // read data cx = Double.valueOf(str.substring(0, 15)); // Double for X cy = Double.valueOf(str.substring(15, 24)); // Double for Y Double.valueOf(str.substring(28, 33).trim()); // validity test Integer.parseInt(str.substring(36, 40).trim()); // validity test Integer.parseInt(str.substring(40, 43).trim()); // validity test Integer.parseInt(str.substring(43, 47).trim()); // validity test Double.valueOf(str.substring(49, 54).trim()); // validity test Integer.parseInt(str.substring(58, 61).trim()); // validity test Integer.parseInt(str.substring(61, 64).trim()); // validity test Integer.parseInt(str.substring(64, 68).trim()); // validity test Double.valueOf(str.substring(70, 85)); // validity test Double.valueOf(str.substring(86, 101)); // validity test } catch (NumberFormatException e) { // format error return null; // skip the line } } else { // TDS (97) if (!str.substring(24, 26).equals(" ") || !str.substring(31, 32).equals(" ") || !str.substring(45, 47).equals("% ") || !str.substring(50, 51).equals(" ") || !str.substring(64, 66).equals("% ") || !str.substring(81, 82).equals(" ")) { // format error return null; // skip the line } try { // read data cx = Double.valueOf(str.substring(0, 15)); // Double for X cy = Double.valueOf(str.substring(15, 24)); // Double for Y Integer.parseInt(str.substring(28, 31).trim()); // validity test Integer.parseInt(str.substring(35, 38).trim()); // validity test Integer.parseInt(str.substring(38, 41).trim()); // validity test Integer.parseInt(str.substring(41, 45).trim()); // validity test Integer.parseInt(str.substring(47, 50).trim()); // validity test Integer.parseInt(str.substring(54, 57).trim()); // validity test Integer.parseInt(str.substring(57, 60).trim()); // validity test Integer.parseInt(str.substring(60, 64).trim()); // validity test Double.valueOf(str.substring(66, 81)); // validity test Double.valueOf(str.substring(82, 97)); // validity test } catch (NumberFormatException e) { // format error return null; // skip the line } } return (new Point2D.Double(cx, cy)); } public static String extractAssignment(String str) { String cjsyn = ""; if (str.length() == 101) { // C3vsTDS cjsyn = str.substring(28, 40) + " " + str.substring(49, 61); } else { // TDS (97) cjsyn = str.substring(28, 38) + " " + str.substring(47, 57); } return cjsyn; } }resources/JobPlay/jmixshift.html000644 001750 001750 00000000325 13544613421 017634 0ustar00cyrilcyril000000 000000

X-shift

X-shift of a data file and the associated pred or exp ticks, if any. The shift area is defined through click and drag.

sources/000755 001750 001750 00000000000 13544613421 013052 5ustar00cyrilcyril000000 000000 resources/JFSelPred/jmilssetp.html000644 001750 001750 00000000214 13544613421 020054 0ustar00cyrilcyril000000 000000

Local simulation

Set parameters for local simulation.

resources/PanAff/jmizoompasy.html000644 001750 001750 00000000250 13544613421 020000 0ustar00cyrilcyril000000 000000

Scale

Pred-as-stick Y-axis zoom. The zoom area is defined through click and drag.

resources/JFSelPred/jmilshide.html000644 001750 001750 00000000234 13544613421 020014 0ustar00cyrilcyril000000 000000

Local simulation

Hide local simulation based on selected predictions.

resources/JobPlay/jmiloadtdsas.html000644 001750 001750 00000000302 13544613421 020300 0ustar00cyrilcyril000000 000000

Load (as stick) prediction file

Load a prediction file in TDS format to plot it as sticks in the data area.

sources/org/spview/filehandler/ExpFile.java000644 001750 001750 00000046123 13544613421 021640 0ustar00cyrilcyril000000 000000 package org.spview.filehandler; /* * Class for experiment file. */ import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import javax.swing.JOptionPane; import org.spview.point.ExpJsynPoint; import org.spview.point.ExpXPoint; //////////////////////////////////////////////////////////////////// /** * This class defines experimental data. */ public class ExpFile { private String name; // file name private double[] x; // X data private double[] y; // Y data private String[] sdobs; // frequency and intensity standard deviations string private ArrayList[] alejsynpt; // frequency mark, intensity mark, assignment, associated pred, comment private String[] exasg; // EXASG private int nbll; // nb of read lines private int nbxy; // nb of points private String str; // to read file private BufferedReader br; private String lnsep; // line separator //////////////////////////////////////////////////////////////////// /** * Construct a new ExpFile. * * @param cname name of the file */ public ExpFile(String cname) { name = cname; // file name nbxy = 0; // nb of points lnsep = System.getProperty("line.separator"); } //////////////////////////////////////////////////////////////////// /** * Read file. *
validity is tested following FORMAT 3000 of eq_tds.f and eq_int.f (assignments.t) */ @SuppressWarnings("unchecked") public boolean read() { Double cx; // to keep X Double cy; // to keep Y // to keep points, unknown nb of points ArrayList alnuo = new ArrayList(); // line number ArrayList alx = new ArrayList(); // frequency ArrayList alfaso = new ArrayList(); // frequency mark ArrayList aly = new ArrayList(); // intensity ArrayList alsaso = new ArrayList(); // intensity mark ArrayList alsdobs = new ArrayList(); // frequency and intensity standard deviations string ArrayList aljsyn = new ArrayList(); // assignment ArrayList alexasg = new ArrayList(); // EXASG ArrayList alcomm = new ArrayList(); // comment String cfaso; // current frequency mark String csaso; // current intensity mark String cjsyn; // current assignment int strl; // line length try{ br = new BufferedReader( new FileReader( new File(name) ) ); // open while( (str = br.readLine()) != null ) { // line read strl = str.length(); // line length if( strl < 31 ) { // line too short continue; // skip it } try { cx = Double.valueOf(str.substring(6,18)); // Double for X cy = Double.valueOf(str.substring(20,31)); // Double for Y } catch (NumberFormatException e) { // format error continue; // skip the line } if( str.substring(1,6).trim().length() == 0 ) { // line number has to be defined invalid("empty line number"); return false; } try { Integer.parseInt(str.substring(1,6).trim()); // validity test } catch (NumberFormatException e) { // format error invalid("not an integer in >>>"+str.substring(1,6)+"<<<"); return false; // invalid read } // keep it alnuo.add(str.substring(1,6)); // line number alx.add(cx); // frequency cfaso = str.substring(19,20); // frequency mark aly.add(cy); // intensity if( strl < 103 ) { // complete with spaces up to 103 characters str = (str+ " "+ " "+ " "+ " "+ " "+ " "+ " "+ " ").substring(0,103); } csaso = str.substring(32,33); // intensity mark // standard deviations if( str.substring(33,43).trim().length() != 0 ) { // frequency standard deviation try { Double.valueOf(str.substring(33,43)); // validity test } catch (NumberFormatException e) { // format error invalid("not a double in >>>"+str.substring(33,43)+"<<<"); return false; // invalid read } } if( str.substring(43,49).trim().length() != 0 ) { // intensity standard deviation try { Double.valueOf(str.substring(43,49)); // validity test } catch (NumberFormatException e) { // format error invalid("not a double in >>>"+str.substring(43,49)+"<<<"); return false; // invalid read } } String cstr = str.substring(33,49); if( cstr.trim().length() == 0 ) { // shrink if empty cstr = ""; } alsdobs.add(cstr); // assignment cjsyn = str.substring(51,72); if( cjsyn.trim().length() == 0 ) { // shrink if empty cjsyn = ""; } // assignment has to be single if( cjsyn.trim().length() != 0 && // not empty and aljsyn.contains( cjsyn ) ) { // found JOptionPane.showMessageDialog(null,cjsyn +lnsep+ "Assignment duplicated in file"+lnsep+ name); return false; // invalid read } // frequency mark, intensity mark, assignment test if( cjsyn.trim().length() == 0 && ! ( cfaso.equals(" ") && csaso.equals(" ")) ) { // no assignment => no freq or int mark invalid("no assignment but a frequency and/or an intensity mark"); return false; // invalid read } if( cjsyn.trim().length() != 0 && ( cfaso.equals(" ") && csaso.equals(" ")) ) { // assignment => freq mark and/or int mark invalid("an assignment but no frequency or intensity mark"); return false; // invalid read } if( ! cfaso.equals(" ") && ! cfaso.equals("+") && ! cfaso.equals("-") ) { // freq mark = space, + or - invalid("invalid frequency mark (must be space, + or -)"); return false; // invalid read } if( ! csaso.equals(" ") && ! csaso.equals("+") && ! csaso.equals("-") ) { // int mark = space, + or - invalid("invalid intensity mark (must be space, + or -)"); return false; // invalid read } alfaso.add(cfaso); alsaso.add(csaso); aljsyn.add(cjsyn); // str.substring(72,73) is blank separator // EXASG string cstr = str.substring(73,103); if( cstr.trim().length() == 0 ) { // shrink if empty cstr = ""; } // assignment, EXASG test if( cjsyn.trim().length() == 0 && cstr.trim().length() != 0 ) { // EXASG without assignment invalid("no assignment but an EXASG"); return false; // invalid read } if( cjsyn.trim().length() != 0 && cstr.trim().length() == 0 ) { // assignment without EXASG invalid("an assignment but no EXASG"); return false; // invalid read } alexasg.add(cstr); // str.substring(103,104) is blank separator // comment cstr = ""; if( strl > 104 ) { cstr = str.substring(104,strl); } cstr = cstr.trim(); // suppress leading and extra spaces (!!!) alcomm.add(cstr); } } catch(IOException ioe) { // IO error JOptionPane.showMessageDialog(null,"IO error while reading file"+lnsep+ name +lnsep+ ioe); return false; } finally { // close if (br !=null) { try { br.close(); } catch (IOException ignored) { } } } // save data nbll = alx.size(); // nb of points if( nbll == 0 ) { // no point JOptionPane.showMessageDialog(null,"No valid data found in file"+lnsep+ name); return false; // invalid read } // sort according to x, nuo, y, sdfreq then sdint ExpXPoint[] expt = new ExpXPoint[nbll]; for(int i=0; i no empty assignment JOptionPane.showMessageDialog(null,"Invalid data found:" +lnsep+ "multi-assignment => no empty assignment"+lnsep+ prevnuo+" "+prevx+" "+prevy+" "+prevjsyn +lnsep+ curnuo +" "+curx +" "+cury +" "+curjsyn +lnsep+ "in file" +lnsep+ name); return false; // invalid read } } else { nbxy ++; // new single line } // to compare with the next one prevx = curx; prevnuo = curnuo; prevy = cury; prevsdfreq = cursdfreq; prevsdint = cursdint ; prevjsyn = curjsyn; } // create arrays x = new double[nbxy]; y = new double[nbxy]; sdobs = new String[nbxy]; alejsynpt = new ArrayList[nbxy]; exasg = new String[nbxy]; prevx = -1.; prevnuo = ""; prevy = -1.; prevsdobs = ""; prevsdfreq = -1.; prevsdint = -1.; int j = -1; for(int i=0; i same x, y and sdobs if( curnuo.equals(prevnuo) && ( curx != prevx || cury != prevy || cursdfreq != prevsdfreq || cursdint != prevsdint ) ) { JOptionPane.showMessageDialog(null,"Invalid data found:" +lnsep+ "same line number => same x, y and sdobs"+lnsep+ prevnuo+" "+prevx+" "+prevy+" "+prevsdobs+lnsep+ curnuo +" "+curx +" "+cury +" "+cursdobs +lnsep+ "in file" +lnsep+ name); return false; // invalid read } if( curx != prevx || ! curnuo.equals(prevnuo) || cury != prevy || cursdfreq != prevsdfreq || cursdint != prevsdint ) { // first occurence j ++; // single line pointer x[j] = curx; y[j] = cury; sdobs[j] = expt[i].getSdobs(); alejsynpt[j] = new ArrayList(); exasg[j] = expt[i].getExasg(); } // add a ExpJsynPoint to the alejsynpt of the current single line ([j]) // a line contains in its alejsynpt all its related ExpJsynPointS. alejsynpt[j].add( new ExpJsynPoint(expt[i].getFaso(), expt[i].getSaso(), expt[i].getJsyn(), -1, expt[i].getComm()) ); prevx = curx; prevnuo = curnuo; prevy = cury; prevsdobs = cursdobs; prevsdfreq = cursdfreq; prevsdint = cursdint; } // sort each alejsynpt (increasing order) // the sort methode needs an array, not an ArrayList ExpJsynPoint[] aejpt; for(int i=0; i 1 ) { // has to be sorted // copy alejsynpt in an array aejpt = new ExpJsynPoint[nbass]; // new array for( int k=0; k(); for( int k=0; k[] getEjsynpt() { return alejsynpt; } /** * Get Exasg array. */ public String[] getExasg() { return exasg; } } resources/PanAff/jmihidebar.html000644 001750 001750 00000000251 13544613421 017516 0ustar00cyrilcyril000000 000000

Vertical bar

Reset a vertical bar which helps to visualize frequency coincidences.

resources/PanAff/jmifaso.html000644 001750 001750 00000000165 13544613421 017054 0ustar00cyrilcyril000000 000000

Assignment

Set frequency mark.

sources/org/spview/peakfinding/Peaks.java000644 001750 001750 00000014531 13544613421 021347 0ustar00cyrilcyril000000 000000 package org.spview.peakfinding; /* Copyright (C) 2001, 2006 by Simon Dixon 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 (the file gpl.txt); if not, download it from http://www.gnu.org/licenses/gpl.txt or write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ import java.util.LinkedList; public class Peaks { public static boolean debug = false; public static int pre = 3; public static int post = 1; /** * General peak picking method for finding n local maxima in an array * * @param data input data * @param peaks list of peak indexes * @param width minimum distance between peaks * @return The number of peaks found */ public static int findPeaks(double[] data, int[] peaks, int width) { int peakCount = 0; int maxp = 0; int mid = 0; int end = data.length; while (mid < end) { int i = mid - width; if (i < 0) i = 0; int stop = mid + width + 1; if (stop > data.length) stop = data.length; maxp = i; for (i++; i < stop; i++) if (data[i] > data[maxp]) maxp = i; if (maxp == mid) { int j; for (j = peakCount; j > 0; j--) { if (data[maxp] <= data[peaks[j - 1]]) break; else if (j < peaks.length) peaks[j] = peaks[j - 1]; } if (j != peaks.length) peaks[j] = maxp; if (peakCount != peaks.length) peakCount++; } mid++; } return peakCount; } // findPeaks() /** * General peak picking method for finding local maxima in an array * * @param data input data * @param width minimum distance between peaks * @param threshold minimum value of peaks * @return list of peak indexes */ public static LinkedList findPeaks(double[] data, int width, double threshold) { return findPeaks(data, width, threshold, 0, false); } // findPeaks() /** * General peak picking method for finding local maxima in an array * * @param data input data * @param width minimum distance between peaks * @param threshold minimum value of peaks * @param decayRate how quickly previous peaks are forgotten * @param isRelative minimum value of peaks is relative to local average * @return list of peak indexes */ public static LinkedList findPeaks(double[] data, int width, double threshold, double decayRate, boolean isRelative) { LinkedList peaks = new LinkedList(); int maxp = 0; int mid = 0; int end = data.length; double av = data[0]; while (mid < end) { av = decayRate * av + (1 - decayRate) * data[mid]; if (av < data[mid]) av = data[mid]; int i = mid - width; if (i < 0) i = 0; int stop = mid + width + 1; if (stop > data.length) stop = data.length; maxp = i; for (i++; i < stop; i++) if (data[i] > data[maxp]) maxp = i; if (maxp == mid) { if (overThreshold(data, maxp, width, threshold, isRelative, av)) { if (debug) System.out.println(" peak"); peaks.add(new Integer(maxp)); } else if (debug) System.out.println(); } mid++; } return peaks; } // findPeaks() public static double expDecayWithHold(double av, double decayRate, double[] data, int start, int stop) { while (start < stop) { av = decayRate * av + (1 - decayRate) * data[start]; if (av < data[start]) av = data[start]; start++; } return av; } // expDecayWithHold() public static boolean overThreshold(double[] data, int index, int width, double threshold, boolean isRelative, double av) { if (debug) System.out.printf("%4d : %6.3f Av1: %6.3f ", index, data[index], av); if (data[index] < av) return false; if (isRelative) { int iStart = index - pre * width; if (iStart < 0) iStart = 0; int iStop = index + post * width; if (iStop > data.length) iStop = data.length; double sum = 0; int count = iStop - iStart; while (iStart < iStop) sum += data[iStart++]; if (debug) System.out.printf(" %6.3f %6.3f ", sum / count, data[index] - sum / count - threshold); return (data[index] > sum / count + threshold); } else return (data[index] > threshold); } // overThreshold() public static void normalise(double[] data) { double sx = 0; double sxx = 0; for (int i = 0; i < data.length; i++) { sx += data[i]; sxx += data[i] * data[i]; } double mean = sx / data.length; double sd = Math.sqrt((sxx - sx * mean) / data.length); if (sd == 0) sd = 1; // all data[i] == mean -> 0; avoids div by 0 for (int i = 0; i < data.length; i++) { data[i] = (data[i] - mean) / sd; } } // normalise() /** * Uses an n-point linear regression to estimate the slope of data. * * @param data input data * @param hop spacing of data points * @param n length of linear regression * @param slope output data */ public static void getSlope(double[] data, double hop, int n, double[] slope) { int i = 0, j = 0; double t; double sx = 0, sxx = 0, sy = 0, sxy = 0; for (; i < n; i++) { t = i * hop; sx += t; sxx += t * t; sy += data[i]; sxy += t * data[i]; } double delta = n * sxx - sx * sx; for (; j < n / 2; j++) slope[j] = (n * sxy - sx * sy) / delta; for (; j < data.length - (n + 1) / 2; j++, i++) { slope[j] = (n * sxy - sx * sy) / delta; sy += data[i] - data[i - n]; sxy += hop * (n * data[i] - sy); } for (; j < data.length; j++) slope[j] = (n * sxy - sx * sy) / delta; } // getSlope() public static double min(double[] arr) { return arr[imin(arr)]; } public static double max(double[] arr) { return arr[imax(arr)]; } public static int imin(double[] arr) { int i = 0; for (int j = 1; j < arr.length; j++) if (arr[j] < arr[i]) i = j; return i; } // imin() public static int imax(double[] arr) { int i = 0; for (int j = 1; j < arr.length; j++) if (arr[j] > arr[i]) i = j; return i; } // imax() } // class Peaks resources/PanAff/jmiunassall.html000644 001750 001750 00000000242 13544613421 017742 0ustar00cyrilcyril000000 000000

Assignment

Deassociate all predictions from the selected experimental peak.

resources/JobPlay/jmilpHITRAN.html000644 001750 001750 00000000277 13544613421 017656 0ustar00cyrilcyril000000 000000

Load prediction file

Load the prediction file in HITRAN format to plot it as ticks in the pred/exp area.

resources/PanAff/jmizoomx.html000644 001750 001750 00000000232 13544613421 017273 0ustar00cyrilcyril000000 000000

Scale

X-axis zoom. The zoom area is defined through click and drag.

resources/PanAff/jmirestorex.html000644 001750 001750 00000000171 13544613421 017774 0ustar00cyrilcyril000000 000000

Scale

Restore the initial X scale.

resources/JobPlay/jmishow.html000644 001750 001750 00000000164 13544613421 017310 0ustar00cyrilcyril000000 000000

Show

Show a hidden data file.

resources/JobPlay/jmixunshift.html000644 001750 001750 00000000247 13544613421 020202 0ustar00cyrilcyril000000 000000

X-unshift

X-unshift of a data file and the associated pred or exp ticks, if any.

resources/PanAff/jmiaddexasg.html000644 001750 001750 00000000175 13544613421 017705 0ustar00cyrilcyril000000 000000

EXASG

Add an EXASG string to the list.

resources/JobPlay/jmiexp2.html000644 001750 001750 00000000271 13544613421 017205 0ustar00cyrilcyril000000 000000

Associate experiment to data

Associate the experimental peak list to one of the loaded data files.

resources/pixmaps/end.png000644 001750 001750 00000002762 13544613421 016345 0ustar00cyrilcyril000000 000000 PNG  IHDR szzIDATXWMEޫ]@DD{0Š ==`<=O"0D;;Dbpb6,ffwN5=3ZIuWw^WEGB !@DD4JDDtZ39i0md!f&$<%JE/Zf#xBfFEDǏϗBw,#&O$H$3cmׯ_B#CRʍRJd0L3l{=7ǟaƪw"DrR qeu$$IeB@qFkROp "A)5gB$IclZ')2OI)RJ#PyRsuY)u* 3mbbJRj6 wmZ"R QAJ yU!ĊшmB Z-ZJ 107f 0Pvq ٬ l<Bt1 <ϽLu_(JԻA C(e"z[]n`__:&ǪU:֯_]w[PJeWfa5.^Ggv7_l~G^VC!bDDljG}{p!j|߇<*3T*`̬q5a4.ܼyArkT̎hjjZ>sDc̼5yrr`_\add( ?J"zܹ_k "BV! H0<-466fܘu8`}͕N5$+:\B@)k-&''!iഔmh'PV͢E#"!XK7iz=Z FRЌ?R1<<<ՎwǣҥK+Iծ++ \!PJ~EJuddlw=._/xZZm)y!^f>\*t8mi$5Z<|\.;9]IENDB`resources/PanAff/jmizoomy.html000644 001750 001750 00000000232 13544613421 017274 0ustar00cyrilcyril000000 000000

Scale

Y-axis zoom. The zoom area is defined through click and drag.

sources/org/000755 001750 001750 00000000000 13544613421 013641 5ustar00cyrilcyril000000 000000 sources/org/spview/preferences/000755 001750 001750 00000000000 13544613421 017457 5ustar00cyrilcyril000000 000000 resources/pixmaps/spview.png000644 001750 001750 00000544217 13544613421 017122 0ustar00cyrilcyril000000 000000 PNG  IHDR+{r pHYs.#.#x?v IDATxqYѳ# )Cpg2@@Dpni~IF_kUu!ϸ왽xG9Eb^s}硃/>Я/oPDLSJoWޝwǔ条 9~=JqoDEo]eQi/a<E} k?~-pCNC"M~s>0Txwr4d-|)4?qr!F#"f~ہ65k~s0x"77 #p< o|9@Nf;4/7/ sk@\I Ew~h^ߕ'5z=pMx"ߗ]0n͈Ͱ>DD3n:.L z)T}or0!" .q '9o,O=F^_~woy< 0:."Ncw;|i<'9K-j\{?< Ծ2ϻ:Eļ\vq:n~v #/x{34yB(?Ywf|'3Hx0k\}l˕u ׮BD}^_=?2)a<F^}20`ʋ,a<h~sޘ}""ޛm\̾75xZҼq'ЪI4_k+-xU gs,+ܔ0f>-W~fR_o|I?o|=1I^my>E\` FN@a<DB@O2A0@Ѽ(3`^J0_=,`X=;:9>>DD4m[B?|yg|'蘓+kW:<@ Z} <tƶuM`=HD{?=ʾʗX~g'}шXGX~c%W"ꙙ)ދXrgy#~Cgڞk80"xFgF/Vol;a<0*'|}~-:䲼Xa<0h "x`@^%Y.0Tx`0"#r,s/0x"b~r &c߈P~mD@ ^E|lS^J,O0s#uxs"y %96ח t0hUDL|OlUF,_$n5x^rUh0UyfDļ/\cW9">-"']i[btgI`r|$ pa<𪈘L ;֑|s^0a<??3ZrrU` 0F3.AF(8 `$"?;=? w '0Bya< @DLBM#xC'!|#xrQ^(=$ABx<0:""QBU#YO-i`IByh0n$"Ou(*p%~&f =(/+D$-K#_[?\0>)"Qo >G8VP~gxpa<#"WῙpAP`:a<4DĴ\c7R"Uyc^D,1t±50fxF'"yב|  ?u^7 r,"3 %_wG'l7 xUD17SJK+C5xWϝpc:/@Us6%ύk;/a<DĴW;@lSJo, `\#Pb:fܾ\_A0P1o @U s+K&a<D}JiRzJ)-#s,gs>xAs%*g <סH߄=‹<ύK;3a<@ODc#|6,E= 01<\H#ֈ:Jв6Bo*9o]xWD-܈A$a<`D7"01<H D&B'1<*_H~gH#3mK$|0 bxD xCD,RJObxH~s>6 "|$/(x`"b^B*vl+HFDLK/9-c!fb!u ݆"_U(sY804x`0">Fjۈ^`@3%_ gxw"b^B*A:V|W0腈zK$9oa<i'pQ*/wF t0蜈O)=~fC7\.W.WAWt0hMDLK _=ls%_7E\D,e*@/l@D+nIDDK _=3Sȯa<p51-WL`p)*sX/p-x"M`4U _9睵$.""2|L`ԞK  WAIpX%pS'&)2|00#Y"b^bꙙ_\!:0).X9 x0O)H)=&& l@>9 hi _=w@K+|ym @X.0}"tEM#uwx.ʲ`|0"Twz",`0p:r~b K 䗖 &*c"y&a< HDܗ0R*O)r/ 0z."%;TWWH߄S\@_<0zux8WGQM"= qZ<t0:""RJ`'Ъ\YO-y:<tK眗@ \qEZ$) ~f[ 6peH)H)}3k}jzp1-\_[7\0.("K \`+?SJ+WrpQ_3O t*9 FWQ79"bQof| SJr  1- ~ff.W 'wD<3RparA~i6a<""ʅnX]/ iJG gk  /A}JgJis>X c&`"\vL)-E0FxF%":|lȯ-10 q_6 >39,0hT?40@|JisY0C%`p"bZbB̆]04x#"))ǔfVWsK/C!"bQM?>[T.l]w@ 蕈ʅ|K 26D@/D} )U`t0N? )eygt0ΉiJ\)M"Ƹa<S?V@~et0֕ 6:c_}'缴&5(A-tֱ _ 6x*Azw"6nIMD4<SrA~m܂0y(m V 5 XRJM`U RZ WL`t%%\DD< ~f~W?9 i1M)H)= xs 6 >KEļU?1ARaQxV)'9圗UD,uoT\?*WL +9Vq@x*Atr;CI?"bRze Gy&]R.ȯm`܄#? *_朗0Nx)Aϔwg傼@`d#B ۗ zs>& ."=5sL)< JN00RR[F W_ sY>pՅ@-a<@ ]yPDLSJ?RJOx8sJWym\#F_={)="A<\@G&0"b^ᛔң nbRs^7@:hž\t09yH'a<@ ;y nH'h008y\ O px+HpAx=<.@\0 _.@ x_ A<EyOA\@W&80x4 ^!7~gb&@^J a<0rx%a<0Vxg QU4* 2 D`g`O`6fxIV_g?DO;)7=NLr*'1R<[k%F)ٴ$`M w*'Y$y% `'1S``߳6u1ƭKmϦ~mwQ`= ]B_>Q`oJlSA!켶'S!Եr?cYmW_FO֕eZrdvb<;Ye#Ļ$1Ɲk)m,rY`OK`(3V_=OrNr1Ƹ l'IV_9c.b<[i=JDl+xR$$G.C'1Q`= \rRtlxFYyW%I.b`(ڞL+hV1\l:x6V$dJl*x6R۳$$G.,%1 Q`L+$]}/E&Q`cJV3 XIIN]`c'1N)Vm端[Xz.Eۓi% ls`xVm:_+9)lڞM+GRjwsPM+$o 3&sPI=V$ >Ny<xĴ*Ŀ0λN Sx!U[Y[xqC۫c5W+R[c'cQQL+pbqI%mO~cP৵]=X ˴#(~b<f%d=XY!mϦ#%1 ?Q %XG1e%gb=R/[xz<X`XO(1+l(++l{L1`X`YS{J<;z<QVAb<vxx(xb%"xa%z<QrVo7"n/`{=Irts۹xx-5=ֽu?!_\XN[fZ_&yv`1,lx-b%x-O+>|'Spmg$nzZ-RPVXpT's͢ANWkq?/96D۳$V`#O2^zV.|R:4xYX'J;z7Ƙ9XX$`i{3 a8LRu~c̝ y)<$GֺNr1ƸuB &Lr*o Ifcs<=x'N;I< l*)|G$G9Oc1Ɲ\jvR<^%i{&hoS?ڞ$JF639J\1X&mgI%`$9c:)2ɩ< pd6X:b<6lSAa}}vR<^'i{@>SꑨM7~;Jܡ}1{Ex` ]'9c9O02+W}1ƥ#KIx`$vPv^yI\!oL!;c vR$IN]aIfc#J1ImϦR {Tsp`׼pQ`״]$Inڞ8<kM7 쩣$]1[yx1N$SZ$$]/1Dll'IAOm"x`+\\Owb<U&Y&yrvbq):`p-`[=Ir|h!Mvs#eo޴=% :p(`c=L$\1. l2j{F)$v!b`),$G.޴i{,j`u0h{di%`-\1.lh{F)`m|hp`(,$G.vo޴=v `tڴ=L\1.X'ڴ=Ir|hp"`h;K9ɑ l7mo;cx6m,l$cKxٴ=Ir|hpB9)Ϣ,$Gzo޴=vJ9t!hɴ=L2k)$c+xɴ=Ir|j;wb)YDۋi)@{zZsn)Tr48ɕR<:HOxLG%6n&a<LLm ͦ>$5ra<LYE10{_.gdk0 x$fE0?VCk+Kw[\쾪a0I_궻.xك(&mSU?'ɚr\ HrSUr`Wl_p^.%y[U`vvUuH\3J?n<\3HM ETՇ$ !Kr]UCe(wIY)^ۘD2,LnoPb IDAT[U~4\ISU,GU\[5pdIUvf ^wคpDc?|̾2WX7ݽ~8#uU}% ܎7 T.!0BI~^v_q8`eF0nxoRU`HN_Ho{oXt?/,$kb<亪>K"`,ZM Krdk,YۂX$K Ǫϖ "%y'V䪪\[:Kb<d[UCY`T>X>K"`1(0x fo{R`,AkQ<%8X E}k$̝ZCQ<%yH5Ll%y[Uw6MWUuHʘt0;I 6h_ꦻ q1YIMr/xx907.0C?|+[x7ݽ7Bxf!uU=.;`.\`(~-zݷF Թ%.!ֈ21!XU7٨"${Q<\Uէ$F 1 Ym `LFmQ< q$V!^+;q<S"\W'Q< qJa<5FåMLN$UA0iCdkM\0;:a<gd/!87a<g5F;Sx9^Y 8$$xInsprC? ZUW wxEI%Q<" q;݆ IQp)~c]d\$.}p .ptI>L`u>VMwzxJjWUup9cp4IxOI>GQQ4x9^Qx$$Q<_-5^*m<+7ݽ7 xEܹKx$UI q<0'Rx8hI^x!O5H+mX|W۪3)cUtg{\DUU\1|SwxNd\0ߒ6 T}ULRU7`SxhSU+x 6A<_Kw cbU]o\Wx&x~O_WՃ( ,A{2Få%0Axs1`D.ޢMRInDįq|SV&mU;3n+#`Ʈr<VDVHIމX!HrmjK=0_ꦻ,`\X8Q< 'X0Q<+ Xa<%&yLnX!>UՕBo{ob<\Xa<B #X$עx!H!m3(~c_w3b<vI0oxfN0Cxx2q< f&ɭ(eI0/n+1/xUuݟ`\ Q<UU0#xщfD0qx8q<L&L''a<D%ً,8Sk&a<Qnl6xq< &F#(a<$Q<L8`b L0D0Yx\Hm{Q<LoqkktǪ`6t޺x3l%>(fOpx3bLpxXq< NL%8a< `g 8Q<8Ą' 0DZx(VOpx##q< @|EpDxJr]UDW8~o(/'x1.o;q< I<8 Hx'$x&a<<0DHxO Q<p"xG|(81q<#(8q<w(83q<7(![XFIce&n~x($xQ<0=x'&J0&&N^ 53!VO(q<jx`uDL"fN0X Q<x`u*"O,8X a<hx`*mX$C  >X2T.d/V>ɵeK%iw Ħx`%E8X$a<x_ q<(x`DJ,0$oEiIFYYJr[Uw]ꦻ?0G.$x:̕0Q<"xq<0Kx`6DG!f'mk%6p489p11?Qa<0i76ptx`dBL0$Q<YId[UxFL01.f_Ina<0lbIL8tA09\%ً&ijK5F;[MU ̂88a<pxY%.ɭ(`v8~dku ;Sr88+a<p6xEg6u䒼M`1>vub<prI{X$W8 a<pRcI,N08Q<*'d[UxUV 081.tV_In8a<pTL`u) 8$x_q18${Q<UOrmiPU:c/(ǿ2ॄ$"bl x a<lcg|x9^<['Dp1x$Çw&\%xI(PUvx9%y%8!O!%ɶE?$Xx(~eZɝ8xtaߔd4%N}0X[\?t$1+ Š J Z V?>G]_r-i_ƀ0d|MIF.J_uI#ZT8x_%7DK0$]2ЛxxR䶪K3+b<$Oqgto00WB"ٝq<gn%YV1``Wwo3wŻdx$Uu9_{"/`ƒlm` `;0| %7`d$K$YWz`.̤u3亪>Jp1f"ɪv`l a3䢪U7qdLx$åxx$kFO/ Dox>xQ<3IR4La<LTmUXT80&(ɽQ<34%Y*0&&ɺ~+3p98&&ݭS$OfCw=`">nladYUZ.ɽ(` `Kot {H`jKt)FUoQ<0^.%w퓬e#侪ߵ]` `w{so#HUU}<ˇ0"Q^gl7Iq1H]U-t/r^00Qӥ7W{(`ݪKt)FOvX`\K5'Y0,ɺtGm`Jr[Uu']r1(ӇV7p2I0&EUj8$$YV($kUR>u^ 0 .@$`쒬`侪t8*33Kp~pFIVU ֥^WB0hwITcg`[<ݢKGi'dkORa<PuUFkQU$K餻 '亪>&Sw_Nx8$&*VppdIQB0)wIU Ǘ3QǪ1L/ݽS/pDIF0y$+5$y;-jdj8x8$M0pDʒj#WK8xxEWWKwx]Jߒ0^Ϧ. < 0^A%p}@ 79c$-Kx$,?j IDAT>t\gJrjIIr/Rx/ɾ4p{/Zx-ɃQ<Q,E `%8/ݽ3Cb<䢪8$Q0T NeUj5Z a<CإfNnd%v0A9*vXT6R I[! 58}xNp^ B}U]i`Pu^%]xA%Yss1Jr]U0XZ=MW40hWI6*\lK`r>tZ868ë_;)LM{pl.pTIF7RbxڗQ<, Q$YUgƇU7b<Nr^$,,xM.<.r!\$O}=x=.*x @U]%yx^E4wݽ/b</vx(%YJr1Ir]UW|k.l׺v<p1gK0 ?]ws^2G,sOKr]U%OBgO9ʵpAp,)IO Ru^(a׸x]Q.C곴x%V[;In b<ߕi#)mw? oq1o:e, W%YUg pdV|+[;p7I ׸J4'꺻߹?$Ypb&Y 3/j#Ҷcimk9%YK?3j9m\h/- V{I0_{ x꿣׳`@.l@@w )`\$F 6RAb<%O}$r1`d\%yP|0SIF7`DvxJro,0?.LUU};#o0/.5$k̋a<tx:r/3p^e0]z_f!JӔV-$z`ftq<01I.jWf2Fb<$WՕ^wݽ0.LHx]xHݷ&zN$xiT]_<$Y`j$U^tq<ȹ0bI.jC$#d_UW:z{1#(~6R\b<%YUgOݷ"F*Von0>PUzg$U0IꣾE>uxHŮ<`<\$O}yݏ>F (^6Rg0pI.j'xuU VKw `JGp4{/^r1`<, 0\. TUU}ć500@ץI70 CU]NjBÓV $:ע$ɲ:Jr/~aq1`@F'pvoQ b<@$5ت`8  ?`P.<`ݪ8$ λޫ\8$F0X$Ka<%`8t$޵xwݽWyp&I`4vI8 ɪ>FCwߪ \8ޝVfY H lR!`A! lYfdr{Z4aoh9%1x K[(,TpYn\HwUY0jx r1BQ0zwIjxUR0 $+U\F[gdSU&ި\8$&gdV38]U- KR-yE p&I6U|`~x3I['٪|\8$Q|`6wug(fgr08$ X$;^['k0kC8%N(ɽQ<~a<$YxUud'Iw|t-E ob< $7f/0x$ Tnvn1A?𾻿\x$FO6dA WHѵxw(x^0,<@WM˥I>"@s1o l }߷| %Y ݢ$U.dQU{N:?Ӯr`d%xJw(ɻ,>ux$bpdWU`d0{IU ʧv9r1{Qs02ϵmU݊$ sgZUU0XK(tJZr1$[x`$I0p}`$UU0WncUiEiܸN{x`0$ ?`n̍a<07ߍ&Y)tYH_ LoݽQ$0.s60$0$Zj$ sV40iIUg- LBdUU; .ݭd`|;3񾻿("IJro^Tdm)2p,0C$+SV*0I6UF7~L͓F['{dWU}Hw+$I?|GqSb<0{MCH)0F/֚GII0F-ɢM$;cV"0ZIVA0V.dc,{1cf< +x`j=g{J0FndUU_bx`t\h5WyH06$^ItdZ<&ىx`L6JX ^MU)7x`,4pR$"0$۪=%Y:x`Вj%XpcV0XI>V՝}w10T.dcpOb0$k"I0j N[+$YUW\܇~;04.C U<$وx`PWZ+W$z`h Hp-n a<0$ҍFnd`(.ɻ x`(40(wI6*0$UU a;ʲ*!-x࢒AKw:\.*(`.0':ɽ K2.&cUJ`Q.0$ X&٩xRiL6J% UwUY9S IDAT %k̎Y'd0[IN08Ãe)UL[I$YUWiއ~{ғ4$ag.$!;f!ɦ$9 af0f*!FIQ0_0_mG< %VR.Bi0?03NhVq0?0?Qm`^*8~ݏJp1ILCw0H;}0Œ|t Ge0Hrq5f0)MY>x$۪Z%Y(0&! ;*0!1u5-ݭb$[fCw?*xnY` a;|u <)0ɇ9K02Ro*;-]1Is-)B00V_f76{0.0x00ɹ# \}U= N]0l.%YD g pp9kWa a\p*ݭ$_V/pqx$Fp5{tW<0\\xJ>Wa` a \Aq 0 ɢtqoað]lq+3+;~za0s-xx"`\0r-x2x$+j<\Y[pIU {_wuWpo\a<\x.papa9 W`j<\a<\k0 …efZ<LcpAp9>p0$ٸW)\a<\k0=q] ̎`ׅ 0Ar5.0ȵxٻD% -<<@4AAC_ou#2Y˄䯗.LL!D\8 t|Ä0KD0 .菫0a<̵x0a< j(/Da~j0X\+p.$cs5.$?p-pa< 0Wxk8  Ss5@_Hp4d06T|GO`65a<|εx\/Oj<|As-xWx_RthoxIk9 ÿ}d1`Lg<p ~"x0\Q`8`nNWlP$r50x9p$ ;]&z&[IU/Xǂ0}>`0. h0+?4-a6 Ӭ~a 4a<-ljڲi0&qtf i^.БxZ%U9:-Ӝ$(~c@>, i|")Iz5л$oi(@}-ӒmedkBO6j<ȏ?lKxϏ?XX:Y$$o#xZpzW6 |MO qѰtx-)">ƳtbmNJa,V7."gф,kٝ" Y$l{s5ƳT\p>^ #gqO\m02Hypns<1EƳDx۬Nqٱ4x%pGYan 'gOMn0R@xPq<9YƳG[ĪF 㙵$(~cK0ZN 60MW5a<䭪^l`r3kxh;K5jJ,΃<̇Q3Wxj:$Y9s$gvfcfIje31$g>l)6I̎0YIvz0mi̎0lvI^93IUn#O2"gN>l`0 xf!ɺ0G`.a\l V\ #,y$8,"<$yMS%Vfh5<0gs-`Iv3 yBϱdJ3jeX2O%>L`6I<0HvzM`1<0gL`QvI^gpIUnx2O!d01Ǜ s$hc|a0%^$&=,ɶM?p5㹇k\bdmRJ=\buM[ Ió1=.4s+KWxd[U&\&xnZ<'Ys a<XxZxlL  ǵ\˵x0%YWջp'ǜ0kx`< IDATn`Z`Dń\$[UmL 㹘0KyX.D0?JI0@0Kt\D%<(Lado0o%yS`"$0%Yx0CIުjXǣ;%xhdksw&ɺvHߟ?!XGm`_Ia|_\/h*8#N$yMsG0h{Aa<vB߁$Z>#0@^l}%YWա9Ьj'okLOa|mYqۄ K]syM7N߶} 6>Jj|ÄJZU@7\o0]~'YxFc(a|a7 V&a|=zI$WZ XU@o0=~m h0!IUޱF@wa|[UI"o0IULa|;co"o'$F䵪6g~b?GAU"ݨz-9>i9ћ8xdc9Odׂ9;GG79Ŗ}4⬜vlyA9&J A-qH-$}~.=礁T0@wK)K aV0RJsѩ />xc)i*7a|N[rK)?0L6R6Ɨ0z-1a|IV=:iP%//?xлٔҜy0RJqsuPtKJ_N~`:)9s+a|ɤ#XtG_>uKH_>~`:)9+a|#XtE_.~`̰\"뤔%"/tD}E%"/?Xu%"/ulVJI_H)MGl[L_r[O[r8Y@RJ\Ji:"f>a| 􏞷w>j'/tD}g ?]o dJ) L_P)鈘`@&/.?808ɺR0RJ1[9 J_L~``t%/u A+$/ a|#bs!0x} H_<'>VJI_0I)MGlC&/a|0XN}P8@Rٺ B_ š-a|q@Z)9R H)Gı )a|1,}P@:(NJiι 0~RJqC:lO?|@q @?|~:)93\;V@Y=d!J)0~@ͦK "aoV-_3ac64C?]q d_jl#a|#b/>o\}q 7.G'4C?Gb4}"R-U0?3Rw[O U|)} b)T^ @T eYV#bFFG.+_PN=˲_93Z)Ҹ(8m#q`ugƘS+ƲKzhV=[)z"5[[-R:V .Est$wН_H\;yEs0`,6#B)ֆcy!7wߋl}d;{cݯ\ԝzʭ۱w75,G'Fpb@A{TfSJY}p7Ou"O½w?~߽e_p}+qtW> L 7ORJ)P[FV /nj\Yk|z3-STߞX5 ៙h9q0~k㷆mx7?κzH> +CzJr:lщ]-[ot[D5|C@M5ƺ_ojwb7vy1щVSwRJG,F9MJ)Gӥ~ jO|N/V(o=8>81@o%Moޑл|Wn_cqe4inhũ\<y 7o/qg7i3W9G'dͦ,d'x(cgcla<PHy"qb/>1%RZȲWj}l_xD̖G痮UE"o}鉩Hrw?|Q<ǵ~-(<{3t@o)@7`tO<|n`-pDxҵxRG6:qznI)MgYv9sPjw4N\x@l;L(Q<TfyRVi6༭1qzc-@ϯxc~_#r}r#y<ǩ3 :PG>x*%b7ŋ3gRJu(4xX؄[ M䟽>5M30wŕ/4]y omC>%jI-A`3m>S8s=5m-wtW˖xٔҴ0wn\WV4kڿonͷ6œa0)A`Clq`wو3-z[z%[v\x@0/X{wTcsqbc5Gw9lt;N LFjmq˺i/|<^zbu [,q~aRJt hx<4";ލ]؂M67)P{+uCoCmϨ7D@@60+3yhx`'?Gg|>5R7ƯM3d'S31(:Q<0@Z5RoR(C|z;S3qA04>&iK]nP;Ast$ޘ'w`'Nm .(pǕտd7NA?wONJiԿM] E{ )CGJ)ha@s-'&qznf0oܘkSWx483zGg\o#5\YPL}xz".C7ĸ`m6S6w4<ҁfCS0knJXuh(q|=χ7 P:;_ j4Rǿ)>{cχe0RwRGxjnW((ڷ!sCl Ci;Q[b@>a|o̔((й<ð-ơv?Q,:Ly鉩8>vd^!0?9$/M)MgYv-wCP<0=Q5w.v gOcznx}5W@c}\u%=;Q'>Ws5S.Z<-0Փo\HP1WxT>'`\;eyPJŅ sG|_E@՝ҹ׺ʪRβR]O0eYVR~:;ݍyxt|AIARuZF710^_TL?3r^~u)-]ŕպ\;yU6zy<0@==eku}چ (CɻA݈>u=1=l8:N},ND+k_o-,NuuClB_ ِ_^]?lx%vtW+~㎰n_],\ƿ\Gm$~Ѝ׍l0#+ ݧf\SB+nw?_t->]Yq,.qJuQ:M,Tc] (Bd/݈_^KwC<гg,{eR (!]n*#Ez%r`'OYI ҍ6Y-qru 㟏3x` Nl+u@᝘lǙUyǟŧ7> ،,8񿊈cx4ƺ]q=#&Vnݎ^HP`xs~?O_xXv[,~_i5""Zxdjщn,o|}x}5~r#!@5[b)(o^Ȳl[0>4Q˷Ԟ~h+ҍxNl;@:˲aqTHɟLt77GGmxc(8s@ &L&-ݨ(ߖ,۔*"Q|3-G\!/|p9^T1 ݞXԌh dz2˲iu 㿈6*wm#@TggL5 >ŕպ`{j&h8?XvGBeg4Z)x8>8>v%vefEX޻ \va ϯ,[?g (@M[Ou&h6(K77z?`ؖ,)-UD+ĉvwTc0JF0X29d@sK7>8{'ۆ=D.Bz!˲u9ڄ)x&|ܺ]n}}utW+~<$WVoƳbK<ӯ,[)>"QJ _nO/|T1MsH\x@4GG y޹e@q-gY6^<àkewNlO>ס;q#[.dzDJ)匄u7?+7SA޻utW+hեZ7XmZ)ƃ< rv1~vjw+s6hFc35g+εѹjP6Wm@rZ7?;̂j8L GX%<P26W0*8R|_k>ybSjoS5no:;Mn('xa|EZxѹ齻cS6(>XNJi){ǯ Kst$6b/.u J|S]0Cv]K7joS|wS;ͬ(.W%7Wx|O/|?xՐ{鉩hP*UW=ʥksM<̃Ov=hN6fSJU~Ya<@ ,Ə]w-;˃ϣDk9{c.}$کt[]0΍xBXv@- Kʶx5gO>[g@#o{ŻbOc,NM4>g~b< Z Bb ir@:5YH ovl\MbZ0SIzaLk8 ?qXY@!_㿯P v)I2(~v? ik|}lTRc"\saW{1>2r_=ذ P +Zby9=xYȔ" wZpV^Fؘa惍>8*=љOd "@`Rd ObzRA>x{^ik<@ş_z̭G6x]+ޔ1^[<@dt95L*Q~o Ht'v zN@j֣zS{w [1ypW< |YB3փ gPjVBzXG}tfѻm@$Y(k O:֣-9ܘyrS[VA $B`tq Dbf!JZoȍ  p,@hϘxH#[yJёpS8‹ C``"1>c=?{aE@s30PNO[<$I)խGξM8Djfq6wZLJDYF09=AU z0N}xX[<%,$Irh3۝VXkYS9(Լ@1O۹3>8*@%2]xxzHX4eO)m]Jy7[`|!m5 n̼Pxcz*GG)zx jI.-@4za3NI30L+ 6;cm@)I|fO:VˊB|sQyhkd͎ҭGj^Ƌ- OoŢ ʼJ8(C&PrZOP)@ߔKSբmVт OiV`pߔ7NC[<P4I*1h?K62isJu P$IV @EivgjdJx4x I[?ޱƴezs JcT۶/],̬@n4)h l>I¼x&@V[{agTbV N˗B}i8|Wa2E ƿ dxcz8ѹ9M9QeaxEYB$PQξ򥋅O}l$pS>8*ߡ1~ swgVOi5 B񧒶.ϥ1~4T;DԘR,L[StG[<PSI,>^<ղQ}ZX9xɚ9[>+̬'(D(@n?޶}Z4U9xܘynBzX˓~a8` $Ir=4ڳ}f]3п3 u w,̬}(D8aDM@҃4fk㖫O!-jEcpV+lv-FA$Y({;6'kaN4Ї)ԧp>]`f oۊ>iN|i*:DoB@ ƟG$c=쇵֞kyip8 PZcodwwKއE xswGV (+$wڇ‰'f@nP|;AT$ 1h3"w3 sa݉zF y =[lLМDCbgUvQXk'fz۱F0`|VSyHV rT9~9y^XlL_<q`~{|vZPri0z$D*mOOC2C[?K_ٟo;EJ% /O_ o\ iZE/_qH~/OM%u;k@pZ<|颵A,Z s0lm6ޘ: ip? ? 8$m঒$Y1ކ`<;~ 1YjLT} oik~7p$ įOC}t˜>+3헿\^pgIg?$xGfjc+#O IDAT{ۚO>LHݜy:Vs@0Kk yCߖˍF5{·9my$IG0pWZgEl}Y9om;hO .><+'hN^z> iFj/0˗¿/R@_Ka+ q НSoXh&CmU9 fT0_2^ z-zJd!%O(n4,CڇG]sJ[wק,7.O_bz bCF_dwZV (}6ޫ-iS:@$f ~l ǟd1Pow,Ȥx0ܘiؙ,6&ךXE1>۽_١\k*[tn'; ikwJ<~'? 7$Gc|" ȭl 07?wZEqЛWo~4k倘L%I] xJIg҇sq+ԘJ=s@,P||~9bx:q.c0fƟlIc4TRzJz 1br=݈*$xLɚ  ex "O i?Yslmܲg,5&( ǯ,L?BdP05ؘx:`|h`RW^ ؅!+3ǭ9؂#5P˗.>{U3@c#^{_h{@$*[0>J}ekNpeSE}y{S@Ped&=_$w4$IBS@;}xd {h/D;0XK M }`{'^V"YH.0k= CPI݇{O~F\m(4fkߋu4`@~騋 >9v*xzYkڒy6_ ?r6b(I\` J$}p)]$}+ခX'x^?KW^nE|owBh˗.Z5P49`M> ZkbpWFL/fVK] 'k!i@'~|ݵik<@Ɂ PJvlldwvNxvZOx;)Z22$B K0>!#=;g%}o#It޿1Bn*'B5'k1½y [FxB[6y9"C0^c<CK.eؘ'XkE=iT.WOCwrl_?4[_7m1,t @I ?vW XHc=* i(>} k}^P3o9jI$Lx (('};ÕIC]x鋙/L&Rl[6;^sy:rτO$+9 nЬ_v6şnǡ)E7;ᝏ7Ko>ã̮>u ^s_m>:l-5& ٌiz y?Q2"(9<r>ٽ_>""wZ}#w2ޢCԁl|}*`oeryf?OxfB+sgމw>ZWJd!ϥ;P ;݅-eE-IɋK3 2T`k9_ -\m<ှ-6&- @w]gnolgv-Bϻ*Xn p$ݸdNYow7 2Rk9^ Գj/sp/dPDãN2T}gU~gk:@!{<Ї%=݉y<U{U6;RerT]n<[n@~:{t+nfpS$In< 9^98]x0 ŗe{CQ\m"]Sc<^s*Nid]`|=+dZI\Tfv P| ؃Q _Wr'z@iϫ1>|ISpoZ㡸|Oڍ}DQ%7 Vn9qx*ݎaJk<֕Ih2`|nT{k/<ЃooPU}v%P6Ii5^XlLXkjji}t[_gj@|PP:d V|\mܪ@A9,^ղCtŁ@/W5>Gv'Ԭ{y$ݸJY`%/y0>p-k@8ԢQXowbƄmʦy(i jX(V^>=eOb1 J@o* (3Tdo @ڍy<c#aeLnnN@*kbI_C/~9+>:;GB̺1^[<Zĕɚa^rԘ7f]IgVY+wc`<k1iw@ U9^@Jϼm}c=Ry_ ?]~YJb@p5zK@/M_οuriv\0Ji wԘs0๚u^V[{RW3}'}Qy(g0*ϣA(舽& [O,w@~r`ۂ@PZ.~WvK9ZZHno=h6>=ےc6i>cO;G K +źO!K'?Pۏm+W0>IY\8%a[^}>6?= !rY5ghnj,@o~x@Z7qX1^0x(U nV'hg+P|H[<f*Y>p>ͺpIl{N }mx@21|0/` z؍ .cY/~P}pڇGDsA\˓~1"Tr / s`چ9TH~v:Ojk/i23`<mYxȝ*zWT~>Y<^swPmBId(Ya/s`ZmՐ/Z{d@( ZCɚ+uH sxdQ{hN^v6Y@u D0x0>IA& i,5&~PMBJ|]%ڍy<` 0T0inQc5f=Q'PCɛ#q C=F"Jfw{b TP<@L ca3`6;=\΅<ƭ{wXU!PB}0~].9^g$Pϝ:q98=,5& H0MmPJB25t0?2ڵ=F ha]=($I=9y!Tڋy<ǠW:E%ەz-T{K_@A(lOD[<pn#q%Ԭ_=v6B7  Z[lL:gnZ}ϵRXK*AÍT;n\=I Mɐ ˟r7pcUl7bsO(XE\Rv^n *aQój/Ҝz[k1`kWy1׬1@_CL^'zg@YHX19%i-'2U̓J`C/ŮyW&ۗewɶ J(~zs\d|MyP;BYHx(j|&} _Z֙P@0*m,r};ٶ@],VTKǍI Rtuq)b<@MS1N`eK4@ϴZ?:&&&:?y5==}uu I0X}UՇϟK9g8iO2::}wlmdd$΍6?ImmsY[ {eW. n]E!q'  ܻG>x.~nꗗ? 'qOL}8@|@_+ @FOw`|՚0[ݪ{T~655{ۏyϟwPD5bp+C_ hOZ1^0 B|Ȉ.n`~ffFe| };~__SSSQXy^h_8m9<r]f}-ǦNǝ4w0.M_2>%6#jk&5 @y57G =zdH̜dnZڞ$HIfgg?U qt><\Qhéb޴߽{;sanp>6QHJ7> 1v9$[w=d XIm4[ALMM5ᄈ $j^#v 9Qvq@Սv^tQmE8a7S!P(C0}W,\uCͻZͮ]o:t16A*|?}j 2@/;[(EVkPUc %;wd]JXZsEr};b|7$, % "D!Ar@N_?Ix3'*%;/伜FFF&N@>>wBqXQ,xbТw( fa.09|)ٶ\WH]0T4.e\N6(͉&9' ƏCRqdN" ?779-,w^'FKH\1'^*>}Tl,26Eۻ)7T,! sݛ! üJwPIRU T|#LaW^ W3s!6Fݠ|P? q?ȷq/jC@_0x䚀4kR~(_:vI0E7pDHѣG/ aAVAFPM>v9զ^[r) 47C|ٳ&cOtNKD7.BXO<666lbGuh kQM< g!ձwVOHL9FFF sk/ .(0Wb@N6S,fD$*&>}#ܹϝEy= N5"[foH_PA`C7Sn|3J`}+-a:kkkd@} \:|?"$;(W,bXV%@O9XE~vv$" /w Ew^o<LP08qm`|؛b[1.[z"Q>C'O>0 Qhqk0`[ A$Pl{) (S/g7`#`<I(nDuL |j*)@ZGeKg6;;k`VT9ΣB6n-N Cʔ#8C0<> = ,Hqn8\ڧOv*PYġqҒ|ɓ'g;J-` @̔C@'xQ\#0E0jZz`*Ȉ΂C0ҶζMLL1!M_JyP+C_TL9|BejjJٳgM5 eǚ7 ' xnsN?gNG:]k<(ō:(U#0S؋{Ԁr񽃣8@!r8 AxNL (" P sss٫W:l\i{W/h?dLW.T+C~< 9. |kkkF~UHYO+K< <@5LOOgO>3R8u!"RM.<{3w4xN 8Y(y8[*Q-&pBTL9u<9X[c>T{#V.@Egx" A+ lsisƿ'U%8SA0(h65596kPr>`b<VxU# +ݠR611_% 'aOl_Jmoî"ovߧ8( 8Sػ]rRP__@u'/ RE?8觙,`$_\\tx{ O]k+[ɶ J | 'IfAX[[666@ꎵIU0F85Bz(˝;wݻ asss6#U8`0`|Tܛk0d! PsFPjSadd${AŒxis{#K0&7:rB)IŞ?g?߳r@'oPS> *Aʞ>}---e Q݃" `#qE0l ynh!er@ٳgM5Z֑G 7@fiPR333Y.vcr̓PBowMup4rzDyC؅Õ?^@R| t`<52??ߩ777gXu&/ilt}#Elkz&/c /\;_?X[[666@m'?m/* ŏ=MbjjStaa g{9؈F,ve諔}@b/wRn3=-.D%؟ O9 9GNThl^^UvΝνlvv8$F4`|k}!{&5j(Kb*%g1)`<TOa0jٹ Pa0jQOx'OdKKKBVld#MR\4=DgϞAnqVփܣa>92,tTx(*^TΉ-6R=gs|;b<0b+ۻ)7MrĚ=f5#sGUlddDxP=&y%YDP&qS1֌g TM޳~Y9ü1<P-G=TݻwU[=" @W:[~g|  $džw-KCr(Ng {UxHґٳgك H@ Y9} mN7>4ȅsƻd'%PSk [Bk zϼ#+ qiC4^/655ՙݽ{HQ;/w jAadrxx j%y@oN+{0j:*?a\'Ot*%YzJ q,lii uv!(LL]yVT^T,5!afz%?C)=y<jf*(N @!+j,4::y#KPh_8ϟ39'lmm͸zĄ%= T<Hҙ$f~~(&dP իWg^m ׆QD0:Rm*\Co.k)ߧr@uPQxqq1{Q622b{.H\<Ƴo<C |1v9AOL//׷m`M9G\S;;0bx*sssFq.;$Lxlvv555e(hffsO m 'sQUw]+C_%6!}Y@0:Rqj~YEa{RUmSw`|R `߿=y$1=:GHW< z*7JTև=VZ[`S1>Tg^/-8;:uxxޖ{>U<Ge F'0L\qR-:Sucp63{t9 y0R(*~>H;;wt3oJ?};b}y)@bguu Eż-N6o ??rL } 88:SyBpz*zo18(0>>K`+(B# 0@q0IXyp<,v}l8 l&68lmmM?@Nw~sQǼ.lqq1saH@xu5 ~:t1@>Y18k3{t9ZVn]0`@FGG;Usss 1KHW>}P#V\w74M9/t}5>>MLiߔ|*Tx$BQnjjJ$*.H_j$O@MRmk-F ɩDLY\kp:70_+ Ə_ދ8eL( }`q 'U/wMsY¹$gqUBowMu*P;89K"'T\ 2rTG ?6P O*^#%.8ɶP|4J=DFGGq=Vtx>x '*$SY9ﰇ"owMqcښn-% eK" ^r<@ͪ@(!$b*lS'džgCF5rXMLLD@8wP9/}8%xl 61H/׷Cgۻɶ A.h8ߕr@58/)C‚hxul͏{ ԉ`|{C%KL9>Tx l@LMM $.(ʖ EcgBhuuո lńi}G= 㺩*@ZC7|7pBϜAi[ 4`@E0~ssЗ@ \2hPLreMUn,8&xA+s#D6?$'%_}*e9 P2b#0/z88IsqqQ("hn ]sssysϟ%68%U`e]m~r~9!%b1z Ogb@~H۽{yD) \V5S1ݔ}#S2'̠GC1ߑr8 *ЇZN)Bpݻw@,2S7utI<pa. @~0h###d!GܧuO ^N!B333B!4v(A~HTg#F]qubrm6Z|x. ?$E8K9ҎB||gjRn { iEҸ|?Hϝ;w:ME$p uE0l_2^o'6( N9#. %),_2)G{8QTD>^Y|κa/(%Q$...f Q1_ÌlRTL.6TՇ*pB4w}T&5qMz,'@wB ?ԭ<04 '^Ogeff&[XX޽k  pƆ!~7:5G㩪!cW@0,  '5%˱fTۡÂwi)c&ݟ^70Ay)ӝ;w:k/߿0#znN-09|)l^4(U?bOKRD9;Â|677;N7uXX>^0u?"鷨w/3g8+Ћ SeW\ ~ \&o[a.ԓ`<@x|/XK###q}mll[|-6fK?mfCSU7. 90w!'Ajڴg~cR{8,x8FGGU?޹UI|!iр^"ly<ǩA/m~P99ub*ʡVߥ<(BP~c}Tŵi6/y||\O<jӧO_v' GTYlnnf?cv믿[XXp]QQ!2 Q7o>|ةg133ݽ{W$*6ЙK/wgsɶ \Jx>ٶ@:n'T_xڄߘ#yp~ TūǏgn\a<'*ǽbbb"9x 3owՙ %6sc첾)ll j;}= ]SSSt(7axO@c(IDen>*/--&BU7HH3M/<8ա:&OB_bi6>>n a`Rx?m Oo"(q-//goξNexف͛7Ǐg#b@rATz ϟKm`|{ C0f41s߃8 jÂL E7t^HDuccCqx2?? ! ϟ?Q\3޽{=GA<7.015_/t~M%O\4]Y(7ԗ`<@u*~ [nuQ |uuUGqlqxB/sP8\Ay!-V銹=֮>qUm*5[)7J{)*41s MgR(V5jSllXVKKK38\!;QE~yyY򅑑NHXl҈9=ʶ`|+BT%CVdje9h*U 8drw@!~b7A@D9t,OE9n޼=~X@߿TaOl%68Ћ[3=_xJؒpd)Z`0Q"xDxyv֭N > 7| onnyx 8\/^oWUB\ު)=41UZS@*֧O>V+0s " 7[ڟ_R'Ў?5GZ- %½[|H͛7=Kr*ӓ:/?''68/w%ɶ_35]4^wz,4Q쉝2$/ M/bK_+ӧO_u0?e4Al^h.xR' O:*8r(i'L6>>n(ऄiOfv?6>leCr8{rxTt9\p6б{iaK}&-Oeos@,鋪:*I 4P|CE >ŋxR3Ri898\,ǜ>Lccvo߾ݙG30| N]}\킃F\p`,CtpDro@Lj/N\XX0 #OU 7[n9;o&uVB\cq}I}r\dcw4kܫ!'4N#"hH3u/T]7 /?~l<dzz:oz7fKKK |Э,߭*iR1ա6uZ)M#dLոfi"r @>}lZ,g܁(O>5 U#D,@]˱#4M=mbbs@qOf截8;;9>>n9os_e}&OXIqW6>vYwb^-v35]4Mz-4!w` R~^~[O>}`xn⩿v⩳x[nekkkƺT"(???y/H7pRovKɶ lE8 SPyrI\=BP?V߃xڊ*;ᕻwz1"~iYADq0M,LF5p!yLOOq":t1k+ۂpq!FSX\4 @#Dh4So߾yaa?b1/T-ݐ| Ӱ_$>CI ㋽}r 8C0\4yI9̳FȈǏw>X\\lzW@'/oݺz|MMMMeMX@9$]?#ƛq+[**:&udžQwɶ R!S4µNUwޡ ܫٳ&xfZ@DHtffLTgyf't/,--u^ iS2::n$ļkvv6o~Dωl "OPI0q-]-T bgAg@m}}?T Nv^: ŁR=~b!+X]]c!۝hXV5 l@0ؖI`[ VxlF"U%&˵e=Ysssp/q!(b<}QQop\"MU2x"``y/fgg=B---uGuuǏ#IIq) 's=V4ZTa_r.CYډpj/o޼-,,4+4"(^:T;Aqr5#N'Em_ RXZ|Rx#-X+vN{:3T/ᢞܧE¤n~sh7 wG*e H{ JdҾT$._dBSc=4@ c3w+-moo_~sUzy꾬R`|97Z|XA 5@E_ 0W N@~o3&qZ9^+^n:/{At_~Y@\\X8)۶@[Cؒ&!_8M#hhxvTZ_#v;~nȶm4k*/F0j4kԑp |+n h7xVR/U%Ϟ=`.R8~6鐌ܿ_ Z(ݛhfrgT*b'97jG'`@{lnȎ{4zsX,E /vSç\A 5D88Eio|[[[U7.|$`Zowޫ^ Eeż(TEpƩV:*xa 2W@~bX'w8\1̻@G0]z@vƩBO<~~`Relg+^g4 ĩE*x$cTr `#wŸʜN&z}] w^S@G0ȝ^RpӧmeZ/wSakk]?n~mh0r#HA6ȕGK2g/A?&5f?f4gO6|T+ぬ W+Uu!㝔[-tGT: y}| \.۶,m4 F\1j]*9s}P-8%d+: PER`UEg,ЍtroH>|}/q#vc,cjob<-zIAX(C88ӧ6lTrN .2A6]k:|gacX'W/M/f!W'c`"23O0ȒEj?UIr |.mi:^scE)ݍ; `| kd0t1)Yf I3gq_ ofGD'KT*9^_:^sjᓾX2%sbXB1|ڷ9QjΎ;BN쿌1L: N/db5<0V?6)P6s<| __ɶmMޜinɅk1`|}yJN\1TΘ?4EX6~l #pϟ D 2y{^(p{m5۶Qow7nTh@1 eGQ~a!'3~`<zBx;e,1 fEs+9x +"Z5(fYgoo5ӧOR0/E=(ݍy6sm{y.@##۬S5{xb4g]!h :L6|Tぬx@B_sj)p8lgT_y6^_1 =#v@/R5ae~\sv|Wȁ0jYOx UsÜ |I ƻ1p+S<"^2VɫcP,kۓsn4`| kTI7`|sP^ `3ś c N/^@*xvFzZE6׾ϷqԒk؛?rn4eTh* 3L-C!~_p0`< -1/ucIϒ@'UfIn~+ }m-bD-l6#gΦ щwZAS.|^JÂ-PƍxHޜ lmۨ5R6Z"Ta}HzvdU웵W7%暋a PD0Ȃ ,ubΊ(]A̽<|# Ͳ>>ɹyB1ވz!\CDsN @x x,ubΊQKp_9I/et<9!F$[*u9{6U[D0hER0^8tږ 4V,b|aR0*Y!ԝS |TS1XY0@bHk!U5|~7J~ [z)?[@z=sD1<n s T/"y!Dz:#`| 1~ y8/z P5ZЁj q#摡 KWٶ "Dzb8G:$`<˖}< `<@Kx4`<@ZG@+ٶyer=p_ \`<@KXLWVͲ]iJgڊYAPD1X*b2a~.B0BZ^B>~2 7wRPD1aYuc<7l6ˠ%ƲzNן.B0ژN B/P-abs^moD1a>&#ѡ&Kw,y;d2?x\leS _"ZL0Z 9#۶D)HDTFQm0yepppQ8 wQ(pgc-۶7HlxGxGU WƨC\0>yep.J08z/몀s>VS z,u"`C0Q91@gY-i69 E aʆáN =0,eMޘcVT،!U ƨKR|[[[M,9YZ`:fĆx^b|ݍz#N%px0W!\c4զ*쑈1Ld 6`0ecE֯0rKB3nxܙf%%ډQe**\?1 .^.R0ɓ'ƫd9眆P1X]Mb7W31P?)PeJޕr•14*쑈!\`<@ x4ΎX"G9Q I'щIK{] %nahd.yppPpkxO0ETs.8_ޚ_Tڌ] :Pߕl3Nkfau]s7~.C0(4 sM/POE1 u 6|Lc2P @!/}F}d.;]jqCxinZǝlfXrQu< D0> ẉp'Zj.K_ȏ΋b<98ۓsnP@(Ä(b5dA+w{+pY-wRu("_LEn~o [TaJ6Ljn]n M,@&~ 5QxqCxy.۶T܌!\ETJ\D׳G"WZ¢y|l<*Խxk^Z,7=[ xwP->d2L6|TB:|щ>*bsw~g04c$~c*N;|t(cPy1hā ޞssq:vdM1ݜk% xHz= Wc4cs ;/~m~}%Q͵u}m@C`P->`<;yi=s \`<@X y} ^S5t{5QaPF11"!Md2ɠ%;yk#yEW!Tb|:jձVyWn~mۨkb@#pl63HWS5|p~8<>=U sW ׃UE^7W˶mT5y#a9x ~J6Yc=5~c_J0E,pi֖Hq~*pwFm#P|m@cW14 0w5W*g1'N۵ W=zH'UZ Z{}%vQ[*@sXc!8G4c4-?2hInRu> ~*xr ng蹊FV~n.OuT6׾g6bblmmcrI·1VqX)ЛD~2xrlbYpH w]}Tx \v-z}|qH̪Kxش`| Yĵ!N2pk8^K=z_*d:8VHJ#ԭouG?u>|ʲmXk!ϗ.b4q!"Seh!!$UWZ^sQ*sÚM#\C/y.'f|GYz {"e0 D|VoggGoUfE.J*$BE#4G1M}f.V?"bA0҃p<g_wPB$k+?mp9G1+\ VCRNm:69D;Mk"l66|Td@,K8Z|pY*Xg6rR((͹ IDAT gɇx_wϹ&b8 Xxw^g0~Tτ\wnk+명ݭo^d:ಬ9,C&cA9w s,@} )v c,ۓuikٶrlE^9HZC0>`0hG m-Xl^E2ٱH!PO)x=^Y6՟msX+k+uh42ktBo{7JcH!@xi8i*;>_KDnkv!`>(`"7[esm]PH0E0>F 6|TYm8\V*f1np E0ȒJi-.,zWrmPh{WB1*N/,@Bl638J_~ezB.Duo[ƷwBGm$\CЮ=u Jwv10ezZRӧmJ d2R9C\>۶B&n1w%E9p8U=`yTm<=sQ?:aޞ 7wBoNȴe@ͷ.(l63g}F+ pAgg$dm:v?njzYzR-H6׿Ϲy\5⋼>R1L@)rf|c7i6sxtI*Px {[d/t>}:?eKQ)P? ל`<^To6;8~s HtTn.B>;l7{Nl@R0~2{G+%T67ܿ_ϝNt*79#Fn"ms Uߦig?f5ٌo yejAfH'o Cҋp@xpptn637¦1K0>Pw^>p M0O~i@gY)*RT"7ms]0~_ R)*+h4jG4cÛ)xS>@ZH-t5Vgr0=+*}7m~}~mE.,T"m3ߋcLl(`f!Py~*99e @xTg~/$J"=z4駟:[[[T'7*Dnߵ 9#U\!P 19<\͐t%E0-UC򻻻ːJyoO .i˸7[e\K3' 鰎 `udfO@^)gYɝ@l97sqCWxy.۶ղ)F UwU ԏ@e s奾;-Dyד1nsMM/ƓpNV?NkONOoe{:«w;_tk [E:p8M%K﫼SW^y%`|}9$&4FZ{ٿxCNʟ%,sZ49g߇CYf>?7z#|E$_W〓 WחaO<M0hJdiQX~<GX~:@Z4~49$AZF]>:kHƅƍwA2n_Ƣdy$C0jR Ɨ+oڻp1$`<M0hOZ8 ˟}4LaXy64!N O>5{U@0n_+k@K!_?i̺]Ζ-j3Çb^?c1" ^xѹwRH(| ^ ʧ l:|[ ҡ|P'G>w6Tծߵ 9(Shb` ׋@e sY 4҃bu$pC>0`={fs #]{}%w7nyi_JAkC2ե'1@FJ<۝x*fy@4,w|vvvo lf&z T/*C6ˑxRz=EjD0>yB ƻ )-*n>4R۝O?W7V?,/4u<сz#`|{#S3t}U2 b5+U9m9qC:<|\?|)UqKv:Ux񢳷:w6n/X]8B{pc/}]l tkzhM"D |]Qh>-`ailx_(= _"[z{{ƭr"#Jlʟ@e s( 27ԇhb8\ `Rv%?1a"ׂtK4Juޞ^tgnvH}ag/h=H%bt+\ 0+\2W =$jMJ0fkzU7Q#:['22/-Խ r|. {x1 -Tw//'op0NP8 x6BukjM;13:' W!gccCS 2u9?S {t*'>U,=}`|FQno`^Z R]HЊIpq8~Qa@!{*UP%}ݾzŘCn,:`ׂ) 6!>8g/ {-.y<}(0 $?̲Pya3> ?P~޽M''yz 9TN6.Usn"kqZl:7aqs=̎9"}qأ xAeO$F=}xCE}`tM}C /{#aP?8PbPp  D0xSDž8<s2~:믿IIhk!2 'n䩤{qBm[+J^3#\&K0e1 t{'x/#;%$,o-UTwbgn.-m.qK0>{9CA!抰,//G"̓`< aaǏ Q%`|>GaO#v0O@mll_vݻ8pdX8,A{it:Q|Ȯ Kк\n,?C0R"V5q!"L\IQ+-+2`pz0#]X\|0+yC6Biŋ诀|ڬ;]2 5CB->`XY. c/MK)^zC8i2.qgyTGU9 I8>!}}k8 ͫ0!* u+K/dK?^Fk_R?0@5ٯH:V*3񝝝:\j0s_jM8in;ɇţClmllhK> }繹0><,^6B9zɶ H_X3{*^zTCh;N͞Df˜hԽqFop|S8#|d|qŋ?QVS|*ͥwAW HjG5sLx R٬eq Cp<TC2-aϕ* ỦC0>j8<+)8pR<}.ս rwǂ C5 {v.9пfbQFIxO&9B8ɓ'V5믿~SU>| P%9GZӶx]7zpP9#q(V^.<<8:\*6L>x@o*?~8{EV&(@wzxooD ɶ,\nPP9 !>8<#8֭[ |{aKP NiPO}u1ٶe.)FG7p~`0ГTΟ1CH;0JH`<)Ph8UbPG777-*G Wz#^ƢӸYR4naN^ժ_b)08~?>\?^xeF\ Ϟ=˶ ƧkeI(>O} ̐S|l6(`0%>՝PXh~FQ.!I0~ψ^6<޽1BHaB(~}}]Ïf t9 )7(a8K58%oi!'㏎pF!yΝkZÇ_P<|˷K/dK?^Hmux]7zpQ4K5 !Pb fϗó!Ha4/,څgћS|^M>,E,H0kBp2or\T5>E7Uj e'Lp8K\2_?s x ‹'Ot)wӮC5}|*m[༄^|[9VT&OKuFD[ʠq(,1fSxc./^0ϑ\D0`677[n9-Z8$ŋ!#;;;ښTtTηtBͫ*OCo>{* ϟ1CaX^^L@<)(@x ۺ_}{BeParIʒP|.Sao|a9TX740:\*P `vBscc#w%3֖EL#x8#p)զՖ1CJJe8v.39BqƧ8Ϝ2H_%f.ZÇ|X` z{%li&u\[U(3 _񭮮풣 E) _PȞ$ ?@Ν;>S8%_#S}8|+K )7vn\nPfBqx etan8@j" K|{{[ݻwO B P}ĭ[a~{s\W5>)cѧl0%'`_\«qc\%_4Tx 5x37>|8">"PM!6 1$Hger*OG5w援س\Oo߽ Ǻ|v 8bς@B xd{{PUwww}(ϟGl[v*t|><`00GR}EKu!q;T`NǃPwf/^~5M P 5x(㡮+IV/׽ rFnP*!L e1&qcw3ρ@aAΝ;Y543jOMy |NXBmK u\nPQq!y#Mwrh4psg>R$p*cX``f,,>~x/³P79n. d¥wTOaB8q7d\n\Gػ`c|3 k #߿U sS!tɶNn8`HxxQq0% ߠZ^.X*}elO0>sM< Q!^y &e oK/$۶XY!LY,26qm|9HJad!677aMyqݻmll}ѧC>/W$ٮ:p][TqSK2Atȡ?28<(I@lf<!(<@aEhaNz#ʞu\[Tk~VC2m⭮V*l45x@Jl($ 5>oz樷/?5P D"`|q¾VUKF_pGqc8d?::PR;wNc "85nllJHa+ɶTn0Hhu̹RC:}(sNq$*$,V[neϞ=33h4Ǐ ?>>͆ HooF/$۶:b4j@}t J Pw}3<mmmս+T+6Tʁ@dql>{©q[GK<X4s HPn0 UU<B2Tx”?/{fOa>R'EpJ~nʞ={9=~x @loovww;̛qcQizD2 .(Vsj~(5 ُH`<_/YW !yΦng@u:AkCI>`r,]NmU$/̇ epBc>4;ᐁp3: !$O?e<Ȟ?s@xB>0 ;#Cy>Y{@̎PjBbf8¼p@}ҩb<dkkkBgLJ@*@D^777Nj?Sv޽l{{[P1ŋ ^oo).^H]U|RnP*!vBqQ1Üt>H7)_㏎\Cwww/|18@-<}T( (\xǺs˳01t/}J S{t} ̟ eg'e5؟[<مCC!gNM e|7ÿHk*BYyY}} | Z4!C*OAp*Aʳ!պwC[p8( xJ',~<&!vmPJ&`0W\A9㋷$/A0>Aʳ Յ[V^*e5=>{7.t (֎L‹xx?~Ν;ٓ'Oϟ_*Ûͦ1Nd<o U}C:e!8@¾yPQ1J|~^U>h|B8>TN&Iuxz>Bmu\[Mày~7ENG2!w>5cn:Y(xj!,}/,Z-? Ia~ sX,@ C >87kvkeq!VU%}Aj'c/@ aS9]0XfBh2aAB+|n0+kV wooѧl0udB o8*xt}}rt{N29.ҁqa +!$?0gyB>Cex@zW1.^HMUsCUz#N.Z|_Ęr2`|~@ʎyYQ1N !|IH>b s?"L+˷PTHʢ0|rBqQWO!+ڪ%ΔN0e#0m!@`($> 4  1Fw m[|RtT4@0(0߯{7u:;3P6j-7a8!X}bggLJG`no][g+u\RgT<{÷j/^簓 {CQ" aְxܢ⤲<0$o!!Tm,RwW1/\JMUo}:FSmPc}q~2qY]!Bt+U;;;Uę2r@ @Bcw|CRLJu?HLOB_8 u!n,j^};]oZ<&axT>8-ݻw 2W~Üqx+&PyC&CNjxN40GN|؜$ѫAiBel\I,  F(`.e j~LgNócV J.o'UUjyxߤ0 rW_p(\0sz>GfYMjlIZ-?Q"ܻaqxo!>M0<@F;G ɶn.-Խ rwOCU|q8<8߽{P(sV>8<%p pIHhIhjN8!!o?臃d&wx9][G(=k֦}:FmPULa>=2qCgnj99=s:P.L $P4md`_Xf'9u2 OK'G=Sy-?Պ3waSF gT4/`B[vxk"|Wqݻpal(~÷T3PV@t0qIeIϫx>P{M2~|aw˷Wc,]\Az@w}T|Ke8|c`v`<PVӂ]8-|OOBV`a<'NlPkOu\\2>@olld[[[ ۺX7lU\}x<]Oa`|(%Y*P^ӂ{xxA.|h y ¤jsss|rM{B0VT>re"8ž-{z {%>|Xn(\k IDATc7.7$܏ ?8"סIP~χRh4֌^h\l?z# PBVq}hr\!2Cd^ý ԇAţ@^__Cw=z=< z{`<]U}u1/WԽ r?Hut:z%u$@e}AnP8s}A @ D6 ˇPr8~ݻ=yA C@ Z!DQyzs0BBA;%IX즾ϫ7֭[bccc|*4ZYZHe+u\}x|ht8@,Z{u'9߶X<U Pa!JP"fU|NLtB$V*s(PFVqu/ DP4`0}?M(ܼy`)D}sNu]CƩݿKFNƟյFkq@0GCqPDaNw-%2%/g!,UW(^**ZQ}d~QZZ h4hIyNhj=/@ qyRM޽{ٳgτ>:u8pn>UΡӍ>f6 UuQCbt:P˼y}a1@㽽Tn>ߺu+:F熐.S O9(/8"T!2ᷠ0O)y(n^SSPNaQkcc#[^^UsNBMKs@y ]h4{8 =ρ'} Hn=/@JAx8>)n,.$ٮ]W->{(Nc #kR2J>Pv=YG*"*xjbwww駟dnTon%Ӻr58}8#\sO}Ԍ`|u3x;-}*+KKn TVu *3mQ.x*Ru/ܼpbXq)@p]t:S0:6}J${r}]v3U\\HyIYWBTpm*3kxUĿ؟g2lr |uΝ P5P:唛%i޸ hd˕f9.@BUaJ}Q@xg2jEpK(5?9.^Hm)Y jVw'{FK%upP2]L^0><H3TRTwea6t+$ەy]8A8ggooϡ'a {KDy (ڿs !X}Νl0R5T¥4u\opNO+:(U=I8@xufe8f~_?::L𰐹CKݻY٬{7Y>&"F6PuVWW+)x$N*W=8.g1¡b<фǗ@&]+K pVQoߥ83jUA*'Խ 8!s{Uq_*:I0~hIϟג{ ݮʕw'Bqb$ܹ C8U|*绹Z|oߥ8sȊʕwWWWhE :s~/kZyGؗp@͜$)BEvuta |+K*ystpqT5d(<}[`|Uon3PRʹ p*eXt:$QU]dNGn_jӒ|-'f~8ܧV7 [:0ettt4`<D7^|OPP5^Tϳt7g+ y] 8ըb^8'9 yTIj}}]8>Q>6oS>sS{%}3̊:UC0jefR״<.Cܣ@ dœ> ǧFo n~/\ʖ.?Mo ͆̈`VUGxxn7Gp8~.$s!v=>o!ηKW#xZP8ܟU-,@}7tt/F8>=>:OiVl؜ݾXpN jfYyj?ý ԉbT yY5P0 TJe|><#*QCx)^v b<Pe'  ci ,L}i K0>&:Њ*aq|c}̙ Q={ano4 >@v]k .>>rfFx2xN},t:X0xNTIHN31gy,^Ny {5R1hZY,u؛Y;*j%á'q';Q=R1G\ZHyݾX+>25\ݮo چá̄nUسГ8@Y(.@en,PWzl؜A@jQ q33+~Kq}n\^^F->[@I O=mP$,Pjy}JM |C&Ԋff:,XvxY߯åsE 9ED`+'bf' sdk*SvC~{.іKh+,۾vuLGJ{J{~lssDfM|\r $ޞBqNR~o~{q8(gP5~8ЈTz׽ r-x!ﺪ:܊lIH~_+\5ZR};U4xOH$-($W7|+Sn^~P 8ʶC0>eUVU6J:\*PMZ(:M0'Pon.-ܼԙde #(\n;.>E1QDpP''yC y!N$v~{]0K,E<@ oQªޣhb`0+Ӝi~á@ɝaFx*GxxF7j V8PPZp2TUQ8IbpCTk;NN@r+۫Aݻ W]rJHj\%hIwVv5۹5ZR}럦 Ɵ8̃uxzvz'% K!8jhI xQ]8á(B{~noo/t:)2< gP}u1ٶ?{q3_y NQPjq8Xo-u)VN8@*~`%Jx,^@|]ㅄ[W_^̈́B\(TV2̝8o@jx(Oy#;B-+KUs}:`+"H=(8$1ٿWۨN7nT,l6rBӭ,3M0~ іgG)þV@Km8߈A q|rh4hI뜶 P~A9 NtB +/WTf7A8RۡZ|B7Gs}q}a,@6i  -(~]\ N!}TCs`fi0@]qP2I{qx8OoZϢ/58=<O0.Tѩ_TW+KhE'ꊣn'צZQ}1I0xF#[^^NM>Yތ/u :Ϫ7r|moo/ %Bqt="Gjsq8Y.,xoTwb͛Ņ\I1^}W878R * !̼ +95TU)'ΔW?K0|7:9RI}eI0~7J+ !O R0p8}.@s`ё''!qZ&P1~['kZJ)}TD` j(Nc"R^}WΆD GN!4h4hI loo@G*tF9nYwF2Y 0p}W xk9%N`UFX Xu5힦TFFF>nWVdddf8~' _:wM".m:_*w.۬Z^ToY~/Y oV,ChT}c|alݭ8TæB@&m|у4Lg2 |C߳pca>*Ɨ{}>]NZQXoxR{ 0BFG8WV{>7zAJ/ G |U5EJ꭯KKK=p8P |)qmdmn-_mJ8-j+++C I"GUyJO>k3_nϦ_%G(\Cmz"5aPjL7a ~ yVcNxy.㚅|D^Fh2:BqM"z*ƷO;W0~<{# yKKKN@dk)[7dR_Vocc^]]-k6d/*4Nx `|\+P1t&kMM(rRgp8$I8ڀz8UH0Y2R⥹ܮ#cotԆ pa¼q^T->cRZyd6 A_ %6OerR>snAiy(pZ^qqHYZc|6?2rEHϘÎzck2v+u,=`ChիkݤqkQ1MT@ %^ O=],Y|;=UmIYcs$ Xx6 |]1pȱ•"]{g"4Gu* v5i0c|NEoW׻7T1HًKsE\v^6#S1LTB#vQ8i8TO0>O\(~`mxيC0t666Tv oڤč_&Hmo31j sqv\hx,|BupJ+++ +4Q$_ -H~M0~o=2tu f_.ⰱM [ŨTd@O rI-<1 IDAT:<%챝:lp>_qZ_p^O+G7Cv\:EJCP164_g}'\n3Z.ߣ Ǯs ká拠굈/..&m5 7 "Gк5qi\3eR-0Qc?&i\?.%gP5sy\KHҴ7:j{\XUCȘ k{V'qx.2r`<0sviDŽ17x,X[챝֍ \oypDիz V->PHx IxL&|_vU3R-\:W|@"!xHzTXg" 3W*@S0 -=UCFrQ:bqq1/!i*8\on-{ 3IEO/L&Zr ?k)n-_Mbma9[W6 _WU_x~ `NcժUfA@f{>qppA"2q )"@:^u6Jt.%{lC*&`| doCqŴl<,'xeSZ$"ʼ9MI(ҵ7R-`KC0\'4uب3Tc8$c<_8b<0s*% au->P{Sbs%cr/ߦ|x!0Gưgee%/td6vJ0̜~g<}(P2KsWZ^Hv7XGՄ&pt V*~&yU*1 4lDf5.{kFc4Ii_1d$[$9Џb|sLn.* #PݻwDDiT"]/߶ fF ,f(&q666fab_63$S1>0AWX8 W4㧹`w ӼQ-`Gcb}}=/ 9Џ8Z|P# 7iT'' Vۛ :{4SV^o1d3ٲ>!YUk 1˱Y0>*ۢ B0> Fa.tNv*qUx1 ̒ qllls&Pez %<x<Y>%,EUR-i>zJ-\Iئi1Ǵw=_ xfhõANEc2z=v/@$_`к `|x1p :β< z,Ϣz@ff63`~~tFn>u677M+p<<^St.%y\ewYN!Y?T->P~!,yk@nf;`x<6|Dt=Tfgg9<p*hOwkj6յo=)!B۝YI-g C3{U`8ßd[=ݻW-&iWVVgJR4 L:@5ظa9ү718PZg lmm-Z|}xs*Ѥ`|޷KD`B<p r_W/"h6| CIVg888(zSYbiiuh,v>pZ:WR>O4Xr}_ n#H1 H7!dhf/@#L8p<@T_@gb6+Ѥ*k ElPH0"aKNr([ CI61VUぜ_/hcXMѤZG0`<@uWC0>}3zdh;`20ßdKY}TrZ|8ёv);Υ$M/߶ *e=b)V!;Lpi\xRa"z8j䚨Hz_4w(?͵o4}qjY?+; kwV&[q7b|y gfxbc^ݳ;b}} :p^/]dĚF>:<!.kwhzGc8~ _h>:j<S]Ғ,y]nm!jI(MP98@?y  YT= /ga2곱1 d;;;sXp?7 `|ZQi}8n{3Tκ8~\]]-VVVB0>nhb8 Gx/gL:5 UCe& lp.[m8E\uBr{#b #aC-~1 uV1>c=? Q/LTjMS-E|YPѾN/lM%),;ppTO24/2Pmά@ӄM=ם zv-\I(跶7@4cq%n]b&{666N6@c8z@vf>3`x<>^z3Puyii4DL}ӕ``wD*Ɨz}>ȋ`| ^!(Lqv3g]1>V3 HJ7a3ҠZ<0 ڱZ'ݪ)Sbmۛ 8NT->n}%z62֧Erƫ|pc:ݻWlnnM:!,K9|݂ӼQ- *8կ~d’~_=T#*{}i fa> Oh"]{GmoTώ4AHa8%i#k֪w`|Xo6Kzz Gx9UL ͦ#LP8@Oq>Yz-?Z'`|ʕSj$X olle' L֓mJQ/dgPKz7phZܿYR]{Υ$ Eߵ kOSizulr8<$o^E00UօHǏ?Xlmm9#@fvNKo b|WS 0`|Yu+fOT%83Əcv6um`Fk>MrǴ֙O(ҵ7:j{D'b:%6@*ɛWQ1>-0]zu8/KKKmo &a4lAzܷYS]ܵo:幢si.#Imoڨ"GY rcc#/(aIL0z+++S7A XgN@*y*j<0U C 0&¸ kx`H: cZ0^8AUV5XGXi2ըfRBviZ__WJ(>m@UTٞ7IZJG.x1-,9g(ݮV`|<Ǖ}f" r&*vоb| @ބC01e25k AecۚT] ŧ+ܧMUy5:Ҷ%RZԼ:ԗ"(bg Kơp a-gb|z S+ ƏcoWBG[[[mo"6 ]PwDJa[W84>moZz=' #y5%A0>nx6E1a2Uك|Ua?Ȁ`| P?a8g\YYK'@xǟ*ar5]spvۛ8#fq_byV[Oѹ4q\&H> ^LDpTA8nۆ cdMQ`<J_j T5ˣG3T]yqۛdXS|cnAiި 8N*ǡ:6|uQ`>p8 C+ ƏcL_~Ec5H eB(>LB߽{W;5ȳgLiuWkO!ã7@28 K0|uQgX:UV| Be<_,L u01,.umZ?`~^_T! s]6@ J4J+6VWn8R4VÄ p B4 LQ>k7:~ZJwmodXbՆZn/p8: ­ >@7*t3 ~/hg [>E 7@RC0>AIf( cuq\JܫT<}tR ! AK1ɓ'NCo8 O]+֧not&H`Y\31~BuVU2gj|=z-_,޻wIo0x. w.Ks|v&H`<9\³ tつ`^{d͛"dΝ;96[ژ;m_bpէΆ.#^888p>a0[kNldx80'|!$^ַ⢓pi@]Z^h6~ 2r/׹NȁM}UPb|Ѝ@FB@N~²=*vww7dcuuu2'5u9%Ӫmmo$Jtur|'~2j|^޽[Ν;mo hD Q}{7:|nS:@ȁJu.5 2U`<$U?|r^U nɓLTRZ0~-O3x\>yp-'O AI8x3 xE0[pfȫͱ9eݻw̨[bΥsy.goj2}ݮ֢@Ƣ<Kj|VVVT8믿! Lw#r8%R%dFpzf>@Ƣ+ƏcOl*;;;/Sz|BQiV%>s)s>J-\yM9C4$`cᾪZ<W*p6mϻ|55mo TP3xWd*`6TFkr]BPz$oaU-HñQ"vP=vyM4bJήSd.J5qg݈YMO،w\74M|E+sLgϞ9-Q<|rWWW03!p}(hn@˭u:W|NS^u03pvD{ crQpap8Ԑ-׿O gwwwzX4sT/w.M ^gwpp`3%d!*Z C'?lllLakkkK KKK:DO&y"wJ•J~ӽ>z&h@H.Nx |d,N`|2@KΎ3gVVV'O>N׏?~@@9*qcaҟ;BU&k{41M! : <Pb|> v2_Xz)NBOf)O3+>hh:rkJWY>U9@c >.$ -CUd@?_Q݂*_RE*9;Y@`ݻwCBYKG@u|=x K;;;IUo%'I3I^ExRmN-egޮgdoMh"]N۵~ՒeXBP;T5(_>vTOI5 |Oc ) F@^󿽇OӹUQ>'Th4LH$T'\_ijZ^p_^_UR54I nt ד!$'z? 'ok ŋ3Y!dM0~7Gg u`RRa} TEjI s'?S#MBa}?ϟ'}}}]k8>k4Gk+3 Ƈ=ykI?P) A2WKЭ`ݚ>hǏOBsiv0> ɇm*x"Ϟ=+vvvO k }sinf,N_CXW5XPnBam(Lp)P x:N+z" YCuf]))0 k\Bxsss^\\ dޟ~g*Hj/B 6'pM訸|չgƗy}>݃Tk%%BPpZy2W[N`|(Z,TV{l{\a0;K hP`0+++&Hu@j{_5kme /hp2Qñs^ 6 XS- g%F z=! QNpR c ƛaj$_~ܷs^sy?j^O8+xR8zn=he0G@m'aCHUOmmm9?@+ %[[rqmjY$!zn x\[F`Vnt.^jFYQIB<7\ίbj~;|㱖"kշmol Q#OlVCv[/jB_rt{jloYPPyZHp<U8Ci[}s%5>7Ib $>?b@ق%5x{}^k8OG<@ڋ2Pn,܍cxx ůP<isgw|[sy PbI0\/'p !ߛ\C(T.pέsTooX#& 'O,ah؄ cIǞF"wL}#?N0܍3mã7@+HsPH"B1|UxYNB&; Su.͝響 _F `tC*\`xI%o hp`0pJ(`6F響6mģkW#ZbtA?Z xs/7o,z3j`]3aۛTM0z$kF A _1`|?c8I%nCŇCOpq{b:5as: @[ .H¦;a%D0~<{$/8L7oчcY©\(7x$U 5t5}KdLIb|-hÇN @ϓb-xtawTh5fH*_@ $3R0>2米Sܿ_Pz9ziX[8]}mJ G6`hx& q]R%@ $O))hOߋpd@øZ0~V|k7G Z[Gp!=TIr7Uo@K͛7^d,a7 P#JXWtpp}!1aS`0saп2M髩Pb{Ν_~Ѽzd7 V sy&_jo$6*zS.@T@R<q[@6n[[[O?dÇ]"%V |Go$FUo!]O_- _BM ;?.b8: 08_kyLNTE@ )H*Z0[0r͢9 0r_;s2K6ZZ 8l$) dowwwR}KnvVd~HīёSQbZW94Ph3a6fM:e'O  ~|y2>qts6JL Ưu$riz}Mjp8ԧuW>h/P0m An-/|9fpp$j04YZ@0<&WBugϞ95n 0Z<ſ/r0݃ 6fE_p2 as@ 'bss@ Io߿?8 @ި?մߩ_ա N!fE_p2 6XZ ؓ!jnMP0Άӧ!^ O𷗯&s|) ->ZOYp2 g Z/ܹSOXW0/:[St.sZJBG=gFCqrQ!Hr'Tx3tR%>4en,|Z5~m*ǫ`<.d j04떋Z@3t7pNaoΙ,q}OFG0ޡ qQ<[."K`<ӧj3 ¸OUա e~b|=p$eshc?aZ $"_ MP"a f?hчcg;}<.^2Lq^$hpyXhs0ExyfCMa| 㤉GNxyX\IҢZ<&EX<;- JEwvv*ݮ(x0>څ O|O^`?srr^@ ƟDSw)~b0h20E%@˭u/w.݃ p^\_c8Z n8}nZ<|p a ͛7' h.xinߩ_jotP_9P@AC9}g~I6?mp;;;/q.wa%P1ܭՔ1 %y6 :~Ib|`-sVvJ׾8;Er):WR>ڽK9Hh>?g-bxZ}ΝIt0hJ8?L5Ph7}O5 /'zti;r\Ϝ@\ϜVV@To&Y:Tw(!i5O #4@ ?"bFcǙi4Ju] W. q]s@8p`<s@`0@Lq姟~BF*svT+Olw֎ YYv'TѵC݋t #sd={^ ,}OiiŊ161HW 2/-r)C  (4y:45P>>5T]XX8ȯ;Lr >?Os֭[ɽ22 83q_s m(\t,?7#&A0Q S 1 ZvNGj-K0޻G^v-]|9}ᇎ8Q~NE~n &mdc˴xN'i g'q}5`byP f3]~=KwMV{ ?!?'xW]F P9!!P]oN"T\+":eآ`<ct:wI.]Jo 70M=ӿ&0$7N"8 fߓj4">](tڵtnȠ}|aa0Swf K0>ij)^ fyfphz<y>UwV(& T>s (M2(<=VLVƖi OALss )._t)[?tPo޻oMsa(+-`$&sY>9*nL`K/nܸK&B/7|s"q. egb<8P}YPz\`|D, t:iaa!]r%]|9B0GVk>c/S(Tǻ(02H߱*|N3yOԀ`iPAf3ݺu $} LWoK.݇~2e8'3-qqiPwR.[0޻Iˡܛ7otsX7vu]9(/9J{[p,ԇü'."Jao(r8!Bf9oׯ_]]a>j6L-%`,իAY;-Pqe۞B$֭tʕttƍtm޻_}PE;WN mvCJI@ŕÏRMNh.`9Ip9Oί .k׮M?/^Gj:...@3ޣ]`,3=';^ȟ*` r7+˓W^Ur*-w :[mo?}ۮEϴx;9,Rw 5P1& Çu?I>tm>hݟ |cc/ϱV[ ؄''y/T_7"eeY0/\p ZSAN+Hix[&p6իXcnW0jl}ŋ<+囝FD`i4[4#(O?H;үßO=MϿWo~P;WN X`֋LT_r (/*2SEpDxߧW_K= r`~oS<_5cM0Iˡ*YiA3Yior _Jn*s01iuҥt^-xSn{|o6&} \}p_-}#zRʉl4ݔҋXpA`>Z`ZAp)ec${{?&+AK91>}35~1,F?]~Kh~~{w%n6WUFD2_`;)_`)0Q?{輪}'Ig_]#"Q֚9-wX ܵktWP~?p}?Tkϥg:iҫSѮBӖ#ZYkR`|&_ϧ#,Oϯ=~Q~= ?tԥnӟ_׽ pw#❲V,SJw0}GCCU~εƾ^Kk8 b-Ũ9 $?GFVۊQs8V+"e.@eZS98Ns٥GD>n韍`;e/L''SÖ6;QS+11Jߝ"[}|g,W$W;0Y5cZ< T{VjRq;iׯ{` H0xʒ񕷢 ҍ 2LÎJVҦ3*L0>"LrnL*lk DpV۩heA x)=Tf%"B0*6ztS U@,^=w鞆0Hrו GD TbVu/D0*' 6zttJNTu^fW+"79c"Y`xuhr'd޺r' | xJ0'S~֪X*NO1irsAsSQJNs8Q7"L/x;ieуսp+j>zVŒI= YWub|\5cxy-mv^8%TC{>.u/("KH08sww^8rS`|gzwUD>zЮ{ 4WWyb|zW`| Z)p*[1}TdzLST:[]`|Im,TѩrXwn|'] >z ^S\S W@f? E0>hm*NA}MLӬGDUjh7}lj|!}ԴP~;*F0VD4P)xJ{;>h%a&G]`.,(YAk5WL<-hea W`<p*SǴxI+"u)`<!yj']%`$O&AK 翺f̴x`|^'}P3dZ<L03};hZѬS)L{_~mZ<vZt=h`)@ vfG* S\iWws0=5  m>*uiׯܾ`ZѬ[N[xW&(2e^v'ZX PGyar=s] ׈Hv']E\\O`,5"gA^"Y  h7>:cmN']|k J{;?(rr אXfWFPҬ J0VW!}Uu@"YCCn˯R 's3u>' w?p ~˯Fd}:Sݻ"gC{VZioqiPF&ט`<pf9_WCr(¬Jn=":u>Dx !|B0 E:+zTn᧿u8^(B0k_l >-"&,FկEis(>7XNK+/LAn/&}\j{{ @nLEI0>' br8筽Uޗ7)>EMX|5wRJs ޹ҭ{1.}w+-"X0~OѸR,^N?ϕryJMS`6#"gkO0FLs鿽W^.MW{Sw w#-h,~P5s/Y|Ŀi]@k]0@ѸRYP#E u#c`FJJB,z.WY?J=Kp6fq|ݎ77i4ҋYP[?w._LM aVZzu@q7i4)fAO&N?sύUv꧍J{dx(7"b|C0Fq=7Y rH>޹wgݽ|V?*'C+".9|QRw^ӝ8L Ɵ Q?НdAeN0~2nWaQҳ SZ*g'?4G!O`DD3^!?9.J@D O`(}Ubr'$"RJJl8;*89ej<d'K0~\zD4k_ ;U 0 褔nWfC8Tm'OnD9ŪmOXD4SJ0,);Up*Y)*n 8( OADpD0~z1X2S"?=.Zh:;U )褔nWrsQ *2=ӵX{Z#?]w9`\ OQD4SJ -t O2S&?}.b;v,"RJJoˠ 3T, φg9":ug "(ԋ3"?;.j5TzD4lΝlj`褔nbP}3$?[.n(VD9-x(?褔ka;ugon F3&?{.r(/y9hki9;PD ρ`||n;XK)jq(7D0~~\P.2s"?? u88XK)jy(H0~yP"s$?_B@GD9͏`EDwk[(4_gj<L ϟk="g,"r0["@q-8/Sd @0ԽP@h:/]"x B0"R]:gNS˖,FzR&=d& 8,X5Aޫf7s!~}'6kЎ%> o0ڡm0I֪>h"!oF-Ia|[|ds'Z@[x%"o0G a|cU}$[o0M"$9{{mz}`7Jߠ$>xI._Y̻Mv q 7*ZU5v pK9K6a<ܟq%Yj?ζ6a||]gIr0߶ 'v@߸$kUg`'L-I>a|p{:N;dsh %< 0nGa|'U}p#[0/:߷$9c?}v;#Hik}'$03I._8>G'Wkɏ >dnw(%?>I/Ws4ˏ>d^}w*%?>AK߷T}퓬/a|ǒj} wN??BLK IDAT9Mn>}Հ&\CUgCƏdg.ƏI;a8oƏc3O$AG O;a U}p5qP$98cه\0~ IVW@?ax/`,$\0~L~Jk; aX>j(ɡtvV>&a\`&ga0]$TSUgp-~`mfSX&/3N?$kUgZ؄#`d$0~pIvUu} ˡ 簛} KK;a6!퓜v| $9T2kc;Y?a<dd9'TU0\0~.$ tO$ZUmp.=;&9\Ir ϳn?!ann>9 >jsO(ɡ8 =)a9$0c'&Tn'&?=8&9ԼKsyFONGib''#@IV0~rIUu}4ˡhc@Iv60(,SI֪ڛ;a<(ВcPxdWUЈEa<3 }忄fЂ$MaBGO(!ChZ܈k|0p5[XLlb|k|0K^xa<"6&7쓜 )IUu45ȵx>MWxl%,a<_!+D|0OKVիI+||> a<_䭪vW $[⫄|Х-x,ZU&/l ]ϼ'9![Ubk|0[x1EŒdg0|0[@a<7PUGʵxnF-Œdg܊0[lG ;>Dy a<dWxa<>xa<&jִHO/<֬i0C&95ӬnCwZŨ0mlC%ag0Qxrصx gWbd5F gGygZ<3kQ0 a<ø>ί6 1c3{w-Jcm\g8xFU`R!b0$Ub fHxFbd$[KgDxt}϶ Lĵx%gdo`î3,a<#۸LbdlF%gXۗMll GݫkNВ.-{\F'gs`TC04a<û>6 hc@,\F`@ aa!g&q)F]U-6 Aa"g6/6tnIDf"g*Gxg 3a<3:ЩkHό.9 ̔L':tH2+a<ڸtfs= 3룿}#3-a<3xu- V埀/̄??k> pvG@d@d "0D` P y\2T 3giw`0LbH1>cZ<b<|x+ (qx/Y#Q#0/b< x8"x8g )qykpdpDVCp|p|+.kppdV` (ix`zÉ( XI2 '''b5&.bI6 ==V< B)CyDC)Cu荌dvU5w^7xeǷLoscNA1j<xxQ] fk-% DkmSUWNr0 aXmaXa@Gv+3C000<3($Y]XRaۭ[``aGQv&saR< b< TdL0\0lGx'Cn(x^^ç÷Z&yv6x1qhID #ZTՕ,OIb$OR KP,,eg)u^vĵ$SgڦNr'bB8}'K1x$qAbg(xࣖUuE^H8G$|HkmVU"_&Q|XZ$_9p ]<&Y9p Q$y[vYcRi}0m$8xhP..ɪ%;s}h' ޸M$^H4za?-0h={\/IDxoR<7@$YUսT.f@(}_Inlxw:ɝCa1>d b<0(IVUu/5w3` b<0DInl DhHMsCd1$wUfN b<0d>sdVP)dSU7]U͝D+):ɝCf1^V@1$$?&FA1yU $Ơ%$0 /*M&FZKfNb<06>OqQF%ɦn LԮƦ%*0:^AX/SVJ1$.0 D(6U/ #IBJ1Uc_,CU= pS`^U;I#tI)dSU I#P)hI LBkmUU?J Lx`JfF^)x`2lFj.D`JZZ{ /ILx`0Tkx`I[Ѐ)RjQU[H0E-Ij_[PTY&+ɪ00eͫj7#vd#"`Z~ߦ~>%A4Y&/CU=N!n3]Ep\IA0  f#68 ABзt朽g2瓴nUYrL\-8O0!m 0om$$ `"|VXc&y+`޵UI2(??| '6N5ڊOהرw?w.`Ǿa%󌶢x1Yo~{3</6ɥ L2ܧ$r~SxV/48KML /b<Mr)K`md. 0؜OI Fm`3F[Ql,7yIC$6mKZ&`\؂1"+yFb6 xhQp4`7F[Q6[y{Vbb<5[pic1IxcJr-1^`d.@0:_%5BxJj IDAT' }p1c$MMۅا0Q<d޴}H2Kd]0ZvI` ػW40)$j`F[%0 cWmoT/_FLLc5LLL% 2LLL6[ԛ 05.0U3*x&z],f0Z0v!` WǴ$`F[0ycWبmoD Թ_ `3.8.p0gIi ž=#xF$5"If"c$MsBt8D$wxF"xNۇ8~=Gn{%.h8c]bPj{RLr&"1mwmoE!s1c0KrIh10}Xm?c`QhHrMvgk11hJrQ->zV1mZNԻ1%,p>p 8:mvr8F$Nĝ-0*ɥ#L2khh\6[-G][p\̒k8B8qRnYxNBEsmGVSbh{R[&}P$bU6'eq8%.pfI5F"xNNۇ8~}\0NhxNc5}ܵ}(N7I.|[&9SxNc5s&Mۅz8e.@2Or'`>a<CY4 l{HF[1gImb<MA%)a<WIe2ɼ?c, csgIeGx9xIfIvgAhHr.`l ^%%$gm 0AOIlQ< x$sJr)7IfmO3ڊ aq7BXt.͓xF|Lm̒,ee+cN v&x.|#'wIB3 h{R2ɬ@F[11n&O8yo.N=`Id 'Q<la<lPۇ$$KIl{z,xذ?ɹn{v0$2e;`wNp.T e[~,ɽ|l{R>x؁8~d)o8 m?vc5c5"o8hwm_vxء7I>]3nJr-w88$mE{0X]Mp0޴] vx؟y;A`c{!,R0imTc{G3x2=kH2Lϝi0 h{.`2}P a<LDI{L23m2ƸMV'ٻ+vA "*TTAA\R/Tq:;*N^`C}]%<5e[b<ϫb%$Wբzd0>x!q<\&ɏԒF>pV$7N x$je#8]U-M#d]U;jd0nx$Kq</lOvx+D$_CrUu,jgkff%>I8`of}1x8$ѠЏБMULԧ$}b<t&ɶVv`vU4GJ01CH7G:? 8T+Q<KK6_jIk}~FoIy1,jJ0$WB Q @ ώq:8 W(0M_/NjM|%q+partAmU\ U;%Y!_$;8pa<M8 pFQ<=xO%6{ߕd)>G[%q$^ZkÏ /\ xCx!Us1h%B[8'#!/r%y\y1$UKd J|/ *a<0ix?%fAL8Nx`6,"fĔ8DY9 t HNjcY3x`,%Y|FH̖8(=a<0kx`D@]3#"!fBtGtEL(08(Q<Э@Zk&@t͋@φw X n%_L#JH@τ@ QH@@Hx`|D_0 xDw8Q<7 .L' .Dx?!Lpxg"'a<=<0HxD x q<HxG<8x Q<Iܓ(O Cpx' 8a< 0D(Ą'$@pbx(Lg Ψ%q_3j ?nqcVyNjgdYUw\00;x \8fCpax @pax,Q<@#"a<`2DW&"q<(`W&0`q0(`#d-Q_ߛ`#"0`dp5x8.N0bxňFN0b_;Y,L#Z۪zf+8Ms& v dD"q<(`b"'L0`bhxL1^މ%1D֞WmU!|*yˋd_U /7f@0qx&Q<Lf@_9%1)ֆN Q"|x1`f,jcW:$)a< (`Ƅ3%#x1_U_E&$kq<3;70 : `Dt8`s&gQ<@_ZtvSUUL&p}b<@glcz9 tJ!q<$0S8vwx$kUu[U/zJ6 @߼й$Zx9?x?#pעx>kIߴֆ߸W2D$[JeUm\+p'a<p߻ --ppswhx)ɺV..a<ǿKpbDGKP|Wknkp$K>$_r<' A1^߹NC$֞WmUp9`d`<x$ZTϮ=D<xW(~d@<x$˪ڸ"wpxǿsIQ<В8$'Z н}4$YWժ ЭE8MUV3&8$2/0ig&i2/0iIU5;K;Q<sxfr *)a<Z~}cUcZ$#`.~$sdYU tj'`,ֆ@u|F`n,%YW˪:XFy1YkTǪ)[0gxfnꅵY%Y]}U-jcl`&UR@/@WZkZ_U0֖Ujdo<zMuU وVk>V_#SFWxZ{^UU[J6=,ɾU̡^ڿ.U* ֖UU+U";gn\&k?|-vk^wb<|CkyU}pFzdp7a<|Gkm;g0D$[om%YV;gőn[^ 8WaQ phꞺsfGz'9PSg$q)Asbg$WI> x}"<x>xxKr//#/x~JHr):I>)(+ >Nr&?'QNuTP?O+G?&9Fy+PUInq_#Cu}d?ɽ8$+(tSL`k-| ?XxX?z&W:Nw8=VuH` j(ȟ'ٕ/madǩ`` Ur' kVU{In|5}^Fjy,,,9`vd o|7l$Jv uyO+ގb< > l>'7U-rxU*ɡ`ҖIN™}(;$_&1Qw9x:N2w&>ɢޗb<LDU$QIciqK?. ߕ`Z,UE/nojd1b1&h|eOrӤI>s9.?i`ªj?U+m&b<Lb|XeOJ`tSw'9s/ehMw߈6CuS$Iv ^:0Z#:`tJZ-|g}b<l?!%&L`C ׺!$ xl`h\uOq)I$, .Wm䬻`,T޸]Rq%b<ʭ,`~,LUѸlq)ɱ`~,L.o`κH)b<\U%9Oŭe0o%$K {X4 2B)x2U*G`}b-[.|q6r\s0>;n۩l$J`u?I}OK1zAmIY&O$_;{Lr4Xi|U]xIJHr/YwKOUu@RU{IΓ|kL2o x/UII 5Kb<SUudxwWZew  ?wI X&])x.xYI$/O !U-,E(AbWruaEhK(RUI| Ǝ$$/,|R~xUqŮ4II( 謻J*XV %RZ$}'b<rUuo:IUR֢ ~0V'N ÎTu$C9VLR<NtSw/I`,yu0vU5䯒J`. #* b<fjo,J`c-Bxx+ë=,ǟ `#'Y(ob<.j1F⟜ xk  Vw#z w&>B)xoI$Ç]$sM1Or䣫o}T(SUǔ.u)q `j$ɧ$Kx3I)LVU%JrJk3tLVw?u"ə+}R<0uPUq=~Vr\'0uƨj VT^%a9^>B)4$<Kw"6Mu vA?LrW"6b<$\'9L1:H2fEϏ>0;Aw% leOJXf'u]`&9'b<0;}du-r x`,VUrWWfq\sd`,'I~Kti`(sg1 U*ɡ30tcb<I\pIJ6l:?>a~tb<u.Pv}`C,l+V$Iv= `nub<պ""gLYw/mg1`TUrWy89x$,$Jd1?T^$ea㸻,~$߬ov\WBUYw )/O}xnǕxxJUu0!g}*$QEU5|.G<&9;ގ~@)YXKrL`-wն*+VUGcA~WuRΎ,Vk| ɭh`k +ߺH)`,QU&.c$C!b<uP0?g}^kwII~f1ɧq<51 `c #oC1UX,{($}loK1TXuo%}F$ua%[w)PU'IN܎+&$Yw:4(LLU Ӿ q%Nӡ0A]XEkR<tYZ Vn8'Lb<[+1w8O1`TѸnjc)J<P0zPv"˱%6͢X`z<xqD5^rOI6xq=Mriwo{s03Uu2|Kla%`>fz<[J<)̘xxS9̘x-%03Vb< XB[z<J<RR Vb<Y@1LxA1DX(oCxcVS)+b<?e=5(,X!+b</RUGcAz<q=?IRŪjo,ϴ Wx5uB1ɩI]xSmtx&CXe>5SUqsks=?R`jo,q-y W"`UHr䃫INIlx6NU&r/v主D&Q`#U?E&R`UqK$' 6b<rDZ%6b<QU$I>*~$9myP`v4w}s|D1Yq=Ѕ-9R`֪8wץNr \)0{U7k3主oS`kTb\;m֩qA~ s;?8D1TUzg`,tcjUH2|0Y#iw?9J1^?M]'9;G`)Ch9.ğ;b<:J2|X ]&9'?)#sX67x Uu0 X }*\s Uu<w PkLUdx_主oϣ/TUzXsݧBQW +C'tT^rcb<@U,%Sa w IDATS +WZINOVC1VIXqvX-xXOrP0k$}fUudA0;J(#xY 7 or oG1AU- ?6Ə$dU|]wɺWއb<Kr[<+gQU$ÂZܟwSSWDӡTU{G$X7Lb<LXU'HrN$}.^.xU  VX)Lb<l:>'u7x$ B aj/y/n/䤻E16TUC7w`3) -\+Oͥ3QUë'Ivr;DO1f/ z W~00CUu0-w(UX0Ojx $ɮ{޽5- l$< JmA0(d8=[uOpCX+b3}J?[* 0F"39=E)ee0x̜G2"5? _J8a<Tf^@~3@Se`2s/O> :[DܖR%8~|><]T/įleRAD|5dS{xdu LE}J)[CڄOeM̔8?#~+3oip@O( a<&9m~?"z!~e[wyxM?RqW&o1R a<)y/L^QU)eE0"Rʭ(,iD71YQzW08Eߦ 0XcTC+lK)?# *E]f^ W 0o^ 08/#bfOxT0iTJ)R<"CDYJb<p6y1N{j[Jy&YeyiRnsFnSU] :fNNt0̼lvGK)[Ft@@/^E g6paK)kN@@iD7A7yAʸ%xA<{xj &wX!+lK)?#BkJ)sQ<0.zA#wC#>l] -*a<0xy]/ !i&/lm2a<0y` =x`he3oR0=<ax`ByC-xW ~@5G-"n?&̜6_>O S2Y@80A<;A |  I xO!8a<W$8 < G 00xx@GpBx@ @pyA< H 'a<@@~Q=DR x&Y< ka<@G &8< =!0g2&"n#]vqKA<@z*3y<>/l =' 0` j v mj 0``2s^/ &+,m`X%`D'/"6"& %3k eRG 87W俚(mjpx*3MDLL`T^upHx"3q[@`؞O.cptWg 0(5_[+$d2^2uE}D,0h5}شpJx&3|Olj Eel5K)+܄tJf.j$a3'Lj+Iy]/6ptX [ktZfΛ$q8/. 915OV1xz'35=7EIJkcOVf^@-Ԧ(5&H@e<"nk$?Q=~i0iDD]DlB|)0Hy]+F`5Z8C#`2s^Ķy1b2a<ӈXDmDl蹇XRV ̼=k ~mq0yDEDO|ziR҂+a<ӈX+茇z~e%0Z2W_d<"" 'fKėR MӈX+3 ?'7136A N9o]FOM_JY0>!39?Lj+ >F5j@DlK)[e4"Wgf Rpp$yS#/f \_ ~mpxx8̜O)"K)V %EziW߻#3Wok$<t_s~YJY0(3qS# Ni?V#߸"gM_JZ0:y8 Äa+_ bw@ EgvR(3y]#yW}5wzD=U+?G߄0yY&)K:<0yFn7H^Z1ڸV 64!|ėR3a<05_waZ1 a<0H9oE3[[-"a<0xyY<0 uRb!׭H~b@ϼ4ux1<0x`2"y1|s~mS i+2yiBzJ30'2s^ED\pV 2`H8} XJy4XH1<'>F,WER 9xzEF$u~;a0D0:bx#HK p"x@@p&"y 1< :_GąY"b%a<@d^_dvEa"y8*1<@OzB$!!a<@eFbK/K)F?xD00y ' 4!|ėR0xugv }`؄#0M Xc 0`2s^&vѲG0r5شb02sڊ71N%"*<<{x~*3ۑ̤8o2|ï &yY/"] 1 a<%/&olj,<%2s7g& @DUxzK@o&[0x5yW&a<T_.l} *<C%`5:cU0Q̛V(Stn7A|)emY0y+og*|)ee0^V$e> lk 5ta<Ff޴._p×Rֆ ?'wi$gS+64x;a<|Bf_URʣ 2_-f׫[e|_5 ʮ [W !iO(k]oBgBwf9߄p~x̜(/{j+n@G $x <zH=%7` /!< 0_ֿv j,aHdEy<}mA#UCV(@lZ!K|H~OLzG"Bp@OB?",3B v"o%>,3HyW @!1|)`L`^]Z;p(x2sފ/]>W 08̼~˻*mOB} /f9IDAT$UyNq a<Ik@ ^i+l|@c nߺ5dX~fHH xq BJw:H: fd>ְ$Ďϙl|Rny@Gpfx ./k~OKX]Cݏ"x#c6P69\f("SJe=7] 51$"PO>o+|tt XR]4`7*"P[ ٕ𽮡N?`#Xh'ˏ;wa!wM$/ZL.<"K|`OpxΦ z)ܴ] RJ'<$WDDI,K3m | 4a<Wtn7e:V7e~ MqDǜ0Gx'"XyCwF,0"VF*X <PwVOUDu|o,/uz'|O$a<0+NoyP#TCs΃D,ZҷDM7襙Nt/ڸTw`фDD;}湼.j?6{k'.O]D,~{ >IK"о^?qGpq}1|t5'X>MLO}2ɞOfzҞ#w52؏>,x*S[SN9pU񯸾w{uݒG_?.WJ?Kȏ}IENDB`resources/JobPlay/jmisavexp.html000644 001750 001750 00000000303 13544613421 017631 0ustar00cyrilcyril000000 000000

Save assignment file

Save in a file the present state of experimental peaks with assignments and attributes.

sources/org/spview/filehandler/HITRANFile.java000644 001750 001750 00000003513 13544613421 022065 0ustar00cyrilcyril000000 000000 package org.spview.filehandler; import java.awt.geom.Point2D; public class HITRANFile { private static double cx; private static double cy; public static Point2D extractXY(String str) { if (str.length() < 100) { // line too short return null; // skip it } // HITRAN pred-as-stick (100 for HITRAN, 160 for HITRAN 2004) try { // read data // extraction and validity test on 67 char (ie not all) Integer.parseInt(str.substring(0, 3).trim()); // validity test cx = Double.valueOf(str.substring(3, 15)); // Double for X cy = Double.valueOf(str.substring(15, 25)); // Double for Y Double.valueOf(str.substring(25, 35)); // validity test Double.valueOf(str.substring(35, 40)); // validity test Double.valueOf(str.substring(40, 45)); // validity test Double.valueOf(str.substring(45, 55)); // validity test Double.valueOf(str.substring(55, 59)); // validity test Double.valueOf(str.substring(59, 67)); // validity test } catch (NumberFormatException e) { // format error return null; } return (new Point2D.Double(cx, cy)); } public static String extractAssignment(String str) { String cjsyn = ""; if (str.length() == 100) { // HITRAN 2000 cjsyn = str.substring(82, 85) + " " + str.substring(85, 87) + " " + str.substring(87, 90) + " " + str.substring(73, 76) + " " + str.substring(76, 78) + " " + str.substring(78, 81); } else if (str.length() == 160) { // HITRAN 2004 cjsyn = str.substring(112, 122) + " " + str.substring(97, 107); } return cjsyn; } /* * get current extended assignment * */ public static String extractExtendedAssignment(String str) { String cxjsyn = ""; if (str.length() == 100) { // HITRAN 2000 cxjsyn = str.substring(67, 91); } else if (str.length() == 160) { // HITRAN 2004 cxjsyn = str.substring(67, 127); } return cxjsyn; } }sources/org/spview/gui/About.java000644 001750 001750 00000002621 13544613421 017660 0ustar00cyrilcyril000000 000000 package org.spview.gui; import java.awt.Component; import java.awt.Dimension; import java.awt.Image; import java.io.IOException; import java.net.URL; import javax.swing.ImageIcon; import javax.swing.JEditorPane; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import org.spview.Main; public class About { final private static String versionnedName() { return ("About " + Main.PACKAGE_NAME + " " + Main.VERSION); } public static void show(Component parent) { JEditorPane editorPane = new JEditorPane(); editorPane.setContentType("text/html"); editorPane.setEditable(false); URL helpURL = About.class.getResource("/about.html"); if (helpURL != null) { try { editorPane.setPage(helpURL); } catch (IOException e) { System.err.println("Attempted to read a bad URL: " + helpURL); } } else { System.err.println("Couldn't find file: About.html"); return; } final ImageIcon icon = new ImageIcon(new ImageIcon(JobPlay.class.getResource("/pixmaps/spview.png")).getImage() .getScaledInstance(64, 64, Image.SCALE_SMOOTH)); // Put the editor pane in a scroll pane. JScrollPane scrollPane = new JScrollPane(editorPane); scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); scrollPane.setPreferredSize(new Dimension(800, 600)); JOptionPane.showMessageDialog(parent, scrollPane, versionnedName(), JOptionPane.PLAIN_MESSAGE, icon); } } sources/org/spview/gui/PopFile.java000644 001750 001750 00000003273 13544613421 020150 0ustar00cyrilcyril000000 000000 package org.spview.gui; import java.awt.Dimension; import java.awt.Font; import java.awt.Image; import java.io.IOException; import java.net.URL; import javax.swing.ImageIcon; import javax.swing.JEditorPane; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTextArea; public class PopFile { /** * Show help file text. * * @param nhelpf help file name */ public static void show(String nhelpf) { if (nhelpf == null) { JOptionPane.showMessageDialog(null, "No help provided for this item"); return; } JTextArea jtahelp = new JTextArea(); jtahelp.setFont(new Font("Serif", Font.PLAIN, 14)); jtahelp.setLineWrap(true); // line wrap allowed jtahelp.setWrapStyleWord(true); // between 2 words jtahelp.setEditable(false); // not editable String lnsep = System.getProperty("line.separator"); String fisep = System.getProperty("file.separator"); JEditorPane editorPane = new JEditorPane(); editorPane.setContentType("text/html"); editorPane.setEditable(false); URL res = PopFile.class.getResource(fisep + nhelpf + ".html"); if (res != null) { try { editorPane.setPage(res); } catch (IOException ioe) { // IO error JOptionPane.showMessageDialog(null, "IO error while reading file" + lnsep + fisep + nhelpf + ".html" + lnsep + ioe); return; } } final ImageIcon icon = new ImageIcon(new ImageIcon(JobPlay.class.getResource("/pixmaps/spview.png")).getImage() .getScaledInstance(64, 64, Image.SCALE_SMOOTH)); JScrollPane scrollPane = new JScrollPane(editorPane); scrollPane.setPreferredSize(new Dimension(600, 200)); JOptionPane.showMessageDialog(null, scrollPane, "Help", JOptionPane.PLAIN_MESSAGE, icon); } } resources/JobPlay/jmiexp2null.html000644 001750 001750 00000000235 13544613421 020100 0ustar00cyrilcyril000000 000000

Deassociate experiment to data

Deassociate the experimental peak list.

sources/org/spview/filehandler/SPVProject.java000644 001750 001750 00000032204 13544613421 022276 0ustar00cyrilcyril000000 000000 package org.spview.filehandler; import java.io.File; import java.io.IOException; import java.util.ArrayList; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.filechooser.FileNameExtensionFilter; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; import org.spview.gui.JobPlay; import org.spview.Main; public class SPVProject { private String projectFileName; private JobPlay jobplay; private boolean unsave = false; private ArrayList paths = new ArrayList<>(); // List of paths of the project to load private ArrayList typeAttribute = new ArrayList<>(); private ArrayList AttributeOfFileToLoad = new ArrayList<>(); // Contains all attribute-types in order to private ArrayList yReverseElementToLoad = new ArrayList<>(); // Contains information about "y-reverse" state private ArrayList hideElementToLoad = new ArrayList<>(); private ArrayList xShiftedElementToLoad = new ArrayList<>(); private ArrayList yShiftedElementToLoad = new ArrayList<>(); private int indexColorPredStr; // Contains the color got from the project file private int indexColorExpStr; // Contains the color got from the project file private double MinX, MaxX; // X Zoom values private double MinY, MaxY; // Y Zoom values public SPVProject(JobPlay jobplay) { this.jobplay = jobplay; } public SPVProject(JobPlay jobplay, String projectFileName) throws ParserConfigurationException, SAXException, IOException { this.projectFileName = projectFileName; this.jobplay = jobplay; FileParser cFileParser = new FileParser(this.projectFileName); paths = cFileParser.getPathlist(); typeAttribute = cFileParser.getAttrlist(); AttributeOfFileToLoad = cFileParser.getAttributeOfFilelist(); yReverseElementToLoad = cFileParser.getyReverseElementslist(); hideElementToLoad = cFileParser.getHideElementslist(); xShiftedElementToLoad = cFileParser.getxShiftElementslist(); yShiftedElementToLoad = cFileParser.getyShiftElementslist(); indexColorPredStr = cFileParser.getIndexColorPred(); indexColorExpStr = cFileParser.getIndexColorExp(); MinX = cFileParser.getMinX(); MaxX = cFileParser.getMaxX(); MinY = cFileParser.getMinY(); MaxY = cFileParser.getMaxY(); } public void open() { int j = 0; try { for (Element pl : paths) { jobplay.loadFileByFilename(pl.getTextContent(), typeAttribute.get(j), j); if (typeAttribute.get(j).equals("spectrum") || typeAttribute.get(j).equals("tdsas") || typeAttribute.get(j).equals("hitras")) { if (!yReverseElementToLoad.isEmpty() && yReverseElementToLoad.get(j).equals("true")) { jobplay.getPanAff().yReverse(j); } if (!hideElementToLoad.isEmpty() && hideElementToLoad.get(j).equals("true")) { jobplay.getPanAff().setShow(j, false); jobplay.enableHideMenu(j, false); jobplay.enableShowMenu(j, true); } if (MinX != 0.0 && MaxX != 0.0) jobplay.getPanAff().setXZoom(MinX, MaxX); if (MinY != 0.0 && MaxY != 0.0) jobplay.getPanAff().setYZoom(MinY, MaxY); Double xshift = Double.parseDouble(xShiftedElementToLoad.get(j)); Double yshift = Double.parseDouble(yShiftedElementToLoad.get(j)); jobplay.getPanAff().setXShift(xshift, j); jobplay.getPanAff().setYShift(yshift, j); if (xshift != 0.0) { jobplay.enableXUnshiftMenu(j, true); } if (yshift != 0.0) { jobplay.enableYUnshiftMenu(j, true); } } j++; } } catch (Exception e) { // IO error JOptionPane.showMessageDialog(null, "Cannot Open File " + projectFileName, "Error", JOptionPane.ERROR_MESSAGE); e.printStackTrace(new java.io.PrintStream(System.out)); } } private void saveVersion(Document doc, Element Project) { Element Version = doc.createElement("Version"); Project.appendChild(Version); Project.appendChild(doc.createTextNode(Main.VERSION)); } private void saveZoomValues(Document doc, Element Project) { // Zoom Element Zoom = doc.createElement("Zoom"); Project.appendChild(Zoom); // create xZoomMin node double xmin = jobplay.getPanAff().getbxmi(); Element xZoomMin = doc.createElement("xmin"); xZoomMin.appendChild(doc.createTextNode(Double.toString(xmin))); Zoom.appendChild(xZoomMin); // create xZoomMax node double xmax = jobplay.getPanAff().getbxma(); Element xZoomMax = doc.createElement("xmax"); xZoomMax.appendChild(doc.createTextNode(Double.toString(xmax))); Zoom.appendChild(xZoomMax); // create yZoomMin node double yZoom0 = jobplay.getPanAff().getbymi(); Element yZoomMin = doc.createElement("ymin"); yZoomMin.appendChild(doc.createTextNode(Double.toString(yZoom0))); Zoom.appendChild(yZoomMin); // create yZoomMax node double yZoom1 = jobplay.getPanAff().getbyma(); Element yZoomMax = doc.createElement("ymax"); yZoomMax.appendChild(doc.createTextNode(Double.toString(yZoom1))); Zoom.appendChild(yZoomMax); } private void saveDataFiles(Document doc, Element Project) { for (int i = 0; i < jobplay.getPathsList().size(); i++) { // file element Element File = doc.createElement("File"); Project.appendChild(File); Element path = doc.createElement("path"); path.appendChild(doc.createTextNode(jobplay.getPathsList().get(i))); File.appendChild(path); // create and append attribute to File Attr AttributeOfFile = doc.createAttribute("AttributeOfFile"); AttributeOfFile.setValue(jobplay.getAttributeOfFileList().get(i)); File.setAttributeNode(AttributeOfFile); // create and append attribute to path Attr Type = doc.createAttribute("Type"); Type.setValue(jobplay.getTypeOfFileList().get(i)); path.setAttributeNode(Type); // create yReverse node Element yReverse = doc.createElement("yReverse"); yReverse.appendChild(doc.createTextNode(jobplay.getReverseYElementList().get(i))); File.appendChild(yReverse); // create hide node Element hide = doc.createElement("hide"); hide.appendChild(doc.createTextNode(jobplay.getHideElementList().get(i))); File.appendChild(hide); // create xShift node double xState = jobplay.getPanAff().getXShift(i); Element xShiftState = doc.createElement("xShiftState"); xShiftState.appendChild(doc.createTextNode(Double.toString(xState))); File.appendChild(xShiftState); // create yShift node double yState = jobplay.getPanAff().getYShift(i); Element yShiftState = doc.createElement("yShiftState"); yShiftState.appendChild(doc.createTextNode(Double.toString(yState))); File.appendChild(yShiftState); } } private void savePredictionFile(Document doc, Element Project) { // file element Element File = doc.createElement("File"); Project.appendChild(File); Element path = doc.createElement("path"); path.appendChild(doc.createTextNode(jobplay.getPathOfPredFile())); File.appendChild(path); // create and append attribute to File Attr AttributeOfFile = doc.createAttribute("AttributeOfFile"); AttributeOfFile.setValue(jobplay.getAttributeOfPredFile()); File.setAttributeNode(AttributeOfFile); // create and append attribute to path Attr Type = doc.createAttribute("Type"); Type.setValue(jobplay.getTypeOfPredFile()); path.setAttributeNode(Type); // create color node String indexColorToSavePred = Integer.toString(jobplay.getPanAff().getPfass2()); Element indexColorPred = doc.createElement("indexColorPred"); indexColorPred.appendChild(doc.createTextNode(indexColorToSavePred)); File.appendChild(indexColorPred); } private void saveExperimentFile(Document doc, Element Project) { // file element Element File = doc.createElement("File"); Project.appendChild(File); Element path = doc.createElement("path"); path.appendChild(doc.createTextNode(jobplay.getPathOfExpfile())); File.appendChild(path); // create and append attribute to File Attr AttributeOfFile = doc.createAttribute("AttributeOfFile"); AttributeOfFile.setValue(jobplay.getAttributeOfExpFile()); File.setAttributeNode(AttributeOfFile); // create and append attribute to path Attr Type = doc.createAttribute("Type"); Type.setValue(jobplay.getTypeOfExpFile()); path.setAttributeNode(Type); // create color node String indexColorToSaveExp = Integer.toString(jobplay.getPanAff().getEfass2()); Element indexColorExp = doc.createElement("indexColorExp"); indexColorExp.appendChild(doc.createTextNode(indexColorToSaveExp)); File.appendChild(indexColorExp); } /** * Save the current project to an XML file with .spv extension * * @since SPVIEW2 */ private File pickAFileName(String nameSuggestion) { // This method creates an XML File to save the file(s) added in the project. File selectedFile = null; // choose the project file JFileChooser jfcfile = new JFileChooser(nameSuggestion); // default choice directory FileNameExtensionFilter filter = new FileNameExtensionFilter("Project file (*.spv)", "spv"); // Only files .spv jfcfile.setSize(400, 300); jfcfile.setFileSelectionMode(JFileChooser.FILES_ONLY); // files only jfcfile.setDialogTitle("Save Project"); jfcfile.addChoosableFileFilter(filter); // add the filter created above jfcfile.setAcceptAllFileFilterUsed(false); // All types of file are NOT accepted jfcfile.setSelectedFile(new File(nameSuggestion)); if (jfcfile.showSaveDialog(jobplay.getParent()) == JFileChooser.APPROVE_OPTION) { selectedFile = jfcfile.getSelectedFile(); if (selectedFile.getAbsolutePath().endsWith(".spv") == false) { selectedFile = new File(jfcfile.getSelectedFile() + ".spv"); } if (!selectedFile.exists() || (selectedFile.exists() && JOptionPane.OK_OPTION == JOptionPane.showConfirmDialog(jobplay.getParent(), "File " + selectedFile.getAbsolutePath() + " already exists! Overwrite?", "Save", JOptionPane.YES_NO_OPTION))) { return selectedFile; } } return null; } public void saveSPVFile(String nameSuggestion) { if (jobplay.getNbOfDataFile() == 0) return; File pickedFile = pickAFileName(nameSuggestion); if (pickedFile != null) { // Sort the attributes of each type of file, first Predfile, then Expfile for (int i = 0; i < AttributeOfFileToLoad.size(); i++) { // Sort the attributes "TDS" or "HITRAN" if (AttributeOfFileToLoad.get(i).equals("predread")) { jobplay.setAttributefPredFile(AttributeOfFileToLoad.get(i)); jobplay.setTypeOfPredFile(typeAttribute.get(i)); jobplay.setPathOfPredFile(jobplay.getPredFileName()); } // Sort the attributes "peakExp" if (AttributeOfFileToLoad.get(i).equals("expread")) { jobplay.setAttributefExpFile(AttributeOfFileToLoad.get(i)); jobplay.setTypeOfExpFile(typeAttribute.get(i)); jobplay.setPathOfExpFile(jobplay.getExpFileName()); } } if (jobplay.getNbOfDataFile() > 0 && jobplay.getTypeOfFileList().size() + jobplay.getPredfileToSave() + jobplay.getExpfileToSave() > 0) { try { // --- instantiate a project file --- // DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = dbFactory.newDocumentBuilder(); Document doc = docBuilder.newDocument(); // Project root element Element Project = doc.createElement("Project"); doc.appendChild(Project); saveVersion(doc, Project); saveZoomValues(doc, Project); saveDataFiles(doc, Project); // The prediction and experimentation files have to be added to the project // AFTER the data files, otherwise there would be a shift in the colors. if (jobplay.getPredfileToSave() == 1) { savePredictionFile(doc, Project); } if (jobplay.getExpfileToSave() == 1) { saveExperimentFile(doc, Project); } // Write the content into xml file TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); DOMSource source = new DOMSource(doc); StreamResult result = new StreamResult(pickedFile); transformer.transform(source, result); } catch (TransformerException tfe) { tfe.printStackTrace(); } // handle exception creating TransformerFactory catch (TransformerFactoryConfigurationError factoryError) { System.err.println("Error creating " + "TransformerFactory"); factoryError.printStackTrace(); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } this.setUnsave(false); System.out.println("Your project has been saved succesfully"); } } } public int getIndexColorPred() { return indexColorPredStr; } public int getIndexColorExp() { return indexColorExpStr; } public ArrayList getAttributeOfFileList() { return AttributeOfFileToLoad; } public boolean isUnsave() { return unsave; } public void setUnsave(boolean unsave) { this.unsave = unsave; } } sources/org/spview/residuals/ObsCalc.java000644 001750 001750 00000006164 13544613421 021331 0ustar00cyrilcyril000000 000000 package org.spview.residuals; import java.awt.Dimension; import java.awt.Toolkit; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.List; import javax.swing.JFrame; import javax.swing.JOptionPane; import org.spview.point.ResidualPoint; import org.spview.filehandler.ExpFile; import org.spview.filehandler.PredFile; import org.spview.point.ExpJsynPoint; import org.spview.gui.JFCreatePeakFile; import org.spview.gui.JobPlay; import org.spview.gui.PlotData; public class ObsCalc { private ExpFile expFile; private PredFile predFile; private PlotData mainPanel; public ObsCalc(ExpFile expFile, PredFile predFile) throws Exception { if (expFile == null || expFile.getNbxy() == 0 || predFile == null || predFile.getNbxy() == 0) { throw new Exception("Invalid data"); } this.expFile = expFile; this.predFile = predFile; } public ArrayList getFreqResiduals() { int n = this.expFile.getNbxy(); if (n < 1) return null; ArrayList XResiduals = new ArrayList<>(); ArrayList[] expPoint = expFile.getEjsynpt(); for (int i = 0; i < n; i++) { for (ExpJsynPoint uniqPoint : expPoint[i]) { int index = uniqPoint.getIpred(); if (index != -1 && uniqPoint.getFaso().equals("+")) { double diff = (this.expFile.getX(i) - this.predFile.getX(index)) * 1E3; XResiduals.add(new ResidualPoint(this.expFile.getX(i), diff, uniqPoint.getJsyn())); } } } return XResiduals.isEmpty() ? null : XResiduals; } public ArrayList getIntResiduals() { int n = this.expFile.getNbxy(); if (n < 1) return null; ArrayList YResiduals = new ArrayList<>(); ArrayList[] expPoint = expFile.getEjsynpt(); for (int i = 0; i < n; i++) { for (ExpJsynPoint uniqPoint : expPoint[i]) { int index = uniqPoint.getIpred(); if (index != -1 && uniqPoint.getSaso().equals("+")) { double diff = this.expFile.getY(i) - this.predFile.getY(index); YResiduals.add(new ResidualPoint(this.expFile.getX(i), diff, uniqPoint.getJsyn())); } } } return YResiduals.isEmpty() ? null : YResiduals; } public void show(JobPlay jobplay, String type) { List data = type.equals("X") ? getFreqResiduals() : getIntResiduals(); if (data == null) { JOptionPane.showMessageDialog(null, "There is no data to display!", "No data", JOptionPane.WARNING_MESSAGE); return; } mainPanel = new PlotData(jobplay, data); mainPanel.setPreferredSize(new Dimension(800, 600)); JFrame frame; if (type.equals("X")) { frame = new JFrame("Frequency Obs-Cal Display"); } else { frame = new JFrame("Intensity Obs-Cal Display"); } frame.setIconImage(Toolkit.getDefaultToolkit().getImage(JFCreatePeakFile.class.getResource("/pixmaps/spview.png"))); frame.getContentPane().add(mainPanel); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); frame.addWindowListener(new WindowAdapter() { // clean end public void windowClosing(WindowEvent e) { if (mainPanel.getJFT() != null) { mainPanel.getJFT().dispose(); } } }); } } resources/JFSelPred/jmilsshow.html000644 001750 001750 00000000234 13544613421 020063 0ustar00cyrilcyril000000 000000

Local simulation

Show local simulation based on selected predictions.

resources/JobPlay/jmiloadd2hsas.html000644 001750 001750 00000000121 13544613421 020345 0ustar00cyrilcyril000000 000000 Load a prediction file in D2hStark format to plot it as sticks in the data area. sources/org/spview/gui/JFSimul.java000644 001750 001750 00000070501 13544613421 020121 0ustar00cyrilcyril000000 000000 package org.spview.gui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; //import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Locale; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import org.spview.filehandler.FortranFormat; /* * Class to calculate local simulation spectrum through a simul job; called by JFSelPred */ /** * This panel creates and runs a job to calculate a local simulation spectrum * from (area) selected predictions. */ public class JFSimul extends JFrame implements ActionListener { /** * */ private static final long serialVersionUID = -3391496760301771994L; private String playd; // SPVIEW installation directory private JFSelPred calling; private double dcdae; // default cdae private double[] lsx; // loc-sim spectrum X private double[] lsy; // loc-sim spectrum Y // panels private JPanel pcentre; private JPanel psud; // simulation parameters private JFormattedTextField jftfumin; // for vumin private float vumin; // lower frequency cm-1 private JFormattedTextField jftfumax; // for vumax private float vumax; // upper frequency cm-1 private JFormattedTextField jftftemp; // for vtemp private float vtemp; // temperature K private JFormattedTextField jftfres; // for vres private float vres; // resolution cm-1 private JFormattedTextField jftfpaf; // for vpaf private float vpaf; // Drawing Steps Size cm-1 private JFormattedTextField jftfthres; // for vthres private float vthres; // Intensity Threshold cm-2/atm private String[] tsptype; // spectrum type choice array private JComboBox jcbsptype; // for tsptype private String nsptype; // Spectrum type private String[] tappf; // apparatus function choice array private JComboBox jcbappf; // for tappf private String nappf; // Apparatus function private JFormattedTextField jftfcdae; // for cdae private float cdae; // Press Broadening Coeff cm-1.atm-1 private JFormattedTextField jftfmass; // for mass private float mass; // Molar Mass private JFormattedTextField jftfptt; // for ptt private float ptt; // Total Pressure Torr private JButton jbset; // set button private Box boxsud; // box for jbset // Number Format private NumberFormat nffloat; // variables private String tempod; // SPVIEW tempo directory private String njobf; // job file private boolean jobexist; // job file exist status private PrintWriter out1; // to write job private String lfil; // line file private String nerrf; // error file private String noutf; // output file private String ncmd; // command private Process monproc; // various processes private String nxyf; // simulated spectrum file private BufferedReader br; private boolean verbose = true; // Number Format // private NumberFormat nff; // float // private DecimalFormat dff; // private NumberFormat nfi; // integer // private DecimalFormat dfi; private String lnsep; // line separator private String fisep; // file separator ///////////////////////////////////////////////////////////////////// /** * Construct a new JFSimul. * * @param ccalling calling JFSelPred * @param cix0 window X location * @param ciy0 window Y location */ public JFSimul( JFSelPred ccalling, int cix0, int ciy0 ) { playd = System.getProperty("spview.home"); // SPVIEW installation directory calling = ccalling; // calling JFSelPred lnsep = System.getProperty("line.separator"); fisep = System.getProperty("file.separator"); dcdae = .09; // default cdae // format definition // nff = NumberFormat.getNumberInstance(Locale.US); // ask a plain format // dff = (DecimalFormat)nff; // reduce to decimal format // dff.applyPattern("00000.000000"); // define pattern // nfi = NumberFormat.getNumberInstance(Locale.US); // ask a plain format // dfi = (DecimalFormat)nfi; // reduce to decimal format // dfi.applyPattern("0.00E00"); // define pattern tempod =playd+fisep+"tempo"; // SPVIEW tempo directory njobf = tempod+fisep+"locsim_job"; // job file jobexist = false; // job file MUST be created lfil = tempod+fisep+"locsim_lines"; // line file nerrf = njobf+"_err"; // error file noutf = njobf+"_out"; // output file nxyf = tempod+fisep+"simul.xy"; // simulated spectrum file setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); //setLayout(new BorderLayout()); getContentPane().setLayout(new BorderLayout()); setLocation(cix0, ciy0); // panel to show and get local simulation parameters pcentre = new JPanel(new GridLayout(11,2,5,5)); // SIMULATION PARAMETERS // formats nffloat = NumberFormat.getInstance(Locale.US); // float nffloat.setGroupingUsed(false); // NO grouping nffloat.setMaximumFractionDigits( 7); // fraction digits // UMIN pcentre.add(new JLabel(" Lower Frequency Limit (cm-1) ",null,JLabel.LEFT)); jftfumin = new JFormattedTextField(nffloat); jftfumin.setValue( new Float(0.0)); pcentre.add(jftfumin); // UMAX pcentre.add(new JLabel(" Upper Frequency Limit (cm-1) ",null,JLabel.LEFT)); jftfumax = new JFormattedTextField(nffloat); jftfumax.setValue( new Float(0.0)); pcentre.add(jftfumax); // TEMP pcentre.add(new JLabel(" Temperature (K) ",null,JLabel.LEFT)); jftftemp = new JFormattedTextField(nffloat); jftftemp.setValue( new Float(0.0)); pcentre.add(jftftemp); // RES pcentre.add(new JLabel(" Resolution (cm-1) ",null,JLabel.LEFT)); jftfres = new JFormattedTextField(nffloat); jftfres.setValue( new Float(0.0)); pcentre.add(jftfres); // PAF pcentre.add(new JLabel(" Drawing Steps Size (cm-1) ",null,JLabel.LEFT)); jftfpaf = new JFormattedTextField(nffloat); jftfpaf.setValue( new Float(0.0)); pcentre.add(jftfpaf); // THRES pcentre.add(new JLabel(" Intensity Threshold (cm-2/atm) ",null,JLabel.LEFT)); jftfthres = new JFormattedTextField(nffloat); jftfthres.setValue(new Float(0.0)); pcentre.add(jftfthres); // TYPE tsptype = new String[3]; tsptype[0] = "trans"; tsptype[1] = "raman"; tsptype[2] = "absor"; pcentre.add(new JLabel(" Spectrum Type ",null,JLabel.LEFT)); jcbsptype = new JComboBox(tsptype); jcbsptype.addItem(""); jcbsptype.setSelectedItem(""); // default to space jcbsptype.setBackground(Color.WHITE); nsptype = ""; pcentre.add(jcbsptype); // APPF tappf = new String[4]; tappf[0] = "dirac"; tappf[1] = "sinc"; tappf[2] = "sinc2"; tappf[3] = "gauss"; pcentre.add(new JLabel(" Apparatus Function ",null,JLabel.LEFT)); jcbappf = new JComboBox(tappf); jcbappf.addItem(""); jcbappf.setSelectedItem(""); // default to space jcbappf.setBackground(Color.WHITE); nappf = ""; pcentre.add(jcbappf); // CDAE pcentre.add(new JLabel(" Press Broad Coeff (cm-1.atm-1) ")); jftfcdae = new JFormattedTextField(nffloat); jftfcdae.setValue( new Float(dcdae)); pcentre.add(jftfcdae); // PTT pcentre.add(new JLabel(" Total Pressure (Torr) ")); jftfptt = new JFormattedTextField(nffloat); jftfptt.setValue( new Float(0.0)); pcentre.add(jftfptt); // MASS pcentre.add(new JLabel(" Molar Mass ")); jftfmass = new JFormattedTextField(nffloat); jftfmass.setValue( new Float(0.0)); pcentre.add(jftfmass); pcentre.setBorder(BorderFactory.createTitledBorder("SIMULATION PARAMETERS")); // south panel jbset = new JButton("Set"); jbset.setToolTipText("Set local simulation parameters"); jbset.setBackground(Color.WHITE); jbset.addActionListener(this); boxsud = Box.createHorizontalBox(); // add button to box boxsud.add(jbset); psud = new JPanel(); psud.setBorder(BorderFactory.createLineBorder(Color.BLACK)); psud.add(boxsud); // add box // add panels //add(pcentre,"Center"); getContentPane().add(pcentre,"Center"); //add(psud,"South"); getContentPane().add(psud,"South"); setVisible(false); pack(); } ///////////////////////////////////////////////////////////////////// /** * Process events. */ public void actionPerformed(ActionEvent evt) { // set button if( evt.getSource() == jbset ) { if( testCJP( verbose ) ) { // good new parameters jobexist = false; // job file MUST be created setVisible(false); calling.simParmSet(); // warn JFSelPred } return; } } ///////////////////////////////////////////////////////////////////// // test parameters private boolean testCJP( boolean verb ) { // SIMULATION PARAMETERS // UMIN vumin = ((Number)jftfumin.getValue()).floatValue(); if( vumin < 0 ) { if( verb ) { JOptionPane.showMessageDialog(null,"Lower Frequency >= 0 requested"); } return false; } // UMAX vumax = ((Number)jftfumax.getValue()).floatValue(); if( vumax <= vumin ) { if( verb ) { JOptionPane.showMessageDialog(null,"Upper Frequency > Lower Frequency requested"); } return false; } // TEMP vtemp = ((Number)jftftemp.getValue()).floatValue(); if( vtemp < 0 ) { if( verb ) { JOptionPane.showMessageDialog(null,"Temperature >= 0 requested"); } return false; } // RES vres = ((Number)jftfres.getValue()).floatValue(); if( vres < 0 ) { if( verb ) { JOptionPane.showMessageDialog(null,"Resolution >= 0 requested"); } return false; } // PAF vpaf = ((Number)jftfpaf.getValue()).floatValue(); if( vpaf <= 0 ) { if( verb ) { JOptionPane.showMessageDialog(null,"Drawing Step Size > 0 requested"); } return false; } if( vpaf >= vres ) { if( verb ) { JOptionPane.showMessageDialog(null,"Drawing Step Size < Resolution requested"); } return false; } // THRES vthres = ((Number)jftfthres.getValue()).floatValue(); if( vthres < 0 ) { if( verb ) { JOptionPane.showMessageDialog(null,"Intensity Thershold >= 0 requested"); } return false; } // SPECTRUM TYPE nsptype = (String)jcbsptype.getSelectedItem(); if( nsptype == "" ) { if( verb ) { JOptionPane.showMessageDialog(null,"You have to first define the Spectrum Type"); } return false; } // APPF nappf = (String)jcbappf.getSelectedItem(); if( nappf == "" ) { if( verb ) { JOptionPane.showMessageDialog(null,"You have to first define the Apparatus Function"); } return false; } // line file parameters test // CDAE cdae = ((Number)jftfcdae.getValue()).floatValue(); if( cdae < 0 ) { if( verb ) { JOptionPane.showMessageDialog(null,"Press Broad Coeff >= 0 requested"); } return false; } // MASS mass = ((Number)jftfmass.getValue()).floatValue(); if( mass <= 0 ) { if( verb ) { JOptionPane.showMessageDialog(null,"Molar Mass > 0 requested"); } return false; } // PTT ptt = ((Number)jftfptt.getValue()).floatValue(); if( ptt < 0 ) { if( verb ) { JOptionPane.showMessageDialog(null,"Total Pressure >= 0 requested"); } return false; } // simul.f limits double refl = 0.; // FWHM reference double pdlmh = 0.; // FWHM nb of steps if( nappf.equals(tappf[0]) ) { // DIRAC vres = (float) 0.; // resolution = 0 } double tef = 0.; // effective temperature double sl; // LORENTZ double sd; // DOPPLER if( nappf.equals(tappf[3]) ) { // GAUSS sd = (3.581097E-7)*Math.sqrt(vtemp/mass)*(vumin+vumax)/2.; tef = vtemp*(1.+Math.pow(vres/sd,2.)); } else { tef = vtemp; } sl = cdae*ptt/760.; // 760 <- atmospheres sd = (3.581097E-7)*Math.sqrt(tef/mass)*(vumin+vumax)/2.; if( nsptype == "raman" ) { sd = Math.sqrt(sd*sd+vres*vres); } refl = Math.max(refl,sl); refl = Math.max(refl,sd); // sampling test refl = 2.*refl; if( vres > refl && (! nappf.equals(tappf[0])) ) { // NOT DIRAC refl = vres; } pdlmh = refl/vpaf; if( pdlmh < 3. ) { if( verb ) { JOptionPane.showMessageDialog(null,"Sampling too sparse" +lnsep+ pdlmh+" drawing steps in a full width at half maximum"+lnsep+ "Has to be >= 3"); } return false; } if( pdlmh > 20. ) { if( verb ) { JOptionPane.showMessageDialog(null,"Sampling too dense" +lnsep+ pdlmh+" drawing steps in a full width at half maximum"+lnsep+ "Should be <= 20"); } //return false; // only a warning in simul.f } // everything is OK return true; } /** * Calculate local simulation spectrum. * * @param cpredx predictions X * @param cpredy predictions Y */ public boolean calLocSim( double[] cpredx, double[] cpredy ) { if( ! testCJP( ! verbose ) ) { // simulation parameters NOT OK JOptionPane.showMessageDialog(null,"You have to define local simulation parameters"); setVisible(true); return false; } if( ! createLines( cpredx, cpredy ) ) { // line file NOT OK return false; } if( ! jobexist ) { if( ! createJob() ) { // job NOT OK return false; } } if( ! runJob() ){ // run NOT OK return false; } if( ! readLsxy() ) { // spectrum read NOT OK return false; } // happy end return true; } // Create line file following FORMAT 2000 of simul.f private boolean createLines(double[] cpredx, double[] cpredy) { try { out1 = new PrintWriter(new BufferedWriter(new FileWriter(lfil))); for (int i = 0; i < cpredx.length; i++) { // for each selected pred point out1.println(FortranFormat.formFreq(cpredx[i]) + FortranFormat.formInt(cpredy[i])); } } catch (IOException ioe) { // IO error JOptionPane.showMessageDialog(null, "IO error while writing file" + lnsep + lfil + lnsep + ioe); return false; } finally { // close the file if (out1 != null) { out1.close(); if (out1.checkError()) { JOptionPane.showMessageDialog(null, "PrintWriter error while creating line file" + lnsep + lfil); return false; } } } return true; } // Create job private boolean createJob() { try { out1 = new PrintWriter( new BufferedWriter( new FileWriter( njobf ) ) ); out1.println("#! /bin/sh"); out1.println("##"); out1.println("## Local simulation job created by SPVIEW"); out1.println("##"); out1.println("BASD="+playd+fisep+"packages"+fisep+"PKF"); out1.println("##"); out1.println(" SCRD=$BASD"+fisep+"prog"+fisep+"exe"); out1.println("##"); out1.println("## SIMULATION PARAMETERS"); out1.println("##"); out1.println(" UMIN="+vumin); out1.println(" UMAX="+vumax); out1.println(" TEMP="+vtemp); out1.println(" RES="+vres); out1.println(" PAF="+vpaf); out1.println(" THRES="+vthres); out1.println("##"); out1.println(" LFIL="+lfil); out1.println(" CDAE="+cdae); out1.println(" MASS="+mass); out1.println(" UK="+1.); out1.println(" PTT="+ptt); if( nsptype != "raman" ) { out1.println(" PPT=$PTT"); out1.println(" CL="+1.); } out1.println("##"); out1.println(" APPF="+nappf); out1.println("##"); out1.println("## SIMULATION"); out1.println("##"); out1.println(" $SCRD"+fisep+"passx simul "+nsptype+" $UMIN $UMAX $TEMP $RES $PAF $THRES \\"); out1.print (" "); // 1st out1.print (" $LFIL $CDAE $MASS $UK $PTT"); if( nsptype != "raman" ) { out1.println(" $PPT $CL \\"); } else { out1.println(" \\"); } out1.println(" end $APPF"); out1.println("##"); } catch (IOException ioe) { // IO error JOptionPane.showMessageDialog(null,"IO error while writing file"+lnsep+ njobf +lnsep+ ioe); return false; } finally { // close the file if (out1 != null) { out1.close(); if( out1.checkError() ) { JOptionPane.showMessageDialog(null,"PrintWriter error while creating job file"+lnsep+ njobf); return false; } } } try { monproc = Runtime.getRuntime().exec("chmod u+x "+njobf); // allow execution } catch (IOException ioe) { // IO error JOptionPane.showMessageDialog(null,"IO error while changing rights of file"+lnsep+ njobf +lnsep+ ioe); return false; } return true; } // run job and test error file private boolean runJob() { ncmd = "cd "+tempod+" ; "+njobf+" >"+noutf+" 2>"+nerrf; // change to tempo directory // run command in a shell try { String[] cmd = {"/bin/sh", "-c", ncmd}; monproc = Runtime.getRuntime().exec(cmd); } catch (IOException ioe) { // IO error JOptionPane.showMessageDialog(null,"IO error while running command"+lnsep+ ncmd +lnsep+ ioe); return false; } try { monproc.waitFor(); // wait for end of job } catch (InterruptedException ie) { // error JOptionPane.showMessageDialog(null,"InterruptedException while running command"+lnsep+ ncmd); return false; } // error file has to be empty File errf = new File( nerrf ); if( errf.length() != 0 ) { JOptionPane.showMessageDialog(null,"Error while running local simulation job"+lnsep+ "See : "+nerrf); return false; } return true; } // Read lsx and lsy from simul.xy following FORMAT 2001 of simul.f private boolean readLsxy() { String str; // to read file Double cx; // to keep X Double cy; // to keep Y // to keep points, unknown nb of points ArrayList alx = new ArrayList(); // frequency ArrayList aly = new ArrayList(); // intensity try{ File f = new File( nxyf ); // the file br = new BufferedReader( new FileReader( f ) ); // open while ((str = br.readLine()) != null) { // line read try { // read data cx = Double.valueOf(str.substring(0,12)); // Double for X cy = Double.valueOf(str.substring(12,25)); // Double for Y } catch (NumberFormatException e) { // format error continue; // skip the line } alx.add(cx); // keep data aly.add(cy); } } catch(IOException ioe) { // IO error JOptionPane.showMessageDialog(null,"IO error while reading file"+lnsep+ nxyf +lnsep+ ioe); return false; } finally { // close if (br !=null) { try { br.close(); } catch (IOException ignored) { } } } // set lsx, lsy int nbxy = alx.size(); // nb of points if( nbxy == 0 ) { // no point JOptionPane.showMessageDialog(null,"No valid data found in file"+lnsep+ nxyf); return false; // invalid read } lsx = new double[nbxy]; // create arrays lsy = new double[nbxy]; for(int i=0; i 0) { jp.loadProjectFileName(args[0]); } } }); } } sources/org/spview/preferences/CoalescedEventUpdater.java000644 001750 001750 00000000733 13544613421 024536 0ustar00cyrilcyril000000 000000 package org.spview.preferences; import javax.swing.SwingUtilities; import javax.swing.Timer; public class CoalescedEventUpdater { private Timer timer; public CoalescedEventUpdater(int delay, Runnable callback) { timer = new Timer(delay, e -> { timer.stop(); callback.run(); }); } public void update() { if (!SwingUtilities.isEventDispatchThread()) { SwingUtilities.invokeLater(() -> { timer.restart(); }); } else { timer.restart(); } } }resources/JobPlay/jmipred2.html000644 001750 001750 00000000262 13544613421 017343 0ustar00cyrilcyril000000 000000

Associate prediction to data

Associate the prediction file to one of the loaded data files.

sources/org/spview/filehandler/DataFile.java000644 001750 001750 00000011477 13544613421 021761 0ustar00cyrilcyril000000 000000 package org.spview.filehandler; /* * Class for data files (spectrum or stick/peakas/tdsas/hitras). */ import java.awt.geom.Point2D; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.StringTokenizer; import javax.swing.JOptionPane; import org.spview.point.StickPoint; //////////////////////////////////////////////////////////////////// /** * This class defines spectrum or stick data. */ public class DataFile { private String name; // file name private String ntfile; // type private double[] x; // X data private double[] y; // Y data private int nbxy; // nb of points private String str; // to read file private BufferedReader br; private String lnsep; // line separator //////////////////////////////////////////////////////////////////// /** * Construct a new DataFile. * * @param cname file name */ public DataFile(String cname) { name = cname; // file name nbxy = 0; // nb of points lnsep = System.getProperty("line.separator"); } /** * Get name selection string. */ public String getname() { return name; } //////////////////////////////////////////////////////////////////// /** * Read file.
* validity is tested following :
* FORMAT 1000 of spech.f (HITRAN format prediction)
* FORMAT 1022 of spect.f (TDS format prediction)
* FORMAT 1024 of spects.f (D2hStark format prediction) */ public boolean read() { Double cx; // to keep X Double cy; // to keep Y Point2D data = null; // to keep points, unknown nb of points ArrayList alx = new ArrayList(); // frequency ArrayList aly = new ArrayList(); // intensity try { br = new BufferedReader(new FileReader(new File(name))); // open while ((str = br.readLine()) != null) { // line read if (ntfile.equals("peakas")) { // peak or assignment file as stick if (str.length() < 31) { // line too short continue; // skip it } try { // read data cx = Double.valueOf(str.substring(6, 18)); // Double for X cy = Double.valueOf(str.substring(20, 31)); // Double for Y data = new Point2D.Double(cx, cy); } catch (NumberFormatException e) { // format error continue; // skip the line } } else if (ntfile.equals("hitras")) { data = HITRANFile.extractXY(str); } else if (ntfile.equals("tdsas")) { data = TDSFile.extractXY(str); } else if (ntfile.equals("pickettas")) { data = PickettFile.extractXY(str); } else { // spectrum or stick file str = str.replace(',', ' '); // comma as separator (-> space) StringTokenizer st = new StringTokenizer(str); // separate X and Y if (st.countTokens() < 2) { // not enough tokens continue; // skip the line } try { cx = Double.valueOf(st.nextToken()); // Double for X cy = Double.valueOf(st.nextToken()); // Double for Y data = new Point2D.Double(cx, cy); } catch (NumberFormatException e) { // format error continue; // skip the line } } if (data != null) { alx.add(data.getX()); // keep data aly.add(data.getY()); } } } catch (IOException ioe) { // IO error JOptionPane.showMessageDialog(null, "IO error while reading file" + lnsep + name + lnsep + ioe); return false; } finally { // close if (br != null) { try { br.close(); } catch (IOException ignored) { } } } // save data int cnbxy = alx.size(); // current nb of points if (cnbxy == 0) { // no point JOptionPane.showMessageDialog(null, "No valid data found in file" + lnsep + name); return false; // invalid read } nbxy = cnbxy; x = new double[nbxy]; // create arrays y = new double[nbxy]; // sort StickPoint[] stickpoint = new StickPoint[nbxy]; // compare X for (int i = 0; i < nbxy; i++) { stickpoint[i] = new StickPoint(((Double) alx.get(i)).doubleValue(), ((Double) aly.get(i)).doubleValue()); // X, // Y } Arrays.sort(stickpoint); // sort for (int i = 0; i < nbxy; i++) { // save data x[i] = stickpoint[i].getX(); y[i] = stickpoint[i].getY(); } // happy end return true; } /** * Set file type. * * @param cntfile file type (spectrum/stick/peakas/tdsas/hitras) */ public void setType(String cntfile) { ntfile = cntfile; } /** * Get file type. */ public String getType() { return ntfile; } /** * Get number of data points. */ public int getNbxy() { return nbxy; } /** * Get X array. */ public double[] getX() { return x; } /** * Get X value. */ public double getX(int id) { return x[id]; } /** * Get Y array. */ public double[] getY() { return y; } /** * Get Y value. */ public double getY(int id) { return y[id]; } } resources/PanAff/jmishowbar.html000644 001750 001750 00000000247 13544613421 017572 0ustar00cyrilcyril000000 000000

Vertical bar

Set a vertical bar which helps to visualize frequency coincidences.

resources/JobPlay/jmiopenproject.html000644 001750 001750 00000000371 13544613421 020660 0ustar00cyrilcyril000000 000000

Open Project

Open a New Project. A project is a file ending with the ".spv" extension and created by SPVIEW: it only contains file paths embedded in a xml format.

sources/org/spview/preferences/WindowHandler.java000644 001750 001750 00000005316 13544613421 023074 0ustar00cyrilcyril000000 000000 package org.spview.preferences; import java.awt.Dimension; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.util.prefs.Preferences; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; public class WindowHandler { public static void registerFrame(JFrame frame, String frameUniqueId, int defaultX, int defaultY, int defaultW, int defaultH) { Preferences prefs = Preferences.userRoot().node(WindowHandler.class.getSimpleName() + "-" + frameUniqueId); Dimension savedDim = getFrameSize(prefs, defaultW, defaultH); Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); // The following test is needed on macOS. if ((savedDim.getWidth() >= screenSize.getWidth()) || (savedDim.getHeight() >= screenSize.getHeight())) { frame.setExtendedState(frame.getExtendedState() | JFrame.MAXIMIZED_BOTH); } else { frame.setSize(savedDim); frame.setLocation(getFrameLocation(prefs, defaultX, defaultY)); } CoalescedEventUpdater updater = new CoalescedEventUpdater(400, () -> updatePref(frame, prefs)); frame.addComponentListener(new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { updater.update(); } @Override public void componentMoved(ComponentEvent e) { updater.update(); } }); } public static void setLookAndFeel() { if (isMacOS()) { // take the menu bar off the jframe System.setProperty("apple.laf.useScreenMenuBar", "true"); // set the look and feel try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } private static boolean isMacOS() { String lcOSName = System.getProperty("os.name").toLowerCase(); return lcOSName.startsWith("mac os x"); } private static void updatePref(JFrame frame, Preferences prefs) { // System.out.println("Updating preferences"); Point location = frame.getLocation(); prefs.putInt("x", location.x); prefs.putInt("y", location.y); Dimension size = frame.getSize(); prefs.putInt("w", size.width); prefs.putInt("h", size.height); } private static Dimension getFrameSize(Preferences pref, int defaultW, int defaultH) { int w = pref.getInt("w", defaultW); int h = pref.getInt("h", defaultH); return new Dimension(w, h); } private static Point getFrameLocation(Preferences pref, int defaultX, int defaultY) { int x = pref.getInt("x", defaultX); int y = pref.getInt("y", defaultY); return new Point(x, y); } }sources/org/spview/gui/JFText.java000644 001750 001750 00000004437 13544613421 017761 0ustar00cyrilcyril000000 000000 package org.spview.gui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; /* * Class to show a string array */ ///////////////////////////////////////////////////////////////////// /** * Window to show a string array. */ public class JFText extends JFrame { /** * */ private static final long serialVersionUID = 1L; // panels private JPanel pcentre; // to show the string array private JScrollPane jsp; // with lifts private JTextArea jta; ///////////////////////////////////////////////////////////////////// /** * Constructs a JFText. * * @param cstr ArrayList array * @param cp_x x location of frame * @param cp_y y location of frame */ public JFText(ArrayList list, int cp_x, int cp_y) { super("List of points"); // main window setResizable(false); setAlwaysOnTop(true); addWindowListener(new WindowAdapter() { // clean end public void windowClosing(WindowEvent e) { dispose(); // free window } }); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); getContentPane().setLayout(new BorderLayout()); JPanel jp = new JPanel(new BorderLayout()); getContentPane().add(jp, "Center"); // panels pcentre = new JPanel(); // center jta = new JTextArea(); int ml = 0; // max length of strings for (int i = 0; i < list.size(); i++) { if (list.get(i).length() > ml) { ml = list.get(i).length(); } } jta.setColumns(ml); // jta width for (int i = 0; i < list.size(); i++) { jta.append(list.get(i)); // add strings } jta.setBackground(Color.BLACK); jta.setForeground(Color.WHITE); jta.setEditable(false); // not editable jta.setFont(new Font("Monospaced", Font.PLAIN, 15)); jta.setLineWrap(false); // no line wrap jta.setRows(10); // nb of lines jsp = new JScrollPane(jta, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); try { jta.setCaretPosition(0); // at the top of the text } catch (IllegalArgumentException iae) { } pcentre.add(jsp); // insert panels jp.add(pcentre, "Center"); setLocation(cp_x, cp_y); pack(); } }sources/org/spview/gui/PanAff.java000644 001750 001750 00000557722 13544613421 017762 0ustar00cyrilcyril000000 000000 package org.spview.gui; /* * Class to draw spectra and assignments */ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Locale; import javax.swing.Box; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JProgressBar; import javax.swing.JTextArea; import javax.swing.SwingUtilities; import org.spview.point.ExpJsynPoint; import org.spview.point.PredJsynPoint; import org.spview.filehandler.ExpFile; import org.spview.filehandler.DataFile; import org.spview.filehandler.PredFile; import org.spview.filehandler.FortranFormat; //////////////////////////////////////////////////////////// /** * This panel is used to paint the graphs. */ public class PanAff extends JPanel implements ActionListener, MouseListener, MouseMotionListener, Printable { /** * */ private static final long serialVersionUID = -6454762258521638796L; private JobPlay jobplay; // calling JobPlay private String workd; // working directory private Graphics2D g2d; // to be able to rotate text private boolean printing; // print status // all variables beginning with p_... contain pixel values (int or double) // others are in their own units : frequency, intensity // the following are related only to screen drawing private int p_xmouse; // x mouse position private int p_ymouse; // y mouse position private int p_wxma; // window width private int p_wyma; // window height private int prevp_wxma; // previous p_wxma private int p_cxmi; // x min of data area private int p_cxma; // x max of data area private int p_cwidth; // x range private int p_epymi; // exp/pred area y lower limit private int p_yatma; // exp area y upper limit private int p_yprmi; // pred area y lower limit private int p_yprma; // pred area y upper limit private int p_epyma; // exp/pred area y upper limit private int p_gap; // gap along axis private int p_cymi; // y min of data area private int p_cyma; // y max of data area private int p_cheight; // y range private int p_ovray; // oval ray private int p_ovwidth; // oval long ray private int p_xhalf; // half fuzzy width // sc_ variables define scale while drawing/printing private double sc_fontsz = .015; // font size % ddp_height private double sc_epymi = .005; // basic y gap % ddp_height private double sc_gap = .0035; // gap % ddp_width private double sc_ovray = .003; // oval ray % ddp_width private double sc_xhalf = .003; // half fuzzy width % ddp_width // data private String[] ntfile; // data file type private int[] nbxy; // number of points in data file private double[][] x; // frequency private double[][] y; // intensity private double[] sxmi; // X min (including shift) private double[] sxma; // X max (including shift) private int[] ixdeb; // window first point index private int[] ixfin; // window last point index private boolean[] use_red; // use reduced data private int[][] i_red; // index of reduced data private int[] nbxy_red; // reduced number of points private int[] ixdeb_red; // window first reduced point index private int[] ixfin_red; // window last reduced point index private boolean[] show; // show the data file private boolean[] yreverse; // Y reverse the data file private double[] xshifted; // X shift value private double[] yshifted; // Y shift value private int nbdf; // number of data files private int mxnbdf; // max number of data files private int nbpredasf; // number of pred-as-stick files private boolean[] dfready; // data file ready // exp private ExpFile expf; // experiment file private int efnbxy; // number of points in exp file private double[] efx; // frequency private String[] effasog; // global frequency mark private double[] efy; // intensity private String[] efsasog; // global intensity mark private String[] efsdobs; // frequency and intensity standard deviations string private ArrayList[] efejsynpt; // exp assignment point private String[] efexasg; // EXASG private int efixdeb; // window first point index private int efixfin; // window last point index private int efass2; // associated data file index private ArrayList alexasg; // EXASG choice private String[] exasg; // easy access EXASG private int nbexasg; // number of EXASG private String defexasg; // default EXASG private boolean efready; // exp file ready // pred private int pfnbxy; // number of points in pred file private double[] pfx; // frequency private double[] pfy; // intensity private int[] pfj; // J inf private String[] pfjsyn; // assignment string private int[] pfiexpa; // index of assigned exp private int pfixdeb; // window first point index private int pfixfin; // window last point index private int pfass2; // associated data file index private boolean pfready; // pred file ready private double predselx0; // starting x of pred selection area private double predselx1; // ending x of pred selection area // private double p_zx0; // starting x of zoom area private double p_zy0; // starting y of zoom area private double p_zx1; // ending x of zoom area private double p_zy1; // ending y of zoom area private double prevp_zx1; // previous p_zx1 private double prevp_zy1; // previous p_zy1 private double p_pfx0; // starting x of pred selection area private double p_pfx1; // ending x of pred selection area // private int p_paintx; // starting X of myrepaint area private int p_painty; // starting Y of myrepaint area private int p_paintwidth; // width of myrepaint area private int p_paintheight; // height of myrepaint area // private double axmi; // global frequency mini private double axma; // global frequency maxi private double axdelta; // global frequency range private double aymi; // global intensity mini private double ayma; // global intensity maxi private double aydelta; // global intensity range private double ayrev; // global intensity reverse axis private double saxmi; // global frequency mini (including shift) private double saxma; // global frequency maxi (including shift) private double bxmi; // window frequency mini private double bxma; // window frequency maxi private double bxdelta; // window frequency range private double bymi; // window intensity mini private double byma; // window intensity maxi private double bydelta; // window intensity range private double apasymi; // pred-as-stick global intensity mini private double apasyma; // pred-as-stick global intensity maxi private double apasydelta; // pred-as-stick global intensity range private double apasyrev; // pred-as-stick global intensity reverse axis private double bpasymi; // pred-as-stick window intensity mini private double bpasyma; // pred-as-stick window intensity maxi private double bpasydelta; // pred-as-stick window intensity range // first tick , interval, nb of intervals, last tick private double[] acadreX = {0., 0., 0., 0.}; // global frequency private double[] acadreY = {0., 0., 0., 0.}; // global intensity private double[] bcadreX = {0., 0., 0., 0.}; // window frequency private double[] bcadreY = {0., 0., 0., 0.}; // window intensity private double[] acadrepasY = {0., 0., 0., 0.}; // pred-as-stick global intensity private double[] bcadrepasY = {0., 0., 0., 0.}; // pred-as-stick window intensity private Rectangle2D rectS; // rectangle defined by a string private Color[] coul; // colors private int nbcoul; // number of colors private JTextArea jta; // for selected exp and pred characteristics private boolean showbar; // allow to show vertical bar private boolean movebar; // allow to move vertical bar private double xbar; // X position of vertical bar private boolean zoomx; // X zoom has to be defined private boolean zoomy; // Y zoom has to be defined private boolean zoompasy; // pred-as-stick Y zoom has to be defined private boolean zoom; // draw zoom area private int shiftedf; // index of shifted data file private boolean shiftx; // X shift has to be defined private boolean shifty; // Y shift has to be defined private boolean shift; // X or Y shift have to be defined private boolean predsel; // pred selection running // mouse position private JLabel jlx; // X in data scale private JLabel jly; // Y in data scale private JLabel jlypredas; // Y in pred-as-stick scale // data file area popup menu private JPopupMenu jpmdata; private JMenuItem jmishowbar; // show-set vertical bar private JMenuItem jmihidebar; // hide vertical bar private JMenuItem jmizoomx; // X zoom private JMenuItem jmizoomy; // Y zoom private JMenuItem jmizoompasy; // pred_as_stick Y zoom private JMenu jmrescalex; // X rescale private JMenu jmrescaley; // Y rescale private JMenu jmrescalepasy; // pred-as-stick Y rescale private JMenuItem jmirestorex; // X restore private JMenuItem jmirestorey; // Y restore private JMenuItem jmirestorepasy; // pred-as-stick Y restore // assignment area popup menu private JPopupMenu jpmassign; private JMenuItem jmiunselexp; // unselect exp private JMenu jmunass; // unassign private JMenuItem[] jmiunass; // select one assignment to be unassigned private JMenuItem jmiunassall; // select all assignments to be unassigned private String[] xaso = { " ", "+", "-" }; // possible values for frequency and intensity marks private int nbxaso; // number of values private JMenu jmfaso; // set frequency mark private JMenuItem[][] jmifaso; // [assignments][frequency marks] private JMenu jmsaso; // set intensity mark private JMenuItem[][] jmisaso; // [assignments][intensity marks] private JMenu jmexasg; // set EXASG private JMenuItem[] jmiexasg; // [exp data] private JMenu jmcomm; // set comment private JMenuItem[] jmicomm; // [exp data] private JMenuItem jmiaddexasg; // add EXASG string private JMenu jmdefexasg; // set default EXASG private JMenuItem[] jmidefexasg; // [possible EXASG] // exp selection popupmenu private JPopupMenu jpmexp; private int mxticks = 30; // max nb of ticks in an exp selection popup menu private JMenuItem[] jmiexp; // selectable private int ixexp; // selected exp index private int ixdebexp; // window first point index private int ixfinexp; // window last point index // pred selection window private JFSelPred jfsp; // selected pred display private boolean lsallowed; // local simulation allowed private boolean locsim; // loc-sim shown private double[] lsx; // loc-sim spectrum X private double[] lsy; // loc-sim spectrum Y private double lsmi; // loc-sim spectrum Ymin private double lsma; // loc-sim spectrum Ymax private double lsmis; // pred associated spectrum Ymin private double lsmas; // pred associated spectrum Ymax private int[] ixpred; // selected pred index private int[] ixpreds; // selected pred status >> -1: nothing(---), 0: already in exp(ASG), 1: selected(SEL) private int nbixpred; // nb of selected xpred private int ixdebpred; // pred area first point index // private int ixfinpred; // pred area last point index private int ixpredable; // index of current selectable pred // for X/Y rescale private int[] fact = { 2, 5, 10, 20, 50, 100 }; // scaling factors private int nbfact; // number of scaling factors private int nbscalec; // number of scaling choices private JMenuItem[] jmivalexpx; // frequency choices private JMenuItem[] jmivalexpy; // intensity choices private JMenuItem[] jmivalexppasy; // pred-as-stick intensity choices // format private String cStr; private ExpJsynPoint cejpt; // to sort private String nsavexp; // saved exp file name private PrintWriter out1; private String lnsep; // line separator private String fisep; // file separator private Font mono14; // Monospaced 14 font private int fontsz = 14; // font size public final static String EXASG_DEFAULT = "SPVIEW_EXASG "; ///////////////////////////////////////////////////////////////////// /** * Construct a new PanAff. * * @param cjobplay calling JobPlay * @param cmxnbdf max number of data files * @param ccoul colors * @param cjta to show selected exp and pred * @param cjlx to show X mouse position (data scale) * @param cjly to show Y mouse position (data scale) * @param cjlypredas to show Y mouse position (pred-as-stick scale) */ public PanAff( JobPlay cjobplay, int cmxnbdf, Color[] ccoul, JTextArea cjta, JLabel cjlx, JLabel cjly, JLabel cjlypredas) { setName("PanAff"); // for help files jobplay = cjobplay; // calling jobplay workd = System.getProperty("user.dir"); // working directory mxnbdf = cmxnbdf; // max nb of data files coul = (Color[]) ccoul.clone(); // color choice nbcoul = ccoul.length; // nb of colors jta = cjta; // to show selected exp and pred jlx = cjlx; // to show X mouse position (data scale) jly = cjly; // to show Y mouse position (data scale) jlypredas = cjlypredas; // to show Y mouse position (pred-as-stick scale) lnsep = System.getProperty("line.separator"); fisep = System.getProperty("file.separator"); mono14 = new Font("Monospaced", Font.PLAIN, fontsz); // default font // create arrays ntfile = new String[mxnbdf]; // data file type nbxy = new int[mxnbdf]; // number of points in data file x = new double[mxnbdf][]; // frequency y = new double[mxnbdf][]; // intensity sxmi = new double[mxnbdf]; // X min (including shift) sxma = new double[mxnbdf]; // X max (including shift) ixdeb = new int[mxnbdf]; // window first point index ixfin = new int[mxnbdf]; // window last point index use_red = new boolean[mxnbdf]; // use reduced data i_red = new int[mxnbdf][]; // index of reduced data nbxy_red = new int[mxnbdf]; // reduced number of points ixdeb_red = new int[mxnbdf]; // window first reduced point index ixfin_red = new int[mxnbdf]; // window last reduced point index show = new boolean[mxnbdf]; // show the data file yreverse = new boolean[mxnbdf]; // Y reverse the data file xshifted = new double[mxnbdf]; // X shift value yshifted = new double[mxnbdf]; // Y shift value dfready = new boolean[mxnbdf]; // data file ready status Arrays.fill(dfready,false); // NO data file ready efass2 = -1; // exp NOT associated to a data file pfass2 = -1; // pred NOT associated to a data file nbdf = 0; // nb of data files nbpredasf = 0; // nb of pred-as-stick files efnbxy = 0; // nb of exp points ixexp = -1; // NO exp data selected efready = false; // exp file NOT ready pfnbxy = 0; // nb of pred points nbixpred = 0; // NO selected pred points pfready = false; // pred file NOT ready nbxaso = xaso.length; // nb of possible values for frequency and intensity marks // mouse survey addMouseListener(this); addMouseMotionListener(this); // printing status printing = false; // no waited action showbar = false; // no vertical bar to show movebar = false; // no move of vertical bar zoomx = false; // no x zoom area to define zoomy = false; // no y zoom area to define zoompasy = false; // no pred-as-stick y zoom area to define zoom = false; // no zoom area to draw shiftx = false; // no x shift area to define shifty = false; // no y shift area to define shift = false; // no shift area to draw predsel = false; // no running pred selection lsallowed = false; // local simulation not allowed locsim = false; // no local simulation shown // define X/Y scaling menus nbfact = fact.length; // nb of scaling factors nbscalec = 2*nbfact; // nb of scaling choices (* and /) jmivalexpx = new JMenuItem[nbscalec]; // frequency choices jmivalexpy = new JMenuItem[nbscalec]; // intensity choices jmivalexppasy = new JMenuItem[nbscalec]; // pred-as-stick intensity choices jmrescalex = new JMenu("Rescale X"); jmrescaley = new JMenu("Rescale Y"); jmrescalepasy = new JMenu("Rescale pred-as-stick Y"); for( int i=0; i= 1) { // number of the page to print return Printable.NO_SUCH_PAGE; // only one } printing = true; // used to disallowed some button actions while printing double pfIW = pf.getImageableWidth(); double pfIH = pf.getImageableHeight(); // we have to reduce printed area to fit various OS behaviours int prp_wxma = (int) (.9*pfIW -1); // paper printable X max int prp_wyma = (int) (.9*pfIH -1); // paper printable Y max g2d = (Graphics2D) g; // for extended functions g2d.translate(pf.getImageableX()+.05*pfIW, // translate to printable area pf.getImageableY()+.05*pfIH ); boolean screen = false; // NOT screen but printer drawing int p_width = (int) pf.getWidth(); // paper width int p_height = (int) pf.getHeight(); // paper height drawData( g2d, prp_wxma, prp_wyma, screen, p_width, p_height ); // draw printing = false; // NOT longer printing return Printable.PAGE_EXISTS; // page ready } ///////////////////////////////////////////////////////////////////////////// // create the page to print or draw on screen private void drawData(Graphics2D g2d, int ddp_wxma, int ddp_wyma, boolean screen, int ddp_width, int ddp_height) { // all dd_ and ddp_ variables are drawData local // usefull variables int ddp_x0; int ddp_x1; int ddp_x2; int ddp_y0; int ddp_y1; int ddp_y2; String dd_str; // paint g2d.setColor(Color.BLACK); // black int dd_fontsz = (int) Math.round(ddp_height*sc_fontsz); // font size Font monoFt = new Font("Monospaced", Font.PLAIN, dd_fontsz); // default font g2d.setFont( monoFt ); FontMetrics fm = g2d.getFontMetrics(); // for its methods // ddp_wxma and ddp_wyma are defined before call to drawData // in paintComponent (draw) or print int ddp_gap = (int) Math.round(ddp_width*sc_gap); // gap int ddp_cxmi = 2*ddp_gap+(int) Math.round(dd_fontsz*2.5); // x min int ddp_cxma = ddp_wxma-ddp_cxmi; // x max int ddp_cwidth = ddp_cxma-ddp_cxmi+1; // x range int ddp_epymi = (int) Math.round(ddp_height*sc_epymi); // exp/pred area y lower limit (basic y gap) int ddp_ysaso = ddp_epymi+ 3*ddp_epymi; // y of intensity mark int ddp_yfaso = ddp_epymi+ 6*ddp_epymi; // y of frequency mark int ddp_yatmi = ddp_epymi+ 7*ddp_epymi; // exp area y lower limit int ddp_yatma = ddp_epymi+11*ddp_epymi; // exp area y upper limit int ddp_yprmi = ddp_epymi+12*ddp_epymi; // pred area y lower limit int ddp_yprma = ddp_epymi+16*ddp_epymi; // pred area y upper limit int ddp_epyma = ddp_epymi+17*ddp_epymi; // exp/pred area y upper limit int ddp_cymi = ddp_epyma+ddp_gap; // y min int ddp_cyma = ddp_wyma-ddp_cxmi; // y max int ddp_cheight = ddp_cyma-ddp_cymi+1; // y range int ddp_ovray = (int) Math.round(ddp_width*sc_ovray); // oval ray int ddp_ovwidth = 2*ddp_ovray+1; // oval long ray int ddp_sqhw = ddp_ovray+1; // square half side int ddp_sqwidth = 2*ddp_sqhw+1; // square side int ddp_xhalf = (int) Math.round(ddp_width*sc_xhalf); // half fuzzy width // save some for external usage (mouse location, reduced data) if( screen ) { p_gap = ddp_gap; p_cxmi = ddp_cxmi; p_cxma = ddp_cxma; p_cwidth = ddp_cwidth; p_epymi = ddp_epymi; p_yatma = ddp_yatma; p_yprmi = ddp_yprmi; p_yprma = ddp_yprma; p_epyma = ddp_epyma; p_cymi = ddp_cymi; p_cyma = ddp_cyma; p_cheight = ddp_cheight; p_ovray = ddp_ovray; p_ovwidth = ddp_ovwidth; p_xhalf = ddp_xhalf; if( ddp_wxma != prevp_wxma ) { // window size changed setRedSpect(); // reduce spectrum data if necessary } prevp_wxma = ddp_wxma; // keep it for next call } if( nbdf == 0 ) { // no data file return; } // in-clip area to (re)paint Rectangle rect = g2d.getClipBounds(); // in-clip rectangle int ddp_clipxmi = Math.max(0,rect.x-1); // lower X pixel ??? one more needed int ddp_clipxma = rect.x+rect.width; // upper X pixel ??? one more needed double dd_clipxmi = p2X(ddp_clipxmi, ddp_cxmi, ddp_cxma); // lower frequency double dd_clipxma = p2X(ddp_clipxma, ddp_cxmi, ddp_cxma); // upper frequency int ddp_clipymi = rect.y; // lower Y pixel int ddp_clipyma = rect.y+rect.height-1; // upper Y pixel // axis and ticks // in-clip area not taken into account // X data axis ddp_y0 = ddp_cyma+ddp_gap; ddp_y1 = ddp_y0+ddp_gap; ddp_y2 = ddp_y1+(int) Math.round(dd_fontsz*1.2); // text location g2d.drawLine( ddp_cxmi, ddp_y0, ddp_cxma, ddp_y0); // draw axis for( int i = 0; i<=(int) bcadreX[2]; i++) { // for each tick mark ddp_x0 = ip_X(bcadreX[0]+i*bcadreX[1], ddp_cxmi, ddp_cxma); g2d.drawLine(ddp_x0, ddp_y0, ddp_x0, ddp_y1); // draw tick mark } dd_str = ""+(float) bcadreX[0]; rectS = fm.getStringBounds(dd_str,g2d); ddp_x0 = Math.max(0, (int) Math.round( ip_X(bcadreX[0], ddp_cxmi, ddp_cxma)-rectS.getWidth()/2. ) ); // center value of 1st tick in limits g2d.drawString(dd_str, ddp_x0, ddp_y2); dd_str = "("+(float) bcadreX[1]+")"; rectS = fm.getStringBounds(dd_str,g2d); ddp_x0 = (int) Math.round( ip_X((bcadreX[0]+bcadreX[3])/2., ddp_cxmi, ddp_cxma)-rectS.getWidth()/2. ); // center interval value g2d.drawString(dd_str, ddp_x0, ddp_y2); dd_str = ""+(float) bcadreX[3]; rectS = fm.getStringBounds(dd_str,g2d); ddp_x0 = Math.min( (int) Math.round( ip_X(bcadreX[3], ddp_cxmi, ddp_cxma)-rectS.getWidth()/2. ), (int) Math.round(ddp_wxma-rectS.getWidth())); // center value of last tick in limits g2d.drawString(dd_str, ddp_x0, ddp_y2); // Y data axis ddp_x0 = ddp_cxmi-ddp_gap; ddp_x1 = ddp_x0-ddp_gap; g2d.drawLine(ddp_x0, ddp_cyma, ddp_x0, ddp_cymi ); // draw axis for( int i = 0; i<=(int) bcadreY[2]; i++) { // for each tick mark ddp_y0 = ip_Y(bcadreY[0]+i*bcadreY[1], ddp_cymi, ddp_cyma); g2d.drawLine(ddp_x0, ddp_y0, ddp_x1, ddp_y0); // draw tick } ddp_x2 = ddp_x1-(int) Math.round(dd_fontsz*.4); // text location dd_str = ""+ (float) bcadreY[0]; rectS = fm.getStringBounds(dd_str,g2d); ddp_y0 = Math.min( ddp_y1, (int) Math.round( ip_Y(bcadreY[0], ddp_cymi, ddp_cyma)+rectS.getWidth()/2. ) ); // center value of 1st tick in limits drawRotString(dd_str, ddp_x2, ddp_y0); dd_str = "("+(float) bcadreY[1]+")"; rectS = fm.getStringBounds(dd_str,g2d); ddp_y0 = (int) Math.round( ip_Y((bcadreY[0]+bcadreY[3])/2., ddp_cymi, ddp_cyma)+rectS.getWidth()/2. ); // center interval value drawRotString(dd_str, ddp_x2, ddp_y0); dd_str = ""+ (float) bcadreY[3]; rectS = fm.getStringBounds(dd_str,g2d); ddp_y0 = Math.max( (int) Math.round( ip_Y(bcadreY[3], ddp_cymi, ddp_cyma)+rectS.getWidth()/2. ), (int) Math.round(ddp_cymi-ddp_gap/2+rectS.getWidth())); // center value of last tick in limits drawRotString(dd_str, ddp_x2, ddp_y0); // Y pred-as-stick axis if( nbpredasf != 0 ) { ddp_x0 = ddp_cxma+ddp_gap; ddp_x1 = ddp_x0+ddp_gap; g2d.drawLine(ddp_x0, ddp_cyma, ddp_x0, ddp_cymi ); // draw axis for( int i = 0; i<=(int) bcadrepasY[2]; i++) { // for each tick mark ddp_y0 = ip_pasY(bcadrepasY[0]+i*bcadrepasY[1], ddp_cymi, ddp_cyma); g2d.drawLine(ddp_x0, ddp_y0, ddp_x1, ddp_y0); // draw tick } ddp_x2 = ddp_x1+(int) Math.round(dd_fontsz*1.2); // text location dd_str = ""+ (float) bcadrepasY[0]; rectS = fm.getStringBounds(dd_str,g2d); ddp_y0 = Math.min( ddp_y1, (int) Math.round( ip_pasY(bcadrepasY[0], ddp_cymi, ddp_cyma)+rectS.getWidth()/2. ) ); // center value of 1st tick in limits drawRotString(dd_str, ddp_x2, ddp_y0); dd_str = "("+(float) bcadrepasY[1]+")"; rectS = fm.getStringBounds(dd_str,g2d); ddp_y0 = (int) Math.round( ip_pasY((bcadrepasY[0]+bcadrepasY[3])/2., ddp_cymi, ddp_cyma)+rectS.getWidth()/2. ); // center interval value drawRotString(dd_str, ddp_x2, ddp_y0); dd_str = ""+ (float) bcadrepasY[3]; rectS = fm.getStringBounds(dd_str,g2d); ddp_y0 = Math.max( (int) Math.round( ip_pasY(bcadrepasY[3], ddp_cymi, ddp_cyma)+rectS.getWidth()/2. ), (int) (ddp_cymi-ddp_gap/2+rectS.getWidth())); // center value of last tick in limits drawRotString(dd_str, ddp_x2, ddp_y0); } // for each data if( (ddp_clipxma >= ddp_cxmi && ddp_clipxmi <= ddp_cxma) && (ddp_clipyma >= ddp_cymi && ddp_clipymi <= ddp_cyma) ) { // in in-clip area // define out-clip area g2d.setClip( ddp_cxmi, ddp_cymi, ddp_cwidth, ddp_cheight ); for( int j=0; j dd_clipxma ) { // end of draw break; } ddp_x0 = ip_X(x[j][cim1], ddp_cxmi, ddp_cxma); ddp_x1 = ip_X(x[j][ci], ddp_cxmi, ddp_cxma); ddp_y0 = ip_Y(ayrev-y[j][cim1], ddp_cymi, ddp_cyma); ddp_y1 = ip_Y(ayrev-y[j][ci], ddp_cymi, ddp_cyma); g2d.drawLine( ddp_x0, ddp_y0, ddp_x1, ddp_y1); } } else { // no Y reverse for( int i=cixdeb+1; i<=cixfin; i++ ) { if( reduce ) { ci = i_red[j][i]; cim1 = i_red[j][i-1]; } else { ci = i; cim1 = i-1; } if( x[j][ci] < dd_clipxmi ) { continue; } if( x[j][cim1] > dd_clipxma ) { break; } ddp_x0 = ip_X(x[j][cim1], ddp_cxmi, ddp_cxma); ddp_x1 = ip_X(x[j][ci], ddp_cxmi, ddp_cxma); ddp_y0 = ip_Y(y[j][cim1], ddp_cymi, ddp_cyma); ddp_y1 = ip_Y(y[j][ci], ddp_cymi, ddp_cyma); g2d.drawLine( ddp_x0, ddp_y0, ddp_x1, ddp_y1); } } } } // stick else if( ntfile[j].equals("stick") ) { if( yreverse[j] ) { // Y reverse for( int i=ixdeb[j]; i<=ixfin[j]; i++ ) { if( x[j][i] < dd_clipxmi ) { continue; } if( x[j][i] > dd_clipxma ) { break; } ddp_x0 = ip_X(x[j][i], ddp_cxmi, ddp_cxma); ddp_x1 = ddp_x0; ddp_y0 = ip_Y(ayrev- yshifted[j], ddp_cymi, ddp_cyma); ddp_y1 = ip_Y(ayrev-(y[j][i]+yshifted[j]), ddp_cymi, ddp_cyma); g2d.drawLine( ddp_x0, ddp_y0, ddp_x1, ddp_y1); } } else { // no Y reverse for( int i=ixdeb[j]; i<=ixfin[j]; i++ ) { if( x[j][i] < dd_clipxmi ) { continue; } if( x[j][i] > dd_clipxma ) { break; } ddp_x0 = ip_X(x[j][i], ddp_cxmi, ddp_cxma); ddp_x1 = ddp_x0; ddp_y0 = ip_Y( yshifted[j], ddp_cymi, ddp_cyma); ddp_y1 = ip_Y(y[j][i]+yshifted[j], ddp_cymi, ddp_cyma); g2d.drawLine( ddp_x0, ddp_y0, ddp_x1, ddp_y1); } } } // peakas else if( ntfile[j].equals("peakas") ) { if( yreverse[j] ) { // Y reverse for( int i=ixdeb[j]; i<=ixfin[j]; i++ ) { if( x[j][i] < dd_clipxmi ) { continue; } if( x[j][i] > dd_clipxma ) { break; } ddp_x0 = ip_X(x[j][i], ddp_cxmi, ddp_cxma); ddp_x1 = ddp_x0; ddp_y0 = ip_Y(1. +yshifted[j], ddp_cymi, ddp_cyma); ddp_y1 = ip_Y(y[j][i]+yshifted[j], ddp_cymi, ddp_cyma); g2d.drawLine( ddp_x0, ddp_y0, ddp_x1, ddp_y1); } } else { // no Y reverse for( int i=ixdeb[j]; i<=ixfin[j]; i++ ) { if( x[j][i] < dd_clipxmi ) { continue; } if( x[j][i] > dd_clipxma ) { break; } ddp_x0 = ip_X(x[j][i], ddp_cxmi, ddp_cxma); ddp_x1 = ddp_x0; ddp_y0 = ip_Y( +yshifted[j], ddp_cymi, ddp_cyma); ddp_y1 = ip_Y(y[j][i]+yshifted[j], ddp_cymi, ddp_cyma); g2d.drawLine( ddp_x0, ddp_y0, ddp_x1, ddp_y1); } } } // pred-as-stick else { if( yreverse[j] ) { // Y reverse for( int i=ixdeb[j]; i<=ixfin[j]; i++ ) { if( x[j][i] < dd_clipxmi ) { continue; } if( x[j][i] > dd_clipxma ) { break; } ddp_x0 = ip_X(x[j][i], ddp_cxmi, ddp_cxma); ddp_x1 = ddp_x0; ddp_y0 = ip_pasY(apasyrev- yshifted[j], ddp_cymi, ddp_cyma); ddp_y1 = ip_pasY(apasyrev-(y[j][i]+yshifted[j]), ddp_cymi, ddp_cyma); g2d.drawLine( ddp_x0, ddp_y0, ddp_x1, ddp_y1); } } else { // no Y reverse for( int i=ixdeb[j]; i<=ixfin[j]; i++ ) { if( x[j][i] < dd_clipxmi ) { continue; } if( x[j][i] > dd_clipxma ) { break; } ddp_x0 = ip_X(x[j][i], ddp_cxmi, ddp_cxma); ddp_x1 = ddp_x0; ddp_y0 = ip_pasY( yshifted[j], ddp_cymi, ddp_cyma); ddp_y1 = ip_pasY(y[j][i]+yshifted[j], ddp_cymi, ddp_cyma); g2d.drawLine( ddp_x0, ddp_y0, ddp_x1, ddp_y1); } } } } } } // local simulation if( locsim ) { g2d.setColor(Color.RED); for( int i=1; i dd_clipxma ) { // end of draw break; } ddp_x0 = ip_X(lsx[i-1], ddp_cxmi, ddp_cxma); ddp_x1 = ip_X(lsx[i], ddp_cxmi, ddp_cxma); ddp_y0 = ip_Y(lsy[i-1], ddp_cymi, ddp_cyma); ddp_y1 = ip_Y(lsy[i], ddp_cymi, ddp_cyma); g2d.drawLine( ddp_x0, ddp_y0, ddp_x1, ddp_y1); } } } // exp/pred area if( (ddp_clipxma >= ddp_cxmi && ddp_clipxmi <= ddp_cxma) ) { // define out-clip area g2d.setClip( ddp_cxmi, ddp_epymi, ddp_cxma-ddp_cxmi+1, ddp_epyma-ddp_epymi+1 ); g2d.setColor(Color.BLACK); // black int cp_clipxmi; // current in-clip X min int cp_clipxma; // current in-clip X max int ddp_ovxmi; // oval X min // exp if( (ddp_clipyma >= ddp_epymi && ddp_clipymi <= ddp_yatma) ) { // in in-clip area cp_clipxmi = ddp_clipxmi; // current in-clip X min cp_clipxma = ddp_clipxma; // current in-clip X max if( efready ) { // exp file loaded if( ixexp >= 0 ) { // exp selected double xexp = efx[ixexp]; if( xexp >= bxmi && xexp <= bxma ) { // in window ddp_ovxmi = ip_X(xexp, ddp_cxmi, ddp_cxma)-ddp_ovray; if( ddp_ovxmi+ddp_ovwidth >= ddp_clipxmi && ddp_ovxmi <= ddp_clipxma ) { g2d.setColor(Color.RED); g2d.fillOval(ddp_ovxmi, ddp_yatmi, ddp_ovwidth, ddp_yatma-ddp_yatmi+1); // red oval cp_clipxmi = Math.min(cp_clipxmi, ddp_ovxmi); cp_clipxma = Math.max(cp_clipxma, ddp_ovxmi+ddp_ovwidth); } } } // associated to a data file ? if( efass2 >= 0 ) { // yes g2d.setColor(coul[efass2 -nbcoul*(efass2/nbcoul)]); // color } else { // no g2d.setColor(Color.BLACK); // black } // draw exp String str; for( int i=efixdeb; i<=efixfin; i++ ) { ddp_x0 = ip_X(efx[i], ddp_cxmi, ddp_cxma); if( ddp_x0 < cp_clipxmi ) { continue; } if( ddp_x0 > cp_clipxma ) { break; } // global frequency mark if( ! effasog[i].equals(" ") ) { str = String.valueOf(effasog[i]); rectS = fm.getStringBounds(str, g2d); g2d.drawString(str, (int) Math.round(ddp_x0-rectS.getWidth()/2.), ddp_yfaso); } // global intensity mark if( ! efsasog[i].equals(" ") ) { str = String.valueOf(efsasog[i]); rectS = fm.getStringBounds(str, g2d); g2d.drawString(str, (int) Math.round(ddp_x0-rectS.getWidth()/2.), ddp_ysaso); } // size if( (i/5)*5 == i ) { // big ddp_y2 = ddp_yatmi; } else { // plain ddp_y2 = (ddp_yatmi+ddp_yatma)/2; } g2d.drawLine( ddp_x0, ddp_y2, ddp_x0, ddp_yatma ); } } } // pred selection area if( (ddp_clipyma >= ddp_yprmi && ddp_clipymi <= ddp_yprma) ) { // in in-clip area cp_clipxmi = ddp_clipxmi; // current in-clip X min cp_clipxma = ddp_clipxma; // current in-clip X max if( ip_X(predselx0, ddp_cxmi, ddp_cxma) != ip_X(predselx1, ddp_cxmi, ddp_cxma) ) { // null zone ignored if( predsel ) { // pred file loaded // pred selection area if( dd_clipxma >= predselx0 && dd_clipxmi <= predselx1 ) { g2d.setColor(Color.LIGHT_GRAY); g2d.fillRect(ip_X(Math.max(predselx0,dd_clipxmi), ddp_cxmi, ddp_cxma), ddp_yprmi, ip_X(Math.min(predselx1,dd_clipxma), ddp_cxmi, ddp_cxma)-ip_X(Math.max(predselx0,dd_clipxmi), ddp_cxmi, ddp_cxma)+1, ddp_yprma-ddp_yprmi+1); // pred selection area } if( nbixpred > 0 ) { // pred selected g2d.setColor(Color.GREEN); for( int i=0; i cp_clipxma+ddp_ovray ) { break; } // in window if( ixpreds[i] == 1) { // selected ddp_ovxmi = ddp_x0-ddp_ovray; if( ddp_ovxmi+ddp_ovwidth >= ddp_clipxmi && ddp_ovxmi <= ddp_clipxma ) { g2d.fillOval(ddp_ovxmi, ddp_yprmi, ddp_ovwidth, ddp_yprma-ddp_yprmi+1); // green oval cp_clipxmi = Math.min(cp_clipxmi, ddp_ovxmi); cp_clipxma = Math.max(cp_clipxma, ddp_ovxmi+ddp_ovwidth); } } } if( ixpredable != -1 ) { g2d.setColor(Color.YELLOW); ddp_x0 = ip_X(pfx[ixpredable], ddp_cxmi, ddp_cxma); if( ddp_x0 >= cp_clipxmi-ddp_sqhw && ddp_x0 <= cp_clipxma+ddp_sqhw ) { ddp_ovxmi = ddp_x0-ddp_sqhw; g2d.fillRect(ddp_ovxmi, (ddp_yprmi+ddp_yprma)/2-ddp_sqhw, ddp_sqwidth, ddp_sqwidth); // yellow square cp_clipxmi = Math.min(cp_clipxmi, ddp_ovxmi); cp_clipxma = Math.max(cp_clipxma, ddp_ovxmi+ddp_sqwidth); } } } } } /* * pred file ready */ if( pfready ) { // show assigned pred g2d.setColor(Color.ORANGE); ddp_y2 = (ddp_yprmi+ddp_yprma)/2-ddp_ovray; for( int i=pfixdeb; i<=pfixfin; i++ ) { ddp_x0 = ip_X(pfx[i], ddp_cxmi, ddp_cxma); if( ddp_x0 < cp_clipxmi-ddp_ovray ) { continue; } if( ddp_x0 > cp_clipxma+ddp_ovray ) { break; } if( pfiexpa[i] >= 0 ) { ddp_ovxmi = ddp_x0-ddp_ovray; g2d.fillOval(ddp_ovxmi, ddp_y2, ddp_ovwidth, ddp_ovwidth); // orange disc cp_clipxmi = Math.min(cp_clipxmi, ddp_ovxmi); cp_clipxma = Math.max(cp_clipxma, ddp_ovxmi+ddp_ovwidth); } } } /* exp selected * and * exp and pred file ready */ if( ixexp >= 0 && efready && pfready ) { // show exp assigned pred g2d.setColor(Color.RED); ddp_y2 = (ddp_yprmi+ddp_yprma)/2-ddp_ovray; for( int k=0; k= 0 ) { // if defined double xpred = pfx[ipreda]; // its frequency if( xpred >= bxmi && xpred <= bxma ) { // if in the window ddp_x0 = ip_X(xpred, ddp_cxmi, ddp_cxma); if( ddp_x0 >= cp_clipxmi-ddp_ovray && ddp_x0 <= cp_clipxma+ddp_ovray ) { ddp_ovxmi = ddp_x0-ddp_ovray; g2d.fillOval(ddp_ovxmi, ddp_y2, ddp_ovwidth, ddp_ovwidth); // red disc cp_clipxmi = Math.min(cp_clipxmi, ddp_ovxmi); cp_clipxma = Math.max(cp_clipxma, ddp_ovxmi+ddp_ovwidth); } } } } } // pred if( pfready ) { // pred file ready // associated to a data file ? if( pfass2 >= 0 ) { // yes g2d.setColor(coul[pfass2 - nbcoul*(pfass2/nbcoul)]); // color } else { // no g2d.setColor(Color.BLACK); // black } // draw pred ddp_y2 = (ddp_yprmi+ddp_yprma)/2; for( int i=pfixdeb; i<=pfixfin; i++ ) { ddp_x0 = ip_X(pfx[i], ddp_cxmi, ddp_cxma); if( ddp_x0 < cp_clipxmi ) { continue; } if( ddp_x0 > cp_clipxma ) { break; } // size if( (pfj[i]/2)*2 == pfj[i] ) { // down ddp_y0 = ddp_y2; ddp_y1 = ddp_yprma; } else { // up ddp_y0 = ddp_yprmi; ddp_y1 = ddp_y2; } g2d.drawLine( ddp_x0, ddp_y0, ddp_x0, ddp_y1); } } } } // draw area frame g2d.setClip(null); g2d.setColor(Color.BLACK); // black g2d.drawRect( ddp_cxmi, ddp_epymi, ddp_cxma-ddp_cxmi, ddp_epyma-ddp_epymi); // vertical bar if( showbar ) { // show it // in-clip area not taken into account int ddp_xbar = ip_X(xbar, ddp_cxmi, ddp_cxma); // pixel X position if( ddp_xbar >= ddp_cxmi && ddp_xbar <= ddp_cxma ) { g2d.setColor(Color.RED); // color g2d.drawLine( ddp_xbar, ddp_epymi+ddp_gap/2, ddp_xbar, ddp_cyma+ddp_gap/2 ); // bar } } // zoom or shift to draw if( zoom || shift ) { // in-clip area not taken into account g2d.setColor(Color.BLACK); // black if( zoomx || shiftx ) { // X zoom/shift g2d.drawRect((int) Math.min(p_zx0,p_zx1), ddp_epymi+ddp_gap/2, (int) Math.abs(p_zx1-p_zx0)+1, ddp_cyma-ddp_epymi); // zoom area } if( zoomy || zoompasy || shifty ) { // Y zoom/pred-as-stick Y zoom/shift g2d.drawRect(ddp_cxmi-ddp_gap/2, (int) Math.min(p_zy0,p_zy1), ddp_cwidth+ddp_gap, (int) Math.abs(p_zy1-p_zy0)); // zoom area } } } // convert X from double to pixel private int ip_X( double x, int cup_cxmi, int cup_cxma ) { double cup_cwidth = cup_cxma-cup_cxmi; return (int) Math.round(cup_cxmi+cup_cwidth*((x-bxmi)/bxdelta)); } // convert X from pixel to double private double p2X( int p_x, int cup_cxmi, int cup_cxma ) { double cup_cwidth = cup_cxma-cup_cxmi; return bxmi+bxdelta*(p_x-cup_cxmi)/cup_cwidth; } // convert Y from double to pixel private int ip_Y( double y, int cup_cymi, int cup_cyma ) { double cup_cheight = cup_cyma-cup_cymi; return (int) Math.round(cup_cyma-cup_cheight*((y-bymi)/bydelta)); } // convert Y from pixel to double private double p2Y( int p_y, int cup_cymi, int cup_cyma ) { double cup_cheight = cup_cyma-cup_cymi; return bymi+bydelta*(cup_cyma-p_y)/cup_cheight; } // convert pasY from double to pixel private int ip_pasY( double y, int cup_cymi, int cup_cyma ) { double cup_cheight = cup_cyma-cup_cymi; return (int) Math.round(cup_cyma-cup_cheight*((y-bpasymi)/bpasydelta)); } // convert pasY from pixel to double private double p2pasY( int p_y, int cup_cymi, int cup_cyma ) { double cup_cheight = cup_cyma-cup_cymi; return bpasymi+bpasydelta*(cup_cyma-p_y)/cup_cheight; } // write a string along Y axis private void drawRotString( String s, int x, int y ) { AffineTransform at = g2d.getTransform(); g2d.rotate(-Math.PI/2., x, y); g2d.drawString(s, x, y); //g2d.rotate( Math.PI/2., x, y); g2d.setTransform( at ); } /** * Printing status. */ public boolean getPrinting() { return printing; } ///////////////////////////////////////////////////////////////////////////// // mouse events management /** * Mouse button pressed. *
IN EXPERIMENT/PREDICTION AREA : *
left button : experiment/prediction selection *
right button : assignment popup menu *
*
IN DATA DRAWING AREA : *
left button : vertical bar capture OR zoom/shift starting point *
right button : data popup menu */ public void mousePressed(MouseEvent mevt) { if( nbdf == 0 ) { // no data file return; } double p_x0 = mevt.getX(); // store X double p_y0 = mevt.getY(); // store Y // zoom starting point limited to frame p_zx0 = p_x0; p_zy0 = p_y0; if ( p_x0 < p_cxmi-p_gap/2 ) { p_zx0 = p_cxmi-p_gap/2; } else if( p_x0 > p_cxma+p_gap/2 ) { p_zx0 = p_cxma+p_gap/2; } if ( p_y0 < p_cymi-p_gap/2 ) { p_zy0 = p_cymi-p_gap/2; } else if( p_y0 > p_cyma+p_gap/2 ) { p_zy0 = p_cyma+p_gap/2; } // will be used to define clip area to redraw prevp_zx1 = p_zx0; prevp_zy1 = p_zy0; // if( zoomx || zoomy || zoompasy || shiftx || shifty ) { // zoom or shift if( ! SwingUtilities.isLeftMouseButton(mevt) ) { // not left button return; } // left button if( zoomx || zoomy || zoompasy ) { zoom = true; } else if( shiftx || shifty ) { shift = true; } return; } else { // neither zoom nor shift if( SwingUtilities.isRightMouseButton(mevt) ) { // right button // stop pred selection if any if( predsel ) { endSelPred(); } if( p_y0 > p_epyma ) { // data popup jpmdata.show(mevt.getComponent(), (int) p_zx0, (int) p_zy0); } else { // assignment popup if( setJpmAssign() ) { jpmassign.show(mevt.getComponent(), (int) p_zx0, (int) p_zy0); } else { JOptionPane.showMessageDialog(null,"This button is active in this area only if"+lnsep+ "a peak/experiment file is loaded"); } } return; } else if( SwingUtilities.isLeftMouseButton(mevt) ) { // left button if( p_x0 > p_cxmi && p_x0 < p_cxma ) { // vertical bar if( showbar && Math.abs(p_x0-ip_X(xbar, p_cxmi, p_cxma)) < p_xhalf && p_y0 >= p_cymi && p_y0 <= p_cyma ) { // vertical bar selected movebar = true; } else { // stop pred selection if any if( predsel ) { endSelPred(); } if( efready && // exp file ready p_y0 > p_epymi && p_y0 < p_yatma ) { // mouse in exp area // assignment selection predsel = false; selExp(p_zx0); } else if( pfready && // pred file ready p_y0 > p_yprmi && p_y0 < p_epyma ) { // mouse in pred area // pred selection starting p_pfx0 = p_x0; // pred selection area starting point (pixel) p_pfx1 = p_pfx0; // pred selection area ending point (pixel) predselx0 = p2X( (int) p_pfx0, p_cxmi, p_cxma ); // pred selection area starting point (double) predselx1 = predselx0; // pred selection area ending point (double) predsel = true; // pred selection running } } } } } } /** * Mouse moved with button pressed. *
(zoom/shift area definition) */ public void mouseDragged(MouseEvent mevt) { if( nbdf == 0 ) { // no data file return; } double p_x1 = mevt.getX(); // store X double p_y1 = mevt.getY(); // store Y p_xmouse = (int) p_x1; // store X p_ymouse = (int) p_y1; // store Y showXY(); // show mouse position if( movebar || zoomx || zoomy || zoompasy || shiftx || shifty ) { if( ! SwingUtilities.isLeftMouseButton(mevt) ) { // not left button return; } p_zx1 = p_x1; // store X (current end of zoom area) p_zy1 = p_y1; // store Y (current end of zoom area) // limited to the frame if ( p_x1 < p_cxmi-p_gap/2 ) { p_zx1 = p_cxmi-p_gap/2; } else if( p_x1 > p_cxma+p_gap/2 ) { p_zx1 = p_cxma+p_gap/2; } if ( p_y1 < p_cymi-p_gap/2 ) { p_zy1 = p_cymi-p_gap/2; } else if( p_y1 > p_cyma+p_gap/2 ) { p_zy1 = p_cyma+p_gap/2; } // define clip area to redraw if( movebar || zoomx || shiftx ) { p_paintx = (int) Math.min(prevp_zx1, p_zx1); p_painty = p_epymi+p_gap/2; p_paintwidth = (int) (Math.abs(p_zx1-prevp_zx1)+1); p_paintheight = (int) p_cyma-p_epymi+1; // vertical bar if( movebar ) { xbar = p2X((int) p_zx1, p_cxmi, p_cxma); // store its position xbar = Math.max(xbar, bxmi); xbar = Math.min(xbar, bxma); p_paintx = p_paintx-p_xhalf; // due to vertical bar X selection area p_paintwidth = p_paintwidth+2*p_xhalf; } } else { // zoomy/zoompasy/shifty p_paintx = p_cxmi-p_gap/2; p_painty = (int) Math.min(prevp_zy1,p_zy1); p_paintwidth = p_cwidth+p_gap; p_paintheight = (int) Math.abs(p_zy1-prevp_zy1)+1; } myrepaint(p_paintx, p_painty, p_paintwidth, p_paintheight); // limited along X direction prevp_zx1 = p_zx1; prevp_zy1 = p_zy1; } else if( predsel ) { // predselection running p_pfx1 = p_x1; // pred selection area ending point // limited to the frame if ( p_x1 < p_cxmi ) { p_pfx1 = p_cxmi; } else if( p_x1 > p_cxma ) { p_pfx1 = p_cxma; } selPred(Math.min(p_pfx0,p_pfx1), Math.max(p_pfx0,p_pfx1)); // show pred area and selection window jfsp.setContent( nbixpred, ixdebpred, ixpreds, ixexp ); // set selection window content } } /** * Mouse button released. *
(zoom/shift ending point) */ public void mouseReleased(MouseEvent mevt) { if (nbdf == 0) { // no data file return; } double p_x1 = mevt.getX(); // store X double p_y1 = mevt.getY(); // store Y if (movebar || zoomx || zoomy || zoompasy || shiftx || shifty) { // movebar, zoom or shift if (!SwingUtilities.isLeftMouseButton(mevt)) { // not left button return; } // left button p_zx1 = p_x1; // store X (end of zoom area) p_zy1 = p_y1; // store Y (end of zoom area) // limited to the frame if (p_x1 < p_cxmi - p_gap / 2) { p_zx1 = p_cxmi - p_gap / 2; } else if (p_x1 > p_cxma + p_gap / 2) { p_zx1 = p_cxma + p_gap / 2; } if (p_y1 < p_cymi - p_gap / 2) { p_zy1 = p_cymi - p_gap / 2; } else if (p_y1 > p_cyma + p_gap / 2) { p_zy1 = p_cyma + p_gap / 2; } // if (movebar || zoomx || shiftx) { p_painty = p_epymi + p_gap / 2; p_paintheight = p_cyma - p_epymi + 1; // zoom/shift area has to be not too small if (Math.abs(p_zx1 - p_zx0) < 5) { if (zoomx || shiftx) { p_paintx = (int) Math.min(p_zx0, p_zx1); p_paintwidth = (int) Math.abs(p_zx1 - p_zx0) + 1; JOptionPane.showMessageDialog(null, "zoom/shift area to small"); if (zoomx) { zoomx = false; zoom = false; } else if (shiftx) { shiftx = false; shift = false; } } myrepaint(p_paintx, p_painty, p_paintwidth, p_paintheight); // limited along X direction return; } if (movebar) { p_paintx = (int) Math.min(prevp_zx1, p_zx1); p_paintwidth = (int) Math.abs(p_zx1 - prevp_zx1) + 1; xbar = p2X((int) p_zx1, p_cxmi, p_cxma); xbar = Math.max(xbar, bxmi); xbar = Math.min(xbar, bxma); movebar = false; myrepaint(p_paintx, p_painty, p_paintwidth, p_paintheight); // limited along X direction return; } } else { // zoomy/zoompasy/shifty p_paintx = p_cxmi - p_gap / 2; p_paintwidth = p_cwidth + p_gap; // zoom/shift area has to be not too small if (Math.abs(p_zy1 - p_zy0) < 5) { p_painty = (int) Math.min(p_zy0, p_zy1); p_paintheight = (int) Math.abs(p_zy1 - p_zy0) + 1; JOptionPane.showMessageDialog(null, "zoom/shift area to small"); if (zoomy) { zoomy = false; zoom = false; } else if (zoompasy) { zoompasy = false; zoom = false; } else if (shifty) { shifty = false; shift = false; } myrepaint(p_paintx, p_painty, p_paintwidth, p_paintheight); // limited along Y direction return; } } // if (zoomx) { // X zoom bxma = bxmi + bxdelta * (Math.max(p_zx0, p_zx1) - p_cxmi) / p_cwidth; bxmi = bxmi + bxdelta * (Math.min(p_zx0, p_zx1) - p_cxmi) / p_cwidth; bxdelta = bxma - bxmi; // window frequency range setXax(); // set X axis characteristics zoomx = false; // no x zoom area to define zoom = false; // no zoom area to draw prevp_wxma = -1; // call to setRedSpect at next repaint repaint(); // all setUnsave(true); return; } else if (shiftx) { // X shift double cshift = bxdelta * (p_zx1 - p_zx0) / p_cwidth; for (int i = 0; i < nbxy[shiftedf]; i++) { // update shifted data file x[shiftedf][i] += cshift; } defxlim(shiftedf); // define first and last data points in window defxlim_red(shiftedf); // define first and last reduced data points in window // exp associated to this shifted data file ? if (efass2 == shiftedf) { // yes, update it for (int i = 0; i < efnbxy; i++) { efx[i] += cshift; } efdefxlim(); // define first and last exp points in window } // pred associated to this shifted data file ? if (pfass2 == shiftedf) { // yes, update it for (int i = 0; i < pfnbxy; i++) { pfx[i] += cshift; } pfdefxlim(); // define first and last pred points in window } xshifted[shiftedf] += cshift; // store actual shift value // set global X limits (including shift) sxmi[shiftedf] += cshift; sxma[shiftedf] += cshift; saxmi = sxmi[0]; saxma = sxma[0]; for (int i = 0; i < nbdf; i++) { saxmi = Math.min(sxmi[i], saxmi); saxma = Math.max(sxma[i], saxma); } // shiftx = false; // no x shift area to define shift = false; // no shift area to draw repaint(); // all setUnsave(true); return; } // Y axis if (zoomy) { // Y zoom byma = bymi + bydelta * (p_cyma - Math.min(p_zy0, p_zy1)) / p_cheight; bymi = bymi + bydelta * (p_cyma - Math.max(p_zy0, p_zy1)) / p_cheight; bydelta = byma - bymi; cadreint(bymi, bydelta, bcadreY); // resize the Y axis zoomy = false; // no y zoom area to define zoom = false; // no zoom area to draw } else if (zoompasy) { // pred-as-stick Y zoom bpasyma = bpasymi + bpasydelta * (p_cyma - Math.min(p_zy0, p_zy1)) / p_cheight; bpasymi = bpasymi + bpasydelta * (p_cyma - Math.max(p_zy0, p_zy1)) / p_cheight; bpasydelta = bpasyma - bpasymi; cadreint(bpasymi, bpasydelta, bcadrepasY); // resize the pred-as-stick Y axis zoompasy = false; // no pred-as-stick y zoom area to define zoom = false; // no zoom area to draw } else if (shifty) { // Y shift double cshift; if (ntfile[shiftedf].equals("predas")) { cshift = bpasydelta * (p_zy0 - p_zy1) / p_cheight; // p2pasY((int) p_zy1)-p2pasY((int) p_zy0) } else { cshift = bydelta * (p_zy0 - p_zy1) / p_cheight; // p2Y((int) p_zy1)-p2Y((int) p_zy0) } if (!ntfile[shiftedf].equals("peakas")) { if (yreverse[shiftedf]) { // Y reverse -> opposit sign cshift = -cshift; } } if (ntfile[shiftedf].equals("spectrum")) { // shift taken in account in y for (int i = 0; i < nbxy[shiftedf]; i++) { y[shiftedf][i] += cshift; } } yshifted[shiftedf] += cshift; // store actual shift value shifty = false; // no y shift area to define shift = false; // no shift area to draw } // redraw data area p_paintx = 0; p_painty = p_cymi - p_gap / 2; p_paintwidth = p_wxma + 1; p_paintheight = p_cheight + p_gap; myrepaint(p_paintx, p_painty, p_paintwidth, p_paintheight); setUnsave(true); } else if (predsel) { // prediction selection running p_pfx1 = p_x1; // pred selection area ending point // limited to the frame if (p_x1 < p_cxmi) { p_pfx1 = p_cxmi; } else if (p_x1 > p_cxma) { p_pfx1 = p_cxma; } if (p_pfx0 == p_pfx1) { // null selection area predsel = false; return; } selPred(Math.min(p_pfx0, p_pfx1), Math.max(p_pfx0, p_pfx1)); // show pred area and selection window if (nbixpred == 0) { // no pred point in selection area predsel = false; } else { jfsp.setContent(nbixpred, ixdebpred, ixpreds, ixexp); // set selection window content // loc-sim if (lsallowed) { // test if there is enough pred associated spectrum data points in area int i; int i0; int i1; int j = pfass2; for (i = ixdeb[j]; i < ixfin[j]; i++) { if (x[j][i] >= predselx0) { // first point found break; } } i0 = Math.min(i, nbxy[j] - 1); for (i = i0; i < nbxy[j]; i++) { if (x[j][i] > predselx1) { // last point exceeded break; } } i1 = Math.max(0, i - 1); if (i1 - i0 + 1 < 3) { // at least 3 points JOptionPane.showMessageDialog(null, "Not enough pred associated spectrum data points in selection area"); endSelPred(); } else { // set pred associated spectrum Ymin and Ymax in area // will be used to scale loc-sim to spectrum lsmis = y[j][i0]; lsmas = y[j][i0]; for (i = i0; i <= i1; i++) { double cy = y[j][i]; if (cy < lsmis) { lsmis = cy; } if (cy > lsmas) { lsmas = cy; } } jfsp.setLsBasic(predselx0, predselx1, lsallowed); // set loc-sim basics in JFSelPred } } } } } /** * Mouse moved without button pressed. *
Show its position. */ public void mouseMoved(MouseEvent mevt) { p_xmouse = mevt.getX(); // store X p_ymouse = mevt.getY(); // store Y showXY(); // show mouse position } /** * Not implemented. */ public void mouseClicked(MouseEvent mevt) { } /** * Not implemented. */ public void mouseEntered(MouseEvent mevt) { } /** * Not implemented. */ public void mouseExited(MouseEvent mevt) { } ///////////////////////////////////////////////////////////////////// // show mouse position private void showXY() { if( p_xmouse > p_cxmi && // inside frame p_xmouse < p_cxma && p_ymouse > p_epymi && p_ymouse < p_cyma ) { // X jlx.setText(FortranFormat.formFreq(p2X(p_xmouse, p_cxmi, p_cxma))); // Y if (p_ymouse > p_cymi) { // inside the data area jly.setText(FortranFormat.formInt(p2Y(p_ymouse, p_cymi, p_cyma))); // intensity in data scale if (nbpredasf != 0) { jlypredas.setText(FortranFormat.formInt(p2pasY(p_ymouse, p_cymi, p_cyma))); // intensity in // pred-as-stick scale } } else { // inside the exp/pred area jly.setText(""); jlypredas.setText(""); } } else { // ouside frame jlx.setText(""); jly.setText(""); jlypredas.setText(""); } } // select an exp private void selExp(double cp_x0) { double bxdeb; double bxfin; bxdeb = p2X((int) cp_x0-p_xhalf, p_cxmi, p_cxma); // begin choice area bxfin = p2X((int) cp_x0+p_xhalf, p_cxmi, p_cxma); // end choice area int nbep = 0; // nb of selected points int nbjmi = 0; // nb of associated jmi // select points for( int i=efixdeb; i<=efixfin; i++ ) { if( efx[i] < bxdeb ) { // before begin, next continue; } else if( efx[i] > bxfin ) { // after end, stop break; } nbep ++; // nb of selected points nbjmi += efejsynpt[i].size(); // nb of associated jmi if( nbep == 1 ) { // 1st point, set begin index ixdebexp = i; } // always set end index ixfinexp = i; } // clean the old popup menu if any if( jpmexp != null ) { jpmexp.setVisible(false); jpmexp = null; } if( nbep > mxticks ) { JOptionPane.showMessageDialog(null,"More then "+mxticks+" selected ticks"); return; } // if points are selected if( nbep >= 1 ) { // create popup menu for final choice jpmexp = new JPopupMenu(); jmiexp = new JMenuItem[nbjmi]; // for each point and each of its assignments int i; nbjmi = 0; for( int j=0; j 1 ) { // more then 1 assignment for( int l=1; l predselx1 ) { // after end, stop break; } nbixpred ++; // nb of selected points if( nbixpred == 1 ) { // 1st point, set begin index ixdebpred = i; } // always set end index // ixfinpred = i; } // if points are selected if( nbixpred > 0 ) { // create arrays ixpred = new int[nbixpred]; // selected pred index ixpreds = new int[nbixpred]; // selected pred status >> -1: nothing(---), 0: already in exp(ASG), 1: selected(SEL) for( int j=0; j= 0 ) { ixpreds[j] = 0; // status assigned } else { ixpreds[j] = -1; // status unselected } } } else { // no selected point setJta(); } myrepaint(p_paintx, p_painty, p_paintwidth, p_paintheight); // limited to pred selection area return; } ///////////////////////////////////////////////////////////////////// // define frequency and intensity global marks // ? if some mark differs // the one mark if all marks are same private void setAsog(int ci) { String gxaso; boolean plus; boolean minus; if( efnbxy != 0 ) { // if exp file ready int nbass = efejsynpt[ci].size(); // nb of assignments plus = false; minus = false; for( int i=0; i= 0 ) { // exp String cStrEXASG = efexasg[ixexp]; if( cStrEXASG.length() == 0 ) { cStrEXASG = FortranFormat.bStr(30); // EXASG = 30 char } int k = efejsynpt[ixexp].size(); for( int l=0; l= 0 ) { // pred frequency, pred intensity, EXASG, comment jta.append(" ("+FortranFormat.formFreq(pfx[ipreda])+" "+FortranFormat.formInt(pfy[ipreda])+") | "+cStrEXASG+" "+cejpt.getComm()+lnsep); found = true; } } if( ! found ) { // EXASG, comment jta.append(" | "+cStrEXASG+" "+cejpt.getComm()+lnsep); } } } // pred selected if( nbixpred > 0 ) { // type, frequency, intensity, assignment int nbs =0; for( int l=0; l show vertical bar if( evt.getSource() == jmishowbar ) { if( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) { // help PopFile.show(getName()+fisep+"jmishowbar"); return; } if( showbar ) { // hide current bar myrepaint(ip_X( xbar, p_cxmi, p_cxma ), p_epymi+p_gap/2, 1, p_cyma-p_epymi+1 ); // limited along X direction } else { showbar = true; jmihidebar.setEnabled(true); } xbar = p2X(p_xmouse, p_cxmi, p_cxma); xbar = Math.max(xbar, bxmi); xbar = Math.min(xbar, bxma); myrepaint(ip_X( xbar, p_cxmi, p_cxma ), p_epymi+p_gap/2, 1, p_cyma-p_epymi+1 ); // limited along X direction return; } // -> hide vertical bar if( evt.getSource() == jmihidebar ) { if( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) { // help PopFile.show(getName()+fisep+"jmihidebar"); return; } showbar = false; jmihidebar.setEnabled(false); myrepaint(ip_X( xbar, p_cxmi, p_cxma ), p_epymi+p_gap/2, 1, p_cyma-p_epymi+1 ); // limited along X direction return; } // -> X zoom if( evt.getSource() == jmizoomx ) { if( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) { // help PopFile.show(getName()+fisep+"jmizoomx"); return; } zoomx = true; zoom = false; return; } // -> Y zoom if( evt.getSource() == jmizoomy ) { if( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) { // help PopFile.show(getName()+fisep+"jmizoomy"); return; } zoomy = true; zoom = false; return; } // -> pred-as-stick Y zoom if( evt.getSource() == jmizoompasy ) { if( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) { // help PopFile.show(getName()+fisep+"jmizoompasy"); return; } zoompasy = true; zoom = false; return; } // -> X rescale for( int i=0; i Y rescale for( int i=0; i pred-as-stick Y rescale for( int i=0; i restore X scale if( evt.getSource() == jmirestorex ) { if( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) { // help PopFile.show(getName()+fisep+"jmirestorex"); return; } bxmi = (bxmi+bxma-axdelta)/2.; // let the window be X centered bxma = bxmi+axdelta; // full original width bxdelta = bxma-bxmi; // window frequency range setXax(); // set X axis characteristics prevp_wxma = -1; // call to setRedSpect at next repaint repaint(); // all setUnsave(true); return; } // -> restore Y scale if( evt.getSource() == jmirestorey ) { if( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) { // help PopFile.show(getName()+fisep+"jmirestorey"); return; } bymi = (bymi+byma-aydelta)/2.; // let the window be Y centered byma = bymi+aydelta; // full original height bydelta = aydelta; cadreint(bymi, bydelta, bcadreY); // resize the Y axis myrepaint(0, p_cymi-p_gap, p_wxma+1, p_cheight+3*p_gap); // Y axis and all data area setUnsave(true); return; } // -> restore pred-as-stick Y scale if( evt.getSource() == jmirestorepasy ) { if( (evt.getModifiers()&InputEvent.BUTTON3_MASK) != 0 ) { // help PopFile.show(getName()+fisep+"jmirestorepasy"); return; } // full original window bpasymi = apasymi; bpasyma = apasyma; bpasydelta = apasydelta; bcadrepasY = (double[]) acadrepasY.clone(); // set Y axis ticks myrepaint(0, p_cymi-p_gap, p_wxma+1, p_cheight+3*p_gap); // Y axis and all data area return; } // exp selection if( jpmexp != null ) { int nbjmi = 0; // number of jmi boolean found = false; // event not found for( int j=0; j=0; i-- ) { cejpt = (ExpJsynPoint)efejsynpt[ixexp].get(i); pfiexpa[cejpt.getIpred()] = -1; if( i == 0 ) { // only one assignment, empty it cejpt.setFaso(" "); cejpt.setSaso(" "); cejpt.setJsyn( ""); cejpt.setIpred(-1); efexasg[ixexp] = ""; } else { // suppress it efejsynpt[ixexp].remove(i); } } found = true; // end search } } if( found ) { jpmassign = null; // no more active setAsog(ixexp); // set global frequency and intensity marks myrepaint( p_cxmi, p_epymi, p_cwidth, p_epyma-p_epymi+1); // all exp/pred area setJta(); // update TextArea updateExp(jobplay.getExpFileName()); return; } } // set frequency or intensity mark if( jmfaso.isEnabled() && jmsaso.isEnabled() ) { boolean found = false; nbass = efejsynpt[ixexp].size(); // nb of assignments for( int i=0; i= xdeb) // cd[1] <- interval (1Exx, 2Exx ou 5Exx) // cd[2] <- nb of intervals // cd[3] <- last X tick ( <= xdeb+delta) // // we dont try to set xdeb and delta on an interval multiple // private void cadreint( double xdeb, double delta ,double[] cd) { NumberFormat nf; // to set interval DecimalFormat df; // idem String cStr; // current string int iexp; // exponent int imant; // mantissa double cxdeb; // 1st X tick double cdelta; // current range double cint; // interval int nbint; // nb of intervals inside the range double cx; // variable nf = NumberFormat.getNumberInstance(Locale.US); // ask a plain format df = (DecimalFormat)nf; // reduce to decimal format df.applyPattern(".0E00"); // define pattern cdelta = Math.abs(delta); // current range cStr = df.format(cdelta); // format it cx = Double.parseDouble(cStr); // reread if( cx < cdelta ) { // rounded up cdelta = cdelta + Double.parseDouble(".05"+cStr.substring(2)); // fit range cStr = df.format(cdelta); } iexp = Integer.parseInt(cStr.substring(3)); // exponent imant = Integer.parseInt(cStr.substring(1,2)); // mantissa // interval = 1, 2 or 5Exx if( imant > 5) { imant = 1; iexp = iexp+1; } else if (imant > 2) { imant = 5; } cint = imant*Math.pow( 10, iexp-2 ); // interval // 1st X tick long l = (long) (xdeb/cint); // nb of intervals in xdeb cx = xdeb - l*cint; // difference // xdeb positive and interval multiple ? if( xdeb > 0. ) { if( cx > 0. ) { // no l++; } } cxdeb = l*cint; // fit xdeb // nb of intervals cdelta = xdeb + Math.abs(delta) - cxdeb; nbint = (int) (cdelta/cint); // nb of intervals in range cd[0] = cxdeb; cd[1] = cint; cd[2] = nbint; cd[3] = cxdeb+nbint*cint; } ///////////////////////////////////////////////////////////////////// /** * Show a progress bar in panel. * * @param text waiting message */ public void prepThread(String text) { removeAll(); // clean setLayout(new BorderLayout()); JProgressBar progressBar = new JProgressBar(); // create a progress bar progressBar.setStringPainted(true); // with title progressBar.setString(text); // set it progressBar.setIndeterminate(true); // we dont know how long time Box box =Box.createVerticalBox(); // box box.add(Box.createVerticalStrut( (int) (this.getHeight()/2.) )); // at the middle of the window box.add(progressBar); // add JProgressBar add(box,"North"); // add box revalidate(); } /** * Redraw panel after thread. */ public void endThread() { removeAll(); // clean repaint(); // all } ///////////////////////////////////////////////////////////////////// /** * Set experiment data and redraw panel. * * @param cexpf experiment file */ @SuppressWarnings("unchecked") public void setExp(ExpFile cexpf) { efready = false; // exp file not ready expf = cexpf; // exp file efnbxy = cexpf.getNbxy(); // nb of exp data efx = new double[efnbxy]; // frequency efx = cexpf.getX(); effasog = new String[efnbxy]; // global frequency mark efy = new double[efnbxy]; // intensity efy = cexpf.getY(); efsasog = new String[efnbxy]; // global intensity mark efsdobs = new String[efnbxy]; // frequency and intensity standard deviations efsdobs = cexpf.getSdobs(); efejsynpt = new ArrayList[efnbxy]; // ArrayList of ExpJsynPoint for each data efejsynpt = cexpf.getEjsynpt(); efexasg = new String[efnbxy]; // EXASG efexasg = cexpf.getExasg(); for (int i = 0; i < efnbxy; i++) { setAsog(i); // set global frequency mark and global intensity mark } alexasg = new ArrayList(); // possible EXASG for (int i = 0; i < efnbxy; i++) { addExasg(efexasg[i]); } addExasg(PanAff.EXASG_DEFAULT); // default SPVIEW EXASG 30 char. setDefexasg(PanAff.EXASG_DEFAULT); efdefxlim(); // define first and last exp points in window epLink(); // link exp and pred through assignments efready = true; // exp file ready myrepaint((int) p_cxmi, p_epymi, (int) p_cwidth, p_yatma - p_epymi + 1); // all exp area } /** * Set prediction data and redraw panel. * * @param cpredf prediction file */ public void setPred(PredFile cpredf) { pfready = false; // pred file NOT ready pfnbxy = cpredf.getNbxy(); // nb of pred data pfx = new double[pfnbxy]; // frequency pfx = cpredf.getX(); pfy = new double[pfnbxy]; // intensity pfy = cpredf.getY(); pfj = new int[pfnbxy]; // J inf pfj = cpredf.getJinf(); pfjsyn = new String[pfnbxy]; // assignment pfjsyn = cpredf.getJsyn(); pfiexpa = new int[pfnbxy]; // index of assigned exp pfdefxlim(); // define first and last pred points in window if( efnbxy != 0 ) { // reload exp data (may be reduced) expf.read(); setExp(expf); } else { epLink(); // link exp and pred through assignments } jfsp = new JFSelPred(this, (int) (this.getLocationOnScreen().getX()+.75*(p_cxma-p_cxmi)), (int) (this.getLocationOnScreen().getY()+p_epyma+10), pfx, pfy, pfjsyn ); ixpredable = -1; // NO current selectable pred pfready = true; // pred file ready myrepaint( (int) p_cxmi, p_yprmi, (int) p_cwidth, p_yprma-p_yprmi+1); // all pred area } /** * Set experiment associated to a data file. * * @param cdf index of the data file */ public String expAss2(int cdf) { if( cdf > nbdf-1 ) { // bad index return "!!! index out of bounds in PanAff.expAss2 ("+cdf+")."; } if( cdf >= 0 && cdf == pfass2 ) { // the same file can't be associated to exp AND pred return "This data file is already associated to prediction"; } if( efass2 >= 0 ) { // already associated, unshift if necessary if( xshifted[efass2] != 0. ) { for( int i=0; i= 0 ) { // not associated to null // shift if necessary if( xshifted[efass2] != 0. ) { for( int i=0; i nbdf-1 ) { // bad index return "!!! index out of bounds in PanAff.predAss2 ("+cdf+")."; } if( cdf >= 0 && cdf == efass2 ) { // the same file can't be associated to exp AND pred return "This data file is already associated to experiment"; } if( pfass2 >= 0 ) { // already associated, unshift if necessary if( xshifted[pfass2] != 0. ) { for( int i=0; i= 0 ) { // not associated to null // shift if necessary if( xshifted[pfass2] != 0. ) { for( int i=0; i cyma ) { cyma = y[nbdf][i]; // highest intensity } } if( ! ntfile[nbdf].equals("spectrum") ) { // stick files, 0. has to be in cymi = Math.min(cymi,0.); cyma = Math.max(cyma,0.); } // set global limits for pred-as-stick and others if( nbdf == 0 ) { // 1st data file (can't be pred-as-stick) axmi = cxmi; axma = cxma; aymi = cymi; ayma = cyma; apasyma = 0.; // dummy default value, will be set by 1st pred-as-stick file load saxmi = axmi; saxma = axma; } else { axmi = Math.min(axmi, cxmi); axma = Math.max(axma, cxma); if( ntfile[nbdf].equals("predas") ) { // pred-as-stick have their own Y settings apasymi = 0.; // base value apasyma = Math.max(apasyma, cyma); // max value apasydelta = apasyma; // max range apasyrev = apasyma; // reverse value cadreint(apasymi, apasydelta, acadrepasY); // set pred-as-stick Y axis tics nbpredasf ++; // nb of pred-as-stick files loaded // allow pred-as-stick menus jmizoompasy.setEnabled(true); jmrescalepasy.setEnabled(true); jmirestorepasy.setEnabled(true); } else { aymi = Math.min(aymi, cymi); ayma = Math.max(ayma, cyma); } } axdelta = axma-axmi; cadreint(axmi, axdelta, acadreX); aydelta = ayma-aymi; ayrev = ayma+aymi; cadreint(aymi, aydelta, acadreY); // set current window limits // current window is (re)set to global limits each time a data file is loaded bxmi = axmi; // frequency mini bxma = axma; // frequency maxi bxdelta = axdelta; // frequency range bcadreX = (double[]) acadreX.clone(); // set X axis ticks if( ntfile[nbdf].equals("predas") ) { // pred-as-stick are specifically involved in Y settings bpasymi = apasymi; // pred-as-stick intensity mini bpasyma = apasyma; // pred-as-stick intensity maxi bpasydelta = apasydelta; // pred-as-stick intensity range bcadrepasY = (double[]) acadrepasY.clone(); // set pred-as-stick Y axis ticks } else { bymi = aymi; // intensity mini byma = ayma; // intensity maxi bydelta = aydelta; // intensity range bcadreY = (double[]) acadreY.clone(); // set Y axis ticks } for( int i=0; i<=nbdf; i++ ) { // for each data file ixdeb[i] = 0; // first data point in window ixfin[i] = nbxy[i]-1; // last data point in window show[nbdf] = true; // show data } // set global X limits (including shift) sxmi[nbdf] = cxmi; sxma[nbdf] = cxma; // nbdf++; // one more data file // saxmi = sxmi[0]; saxma = sxma[0]; for( int i = 0; i= 0) { cshift = xshifted[pfass2]; // current shift if (cshift != 0.) { for (int i = 0; i < pfnbxy; i++) { // update shifted data pfx[i] += cshift; } } } pfdefxlim(); // define first and last data points in window prevp_wxma = -1; // call to setRedSpect at next repaint } ///////////////////////////////////////////////////////////////////// /** * get/set the index of the color to associate to prediction file * @since SPVIEW2 */ public void setPfass2(int val) { pfass2 = val; } public int getPfass2() { int indexColor; indexColor = pfass2; return indexColor; } /** * get/set the index of the color to associate to prediction file * @since SPVIEW2 */ public void setEfass2(int val) { efass2 = val; } public int getEfass2() { int indexColor; indexColor = efass2; return indexColor; } ///////////////////////////////////////////////////////////////////// /** * Shift drawing one interval down along Y axis. */ public void jbyplus() { if( nbdf == 0 ) { // no data file return; } bymi += bcadreY[1]; // one interval byma = bymi+bydelta; // current height cadreint(bymi, bydelta, bcadreY); // reset Y axis ticks myrepaint(0, p_cymi-p_gap, p_wxma+1, p_cheight+3*p_gap); // Y axis and all data area } /** * Center drawing along Y axis. */ public void jbyegal() { if( nbdf == 0 ) { // no data file return; } bymi = (aymi+ayma)/2.-bydelta/2.; // center byma = bymi+bydelta; // current height cadreint(bymi, bydelta, bcadreY); // reset Y axis ticks myrepaint(0, p_cymi-p_gap, p_wxma+1, p_cheight+3*p_gap); // Y axis and all data area } /** * Shift drawing one interval up along Y axis. */ public void jbymoins() { if( nbdf == 0 ) { // no data file return; } bymi -= bcadreY[1]; // one interval byma = bymi+bydelta; // current height cadreint(bymi, bydelta, bcadreY); // reset Y axis ticks myrepaint(0, p_cymi-p_gap, p_wxma+1, p_cheight+3*p_gap); // Y axis and all data area } /** * Shift drawing at the beginning of X axis. */ public void jbxpipeinf() { if( nbdf == 0 ) { // no data file return; } // start global centered then simulate << button to find beginning bxmi = (axmi+axma)/2.-bxdelta/2.; while( bxmi > saxmi ) { bxmi -= bxdelta; } bxma = bxmi+bxdelta; // current width setXax(); // set X axis characteristics for( int i=0; i> button to find end bxma = (axmi+axma)/2.+bxdelta/2.; while( bxma < saxma ) { bxma += bxdelta; } bxmi = bxma - bxdelta; // current width setXax(); // set X axis characteristics for( int i=0; i= bxmi ) { // first point found break; } } ixdeb[cj] = Math.min(i,nbxy[cj]-1); // in array for( i=ixdeb[cj]; i bxma ) { // last point exceeded break; } } ixfin[cj] = Math.max(0,i-1); // at max last data point if( ntfile[cj].equals("spectrum") ) { // one more point at each end ixdeb[cj] = Math.max(0, ixdeb[cj]-1); ixfin[cj] = Math.min(ixfin[cj]+1, nbxy[cj]-1 ); } } // define first and last reduced spectrum data points in window private void defxlim_red(int cj) { int i; if( use_red[cj] ) { for( i=0; i= bxmi ) { // first point found break; } } ixdeb_red[cj] = Math.min(i,nbxy_red[cj]-1); // at least first data point for( i=ixdeb_red[cj]; i bxma ) { // last point exceeded break; } } ixfin_red[cj] = Math.max(0,i-1); // at max last data point if( ntfile[cj].equals("spectrum") ) { // one more point at each end ixdeb_red[cj] = Math.max(0, ixdeb_red[cj]-1); // ATTENTION : ceci ne represente qu'une partie du pixel precedent ixfin_red[cj] = Math.min(ixfin_red[cj]+1, nbxy_red[cj]-1 ); // ATTENTION : ceci ne represente qu'une partie du pixel suivant } } } // define first and last exp points in window private void efdefxlim() { if( efnbxy != 0 ) { // exp file loaded if( nbdf == 0 ) { // no data file -> all points efixdeb = 0; efixfin = efnbxy-1; } else { int j; for( j=0; j= bxmi ) { // first point found break; } } efixdeb = Math.min(j,efnbxy-1); // at max last exp point for( j=efixdeb; j bxma ) { // last point exceeded break; } } if( j == efnbxy ) { efixfin = efnbxy-1; // in array } else { efixfin = Math.max(0,j-1); // at max last exp point } } } } // define first and last pred points in window private void pfdefxlim() { if( pfnbxy != 0 ) { if( nbdf == 0 ) { // no data file -> all points pfixdeb = 0; pfixfin = pfnbxy-1; } else { int j; for( j=0; j= bxmi ) { // first point found break; } } pfixdeb = Math.min(j,pfnbxy-1); // at max last pred point for( j=pfixdeb; j bxma ) { // last point exceeded break; } } if( j == pfnbxy ) { pfixfin = pfnbxy-1; // in array } else { pfixfin = Math.max(0,j-1); // at max last pred point } } } } ///////////////////////////////////////////////////////////////////// /** * Set/unset data showable. * * @param cdf data file index * @param cbool show value */ public void setShow(int cdf, boolean cbool) { if( (cdf < 0) || (cdf > (nbdf-1)) ) { System.out.println("!!! index out of bounds in PanAff.setShow ("+cdf+")"); return; } show[cdf] = cbool; myrepaint( p_cxmi, p_cymi, p_cwidth, p_cheight); // data area } /** * Reverse Y data reverse state. * * @param cdf data file index */ public void yReverse(int cdf) { if( (cdf < 0) || (cdf > (nbdf-1)) ) { System.out.println("!!! index out of bounds in PanAff.yReverse ("+cdf+")"); return; } yreverse[cdf] = ! yreverse[cdf]; myrepaint( p_cxmi, p_cymi, p_cwidth, p_cheight); // data area } /** * Ask to shift X data. * * @param cdf data file index */ public void xShift(int cdf) { if( (cdf < 0) || (cdf > (nbdf-1)) ) { System.out.println("!!! index out of bounds in PanAff.xShift ("+cdf+")"); return; } shiftedf = cdf; shiftx = true; } /** * Get current X shift. * * @param cdf data file index */ public double getXShift(int cdf) { if( (cdf < 0) || (cdf > (nbdf-1)) ) { System.out.println("!!! index out of bounds in PanAff.getXShift ("+cdf+")"); return 0.; } return xshifted[cdf]; } /** * Unshift X data to original position. * * @param cdf data file index */ public void xUnshift(int cdf) { if( (cdf < 0) || (cdf > (nbdf-1)) ) { System.out.println("!!! index out of bounds in PanAff.xUnshift ("+cdf+")"); return; } xUnshiftLoc(cdf); myrepaint( p_cxmi, 0, p_cwidth, p_cyma+1); // exp/pred/data area } // local method to unshift X data to original position private void xUnshiftLoc(int cdf) { for( int i=0; i (nbdf-1)) ) { System.out.println("!!! index out of bounds in PanAff.yShift ("+cdf+")"); return; } shiftedf = cdf; shifty = true; } /** * Set current Y shift to the value given in argument * @param xshift * @param cdf * * @since SPVIEW2 */ public void setXShift(double xshift, int cdf) { xshifted[cdf] = xshift; for (int i = 0; i < nbxy[cdf]; i++) { // for each data point x[cdf][i] += xshifted[cdf]; } } /** * Set current Y shift to the value given in argument * @param yshift * @param cdf * * @since SPVIEW2 */ public void setYShift(double yshift, int cdf) { yshifted[cdf] = yshift; for (int i = 0; i < nbxy[cdf]; i++) { // for each data point y[cdf][i] += yshifted[cdf]; } } /** * Set current X zoom to the value given in argument * * @param boundMin * @param boundMax * * @since SPVIEW2 */ public void setXZoom(double boundMin, double boundMax) { // X zoom bxma = Math.max(boundMin, boundMax); bxmi = Math.min(boundMin, boundMax); bxdelta = bxma - bxmi; // window frequency range setXax(); // set X axis characteristics zoomx = false; // no x zoom area to define zoom = false; // no zoom area to draw prevp_wxma = -1; // call to setRedSpect at next repaint repaint(); // all return; } /** * Set current Y zoom to the value given in argument * * @param boundMin * @param boundMax * * @since SPVIEW2 */ public void setYZoom(double boundMin, double boundMax) { byma = Math.max(boundMin, boundMax); bymi = Math.min(boundMin, boundMax); bydelta = byma-bymi; cadreint(bymi, bydelta, bcadreY); // resize the Y axis zoomy = false; // no y zoom area to define zoom = false; } /** * Get p_zx0 value of X zoom. * * @since SPVIEW2 */ public Double getbxmi() { return bxmi; } /** * Get p_zx1 value of X zoom. * * @since SPVIEW2 */ public Double getbxma() { return bxma; } /** * Get p_zy0 value of Y zoom. * * @since SPVIEW2 */ public Double getbymi() { return bymi; } /** * Get p_zy1 value of Y zoom. * * @since SPVIEW2 */ public Double getbyma() { return byma; } /** * Get current Y shift. * @param cdf * * @param cdf data file index */ public double getYShift(int cdf) { if( (cdf < 0) || (cdf > (nbdf-1)) ) { System.out.println("!!! index out of bounds in PanAff.getYShift ("+cdf+")"); return 0.; } return yshifted[cdf]; } /** * Unshift Y data original position. * * @param cdf data file index */ public void yUnshift(int cdf) { if( (cdf < 0) || (cdf > (nbdf-1)) ) { System.out.println("!!! index out of bounds in PanAff.yUnshift ("+cdf+")"); return; } yUnshiftLoc(cdf); myrepaint( p_cxmi, p_cymi, p_cwidth, p_cheight); // data area } // local method to unshift Y data to original position private void yUnshiftLoc(int cdf) { if( ntfile[cdf].equals("spectrum") ) { // only for spectrum data file for( int i=0; i= 0) { // found int pjpInd = pjp[k].getInd(); cejpt.setIpred(pjpInd); // index of assigned pred pfiexpa[pjpInd] = i; // index of assigned exp } else { // not found if( nbass == 1 ) { // only one assignment, empty it cejpt.setFaso(" "); cejpt.setSaso(" "); cejpt.setJsyn(""); cejpt.setIpred(-1); efexasg[i] = ""; } else { // suppress it efejsynpt[i].remove(j); again = true; // re-do the loop } nbrem++; // nb of removed ExpJsynPoint break; // now } } } } } setJta(); // update TextArea if (nbrem != 0) { int res = JOptionPane.showConfirmDialog( null, nbrem + " assignments not predicted are ignored." + lnsep + "Do you want to update " + jobplay.getExpFileName() + "?", "Remove not predicted lines", JOptionPane.YES_NO_OPTION); if (res == JOptionPane.YES_OPTION) { updateExp(jobplay.getExpFileName()); /* file has been updated, we need to update display */ setExp(expf); } } } } } // create assignment management popup menu private boolean setJpmAssign() { int nbass; // nb of assignments if (!efready) { // no exp file return false; } jpmassign = new JPopupMenu(); // unselect exp jmiunselexp = new JMenuItem("Unselect exp"); if( ixexp < 0 ) { // no exp selected jmiunselexp.setEnabled(false); } else { jmiunselexp.addActionListener(this); } jpmassign.add(jmiunselexp); jpmassign.addSeparator(); // remove an assignment jmunass = new JMenu("Unassign"); if( ixexp < 0 ) { // no exp selected jmunass.setEnabled(false); } else { nbass = efejsynpt[ixexp].size(); cejpt = (ExpJsynPoint)efejsynpt[ixexp].get(0); if( cejpt.getJsyn().length() == 0 ) { // empty assignment jmunass.setEnabled(false); } else { jmiunass = new JMenuItem[nbass]; // a jmi for each assignment for( int i=0; i1 ) { // more then one assignment aejpt = new ExpJsynPoint[nbass]; // array for( int k=0; k(); for( int k=0; k0; l-- ) { if( cStr.charAt(l-1) != ' ' ) { break; } } out1.println( cStr.substring(0, l) ); // without extra spaces } } } catch (IOException ioe) { // IO error JOptionPane.showMessageDialog(null, "IO error while writing file" + lnsep + nsavexp + lnsep + ioe); return false; } finally { // close the file if (out1 != null) { out1.close(); if (out1.checkError()) { JOptionPane.showMessageDialog(null, "PrintWriter error while creating exp file" + lnsep + nsavexp); return false; } } } return true; } /** * Save updated experiment file
* following FORMAT 3000 of eq_tds.f * * @since SPVIEW2 Or update current experiment file */ public void saveExp() { if (!efready) { // no exp file loaded return; } // choose output file JFileChooser jfcfile = new JFileChooser(workd); // default = working directory jfcfile.setSize(400, 300); jfcfile.setFileSelectionMode(JFileChooser.FILES_ONLY); // only files jfcfile.setDialogTitle("Define the name of the saved experiment file"); Container parent = this.getParent(); int choice = jfcfile.showDialog(parent, "Select"); // Dialog, Select if (choice == JFileChooser.APPROVE_OPTION) { nsavexp = jfcfile.getSelectedFile().getAbsolutePath(); // full file name if (updateExp(nsavexp)) { // finished JOptionPane.showMessageDialog(null, "Assignment file" + lnsep + nsavexp + lnsep + "is saved"); } } } /** * Add assignment(s) to selected exp. */ public void addAss2exp(boolean freq) { // add assignment(s) for (int k = 0; k < nbixpred; k++) { if (ixpreds[k] == 1) { // pred selected int cixpred = ixpred[k]; // add it pfiexpa[cixpred] = ixexp; // index of assigned exp int nbass = efejsynpt[ixexp].size(); // number of assignments cejpt = (ExpJsynPoint) efejsynpt[ixexp].get(0); if (nbass == 1 && cejpt.getJsyn().length() == 0) { // the only assignment is empty, replace it if (freq) { // frequency cejpt.setFaso("+"); cejpt.setSaso(" "); } else { // intensity cejpt.setFaso(" "); cejpt.setSaso("+"); } cejpt.setJsyn(pfjsyn[cixpred]); cejpt.setIpred(cixpred); efexasg[ixexp] = defexasg; // 1st one -> default EXASG } else { // add one if (freq) { // frequency efejsynpt[ixexp].add(new ExpJsynPoint("+", " ", pfjsyn[cixpred], cixpred, "")); } else { // intensity efejsynpt[ixexp].add(new ExpJsynPoint(" ", "+", pfjsyn[cixpred], cixpred, "")); } sortEfejsynpt(ixexp); // sort -> easier to read in TextArea } } } setAsog(ixexp); // set global frequency and intensity marks myrepaint(ip_X(efx[ixexp], p_cxmi, p_cxma) - p_ovray, p_epymi, 2 * p_ovray, p_yatma - p_epymi + 1); // exp marks // area endSelPred(); // end pred selection updateExp(jobplay.getExpFileName()); return; } /** * End pred selection. */ public void endSelPred() { if (predsel) { // pred selection running predsel = false; // No pred selection running nbixpred = 0; // NO pred selected jfsp.setContent(nbixpred, ixdebpred, ixpreds, ixexp); // set pred selection window content setLocSim(false); // NO loc-sim drawPredSel(); // draw pred selection area setJta(); // update TextArea } return; } /** * Draw pred selection area */ public void drawPredSel() { myrepaint( ip_X(predselx0, p_cxmi, p_cxma)-p_ovray, p_yprmi, ip_X(predselx1, p_cxmi, p_cxma)-ip_X(predselx0, p_cxmi, p_cxma)+p_ovwidth+1, p_yprma-p_yprmi+1); // pred selection area } /** * set current selectable pred. */ public void setPredable(int cixpredable) { ixpredable = cixpredable; drawPredSel(); } /** * Set local simulation spectrum. */ public void setLocSim( boolean clocsim ) { boolean prevlocsim = locsim; // previous locsim int lslen = 0; // nb of loc-sim points int p_prevx0 = 0; // pixel starting point of previous loc-sim int p_prevx1 = 0; // pixel ending point of previous loc-sim if( prevlocsim ) { // set previous loc-sim limits p_prevx0 = ip_X(lsx[0], p_cxmi, p_cxma); p_prevx1 = ip_X(lsx[lsx.length-1], p_cxmi, p_cxma); } locsim = clocsim; if( locsim ) { // get points and show them lsx = jfsp.getLsx(); lsy = jfsp.getLsy(); lslen = lsx.length; if( lslen < 2 ) { // not enough points locsim = false; } else { // rescale to fit spectrum for( int i=0; i lsma ) { lsma = lsy[i]; } } return; } // Set reduced spectra for speeding draw private void setRedSpect() { if( nbdf == 0 ) { // no data file return; } int[] ci_red = new int[0]; // index of reduced data int ind0; // running index : original (non reduced) data int ip_0; // pixel position of running original point int ind_red; // running index : reduced data int ciymi; int ciyma; double cymi; // Y min of current pixel area double cyma; // Y max of current pixel area double cy; // running y int nbred; // original nb of data points for one pixel width area for( int j=0; j 4 ) { // do we have to reduce ? // reduction use_red[j] = true; ci_red = new int[nbxy[j]]; // define array ind0 = 0; // index of 1st original point of 1st pixel area ip_0 = ip_X(x[j][ind0], p_cxmi, p_cxma); // pixel value of this pixel area ciymi = ind0; cymi = y[j][ciymi]; // Y min of this pixel area ciyma = ciymi; cyma = y[j][ciyma]; // Y max of this pixel area ind_red = 0; // index of 1st reduced point for( int i=0; i cyma ) { // test max ciyma = i; cyma = cy; } } } nbxy_red[j] = ind_red; // effective nb of reduced points i_red[j] = new int[nbxy_red[j]]; System.arraycopy(ci_red,0,i_red[j],0,nbxy_red[j]); defxlim_red(j); // set 1st and last points in data area } } } } private void setUnsave(boolean unsave) { if (this.jobplay.getProject() != null) { this.jobplay.getProject().setUnsave(true); } } } resources/pixmaps/play.png000644 001750 001750 00000002436 13544613421 016542 0ustar00cyrilcyril000000 000000 PNG  IHDR szzIDATXWMoTU~s?f:ҺnHBM\c4lI XH ;$6YIv3˝̤ss1Rj,ɣ$|$H\h6#E伈@xKɋɫ$l4v/NȼR-DEpιJŵ_).)Dk O+ϲ,ݎH\OFZnŰGPJgp\5ݮwa~|( _ ^$H+w!ISLn$ M18i9bܺynw|C+tֆ&w0p6mzٳgCWG؀1ל&$OϜA^9wFH$WI+d\+'h4 "D6 yIVONNӧ(#\.ZDNw12JJ(Vվ-&&&~'&7 8 dۭXD1`:(8^ZwsiEe{E"_~R09N ha(ZZ\Vj@۷J)u[7dY$InsKdY4Mjt -[\Zhvw|eّ,Pn1# cСCιS9 i)OKKK{:W̒< x."uBVwT;WQIENDB`resources/PanAff/jmisaso.html000644 001750 001750 00000000165 13544613421 017071 0ustar00cyrilcyril000000 000000

Assignment

Set intensity mark.

resources/JobPlay/jmiloadspect.html000644 001750 001750 00000000237 13544613421 020307 0ustar00cyrilcyril000000 000000

Load spectrum file

Load an XY spectrum file to plot it in the data area.

resources/PanAff/jmiunass.html000644 001750 001750 00000000251 13544613421 017251 0ustar00cyrilcyril000000 000000

Assignment

Deassociate one of the predictions from the selected experimental peak.

resources/JobPlay/jmiprint.html000644 001750 001750 00000000174 13544613421 017465 0ustar00cyrilcyril000000 000000

Print

Print data displayed at screen.

sources/org/spview/point/StickPoint.java000644 001750 001750 00000002714 13544613421 021245 0ustar00cyrilcyril000000 000000 package org.spview.point; /** * This class allows to sort stick file data. */ public class StickPoint implements Comparable { private double x; // frequency private double y; // intensity /** * Construct a new StickPoint. * * @param cx frequency * @param cy intensity */ public StickPoint(double cx, double cy) { x = cx; // frequency y = cy; // intensity } ///////////////////////////////////////////////////////////////////// /** * Get frequency. */ public double getX() { return x; } /** * Get intensity. */ public double getY() { return y; } /** * Compare frequencies only. * * @param csp the StickPoint to compare to */ public int compareTo(Object csp) { if( ! (csp instanceof StickPoint) ) { // not the right object throw new ClassCastException(); } double delta = ((StickPoint)csp).getX() - x; // compare frequencies if ( delta < 0 ) { return 1; } else if( delta > 0 ) { return -1; } return 0; // equal } } resources/JobPlay/jmireload.html000644 001750 001750 00000000161 13544613421 017573 0ustar00cyrilcyril000000 000000

Reload

Reload a data file.

resources/JFSelPred/jmipredall.html000644 001750 001750 00000000177 13544613421 020175 0ustar00cyrilcyril000000 000000

Select

Select all predictions in a list.

resources/PanAff/jmiexp.html000644 001750 001750 00000000216 13544613421 016715 0ustar00cyrilcyril000000 000000

Assignment

Select an experimental peak in a popup list.

sources/org/spview/gui/JobPlay.java000644 001750 001750 00000151431 13544613421 020152 0ustar00cyrilcyril000000 000000 package org.spview.gui; /* * Class to play with SPVIEW */ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Cursor; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; import java.awt.event.WindowAdapter; import java.awt.print.PageFormat; import java.awt.print.PrinterException; import java.awt.print.PrinterJob; import java.io.File; import java.io.IOException; import java.util.ArrayList; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JTextArea; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.WindowConstants; import javax.swing.filechooser.FileNameExtensionFilter; import javax.xml.parsers.ParserConfigurationException; import org.xml.sax.SAXException; import java.awt.Toolkit; import org.spview.filehandler.ExpFile; import org.spview.filehandler.DataFile; import org.spview.filehandler.PredFile; import org.spview.filehandler.SPVProject; import org.spview.gui.PanAff; import org.spview.residuals.ObsCalc; ///////////////////////////////////////////////////////////////////// /** * This is the master window. */ public class JobPlay extends JFrame implements ActionListener, Runnable { /** * */ private static final long serialVersionUID = -8418036777163263772L; private SPVProject project = null; private String workd; // working directory private String threadType; // dataread, expread, predread or print // menus private JMenuItem jmiexit; // Exit of FILE menu // private JMenuItem jmiloadspect; // Load spectrum of DATA menu private JMenuItem jmiloadstick; // Load stick of DATA menu private JMenuItem jmiloadpeakas; // Load peak/experiment as stick of DATA menu private JMenu jmloadpredas; // Load pred-as-stick of DATA menu private JMenuItem jmiloadtdsas; // Load pred-as-stick (TDS) of DATA menu private JMenuItem jmiloadhitras; // Load pred-as-stick (HITRAN) of DATA menu // private JMenu jmdataman; // DataManagement private JMenuItem jmiresetall; // Restore all in basic state of DATAMANAGEMENT menu private JMenu[] jmndataf; // data file names private JMenuItem[] jmishow; // Show of DATAMANAGEMENT menu private JMenuItem[] jmihide; // Hide of DATAMANAGEMENT menu private JMenuItem[] jmireload; // Reload of DATAMANAGEMENT menu private JMenuItem[] jmixshift; // X shift of DATAMANAGEMENT menu private JMenuItem[] jmixunshift; // X unshift of DATAMANAGEMENT menu private JMenuItem[] jmiyshift; // Y shift of DATAMANAGEMENT menu private JMenuItem[] jmiyunshift; // Y unshift of DATAMANAGEMENT menu private JMenuItem[] jmiyreverse; // Y reverse of DATAMANAGEMENT menu // private JMenu jmcreatepeakf; // Create peak file of ASSIGNMENT menu private JMenuItem jmicpfnone; // no default spectrum file name private JMenuItem[] jmicpf; // data file names private JMenuItem jmiloadexpf; // Load experiment file of ASSIGNMENT menu private JMenu jmloadpredf; // Load prediction file of ASSIGNMENT menu private JMenuItem jmilpTDS; // Load prediction file (TDS) of ASSIGNMENT menu private JMenuItem jmilpHITRAN; // Load prediction file (HITRAN) of ASSIGNMENT menu private JMenu jmexp2data; // Associate experiment to data of ASSIGNMENT menu private JMenuItem jmiexp2null; // Associate experiment to null of ASSIGNMENT menu private JMenuItem[] jmiexp2; // data file names private JMenu jmpred2data; // Associate prediction to data of ASSIGNMENT menu private JMenuItem jmipred2null; // Associate prediction to null of ASSIGNMENT menu private JMenuItem[] jmipred2; // data file names private JMenuItem jmisavexp; // Update experiment file of ASSIGNMENT menu // private JMenuItem jmiprint; // Print of PLOT menu // private JMenuItem jmiabout; // About SPVIEW of HELP menu // panels private JPanel pcentre; private JPanel pco; private JPanel pcc; private JPanel pccc; private JPanel pccs; private JPanel psud; // boxes and buttons private Box boxy; // box for Y buttons private JButton jbyplus; // Y + private JButton jbyegal; // Y = private JButton jbymoins; // Y - private Box boxx; // box for X buttons private JButton jbxpipeinf; // X |< private JButton jbx2inf; // X << private JButton jbx1inf; // X < private JButton jbxegal; // X = private JButton jbx1sup; // X > private JButton jbx2sup; // X >> private JButton jbxpipesup; // X >| private JScrollPane jsp; // with lifts private JTextArea jta; // show selected exp/pred // labels to show mouse position private JLabel jlx; // X mouse private JLabel jly; // Y mouse private JLabel jlypredas; // Y mouse in pred-as-stick scale private JLabel cjl; // value // drawing window private PanAff panaff; private Color[] coul = { Color.BLUE, Color.RED, Color.GRAY, Color.GREEN, Color.MAGENTA, // colors choice Color.ORANGE, Color.BLACK, Color.PINK, Color.CYAN, Color.YELLOW }; private float coulength; // size of color array // data files private DataFile[] dataf; // data file private String[] ndataf; // data file name private int nbdf; // nb of data files private int mxnbdf = 20; // max nb of data files private int relfi; // reloadable file index // experiment file private ExpFile expf; // experiment file private String nexpf; // name of experiment file // prediction file private PredFile predf; // prediction file private String npredf; // name of prediction file private String str; private String lnsep; // line separator private String fisep; // file separator private Font mono14; // Monospaced 14 font private JMenuItem jmiopenproject; private JMenuItem jmisaveproject; private String spvFileName = null; // path file name private ArrayList pathListToSave = new ArrayList<>(); // List of paths of the project to save private ArrayList typeOfFileToSave = new ArrayList<>(); // Contains all attribute-types of DataFiles in order to save private ArrayList AttributeOfFileToSave = new ArrayList<>(); // Contains attribute "dataread" to // differentiate them from predread or expread // Prediction files private String typeOfPredFile; // Contains the type of the PrefFile loaded private String attributeOfPredFile; // Contains "predread", if one has been loaded private String pathOfPredfileToSave; // Contains the path of the prediction file loaded private int PredfileToSave = 0; // Indicates if there is a prediction file to save or not // Experimental files private String typeOfExpFile; // Contains the type of the ExpFile loaded private String attributeOfExpFile; // Contains "expread", if one has been loaded private String pathOfExpfileToSave; // Contains the path of the experimental file loaded private int ExpfileToSave = 0; // Indicates if there is an experimental file to save or not // Y reverse private ArrayList yReverseElementToSave = new ArrayList<>(); // Contains information about "y-reverse" state // hide private ArrayList hideElementToSave = new ArrayList<>(); private JMenuItem jmixobscalc; private JMenuItem jmiyobscalc; private JMenuItem jmilpreload; private JLabel expFileLabel; private JMenuItem jmicloseproject; private JSeparator datamanSeparator; ///////////////////////////////////////////////////////////////////// /** * Construct a new JobPlay. */ public JobPlay() { super("Managing SPVIEW"); // main window setIconImage(Toolkit.getDefaultToolkit().getImage(JobPlay.class.getResource("/pixmaps/spview.png"))); setName("JobPlay"); // for help files setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { // clean end public void windowClosing(WindowEvent e) { closeApplication(); } }); workd = System.getProperty("user.dir"); // working directory lnsep = System.getProperty("line.separator"); fisep = System.getProperty("file.separator"); mono14 = new Font("Monospaced", Font.PLAIN, 14); // menu bar buildMenu(); // build menu bar getContentPane().setLayout(new BorderLayout()); // center panel for drawing pcentre = new JPanel(new BorderLayout()); pco = new JPanel(new BorderLayout()); pcc = new JPanel(new BorderLayout()); pccs = new JPanel(new GridLayout(2, 0, 5, 5)); pccc = new JPanel(new BorderLayout()); pcc.add(pccc, "Center"); pcc.add(pccs, "South"); pcentre.add(pco, "West"); pcentre.add(pcc, "Center"); // Y buttons boxy = Box.createVerticalBox(); jbyplus = new JButton(""); jbyplus.setContentAreaFilled(false); jbyplus.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); jbyplus.setBorder(null); jbyplus.setIcon(new ImageIcon(JobPlay.class.getResource("/pixmaps/up.png"))); jbyplus.setFont(new Font("Monospaced", Font.BOLD, 12)); jbyplus.setToolTipText("Shifts drawing one interval down along Y axis"); jbyplus.addActionListener(this); jbyegal = new JButton(""); jbyegal.setContentAreaFilled(false); jbyegal.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); jbyegal.setBorder(null); jbyegal.setIcon(new ImageIcon(JobPlay.class.getResource("/pixmaps/equal.png"))); jbyegal.setFont(new Font("Monospaced", Font.BOLD, 12)); jbyegal.setToolTipText("Centers drawing along Y axis"); jbyegal.addActionListener(this); jbymoins = new JButton(""); jbymoins.setContentAreaFilled(false); jbymoins.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); jbymoins.setBorder(null); jbymoins.setIcon(new ImageIcon(JobPlay.class.getResource("/pixmaps/bottom.png"))); jbymoins.setFont(new Font("Monospaced", Font.BOLD, 12)); jbymoins.setToolTipText("Shifts drawing one interval up along Y axis"); jbymoins.addActionListener(this); boxy.add(Box.createVerticalGlue()); boxy.add(jbyplus); boxy.add(Box.createVerticalStrut(50)); boxy.add(jbyegal); boxy.add(Box.createVerticalStrut(50)); boxy.add(jbymoins); boxy.add(Box.createVerticalGlue()); pco.add(boxy); // mouse position jlx = new JLabel(); jlx.setFont(new Font("Monospaced", Font.PLAIN, 14)); jly = new JLabel(); jly.setFont(new Font("Monospaced", Font.PLAIN, 14)); jlypredas = new JLabel(); jlypredas.setFont(new Font("Monospaced", Font.PLAIN, 14)); JPanel pcs = new JPanel(new GridLayout(0, 7, 5, 5)); pcs.setBackground(Color.WHITE); cjl = new JLabel("x =", null, JLabel.RIGHT); cjl.setFont(new Font("Monospaced", Font.PLAIN, 14)); pcs.add(cjl); pcs.add(jlx); cjl = new JLabel("y =", null, JLabel.RIGHT); cjl.setFont(new Font("Monospaced", Font.PLAIN, 14)); pcs.add(cjl); pcs.add(jly); cjl = new JLabel("", null, JLabel.RIGHT); cjl.setFont(new Font("Monospaced", Font.PLAIN, 14)); pcs.add(cjl); pcs.add(jlypredas); pcs.setBorder(BorderFactory.createLineBorder(Color.BLACK)); pccs.add(pcs); // X buttons boxx = Box.createHorizontalBox(); jbxpipeinf = new JButton(""); jbxpipeinf.setContentAreaFilled(false); jbxpipeinf.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); jbxpipeinf.setBorder(null); jbxpipeinf.setIcon(new ImageIcon(JobPlay.class.getResource("/pixmaps/beg.png"))); jbxpipeinf.setToolTipText("Shifts drawing at the beginning of the X axis"); jbxpipeinf.addActionListener(this); jbx2inf = new JButton(""); jbx2inf.setContentAreaFilled(false); jbx2inf.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); jbx2inf.setBorder(null); jbx2inf.setIcon(new ImageIcon(JobPlay.class.getResource("/pixmaps/backward.png"))); jbx2inf.setToolTipText("Shifts drawing one screen right along X axis"); jbx2inf.addActionListener(this); jbx1inf = new JButton(""); jbx1inf.setContentAreaFilled(false); jbx1inf.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); jbx1inf.setBorder(null); jbx1inf.setIcon(new ImageIcon(JobPlay.class.getResource("/pixmaps/playback.png"))); jbx1inf.setToolTipText("Shifts drawing one interval right along X axis"); jbx1inf.addActionListener(this); jbxegal = new JButton(""); jbxegal.setContentAreaFilled(false); jbxegal.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); jbxegal.setBorder(null); jbxegal.setIcon(new ImageIcon(JobPlay.class.getResource("/pixmaps/pause.png"))); jbxegal.setToolTipText("Centers drawing along X axis"); jbxegal.addActionListener(this); jbx1sup = new JButton(""); jbx1sup.setContentAreaFilled(false); jbx1sup.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); jbx1sup.setBorder(null); jbx1sup.setIcon(new ImageIcon(JobPlay.class.getResource("/pixmaps/play.png"))); jbx1sup.setToolTipText("Shifts drawing one interval left along X axis"); jbx1sup.addActionListener(this); jbx2sup = new JButton(""); jbx2sup.setContentAreaFilled(false); jbx2sup.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); jbx2sup.setBorder(null); jbx2sup.setIcon(new ImageIcon(JobPlay.class.getResource("/pixmaps/forward.png"))); jbx2sup.setToolTipText("Shifts drawing one screen left along X axis"); jbx2sup.addActionListener(this); jbxpipesup = new JButton(""); jbxpipesup.setContentAreaFilled(false); jbxpipesup.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); jbxpipesup.setBorder(null); jbxpipesup.setIcon(new ImageIcon(JobPlay.class.getResource("/pixmaps/end.png"))); jbxpipesup.setToolTipText("Shifts drawing at the end of the X axis"); jbxpipesup.addActionListener(this); boxx.add(Box.createHorizontalGlue()); boxx.add(jbxpipeinf); boxx.add(Box.createHorizontalStrut(25)); boxx.add(jbx2inf); boxx.add(Box.createHorizontalStrut(25)); boxx.add(jbx1inf); boxx.add(Box.createHorizontalStrut(25)); boxx.add(jbxegal); boxx.add(Box.createHorizontalStrut(25)); boxx.add(jbx1sup); boxx.add(Box.createHorizontalStrut(25)); boxx.add(jbx2sup); boxx.add(Box.createHorizontalStrut(25)); boxx.add(jbxpipesup); boxx.add(Box.createHorizontalStrut(25)); boxx.add(Box.createHorizontalGlue()); pccs.add(boxx); // TextArea for selected exp/pred characteristics jta = new JTextArea(); panaff = new PanAff(this, mxnbdf, coul, jta, jlx, jly, jlypredas); expFileLabel = new JLabel("", null, SwingConstants.TRAILING); expFileLabel.setFont(new Font("Monospaced", Font.PLAIN, 14)); pcs.add(expFileLabel); panaff.setBackground(Color.WHITE); pccc.add(panaff, "Center"); pccc.setBorder(BorderFactory.createLineBorder(Color.BLACK)); // south panel contains TextArea psud = new JPanel(new GridLayout(1, 0, 5, 5)); jta.setBackground(Color.BLACK); jta.setForeground(Color.WHITE); jta.setEditable(false); // not editable jta.setFont(mono14); jta.setLineWrap(false); // no line wrap jta.setRows(8); // nb of lines jsp = new JScrollPane(jta); // with lifts psud.add(jsp); // insert panels getContentPane().add(pcentre, "Center"); getContentPane().add(psud, "South"); pack(); // initialisation dataf = new DataFile[mxnbdf]; // data file ndataf = new String[mxnbdf]; // name of data file nbdf = 0; // nb of data files jmndataf = new JMenu[mxnbdf]; // data file menus jmishow = new JMenuItem[mxnbdf]; // show jmihide = new JMenuItem[mxnbdf]; // hide jmireload = new JMenuItem[mxnbdf]; // reload jmixshift = new JMenuItem[mxnbdf]; // X shift jmixunshift = new JMenuItem[mxnbdf]; // X unshift jmiyshift = new JMenuItem[mxnbdf]; // Y shift jmiyunshift = new JMenuItem[mxnbdf]; // Y unshift jmiyreverse = new JMenuItem[mxnbdf]; // Y reverse jmicpf = new JMenuItem[mxnbdf]; // data file names jmiexp2 = new JMenuItem[mxnbdf]; // exp associated to data jmipred2 = new JMenuItem[mxnbdf]; // pred associated to data coulength = coul.length; // size of color array } ///////////////////////////////////////////////////////////////////// // build the menu bar private void buildMenu() { // menu bar JMenuBar jmb = new JMenuBar(); // FILE JMenu jmfile = new JMenu("File"); // DATA JMenu jmload = new JMenu("Data"); jmiloadspect = new JMenuItem("Load spectrum file"); jmiloadspect.addActionListener(this); jmiloadstick = new JMenuItem("Load stick file"); jmiloadstick.addActionListener(this); jmiloadpeakas = new JMenuItem("Load (as stick) peak/experiment file"); jmiloadpeakas.addActionListener(this); jmloadpredas = new JMenu("Load (as stick) prediction file"); jmiloadtdsas = new JMenuItem("TDS format"); jmiloadtdsas.setEnabled(false); jmiloadtdsas.addActionListener(this); jmloadpredas.add(jmiloadtdsas); jmiloadhitras = new JMenuItem("HITRAN format"); jmiloadhitras.setEnabled(false); jmiloadhitras.addActionListener(this); jmloadpredas.add(jmiloadhitras); jmload.add(jmiloadspect); jmload.addSeparator(); jmload.add(jmiloadstick); jmload.add(jmiloadpeakas); jmload.addSeparator(); jmload.add(jmloadpredas); // DATAMANAGEMENT jmdataman = new JMenu("DataManagement"); jmiresetall = new JMenuItem("Restore all in basic state"); jmiresetall.addActionListener(this); jmdataman.add(jmiresetall); // ASSIGNMENT JMenu jmassign = new JMenu("Assignment"); jmcreatepeakf = new JMenu("Create peak file from spectrum file"); jmicpfnone = new JMenuItem("Unknown default spectrum file name"); jmicpfnone.addActionListener(this); jmcreatepeakf.add(jmicpfnone); jmiloadexpf = new JMenuItem("Load peak/experiment file"); jmiloadexpf.setEnabled(false); jmiloadexpf.addActionListener(this); jmloadpredf = new JMenu("Load prediction file"); jmloadpredf.setEnabled(false); jmilpTDS = new JMenuItem("TDS format"); jmilpTDS.addActionListener(this); jmloadpredf.add(jmilpTDS); jmilpHITRAN = new JMenuItem("HITRAN format"); jmilpHITRAN.addActionListener(this); jmloadpredf.add(jmilpHITRAN); jmexp2data = new JMenu("Associate experiment to data"); jmexp2data.setEnabled(false); jmiexp2null = new JMenuItem("null"); jmiexp2null.addActionListener(this); jmexp2data.add(jmiexp2null); jmpred2data = new JMenu("Associate prediction to data"); jmpred2data.setEnabled(false); jmipred2null = new JMenuItem("null"); jmipred2null.addActionListener(this); jmpred2data.add(jmipred2null); jmisavexp = new JMenuItem("Save assignment file as..."); jmisavexp.setEnabled(false); jmisavexp.addActionListener(this); jmassign.add(jmcreatepeakf); jmassign.addSeparator(); jmassign.add(jmiloadexpf); jmassign.add(jmloadpredf); jmilpreload = new JMenuItem("Reload"); jmilpreload.addActionListener(this); jmloadpredf.addSeparator(); jmloadpredf.add(jmilpreload); jmassign.addSeparator(); jmassign.add(jmexp2data); jmassign.add(jmpred2data); jmassign.addSeparator(); jmassign.add(jmisavexp); // PLOT JMenu jmplot = new JMenu("Plot"); jmiprint = new JMenuItem("Print"); jmiprint.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); jmiprint.addActionListener(this); jmixobscalc = new JMenuItem("X Obs.-Calc."); jmplot.add(jmixobscalc); jmixobscalc.addActionListener(this); jmiyobscalc = new JMenuItem("Y Obs.-Calc."); jmplot.add(jmiyobscalc); jmiyobscalc.addActionListener(this); jmplot.addSeparator(); jmplot.add(jmiprint); // HELP JMenu jmhelp = new JMenu("Help"); jmiabout = new JMenuItem("About SPVIEW"); jmiabout.addActionListener(this); jmhelp.add(jmiabout); jmb.add(jmfile); // FILE jmiopenproject = new JMenuItem("Open Project..."); jmiopenproject.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); jmiopenproject.addActionListener(this); jmfile.add(jmiopenproject); jmfile.addSeparator(); jmicloseproject = new JMenuItem("Close Project"); jmicloseproject.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); jmicloseproject.addActionListener(this); jmfile.add(jmicloseproject); jmfile.addSeparator(); jmisaveproject = new JMenuItem("Save Project As..."); jmisaveproject.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); jmisaveproject.addActionListener(this); jmfile.add(jmisaveproject); jmfile.addSeparator(); jmiexit = new JMenuItem("Exit"); jmiexit.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask())); jmiexit.addActionListener(this); jmfile.add(jmiexit); jmb.add(jmload); jmb.add(jmdataman); jmb.add(jmassign); jmb.add(jmplot); jmb.add(jmhelp); setJMenuBar(jmb); // set menu bar } private boolean checkForSave() { if (nbdf == 0) return true; if (project == null) { project = new SPVProject(this); spvFileName = workd; project.setUnsave(true); } if (project.isUnsave()) { int n = JOptionPane.showConfirmDialog(null, "The current project is in a unsaved state, Do you want to save it?", "Project file is unsaved", JOptionPane.YES_NO_CANCEL_OPTION); if (n == JOptionPane.YES_OPTION) { project.saveSPVFile(spvFileName); } else if (n == JOptionPane.CANCEL_OPTION) { return false; } } return true; } ///////////////////////////////////////////////////////////////////// /** * Process events. */ public void actionPerformed(ActionEvent evt) { // FILE // -> Exit if (evt.getSource() == jmiexit) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(null); return; } closeApplication(); return; } // NO action while printing if (panaff.getPrinting()) { JOptionPane.showMessageDialog(null, "No action while printing"); return; } // BUTTONS // Y + if (evt.getSource() == jbyplus) { panaff.jbyplus(); setUnsave(true); return; } // Y = if (evt.getSource() == jbyegal) { panaff.jbyegal(); setUnsave(true); return; } // Y - if (evt.getSource() == jbymoins) { panaff.jbymoins(); setUnsave(true); return; } // X |< if (evt.getSource() == jbxpipeinf) { panaff.jbxpipeinf(); setUnsave(true); return; } // X << if (evt.getSource() == jbx2inf) { panaff.jbx2inf(); setUnsave(true); return; } // X < if (evt.getSource() == jbx1inf) { panaff.jbx1inf(); setUnsave(true); return; } // X = if (evt.getSource() == jbxegal) { panaff.jbxegal(); setUnsave(true); return; } // X > if (evt.getSource() == jbx1sup) { panaff.jbx1sup(); setUnsave(true); return; } // X >> if (evt.getSource() == jbx2sup) { panaff.jbx2sup(); setUnsave(true); return; } // X >| if (evt.getSource() == jbxpipesup) { panaff.jbxpipesup(); setUnsave(true); return; } // all following actions reset pred selection in PanAff panaff.endSelPred(); // PROJECT SPVIEW 2.0 // -> Load project files if (evt.getSource() == jmiopenproject) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiopenproject"); return; } loadProjectFile(); return; } // -> Close project if (evt.getSource() == jmicloseproject) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmicloseproject"); return; } if (checkForSave()) { spvFileName = null; closeAll(); } return; } // -> Save project files if (evt.getSource() == jmisaveproject) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmisaveproject"); return; } if (spvFileName == null) { project = new SPVProject(this); spvFileName = workd; } project.saveSPVFile(spvFileName); return; } // DATA // -> Load spectrum file if (evt.getSource() == jmiloadspect) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiloadspect"); return; } loadDataFile("spectrum"); return; } // -> Load stick file if (evt.getSource() == jmiloadstick) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiloadstick"); return; } loadDataFile("stick"); return; } // -> Load peak/experiment file as stick if (evt.getSource() == jmiloadpeakas) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiloadpeakas"); return; } loadDataFile("peakas"); return; } // -> Load prediction file (TDS) as stick if (evt.getSource() == jmiloadtdsas) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiloadtdsas"); return; } loadDataFile("tdsas"); return; } // -> Load prediction file (HITRAN) as stick if (evt.getSource() == jmiloadhitras) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiloadhitras"); return; } loadDataFile("hitras"); return; } // DATAMANAGEMENT // -> Reset All if (evt.getSource() == jmiresetall) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiresetall"); return; } if (nbdf > 0) { panaff.resetAll(); // call panaff for (int i = 0; i < nbdf; i++) { resetDatafJMI(i); // reset jmi of this dataf (like show) } } setUnsave(true); return; } // -> data files if (nbdf > 0) { for (int i = 0; i < nbdf; i++) { // -> Show if (evt.getSource() == jmishow[i]) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmishow"); return; } panaff.setShow(i, true); // call panaff resetDatafJMI(i); // reset jmi of this dataf setHideState(i, false); setUnsave(true); return; } // -> Hide if (evt.getSource() == jmihide[i]) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmihide"); return; } jmishow[i].setEnabled(true); // disallow jmi of this dataf jmihide[i].setEnabled(false); if (dataf[i].getType() == "spectrum") { jmireload[i].setEnabled(false); } jmixshift[i].setEnabled(false); jmixunshift[i].setEnabled(false); jmiyshift[i].setEnabled(false); jmiyunshift[i].setEnabled(false); jmiyreverse[i].setEnabled(false); panaff.setShow(i, false); // call panaff setHideState(i, true); setUnsave(true); return; } // -> Reload if (evt.getSource() == jmireload[i]) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmireload"); return; } reloadDataFile(i); return; } // -> X shift if (evt.getSource() == jmixshift[i]) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmixshift"); return; } panaff.xShift(i); // call panaff jmixunshift[i].setEnabled(true); setUnsave(true); return; } // -> X unshift if (evt.getSource() == jmixunshift[i]) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmixunshift"); return; } panaff.xUnshift(i); // call panaff jmixunshift[i].setEnabled(false); setUnsave(true); return; } // -> Y shift if (evt.getSource() == jmiyshift[i]) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiyshift"); return; } panaff.yShift(i); // call panaff jmiyunshift[i].setEnabled(true); setUnsave(true); return; } // -> Y unshift if (evt.getSource() == jmiyunshift[i]) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiyunshift"); return; } panaff.yUnshift(i); // call panaff jmiyunshift[i].setEnabled(false); setUnsave(true); return; } // -> Y reverse if (evt.getSource() == jmiyreverse[i]) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiyreverse"); return; } panaff.yReverse(i); // call panaff setyReverseState(i); setUnsave(true); } } } // ASSIGNMENT // -> Create peak file from spectrum if (evt.getSource() == jmicpfnone) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmicpfnone"); return; } // Unknown default spectrum file name JFCreatePeakFile jfcpf = new JFCreatePeakFile(null); // create the window jfcpf.setVisible(true); // show it return; } for (int i = 0; i < nbdf; i++) { // search in spectrum type data files if (evt.getSource() == jmicpf[i]) { // found if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmicpf"); return; } JFCreatePeakFile jfcpf = new JFCreatePeakFile(dataf[i]); // create the window jfcpf.setVisible(true); // show it return; } } // -> Load peak/experiment file if (evt.getSource() == jmiloadexpf) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiloadexpf"); return; } loadExpFile(); typeOfExpFile = "peakExp"; attributeOfExpFile = "expread"; return; } // -> Load prediction file (TDS) if (evt.getSource() == jmilpTDS) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmilpTDS"); return; } loadPredFile("TDS"); typeOfPredFile = "TDS"; return; } // -> Load prediction file (HITRAN) if (evt.getSource() == jmilpHITRAN) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmilpHITRAN"); return; } loadPredFile("HITRAN"); typeOfPredFile = "HITRAN"; return; } // -> Reload prediction file if (evt.getSource() == jmilpreload) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmilpreload"); return; } reloadPredFile(); return; } // -> Associate experiment to data if (evt.getSource() == jmiexp2null) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiexp2null"); return; } panaff.expAss2(-1); // unassociate setUnsave(true); return; } for (int i = 0; i < nbdf; i++) { // for each datafile if (evt.getSource() == jmiexp2[i]) { // found if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiexp2"); return; } str = panaff.expAss2(i); // associate if (str.length() != 0) { // show error message JOptionPane.showMessageDialog(null, str); } setUnsave(true); return; } } // -> Associate prediction to data if (evt.getSource() == jmipred2null) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmipred2null"); return; } panaff.predAss2(-1); // unassociate setUnsave(true); return; } for (int i = 0; i < nbdf; i++) { // for each data file if (evt.getSource() == jmipred2[i]) { // found if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmipred2"); return; } str = panaff.predAss2(i); // associate if (str.length() != 0) { // show error message JOptionPane.showMessageDialog(null, str); } setUnsave(true); return; } } // -> Save experiment file if (evt.getSource() == jmisavexp) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmisavexp"); return; } panaff.saveExp(); // call panaff return; } // PLOT // -> Print if (evt.getSource() == jmiprint) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiprint"); return; } // thread panaff.prepThread("Printing File ..."); // wait message threadType = "print"; // define action of run Thread threadThis = new Thread(this); // define the thread (run of this instance) threadThis.start(); // start it return; } if (evt.getSource() == jmixobscalc) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmixobscalc"); return; } try { ObsCalc obsCalc = new ObsCalc(expf, predf); obsCalc.show(this, "X"); } catch (Exception e) { JOptionPane.showMessageDialog(null, "You must first load prediction and peak/experiment files."); } } if (evt.getSource() == jmiyobscalc) { if ((evt.getModifiers() & InputEvent.BUTTON3_MASK) != 0) { // help PopFile.show(getName() + fisep + "jmiyobscalc"); return; } try { ObsCalc obsCalc = new ObsCalc(expf, predf); obsCalc.show(this, "Y"); } catch (Exception e) { JOptionPane.showMessageDialog(null, "You must first load prediction and peak/experiment files."); } } // HELP // -> About if (evt.getSource() == jmiabout) { About.show(this.getParent()); return; } } ///////////////////////////////////////////////////////////////////// // reset JMenuItem of a data file private void resetDatafJMI(int ci) { jmishow[ci].setEnabled(false); jmihide[ci].setEnabled(true); if (dataf[ci].getType() == "spectrum") { jmireload[ci].setEnabled(true); } jmixshift[ci].setEnabled(true); if (panaff.getXShift(ci) == 0.) { jmixunshift[ci].setEnabled(false); } else { jmixunshift[ci].setEnabled(true); } jmiyshift[ci].setEnabled(true); if (panaff.getYShift(ci) == 0.) { // NO yshift jmiyunshift[ci].setEnabled(false); } else { jmiyunshift[ci].setEnabled(true); } jmiyreverse[ci].setEnabled(true); } private void closeAll() { if (nbdf == 0) return; dataf = new DataFile[mxnbdf]; ndataf = new String[mxnbdf]; pccc.remove(panaff); panaff = new PanAff(this, mxnbdf, coul, jta, jlx, jly, jlypredas); panaff.setBackground(Color.WHITE); pccc.add(panaff, "Center"); pccc.setBorder(BorderFactory.createLineBorder(Color.BLACK)); pccc.repaint(); project = null; pathListToSave.clear(); typeOfFileToSave.clear(); AttributeOfFileToSave.clear(); yReverseElementToSave.clear(); hideElementToSave.clear(); PredfileToSave = 0; ExpfileToSave = 0; expFileLabel.setText(""); jmdataman.remove(datamanSeparator); for (int i = 0; i < nbdf; i++) { jmdataman.remove(jmndataf[i]); jmcreatepeakf.remove(jmicpf[i]); jmexp2data.remove(jmiexp2[i]); jmpred2data.remove(jmipred2[i]); } jmiloadexpf.setEnabled(false); jmloadpredf.setEnabled(false); jmexp2data.setEnabled(false); jmpred2data.setEnabled(false); jmisavexp.setEnabled(false); nbdf = 0; } //////////////////////////////////////////////////////////// /** * Load files by file name * * @param cntfile file type * @since SPVIEW2 */ public void loadFileByFilename(String filename, String cntfile, int i) { // -> Show // instantiate a data file String attribute = project.getAttributeOfFileList().get(i); if (attribute.equals("dataread")) { ndataf[i] = filename; dataf[i] = new DataFile(ndataf[i]); // full data file name dataf[i].setType(cntfile); // type // thread panaff.prepThread("Loading File ..."); // wait message nbdf = i; threadType = "dataread"; // define action of run() this.run(); } else if (attribute.equals("predread")) { PredfileToSave = 1; pathOfPredfileToSave = npredf; // instantiate the prediction file npredf = filename; predf = new PredFile(npredf, cntfile); // full pred file name, type // Color associated panaff.setPfass2(project.getIndexColorPred()); // thread panaff.prepThread("Loading File ..."); // wait message threadType = "predread"; // define action of run() this.run(); } else if (attribute.equals("expread")) { ExpfileToSave = 1; // instantiate the experimental file nexpf = filename; expf = new ExpFile(nexpf); // full exp file name pathOfExpfileToSave = nexpf; // Color associated panaff.setEfass2(project.getIndexColorExp()); // thread panaff.prepThread("Loading File ..."); // wait message threadType = "expread"; // define action of run() this.run(); } } //////////////////////////////////////////////////////////// /** * Get the yReverse-state of each file loaded in order to save this state * * @since SPVIEW2 */ private void setyReverseState(int j) { if (j < yReverseElementToSave.size()) { String reverse = yReverseElementToSave.get(j); yReverseElementToSave.set(j, reverse.equals("true") ? "false" : "true"); } else { yReverseElementToSave.add("true"); } } /** * Get the hide-state of each file loaded in order to save this state * * @since SPVIEW2 */ private void setHideState(int j, boolean hide) { if (j < hideElementToSave.size()) { String tag = hide == true ? "true" : "false"; hideElementToSave.set(j, tag); } else { hideElementToSave.add("false"); } } private void displayName(String filename) { File file = new File(filename); expFileLabel.setText(/*"Peak/experiment file: " + */file.getName()); } //////////////////////////////////////////////////////////// public void loadProjectFileName(String filename) { spvFileName = filename; panaff.prepThread("Loading Project File ..."); // wait message threadType = "project"; // define action of run() Thread threadThis = new Thread(this); // define thread (run of this instance) threadThis.start(); // start it } /** * Open a dialog box to save the files as a project * * @since SPVIEW2 */ private void loadProjectFile() { JFileChooser jfcfile = new JFileChooser(workd); // default choice directory jfcfile.setSize(400, 300); jfcfile.setFileSelectionMode(JFileChooser.FILES_ONLY); // files only jfcfile.setDialogTitle("Open Project"); FileNameExtensionFilter filter = new FileNameExtensionFilter("Project file (*.spv)", "spv"); // Only files .spv // can be chosen jfcfile.addChoosableFileFilter(filter); // add the filter created above jfcfile.setAcceptAllFileFilterUsed(false); // All types of file are NOT accepted Container parent = getParent(); int choice = jfcfile.showOpenDialog(parent); if (choice == JFileChooser.APPROVE_OPTION) { loadProjectFileName(jfcfile.getSelectedFile().getAbsolutePath()); } } //////////////////////////////////////////////////////////// /** * Load a data file. * * @param cntfile file type */ private void loadDataFile(String cntfile) { // max nb of file reached ? if (nbdf == mxnbdf) { JOptionPane.showMessageDialog(null, "Max number of data files is reached (" + mxnbdf + ")"); return; } // choose the file JFileChooser jfcfile = new JFileChooser(workd); // default choice directory jfcfile.setSize(400, 300); jfcfile.setFileSelectionMode(JFileChooser.FILES_ONLY); // files only jfcfile.setDialogTitle("Define the file to be visualized"); Container parent = getParent(); int choice = jfcfile.showDialog(parent, "Select"); // Dialog, Select if (choice == JFileChooser.APPROVE_OPTION) { // instantiate a data file ndataf[nbdf] = jfcfile.getSelectedFile().getAbsolutePath(); dataf[nbdf] = new DataFile(ndataf[nbdf]); // full data file name dataf[nbdf].setType(cntfile); // type // thread panaff.prepThread("Loading File ..."); // wait message threadType = "dataread"; // define action of run() Thread threadThis = new Thread(this); // define thread (run of this instance) threadThis.start(); // start it } } //////////////////////////////////////////////////////////// /** * Reload a data file. * * @param ci file index */ private void reloadDataFile(int ci) { // thread relfi = ci; // reloadable file index panaff.prepThread("Reloading File ..."); // wait message threadType = "datareload"; // define action of run() Thread threadThis = new Thread(this); // define thread (run of this instance) threadThis.start(); // start it } //////////////////////////////////////////////////////////// /** * Reload a data file. * * @param ci file index */ private void reloadPredFile() { // thread panaff.prepThread("Reloading File ..."); // wait message threadType = "predreload"; // define action of run() Thread threadThis = new Thread(this); // define thread (run of this instance) threadThis.start(); // start it } //////////////////////////////////////////////////////////// /** * Load an experiment file. */ private void loadExpFile() { // a file is already loaded if (expf != null) { int n = JOptionPane.showConfirmDialog(null, "An experiment file is already loaded" + lnsep + "Would you like to overload a new experiment file ?" + lnsep, "New experiment file", JOptionPane.YES_NO_OPTION); if (n != JOptionPane.YES_OPTION) { // nothing to do return; } } // choose the file JFileChooser jfcfile = new JFileChooser(workd); // default choice directory jfcfile.setSize(400, 300); jfcfile.setFileSelectionMode(JFileChooser.FILES_ONLY); // files only jfcfile.setDialogTitle("Define the experiment file to be loaded"); Container parent = getParent(); int choice = jfcfile.showDialog(parent, "Select"); // Dialog, Select if (choice == JFileChooser.APPROVE_OPTION) { // instantiate an exp file nexpf = jfcfile.getSelectedFile().getAbsolutePath(); expf = new ExpFile(nexpf); // full exp file name // thread panaff.prepThread("Loading File ..."); // wait message threadType = "expread"; // define action of run() Thread threadThis = new Thread(this); // define thread (run of this instance) threadThis.start(); // start it } } /** * Load a prediction file. * * @param ctype file type */ private void loadPredFile(String ctype) { // a file is already loaded if (predf != null) { int n = JOptionPane.showConfirmDialog( null, "A prediction file is already loaded" + lnsep + "Would you like to overload a new prediction file ?" + lnsep, "New prediction file", JOptionPane.YES_NO_OPTION); if (n != JOptionPane.YES_OPTION) { // nothing to do return; } } // choose the file JFileChooser jfcfile = new JFileChooser(workd); // default choice directory jfcfile.setSize(400, 300); jfcfile.setFileSelectionMode(JFileChooser.FILES_ONLY); // files only jfcfile.setDialogTitle("Define the prediction file to be loaded"); Container parent = getParent(); int choice = jfcfile.showDialog(parent, "Select"); // Dialog, Select if (choice == JFileChooser.APPROVE_OPTION) { // instantiate a pred file npredf = jfcfile.getSelectedFile().getAbsolutePath(); predf = new PredFile(npredf, ctype); // full pred file name, type // thread panaff.prepThread("Loading File ..."); // wait message threadType = "predread"; // define action of run() Thread threadThis = new Thread(this); // define thread (run of this instance) threadThis.start(); // start it } } //////////////////////////////////////////////////////////// /** * Thread launched by start.
* Processes read of data files
* or read of experiment file
* or read of prediction file
* or reload of data files
* or print of graphs. */ public void run() { // what to do if (threadType.equals("dataread")) { // read data file if (dataf[nbdf].read()) { // read data file if (nbdf == 0) { jmiloadtdsas.setEnabled(true); jmiloadhitras.setEnabled(true); } typeOfFileToSave.add(dataf[nbdf].getType()); // show data if (dataf[nbdf].getType().equals("tdsas") || dataf[nbdf].getType().equals("hitras") || dataf[nbdf].getType().equals("pickettas")) { dataf[nbdf].setType("predas"); // generic type for pred-as-stick files jmndataf[nbdf] = new JMenu(ndataf[nbdf] + " (pred-as-stick)"); if (cjl.getText().trim().length() == 0) { // not already set : 1st pred-as-stick file cjl.setText("pred-as-stick y ="); // last x/y/pasy label for mouse position } pathListToSave.add(ndataf[nbdf]); // add the path of the file loaded AttributeOfFileToSave.add("dataread"); yReverseElementToSave.add("false"); // add the y-state : "false" by default hideElementToSave.add("false"); } else if (dataf[nbdf].getType().equals("peakas")) { jmndataf[nbdf] = new JMenu(ndataf[nbdf] + " (peak-as-stick)"); pathListToSave.add(ndataf[nbdf]); // add the path of the file loaded AttributeOfFileToSave.add("dataread"); yReverseElementToSave.add("false"); // add the y-state : "false" by default hideElementToSave.add("false"); } else { // spectrum/stick jmndataf[nbdf] = new JMenu(ndataf[nbdf] + " (" + dataf[nbdf].getType() + ")"); } jmndataf[nbdf].setBackground(Color.WHITE); jmndataf[nbdf].setForeground(coul[nbdf - ((int) coulength) * ((int) (nbdf / coulength))]); jmishow[nbdf] = new JMenuItem("Show"); jmishow[nbdf].setEnabled(false); jmishow[nbdf].addActionListener(this); jmndataf[nbdf].add(jmishow[nbdf]); jmihide[nbdf] = new JMenuItem("Hide"); jmihide[nbdf].addActionListener(this); jmndataf[nbdf].add(jmihide[nbdf]); if (dataf[nbdf].getType().equals("spectrum")) { jmireload[nbdf] = new JMenuItem("Reload"); jmireload[nbdf].addActionListener(this); jmndataf[nbdf].add(jmireload[nbdf]); } jmndataf[nbdf].addSeparator(); jmixshift[nbdf] = new JMenuItem("X shift"); jmixshift[nbdf].addActionListener(this); jmndataf[nbdf].add(jmixshift[nbdf]); jmixunshift[nbdf] = new JMenuItem("X unshift"); jmixunshift[nbdf].setEnabled(false); jmixunshift[nbdf].addActionListener(this); jmndataf[nbdf].add(jmixunshift[nbdf]); jmndataf[nbdf].addSeparator(); jmiyshift[nbdf] = new JMenuItem("Y shift"); jmiyshift[nbdf].addActionListener(this); jmndataf[nbdf].add(jmiyshift[nbdf]); jmiyunshift[nbdf] = new JMenuItem("Y unshift"); jmiyunshift[nbdf].setEnabled(false); jmiyunshift[nbdf].addActionListener(this); jmndataf[nbdf].add(jmiyunshift[nbdf]); jmndataf[nbdf].addSeparator(); jmiyreverse[nbdf] = new JMenuItem("Y reverse"); jmiyreverse[nbdf].addActionListener(this); jmndataf[nbdf].add(jmiyreverse[nbdf]); if (nbdf == 0) { datamanSeparator = new JSeparator(); jmdataman.add(datamanSeparator); } jmdataman.add(jmndataf[nbdf]); // if (dataf[nbdf].getType().equals("spectrum")) { // only spectrum type data file for jmcreatpeakf jmicpf[nbdf] = new JMenuItem(ndataf[nbdf]); jmicpf[nbdf].setBackground(Color.WHITE); jmicpf[nbdf].setForeground(coul[nbdf - ((int) coulength) * ((int) (nbdf / coulength))]); jmicpf[nbdf].addActionListener(this); jmcreatepeakf.add(jmicpf[nbdf]); pathListToSave.add(ndataf[nbdf]); // add the path of the file loaded AttributeOfFileToSave.add("dataread"); yReverseElementToSave.add("false"); // add the y-state : "false" by default hideElementToSave.add("false"); } else { jmicpf[nbdf] = new JMenuItem(); // instantiated but not activated } // jmiexp2[nbdf] = new JMenuItem(ndataf[nbdf]); jmiexp2[nbdf].setBackground(Color.WHITE); jmiexp2[nbdf].setForeground(coul[nbdf - ((int) coulength) * ((int) (nbdf / coulength))]); jmiexp2[nbdf].addActionListener(this); jmexp2data.add(jmiexp2[nbdf]); if (expf != null) { jmexp2data.setEnabled(true); } jmipred2[nbdf] = new JMenuItem(ndataf[nbdf]); jmipred2[nbdf].setBackground(Color.WHITE); jmipred2[nbdf].setForeground(coul[nbdf - ((int) coulength) * ((int) (nbdf / coulength))]); jmipred2[nbdf].addActionListener(this); jmpred2data.add(jmipred2[nbdf]); if (predf != null) { jmpred2data.setEnabled(true); } panaff.addData(dataf[nbdf]); // call panaff jmiloadexpf.setEnabled(true); jmloadpredf.setEnabled(true); nbdf++; setUnsave(true); } else { // read error dataf[nbdf] = null; ndataf[nbdf] = null; } } else if (threadType.equals("expread")) { // read exp file if (expf.read()) { // show exp panaff.setExp(expf); // call panaff if (nbdf != 0) { jmexp2data.setEnabled(true); } jmisavexp.setEnabled(true); typeOfExpFile = "peakExp"; pathOfExpfileToSave = nexpf; attributeOfExpFile = "expread"; ExpfileToSave = 1; displayName(nexpf); setUnsave(true); } else { // read error expf = null; } } else if (threadType.equals("predread")) { // read pred file if (predf.read()) { // show pred panaff.setPred(predf); // call panaff if (nbdf != 0) { jmpred2data.setEnabled(true); pathOfPredfileToSave = npredf; attributeOfPredFile = "predread"; PredfileToSave = 1; } setUnsave(true); } else { // read error predf = null; } } else if (threadType.equals("datareload")) { // reload data file if (dataf[relfi].read()) { // reload data file panaff.reloadData(dataf[relfi], relfi); } } else if (threadType.equals("predreload")) { if (predf.read()) { /* update prediction file */ panaff.setPred(predf); /* update shifts */ panaff.reloadPredf(predf); } } else if (threadType.equals("project")) { try { if ((project == null && nbdf > 0) || (project != null && project.isUnsave())) { int n = JOptionPane.showConfirmDialog(null, "The current project is in a unsaved state, Do you want to save it?", "Project file is unsaved", JOptionPane.YES_NO_CANCEL_OPTION); if (n == JOptionPane.YES_OPTION) { project.saveSPVFile(workd); } else if (n == JOptionPane.CANCEL_OPTION) { panaff.endThread(); return; } } closeAll(); project = new SPVProject(this, spvFileName); project.open(); project.setUnsave(false); } catch (ParserConfigurationException | SAXException | IOException e) { JOptionPane.showMessageDialog(null, "Cannot Parse File " + spvFileName, "Error", JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } } else { // print PrinterJob pjob = PrinterJob.getPrinterJob(); // define a printing job PageFormat pf = pjob.defaultPage(); // define page format pf.setOrientation(PageFormat.LANDSCAPE); pjob.setPrintable(panaff, pf); // associate to PanAff // if (pjob.printDialog(new HashPrintRequestAttributeSet())) { supprime // LANDSCAPE if (pjob.printDialog()) { // define printing try { pjob.print(); // print } catch (PrinterException pe) { JOptionPane.showMessageDialog(null, "Printer exception" + lnsep + pe); } } } panaff.endThread(); } private void closeApplication() { if (checkForSave()) System.exit(0); } /* getters and setters */ public PanAff getPanAff() { return panaff; } public SPVProject getProject() { return project; } public ArrayList getPathsList() { return pathListToSave; } public ArrayList getAttributeOfFileList() { return AttributeOfFileToSave; } public ArrayList getTypeOfFileList() { return typeOfFileToSave; } public ArrayList getReverseYElementList() { return yReverseElementToSave; } public ArrayList getHideElementList() { return hideElementToSave; } public String getPathOfPredFile() { return pathOfPredfileToSave; } public void setPathOfPredFile(String path) { this.pathOfPredfileToSave = path; } public String getAttributeOfPredFile() { return attributeOfPredFile; } public void setAttributefPredFile(String attribute) { this.attributeOfPredFile = attribute; } public String getTypeOfPredFile() { return typeOfPredFile; } public void setTypeOfPredFile(String type) { this.typeOfPredFile = type; } public String getPathOfExpfile() { return pathOfExpfileToSave; } public void setPathOfExpFile(String path) { pathOfExpfileToSave = path; } public void setTypeOfExpFile(String type) { this.typeOfExpFile = type; } public String getAttributeOfExpFile() { return attributeOfExpFile; } public void setAttributefExpFile(String attribute) { attributeOfExpFile = attribute; } public String getTypeOfExpFile() { return typeOfExpFile; } public int getPredfileToSave() { return PredfileToSave; } public int getExpfileToSave() { return ExpfileToSave; } public int getNbOfDataFile() { return nbdf; } public String getPredFileName() { return npredf; } public String getExpFileName() { return nexpf; } public void enableXUnshiftMenu(int n, boolean enable) { jmixunshift[n].setEnabled(enable); } public void enableYUnshiftMenu(int n, boolean enable) { jmiyunshift[n].setEnabled(enable); } public void enableHideMenu(int n, boolean enable) { jmihide[n].setEnabled(enable); } public void enableShowMenu(int n, boolean enable) { jmishow[n].setEnabled(enable); } public void setUnsave(boolean unsave) { if (this.project != null) { this.project.setUnsave(unsave); } } } sources/org/spview/filehandler/PredFile.java000644 001750 001750 00000011725 13544613421 021776 0ustar00cyrilcyril000000 000000 package org.spview.filehandler; /* * Class of prediction file */ import java.awt.geom.Point2D; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import javax.swing.JOptionPane; import org.spview.point.PredXPoint; /** * This class defines prediction data. */ public class PredFile { private String name; // file name private String type; // type (TDS/HITRAN/PICKETT) private double[] x; // X private double[] y; // Y private String[] jsyn; // assignment string private int[] jinf; // jinf extracted from jsyn private int nbxy; // nb of points private String str; // to read file private BufferedReader br; private String lnsep; // line separator //////////////////////////////////////////////////////////////////// /** * Construct a new PredFile.
* (TDS, HITRAN or PICKETT type) * * @param cname name of the file * @param ctype type of the file */ public PredFile(String cname, String ctype) { name = cname; // file name type = ctype; // type (TDS/HITRAN/PICKETT) lnsep = System.getProperty("line.separator"); nbxy = 0; // nb of points } //////////////////////////////////////////////////////////////////// /** * Read file.
* validity is tested following FORMAT : 1022 of spect.f, 1000 of spech.f */ public boolean read() { // to keep points, unknown nb of points ArrayList alx = new ArrayList(); // frequency ArrayList aly = new ArrayList(); // intensity ArrayList aljsyn = new ArrayList(); // assignment ArrayList alxjsyn = new ArrayList(); // extended assignment String cjsyn = ""; // current assignment String cxjsyn = ""; // current extended assignment try { Point2D data = null; br = new BufferedReader(new FileReader(new File(name))); // open while ((str = br.readLine()) != null) { // line read if (type.equals("HITRAN")) { data = HITRANFile.extractXY(str); if (data != null) { cjsyn = HITRANFile.extractAssignment(str); cxjsyn = HITRANFile.extractExtendedAssignment(str); } } else if (type.equals("PICKETT")) { data = PickettFile.extractXY(str); if (data != null) { cjsyn = PickettFile.extractAssignment(str); } } else { data = TDSFile.extractXY(str); if (data != null) { cjsyn = TDSFile.extractAssignment(str); } } if (data != null) { alx.add(data.getX()); // keep data aly.add(data.getY()); // test if jsyn is not empty if (cjsyn.length() == 0) { JOptionPane.showMessageDialog(null, str + lnsep + "Empty jsyn in file" + lnsep + name); return false; } // test if xjsyn (HITRAN) or jsyn (TDS) is uniq if (type.equals("HITRAN")) { // HITRAN if (alxjsyn.contains(cxjsyn)) { JOptionPane.showMessageDialog(null, cxjsyn + lnsep + "Duplicated in file" + lnsep + name); return false; } alxjsyn.add(cxjsyn); // keep data } else { // TDS, PICKETT if (aljsyn.contains(cjsyn)) { JOptionPane.showMessageDialog(null, cjsyn + lnsep + "Duplicated in file" + lnsep + name); return false; } } aljsyn.add(cjsyn); // keep data } } } catch (IOException ioe) { // IO error JOptionPane.showMessageDialog(null, "IO error while reading file" + lnsep + name + lnsep + ioe); return false; } finally { // close if (br != null) { try { br.close(); } catch (IOException ignored) { } } } // save data nbxy = alx.size(); // nb of points if (nbxy == 0) { // no point JOptionPane.showMessageDialog(null, "No valid data found in file" + lnsep + name); return false; } x = new double[nbxy]; y = new double[nbxy]; jsyn = new String[nbxy]; jinf = new int[nbxy]; // sort PredXPoint[] pxpt = new PredXPoint[nbxy]; // compare X for (int i = 0; i < nbxy; i++) { pxpt[i] = new PredXPoint(((Double) alx.get(i)).doubleValue(), ((Double) aly.get(i)).doubleValue(), (String) aljsyn.get(i)); } Arrays.sort(pxpt); // sort // save data for (int i = 0; i < nbxy; i++) { x[i] = pxpt[i].getX(); y[i] = pxpt[i].getY(); jsyn[i] = pxpt[i].getJsyn(); try { // extract jinf from jsyn // TDS, HITRAN jinf[i] = Integer.parseInt(jsyn[i].substring(0, 3).trim()); } catch (NumberFormatException e) { // format error jinf[i] = -1; } } return true; } /** * Get number of data points. */ public int getNbxy() { return nbxy; } /** * Get X array. */ public double[] getX() { return x; } /** * Get Y array. */ public double[] getY() { return y; } /** * Get X value. */ public double getX(int id) { return x[id]; } /** * Get Y value. */ public double getY(int id) { return y[id]; } /** * Get Jinf array. */ public int[] getJinf() { return jinf; } /** * Get Jsyn assignment array. */ public String[] getJsyn() { return jsyn; } } resources/pixmaps/pause.png000644 001750 001750 00000002501 13544613421 016703 0ustar00cyrilcyril000000 000000 PNG  IHDR szzIDATXWMEWUkv^ID.x& !WO%$ȚGcra ^\=ʒͰ;0S4{+bM)5ArI>K$IΑlv]GH3"2)!` $t:v7ȔRDe'>7sKKK7vJ@H~D)%Zkaq\2I""ݻn@DG 5Zy>`8$SJw?kOcXke»r ;.@9WM)-[ &d >j0ƬR 9yL6齟*cR57~Qmcc IDw֘@D0 IZ t,I4MFERŹT?:Z[m7Zkyq)`"r|γ,CE;VF28p*D1FGQ>v-xƘBJjƘ47DDs98pFSO;k׮>8y9|{*VVV֝$)zX6 r޽pPihORMIv*Ill"vH-$Oph6zEvZnd4UDx[pl0LF$o=vK8FZECLjQ N"rVDl8"!n'0m>66GRl *ՅzEZ[d>k-QT j:pqq1s:wZ BLj1#I<~Zkq\J2~j)(nٳJ)uNF4E/4CezH ВڿZjVG6۷u_9*1&;Z볷o߾Ɩ]{{e|Z(.Oiz$#\EdNDZ"2nk7f`gIENDB`resources/pixmaps/forward.png000644 001750 001750 00000002637 13544613421 017244 0ustar00cyrilcyril000000 000000 PNG  IHDR szzfIDATXW]h\EΙI7yyIiK`ۇjɋV(b_T>HR'JB ƿ(P֢ݧH Z!]dٹ&2p93979g&#"JD@De"&MU*:ID1/44,׈}Y*f1!B03>;=ZLD !BQEQ $If>߿uB"HA0 6$[bƍbXYi)n >̻d3+NJC"mB!. !FgffbKpw jZ#JA)I!(Be#Z$HK)O*j, JAMߌR v 3o\.ir3fzl@[yR²,XuWǍBl3A췵kcH)qf`}}>,ZIxHeRҲ,1ZTJuB)5D43K 2 FGG_J(,mSmS`O6>?q6,KXXLDIIAcO $9tZ#Cܹ_J%AS`f&ZM4>({3s{f{bYlZɌ LDQcxUs8\Ǧ8ͷq)4"$J5iK.޽?100Q|.vieannJ)s)N"s& 0G#JM4.`fT*!ɠ ! Bk ðm4U۶ <3JDD[(TPV*Q(b4LD+j$ijd5b h#":ODZIӻj ۶a6,˺_Jy?3CC\JLfxlj)|>L:yg m .t:YXT*T*q FHL&s'nj u]+R+ffAr qbpuYt,k_2usV4.2_֨똛mǵq))勹\X.Z T*pݺuD$ôЉyj%(V&\.7ߊլQm15iSxmt=gif1TPS'?IENDB`resources/JobPlay/000755 001750 001750 00000000000 13544613421 014741 5ustar00cyrilcyril000000 000000 resources/pixmaps/playback.png000644 001750 001750 00000006131 13544613421 017357 0ustar00cyrilcyril000000 000000 PNG  IHDR szzzTXtRaw profile type exifxڭW[v*f Hu, iwsX)P\rI-5V u;]ɿ'<)Ǽ|]>_(=q֩g!^ϼz|\&vPO.[ڮ&FF 7%i}ċ ̃j,x(.\ B"BoU< 3_\%+bi0 é8~PP ]31O;5̳(0Ҕ*(DBr; 6Ȅ•moSmFi3ҦZASRE DIADDs)KιdQZbIEJ.ҊXSk[D [ Tbiۊ{KϽ[ׁiȣ:3N̳Ygh!VZ*t#viλևjGWr߫FG5S,̥|,AVN4bSͦU)%6L1B8L1(lzhܷIJ7r/ &QWި6OYW(lrU;~{8g0R ^kR&-0l 00O?p2F8. ^w?|gң - E #C` x .wȭ#F Y]5{ [K/YQ:Yߑ In{D}#mi w1d Z\;{ֶ{Lø %WGpwƦчlu 7&`kFhN_OX%#$Zx$SU#Lq(#M.Up(X)bcoDWx`(,JQH , H@k>Y@?IDoUb(VEUtkmn3s/;׻|lZٽΜ9N긪Uz^UC^ϴ}PTW)UIDPUXU""~@V:Vz900𼪾($Hm B@aFDy9fi\~WU0P  k-0s!"zEUKTtk,!Q <@XpgD(\Dri1ZXk!"X\\3#IFU1TƘ+$IBsi5w͛'_9rsi }.@B@e(p)]~-022sw _ c Y!MhIR1U}"%Zbts~7mMܞ(QI9V&-R7VA9d-%Vn\j9=k׮!kg^)ZMfO}VBNI|x$ZD713on7‚[nDZwϞ^vOfUjAe(JkU3fQ1"D\^Hil#;kѷF&oi"MSXkj~5]: D~1Gi^*J(Jh6(˹+Wxz,ih``` /Nzt#k-yY̞v߸q㯎իrj4T*0>jMaqq{[R D\&j'"y+izb_P׳O1c,69ܹs (9Z-xADHIZ$I2+W5f۶m{{svef30]|{ `ll̊”~Nїsssޜv[VEdBDE=0LVFeIENDB`resources/PanAff/jmiunselexp.html000644 001750 001750 00000000313 13544613421 017762 0ustar00cyrilcyril000000 000000 Unselect the selected experimental peak.

Assignment

Deassociate all predictions from the selected experimental peak.

sources/org/spview/point/000755 001750 001750 00000000000 13544613421 016307 5ustar00cyrilcyril000000 000000 sources/org/spview/point/ExpJsynPoint.java000644 001750 001750 00000006333 13544613421 021571 0ustar00cyrilcyril000000 000000 package org.spview.point; /** * This class allows to sort experiment data following assignment order. */ public class ExpJsynPoint implements Comparable { private String faso; // frequency mark private String saso; // intensity mark private String jsyn; // assignment private int ipred; // index of related prediction line private String comm; // comment /** * Construct a new ExpJsynPoint. * * @param cfaso frequency mark * @param csaso intensity mark * @param cjsyn assignment * @param cipred index of related prediction line * @param ccomm comment */ public ExpJsynPoint(String cfaso, String csaso, String cjsyn, int cipred, String ccomm) { faso = cfaso; // frequency mark saso = csaso; // intensity mark jsyn = cjsyn; // assignment ipred = cipred; // index of related prediction line comm = ccomm.trim(); // comment (without extra spaces) } ///////////////////////////////////////////////////////////////////// /** * Get frequency mark. */ public String getFaso() { return faso; } /** * Set frequency mark. */ public void setFaso(String cfaso) { faso = cfaso; } /** * Get intensity mark. */ public String getSaso() { return saso; } /** * Set intensity mark. */ public void setSaso(String csaso) { saso = csaso; } /** * Get related assignment. */ public String getJsyn() { return jsyn; } /** * Set related assignment. */ public void setJsyn(String cjsyn) { jsyn = cjsyn; } /** * Get index of related prediction line. */ public int getIpred() { return ipred; } /** * Set index of related prediction line. */ public void setIpred(int cipred) { ipred = cipred; } /** * Get comment. */ public String getComm() { return comm; } /** * Set comment. */ public void setComm(String cstr) { comm = cstr.trim(); // without extra spaces } /** * Compare assignment strings. * * @param cejpt the ExpJsynPoint to compare to */ public int compareTo(Object cejpt) { if( ! (cejpt instanceof ExpJsynPoint) ) { // not the right object throw new ClassCastException(); } int delta = ((ExpJsynPoint)cejpt).getJsyn().compareTo(jsyn); // compare assignment strings if ( delta < 0 ) { return 1; } else if( delta > 0 ) { return -1; } return 0; // equal } } resources/JobPlay/jmicpfnone.html000644 001750 001750 00000000233 13544613421 017755 0ustar00cyrilcyril000000 000000

Create Peak File

Create peak file from a spectrum file to be chosen.

resources/JobPlay/jmilpTDS.html000644 001750 001750 00000000274 13544613421 017320 0ustar00cyrilcyril000000 000000

Load prediction file

Load the prediction file in TDS format to plot it as ticks in the pred/exp area.

test/XMLXSDChecker.java000644 001750 001750 00000004367 13544613421 015527 0ustar00cyrilcyril000000 000000 import java.io.File; import java.io.IOException; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; public class XMLXSDChecker { /* * This program is for checking the XML file and XSD schema. * It uses the class "SimpleErrorHandler" and catch errors in order to create a correct * XML XSD groupe of files */ public void String (String XMLFileName) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { //These 3 lines are for informing that the validation is done via an XSD file. SchemaFactory sfactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); //The XSD schema is created //Here, it is an intern schema, for an extern one an URI is required Schema schema = sfactory.newSchema(new File("ProjectFile.xsd")); //The schema is assigned to the factory so that the document takes in charge the XSD file factory.setSchema(schema); DocumentBuilder builder = factory.newDocumentBuilder(); //Creation of the error handler ErrorHandler errHandler = new SimpleErrorHandler(); //Assignment of the error handler to the document in order to catch some. builder.setErrorHandler(errHandler); File fileXML = new File("ProjectFile.xml"); //A block of capture is added to catch error if there are some. try { Document xml = builder.parse(fileXML); Element root = xml.getDocumentElement(); System.out.println(root.getNodeName()); } catch (SAXParseException e) {} } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }sources/org/spview/gui/PlotData.java000644 001750 001750 00000016630 13544613421 020323 0ustar00cyrilcyril000000 000000 package org.spview.gui; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Cursor; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.RenderingHints; import java.awt.Stroke; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.List; import javax.swing.JPanel; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import org.spview.point.ResidualPoint; public class PlotData extends JPanel { /** * */ JobPlay jobplay; private static final long serialVersionUID = -2309468385394812985L; private int padding = 50; private int labelPadding = 25; private Color lineColor = new Color(44, 102, 230, 180); private Color pointColor = new Color(100, 100, 100, 180); private Color gridColor = new Color(200, 200, 200, 200); private static final Stroke GRAPH_STROKE = new BasicStroke(2f); final private int pointWidth = 4; final private int accuracyRadius = 12; private int numberYDivisions = 10; private List data; private JFText jft; public PlotData(JobPlay jobplay, List data) { addMouseListener(new MouseAdapter() { @Override public void mouseEntered(MouseEvent me) { setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR)); } @Override public void mouseExited(MouseEvent me) { setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); } @Override public void mouseClicked(MouseEvent me) { if (!me.isConsumed()) { if (me.getClickCount() == 2) { // handle double click me.consume(); Point2D point = me.getPoint(); // get Min and Max; double maxX = getRealX(point.getX() + accuracyRadius / 2); double minX = getRealX(point.getX() - accuracyRadius / 2); jobplay.getPanAff().setXZoom(minX, maxX); jobplay.setUnsave(true); } else { Point2D point = me.getPoint(); ArrayList result = findPoint(point); if (result.size() > 0) { showPoint(result); } } } } }); this.data = data; } private double getXScale() { return ((double) getWidth() - (2 * padding) - labelPadding) / (getMaxXData() - getMinXData()); } private double getYScale() { return ((double) getHeight() - (2 * padding) - labelPadding) / (getMaxYData() - getMinYData()); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); List graphPoints = new ArrayList<>(); for (int i = 0; i < data.size(); i++) { int x1 = (int) ((double) getWidth() - padding - (getMaxXData() - data.get(i).getX()) * getXScale()); int y1 = (int) ((getMaxYData() - data.get(i).getY()) * getYScale() + padding); graphPoints.add(new Point(x1, y1)); } // draw white background g2.setColor(Color.WHITE); g2.fillRect(padding + labelPadding, padding, getWidth() - (2 * padding) - labelPadding, getHeight() - 2 * padding - labelPadding); g2.setColor(Color.BLACK); // create hatch marks and grid lines for y axis. for (int i = 0; i < numberYDivisions + 1; i++) { int x0 = padding + labelPadding; // int x1 = pointWidth + padding + labelPadding; int y0 = getHeight() - ((i * (getHeight() - padding * 2 - labelPadding)) / numberYDivisions + padding + labelPadding); int y1 = y0; if (data.size() > 0) { g2.setColor(gridColor); g2.drawLine(padding + labelPadding + 1 + pointWidth, y0, getWidth() - padding, y1); g2.setColor(Color.BLACK); double yLabelDouble = ((int) ((getMinYData() + (getMaxYData() - getMinYData()) * ((i * 1.0) / numberYDivisions)) * 100)) / 100.0; String yLabel = String.format("%.2f", yLabelDouble); FontMetrics metrics = g2.getFontMetrics(); int labelWidth = metrics.stringWidth(yLabel); g2.drawString(yLabel, x0 - labelWidth - 5, y0 + (metrics.getHeight() / 2) - 3); } // g2.drawLine(x0, y0, x1, y1); } // and for x axis for (int i = 0; i < data.size(); i++) { if (data.size() > 1) { int x0 = i * (getWidth() - padding * 2 - labelPadding) / (data.size() - 1) + padding + labelPadding; int x1 = x0; int y0 = getHeight() - padding - labelPadding; // int y1 = y0 - pointWidth; if ((i % ((int) ((data.size() / 3.0)) + 1)) == 0) { g2.setColor(gridColor); g2.drawLine(x0, getHeight() - padding - labelPadding - 1 - pointWidth, x1, padding); g2.setColor(Color.BLACK); String xLabel = String.format("%.3f", data.get(i).getX()); FontMetrics metrics = g2.getFontMetrics(); int labelWidth = metrics.stringWidth(xLabel); g2.drawString(xLabel, x0 - labelWidth / 2, y0 + metrics.getHeight() + 3); } else if (i == data.size() - 1) { String xLabel = String.format("%.3f", data.get(i).getX()); FontMetrics metrics = g2.getFontMetrics(); int labelWidth = metrics.stringWidth(xLabel); g2.drawString(xLabel, x0 - labelWidth / 2, y0 + metrics.getHeight() + 3); } // g2.drawLine(x0, y0, x1, y1); } } // create x and y axes g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, padding + labelPadding, padding); g2.drawLine(padding + labelPadding, getHeight() - padding - labelPadding, getWidth() - padding, getHeight() - padding - labelPadding); Stroke oldStroke = g2.getStroke(); g2.setColor(lineColor); g2.setStroke(GRAPH_STROKE); g2.setStroke(oldStroke); g2.setColor(pointColor); for (int i = 0; i < graphPoints.size(); i++) { int x = graphPoints.get(i).x - pointWidth / 2; int y = graphPoints.get(i).y - pointWidth / 2; int ovalW = pointWidth; int ovalH = pointWidth; g2.fillOval(x, y, ovalW, ovalH); } } private void showPoint(ArrayList result) { if (jft != null) { // free old frame jft.dispose(); } jft = new JFText(result, 0, 50); jft.setVisible(true); } private ArrayList findPoint(Point2D mouse) { ArrayList bingo = new ArrayList<>(); for (ResidualPoint point : data) { Point pxPoint = new Point(getPixelX(point.getX()), getPixelY(point.getY())); double dist = pxPoint.distance(mouse.getX(), mouse.getY()); if (dist < accuracyRadius) { bingo.add(point.toString()); } } return bingo; } public double getRealX(double x) { return ((x - (double) getWidth() + padding) / getXScale()) + getMaxXData(); } public int getPixelX(double x) { return (int) ((double) getWidth() - padding - (getMaxXData() - x) * getXScale()); } public int getPixelY(double y) { return (int) ((getMaxYData() - y) * getYScale() + padding); } public double getRealY(double y) { return ((-y + padding) / getYScale()) + getMaxYData(); } private double getMinYData() { double minData = Double.MAX_VALUE; for (ResidualPoint point : data) { minData = Math.min(minData, point.getY()); } return minData; } private double getMaxYData() { double maxData = Double.MIN_VALUE; for (ResidualPoint point : data) { maxData = Math.max(maxData, point.getY()); } return maxData; } private double getMinXData() { double minData = Double.MAX_VALUE; for (ResidualPoint point : data) { minData = Math.min(minData, point.getX()); } return minData; } private double getMaxXData() { double maxData = Double.MIN_VALUE; for (ResidualPoint point : data) { maxData = Math.max(maxData, point.getX()); } return maxData; } public List getData() { return data; } public JFText getJFT() { return jft; } }sources/org/spview/point/PredJsynPoint.java000644 001750 001750 00000003067 13544613421 021730 0ustar00cyrilcyril000000 000000 package org.spview.point; /** * This class allows to sort prediction jsyn data. */ public class PredJsynPoint implements Comparable { private String jsyn; // assignment private int ind; // index before sort /** * Construct a new PredJsynPoint. * * @param cjsyn assignment * @param cind index before sort */ public PredJsynPoint(String cjsyn, int cind) { jsyn = cjsyn; // assignment ind = cind; // index before sort } ///////////////////////////////////////////////////////////////////// /** * Get prediction assignment string. */ public String getJsyn() { return jsyn; } /** * Get index before sort. */ public int getInd() { return ind; } /** * Compare following assignment string. * * @param cpjp the PredJsynPoint to compare to */ public int compareTo(Object cpjp) { if( ! (cpjp instanceof PredJsynPoint) ) { // not the right object throw new ClassCastException(); } int delta = ((PredJsynPoint)cpjp).getJsyn().compareTo(jsyn); // compare assignment strings if ( delta < 0 ) { return 1; } else if( delta > 0 ) { return -1; } return 0; // equal } } resources/pixmaps/text-x-spv.svg000644 001750 001750 00001020704 13544613421 017646 0ustar00cyrilcyril000000 000000 image/svg+xml sources/org/spview/filehandler/FortranFormat.java000644 001750 001750 00000007654 13544613421 023076 0ustar00cyrilcyril000000 000000 package org.spview.filehandler; import java.awt.geom.Point2D; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Locale; import javax.swing.JOptionPane; public class FortranFormat { /** * Format a frequency.
* F12.6 FORTRAN FORMAT
* WARNING : only positive values */ public static String formFreq(double cx) { StringBuffer sb; NumberFormat nff = NumberFormat.getNumberInstance(Locale.US); // ask a plain format DecimalFormat dff = (DecimalFormat) nff; // reduce to decimal format dff.applyPattern("00000.000000"); // define pattern sb = new StringBuffer(dff.format(cx)); // format for (int i = 0; i < sb.length(); i++) { if (sb.charAt(i) == '0') { sb.setCharAt(i, ' '); // replace leading 0s with spaces } else { // end of leading 0s break; } } return sb.toString(); } public static String formResidus(double cx) { StringBuffer sb; NumberFormat nff = NumberFormat.getNumberInstance(Locale.US); // ask a plain format DecimalFormat dff = (DecimalFormat) nff; // reduce to decimal format dff.applyPattern(".0000"); // define pattern sb = new StringBuffer(dff.format(cx)); // format if (sb.charAt(0) != '-') { // if not beginning with a - sb.insert(0, ' '); // insert a space } for (int i = 0; i < sb.length(); i++) { if (sb.charAt(i) == '0') { sb.setCharAt(i, ' '); // replace leading 0s with spaces } else { // end of leading 0s break; } } return sb.toString(); } /** * Format an intensity.
* E11.4 FORTRAN FORMAT */ public static String formInt(double cy) { StringBuffer sb; int ie; NumberFormat nfi = NumberFormat.getNumberInstance(Locale.US); // ask a plain format DecimalFormat dfi = (DecimalFormat) nfi; // reduce to decimal format dfi.applyPattern(".0000E00"); // define pattern sb = new StringBuffer(dfi.format(cy)); // format if (sb.charAt(0) != '-') { // if not beginning with a - sb.insert(0, ' '); // insert a space } ie = sb.indexOf("."); if (ie >= 0) { sb.insert(ie, '0'); // insert a 0 before the . } ie = sb.indexOf("E"); ie++; if (sb.charAt(ie) != '-') { // if positive exponent sb.insert(ie, '+'); // insert a + } return sb.toString(); } // return an blank string public static String bStr(int nbc) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < nbc; i++) { sb.append(" "); } return sb.toString(); } public static void printAssignmentFormattedOutput(ArrayList peakPositions, Point2D uncert, File file) { String lnsep = System.getProperty("line.separator"); PrintWriter out1 = null; try { out1 = new PrintWriter(file); for (int i = 0; i < peakPositions.size(); i++) { double x = peakPositions.get(i).getX(); double y = peakPositions.get(i).getY(); // NUO (5 char, RIGHT) String cStrNUO = " " + ("" + (i + 1)).trim(); cStrNUO = cStrNUO.substring(cStrNUO.length() - 5, cStrNUO.length()); String cStr = (" " + // ISP cStrNUO + // NUO line number FortranFormat.formFreq(x) + // FOBS frequency " " + FortranFormat.formInt(y) + // SOBS intensity " " + String.format("%9.6f %4.1f", uncert.getX(), uncert.getY()));// SDFOBS,SDSOBS frequency // and intensity // standard deviations string int l; for (l = cStr.length(); l > 0; l--) { if (cStr.charAt(l - 1) != ' ') { break; } } out1.println(cStr.substring(0, l)); // without extra spaces } } catch (IOException ioe) { // IO error JOptionPane.showMessageDialog(null, "IO error while writing file" + lnsep + ioe); return; } finally { // close the file if (out1 != null) { out1.close(); if (out1.checkError()) { JOptionPane.showMessageDialog(null, "PrintWriter error while creating exp file" + lnsep); return; } } } } } resources/JobPlay/jmiloadstick.html000644 001750 001750 00000000240 13544613421 020300 0ustar00cyrilcyril000000 000000

Load as stick

Load an XY peak list to plot it as sticks in the data area.

resources/PanAff/jmivalexppasy.html000644 001750 001750 00000000233 13544613421 020314 0ustar00cyrilcyril000000 000000

Scale

Pred-as-stick Y-axis zoom/unzoom by choosing a scaling factor.

test/SimpleErrorHandler.java000644 001750 001750 00000001127 13544613421 016753 0ustar00cyrilcyril000000 000000 import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; public class SimpleErrorHandler implements ErrorHandler { public void warning(SAXParseException e) throws SAXException { System.out.println("WARNING : " + e.getMessage()); } public void error(SAXParseException e) throws SAXException { System.out.println("ERROR : " + e.getMessage()); throw e; } public void fatalError(SAXParseException e) throws SAXException { System.out.println("FATAL ERROR : " + e.getMessage()); throw e; } }resources/JobPlay/jmicpf.html000644 001750 001750 00000000230 13544613421 017072 0ustar00cyrilcyril000000 000000

Create Peak File

Create peak file from one of the loaded spectra.

sources/org/spview/point/ResidualPoint.java000644 001750 001750 00000002335 13544613421 021737 0ustar00cyrilcyril000000 000000 package org.spview.point; import java.awt.geom.Point2D; import org.spview.filehandler.FortranFormat; public class ResidualPoint { private double x; private double y; private String attrib; public ResidualPoint(Point2D coordinates, String attribution) { this.x = coordinates.getX(); this.y = coordinates.getY(); this.attrib = attribution; } public ResidualPoint(double x, double y, String attribution) { this.x = x; this.y = y; this.attrib = attribution; } public double getX() { return this.x; } public double getY() { return this.y; } public String getAttrib() { return this.attrib; } public static double distanceSq(double x1, double y1, double x2, double y2) { x2 -= x1; y2 -= y1; return x2 * x2 + y2 * y2; } public static double distance(double x1, double y1, double x2, double y2) { return Math.sqrt(distanceSq(x1, y1, x2, y2)); } public double distance(double x, double y) { return distance(getX(), getY(), x, y); } public String toString() { String lnsep = System.getProperty("line.separator"); String strX = FortranFormat.formFreq(getX()); String strY = FortranFormat.formResidus(getY()); return "x=" + strX + ", delta=" + strY + " ass=" + getAttrib() + lnsep; } } resources/PanAff/000755 001750 001750 00000000000 13544613421 014534 5ustar00cyrilcyril000000 000000 resources/JobPlay/jmipred2null.html000644 001750 001750 00000000226 13544613421 020236 0ustar00cyrilcyril000000 000000

Deassociate prediction to data

Deassociate the prediction file.

resources/pixmaps/beg.png000644 001750 001750 00000002714 13544613421 016331 0ustar00cyrilcyril000000 000000 PNG  IHDR szzIDATXWOlTE}̼on!!)5ƐpQInƤQ&BbŃ P hlF B)Iٔ]oymN2o77C@B䉨Q'uhD4MDrID'W +7<P*fgQ!.!qp Ƙ>7 ...NlB3BRaF$N/0B}="RK)Z# 2qVvcuf/?R~,5|߇ڒ0M!u!Ļsss% ш`j$I(V5Za"+Y1f4)boI)UJ%PV8Rﶭ:rn7I*YZYy񚈠B^q;BWbzi#6n$R"+ǀ0>}lkց"Rq1}VJEM$<JWY}me'yᛱ1lݺM߃ !ԯR*#7˚5ˡ===fQݻŋܹ&.L^m`K$N b'ax)zz{!ʏ:;;1225޽fucIDY j3Msl`zz.tãu~#j 62DZ=Ws*cL}&._ĥK}\kh`||W\igm j:u 9) 4"?1;;`fah#"Dt7>h5 XslGqܿw?=| caa:ST*GDVvEZ뺨Vm[(JHd2<JY"zHDU$/u#V! uݗ\.jA'"d2T*(J) F(T*jφBdDDD%z <Ju]8sJ%0Ifv؜Z`x6ţGH$GJyrffNDsTJ2;&!D 7y*"A2D2D"P(#oD:fͯ<2j<\Zk,--!HDMJ)?윶}c>Sk0 aϊV"PJZ'O@J uܟH$&OOO7E+rlٲ"BzjY" CJZh_K)[y5۶m pMQj`W)%RvߖRuյ0{9ݾ};c|j9`V<3833iSٹsh/93y' ½/_TPIENDB`resources/PanAff/jmivalexpx.html000644 001750 001750 00000000215 13544613421 017607 0ustar00cyrilcyril000000 000000

Scale

X-axis zoom/unzoom by choosing a scaling factor.

resources/JobPlay/jmiyshift.html000644 001750 001750 00000000250 13544613421 017632 0ustar00cyrilcyril000000 000000

Y-shift

Y-shift of a data file. The shift area is defined through click and drag.

resources/PanAff/jmirestorepasy.html000644 001750 001750 00000000207 13544613421 020501 0ustar00cyrilcyril000000 000000

Scale

Restore the initial pred-as-stick Y scale.

sources/org/spview/filehandler/000755 001750 001750 00000000000 13544613421 017433 5ustar00cyrilcyril000000 000000 resources/JobPlay/jmiyunshift.html000644 001750 001750 00000000172 13544613421 020200 0ustar00cyrilcyril000000 000000

Y-unshift

Y-unshift of a data file.

resources/JobPlay/jmilpPICKETT.html000644 001750 001750 00000000300 13544613421 017757 0ustar00cyrilcyril000000 000000

Load prediction file

Load the prediction file in PICKETT format to plot it as ticks in the pred/exp area.

resources/JFSelPred/jmiaddassi.html000644 001750 001750 00000000315 13544613421 020154 0ustar00cyrilcyril000000 000000

Add pred assignment(s) to exp

Add the selected predictions as intensity assignments to the selected experimental peak.

resources/JobPlay/jmiyobscalc.html000644 001750 001750 00000000370 13544613421 020126 0ustar00cyrilcyril000000 000000

Obs.-Calc.

Display Y Obs.-Calc. data. It is possible to double-click on a data point, then the program goes to the corresponding area in order to check the line.

resources/JobPlay/jmiloadpeakas.html000644 001750 001750 00000000301 13544613421 020425 0ustar00cyrilcyril000000 000000

Load (as stick) peak/experiment file

Load a peak list in PKF format to plot it as sticks in the data area.

sources/org/spview/gui/JFSelPred.java000644 001750 001750 00000064565 13544613421 020403 0ustar00cyrilcyril000000 000000 package org.spview.gui; /* * Class to select predictions */ import java.awt.BorderLayout; import java.awt.Font; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.WindowEvent; import java.awt.event.WindowAdapter; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import org.spview.filehandler.FortranFormat; ///////////////////////////////////////////////////////////////////// /** * Window to select predictions. */ public class JFSelPred extends JFrame implements ActionListener, MouseListener { /** * */ private static final long serialVersionUID = 2287307861585753581L; // private JobPlay jobplay; // calling JobPlay private PanAff calling; // calling PanAff private double[] pfx; // frequency private double[] pfy; // intensity private String[] pfjsyn; // assignment string // panels private JPanel pcentre; private JScrollPane jsp; private int currentpos; // current position of vertical scroll bar // menus private JMenu jmpred; // select pred private JMenuItem jmipredall; // select all pred private JMenuItem jmipredno; // select no pred private JMenu jmls; // local simulation private JMenuItem jmilsshow; // show local simulation private JMenuItem jmilshide; // hide local simulation private JMenuItem jmilssetp; // set local simulation parameters private boolean locsim; // local simulation status private boolean lspending; // loc-sim pending private boolean lschecked; // loc-sim checked private boolean lsallowed; // loc-sim allowed private boolean lsscaleok; // loc-sim spectrum scaling factor private JMenu jmaddass; // add assignment private JMenuItem jmiaddassf; // add frequency assignment private JMenuItem jmiaddassi; // add intensity assignment // content private int nbixpred; // nb of (area) pred private JButton[] jbpred; // a button for each (area) pred private int ixdebpred; // (full) index of 1st (area) pred private int[] ixpreds; // (area) pred status >> -1: nothing(---), 0: already in exp(ASG), 1: selected(SEL) private int ixexp; // selected exp index private double[] predx; // (area) pred x private double[] predy; // (area) pred y private double umin; // area min frequency private double umax; // area max frequency private JFSimul jfs; // simulation manager private String lnsep; // line separator private String fisep; // file separator private Font mono14; // Monospaced 14 font ///////////////////////////////////////////////////////////////////// /** * Construct a JFSelPred to select predictions. * * @param ccall calling PanAff * @param cix0 location * @param ciy0 location * @param cpfx frequency * @param cpfy intensity * @param cpfjsyn assignment string */ public JFSelPred(PanAff ccall, int cix0, int ciy0, double[] cpfx, double[] cpfy, String[] cpfjsyn) { super("Predictions selection"); // main window setName("JFSelPred"); // for help files calling = ccall; // calling PanAff pfx = cpfx; // frequency pfy = cpfy; // intensity pfjsyn = cpfjsyn; // assignment string lnsep = System.getProperty("line.separator"); fisep = System.getProperty("file.separator"); mono14 = new Font("Monospaced", Font.PLAIN, 14); currentpos = 0; // current position of vertical scroll bar lschecked = false; // loc-sim NOT checked lsallowed = false; // loc-sim NOT allowed addWindowListener(new WindowAdapter() { // clean end public void windowClosing(WindowEvent e) { if( locsim ) { jmilshide.doClick(); // hide local simulation } calling.endSelPred(); // end prediction selection dispose(); // free window } }); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); setLocation(cix0, ciy0); setSize(650,200); jfs = new JFSimul( this, cix0, ciy0+getSize().height+10 ); // simulation manager // MENUS JMenuBar jmb = new JMenuBar(); // select all jmpred = new JMenu("Select"); jmipredall = new JMenuItem("All"); jmipredall.setEnabled(false); jmipredall.addActionListener(this); jmpred.add(jmipredall); jmipredno = new JMenuItem("No"); jmipredno.setEnabled(false); jmipredno.addActionListener(this); jmpred.add(jmipredno); // local simulation jmls = new JMenu("Local simulation"); jmilsshow = new JMenuItem("Show"); jmilsshow .addActionListener(this); jmls.add(jmilsshow ); jmilshide = new JMenuItem("Hide"); jmilshide .addActionListener(this); jmls.add(jmilshide ); jmilssetp = new JMenuItem("Set parameters"); jmilssetp .addActionListener(this); jmls.add(jmilssetp ); // add assignment jmaddass = new JMenu("Add pred assignment(s) to exp"); jmaddass.setEnabled(false); // related to frequency jmiaddassf = new JMenuItem("frequency"); jmiaddassf.addActionListener(this); jmaddass.add(jmiaddassf); // related to intensity jmiaddassi = new JMenuItem("intensity"); jmiaddassi.addActionListener(this); jmaddass.add(jmiaddassi); jmb.add(jmpred); jmb.add(jmls); jmb.add(jmaddass); setJMenuBar(jmb); // set menu bar getContentPane().setLayout(new BorderLayout()); // panels jsp = new JScrollPane( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); getContentPane().add(jsp,"Center"); setVisible(false); } ///////////////////////////////////////////////////////////////////// /** * Show area selected predictions. * * @param cnbixpred nb of (area) pred * @param cixdebpred (full) index of 1st (area) pred * @param cixpreds (area) pred status >> -1: nothing(---), 0: already assigned(ASG), 1: selected(SEL) * @param cixexp selected exp index */ public void setContent( int cnbixpred, int cixdebpred, int[] cixpreds, int cixexp ) { nbixpred = cnbixpred; // nb of (area) pred ixdebpred = cixdebpred; // (full) index of 1st (area) pred ixpreds = cixpreds; // (area) pred status ixexp = cixexp; // selected exp index if( nbixpred == 0 ) { // nothing to show setVisible(false); } else { jbpred = new JButton[nbixpred]; // for each point int nbsable = 0; // nb of selectable pred int nbassi = 0; // nb of assigned pred pcentre = new JPanel( new GridLayout(Math.max(5,nbixpred),1,0,0) ); // at least 5 lines // create prediction buttons for( int j=0; j= 0 ) { predx[curi] = pfx[i]; predy[curi] = pfy[i]; curi ++; } } } else { jmipredno.setEnabled(false); } // show running loc-sim if( locsim ) { if( nbsassi == 0 ) { // nothing to show calling.setLocSim(false); jmls.setEnabled(false); } else { // some are selected or assigned if( jfs.calLocSim( predx, predy ) ) { // loc-sim calculated // show it calling.setLocSim(locsim); } else { // nothing to show calling.setLocSim(false); } jmls.setEnabled(true); } } else { // NO running loc-sim if( nbsassi == 0 ) { // NO selected or assigned pred jmls.setEnabled(false); } else { if( lschecked && ! lsallowed ) { // loc-sim NOT allowed jmls.setEnabled(false); } else { jmls.setEnabled(true); } } } // Add pred assignment(s) to exp if( ixexp < 0 || nbs == 0 ) { // no exp selected or no pred selected jmaddass.setEnabled(false); } else { jmaddass.setEnabled(true); } // update view jsp.setViewportView(pcentre); jsp.getVerticalScrollBar().setValue(currentpos); // at the right position } ///////////////////////////////////////////////////////////////////// // Mouse events are managed to show in Panaff (yellow square) // which pred is currently pointed by mouse (by its index) /** * Process Mouse event. */ public void mouseEntered(MouseEvent mevt) { for( int j=0; j

Reset all

Cancels all the hide, move and rescale actions on data files.

test/000755 001750 001750 00000000000 13544613421 012346 5ustar00cyrilcyril000000 000000 sources/org/spview/filehandler/PickettFile.java000644 001750 001750 00000002056 13544613421 022504 0ustar00cyrilcyril000000 000000 package org.spview.filehandler; import java.awt.geom.Point2D; public class PickettFile { public static Point2D extractXY(String str) { double cx, cy; try { cx = Double.valueOf(str.substring(0, 13)); // Double for X Double.valueOf(str.substring(13, 21).trim()); // validity test cy = Math.pow(10, Double.valueOf(str.substring(21, 29))); // Double for Y Integer.parseInt(str.substring(29, 31).trim()); // validity test Double.valueOf(str.substring(31, 41).trim()); // validity test Integer.parseInt(str.substring(41, 44).trim()); // validity test Double.valueOf(str.substring(44, 51).trim()); // validity test Integer.parseInt(str.substring(51, 55).trim()); // validity test } catch (NumberFormatException e) { // format error return null; } return (new Point2D.Double(cx, cy)); } public static String extractAssignment(String str) { return str.substring(55, 57) + " " + str.substring(57, 59) + " " + str.substring(59, 61) + " " + str.substring(67, 69) + " " + str.substring(69, 71) + " " + str.substring(71, 73); } } resources/JobPlay/jmicloseproject.html000644 001750 001750 00000000205 13544613421 021020 0ustar00cyrilcyril000000 000000

Close Project

Close all data opened in SPVIEW.

resources/JobPlay/jmixobscalc.html000644 001750 001750 00000000370 13544613421 020125 0ustar00cyrilcyril000000 000000

Obs.-Calc.

Display X Obs.-Calc. data. It is possible to double-click on a data point, then the program goes to the corresponding area in order to check the line.

sources/org/spview/gui/000755 001750 001750 00000000000 13544613421 015742 5ustar00cyrilcyril000000 000000 sources/org/spview/residuals/000755 001750 001750 00000000000 13544613421 017151 5ustar00cyrilcyril000000 000000 sources/org/spview/point/ExpXPoint.java000644 001750 001750 00000015525 13544613421 021060 0ustar00cyrilcyril000000 000000 package org.spview.point; /** * This class allows to sort experimental data following frequency order. */ public class ExpXPoint implements Comparable { private String nuo; // line number string private double x; // frequency private String faso; // frequency mark private double y; // intensity private String saso; // intensity mark private String sdobs; // frequency and intensity standard deviations private String jsyn; // assignment private String exasg; // EXASG selection string private String comm; // comment private int inuo; // line number int private double sdfreq; // frequency standard deviation private double sdint; // intensity standard deviation /** * Construct a new ExpXPoint. * * @param cnuo line number * @param cx frequency * @param cfaso frequency mark * @param cy intensity * @param csaso intensity mark * @param csdobs frequency and intensity standard deviations * @param cjsyn assignment * @param cexasg EXASG selection string * @param ccomm comment */ public ExpXPoint(String cnuo, double cx, String cfaso, double cy, String csaso, String csdobs, String cjsyn, String cexasg, String ccomm) { nuo = cnuo; // line number x = cx; // frequency faso = cfaso; // frequency mark y = cy; // intensity saso = csaso; // intensity mark sdobs = csdobs; // frequency and intensity standard deviations jsyn = cjsyn; // assignment exasg = cexasg; // EXASG selection string comm = ccomm; // comment try { inuo = Integer.parseInt(nuo.trim()); } catch (NumberFormatException e) { // format error } // already tested if( sdobs.length() == 0 ) { sdfreq = 0.; sdint = 0.; } else { try { sdfreq = Double.parseDouble(sdobs.substring(0,10)); } catch (NumberFormatException e) { } // already tested try { sdint = Double.parseDouble(sdobs.substring(10,16)); } catch (NumberFormatException e) { } // already tested } } ///////////////////////////////////////////////////////////////////// /** * Get line number. */ public String getNuo() { return nuo; } /* * Get line number (int). */ public int getInuo() { return inuo; } /** * Get frequency. */ public double getX() { return x; } /** * Get frequency mark. */ public String getFaso() { return faso; } /** * Get intensity. */ public double getY() { return y; } /** * Get intensity mark. */ public String getSaso() { return saso; } /** * Get freqency and intensity standard deviations. */ public String getSdobs() { return sdobs; } /* * Get frequency standard deviation. */ public double getSdfreq() { return sdfreq; } /* * Get intensity standard deviation. */ public double getSdint() { return sdint; } /** * Get assignment. */ public String getJsyn() { return jsyn; } /** * Get EXASG selection string. */ public String getExasg() { return exasg; } /** * Get comment. */ public String getComm() { return comm; } /** * Compare according to x, nuo, y, sdfreq then sdint * * @param cexpt the ExpXPoint to compare to */ public int compareTo(Object cexpt) { if( ! (cexpt instanceof ExpXPoint) ) { // not the right object throw new ClassCastException(); } double xc = ((ExpXPoint)cexpt).getX(); int inuoc = ((ExpXPoint)cexpt).getInuo(); double yc = ((ExpXPoint)cexpt).getY(); double sdfreqc = ((ExpXPoint)cexpt).getSdfreq(); double sdintc = ((ExpXPoint)cexpt).getSdint(); int idelta; double delta; delta = xc - x; // frequency if ( delta < 0 ) { return 1; } else if( delta > 0 ) { return -1; } else { idelta = inuoc - inuo; // line number if ( idelta < 0 ) { return 1; } else if( idelta > 0 ) { return -1; } else { delta = yc - y; // intensity if ( delta < 0 ) { return 1; } else if( delta > 0 ) { return -1; } else { delta = sdfreqc - sdfreq; // frequency standard deviation if ( delta < 0 ) { return 1; } else if( delta > 0 ) { return -1; } else { delta = sdintc - sdint; // intensity standard deviation if ( delta < 0 ) { return 1; } else if( delta > 0 ) { return -1; } } } } } return 0; // equal } } resources/PanAff/jmivalexpy.html000644 001750 001750 00000000215 13544613421 017610 0ustar00cyrilcyril000000 000000

Scale

Y-axis zoom/unzoom by choosing a scaling factor.

sources/org/spview/gui/JFFileOut.java000644 001750 001750 00000013471 13544613421 020402 0ustar00cyrilcyril000000 000000 package org.spview.gui; /* * Class to show a text file content */ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Font; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; ///////////////////////////////////////////////////////////////////// /** * Window to show a text file content. */ public class JFFileOut extends JFrame implements Runnable { /** * */ private static final long serialVersionUID = 6788894636251358665L; private String nfil; // file name // panels private JPanel pcentre; // to show the string array private JScrollPane jsp; // with lifts private JTextArea jta; // thread private volatile Thread threadThis; // volatile for clean exit private String lnsep; // line separator private Font mono14; // Monospaced 14 font ///////////////////////////////////////////////////////////////////// /** * Constructs a JFFileOut. * * @param cnfil file name * @param cp_x x location of frame * @param cp_y y location of frame */ public JFFileOut( String cnfil, int cp_x, int cp_y ) { super(cnfil); // main window addWindowListener(new WindowAdapter() { // clean end public void windowClosing(WindowEvent e) { threadThis = null; // clean exit flag dispose(); // free window } }); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); if( cnfil.trim().length() == 0 ) { // empty file name dispose(); return; } nfil = cnfil; // file name mono14 = new Font("Monospaced", Font.PLAIN, 14); lnsep = System.getProperty("line.separator"); getContentPane().setLayout(new BorderLayout()); JPanel jp = new JPanel(new BorderLayout()); jp.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.BLUE,4),null)); getContentPane().add(jp,"Center"); // panels pcentre = new JPanel(); // center jta = new JTextArea(); jta.setColumns(70); // jta width jta.setBackground(Color.BLACK); jta.setForeground(Color.WHITE); jta.setEditable(false); // not editable jta.setFont( mono14 ); jta.setLineWrap(false); // no line wrap jta.setRows(10); // nb of lines jsp = new JScrollPane(jta, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); // with lifts pcentre.add(jsp); // insert panels jp.add(pcentre,"Center"); // launch thread for read and display file threadThis = new Thread(this); // set thread (run of this instance) threadThis.start(); // launch it setLocation( cp_x/2, cp_y/2 ); pack(); } /** * Thread launched by start. *
Wait for file to exist *
Display it's content while it grows */ public void run() { // file read variables FileReader fr; BufferedReader br; File ffil; String str; Thread currenT = Thread.currentThread(); // get current thread // wait for file to exist jta.append("Please, wait "); ffil = new File(nfil); while( ! ffil.exists() ) { // window closed ? if( threadThis != currenT ) { // yes, exit return; } try{ //wait(1000); Thread.sleep(1000); // every second } catch(InterruptedException e) { e.printStackTrace(); } jta.append("."); } jta.setText(""); // empty text area // read file as it grows try { fr = new FileReader( ffil ); br = new BufferedReader( fr ); while( true ) { // indefinitly // window closed ? if( threadThis != currenT ) { // yes, clean exit br.close(); // free file access return; } if( (str = br.readLine()) != null ) { // some line to display jta.append(str+"\n"); } else { try{ //wait(1000); Thread.sleep(1000); // every second } catch(InterruptedException e) { e.printStackTrace(); } } } } catch (IOException ioe) { // IO error JOptionPane.showMessageDialog(null, "IO error while reading file" + lnsep + ffil + lnsep + ioe); } } } resources/PanAff/jmirestorey.html000644 001750 001750 00000000171 13544613421 017775 0ustar00cyrilcyril000000 000000

Scale

Restore the initial Y scale.

resources/pixmaps/000755 001750 001750 00000000000 13544613421 015062 5ustar00cyrilcyril000000 000000 resources/PanAff/jmicomm.html000644 001750 001750 00000000153 13544613421 017054 0ustar00cyrilcyril000000 000000

Comment

Set comment.

resources/JobPlay/jmiloadpickettas.html000644 001750 001750 00000000306 13544613421 021155 0ustar00cyrilcyril000000 000000

Load (as stick) prediction file

Load a prediction file in PICKETT format to plot it as sticks in the data area.

sources/org/spview/peakfinding/DigitalFilter.java000644 001750 001750 00000004244 13544613421 023027 0ustar00cyrilcyril000000 000000 package org.spview.peakfinding; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.Arrays; public class DigitalFilter { public static boolean debug = false; public static ArrayList findPeaks(double[] x, double[] y, double pt, double cutoff, int filterWidth) { int nPeaks = 0; pt = (pt >= 0 ? 1 : -1); /* set a single-cycle square of width filterWidth */ double[] filter = new double[filterWidth]; Arrays.fill(filter, 1.0); Arrays.fill(filter, (int) Math.ceil(filterWidth / 2.0), filterWidth, -1.0); if (Math.ceil(filterWidth / 2.0) > (filterWidth / 2.0)) filter[(int) Math.floor(filterWidth / 2.0)] = 0.0; int offset = (int) Math.ceil((filterWidth - 1) / 2.0); double[] yConv = convolve(y, filter); for (int index = 0; index < yConv.length - 1; index += 1) { if (yConv[index] * yConv[index + 1] < 0) { if ((pt * y[index - offset] >= pt * cutoff) && ((yConv[index + 1] - yConv[index]) * pt < 0)) { nPeaks++; } } } if (nPeaks == 0) { System.out.println("Screwup - no peaks were located"); return null; } ArrayList peakList = new ArrayList<>(); nPeaks = 0; for (int index = 0; index < yConv.length - 1; index += 1) { if (yConv[index] * yConv[index + 1] < 0) { if ((pt * y[index - offset] >= pt * cutoff) && ((yConv[index + 1] - yConv[index]) * pt < 0)) { // Interpolate the peak position int peak = (int) Math.abs(yConv[index] / (yConv[index] - yConv[index + 1])) + index - offset; Point2D XY = new Point2D.Double(x[peak], y[peak]); if (debug) System.out.println(XY); peakList.add(XY); nPeaks += 1; } } } return peakList; } private static double[] convolve(double[] x, double[] h) { final int xLen = x.length; final int hLen = h.length; // initialize the output array final int totalLength = xLen + hLen - 1; final double[] y = new double[totalLength]; // straightforward implementation of the convolution sum for (int n = 0; n < totalLength; n++) { double yn = 0; int k = Math.max(0, n + 1 - xLen); int j = n - k; while (k < hLen && j >= 0) { yn += x[j--] * h[k++]; } y[n] = yn; } return y; } } resources/JFSelPred/000755 001750 001750 00000000000 13544613421 015157 5ustar00cyrilcyril000000 000000 sources/org/spview/gui/JFnewText.java000644 001750 001750 00000014662 13544613421 020474 0ustar00cyrilcyril000000 000000 package org.spview.gui; /* * Class to choose a string and return it to a method (PanAff.addExasg or PanAff.setComm) */ import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.Box; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextField; ///////////////////////////////////////////////////////////////////// /** * Window to define a new string. */ public class JFnewText extends JFrame implements ActionListener { /** * */ private static final long serialVersionUID = -523507943384721497L; private PanAff calling; // calling PanAff private String type; // string type private String init; // initial string private int ixexp; // exp data index private int iass; // related assignment index // panels private JPanel pcentre; private JPanel psud; // buttons private JButton jbcancel; private JButton jbset; // to get the string private JTextField jtf; private String str; private String lnsep; // line separator ///////////////////////////////////////////////////////////////////// /** * Construct a JFnewText for a new EXASG. * * @param ccall calling PanAff */ public JFnewText( PanAff ccall ) { super("New EXASG"); // main window calling = ccall; // calling PanAff type = "exasg"; // string type init = ""; // initial string lnsep = System.getProperty("line.separator"); setwin(); // set the window } /** * Construct a JFnewText for a comment. * * @param ccall calling PanAff * @param cinit initial string * @param cixexp exp data index * @param ciass related assignment index */ public JFnewText( PanAff ccall, String cinit, int cixexp, int ciass ) { super("New comment"); // main window calling = ccall; // calling PanAff type = "comm"; // string type init = cinit; // initial string ixexp = cixexp; // exp data index iass = ciass; // related assignment index setwin(); // set the window } // set the window private void setwin() { addWindowListener(new WindowAdapter() { // clean end public void windowClosing(WindowEvent e) { dispose(); // free window } }); setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); setLocation(100,100); // location getContentPane().setLayout(new BorderLayout()); JPanel jp = new JPanel(new BorderLayout()); getContentPane().add(jp,"Center"); // panels pcentre = new JPanel(); psud = new JPanel(); // center jtf = new JTextField(Math.max(30, init.length())); jtf.setText(init); pcentre.add(jtf); // south jbcancel = new JButton("Cancel"); jbcancel.setToolTipText("Cancel text setting"); jbcancel.addActionListener(this); jbset = new JButton("Set"); jbset.setToolTipText("Set text"); jbset.addActionListener(this); Box boxsud = Box.createHorizontalBox(); // add buttons to box boxsud.add(jbcancel); boxsud.add(Box.createHorizontalStrut(15)); boxsud.add(jbset); psud.add(boxsud); // insert panels jp.add(pcentre,"Center"); jp.add(psud, "South"); pack(); } ///////////////////////////////////////////////////////////////////// /** * Process events. */ public void actionPerformed(ActionEvent evt) { // cancel if( evt.getSource() == jbcancel ) { dispose(); // free window return; } // accept if( evt.getSource() == jbset ) { // exasg if( type.equals("exasg") ) { str = jtf.getText().trim(); // without extra spaces if( str.length() > 30 ) { // troncate to 30 chars (FORMAT 3000 of eq_tds.f) int n = JOptionPane.showConfirmDialog(null,"Do you agree to troncate the string to"+lnsep+ ">>>"+str.substring(0,30)+"<<<", "String too long", JOptionPane.YES_NO_OPTION); if(n == JOptionPane.NO_OPTION) { // nothing to do return; } } str = str+ " "+ " "+ " "; // complete end of string with spaces str = str.substring(0,30); // troncate string calling.addExasg(str); // call method to set exasg dispose(); // free window } // comm else if( type.equals("comm") ) { str = jtf.getText().trim(); // without extra spaces calling.setComm( str, ixexp, iass ); // call method to set comment dispose(); // free window } } } } resources/pixmaps/equal.png000644 001750 001750 00000006253 13544613421 016705 0ustar00cyrilcyril000000 000000 PNG  IHDR szzzTXtRaw profile type exifxڭi^a9`^~ŽȬȬw:\ecAWSH5TS:4~qOOAx5{~C rާN=~w^99mf}y0_'3pp/vJ@PC㙹$8"37ع xvg(ܑ Fyx#4'0Ƒ vkּk1TrQS(^2qW*x؀u:_s?Ob))aJȸIv%z NX 婋} 'LlY Zz4jsvguc}9^ 0悁]os`Wh< e|#>#dOCs Q: xU- DB"v6ksEZ BC"ldŨOj4:UMhՖBISJ9Yj95s5J,ZRɥZZHaZSͮZkkغ1.=ص{鵷9g:Yz!# (6ĕf:̳:VXqJ+jOnV?03kf{^` qΏ-5`Ll b(ƜqvT!(T`ͫ31qz}0#oNMcusΨ7+JYGX$6&Ҥ4I>uQJBBE٢3#ibVa ņiأX OO݇:4ő*`aׁ^ld &ՍW٧ime\ŏ`ѣR4N>[x܆ ?$/Mn/ZmE(jMBJsfx= r2 i#ŁTt CQ蕂&QT{r'2Y9wsŃ<IV|&~0 R>:sd; h?Xq lE"#w9eT6BbӴ0cH͈-NgkYOes[QKԊd&#gS[JF~AȐ'X@ƾjZ6r a%e<,` <N_?jIο¶j€KNoQUsjHj)99MH+)ç-4 i88lfQ _>L_;wǚ`}-ŗ,%sf]EM"6оgQUbLszlw `݁ 4Fj],+]jtο^ytڠفpw#͎n$l]]Mq-zfUSWe]?Ss0 ={xy1PB%ޚ,2 Vo&R.[jՋ8[:5ٺl}4H\7M{}V8;epa+0~l>Q'HZ5[td꺱{d+}sIZu8z Isf*3[VwmUC*B5rXp'ȎtXƕ(QgFxbKGD pHYs.#.#x?vtIME ( 9,IDATXåWkW|̆DdCRZh*^SުG/(hz(E ࡭*SEw7;3}=3l ٝy|?&jZSUuJU'TTuQUWkGi7VAUqU}%"RD2,"zii۶m/"gUu  {o" k0塡SVRf cL. ՉCU \Z`ǎ|+"G(3/ά1VpeU= YcccߋȑOs̫gJ3qAq틪e˖3">1E1A(wAV`||U$I9=0sn7]{$IJ4E{011z9]r,'Z0 trcg2]8`" µlBU킘$93"0 @,& Ci1ݻG4]t:tPU$I7iY$ 4j(jrD#Ul߾i){lZCD"<}U%}}yg'N CA018} hR> `gV݌1ySf}v3FD;-d._k._ƟOH*ȥ;w][~&.A"n9fܣ Dcq!8yA718u4fΝie72b9 zXA8'I(GDhfVʲ`)\vuU 23߿ߗuliyZ+ZrRn@BZs|WHvݿ(Wl6Qy7Ty"I6LD_>x3a^_#̌Ow-(C!0 krrr%""{<>Vn[XXXtnWAO76IENDB`