escape clears a sequence browser selection
[mussa.git] / qui / seqbrowser / SequenceBrowser.cpp
1 #include <QApplication>
2 #include <QClipboard>
3 #include <QDir>
4 #include <QFileDialog>
5 #include <QMessageBox>
6 #include <QMouseEvent>
7 #include <QRubberBand>
8 #include <QRect>
9 #include <QString>
10 #include <iostream>
11 #include <set>
12
13 #include <math.h>
14
15 #include "qui/seqbrowser/SequenceBrowser.hpp"
16 #include "mussa_exceptions.hpp"
17
18 using namespace std;
19
20 SequenceBrowser::SequenceBrowser(QWidget *parent)
21   : QGLWidget(parent),
22     rubberBand(0),
23     popupMenu(0),
24     copySelectedSequenceAsFastaAction(0),
25     copySelectedSequenceAsStringAction(0),
26     editSequencePropertiesAction(0),
27     clearSelectionAction(0)
28
29   popupMenu = new QMenu(this);
30   copySelectedSequenceAsFastaAction = new QAction(tr("&Copy as Fasta"), this);
31   connect(copySelectedSequenceAsFastaAction, SIGNAL(triggered()), 
32           this, SLOT(copySelectedSequenceAsFasta()));
33   popupMenu->addAction(copySelectedSequenceAsFastaAction);
34
35   copySelectedSequenceAsStringAction = new QAction(tr("&Copy Sequence"), this);
36   copySelectedSequenceAsStringAction->setShortcut(Qt::CTRL | Qt::Key_C);
37   connect(copySelectedSequenceAsStringAction, SIGNAL(triggered()), 
38           this, SLOT(copySelectedSequenceAsString()));
39   popupMenu->addAction(copySelectedSequenceAsStringAction);
40
41   // connect edit properties action
42   editSequencePropertiesAction = new QAction(tr("Sequence &Properties"), this);
43   connect(editSequencePropertiesAction, SIGNAL(triggered()), 
44           this, SLOT(editSequenceProperties()));
45           
46   clearSelectionAction = new QAction(tr("Clear Selection"), this);
47   clearSelectionAction->setShortcut(Qt::Key_Escape);
48   connect(clearSelectionAction, SIGNAL(triggered()), 
49           this, SLOT(clearSelection()));
50   this->addAction(clearSelectionAction);          
51   
52 }
53
54 SequenceBrowser::SequenceBrowser(const SequenceBrowser& sb, QWidget *parent)
55   : QGLWidget(parent),
56     GlSeqBrowser(sb),
57     rubberBand(sb.rubberBand),
58     popupMenu(sb.popupMenu),
59     copySelectedSequenceAsFastaAction(sb.copySelectedSequenceAsFastaAction),
60     copySelectedSequenceAsStringAction(sb.copySelectedSequenceAsStringAction),
61     editSequencePropertiesAction(sb.editSequencePropertiesAction),
62     clearSelectionAction(sb.clearSelectionAction)
63 {
64   resize(sb.width(), sb.height());
65   setZoom(sb.zoom());
66   paintGL();
67 }
68
69 QMenu *SequenceBrowser::getPopupMenu()
70 {
71   return popupMenu;
72 }
73
74 QAction *SequenceBrowser::getCopySelectedSequenceAsFastaAction()
75 {
76   return copySelectedSequenceAsFastaAction;
77 }
78
79 QAction *SequenceBrowser::getCopySelectedSequenceAsStringAction()
80 {
81   return copySelectedSequenceAsStringAction;
82 }
83
84 QAction *SequenceBrowser::getEditSequencePropertiesAction()
85 {
86   return editSequencePropertiesAction;
87 }
88
89 QSize SequenceBrowser::sizeHint() const
90 {
91   return QSize(viewportPixelWidth(), viewportPixelHeight());
92 }
93
94 void SequenceBrowser::setViewportCenter(float x)
95 {
96   const float epsilon = 1e-10;
97   float center = GlSeqBrowser::viewportCenter();
98   float difference = fabsf(x - center);
99   float abs_x = fabsf(x);
100   center = fabsf(center);
101
102   // the difference < epsilon * val is one of the recommended tests
103   // for float equality.
104   // of course since we're looking for not equals, we need to toss a
105   // not at the beginning
106   if (not (difference < epsilon * abs_x or difference < epsilon * center))
107   {
108     GlSeqBrowser::setViewportCenter(x);
109     emit viewportChanged();
110     update();
111   }
112 }
113
114 void SequenceBrowser::setZoom(double new_zoom)
115 {
116   if (new_zoom != GlSeqBrowser::zoom()) {
117     GlSeqBrowser::setZoom(new_zoom);
118     emit viewportChanged();
119     update();
120   }
121 }
122
123 void SequenceBrowser::setClipPlane(int )
124 {
125 /*
126   if (clipZ != (double) newZ){
127     clipZ = (double) newZ;
128     update();
129   }
130 */
131 }
132
133 void SequenceBrowser::copySelectedSequenceAsFasta()
134 {
135   // get fasta data
136   std::string buffer;
137   size_t base_pairs_copied = copySelectedTracksAsFasta(buffer);
138
139   // get reference to clipboard
140   QClipboard *clipboard = QApplication::clipboard();
141   clipboard->setText(buffer.c_str());
142   emit basepairsCopied(base_pairs_copied);
143 }
144
145 void SequenceBrowser::copySelectedSequenceAsString()
146 {
147   // get fasta data
148   std::string buffer;
149   size_t base_pairs_copied = copySelectedTracksAsString(buffer);
150
151   // get reference to clipboard
152   QClipboard *clipboard = QApplication::clipboard();
153   clipboard->setText(buffer.c_str());
154   emit basepairsCopied(base_pairs_copied);
155 }
156
157 void SequenceBrowser::clear()
158 {
159   GlSeqBrowser::clear();
160   emit tracksChanged();
161 }
162
163 void SequenceBrowser::displayContextMenu(const QPoint& point)
164 {
165   popupMenu->popup(point);
166 }
167
168 void SequenceBrowser::editSequenceProperties()
169 {
170   // if there's a previous window, disconnect its signal
171   if (properties) {
172     disconnect(properties.get(), SIGNAL(propertiesChanged()),
173                this, SLOT(updateGL()));
174   }
175   PropertiesWindowRef new_properties(new PropertiesWindow(track_container));
176   properties = new_properties;
177   connect(properties.get(), SIGNAL(propertiesChanged()),
178           this, SLOT(updateGL()));
179   properties->show();
180 }
181
182 void SequenceBrowser::push_sequence(boost::shared_ptr<Sequence> s)
183 {
184   GlSeqBrowser::push_sequence(s);
185   emit tracksChanged();
186 }
187
188 void SequenceBrowser::push_sequence(boost::shared_ptr<GlSequence> gs)
189 {
190   GlSeqBrowser::push_sequence(gs);
191   emit tracksChanged();
192 }
193
194 ////////////////////
195 // Rendering code
196 void SequenceBrowser::initializeGL()
197 {
198   GlSeqBrowser::initializeGL();
199 }
200
201 void SequenceBrowser::resizeGL(int width, int height)
202 {
203   GlSeqBrowser::resizeGL(width, height);
204   emit viewportChanged();
205 }
206
207 void SequenceBrowser::paintGL()
208 {
209   GlSeqBrowser::paintGL();
210 }
211
212 void SequenceBrowser::mousePressEvent( QMouseEvent *e)
213 {
214   switch(e->button()) {
215     case Qt::LeftButton:
216       startSelecting(e);
217       break;
218    case Qt::RightButton:
219       break;
220    default:
221       break;
222   }
223 }
224
225 void SequenceBrowser::mouseMoveEvent( QMouseEvent *e )
226 {
227   if (rubberBand and rubberBand->isVisible()) {
228     rubberBand->setGeometry(QRect(bandOrigin, e->pos()).normalized());
229   }
230 }
231
232 void SequenceBrowser::mouseReleaseEvent( QMouseEvent *e)
233 {
234   switch(e->button()) {
235     case Qt::LeftButton:
236       stopSelecting(e);
237       break;
238    case Qt::RightButton:
239       // ok so selectedMode and drawing mode should probably be combinded
240       // into a single state variable.
241       if (rubberBand and 
242           not rubberBand->isVisible() and
243           selectedCanvasRegion.contains(e->pos())) {
244         displayContextMenu(e->globalPos());
245       }
246       break;
247    default:
248       break;
249   }
250
251 }
252
253 void SequenceBrowser::startSelecting(QMouseEvent *e)
254 {
255   if (!rubberBand)
256     rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
257
258   if (not rubberBand->isVisible()) {
259     bandOrigin = e->pos();
260     rubberBand->setGeometry(QRect(bandOrigin, QSize()));
261     rubberBand->show();
262   }
263 }
264
265 void SequenceBrowser::stopSelecting(QMouseEvent *e)
266 {
267   if (rubberBand and rubberBand->isVisible()) {
268     rubberBand->hide();
269     selectedMode = false;
270     QRect r = QRect(bandOrigin, e->pos()).normalized();
271     bandOrigin = r.topLeft();
272   
273     selectRegion(r.top(), r.left(), r.bottom(), r.right());
274     selectedCanvasRegion = r;
275   }
276 }
277
278 void SequenceBrowser::clearSelection()
279 {
280   GlSeqBrowser::clearSelection();
281   if (rubberBand and rubberBand->isVisible()) {
282     rubberBand->hide();
283   }
284   updateGL();
285 }