// Implementation of QTreeCanvas #include <clientapi.h> #include <qcanvas.h> #include "qtreeitem.h" #include "changesorter.h" #include "filehead.h" #include "filelogcache.h" #include "clientchangeuser.h" #include "qtreechangenum.h" #include "qtreechangebar.h" #include "clientjobdescuser.h" #include "qtreejobtext.h" #include "qtreejobbar.h" #include "qtreerevtext.h" #include "qtreerevball.h" #include "qtreefiletext.h" #include "qtreefilestripe.h" #include "qtreearrow.h" #include "qtreecanvas.h" extern bool namesort; QTreeCanvas::QTreeCanvas ( QWidget* parent, char* file, ClientApi* cli, Error* e, bool jobs, bool trunc, QString cstart, QString dstart, QString end, bool all, char* cfile ) :QCanvas( parent ), client( cli ), error( e ), cachefile( cfile ) { StrBuf filebuf = StrBuf(); filebuf.Set( file ); client->Init( error ); // This is where the server actually gets queried. cache = new FileLogCache ( filebuf, client, error, cstart.latin1(), dstart.latin1(), end.latin1(), all, cfile ); if ( IsEmpty() ) { client->Final( error ); if ( !cstart.isNull() || !end.isNull() || !dstart.isNull() ) error->Set( E_WARN, "Try turning off date cropping.\n" ); error->Set( E_WARN, "The graph could not be generated.\n" ); return; // Fatal error, abort. } // If birds-eye view, need to tell the FileLogCache that. if ( trunc ) cache->SetArrows(); // Now lay out all the actual canvas items. // Set width. QCanvasText* testtext = new QCanvasText( cache->main->name.Text(), this ); barwidth = testtext->boundingRect().width(); barwidth += 100; delete testtext; // Changebar changebar = new QTreeChangeBar( this, cache->changes, trunc ); changebar->show(); // Jobbar int jheight = 0; if ( jobs ) { jobbar = new QTreeJobBar( this, changebar->width(), changebar->height(), cache->changes, client, error, trunc ); jobbar->show(); jheight = jobbar->height(); } else jobbar = NULL; // After the jobbar finishes running "p4 fixes", we're done talking. client->Final( error ); // Now do FileStripes. The FileStripe constructor does RevBalls. filestripes = new QTreeFileStripe*[cache->size]; FileHead* fileh; char color; bool altcolor = true; int i = 0; for ( fileh = cache->head ; fileh ; fileh = fileh->next_into ) { if ( fileh->size == 0 ) //nothing to see here, folks { cache->size--; //warning - this makes it impossible to //reuse a FLC. Think about rewriting this. continue; } if ( fileh == cache->main ) color = 'M'; else { if ( altcolor ) color = 'A'; else color = 'B'; altcolor = !altcolor; } filestripes[i] = new QTreeFileStripe( this, fileh, changebar->width(), TREE_STRIPEHEIGHT*i+changebar->height()+jheight, color, trunc ); filestripes[i]->show(); i++; } // Now that we know the geometry, set the canvas size. resize( changebar->width(), changebar->height() + TREE_STRIPEHEIGHT*cache->size + jheight ); if ( namesort ) NameSort(); // Last, set up arrows - this is sufficiently different depending on // whether it's a branch-only view that it needs its own method. if (trunc) InitTruncArrows(); else InitNormalArrows(); // Gridline - hidden to start. gridline = new QCanvasLine( this ); gridline->setZ( TREE_ZARROW ); gridline->hide(); UpdateColors(); } // Set up FileStripes, RevBalls, Arrows, etc. void QTreeCanvas::InitNormalArrows() { // Loop thru all files, revs, and arrows. arrows = new QTreeArrow*[cache->numarrows]; int a = 0; // Need to do an arrow for each FileRevArrow we find. for ( FileHead* fileh = cache->head ; fileh ; fileh = fileh->next_into ) { for ( FileRev* filer = fileh->head ; filer ; filer = filer->next ) { for ( FileRevArrow* farrow = filer->fromarrows ; farrow && a < cache->numarrows ; farrow = farrow->next ) { arrows[a] = new QTreeArrow( farrow->ptr->revball, filer->revball, farrow->type, farrow->contrib ); arrows[a++]->show(); } } } // Initialize any empty array spots to NULL, just in case. for ( ; a < cache->numarrows ; a++ ) arrows[a] = NULL; } void QTreeCanvas::InitTruncArrows() { // In addition to drawing arrows normally, fill gaps with gold arrows. arrows = new QTreeArrow*[cache->numarrows]; int a = 0; for ( FileHead* fileh = cache->head ; fileh ; fileh = fileh->next_into ) { for ( FileRev* filer = fileh->head ; filer ; filer = filer->next ) { if ( filer->revball == NULL ) continue; // rev not drawn for ( FileRevArrow* farrow = filer->fromarrows ; farrow && a < cache->numarrows ; farrow = farrow->next ) { if ( farrow->ptr->revball ) { arrows[a] = new QTreeArrow(farrow->ptr->revball, filer->revball, farrow->type, farrow->contrib); arrows[a++]->show(); continue; } // No revball. Add a gold arrow and then continue for ( FileRev* anc = farrow->ptr; anc; anc = anc->next ) { if ( anc->revball ) { arrows[a] = new QTreeArrow( anc->revball, filer->revball, a_broken, c_broken ); arrows[a++]->show(); break; } } } } } // Initialize any empty array spots to NULL, just in case. for ( ; a < cache->numarrows ; a++ ) arrows[a] = NULL; } void QTreeCanvas::NameSort() { //Alphabetical sort of filestripes. int a, b; QTreeFileStripe* temp; double ay, by; char color = 'A'; for ( a = 0 ; a < cache->size ; a++ ) { for ( b = a+1 ; b < cache->size ; b++ ) { if ( filestripes[b]->Name() < filestripes[a]->Name() ) { ay = filestripes[a]->y(); by = filestripes[b]->y(); temp = filestripes[b]; filestripes[b] = filestripes[a]; filestripes[a] = temp; filestripes[a]->MoveY( ay ); filestripes[b]->MoveY( by ); } } if ( filestripes[a]->stripecolor == 'M' ) continue; filestripes[a]->stripecolor = color; color = ( color == 'A' ? 'B' : 'A' ); } } void QTreeCanvas::UpdateColors() { for ( int a = 0 ; a < cache->size ; a++ ) { if ( filestripes[a] ) filestripes[a]->UpdateBrush(); } for ( int b = 0 ; b < cache->numarrows ; b++ ) { if ( arrows[b] ) arrows[b]->UpdatePen(); } changebar->UpdateBrush(); if ( jobbar ) jobbar->UpdateBrush(); } void QTreeCanvas::UpdateFTexts( int xcoord ) { for ( int a=0 ; a < cache->size ; a++ ) if ( filestripes[a] ) filestripes[a]->UpdateFText( xcoord ); // Update the canvas so it redraws the FileTexts. update(); } QSize QTreeCanvas::ChangeSize() { if ( jobbar ) return QSize( changebar->width(), changebar->height() + jobbar->height() ); else return QSize( changebar->width(), changebar->height() ); } void QTreeCanvas::GridLine( int x ) { if ( gridline->isVisible() ) { gridline->hide(); return; } gridline->setPoints( x, TREE_BARHEIGHT, x, height() ); gridline->show(); } QTreeCanvas::~QTreeCanvas() { }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#9 | 4450 | Sam Stafford |
Slight refactoring of "name sort" code... this was to lead to an implementation of "directory graphing" but it didn't pan out. Will need to kludge more than previously thought to make that happen. |
||
#8 | 4422 | Sam Stafford |
Finished implementing alphabetical sort. Along the way, I gained new appreciation for the OpenGL canvas system I implemented for Revision Graph, for it is vastly superior to this QCanvas crud in many ways. Might go ahead and implement this in Revision Graph just to marvel at how many fewer lines of new code it takes. Turn on alphabetical sort by adding the "-n" option to the command line ("-n" for "name sort"). This feature is not accessible from the settings dialog, nor does it persist after a refresh, but it DOES stack with "-o outputfile", which as far as I know is all that anyone needs. |
||
#7 | 4419 | Sam Stafford |
Framework for command line alphabetical sort option. No functional change (still need to implement the sort algorithm). |
||
#6 | 2949 | Sam Stafford |
Don't draw empty FileHeads. This includes ones that you don't have "list" permission to filelog, as well as ones missing from a cache file. You'll still get warnings about their inaccessibility. |
||
#5 | 2947 | Sam Stafford |
Give P4QTree the ability to read filelog data from a supplied text file. The syntax is: P4QTree [g-opts] [-F cachefile] depotfile The data in the supplied file will be read before the server is queried for a given filelog. If a required filelog is not found in the file, the server will be queried instead. The most handy application for this that I can see is quickly graphing integ scenarios based on customer-supplied (or even manually-generated) filelogs, when for whatever reason it's not feasible to access the server directly. |
||
#4 | 2584 | Sam Stafford |
Make minimum canvas width more dynamic - create a dummy CanvasText and use that to guesstimate minimum width. |
||
#3 | 2399 | Sam Stafford | The "show all integs" feature in all its glory. | ||
#2 | 2398 | Sam Stafford |
Support for PB's "show all" feature. Still needs the UI bits to turn it on. Infrastructure change. |
||
#1 | 2377 | Sam Stafford | P4QTree. |