USGS

Isis 3.0 Object Programmers' Reference

Home

CubeViewport.cpp

Go to the documentation of this file.
00001 
00020 #include "IsisDebug.h"
00021 #include "CubeViewport.h"
00022 
00023 #include <iomanip>
00024 #include <iostream>
00025 #include <QApplication>
00026 #include <QCloseEvent>
00027 #include <QCursor>
00028 #include <QDebug>
00029 #include <QIcon>
00030 #include <QPen>
00031 #include <QPainter>
00032 #include <QFileInfo>
00033 #include <QMessageBox>
00034 #include <QMouseEvent>
00035 #include <QRgb>
00036 #include <QScrollBar>
00037 #include <QString>
00038 #include <QTimer>
00039 
00040 #include "Brick.h"
00041 #include "Camera.h"
00042 #include "CubeDataThread.h"
00043 #include "IException.h"
00044 #include "IString.h"
00045 #include "FileName.h"
00046 #include "Histogram.h"
00047 #include "Pvl.h"
00048 #include "PvlGroup.h"
00049 #include "PvlKeyword.h"
00050 #include "PvlObject.h"
00051 #include "Stretch.h"
00052 #include "StretchTool.h"
00053 #include "Tool.h"
00054 #include "UniversalGroundMap.h"
00055 #include "ViewportBuffer.h"
00056 
00057 
00058 using namespace std;
00059 
00060 
00061 namespace Isis {
00069   CubeViewport::CubeViewport(Cube *cube, CubeDataThread * cubeData,
00070       QWidget *parent) : QAbstractScrollArea(parent) {
00071     // Is the cube usable?
00072     if(cube == NULL) {
00073       throw IException(IException::Programmer,
00074                        "Can not view NULL cube pointer",
00075                        _FILEINFO_);
00076     }
00077     else if(!cube->isOpen()) {
00078       throw IException(IException::Programmer,
00079                        "Can not view unopened cube",
00080                        _FILEINFO_);
00081     }
00082 
00083     p_cube = cube;
00084     p_cubeData = NULL;
00085 
00086     if (cubeData)
00087     {
00088       p_cubeData = cubeData;
00089       p_thisOwnsCubeData = false;
00090       p_cubeId = p_cubeData->FindCubeId(cube);
00091     }
00092     else
00093     {
00094       p_cubeData = new CubeDataThread();
00095       p_thisOwnsCubeData = true;
00096       p_cubeId = p_cubeData->AddCube(p_cube);
00097     }
00098 
00099 
00100     connect(p_cubeData, SIGNAL(BrickChanged(int, const Isis::Brick *)),
00101             this, SLOT(cubeDataChanged(int, const Isis::Brick *)));
00102     connect(this, SIGNAL(doneWithData(int, const Isis::Brick *)),
00103             p_cubeData, SLOT(DoneWithData(int, const Isis::Brick *)));
00104 
00105     p_cubeData->AddChangeListener();
00106 
00107     void doneWithData(int, const Brick *);
00108 
00109     // Set up the scroll area
00110     setAttribute(Qt::WA_DeleteOnClose);
00111     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
00112     setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
00113     viewport()->setObjectName("viewport");
00114     viewport()->setCursor(QCursor(Qt::CrossCursor));
00115     viewport()->installEventFilter(this);
00116     viewport()->setAttribute(Qt::WA_OpaquePaintEvent);
00117 
00118     setAttribute(Qt::WA_NoSystemBackground);
00119     setFrameShadow(QFrame::Plain);
00120     setFrameShape(QFrame::NoFrame);
00121     setAutoFillBackground(false);
00122 
00123 //    viewport()->setAttribute(Qt::WA_NoSystemBackground);
00124 //    viewport()->setAttribute(Qt::WA_PaintOnScreen,false);
00125 
00126     p_saveEnabled = false;
00127     // Save off info about the cube
00128     p_scale = -1.0;
00129     p_color = false;
00130 
00131 
00132     setCaption();
00133 
00134     p_redBrick = new Brick(4, 1, 1, cube->pixelType());
00135     p_grnBrick = new Brick(4, 1, 1, cube->pixelType());
00136     p_bluBrick = new Brick(4, 1, 1, cube->pixelType());
00137     p_gryBrick = new Brick(4, 1, 1, cube->pixelType());
00138     p_pntBrick = new Brick(4, 1, 1, cube->pixelType());
00139 
00140     p_paintPixmap = false;
00141     p_image = NULL;
00142     p_cubeShown = true;
00143     p_updatingBuffers = false;
00144 
00145     //updateScrollBars(1,1);
00146 
00147     p_groundMap = NULL;
00148     p_projection = NULL;
00149     p_camera = NULL;
00150 
00151     // Setup a universal ground map
00152     try {
00153       p_groundMap = new UniversalGroundMap(*p_cube);
00154     }
00155     catch(IException &) {
00156     }
00157 
00158     if(p_groundMap != NULL) {
00159       // Setup the camera or the projection
00160       if(p_groundMap->Camera() != NULL) {
00161         p_camera = p_groundMap->Camera();
00162         if(p_camera->HasProjection()) {
00163           try {
00164             p_projection = cube->projection();
00165           }
00166           catch(IException &) {
00167           }
00168         }
00169       }
00170       else {
00171         p_projection = p_groundMap->Projection();
00172       }
00173     }
00174 
00175 
00176     // Setup context sensitive help
00177     QString cubeFileName = p_cube->fileName();
00178     p_whatsThisText = QString("<b>Function: </b>Viewport to ") + cubeFileName;
00179 
00180     p_cubeWhatsThisText =
00181       "<p><b>Cube Dimensions:</b> \
00182       <blockQuote>Samples = " +
00183       QString::number(cube->sampleCount()) + "<br>" +
00184       "Lines = " +
00185       QString::number(cube->lineCount()) + "<br>" +
00186       "Bands = " +
00187       QString::number(cube->bandCount()) + "</blockquote></p>";
00188 
00189     /*setting up the qlist of CubeBandsStretch objs.
00190     for( int b = 0; b < p_cube->bandCount(); b++) {
00191       CubeBandsStretch *stretch = new CubeBandsStretch();
00192       p_bandsStretchList.push_back(stretch);
00193     }*/
00194 
00195     p_grayBuffer = new ViewportBuffer(this, p_cubeData, p_cubeId);
00196     p_grayBuffer->enable(false);
00197     p_grayBuffer->setBand(1);
00198 
00199     p_redBuffer = NULL;
00200     p_greenBuffer = NULL;
00201     p_blueBuffer = NULL;
00202     p_pixmapPaintRects = NULL;
00203 
00204     p_pixmapPaintRects = new QList<QRect *>();
00205     p_progressTimer = new QTimer();
00206     p_progressTimer->setInterval(250);
00207 
00208     p_knownStretches = new QVector< Stretch * >();
00209     p_globalStretches = new QVector< Stretch * >();
00210 
00211     while(p_cube->bandCount() > p_knownStretches->size()) {
00212       p_knownStretches->push_back(NULL);
00213       p_globalStretches->push_back(NULL);
00214     }
00215 
00216     connect(p_progressTimer, SIGNAL(timeout()), this, SLOT(onProgressTimer()));
00217 
00218     p_bgColor = Qt::black;
00219   }
00220 
00221 
00227   void CubeViewport::showEvent(QShowEvent *event) {
00228     if(p_scale == -1) {
00229       // This doesn't equal fitScale() ... causes misalignment in qview initial
00230       //   view versus zoomFit
00231       //double sampScale = (double) sizeHint().width() / (double) cubeSamples();
00232       //double lineScale = (double) sizeHint().height() / (double) cubeLines();
00233       //double scale = sampScale < lineScale ? sampScale : lineScale;
00234 
00235       setScale(fitScale(), cubeSamples() / 2.0, cubeLines() / 2.0);
00236     }
00237 
00238     if(p_grayBuffer && !p_grayBuffer->enabled()) {
00239       p_grayBuffer->enable(true);
00240 
00241       // gives a proper initial stretch (entire cube)
00242       p_grayBuffer->addStretchAction();
00243     }
00244 
00245     QAbstractScrollArea::show();
00246 
00247     p_paintPixmap = true;
00248 
00249     paintPixmap();
00250   }
00251 
00252 
00257   void CubeViewport::onProgressTimer() {
00258     double progress = 0.0;
00259     bool completed = false;
00260 
00261     if(p_grayBuffer) {
00262       progress += p_grayBuffer->currentProgress();
00263       completed = !p_grayBuffer->working();
00264     }
00265 
00266     if(p_redBuffer) {
00267       progress += p_redBuffer->currentProgress() / 3.0;
00268       completed = !p_redBuffer->working();
00269     }
00270 
00271     if(p_greenBuffer) {
00272       progress += p_greenBuffer->currentProgress() / 3.0;
00273       completed = completed && !p_greenBuffer->working();
00274     }
00275 
00276     if(p_blueBuffer) {
00277       progress += p_blueBuffer->currentProgress() / 3.0;
00278       completed = completed && !p_blueBuffer->working();
00279     }
00280 
00281     int realProgress = (int)(progress * 100.0);
00282 
00283     if(completed) {
00284       realProgress = 100;
00285       p_progressTimer->stop();
00286       emit screenPixelsChanged();
00287     }
00288     else if(realProgress == 100) {
00289       realProgress = 99;
00290     }
00291 
00292     emit progressChanged(realProgress);
00293   }
00294 
00295 
00300   CubeViewport::~CubeViewport() {
00301     if(p_redBrick) {
00302       delete p_redBrick;
00303       p_redBrick = NULL;
00304     }
00305 
00306     if(p_grnBrick) {
00307       delete p_grnBrick;
00308       p_grnBrick = NULL;
00309     }
00310 
00311     if(p_bluBrick) {
00312       delete p_bluBrick;
00313       p_bluBrick = NULL;
00314     }
00315 
00316     if(p_gryBrick) {
00317       delete p_gryBrick;
00318       p_gryBrick = NULL;
00319     }
00320 
00321     if(p_pntBrick) {
00322       delete p_pntBrick;
00323       p_pntBrick = NULL;
00324     }
00325 
00326     if(p_groundMap) {
00327       delete p_groundMap;
00328       p_groundMap = NULL;
00329     }
00330 
00331     if(p_grayBuffer) {
00332       delete p_grayBuffer;
00333       p_grayBuffer = NULL;
00334     }
00335 
00336     if(p_redBuffer) {
00337       delete p_redBuffer;
00338       p_redBuffer = NULL;
00339     }
00340 
00341     if(p_greenBuffer) {
00342       delete p_greenBuffer;
00343       p_greenBuffer = NULL;
00344     }
00345 
00346     if(p_blueBuffer) {
00347       delete p_blueBuffer;
00348       p_blueBuffer = NULL;
00349     }
00350 
00351     // p_cubeData MUST be deleted AFTER all viewport buffers!!!
00352     if(p_cubeData) {
00353       p_cubeData->RemoveChangeListener();
00354 
00355       if(p_thisOwnsCubeData)
00356         delete p_cubeData;
00357 
00358       p_cubeData = NULL;
00359     }
00360 
00361     p_cube = NULL;
00362 
00363     if(p_progressTimer) {
00364       delete p_progressTimer;
00365       p_progressTimer = NULL;
00366     }
00367 
00368     if(p_image) {
00369       delete p_image;
00370       p_image = NULL;
00371     }
00372 
00373     if(p_pixmapPaintRects) {
00374       for(int rect = 0; rect < p_pixmapPaintRects->size(); rect++) {
00375         delete(*p_pixmapPaintRects)[rect];
00376       }
00377 
00378       delete p_pixmapPaintRects;
00379       p_pixmapPaintRects = NULL;
00380     }
00381 
00382     if(p_knownStretches) {
00383       for(int stretch = 0; stretch < p_knownStretches->size(); stretch ++) {
00384         if((*p_knownStretches)[stretch] != NULL) {
00385           delete(*p_knownStretches)[stretch];
00386           (*p_knownStretches)[stretch] = NULL;
00387         }
00388       }
00389 
00390       p_knownStretches->clear();
00391 
00392       delete p_knownStretches;
00393       p_knownStretches = NULL;
00394     }
00395 
00396     if(p_globalStretches) {
00397       for(int stretch = 0; stretch < p_globalStretches->size(); stretch ++) {
00398         if((*p_globalStretches)[stretch] != NULL) {
00399           delete(*p_globalStretches)[stretch];
00400           (*p_globalStretches)[stretch] = NULL;
00401         }
00402       }
00403 
00404       p_globalStretches->clear();
00405 
00406       delete p_globalStretches;
00407       p_globalStretches = NULL;
00408     }
00409   }
00410 
00416   void CubeViewport::setCube(Cube *cube) {
00417     p_cube = cube;
00418     setCaption();
00419   }
00420 
00421 
00423   int CubeViewport::cubeSamples() const {
00424     return p_cube->sampleCount();
00425   }
00426 
00427 
00429   int CubeViewport::cubeLines() const {
00430     return p_cube->lineCount();
00431   }
00432 
00433 
00435   int CubeViewport::cubeBands() const {
00436     return p_cube->bandCount();
00437   }
00438 
00439 
00447   void CubeViewport::cubeDataChanged(int cubeId, const Brick *data) {
00448     if(cubeId == p_cubeId) {
00449       double ss, sl, es, el;
00450       ss = data->Sample();
00451       sl = data->Line();
00452       es = data->Sample() + data->SampleDimension();
00453       el = data->Line() + data->LineDimension();
00454       if(ss < 0.5){
00455         ss = 0.5;
00456       }
00457       if(sl < 0.5){
00458         sl = 0.5;
00459       }
00460       if(es > cube()->sampleCount() + 0.5){
00461         es = cube()->sampleCount() + 0.5;
00462       }
00463       if(el > cube()->lineCount() + 0.5){
00464         el = cube()->lineCount() + 0.5;
00465       }
00466 
00467       int sx, sy, ex, ey;
00468 
00469       cubeToViewport(ss, sl, sx, sy);
00470       cubeToViewport(es, el, ex, ey);
00471       if(sx < 0){
00472         sx = 0;
00473       }
00474       if(sy < 0){
00475         sy = 0;
00476       }
00477       if(ex > viewport()->width()){
00478         ex = viewport()->width();
00479       }
00480       if(ey > viewport()->height()){
00481         ey = viewport()->height();
00482       }
00483       QRect vpRect(sx, sy, ex - sx + 1, ey - sy + 1);
00484 
00485       p_updatingBuffers = true;
00486       if(p_grayBuffer){
00487         p_grayBuffer->fillBuffer(vpRect, data);
00488       }
00489       if(p_redBuffer){
00490         p_redBuffer->fillBuffer(vpRect, data);
00491       }
00492       if(p_greenBuffer){
00493         p_greenBuffer->fillBuffer(vpRect, data);
00494       }
00495       if(p_blueBuffer){
00496         p_blueBuffer->fillBuffer(vpRect, data);
00497       }
00498       p_updatingBuffers = false;
00499 
00500       paintPixmapRects();
00501     }
00502 
00503     emit doneWithData(cubeId, data);
00504   }
00505 
00506 
00515   bool CubeViewport::confirmClose() {
00516     bool canClose = true;
00517     if(p_saveEnabled) {
00518       // Enter == button 0, Escape == button 2
00519       switch(QMessageBox::information(this, tr("Confirm Save"),
00520         tr("The cube [<font color='red'>%1</font>] contains unsaved changes. "
00521            "Do you want to save the changes before exiting?").arg(cube()->fileName()),
00522            QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel)) {
00523         //Save changes and close viewport
00524         case QMessageBox::Save:
00525           emit saveChanges(this);
00526           break;
00527 
00528         //Discard changes and close viewport
00529         case QMessageBox::Discard:
00530           emit discardChanges(this);
00531           break;
00532 
00533         //Cancel, don't close viewport
00534         case QMessageBox::Cancel:
00535         default:
00536           canClose = false;
00537           break;
00538       }
00539     }
00540     
00541 //  if (canClose) emit viewportClosed(this);
00542     return canClose;
00543   }
00544 
00551   void CubeViewport::cubeChanged(bool changed) {
00552     p_saveEnabled = changed;
00553   }
00554 
00561   QSize CubeViewport::sizeHint() const {
00562     QSize s(512, 512);
00563     return s;
00564   }
00565 
00566 
00578   void CubeViewport::setScale(double scale) {
00579     // Sanitize the scale value
00580     if(scale == p_scale){
00581       return;
00582     }
00583 
00584     if (viewport()->width() && viewport()->height()) {
00585       // don't let zoom scale be larger than the viewport size
00586       double maxScale = max(viewport()->width(),viewport()->height());
00587       if (scale > maxScale) {
00588         scale = maxScale;
00589       }
00590       // don't let zoom scale be smaller than one pixel high/wide showing
00591       double minScale = 1.0 / (min(cubeSamples(),cubeLines()));
00592       if (scale < minScale) {
00593         scale = minScale;
00594       }
00595     }
00596 
00597     // Resize the scrollbars to reflect the new scale
00598     double samp, line;
00599     contentsToCube(horizontalScrollBar()->value(), verticalScrollBar()->value(),
00600                    samp, line);
00601     p_scale = scale;
00602     updateScrollBars(1, 1); // Setting to 1,1 make sure we don't have bad values
00603 
00604     // Now update the scroll bar value to the old line/sample
00605     int x, y;
00606     cubeToContents(samp, line, x, y);
00607     updateScrollBars(x, y);
00608 
00609     p_updatingBuffers = true;
00610     if(p_grayBuffer){
00611       p_grayBuffer->scaleChanged();
00612     }
00613     if(p_redBuffer){
00614       p_redBuffer->scaleChanged();
00615     }
00616     if(p_greenBuffer){
00617       p_greenBuffer->scaleChanged();
00618     }
00619     if(p_blueBuffer){
00620       p_blueBuffer->scaleChanged();
00621     }
00622     p_updatingBuffers = false;
00623 
00624     paintPixmapRects();
00625 
00626     // Notify other tools about the scale change
00627     emit scaleChanged();
00628 
00629     // Update the display
00630     setCaption();
00631     paintPixmap(); // Will get rid of old data in the display
00632 
00633     viewport()->repaint();
00634     emit screenPixelsChanged();
00635   }
00636 
00645   void CubeViewport::setScale(double scale, int x, int y) {
00646     double samp, line;
00647     viewportToCube(x, y, samp, line);
00648     setScale(scale, samp, line);
00649   }
00650 
00651 
00661   void CubeViewport::setScale(double scale, double sample, double line) {
00662     viewport()->setUpdatesEnabled(false);
00663 
00664     bool wasEnabled = false;
00665 
00666     if((p_grayBuffer && p_grayBuffer->enabled()) ||
00667         (p_redBuffer && p_redBuffer->enabled())) {
00668       wasEnabled = true;
00669     }
00670 
00671     if(p_grayBuffer){
00672       p_grayBuffer->enable(false);
00673     }
00674     if(p_redBuffer){
00675       p_redBuffer->enable(false);
00676     }
00677     if(p_greenBuffer){
00678       p_greenBuffer->enable(false);
00679     }
00680     if(p_blueBuffer){
00681       p_blueBuffer->enable(false);
00682     }
00683     if(p_paintPixmap) {
00684       p_paintPixmap = false;
00685       setScale(scale);
00686       p_paintPixmap = true;
00687     }
00688     else {
00689       setScale(scale);
00690     }
00691 
00692     center(sample, line);
00693 
00694     if(p_grayBuffer){
00695       p_grayBuffer->enable(wasEnabled);
00696     }
00697     if(p_redBuffer){
00698       p_redBuffer->enable(wasEnabled);
00699     }
00700     if(p_greenBuffer){
00701       p_greenBuffer->enable(wasEnabled);
00702     }
00703     if(p_blueBuffer){
00704       p_blueBuffer->enable(wasEnabled);
00705     }
00706 
00707     paintPixmap();
00708     viewport()->setUpdatesEnabled(true);
00709     viewport()->update();
00710     emit screenPixelsChanged();
00711   }
00712 
00713 
00721   void CubeViewport::center(int x, int y) {
00722     double sample, line;
00723     viewportToCube(x, y, sample, line);
00724     center(sample, line);
00725   }
00726 
00727 
00735   void CubeViewport::center(double sample, double line) {
00736     int x, y;
00737     cubeToContents(sample, line, x, y);
00738 
00739     x ++;
00740     y ++;
00741 
00742     int panX = horizontalScrollBar()->value() - x;
00743     int panY = verticalScrollBar()->value() - y;
00744 
00745     updateScrollBars(x, y);
00746 
00747     p_updatingBuffers = true;
00748     if(p_grayBuffer){
00749       p_grayBuffer->pan(panX, panY);
00750     }
00751     if(p_redBuffer){
00752       p_redBuffer->pan(panX, panY);
00753     }
00754     if(p_greenBuffer){
00755       p_greenBuffer->pan(panX, panY);
00756     }
00757     if(p_blueBuffer){
00758       p_blueBuffer->pan(panX, panY);
00759     }
00760     p_updatingBuffers = false;
00761 
00762     paintPixmapRects();
00763 
00764     shiftPixmap(panX, panY);
00765 
00766     emit screenPixelsChanged();
00767   }
00768 
00769 
00774   void CubeViewport::paintPixmapRects() {
00775     for(int rect = 0; rect < p_pixmapPaintRects->size(); rect++) {
00776       paintPixmap(*(*p_pixmapPaintRects)[rect]);
00777     }
00778 
00779     p_pixmapPaintRects->clear();
00780   }
00781 
00782 
00793   void CubeViewport::contentsToCube(int x, int y,
00794                                     double &sample, double &line) const {
00795     sample = x / p_scale;
00796     line = y / p_scale;
00797   }
00798 
00799 
00810   void CubeViewport::viewportToCube(int x, int y,
00811                                     double &sample, double &line) const {
00812     x += horizontalScrollBar()->value();
00813     x -= viewport()->width() / 2;
00814     y += verticalScrollBar()->value();
00815     y -= viewport()->height() / 2;
00816     contentsToCube(x, y, sample, line);
00817   }
00818 
00819 
00830   void CubeViewport::cubeToContents(double sample, double line,
00831                                     int &x, int &y) const {
00832     x = (int)(sample * p_scale + 0.5);
00833     y = (int)(line * p_scale + 0.5);
00834   }
00835 
00836 
00847   void CubeViewport::cubeToViewport(double sample, double line,
00848                                     int &x, int &y) const {
00849     cubeToContents(sample, line, x, y);
00850     x -= horizontalScrollBar()->value();
00851     x += viewport()->width() / 2;
00852     y -= verticalScrollBar()->value();
00853     y += viewport()->height() / 2;
00854   }
00855 
00856 
00864   void CubeViewport::scrollBy(int dx, int dy) {
00865     // Make sure we don't generate bad values outside of the scroll range
00866     int x = horizontalScrollBar()->value() + dx;
00867     if(x <= 1) {
00868       dx = 1 - horizontalScrollBar()->value();
00869     }
00870     else if(x >= horizontalScrollBar()->maximum()) {
00871       dx = horizontalScrollBar()->maximum() - horizontalScrollBar()->value();
00872     }
00873 
00874     // Make sure we don't generate bad values outside of the scroll range
00875     int y = verticalScrollBar()->value() + dy;
00876     if(y <= 1) {
00877       dy = 1 - verticalScrollBar()->value();
00878     }
00879     else if(y >= verticalScrollBar()->maximum()) {
00880       dy = verticalScrollBar()->maximum() - verticalScrollBar()->value();
00881     }
00882 
00883     // Do we do anything?
00884     if((dx == 0) && (dy == 0)){
00885       return;
00886     }
00887 
00888     // We do so update the scroll bars
00889     updateScrollBars(horizontalScrollBar()->value() + dx,
00890                      verticalScrollBar()->value() + dy);
00891 
00892     // Scroll the the pixmap
00893     scrollContentsBy(-dx, -dy);
00894   }
00895 
00896 
00904   void CubeViewport::scrollContentsBy(int dx, int dy) {
00905 
00906     // We shouldn't do anything if scrollbars are being updated
00907     if(viewport()->signalsBlocked()) {
00908       return;
00909     }
00910 
00911     // Tell the buffers to update appropriate for the pan and upon completion
00912     //   they will call bufferUpdated. We don't want bufferUpdated to happen
00913     //   until afterwards. If only shrinking and no new data then the viewport
00914     //   buffers will complete immediately. When all buffers don't have their
00915     //   appropriate actions queued bufferUpdated can't succeed.
00916 
00917     // Also block paints because we'll repaint it all when we're done
00918     //   telling each buffer about the pan.
00919     bool panQueued = false;
00920     QRect bufferXYRect;
00921 
00922     p_updatingBuffers = true;
00923 
00924     if(p_grayBuffer) {
00925       p_grayBuffer->pan(dx, dy);
00926       panQueued |= p_grayBuffer->working();
00927       bufferXYRect = p_grayBuffer->bufferXYRect();
00928     }
00929 
00930     if(p_redBuffer) {
00931       p_redBuffer->pan(dx, dy);
00932       panQueued |= p_redBuffer->working();
00933       bufferXYRect = p_redBuffer->bufferXYRect();
00934     }
00935 
00936     if(p_greenBuffer) {
00937       p_greenBuffer->pan(dx, dy);
00938       panQueued |= p_greenBuffer->working();
00939     }
00940 
00941     if(p_blueBuffer) {
00942       p_blueBuffer->pan(dx, dy);
00943       panQueued |= p_blueBuffer->working();
00944     }
00945 
00946     p_updatingBuffers = false;
00947 
00948     // shift the pixmap by x,y if the viewport buffer didn't do it immediately
00949     if(panQueued) {
00950       shiftPixmap(dx, dy);
00951     }
00952     else {
00953       // Need to do this to clear area outside of cube
00954       p_pixmapPaintRects->clear();
00955       paintPixmap();
00956     }
00957 
00958     viewport()->update();
00959     emit screenPixelsChanged();
00960   }
00961 
00962 
00967   void CubeViewport::enableProgress() {
00968     if(!p_progressTimer->isActive()) {
00969       p_progressTimer->start();
00970 
00971       emit progressChanged(0);
00972     }
00973   }
00974 
00975 
00980   void CubeViewport::setCaption() {
00981     QString cubeFileName = p_cube->fileName();
00982     QString str = QFileInfo(cubeFileName).fileName();
00983     str += QString(" @ ");
00984     str += QString::number(p_scale * 100.0);
00985     str += QString("% ");
00986 
00987     if(p_color) {
00988       str += QString("(RGB = ");
00989       str += QString::number(p_red.band);
00990       str += QString(",");
00991       str += QString::number(p_green.band);
00992       str += QString(",");
00993       str += QString::number(p_blue.band);
00994       str += QString(")");
00995     }
00996     else {
00997       str += QString("(Gray = ");
00998       str += QString::number(p_gray.band);
00999       str += QString(")");
01000     }
01001 
01002     //If changes have been made make sure to add '*' to the end
01003     if(p_saveEnabled) {
01004       str += "*";
01005     }
01006 
01007     parentWidget()->setWindowTitle(str);
01008     emit windowTitleChanged();
01009   }
01010 
01011 
01018   void CubeViewport::resizeEvent(QResizeEvent *e) {
01019     p_paintPixmap = false;
01020 
01021     // Tell the buffers to update their coefficients to reinitialize
01022     //   and have their immediate paint events happen afterwards. Should not
01023     //   happen, but if buffers have actions complete immediately and call
01024     //   bufferUpdated. We don't want to have bufferUpdated ever when all
01025     //   buffers don't have their appropriate actions queued. It can't succeed.
01026     p_updatingBuffers = true;
01027     if(p_grayBuffer){
01028       p_grayBuffer->resizedViewport();
01029     }
01030     if(p_redBuffer){
01031       p_redBuffer->resizedViewport();
01032     }
01033     if(p_greenBuffer){
01034       p_greenBuffer->resizedViewport();
01035     }
01036     if(p_blueBuffer){
01037       p_blueBuffer->resizedViewport();
01038     }
01039     p_updatingBuffers = false;
01040 
01041     paintPixmapRects();
01042 
01043     // Change the size of the image and pixmap
01044     if(p_image) {
01045       delete p_image;
01046       p_image = NULL;
01047     }
01048 
01049     p_image = new QImage(viewport()->size(), QImage::Format_RGB32);
01050     p_pixmap = QPixmap(viewport()->size());
01051 
01052     p_paintPixmap = true;
01053 
01054     // Fixup the scroll bars
01055     updateScrollBars(horizontalScrollBar()->value(),
01056                      verticalScrollBar()->value());
01057 
01058     p_viewportWhatsThisText =
01059       "<p><b>Viewport Dimensions:</b> \
01060       <blockQuote>Samples = " +
01061       QString::number(viewport()->width()) + "<br>" +
01062       "Lines = " +
01063       QString::number(viewport()->height()) + "</blockquote></p>";
01064 
01065     // Repaint the pixmap
01066     paintPixmap();
01067 
01068     // Repaint the internal viewport and scroll bars
01069     viewport()->update();
01070     emit screenPixelsChanged();
01071   }
01072 
01073 
01084   void CubeViewport::paintEvent(QPaintEvent *e) {
01085     if(!p_cubeShown || !viewport()->isVisible()){
01086       return;
01087     }
01088   }
01089 
01090 
01099   void CubeViewport::bufferUpdated(QRect rect) {
01100     paintPixmap(rect);
01101 
01102     // Don't repaint from buffer updates if any buffers are working...
01103     // This set of statements fixes a flash of black when in RGB mode
01104     //   and a pan (or other operation?) completes. What would happen is
01105     //   the first would reset to black then other buffers still working so
01106     //   not restored to DN values.
01107     if(p_grayBuffer && p_grayBuffer->working()){
01108       return;
01109     }
01110     if(p_redBuffer && p_redBuffer->working()){
01111       return;
01112     }
01113     if(p_greenBuffer && p_greenBuffer->working()){
01114       return;
01115     }
01116     if(p_blueBuffer && p_blueBuffer->working()){
01117       return;
01118     }
01119 
01120     viewport()->repaint(rect);
01121   }
01122 
01124   void CubeViewport::paintPixmap() {
01125     QRect rect(0, 0, p_image->width(), p_image->height());
01126     paintPixmap(rect);
01127   }
01128 
01129 
01136   void CubeViewport::paintPixmap(QRect rect) {
01137     if(!p_paintPixmap) {
01138       return;
01139     }
01140 
01141     if(p_updatingBuffers) {
01142       p_pixmapPaintRects->push_back(new QRect(rect));
01143       return;
01144     }
01145 
01146     if(p_pixmap.isNull()){
01147       return;
01148     }
01149 
01150     QPainter p(&p_pixmap);
01151 
01152     p.fillRect(rect, QBrush(p_bgColor));
01153 
01154     QRect dataArea;
01155 
01156     if(p_grayBuffer && p_grayBuffer->enabled()) {
01157       if(p_grayBuffer->working()){
01158         return;
01159       }
01160 
01161       dataArea = QRect(p_grayBuffer->bufferXYRect().intersected(rect));
01162 
01163       for(int y = dataArea.top();
01164           !dataArea.isNull() && y <= dataArea.bottom();
01165           y++) {
01166         const vector< double > & line =
01167           p_grayBuffer->getLine(y - p_grayBuffer->bufferXYRect().top());
01168 
01169         if(line.size() == 0) {
01170           break;
01171         }
01172 
01173         if(y >= p_image->height()) {
01174           throw IException(IException::Programmer, "y too big", _FILEINFO_);
01175         }
01176 
01177         QRgb *rgb = (QRgb *) p_image->scanLine(y);
01178 
01179         for(int x = dataArea.left(); x <= dataArea.right(); x++) {
01180           int bufferLeft = p_grayBuffer->bufferXYRect().left();
01181           int bufferX = x - bufferLeft;
01182 
01183           if(bufferX >= (int)line.size()){
01184             break;
01185           }
01186 
01187           if(bufferX < 0) {
01188             throw IException(IException::Programmer, "bufferX < 0", _FILEINFO_);
01189           }
01190 
01191           if(x >= p_image->width()) {
01192             throw IException(IException::Programmer, "x too big", _FILEINFO_);
01193           }
01194 
01195           double bufferVal = line.at(bufferX);
01196 
01197           // This is still RGB; the pairs are identical but the boundary
01198           //   conditions are different. Display saturations cause this.
01199           int redPix = (int)(p_red.getStretch().Map(bufferVal) + 0.5);
01200           int greenPix = (int)(p_green.getStretch().Map(bufferVal) + 0.5);
01201           int bluePix = (int)(p_blue.getStretch().Map(bufferVal) + 0.5);
01202           rgb[x] =  qRgb(redPix, greenPix, bluePix);
01203         }
01204       }
01205     }
01206     else {
01207       if(p_redBuffer && p_redBuffer->enabled()) {
01208         if(p_redBuffer->working() || p_greenBuffer->working() ||
01209             p_blueBuffer->working()) {
01210           return;
01211         }
01212 
01213 
01214         if((p_greenBuffer->bufferXYRect().top() !=
01215             p_redBuffer->bufferXYRect().top()) ||
01216             (p_greenBuffer->bufferXYRect().top() !=
01217              p_blueBuffer->bufferXYRect().top())) {
01218           throw IException(IException::Programmer,
01219                            "Buffer rects mismatched",
01220                            _FILEINFO_);
01221         }
01222 
01223         if((p_greenBuffer->bufferXYRect().left() !=
01224             p_redBuffer->bufferXYRect().left()) ||
01225             (p_greenBuffer->bufferXYRect().left() !=
01226              p_blueBuffer->bufferXYRect().left())) {
01227           throw IException(IException::Programmer,
01228                            "Buffer rects mismatched",
01229                            _FILEINFO_);
01230         }
01231 
01232         dataArea = QRect(p_redBuffer->bufferXYRect().intersected(rect));
01233 
01234         for(int y = dataArea.top();
01235             !dataArea.isNull() && y <= dataArea.bottom();
01236             y++) {
01237           int bufferLine = y - p_redBuffer->bufferXYRect().top();
01238 
01239           const vector<double> &redLine   = p_redBuffer->getLine(bufferLine);
01240           const vector<double> &greenLine = p_greenBuffer->getLine(bufferLine);
01241           const vector<double> &blueLine  = p_blueBuffer->getLine(bufferLine);
01242 
01243           if((int)redLine.size() < dataArea.width() ||
01244               (int)greenLine.size() < dataArea.width() ||
01245               (int)blueLine.size() < dataArea.width()) {
01246             throw IException(IException::Programmer,
01247                              "Empty buffer line",
01248                              _FILEINFO_);
01249           }
01250 
01251           QRgb *rgb = (QRgb *) p_image->scanLine(y);
01252 
01253           for(int x = dataArea.left(); x <= dataArea.right(); x++) {
01254             int redPix = (int)(p_red.getStretch().Map(redLine[ x - p_redBuffer->bufferXYRect().left()]) + 0.5);
01255             int greenPix = (int)(p_green.getStretch().Map(greenLine[ x - p_greenBuffer->bufferXYRect().left()]) + 0.5);
01256             int bluePix = (int)(p_blue.getStretch().Map(blueLine[ x - p_blueBuffer->bufferXYRect().left()]) + 0.5);
01257 
01258             rgb[x] = qRgb(redPix, greenPix, bluePix);
01259           }
01260         }
01261       }
01262     }
01263 
01264     if(!dataArea.isNull()){
01265       p.drawImage(dataArea.topLeft(), *p_image, dataArea);
01266     }
01267 
01268     // Change whats this info
01269     updateWhatsThis();
01270   }
01271 
01272 
01279   void CubeViewport::shiftPixmap(int dx, int dy) {
01280     if(!p_paintPixmap || !p_pixmap){
01281       return;
01282     }
01283 
01284     // Prep to scroll the pixmap
01285     int drawStartX = dx;
01286     int pixmapStartX = 0;
01287     if(drawStartX < 0) {
01288       drawStartX = 0;
01289       pixmapStartX = -dx;
01290     }
01291 
01292     int drawStartY = dy;
01293     int pixmapStartY = 0;
01294     if(dy < 0) {
01295       drawStartY = 0;
01296       pixmapStartY = -dy;
01297     }
01298 
01299     // Ok we can shift the pixmap and filling
01300     int pixmapDrawWidth  = p_pixmap.width()  - pixmapStartX + 1;
01301     int pixmapDrawHeight = p_pixmap.height() - pixmapStartY + 1;
01302 
01303     QRect rect(0, 0, p_pixmap.width(), p_pixmap.height());
01304     QPixmap pixmapCopy   = p_pixmap.copy();
01305 
01306     QPainter painter(&p_pixmap);
01307     painter.fillRect(rect, QBrush(p_bgColor));
01308     painter.drawPixmap(drawStartX, drawStartY,
01309                        pixmapCopy,
01310                        pixmapStartX, pixmapStartY,
01311                        pixmapDrawWidth, pixmapDrawHeight);
01312     painter.end();
01313 
01314     // Now fill in the left or right side
01315     QRect xFillRect;
01316     QRect yFillRect;
01317 
01318     if(dx > 0) {
01319       xFillRect = QRect(QPoint(0, 0),
01320                         QPoint(dx, p_pixmap.height()));
01321     }
01322     else {
01323       if(dx < 0){
01324         xFillRect = QRect(QPoint(p_pixmap.width() + dx, 0),
01325                           QPoint(p_pixmap.width(), p_pixmap.height()));
01326       }
01327     }
01328 
01329     // Fill in the top or bottom side
01330     if(dy > 0) {
01331       yFillRect = QRect(QPoint(0, 0),
01332                         QPoint(p_pixmap.width(), dy));
01333     }
01334     else {
01335       if(dy < 0){
01336         yFillRect = QRect(QPoint(0, p_pixmap.height() + dy),
01337                           QPoint(p_pixmap.width(), p_pixmap.height()));
01338       }
01339     }
01340 
01341     if(dx != 0) {
01342       paintPixmap(xFillRect);
01343     }
01344 
01345     if(dy != 0) {
01346       paintPixmap(yFillRect);
01347     }
01348 
01349     viewport()->update();
01350   }
01351 
01359   void CubeViewport::getAllWhatsThisInfo(Pvl & pWhatsThisPvl)
01360   {
01361     // Get Cube Info
01362     PvlObject whatsThisObj = PvlObject("WhatsThis");
01363     whatsThisObj += PvlKeyword("Cube", p_cube->fileName());
01364 
01365     PvlGroup cubeGrp("CubeDimensions");
01366     cubeGrp += PvlKeyword("Samples", toString(p_cube->sampleCount()));
01367     cubeGrp += PvlKeyword("Lines",   toString(p_cube->lineCount()));
01368     cubeGrp += PvlKeyword("Bands",   toString(p_cube->bandCount()));
01369     whatsThisObj += cubeGrp;
01370 
01371     // Get Viewport Info
01372     PvlGroup viewportGrp("ViewportDimensions");
01373     viewportGrp += PvlKeyword("Samples", toString(viewport()->width()));
01374     viewportGrp += PvlKeyword("Lines",   toString(viewport()->height()));
01375     whatsThisObj += viewportGrp;
01376 
01377     // Get Cube area Info
01378     PvlObject cubeAreaPvl("CubeArea");
01379     PvlGroup bandGrp("Bands");
01380 
01381     PvlKeyword filterName;
01382     getBandFilterName(filterName);
01383     int iFilterSize = filterName.Size();
01384 
01385     // color
01386     if(p_color ) {
01387       PvlKeyword virtualKey("Virtual"), physicalKey("Physical"), filterNameKey;
01388       int iRedBand   = p_redBuffer->getBand();
01389       int iGreenBand = p_greenBuffer->getBand();
01390       int iBlueBand  = p_blueBuffer->getBand();
01391 
01392       bandGrp += PvlKeyword("Color", "RGB");
01393 
01394       virtualKey = toString(iRedBand);
01395       virtualKey += toString(iGreenBand);
01396       virtualKey += toString(iBlueBand);
01397       bandGrp   += virtualKey;
01398 
01399       physicalKey =  toString(p_cube->physicalBand(iRedBand));
01400       physicalKey += toString(p_cube->physicalBand(iGreenBand));
01401       physicalKey += toString(p_cube->physicalBand(iBlueBand));
01402       bandGrp += physicalKey;
01403 
01404       if(iFilterSize) {
01405         if(iRedBand <= iFilterSize) {
01406           filterNameKey += filterName[iRedBand-1];
01407         }
01408         else {
01409           filterNameKey += "None";
01410         }
01411 
01412         if(iGreenBand <= iFilterSize) {
01413           filterNameKey += filterName[iGreenBand-1];
01414         }
01415         else {
01416           filterNameKey += "None";
01417         }
01418 
01419         if(iBlueBand <= iFilterSize) {
01420           filterNameKey += filterName[iBlueBand-1];
01421         }
01422         else {
01423           filterNameKey += "None";
01424         }
01425         bandGrp += filterNameKey;
01426       }
01427     }
01428     else { // gray
01429       int iGrayBand = p_grayBuffer->getBand();
01430 
01431       bandGrp  += PvlKeyword("Color", "Gray");
01432 
01433       bandGrp  += PvlKeyword("Virtual", toString(iGrayBand));
01434       bandGrp  += PvlKeyword("Physical", toString(p_cube->physicalBand(iGrayBand)));
01435 
01436       if(iFilterSize && iGrayBand <= iFilterSize) {
01437         bandGrp  += PvlKeyword("FilterName", filterName[iGrayBand-1]);
01438       }
01439     }
01440 
01441     //start, end  line and sample
01442     double sl, ss, es, el;
01443     getCubeArea(ss, es, sl, el);
01444     cubeAreaPvl += PvlKeyword("StartSample", toString(int(ss + 0.5)));
01445     cubeAreaPvl += PvlKeyword("EndSample",   toString(int(es + 0.5)));
01446     cubeAreaPvl += PvlKeyword("StartLine",   toString(int(sl + 0.5)));
01447     cubeAreaPvl += PvlKeyword("EndLine",     toString(int(el + 0.5)));
01448     cubeAreaPvl += bandGrp;
01449     whatsThisObj += cubeAreaPvl;
01450     pWhatsThisPvl += whatsThisObj;
01451   }
01452 
01461   void CubeViewport::getBandFilterName(PvlKeyword & pFilterNameKey)
01462   {
01463     // get the band info
01464     Pvl* cubeLbl = p_cube->label();
01465     PvlObject isisObj = cubeLbl->FindObject("IsisCube");
01466     if (isisObj.HasGroup("BandBin")) {
01467       PvlGroup bandBinGrp = isisObj.FindGroup("BandBin");
01468       if(bandBinGrp.HasKeyword("FilterName")) {
01469         pFilterNameKey =bandBinGrp.FindKeyword("FilterName") ;
01470       }
01471     }
01472   }
01473 
01482   void CubeViewport::getCubeArea(double & pdStartSample, double & pdEndSample,
01483                                  double & pdStartLine, double & pdEndLine)
01484   {
01485     viewportToCube(0, 0, pdStartSample, pdStartLine);
01486     if(pdStartSample < 1.0){
01487       pdStartSample = 1.0;
01488     }
01489     if(pdStartLine < 1.0){
01490       pdStartLine = 1.0;
01491     }
01492 
01493     //end line and samples
01494     viewportToCube(viewport()->width() - 1, viewport()->height() - 1, pdEndSample, pdEndLine);
01495     if(pdEndSample > cubeSamples()){
01496       pdEndSample = cubeSamples();
01497     }
01498     if(pdEndLine > cubeLines()){
01499       pdEndLine = cubeLines();
01500     }
01501   }
01502 
01507   void CubeViewport::updateWhatsThis() {
01508     //start, end  line and sample
01509     double sl, ss, es, el;
01510     getCubeArea(ss, es, sl, el);
01511 
01512     QString sBandInfo ;
01513     PvlKeyword filterNameKey;
01514     getBandFilterName(filterNameKey);
01515     int iFilterSize = filterNameKey.Size();
01516 
01517     // color
01518     if(p_color ) {
01519       int iRedBand   = p_redBuffer->getBand();
01520       int iGreenBand = p_greenBuffer->getBand();
01521       int iBlueBand  = p_blueBuffer->getBand();
01522 
01523       sBandInfo = "Bands(RGB)&nbsp;Virtual  = " +
01524           QString::number(iRedBand) + ", ";
01525       sBandInfo += QString::number(iGreenBand) + ", ";
01526       sBandInfo += QString::number(iBlueBand) + " ";
01527 
01528       sBandInfo += "Physical = " +
01529           QString::number(p_cube->physicalBand(iRedBand)) + ", ";
01530       sBandInfo += QString::number(p_cube->physicalBand(iGreenBand)) + ", ";
01531       sBandInfo += QString::number(p_cube->physicalBand(iBlueBand));
01532 
01533       if(iFilterSize) {
01534         sBandInfo += "<br>FilterName = ";
01535         if(iRedBand <= iFilterSize) {
01536           sBandInfo += QString(filterNameKey[iRedBand-1]);
01537         }
01538         else {
01539           sBandInfo += "None";
01540         }
01541         sBandInfo += ", ";
01542 
01543         if(iGreenBand <= iFilterSize) {
01544           sBandInfo += QString(filterNameKey[iGreenBand-1]);
01545         }
01546         else {
01547           sBandInfo += "None";
01548         }
01549         sBandInfo += ", ";
01550 
01551         if(iBlueBand <= iFilterSize) {
01552           sBandInfo += QString(filterNameKey[iBlueBand-1]);
01553         }
01554         else {
01555           sBandInfo += "None";
01556         }
01557       }
01558     }
01559     else { // gray
01560       int iGrayBand = p_grayBuffer->getBand();
01561 
01562       sBandInfo = "Band(Gray)&nbsp;Virtual = " + QString::number(iGrayBand) + " ";
01563 
01564       sBandInfo += "Physical = " + QString::number(p_cube->physicalBand(iGrayBand));
01565 
01566       if(iFilterSize && iGrayBand <= iFilterSize) {
01567         sBandInfo += "<br>FilterName = " + QString(filterNameKey[iGrayBand-1]);
01568       }
01569     }
01570 
01571     QString area =
01572       "<p><b>Visible Cube Area:</b><blockQuote> \
01573       Samples = " + QString::number(int(ss + 0.5)) + "-" +
01574       QString::number(int(es + 0.5)) + "<br> \
01575       Lines = " + QString::number(int(sl + 0.5)) + "-" +
01576       QString::number(int(el + 0.5)) + "<br> " +
01577       sBandInfo + "</blockQuote></p>";
01578 
01579     viewport()->setWhatsThis(p_whatsThisText + area + p_cubeWhatsThisText +
01580                          p_viewportWhatsThisText);
01581   }
01582 
01592   double CubeViewport::redPixel(int sample, int line) {
01593     p_pntBrick->SetBasePosition(sample, line, p_red.band);
01594     p_cube->read(*p_pntBrick);
01595     return (*p_pntBrick)[0];
01596   }
01597 
01598 
01608   double CubeViewport::greenPixel(int sample, int line) {
01609     p_pntBrick->SetBasePosition(sample, line, p_green.band);
01610     p_cube->read(*p_pntBrick);
01611     return (*p_pntBrick)[0];
01612   }
01613 
01614 
01624   double CubeViewport::bluePixel(int sample, int line) {
01625     p_pntBrick->SetBasePosition(sample, line, p_blue.band);
01626     p_cube->read(*p_pntBrick);
01627     return (*p_pntBrick)[0];
01628   }
01629 
01630 
01640   double CubeViewport::grayPixel(int sample, int line) {
01641     p_pntBrick->SetBasePosition(sample, line, p_gray.band);
01642     p_cube->read(*p_pntBrick);
01643     return (*p_pntBrick)[0];
01644   }
01645 
01646 
01648   Stretch CubeViewport::grayStretch() const {
01649     return p_gray.getStretch();
01650   }
01651 
01652 
01654   Stretch CubeViewport::redStretch() const {
01655     return p_red.getStretch();
01656   };
01657 
01658 
01660   Stretch CubeViewport::greenStretch() const {
01661     return p_green.getStretch();
01662   };
01663 
01664 
01666   Stretch CubeViewport::blueStretch() const {
01667     return p_blue.getStretch();
01668   };
01669 
01670 
01680   bool CubeViewport::eventFilter(QObject *o, QEvent *e) {
01681     // Handle standard mouse tracking on the viewport
01682     if(o == viewport()) {
01683       switch(e->type()) {
01684         case QEvent::Enter: {
01685           viewport()->setMouseTracking(true);
01686           emit mouseEnter();
01687           return true;
01688         }
01689 
01690         case QEvent::MouseMove: {
01691           QMouseEvent *m = (QMouseEvent *) e;
01692           emit mouseMove(m->pos());
01693           emit mouseMove(m->pos(), (Qt::MouseButton)(m->button() +
01694                                     m->modifiers()));
01695           return true;
01696         }
01697 
01698         case QEvent::Leave: {
01699           viewport()->setMouseTracking(false);
01700           emit mouseLeave();
01701           return true;
01702         }
01703 
01704         case QEvent::MouseButtonPress: {
01705           QMouseEvent *m = (QMouseEvent *) e;
01706           emit mouseButtonPress(m->pos(),
01707                                 (Qt::MouseButton)(m->button() + m->modifiers()));
01708           return true;
01709         }
01710 
01711         case QEvent::MouseButtonRelease: {
01712           QMouseEvent *m = (QMouseEvent *) e;
01713           emit mouseButtonRelease(m->pos(),
01714                                   (Qt::MouseButton)(m->button() + m->modifiers()));
01715           return true;
01716         }
01717 
01718         case QEvent::MouseButtonDblClick: {
01719           QMouseEvent *m = (QMouseEvent *) e;
01720           emit mouseDoubleClick(m->pos());
01721           return true;
01722         }
01723 
01724         default: {
01725           return false;
01726         }
01727       }
01728     }
01729     else {
01730       return QAbstractScrollArea::eventFilter(o, e);
01731     }
01732   }
01733 
01734 
01741   void CubeViewport::keyPressEvent(QKeyEvent *e) {
01742     if(e->key() == Qt::Key_Plus) {
01743       double scale = p_scale * 2.0;
01744       setScale(scale);
01745       e->accept();
01746     }
01747     else if(e->key() == Qt::Key_Minus) {
01748       double scale = p_scale / 2.0;
01749       setScale(scale);
01750       e->accept();
01751     }
01752     else if(e->key() == Qt::Key_Up) {
01753       moveCursor(0, -1);
01754       e->accept();
01755     }
01756     else if(e->key() == Qt::Key_Down) {
01757       moveCursor(0, 1);
01758       e->accept();
01759     }
01760     else if(e->key() == Qt::Key_Left) {
01761       moveCursor(-1, 0);
01762       e->accept();
01763     }
01764     else if(e->key() == Qt::Key_Right) {
01765       moveCursor(1, 0);
01766       e->accept();
01767     }
01768     else {
01769       QAbstractScrollArea::keyPressEvent(e);
01770     }
01771   }
01772 
01773 
01780   bool CubeViewport::cursorInside() const {
01781     QPoint g = QCursor::pos();
01782     QPoint v = viewport()->mapFromGlobal(g);
01783     if(v.x() < 0){
01784       return false;
01785     }
01786     if(v.y() < 0){
01787       return false;
01788     }
01789     if(v.x() >= viewport()->width()){
01790       return false;
01791     }
01792     if(v.y() >= viewport()->height()){
01793       return false;
01794     }
01795     return true;
01796   }
01797 
01798 
01805   QPoint CubeViewport::cursorPosition() const {
01806     QPoint g = QCursor::pos();
01807     return viewport()->mapFromGlobal(g);
01808   }
01809 
01810 
01818   void CubeViewport::moveCursor(int x, int y) {
01819     QPoint g = QCursor::pos();
01820     g += QPoint(x, y);
01821     QPoint v = viewport()->mapFromGlobal(g);
01822     if(v.x() < 0){
01823       return;
01824     }
01825     if(v.y() < 0){
01826       return;
01827     }
01828     if(v.x() >= viewport()->width()){
01829       return;
01830     }
01831     if(v.y() >= viewport()->height()){
01832       return;
01833     }
01834     QCursor::setPos(g);
01835   }
01836 
01837 
01845   void CubeViewport::setCursorPosition(int x, int y) {
01846     QPoint g(x, y);
01847     QPoint v = viewport()->mapToGlobal(g);
01848     QCursor::setPos(v);
01849   }
01850 
01851 
01859   void CubeViewport::updateScrollBars(int x, int y) {
01860     viewport()->blockSignals(true);
01861 
01862     verticalScrollBar()->setValue(1);
01863     verticalScrollBar()->setMinimum(1);
01864     verticalScrollBar()->setMaximum((int)(ceil(cubeLines() * p_scale) + 0.5));
01865     verticalScrollBar()->setPageStep(viewport()->height() / 2);
01866 
01867     horizontalScrollBar()->setValue(1);
01868     horizontalScrollBar()->setMinimum(1);
01869     horizontalScrollBar()->setMaximum((int)(ceil(cubeSamples() * p_scale) + 0.5));
01870     horizontalScrollBar()->setPageStep(viewport()->width() / 2);
01871 
01872     if(horizontalScrollBar()->value() != x || verticalScrollBar()->value() != y) {
01873       horizontalScrollBar()->setValue(x);
01874       verticalScrollBar()->setValue(y);
01875       emit scaleChanged();
01876     }
01877 
01878     QApplication::sendPostedEvents(viewport(), 0);
01879     viewport()->blockSignals(false);
01880   }
01881 
01882 
01889   void CubeViewport::viewGray(int band) {
01890     p_gray.band = band;
01891     p_color = false;
01892     setCaption();
01893 
01894     if(!p_grayBuffer){
01895       p_grayBuffer = new ViewportBuffer(this, p_cubeData,
01896                                         p_cubeId);
01897     }
01898 
01899     if(p_redBuffer){
01900       delete p_redBuffer;
01901     }
01902     p_redBuffer = NULL;
01903 
01904     if(p_greenBuffer){
01905       delete p_greenBuffer;
01906     }
01907     p_greenBuffer = NULL;
01908 
01909     if(p_blueBuffer){
01910       delete p_blueBuffer;
01911     }
01912     p_blueBuffer = NULL;
01913 
01914     if(p_grayBuffer->getBand() != band) {
01915       int oldBand = p_grayBuffer->getBand();
01916 
01917       if(oldBand >= 0) {
01918         if((*p_knownStretches)[oldBand - 1]) {
01919           delete(*p_knownStretches)[oldBand - 1];
01920         }
01921 
01922         (*p_knownStretches)[oldBand - 1] = new Stretch(p_gray.getStretch());
01923       }
01924 
01925       p_grayBuffer->setBand(band);
01926       p_gray.band = band;
01927 
01928       if((*p_knownStretches)[band - 1]) {
01929         stretchGray(*(*p_knownStretches)[band - 1]);
01930       }
01931       else {
01932         p_grayBuffer->addStretchAction();
01933       }
01934     }
01935 
01936 
01937     if(p_camera) {
01938       p_camera->SetBand(band);
01939     }
01940 
01941     viewport()->repaint();
01942   }
01943 
01944   void CubeViewport::forgetStretches() {
01945     for(int stretch = 0; stretch < p_knownStretches->size(); stretch++) {
01946       if((*p_knownStretches)[stretch]) {
01947         delete(*p_knownStretches)[stretch];
01948         (*p_knownStretches)[stretch] = NULL;
01949       }
01950     }
01951   }
01952 
01953 
01954   void CubeViewport::setAllBandStretches(Stretch stretch) {
01955     for(int index = 0; index < p_knownStretches->size(); index ++) {
01956       if((*p_knownStretches)[index]) {
01957         delete(*p_knownStretches)[index];
01958       }
01959 
01960       (*p_knownStretches)[index] = new Stretch(stretch);
01961     }
01962   }
01963 
01964 
01973   void CubeViewport::viewRGB(int rband, int gband, int bband) {
01974     p_red.band = rband;
01975     p_green.band = gband;
01976     p_blue.band = bband;
01977     p_color = true;
01978     setCaption();
01979 
01980     if(!p_redBuffer) {
01981       p_redBuffer = new ViewportBuffer(this, p_cubeData, p_cubeId);
01982     }
01983 
01984     if(!p_greenBuffer) {
01985       p_greenBuffer = new ViewportBuffer(this, p_cubeData, p_cubeId);
01986     }
01987 
01988     if(!p_blueBuffer) {
01989       p_blueBuffer = new ViewportBuffer(this, p_cubeData, p_cubeId);
01990     }
01991 
01992     if(p_redBuffer->getBand() != rband) {
01993       int oldBand = p_redBuffer->getBand();
01994 
01995       // Remember current stretch for future band changes
01996       if(oldBand >= 0) {
01997         if((*p_knownStretches)[oldBand - 1]) {
01998           delete(*p_knownStretches)[oldBand - 1];
01999         }
02000 
02001         (*p_knownStretches)[oldBand - 1] = new Stretch(p_red.getStretch());
02002       }
02003 
02004       p_redBuffer->setBand(rband);
02005       p_red.band = rband;
02006 
02007       if((*p_knownStretches)[rband - 1]) {
02008         p_red.setStretch(*(*p_knownStretches)[rband - 1]);
02009       }
02010       else {
02011         p_redBuffer->addStretchAction();
02012       }
02013     }
02014 
02015     if(p_greenBuffer->getBand() != gband) {
02016       int oldBand = p_greenBuffer->getBand();
02017 
02018       // Remember current stretch for future band changes
02019       if(oldBand >= 0) {
02020         if((*p_knownStretches)[oldBand - 1]) {
02021           delete(*p_knownStretches)[oldBand - 1];
02022         }
02023 
02024         (*p_knownStretches)[oldBand - 1] = new Stretch(p_green.getStretch());
02025       }
02026 
02027       p_greenBuffer->setBand(gband);
02028       p_green.band = gband;
02029 
02030       if((*p_knownStretches)[gband - 1]) {
02031         p_green.setStretch(*(*p_knownStretches)[gband - 1]);
02032       }
02033       else {
02034         p_greenBuffer->addStretchAction();
02035       }
02036     }
02037 
02038     if(p_blueBuffer->getBand() != bband) {
02039       int oldBand = p_blueBuffer->getBand();
02040 
02041       // Remember current stretch for future band changes
02042       if(oldBand >= 0) {
02043         if((*p_knownStretches)[oldBand - 1]) {
02044           delete(*p_knownStretches)[oldBand - 1];
02045         }
02046 
02047         (*p_knownStretches)[oldBand - 1] = new Stretch(p_blue.getStretch());
02048       }
02049 
02050       p_blueBuffer->setBand(bband);
02051       p_blue.band = bband;
02052 
02053       if((*p_knownStretches)[bband - 1]) {
02054         p_blue.setStretch(*(*p_knownStretches)[bband - 1]);
02055       }
02056       else {
02057         p_blueBuffer->addStretchAction();
02058       }
02059     }
02060 
02061     if(p_grayBuffer){
02062       delete p_grayBuffer;
02063     }
02064     p_grayBuffer = NULL;
02065 
02066     if(p_camera) {
02067       p_camera->SetBand(rband);
02068     }
02069   }
02070 
02071 
02078   void CubeViewport::stretchGray(const QString &string) {
02079     Stretch stretch;
02080     stretch.Parse(string);
02081     stretchGray(stretch);
02082   }
02083 
02084 
02090   void CubeViewport::stretchRed(const QString &string) {
02091     Stretch stretch;
02092     stretch.Parse(string);
02093     stretchRed(stretch);
02094   }
02095 
02096 
02102   void CubeViewport::stretchGreen(const QString &string) {
02103     Stretch stretch;
02104     stretch.Parse(string);
02105     stretchGreen(stretch);
02106   }
02107 
02108 
02114   void CubeViewport::stretchBlue(const QString &string) {
02115     Stretch stretch;
02116     stretch.Parse(string);
02117     stretchBlue(stretch);
02118   }
02119 
02120 
02124   void CubeViewport::stretchKnownGlobal() {
02125     if(!p_globalStretches){
02126       return;
02127     }
02128 
02129     if(isGray()) {
02130       if((*p_globalStretches)[grayBand() - 1]) {
02131         stretchGray(*(*p_globalStretches)[grayBand() - 1]);
02132       }
02133     }
02134     else {
02135       if((*p_globalStretches)[redBand() - 1]) {
02136         stretchRed(*(*p_globalStretches)[redBand() - 1]);
02137       }
02138 
02139       if((*p_globalStretches)[greenBand() - 1]) {
02140         stretchGreen(*(*p_globalStretches)[greenBand() - 1]);
02141       }
02142 
02143       if((*p_globalStretches)[blueBand() - 1]) {
02144         stretchBlue(*(*p_globalStretches)[blueBand() - 1]);
02145       }
02146     }
02147   }
02148 
02149 
02155   void CubeViewport::stretchGray(const Stretch &stretch) {
02156     // Assume first stretch is always the global stretch (and it should be)
02157     if((*p_globalStretches)[grayBand() - 1] == NULL && stretch.Pairs()) {
02158       (*p_globalStretches)[grayBand() - 1] = new Stretch(stretch);
02159     }
02160 
02161     p_gray.setStretch(stretch);
02162 
02163     Stretch newRed(p_red.getStretch());
02164     newRed.CopyPairs(stretch);
02165     p_red.setStretch(newRed);
02166 
02167     Stretch newGreen(p_green.getStretch());
02168     newGreen.CopyPairs(stretch);
02169     p_green.setStretch(newGreen);
02170 
02171     Stretch newBlue(p_blue.getStretch());
02172     newBlue.CopyPairs(stretch);
02173     p_blue.setStretch(newBlue);
02174 
02175     paintPixmap();
02176     viewport()->update();
02177   }
02178 
02179 
02185   void CubeViewport::stretchRed(const Stretch &stretch) {
02186     p_red.setStretch(stretch);
02187 
02188     // Assume first stretch is always the global stretch (and it should be)
02189     if((*p_globalStretches)[redBand() - 1] == NULL && stretch.Pairs()) {
02190       (*p_globalStretches)[redBand() - 1] = new Stretch(p_red.getStretch());
02191     }
02192 
02193     paintPixmap();
02194     viewport()->update();
02195   }
02196 
02197 
02203   void CubeViewport::stretchGreen(const Stretch &stretch) {
02204     p_green.setStretch(stretch);
02205 
02206     // Assume first stretch is always the global stretch (and it should be)
02207     if((*p_globalStretches)[greenBand() - 1] == NULL && stretch.Pairs()) {
02208       (*p_globalStretches)[greenBand() - 1] = new Stretch(p_green.getStretch());
02209     }
02210 
02211     paintPixmap();
02212     viewport()->update();
02213   }
02214 
02215 
02221   void CubeViewport::stretchBlue(const Stretch &stretch) {
02222     p_blue.setStretch(stretch);
02223 
02224     // Assume first stretch is always the global stretch (and it should be)
02225     if((*p_globalStretches)[blueBand() - 1] == NULL && stretch.Pairs()) {
02226       (*p_globalStretches)[blueBand() - 1] = new Stretch(p_blue.getStretch());
02227     }
02228 
02229     paintPixmap();
02230     viewport()->update();
02231   }
02232 
02233 
02241   double CubeViewport::fitScale() const {
02242     double sampScale = (double) viewport()->width() / (double) cubeSamples();
02243     double lineScale = (double) viewport()->height() / (double) cubeLines();
02244     double scale = sampScale < lineScale ? sampScale : lineScale;
02245 //    scale = floor(scale * 100.0) / 100.0;
02246     return scale;
02247   }
02248 
02249 
02256   double CubeViewport::fitScaleWidth() const {
02257     double scale = (double) viewport()->width() / (double) cubeSamples();
02258 
02259 //    scale = floor(scale * 100.0) / 100.0;
02260     return scale;
02261   }
02262 
02269   double CubeViewport::fitScaleHeight() const {
02270     double scale = (double) viewport()->height() / (double) cubeLines();
02271 
02272 //    scale = floor(scale * 100.0) / 100.0;
02273     return scale;
02274   }
02275 
02283   void CubeViewport::cubeContentsChanged(QRect cubeRect) {
02284     //start sample/line and end sample/line
02285     double ss, sl, es, el;
02286     ss = (double)(cubeRect.left()) - 1.;
02287     sl = (double)(cubeRect.top()) - 1.;
02288     es = (double)(cubeRect.right()) + 1.;
02289     el = (double)(cubeRect.bottom()) + 1.;
02290     if(ss < 1){
02291       ss = 0.5;
02292     }
02293     if(sl < 1){
02294       sl = 0.5;
02295     }
02296     if(es > cube()->sampleCount()){
02297       es = cube()->sampleCount() + 0.5;
02298     }
02299     if(el > cube()->lineCount()){
02300       el = cube()->lineCount() + 0.5;
02301     }
02302 
02303     //start x/y and end x/y
02304     int sx, sy, ex, ey;
02305 
02306     cubeToViewport(ss, sl, sx, sy);
02307     cubeToViewport(es, el, ex, ey);
02308     if(sx < 0){
02309       sx = 0;
02310     }
02311     if(sy < 0){
02312       sy = 0;
02313     }
02314     if(ex > viewport()->width()){
02315       ex = viewport()->width();
02316     }
02317     if(ey > viewport()->height()){
02318       ey = viewport()->height();
02319     }
02320     QRect vpRect(sx, sy, ex - sx + 1, ey - sy + 1);
02321 
02322     p_updatingBuffers = true;
02323     if(p_grayBuffer){
02324       p_grayBuffer->fillBuffer(vpRect);
02325     }
02326     if(p_redBuffer){
02327       p_redBuffer->fillBuffer(vpRect);
02328     }
02329     if(p_greenBuffer){
02330       p_greenBuffer->fillBuffer(vpRect);
02331     }
02332     if(p_blueBuffer){
02333       p_blueBuffer->fillBuffer(vpRect);
02334     }
02335     p_updatingBuffers = false;
02336 
02337     paintPixmapRects();
02338   }
02339 
02340 
02347   void CubeViewport::changeCursor(QCursor cursor) {
02348     viewport()->setCursor(cursor);
02349   }
02350 
02351 
02352   CubeViewport::BandInfo::BandInfo() : band(1), stretch(NULL) {
02353     stretch = new Stretch;
02354     stretch->SetNull(0.0);
02355     stretch->SetLis(0.0);
02356     stretch->SetLrs(0.0);
02357     stretch->SetHis(255.0);
02358     stretch->SetHrs(255.0);
02359     stretch->SetMinimum(0.0);
02360     stretch->SetMaximum(255.0);
02361   };
02362 
02363 
02364   CubeViewport::BandInfo::BandInfo(const CubeViewport::BandInfo &other) :
02365     band(other.band) {
02366     stretch = NULL;
02367     stretch = new Stretch(*other.stretch);
02368   }
02369 
02370 
02371   CubeViewport::BandInfo::~BandInfo() {
02372     if(stretch) {
02373       delete stretch;
02374       stretch = NULL;
02375     }
02376   }
02377 
02378 
02379   Stretch CubeViewport::BandInfo::getStretch() const {
02380     ASSERT_PTR(stretch);
02381 
02382     return *stretch;
02383   }
02384 
02385 
02386   void CubeViewport::BandInfo::setStretch(const Stretch &newStretch) {
02387     *stretch = newStretch;
02388   }
02389 
02390 
02391   const CubeViewport::BandInfo &CubeViewport::BandInfo::operator=(
02392     CubeViewport::BandInfo other) {
02393     ASSERT_PTR(other.stretch);
02394 
02395     stretch = NULL;
02396     stretch = new Stretch;
02397     *stretch = *other.stretch;
02398     band = other.band;
02399 
02400     return *this;
02401   }
02402 
02403 }