annotate view/Overview.cpp @ 854:c17719e488c9

Fix some potential null-pointer derefs, and simplify some logic where loops were used with an unconditional "break" that meant they could only happen once (from coverity scan)
author Chris Cannam
date Wed, 03 Sep 2014 12:04:22 +0100
parents 7792b7667f74
children 2857e6352b06 4a578a360011
rev   line source
Chris@173 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@173 2
Chris@173 3 /*
Chris@173 4 Sonic Visualiser
Chris@173 5 An audio file viewer and annotation editor.
Chris@173 6 Centre for Digital Music, Queen Mary, University of London.
Chris@182 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@173 8
Chris@173 9 This program is free software; you can redistribute it and/or
Chris@173 10 modify it under the terms of the GNU General Public License as
Chris@173 11 published by the Free Software Foundation; either version 2 of the
Chris@173 12 License, or (at your option) any later version. See the file
Chris@173 13 COPYING included with this distribution for more information.
Chris@173 14 */
Chris@173 15
Chris@173 16 #include "Overview.h"
Chris@173 17 #include "layer/Layer.h"
Chris@173 18 #include "data/model/Model.h"
Chris@173 19 #include "base/ZoomConstraint.h"
Chris@173 20
Chris@173 21 #include <QPaintEvent>
Chris@173 22 #include <QPainter>
Chris@173 23 #include <iostream>
Chris@173 24
Chris@643 25 //#define DEBUG_OVERVIEW 1
Chris@642 26
Chris@682 27
Chris@173 28 Overview::Overview(QWidget *w) :
Chris@173 29 View(w, false),
Chris@854 30 m_clickedInRange(false),
Chris@854 31 m_dragCentreFrame(0)
Chris@173 32 {
Chris@173 33 setObjectName(tr("Overview"));
Chris@173 34 m_followPan = false;
Chris@173 35 m_followZoom = false;
Chris@211 36 setPlaybackFollow(PlaybackIgnore);
Chris@274 37 m_modelTestTime.start();
Chris@173 38 }
Chris@173 39
Chris@173 40 void
Chris@806 41 Overview::modelChangedWithin(int startFrame, int endFrame)
Chris@173 42 {
Chris@253 43 bool zoomChanged = false;
Chris@253 44
Chris@806 45 int frameCount = getModelsEndFrame() - getModelsStartFrame();
Chris@253 46 int zoomLevel = frameCount / width();
Chris@253 47 if (zoomLevel < 1) zoomLevel = 1;
Chris@253 48 zoomLevel = getZoomConstraintBlockSize(zoomLevel,
Chris@253 49 ZoomConstraint::RoundUp);
Chris@253 50 if (zoomLevel != m_zoomLevel) {
Chris@253 51 zoomChanged = true;
Chris@253 52 }
Chris@253 53
Chris@253 54 if (!zoomChanged) {
Chris@274 55 if (m_modelTestTime.elapsed() < 1000) {
Chris@835 56 for (LayerList::const_iterator i = m_layerStack.begin();
Chris@835 57 i != m_layerStack.end(); ++i) {
Chris@274 58 if ((*i)->getModel() &&
Chris@389 59 (!(*i)->getModel()->isOK() ||
Chris@389 60 !(*i)->getModel()->isReady())) {
Chris@274 61 return;
Chris@274 62 }
Chris@253 63 }
Chris@274 64 } else {
Chris@274 65 m_modelTestTime.restart();
Chris@253 66 }
Chris@253 67 }
Chris@253 68
Chris@806 69 View::modelChangedWithin(startFrame, endFrame);
Chris@173 70 }
Chris@173 71
Chris@173 72 void
Chris@173 73 Overview::modelReplaced()
Chris@173 74 {
Chris@339 75 m_playPointerFrame = getAlignedPlaybackFrame();
Chris@173 76 View::modelReplaced();
Chris@173 77 }
Chris@173 78
Chris@173 79 void
Chris@211 80 Overview::registerView(View *view)
Chris@173 81 {
Chris@211 82 m_views.insert(view);
Chris@173 83 update();
Chris@173 84 }
Chris@173 85
Chris@173 86 void
Chris@211 87 Overview::unregisterView(View *view)
Chris@173 88 {
Chris@211 89 m_views.erase(view);
Chris@173 90 update();
Chris@173 91 }
Chris@173 92
Chris@173 93 void
Chris@806 94 Overview::globalCentreFrameChanged(int
Chris@806 95 #ifdef DEBUG_OVERVIEW
Chris@806 96 f
Chris@806 97 #endif
Chris@806 98 )
Chris@173 99 {
Chris@642 100 #ifdef DEBUG_OVERVIEW
Chris@682 101 cerr << "Overview::globalCentreFrameChanged: " << f << endl;
Chris@642 102 #endif
Chris@211 103 update();
Chris@211 104 }
Chris@173 105
Chris@211 106 void
Chris@806 107 Overview::viewCentreFrameChanged(View *v, int
Chris@806 108 #ifdef DEBUG_OVERVIEW
Chris@806 109 f
Chris@806 110 #endif
Chris@806 111 )
Chris@211 112 {
Chris@642 113 #ifdef DEBUG_OVERVIEW
Chris@682 114 cerr << "Overview[" << this << "]::viewCentreFrameChanged(" << v << "): " << f << endl;
Chris@642 115 #endif
Chris@211 116 if (m_views.find(v) != m_views.end()) {
Chris@173 117 update();
Chris@173 118 }
Chris@211 119 }
Chris@173 120
Chris@173 121 void
Chris@806 122 Overview::viewZoomLevelChanged(View *v, int, bool)
Chris@173 123 {
Chris@222 124 if (v == this) return;
Chris@211 125 if (m_views.find(v) != m_views.end()) {
Chris@173 126 update();
Chris@173 127 }
Chris@173 128 }
Chris@173 129
Chris@173 130 void
Chris@806 131 Overview::viewManagerPlaybackFrameChanged(int f)
Chris@173 132 {
Chris@642 133 #ifdef DEBUG_OVERVIEW
Chris@682 134 cerr << "Overview[" << this << "]::viewManagerPlaybackFrameChanged(" << f << "): " << f << endl;
Chris@642 135 #endif
Chris@642 136
Chris@173 137 bool changed = false;
Chris@173 138
Chris@339 139 f = getAlignedPlaybackFrame();
Chris@339 140
Chris@173 141 if (getXForFrame(m_playPointerFrame) != getXForFrame(f)) changed = true;
Chris@173 142 m_playPointerFrame = f;
Chris@173 143
Chris@173 144 if (changed) update();
Chris@173 145 }
Chris@173 146
Chris@173 147 void
Chris@173 148 Overview::paintEvent(QPaintEvent *e)
Chris@173 149 {
Chris@173 150 // Recalculate zoom in case the size of the widget has changed.
Chris@173 151
Chris@642 152 #ifdef DEBUG_OVERVIEW
Chris@682 153 cerr << "Overview::paintEvent: width is " << width() << ", centre frame " << m_centreFrame << endl;
Chris@642 154 #endif
Chris@214 155
Chris@806 156 int startFrame = getModelsStartFrame();
Chris@806 157 int frameCount = getModelsEndFrame() - getModelsStartFrame();
Chris@173 158 int zoomLevel = frameCount / width();
Chris@173 159 if (zoomLevel < 1) zoomLevel = 1;
Chris@173 160 zoomLevel = getZoomConstraintBlockSize(zoomLevel,
Chris@173 161 ZoomConstraint::RoundUp);
Chris@173 162 if (zoomLevel != m_zoomLevel) {
Chris@173 163 m_zoomLevel = zoomLevel;
Chris@222 164 emit zoomLevelChanged(m_zoomLevel, m_followZoom);
Chris@173 165 }
Chris@253 166
Chris@806 167 int centreFrame = startFrame + m_zoomLevel * (width() / 2);
Chris@173 168 if (centreFrame > (startFrame + getModelsEndFrame())/2) {
Chris@173 169 centreFrame = (startFrame + getModelsEndFrame())/2;
Chris@173 170 }
Chris@173 171 if (centreFrame != m_centreFrame) {
Chris@642 172 #ifdef DEBUG_OVERVIEW
Chris@682 173 cerr << "Overview::paintEvent: Centre frame changed from "
Chris@642 174 << m_centreFrame << " to " << centreFrame << " and thus start frame from " << getStartFrame();
Chris@642 175 #endif
Chris@173 176 m_centreFrame = centreFrame;
Chris@642 177 #ifdef DEBUG_OVERVIEW
Chris@682 178 cerr << " to " << getStartFrame() << endl;
Chris@642 179 #endif
Chris@211 180 emit centreFrameChanged(m_centreFrame, false, PlaybackIgnore);
Chris@173 181 }
Chris@173 182
Chris@173 183 View::paintEvent(e);
Chris@173 184
Chris@173 185 QPainter paint;
Chris@173 186 paint.begin(this);
Chris@173 187
Chris@173 188 QRect r(rect());
Chris@173 189
Chris@173 190 if (e) {
Chris@173 191 r = e->rect();
Chris@173 192 paint.setClipRect(r);
Chris@173 193 }
Chris@173 194
Chris@287 195 paint.setPen(getForeground());
Chris@173 196
Chris@173 197 int y = 0;
Chris@173 198
Chris@173 199 int prevx0 = -10;
Chris@173 200 int prevx1 = -10;
Chris@173 201
Chris@211 202 for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
Chris@173 203 if (!*i) continue;
Chris@173 204
Chris@173 205 View *w = (View *)*i;
Chris@173 206
Chris@806 207 int f0 = w->getFrameForX(0);
Chris@806 208 int f1 = w->getFrameForX(w->width());
Chris@173 209
Chris@339 210 if (f0 >= 0) {
Chris@806 211 int rf0 = w->alignToReference(f0);
Chris@339 212 f0 = alignFromReference(rf0);
Chris@339 213 }
Chris@339 214 if (f1 >= 0) {
Chris@806 215 int rf1 = w->alignToReference(f1);
Chris@339 216 f1 = alignFromReference(rf1);
Chris@339 217 }
Chris@339 218
Chris@173 219 int x0 = getXForFrame(f0);
Chris@173 220 int x1 = getXForFrame(f1);
Chris@173 221
Chris@173 222 if (x0 != prevx0 || x1 != prevx1) {
Chris@173 223 y += height() / 10 + 1;
Chris@173 224 prevx0 = x0;
Chris@173 225 prevx1 = x1;
Chris@173 226 }
Chris@173 227
Chris@173 228 if (x1 <= x0) x1 = x0 + 1;
Chris@173 229
Chris@173 230 paint.drawRect(x0, y, x1 - x0, height() - 2 * y);
Chris@173 231 }
Chris@173 232
Chris@173 233 paint.end();
Chris@173 234 }
Chris@173 235
Chris@173 236 void
Chris@173 237 Overview::mousePressEvent(QMouseEvent *e)
Chris@173 238 {
Chris@173 239 m_clickPos = e->pos();
Chris@806 240 int clickFrame = getFrameForX(m_clickPos.x());
Chris@339 241 if (clickFrame > 0) m_dragCentreFrame = clickFrame;
Chris@339 242 else m_dragCentreFrame = 0;
Chris@339 243 m_clickedInRange = true;
Chris@339 244
Chris@211 245 for (ViewSet::iterator i = m_views.begin(); i != m_views.end(); ++i) {
Chris@339 246 if (*i && (*i)->getAligningModel() == getAligningModel()) {
Chris@339 247 m_dragCentreFrame = (*i)->getCentreFrame();
Chris@339 248 break;
Chris@339 249 }
Chris@173 250 }
Chris@173 251 }
Chris@173 252
Chris@173 253 void
Chris@173 254 Overview::mouseReleaseEvent(QMouseEvent *e)
Chris@173 255 {
Chris@173 256 if (m_clickedInRange) {
Chris@173 257 mouseMoveEvent(e);
Chris@173 258 }
Chris@173 259 m_clickedInRange = false;
Chris@173 260 }
Chris@173 261
Chris@173 262 void
Chris@173 263 Overview::mouseMoveEvent(QMouseEvent *e)
Chris@173 264 {
Chris@173 265 if (!m_clickedInRange) return;
Chris@173 266
Chris@806 267 int xoff = int(e->x()) - int(m_clickPos.x());
Chris@806 268 int frameOff = xoff * m_zoomLevel;
Chris@173 269
Chris@806 270 int newCentreFrame = m_dragCentreFrame;
Chris@173 271 if (frameOff > 0) {
Chris@173 272 newCentreFrame += frameOff;
Chris@806 273 } else if (newCentreFrame >= int(-frameOff)) {
Chris@173 274 newCentreFrame += frameOff;
Chris@173 275 } else {
Chris@173 276 newCentreFrame = 0;
Chris@173 277 }
Chris@173 278
Chris@173 279 if (newCentreFrame >= getModelsEndFrame()) {
Chris@173 280 newCentreFrame = getModelsEndFrame();
Chris@173 281 if (newCentreFrame > 0) --newCentreFrame;
Chris@173 282 }
Chris@173 283
Chris@173 284 if (std::max(m_centreFrame, newCentreFrame) -
Chris@806 285 std::min(m_centreFrame, newCentreFrame) > int(m_zoomLevel)) {
Chris@806 286 int rf = alignToReference(newCentreFrame);
Chris@643 287 #ifdef DEBUG_OVERVIEW
Chris@682 288 cerr << "Overview::mouseMoveEvent: x " << e->x() << " and click x " << m_clickPos.x() << " -> frame " << newCentreFrame << " -> rf " << rf << endl;
Chris@643 289 #endif
Chris@817 290 if (m_followPlay == PlaybackScrollContinuous ||
Chris@817 291 m_followPlay == PlaybackScrollPageWithCentre) {
Chris@817 292 emit centreFrameChanged(rf, true, PlaybackScrollContinuous);
Chris@817 293 } else {
Chris@817 294 emit centreFrameChanged(rf, true, PlaybackIgnore);
Chris@817 295 }
Chris@173 296 }
Chris@173 297 }
Chris@173 298
Chris@189 299 void
Chris@189 300 Overview::mouseDoubleClickEvent(QMouseEvent *e)
Chris@189 301 {
Chris@806 302 int frame = getFrameForX(e->x());
Chris@806 303 int rf = 0;
Chris@339 304 if (frame > 0) rf = alignToReference(frame);
Chris@643 305 #ifdef DEBUG_OVERVIEW
Chris@682 306 cerr << "Overview::mouseDoubleClickEvent: frame " << frame << " -> rf " << rf << endl;
Chris@643 307 #endif
Chris@643 308 m_clickedInRange = false; // we're not starting a drag with the second click
Chris@339 309 emit centreFrameChanged(rf, true, PlaybackScrollContinuous);
Chris@189 310 }
Chris@173 311
Chris@189 312 void
Chris@189 313 Overview::enterEvent(QEvent *)
Chris@189 314 {
Chris@189 315 emit contextHelpChanged(tr("Click and drag to navigate; double-click to jump"));
Chris@189 316 }
Chris@189 317
Chris@189 318 void
Chris@189 319 Overview::leaveEvent(QEvent *)
Chris@189 320 {
Chris@189 321 emit contextHelpChanged("");
Chris@189 322 }
Chris@189 323
Chris@189 324