001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.nbio.structure.align.gui.aligpanel;
022
023import org.biojava.nbio.structure.Atom;
024import org.biojava.nbio.structure.StructureException;
025import org.biojava.nbio.structure.align.gui.DisplayAFP;
026import org.biojava.nbio.structure.align.gui.JPrintPanel;
027import org.biojava.nbio.structure.align.gui.MenuCreator;
028import org.biojava.nbio.structure.align.gui.StructureAlignmentDisplay;
029import org.biojava.nbio.structure.align.gui.jmol.AbstractAlignmentJmol;
030import org.biojava.nbio.structure.align.gui.jmol.JmolTools;
031import org.biojava.nbio.structure.align.gui.jmol.StructureAlignmentJmol;
032import org.biojava.nbio.structure.align.model.AFPChain;
033import org.biojava.nbio.structure.align.model.AfpChainWriter;
034import org.biojava.nbio.structure.align.util.AFPAlignmentDisplay;
035import org.biojava.nbio.structure.align.util.AtomCache;
036import org.biojava.nbio.structure.align.util.UserConfiguration;
037import org.biojava.nbio.structure.align.webstart.WebStartMain;
038import org.biojava.nbio.structure.align.xml.AFPChainXMLParser;
039import org.biojava.nbio.structure.gui.events.AlignmentPositionListener;
040import org.biojava.nbio.structure.gui.util.AlignedPosition;
041import org.biojava.nbio.structure.gui.util.color.ColorUtils;
042
043import java.awt.*;
044import java.awt.event.ActionEvent;
045import java.awt.event.WindowEvent;
046import java.awt.event.WindowListener;
047import java.io.BufferedReader;
048import java.io.FileReader;
049import java.util.BitSet;
050import java.util.List;
051
052
053/** A JPanel that can display an AFPChain in a nice way and interact with Jmol.
054 *
055 * @author Andreas Prlic
056 *
057 */
058public class AligPanel  extends JPrintPanel implements AlignmentPositionListener, WindowListener{
059
060        /**
061         *
062         */
063        private static final long serialVersionUID = -6892229111166263764L;
064
065        private AFPChain afpChain;
066        private AFPChainCoordManager coordManager ;
067        private Font seqFont;
068        private Font eqFont;
069        private AbstractAlignmentJmol jmol;
070        private AligPanelMouseMotionListener mouseMoLi;
071
072        private BitSet selection;
073
074        private boolean selectionLocked;
075        private Atom[] ca1;
076        private Atom[] ca2;
077
078        private boolean colorBySimilarity;
079
080        private boolean colorByAlignmentBlock;
081
082        private static final Color COLOR_EQUAL   = Color.decode("#6A93D4");
083        private static final Color COLOR_SIMILAR = Color.decode("#D460CF");
084
085
086        public static void main(String[] args){
087
088                String file = "/Users/ap3/tmp/4hhb.ce";
089
090                try {
091                        BufferedReader in = new BufferedReader(new FileReader(file));
092                        StringBuffer xml = new StringBuffer();
093                        String str;
094                        while ((str = in.readLine()) != null) {
095                                xml.append(str);
096                        }
097                        in.close();
098
099                        AFPChain[] afps = AFPChainXMLParser.parseMultiXML(xml.toString());
100                        AFPChain afpChain = afps[0];
101
102                        UserConfiguration config = WebStartMain.getWebStartConfig();
103                        AtomCache cache = new AtomCache(config.getPdbFilePath(),config.getCacheFilePath());
104
105                        Atom[] ca1 = cache.getAtoms(afpChain.getName1());
106                        Atom[] ca2 = cache.getAtoms(afpChain.getName2());
107
108                        AFPChainXMLParser.rebuildAFPChain(afpChain, ca1, ca2);
109
110
111                        //StructureAlignment algorithm = StructureAlignmentFactory.getAlgorithm(afpChain.getAlgorithmName());
112                        StructureAlignmentJmol jmol= StructureAlignmentDisplay.display(afpChain, ca1, ca2);
113
114                        DisplayAFP.showAlignmentPanel(afpChain, ca1, ca2, jmol);
115
116
117
118
119                } catch (Exception e){
120                        e.printStackTrace();
121                }
122        }
123
124
125        public AligPanel(){
126                super();
127                this.setBackground(Color.white);
128                coordManager = new AFPChainCoordManager();
129                seqFont = new Font("SansSerif",Font.PLAIN,12);
130                eqFont = new Font("SansSerif",Font.BOLD,12);
131
132                mouseMoLi = new AligPanelMouseMotionListener(this);
133                this.addMouseMotionListener(mouseMoLi);
134                this.addMouseListener(mouseMoLi);
135                mouseMoLi.addAligPosListener(this);
136
137                selection = new BitSet();
138                colorBySimilarity = false;
139                colorByAlignmentBlock = false;
140        }
141
142
143
144        public AFPChainCoordManager getCoordManager() {
145                return coordManager;
146        }
147
148
149        public void addAlignmentPositionListener(AlignmentPositionListener li){
150                mouseMoLi.addAligPosListener(li);
151        }
152
153        public void destroy(){
154
155                setAFPChain(null);
156                mouseMoLi.destroy();
157                jmol = null;
158                ca1 = null;
159                ca2 = null;
160                selection = null;
161        }
162
163        public AFPChain getAFPChain(){
164                return afpChain;
165        }
166
167        public void setAFPChain(AFPChain afpChain) {
168
169                this.afpChain = afpChain;
170                coordManager.setAFPChain(afpChain);
171                if ( afpChain != null) {
172                        selection = new BitSet (afpChain.getAlnLength());
173                        if ( afpChain.getBlockNum() > 1) {
174                                colorByAlignmentBlock = true;
175                        }
176                }
177
178        }
179
180
181@Override
182public void paintComponent(Graphics g){
183
184                super.paintComponent(g);
185
186                Graphics2D g2D = (Graphics2D) g;
187
188
189                g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
190                                RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
191
192                g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
193                                RenderingHints.VALUE_ANTIALIAS_ON);
194
195
196                // only draw within the ranges of the Clip
197                //Rectangle drawHere = g2D.getClipBounds();
198
199
200                //int startpos = coordManager.getSeqPos(0,drawHere.x);
201                //int endpos   = coordManager.getSeqPos(0,drawHere.x+drawHere.width-2);
202
203
204                char[] seq1 = afpChain.getAlnseq1();
205                char[] seq2 = afpChain.getAlnseq2();
206                char[] symb = afpChain.getAlnsymb();
207
208                int startpos = 0;
209                int endpos = afpChain.getAlnLength();
210
211                String summary = afpChain.toString();
212                g2D.drawString(summary, 20, coordManager.getSummaryPos());
213
214                Color significantCol = Color.red;
215                if ( afpChain.isSignificantResult())
216                        significantCol = Color.green;
217
218                g2D.setPaint(significantCol);
219                // draw a darker backgroun
220                Rectangle sig = new Rectangle(10,10,10,10);
221                g2D.fill(sig);
222                boolean isFATCAT = false;
223                if ( afpChain.getAlgorithmName().startsWith("jFatCat")){
224                        isFATCAT = true;
225                }
226                for ( int i = startpos ; ((i <= endpos) && ( i < afpChain.getAlnLength())) ;i++){
227
228                        // TODO:
229                        // color amino acids by hydrophobicity
230                        char c1 = seq1[i];
231                        char c2 = seq2[i];
232                        boolean isGapped = false;
233                        g2D.setFont(seqFont);
234
235                        List<Integer> alignedPos = null;
236                        if ( colorByAlignmentBlock){
237                                alignedPos = DisplayAFP.getEQRAlignmentPos(afpChain);
238                        }
239                        if ( isFATCAT){
240                                char s = symb[i];
241                                if ( s != ' ') {
242                                        isGapped = false;
243                                        g2D.setFont(eqFont);
244                                }
245                                else
246                                        isGapped = true;
247                        } else {
248                        char s = symb[i];
249                                if ( c1 !=  '-' && c2 != '-' && s!= ' '){
250                                        // no gap
251                                        g2D.setFont(eqFont);
252                                } else {
253                                        isGapped = true;
254
255                                }
256                        }
257
258                        Point p1 = coordManager.getPanelPos(0,i);
259                        int xpos1 = p1.x;
260                        int ypos1 = p1.y;
261                        Point p2 = coordManager.getPanelPos(1, i);
262                        int xpos2 = p2.x;
263                        int ypos2 = p2.y;
264                        int blockNum = afpChain.getBlockNum();
265                        if (! isGapped) {
266                                Color bg = Color.white;
267                                Color bg2 = Color.white;
268                                Color end1 = ColorUtils.rotateHue(ColorUtils.orange,  (1.0f  / 24.0f) * blockNum  );
269                                Color end2 = ColorUtils.rotateHue(ColorUtils.cyan,    (1.0f  / 24.0f) * (blockNum  +1)) ;
270
271                                if ( colorByAlignmentBlock) {
272
273                                        if (! alignedPos.contains(i)){
274
275                                                // unaligned!
276                                                bg = Color.white;
277                                                bg2 = Color.white;
278                                        } else  {
279
280                                                int colorPos = 0;
281                                                if (isFATCAT) {
282                                                        int block = 0;
283                                                        char s = symb[i];
284                                                        try {
285                                                                block = Integer.parseInt(String.valueOf(s)) - 1;
286                                                                bg  = ColorUtils.getIntermediate(ColorUtils.orange, end1, blockNum, block);
287                                                                bg2   = ColorUtils.getIntermediate(ColorUtils.cyan, end2, blockNum, block);
288                                                                //bg = ColorUtils.rotateHue(ColorUtils.orange,  (1.0f  / 24.0f) * block  );
289                                                                //bg2 = ColorUtils.rotateHue(ColorUtils.cyan,  (1.0f  / 16.0f) * block );
290                                                        } catch (Exception e){}
291
292                                                        if ( colorPos > ColorUtils.colorWheel.length){
293                                                                colorPos = ColorUtils.colorWheel.length % colorPos ;
294                                                        }
295                                                } else {
296                                                  colorPos = AFPAlignmentDisplay.getBlockNrForAlignPos(afpChain, i);
297                                                  bg  = ColorUtils.getIntermediate(ColorUtils.orange, end1, blockNum, colorPos);
298                                                  bg2   = ColorUtils.getIntermediate(ColorUtils.cyan, end2, blockNum, colorPos);
299                                                  //bg = ColorUtils.rotateHue(ColorUtils.orange,  (1.0f  / 24.0f) * colorPos );
300                                                  //bg2 = ColorUtils.rotateHue(ColorUtils.cyan,  (1.0f  / 16.0f) * colorPos);
301                                                }
302
303                                        }
304                                } else {
305
306                                        bg = Color.LIGHT_GRAY;
307                                        bg2 = Color.LIGHT_GRAY;
308                                }
309
310                                // draw a darker background
311                                g2D.setPaint(bg);
312                                Rectangle rec = new Rectangle(p1.x-1,p1.y-11, (p2.x-p1.x)+12, (p2.y-p1.y)+1);
313                                g2D.fill(rec);
314                                g2D.setPaint(bg2);
315                                Rectangle rec2 = new Rectangle(p1.x-1,p1.y+4, (p2.x-p1.x)+12, (p2.y-p1.y)-3);
316                                g2D.fill(rec2);
317
318                                //g2D.setPaint(Color.black);
319                                //g2D.draw(rec);
320                        }
321                        if ( colorBySimilarity){
322                                if ( c1 == c2){
323                                        Color bg = COLOR_EQUAL;
324                                        g2D.setPaint(bg);
325                                        Rectangle rec = new Rectangle(p1.x-1,p1.y-11, (p2.x-p1.x)+12, (p2.y-p1.y)+12);
326                                        g2D.fill(rec);
327                                } else if (AFPAlignmentDisplay.aaScore(c1, c2) > 0) {
328                                        Color bg = COLOR_SIMILAR;
329                                        g2D.setPaint(bg);
330                                        Rectangle rec = new Rectangle(p1.x-1,p1.y-11, (p2.x-p1.x)+12, (p2.y-p1.y)+12);
331                                        g2D.fill(rec);
332                                }
333                        }
334
335                        //if ( selectionStart != null && selectionEnd != null){
336                        //      if ( i >= selectionStart.getPos1() && i <= selectionEnd.getPos1()) {
337
338                        if ( isSelected(i)){
339                                // draw selection
340                                Color bg = Color.YELLOW;
341                                g2D.setPaint(bg);
342                                // draw a darker backgroun
343                                Rectangle rec = new Rectangle(p1.x-1,p1.y-11, (p2.x-p1.x)+12, (p2.y-p1.y)+12);
344                                g2D.fill(rec);
345                                //      }
346                        }
347
348                        // draw the AA sequence
349                        g2D.setColor(Color.black);
350                        g2D.drawString(String.valueOf(c1), xpos1, ypos1);
351                        g2D.drawString(String.valueOf(c2), xpos2, ypos2);
352
353
354
355
356                        //System.out.println(seq1[i] + " " + xpos1 + " " + ypos1 + " " + seq2[i] + xpos2 + " " + ypos2);
357                }
358
359                int nrLines = (afpChain.getAlnLength() -1) / AFPChainCoordManager.DEFAULT_LINE_LENGTH;
360
361
362                for ( int i = 0 ; i <= nrLines ; i++){
363
364                        try {
365                                // draw legend at i
366                                Point p1 = coordManager.getLegendPosition(i,0);
367                                Point p2 = coordManager.getLegendPosition(i,1);
368
369
370                                int aligPos = i * AFPChainCoordManager.DEFAULT_LINE_LENGTH ;
371                                Atom a1 = DisplayAFP.getAtomForAligPos(afpChain, 0,aligPos, ca1,false);
372                                Atom a2 = DisplayAFP.getAtomForAligPos(afpChain, 1,aligPos, ca2,false);
373                                String label1 = JmolTools.getPdbInfo(a1,false);
374                                String label2 = JmolTools.getPdbInfo(a2,false);
375                                g2D.drawString(label1, p1.x,p1.y);
376                                g2D.drawString(label2, p2.x,p2.y);
377
378                                Point p3 = coordManager.getEndLegendPosition(i,0);
379                                Point p4 = coordManager.getEndLegendPosition(i,1);
380
381                                aligPos = i * AFPChainCoordManager.DEFAULT_LINE_LENGTH + AFPChainCoordManager.DEFAULT_LINE_LENGTH -1 ;
382                                if ( aligPos > afpChain.getAlnLength())
383                                        aligPos = afpChain.getAlnLength() - 1;
384                                Atom a3 = DisplayAFP.getAtomForAligPos(afpChain, 0,aligPos, ca1,true);
385                                Atom a4 = DisplayAFP.getAtomForAligPos(afpChain, 1,aligPos, ca2,true);
386
387                                String label3 = JmolTools.getPdbInfo(a3,false);
388                                String label4 = JmolTools.getPdbInfo(a4,false);
389
390                                g2D.drawString(label3, p3.x,p3.y);
391                                g2D.drawString(label4, p4.x,p4.y);
392
393
394                        } catch (StructureException e){
395                                e.printStackTrace();
396                        }
397                }
398
399
400        }
401
402
403
404
405        private boolean isSelected(int alignmentPosition) {
406
407                return selection.get(alignmentPosition);
408
409        }
410
411
412        @Override
413public void mouseOverPosition(AlignedPosition p) {
414                //System.out.println("AligPanel: mouse over position " + p.getPos1() );
415
416                if ( ! selectionLocked)
417                        selection.clear();
418                selection.set(p.getPos1());
419
420                updateJmolDisplay();
421
422                this.repaint();
423
424        }
425
426        private void updateJmolDisplay() {
427
428                if ( jmol == null)
429                        return;
430
431                int size = afpChain.getAlnLength();
432
433                StringBuffer cmd = new StringBuffer("select ");
434
435                int nrSelected = 0;
436                try {
437
438                        for (int i = 0 ; i< size ; i++){
439                                if ( selection.get(i)){
440
441                                        Atom a1 = DisplayAFP.getAtomForAligPos(afpChain, 0,i, ca1, false);
442                                        Atom a2 = DisplayAFP.getAtomForAligPos(afpChain, 1,i, ca2, false);
443
444                                        String select1 = "";
445
446                                        if ( a1 != null )
447                                                select1 = JmolTools.getPdbInfo(a1);
448                                        String select2 = "" ;
449                                        if ( a2 != null)
450                                                select2 = JmolTools.getPdbInfo(a2);
451
452                                        // nothing to display
453                                        if ( select1.equals("") && select2.equals(""))
454                                                continue;
455
456                                        if ( nrSelected > 0)
457                                                cmd.append(", ");
458
459                                        cmd.append(select1);
460                                        cmd.append("/1, ");
461                                        cmd.append(select2);
462                                        cmd.append("/2");
463                                        nrSelected++;
464                                }
465                        }
466
467
468                } catch (StructureException e){
469                        e.printStackTrace();
470                }
471                if ( nrSelected == 0)
472                        cmd.append(" none;");
473                else
474                        cmd.append("; set display selected;");
475
476                jmol.evalString(cmd.toString());
477
478
479        }
480
481
482        @Override
483public void positionSelected(AlignedPosition p) {
484                mouseOverPosition(p);
485
486        }
487
488        @Override
489public void rangeSelected(AlignedPosition start, AlignedPosition end) {
490                //System.out.println("AligPanel: range selected " + start.getPos1() + " - " + end.getPos1() + " selectionLockedL " + selectionLocked);
491                if ( ! selectionLocked )
492                        selection.clear();
493                selection.set(start.getPos1(), end.getPos1()+1);
494                updateJmolDisplay();
495                this.repaint();
496
497        }
498
499        @Override
500public void selectionLocked() {
501                selectionLocked = true;
502
503        }
504
505        @Override
506public void selectionUnlocked() {
507                selectionLocked = false;
508                selection.clear();
509                this.repaint();
510
511        }
512
513
514        @Override
515public void toggleSelection(AlignedPosition p) {
516                selection.flip(p.getPos1());
517                //System.out.println("AligPanel: toggle selection " + p.getPos1() + " " + selection.get(p.getPos1()));
518                updateJmolDisplay();
519                this.repaint();
520
521        }
522
523
524
525        public void setAlignmentJmol(AbstractAlignmentJmol jmol) {
526                this.jmol = jmol;
527
528        }
529
530
531        @Override
532public void windowActivated(WindowEvent e) {
533
534                // TODO Auto-generated method stub
535
536        }
537
538
539        @Override
540public void windowClosed(WindowEvent e) {
541                // TODO Auto-generated method stub
542
543        }
544
545
546        @Override
547public void windowClosing(WindowEvent e) {
548                destroy();
549
550        }
551
552
553        @Override
554public void windowDeactivated(WindowEvent e) {
555                // TODO Auto-generated method stub
556
557        }
558
559
560        @Override
561public void windowDeiconified(WindowEvent e) {
562                // TODO Auto-generated method stub
563
564        }
565
566
567        @Override
568public void windowIconified(WindowEvent e) {
569                // TODO Auto-generated method stub
570
571        }
572
573
574        @Override
575public void windowOpened(WindowEvent e) {
576                // TODO Auto-generated method stub
577
578        }
579
580        @Override
581public void actionPerformed(ActionEvent e) {
582                String cmd = e.getActionCommand();
583                // print is handled by superclass
584                if ( cmd.equals(MenuCreator.PRINT)) {
585                        super.actionPerformed(e);
586                } else if (cmd.equals(MenuCreator.TEXT_ONLY)){
587                        String result = AfpChainWriter.toWebSiteDisplay(afpChain, ca1, ca2);
588                        DisplayAFP.showAlignmentImage(afpChain, result);
589                } else if ( cmd.equals(MenuCreator.PAIRS_ONLY)) {
590                        String result = AfpChainWriter.toAlignedPairs(afpChain, ca1, ca2) ;
591                        DisplayAFP.showAlignmentImage(afpChain, result);
592                } else if (cmd.equals(MenuCreator.FATCAT_TEXT)){
593                        String result = afpChain.toFatcat(ca1, ca2);
594                        result += AFPChain.newline;
595                        result += afpChain.toRotMat();
596                        DisplayAFP.showAlignmentImage(afpChain, result);
597                } else if ( cmd.equals(MenuCreator.SELECT_EQR)){
598                        selectEQR();
599                } else if ( cmd.equals(MenuCreator.SIMILARITY_COLOR)){
600                        colorBySimilarity(true);
601                } else if ( cmd.equals(MenuCreator.EQR_COLOR)){
602                        colorBySimilarity(false);
603                } else if ( cmd.equals(MenuCreator.FATCAT_BLOCK)){
604                        colorByAlignmentBlock();
605                }
606                else {
607                        System.err.println("Unknown command:" + cmd);
608                }
609
610        }
611
612
613        private void colorByAlignmentBlock() {
614                colorByAlignmentBlock = true;
615                colorBySimilarity = false;
616                this.repaint();
617
618        }
619
620
621        private void colorBySimilarity(boolean flag) {
622                this.colorBySimilarity = flag;
623                colorByAlignmentBlock = false;
624                this.repaint();
625        }
626
627
628        private void selectEQR() {
629
630                selection.clear();
631
632                List<Integer> pos1 = DisplayAFP.getEQRAlignmentPos(afpChain);
633
634                for (int pos : pos1){
635                        selection.flip(pos);
636                }
637                mouseMoLi.triggerSelectionLocked(true);
638                updateJmolDisplay();
639                this.repaint();
640
641        }
642
643        public Atom[] getCa1() {
644                return ca1;
645        }
646
647
648        public void setCa1(Atom[] ca1) {
649                this.ca1 = ca1;
650        }
651
652
653        public Atom[] getCa2() {
654                return ca2;
655        }
656
657
658        public void setCa2(Atom[] ca2) {
659                this.ca2 = ca2;
660        }
661
662
663}