# HG changeset patch # User Chris Cannam # Date 1289580498 0 # Node ID 3c46b2ac45d3a5cb96ef7621d2d70f18c69cd499 # Parent 384420567575eb04271e87f4c71d91a30b0784df * Put proper labels &c in changeset items; colour branches and users; etc diff -r 384420567575 -r 3c46b2ac45d3 changesetitem.cpp --- a/changesetitem.cpp Fri Nov 12 11:32:01 2010 +0000 +++ b/changesetitem.cpp Fri Nov 12 16:48:18 2010 +0000 @@ -1,22 +1,97 @@ #include "changesetitem.h" #include "changeset.h" +#include "textabbrev.h" +#include "colourset.h" #include +ChangesetItem::ChangesetItem(Changeset *cs) : + m_changeset(cs), m_column(0), m_row(0) +{ + m_font = QFont(); + m_font.setPixelSize(11); + m_font.setBold(false); + m_font.setItalic(false); +} + QRectF ChangesetItem::boundingRect() const { - return QRectF(0, 0, 250, 50); + return QRectF(-24, -30, 97, 79); } void ChangesetItem::paint(QPainter *paint, const QStyleOptionGraphicsItem *option, QWidget *w) { -// paint->drawText(50, 0, m_changeset->comment()); - paint->drawText(5, 15, m_changeset->authorName()); - paint->drawText(5, 30, m_changeset->branch()); - paint->drawRect(QRectF(0, 0, 50, 50)); + QTransform t = paint->worldTransform(); -// paint->drawRect(QRectF(0, 0, 50, 50)); + paint->save(); + + ColourSet *colourSet = ColourSet::instance(); + QColor branchColour = colourSet->getColourFor(m_changeset->branch()); + QColor userColour = colourSet->getColourFor(m_changeset->author()); + + paint->setPen(QPen(branchColour, 2)); + + QFont f(m_font); + + float scale = std::min(t.m11(), t.m22()); + if (scale > 1.0) { + int ps = int((f.pixelSize() / scale) + 0.5); + if (ps < 8) ps = 8; + f.setPixelSize(ps); + } + + paint->setFont(f); + QFontMetrics fm(f); + int fh = fm.height(); + + QRectF r(-24, 0, 97, 49); + paint->drawRect(r); + + if (scale < 0.1) { + paint->restore(); + return; + } + + if (m_changeset->children().empty()) { + f.setBold(true); + paint->setFont(f); + paint->drawText(-24, -fh + fm.ascent() - 4, m_changeset->branch()); + f.setBold(false); + } + + paint->fillRect(QRectF(-23.5, 0.5, 96, fh - 0.5), QBrush(userColour)); + + paint->setPen(QPen(Qt::white)); + + int wid = 95; + QString person = TextAbbrev::abbreviate(m_changeset->authorName(), fm, wid); + paint->drawText(-21, fm.ascent(), person); + + paint->setPen(QPen(Qt::black)); + + f.setItalic(true); + fm = QFontMetrics(f); + fh = fm.height(); + paint->setFont(f); + + QString comment = m_changeset->comment().trimmed(); + comment = comment.replace("\\n", "\n"); + comment = comment.replace(QRegExp("^\"\\s*\\**\\s*"), ""); + comment = comment.replace(QRegExp("\"$"), ""); + comment = comment.replace("\\\"", "\""); + comment = comment.split('\n')[0]; + + wid = 95; + comment = TextAbbrev::abbreviate(comment, fm, wid, TextAbbrev::ElideEnd, + "...", 2); + + QStringList lines = comment.split('\n'); + for (int i = 0; i < lines.size(); ++i) { + paint->drawText(-21, i * fh + fh + fm.ascent(), lines[i].trimmed()); + } + + paint->restore(); } diff -r 384420567575 -r 3c46b2ac45d3 changesetitem.h --- a/changesetitem.h Fri Nov 12 11:32:01 2010 +0000 +++ b/changesetitem.h Fri Nov 12 16:48:18 2010 +0000 @@ -2,23 +2,27 @@ #define CHANGESETITEM_H #include +#include class Changeset; class ChangesetItem : public QGraphicsItem { public: - ChangesetItem(Changeset *cs) : m_changeset(cs), m_column(0), m_row(0) { } + ChangesetItem(Changeset *cs); virtual QRectF boundingRect() const; virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + Changeset *getChangeset() { return m_changeset; } + int column() const { return m_column; } int row() const { return m_row; } void setColumn(int c) { m_column = c; setX(c * 100); } - void setRow(int r) { m_row = r; setY(r * 100); } + void setRow(int r) { m_row = r; setY(r * 90); } private: + QFont m_font; Changeset *m_changeset; int m_column; int m_row; diff -r 384420567575 -r 3c46b2ac45d3 colourset.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/colourset.cpp Fri Nov 12 16:48:18 2010 +0000 @@ -0,0 +1,35 @@ + +#include "colourset.h" + +ColourSet +ColourSet::m_instance; + +ColourSet::ColourSet() { } + +ColourSet * +ColourSet::instance() +{ + return &m_instance; +} + +QColor +ColourSet::getColourFor(QString n) +{ + if (m_defaultNames.contains(n)) return Qt::black; + if (m_colours.contains(n)) return m_colours[n]; + + QColor c; + + if (m_colours.empty()) { + c = QColor::fromHsv(0, 200, 100); + } else { + c = QColor::fromHsv((m_lastColour.hue() + 70) % 360, 200, 100); + } + + m_colours[n] = c; + m_lastColour = c; + return c; +} + + + diff -r 384420567575 -r 3c46b2ac45d3 colourset.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/colourset.h Fri Nov 12 16:48:18 2010 +0000 @@ -0,0 +1,28 @@ +#ifndef _COLOURSET_H_ +#define _COLOURSET_H_ + +#include +#include +#include +#include + +class ColourSet +{ +public: + void clearDefaultNames() { m_defaultNames.clear(); } + void addDefaultName(QString n) { m_defaultNames.insert(n); } + + QColor getColourFor(QString n); + + static ColourSet *instance(); + +private: + ColourSet(); + QSet m_defaultNames; + QMap m_colours; + QColor m_lastColour; + + static ColourSet m_instance; +}; + +#endif diff -r 384420567575 -r 3c46b2ac45d3 connectionitem.cpp --- a/connectionitem.cpp Fri Nov 12 11:32:01 2010 +0000 +++ b/connectionitem.cpp Fri Nov 12 16:48:18 2010 +0000 @@ -3,6 +3,8 @@ #include "connectionitem.h" #include "changesetitem.h" +#include "changeset.h" +#include "colourset.h" #include @@ -10,12 +12,13 @@ ConnectionItem::boundingRect() const { if (!m_parent || !m_child) return QRectF(); - float scale = 100; + float xscale = 100; + float yscale = 90; float size = 50; - return QRectF(scale * m_child->column() + size/2 - 2, - scale * m_child->row() + size - 2, - scale * m_parent->column() - scale * m_child->column() + 4, - scale * m_parent->row() - scale * m_child->row() - size + 4) + return QRectF(xscale * m_child->column() + size/2 - 2, + yscale * m_child->row() + size - 2, + xscale * m_parent->column() - xscale * m_child->column() + 4, + yscale * m_parent->row() - yscale * m_child->row() - size + 4) .normalized(); } @@ -23,26 +26,58 @@ ConnectionItem::paint(QPainter *paint, const QStyleOptionGraphicsItem *, QWidget *) { QPainterPath p; - float scale = 100; + + paint->save(); + + ColourSet *colourSet = ColourSet::instance(); + QColor branchColour = colourSet->getColourFor(m_child->getChangeset()->branch()); + paint->setPen(QPen(branchColour, 2)); + + float xscale = 100; + + float yscale = 90; float size = 50; - p.moveTo(scale * m_child->column() + size/2, - scale * m_child->row() + size); - if (m_parent->column() == m_child->column()) { - p.lineTo(scale * m_parent->column() + size/2, - scale * m_parent->row()); - } else { - p.cubicTo(scale * m_child->column() + size/2, - scale * m_child->row() + size + size, - scale * m_parent->column() + size/2, - scale * m_child->row() + size, - scale * m_parent->column() + size/2, - scale * m_child->row() + scale); - if (abs(m_parent->row() - m_child->row()) > 1) { - p.lineTo(scale * m_parent->column() + size/2, - scale * m_parent->row()); + float ygap = yscale - size; + + int c_col = m_child->column(), c_row = m_child->row(); + int p_col = m_parent->column(), p_row = m_parent->row(); + + float c_x = xscale * c_col + size/2; + float p_x = xscale * p_col + size/2; + + p.moveTo(c_x, yscale * c_row + size); + + if (p_col == c_col) { + + p.lineTo(p_x, yscale * p_row); + + } else if (m_type == Split || m_type == Normal) { + + // place the bulk of the line on the child (i.e. branch) row + + if (abs(p_row - c_row) > 1) { + p.lineTo(c_x, yscale * p_row - ygap); + } + + p.cubicTo(c_x, yscale * p_row, + p_x, yscale * p_row - ygap, + p_x, yscale * p_row); + + } else if (m_type == Merge) { + + // place bulk of the line on the parent row + + p.cubicTo(c_x, yscale * c_row + size + ygap, + p_x, yscale * c_row + size, + p_x, yscale * c_row + size + ygap); + + if (abs(p_row - c_row) > 1) { + p.lineTo(p_x, yscale * p_row); } } + paint->drawPath(p); + paint->restore(); } diff -r 384420567575 -r 3c46b2ac45d3 connectionitem.h --- a/connectionitem.h Fri Nov 12 11:32:01 2010 +0000 +++ b/connectionitem.h Fri Nov 12 16:48:18 2010 +0000 @@ -10,11 +10,20 @@ class ConnectionItem : public QGraphicsItem { public: - ConnectionItem() : m_parent(0), m_child(0) { } + enum Type { + Normal, + Split, + Merge + }; + + ConnectionItem() : m_type(Normal), m_parent(0), m_child(0) { } virtual QRectF boundingRect() const; virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + Type connectionType() const { return m_type; } + void setConnectionType(Type t) { m_type = t; } + //!!! deletion signals from parent/child ChangesetItem *parent() { return m_parent; } @@ -24,6 +33,7 @@ void setChild(ChangesetItem *c) { m_child = c; } private: + Type m_type; ChangesetItem *m_parent; ChangesetItem *m_child; }; diff -r 384420567575 -r 3c46b2ac45d3 dateitem.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dateitem.cpp Fri Nov 12 16:48:18 2010 +0000 @@ -0,0 +1,55 @@ + +#include "dateitem.h" + +#include +#include +#include + +void +DateItem::setRows(int minrow, int n) +{ + m_minrow = minrow; + m_maxrow = minrow + n - 1; + setY(m_minrow * 90); +} + +void +DateItem::setCols(int mincol, int n) +{ + m_mincol = mincol; + m_maxcol = mincol + n - 1; + setX(m_mincol * 100); +} + +QRectF +DateItem::boundingRect() const +{ + return QRectF(-75, -25, + (m_maxcol - m_mincol + 1) * 100 + 100, + (m_maxrow - m_minrow + 1) * 90).normalized(); +} + +void +DateItem::paint(QPainter *paint, const QStyleOptionGraphicsItem *opt, QWidget *w) +{ + QBrush brush; + + if (m_even) { + QColor c(QColor::fromRgb(240, 240, 240)); + brush = QBrush(c); + } else { + QColor c(QColor::fromRgb(250, 250, 250)); + brush = QBrush(c); + } + + paint->fillRect(boundingRect(), brush); + + paint->save(); + QFont f(paint->font()); + f.setBold(true); + paint->setFont(f); + paint->drawText(-70, -10, m_dateString); + paint->restore(); +} + + diff -r 384420567575 -r 3c46b2ac45d3 dateitem.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dateitem.h Fri Nov 12 16:48:18 2010 +0000 @@ -0,0 +1,34 @@ +#ifndef DATEITEM_H +#define DATEITEM_H + +#include + +class DateItem : public QGraphicsItem +{ +public: + DateItem() : + m_minrow(0), m_maxrow(0), + m_mincol(0), m_maxcol(0), + m_even(false) {} + + virtual QRectF boundingRect() const; + virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + + void setRows(int minrow, int n); + void setCols(int mincol, int n); + + void setEven(bool e) { m_even = e; } + + QString dateString() const { return m_dateString; } + void setDateString(QString s) { m_dateString = s; } + +private: + QString m_dateString; + int m_minrow; + int m_maxrow; + int m_mincol; + int m_maxcol; + bool m_even; +}; + +#endif // DATEITEM_H diff -r 384420567575 -r 3c46b2ac45d3 easyhg.pro --- a/easyhg.pro Fri Nov 12 11:32:01 2010 +0000 +++ b/easyhg.pro Fri Nov 12 16:48:18 2010 +0000 @@ -19,7 +19,9 @@ panner.h \ panned.h \ connectionitem.h \ - textabbrev.h + textabbrev.h \ + dateitem.h \ + colourset.h SOURCES = main.cpp \ mainwindow.cpp \ hgexpwidget.cpp \ @@ -33,7 +35,9 @@ panner.cpp \ panned.cpp \ connectionitem.cpp \ - textabbrev.cpp + textabbrev.cpp \ + dateitem.cpp \ + colourset.cpp # ! [0] RESOURCES = hgexplorer.qrc diff -r 384420567575 -r 3c46b2ac45d3 grapher.cpp --- a/grapher.cpp Fri Nov 12 11:32:01 2010 +0000 +++ b/grapher.cpp Fri Nov 12 16:48:18 2010 +0000 @@ -1,6 +1,7 @@ #include "grapher.h" #include "connectionitem.h" +#include "dateitem.h" #include @@ -43,7 +44,7 @@ } Changeset *cs = m_changesets[id]; ChangesetItem *item = m_items[id]; - std::cerr << "Looking at " << id.toStdString() << std::endl; + std::cerr << "layoutRow: Looking at " << id.toStdString() << std::endl; int row = 0; int nparents = cs->parents().size(); @@ -73,11 +74,8 @@ // above all nodes that have earlier dates (to the nearest day). // m_rowDates maps each row to a date: use that. - QString date = cs->date(); - - // n.b. this relies on the fact that the date component of an ISO - // date/time sorts correctly in a dictionary sort - while (m_rowDates.contains(row) && m_rowDates[row] < date) { + QString date = cs->age(); + while (m_rowDates.contains(row) && m_rowDates[row] != date) { --row; } @@ -110,22 +108,11 @@ if (!m_items.contains(id)) { throw LayoutException(QString("Changeset %1 not in item map").arg(id)); } + Changeset *cs = m_changesets[id]; + std::cerr << "layoutCol: Looking at " << id.toStdString() << std::endl; + ChangesetItem *item = m_items[id]; - std::cerr << "Looking at " << id.toStdString() << std::endl; - - foreach (QString parentId, cs->parents()) { - if (!m_changesets.contains(parentId)) continue; - if (!m_handled.contains(parentId)) { - layoutCol(parentId); - } - } - - // Parent may have layed out child in the recursive call - if (m_handled.contains(id)) { - std::cerr << "Looks like we've dealt with " << id.toStdString() << std::endl; - return; - } int col = 0; int row = item->row(); @@ -191,19 +178,19 @@ int nchildren = cs->children().size(); - // look for merging children and make sure nobody - // is going to overwrite their "merge lines" if they extend further - // than a single step + // look for merging children and children distant from us but in a + // straight line, and make sure nobody is going to overwrite their + // connection lines foreach (QString childId, cs->children()) { if (!m_changesets.contains(childId)) continue; Changeset *child = m_changesets[childId]; - if (child->parents().size() > 1) { - int childRow = m_items[childId]->row(); + int childRow = m_items[childId]->row(); + if (child->parents().size() > 1 || child->branch() == cs->branch()) { for (int r = row; r > childRow; --r) { m_alloc[r].insert(col); } - } + } } // look for the case where exactly two children have the same @@ -224,8 +211,11 @@ for (int i = 0; i < 2; ++i) { int off = i * 2 - 1; // 0 -> -1, 1 -> 1 ChangesetItem *it = m_items[special[i]]; + m_alloc[it->row()].insert(col); // avoid our column it->setColumn(findAvailableColumn(it->row(), col + off, true)); - m_alloc[it->row()].insert(it->column()); + for (int r = row; r >= it->row(); --r) { + m_alloc[r].insert(it->column()); + } m_handled.insert(special[i]); } } @@ -279,10 +269,21 @@ } } } - int home = 3; + int home = 2; while (taken.contains(home)) { - if (home > 0) home = -home; - else home = -(home-3); + if (home > 0) { + if (home % 2 == 1) { + home = -home; + } else { + home = home + 1; + } + } else { + if ((-home) % 2 == 1) { + home = home + 1; + } else { + home = -(home-2); + } + } } m_branchHomes[branch] = home; } @@ -298,6 +299,13 @@ return a->timestamp() < b->timestamp(); } +ChangesetItem * +Grapher::getItemFor(Changeset *cs) +{ + if (!cs || !m_items.contains(cs->id())) return 0; + return m_items[cs->id()]; +} + void Grapher::layout(Changesets csets) { @@ -306,6 +314,8 @@ m_alloc.clear(); m_branchHomes.clear(); + if (csets.empty()) return; + foreach (Changeset *cs, csets) { QString id = cs->id(); @@ -330,11 +340,13 @@ foreach (Changeset *cs, csets) { QString id = cs->id(); ChangesetItem *item = m_items[id]; + bool merge = (cs->parents().size() > 1); foreach (QString parentId, cs->parents()) { if (!m_changesets.contains(parentId)) continue; Changeset *parent = m_changesets[parentId]; parent->addChild(id); ConnectionItem *conn = new ConnectionItem(); + if (merge) conn->setConnectionType(ConnectionItem::Merge); conn->setChild(item); conn->setParent(m_items[parentId]); m_scene->addItem(conn); @@ -350,16 +362,80 @@ qStableSort(csets.begin(), csets.end(), compareChangesetsByDate); + foreach (Changeset *cs, csets) { + std::cerr << "id " << cs->id().toStdString() << ", ts " << cs->timestamp() << ", date " << cs->datetime().toStdString() << std::endl; + } + m_handled.clear(); - for (int i = csets.size() - 1; i >= 0; --i) { - layoutRow(csets[i]->id()); + foreach (Changeset *cs, csets) { + layoutRow(cs->id()); } allocateBranchHomes(csets); m_handled.clear(); - for (int i = csets.size() - 1; i >= 0; --i) { - layoutCol(csets[i]->id()); + foreach (Changeset *cs, csets) { + foreach (QString parentId, cs->parents()) { + if (!m_handled.contains(parentId) && + m_changesets.contains(parentId)) { + layoutCol(parentId); + } + } + layoutCol(cs->id()); + } + + // we know that 0 is an upper bound on row, and that mincol must + // be <= 0 and maxcol >= 0, so these initial values are good + int minrow = 0, maxrow = 0; + int mincol = 0, maxcol = 0; + + foreach (int r, m_alloc.keys()) { + if (r < minrow) minrow = r; + if (r > maxrow) maxrow = r; + ColumnSet &c = m_alloc[r]; + foreach (int i, c) { + if (i < mincol) mincol = i; + if (i > maxcol) maxcol = i; + } + } + + QString prevDate; + int changeRow = 0; + + bool even = false; + int n = 0; + + for (int row = minrow; row <= maxrow; ++row) { + + QString date = m_rowDates[row]; + n++; + + if (date != prevDate) { + if (prevDate != "") { + DateItem *item = new DateItem(); + item->setDateString(prevDate); + item->setCols(mincol, maxcol - mincol + 1); + item->setRows(changeRow, n); + item->setEven(even); + item->setZValue(-1); + m_scene->addItem(item); + even = !even; + } + prevDate = date; + changeRow = row; + n = 0; + } + } + + if (n > 0) { + DateItem *item = new DateItem(); + item->setDateString(prevDate); + item->setCols(mincol, maxcol - mincol + 1); + item->setRows(changeRow, n+1); + item->setEven(even); + item->setZValue(-1); + m_scene->addItem(item); + even = !even; } } diff -r 384420567575 -r 3c46b2ac45d3 grapher.h --- a/grapher.h Fri Nov 12 11:32:01 2010 +0000 +++ b/grapher.h Fri Nov 12 16:48:18 2010 +0000 @@ -17,6 +17,8 @@ void layout(Changesets csets); + ChangesetItem *getItemFor(Changeset *cs); + class LayoutException : public std::exception { public: LayoutException(QString message) throw() : m_message(message) { } diff -r 384420567575 -r 3c46b2ac45d3 hgexpwidget.cpp --- a/hgexpwidget.cpp Fri Nov 12 11:32:01 2010 +0000 +++ b/hgexpwidget.cpp Fri Nov 12 16:48:18 2010 +0000 @@ -261,8 +261,9 @@ QGraphicsScene *scene = new QGraphicsScene(); Changesets csets = parseChangeSets(hgLogList); if (csets.empty()) return; + Grapher g(scene); try { - Grapher(scene).layout(csets); + g.layout(csets); } catch (std::string s) { std::cerr << "Internal error: Layout failed: " << s << std::endl; } @@ -270,6 +271,8 @@ panned->setScene(scene); panner->scene()->deleteLater(); panner->setScene(scene); + ChangesetItem *tipItem = g.getItemFor(csets[0]); + if (tipItem) tipItem->ensureVisible(); } diff -r 384420567575 -r 3c46b2ac45d3 mainwindow.cpp --- a/mainwindow.cpp Fri Nov 12 11:32:01 2010 +0000 +++ b/mainwindow.cpp Fri Nov 12 16:48:18 2010 +0000 @@ -2,8 +2,6 @@ ** Copyright (C) Jari Korhonen, 2010 (under lgpl) ****************************************************************************/ -#include "mainwindow.h" -#include "settingsdialog.h" #include #include @@ -18,6 +16,10 @@ #include #include +#include "mainwindow.h" +#include "settingsdialog.h" +#include "colourset.h" + MainWindow::MainWindow() { @@ -1445,6 +1447,12 @@ initialFileTypesBits = (unsigned char) settings.value("viewFileTypes", QVariant(DEFAULT_HG_STAT_BITS)).toInt(); resize(size); move(pos); + + ColourSet *cs = ColourSet::instance(); + cs->clearDefaultNames(); + cs->addDefaultName(""); + cs->addDefaultName("default"); + cs->addDefaultName(userInfo); } diff -r 384420567575 -r 3c46b2ac45d3 panned.cpp --- a/panned.cpp Fri Nov 12 11:32:01 2010 +0000 +++ b/panned.cpp Fri Nov 12 16:48:18 2010 +0000 @@ -19,6 +19,7 @@ #include #include +#include #include @@ -66,6 +67,22 @@ } void +Panned::zoomIn() +{ + QMatrix m = matrix(); + m.scale(1.0 / 1.1, 1.0 / 1.1); + setMatrix(m); +} + +void +Panned::zoomOut() +{ + QMatrix m = matrix(); + m.scale(1.1, 1.1); + setMatrix(m); +} + +void Panned::slotSetPannedRect(QRectF pr) { centerOn(pr.center()); @@ -76,8 +93,23 @@ void Panned::wheelEvent(QWheelEvent *ev) { - emit wheelEventReceived(ev); - QGraphicsView::wheelEvent(ev); + if (ev->modifiers() & Qt::ControlModifier) { + int d = ev->delta(); + if (d > 0) { + while (d > 0) { + zoomOut(); + d -= 120; + } + } else { + while (d < 0) { + zoomIn(); + d += 120; + } + } + } else { + emit wheelEventReceived(ev); + QGraphicsView::wheelEvent(ev); + } } void diff -r 384420567575 -r 3c46b2ac45d3 panned.h --- a/panned.h Fri Nov 12 11:32:01 2010 +0000 +++ b/panned.h Fri Nov 12 16:48:18 2010 +0000 @@ -41,6 +41,9 @@ void slotSetPannedRect(QRectF); void slotEmulateWheelEvent(QWheelEvent *ev); + void zoomIn(); + void zoomOut(); + protected: QRectF m_pannedRect; diff -r 384420567575 -r 3c46b2ac45d3 panner.cpp --- a/panner.cpp Fri Nov 12 11:32:01 2010 +0000 +++ b/panner.cpp Fri Nov 12 16:48:18 2010 +0000 @@ -39,6 +39,7 @@ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setOptimizationFlags(QGraphicsView::DontSavePainterState | QGraphicsView::IndirectPainting); + setRenderHints(QPainter::Antialiasing); setMouseTracking(true); setInteractive(false); } @@ -65,6 +66,12 @@ connect(this, SIGNAL(pannedRectChanged(QRectF)), p, SLOT(slotSetPannedRect(QRectF))); + + connect(this, SIGNAL(zoomIn()), + p, SLOT(zoomIn())); + + connect(this, SIGNAL(zoomOut()), + p, SLOT(zoomOut())); } void @@ -210,10 +217,17 @@ void Panner::wheelEvent(QWheelEvent *e) { - if (e->delta() > 0) { - emit zoomOut(); + int d = e->delta(); + if (d > 0) { + while (d > 0) { + emit zoomOut(); + d -= 120; + } } else { - emit zoomIn(); + while (d < 0) { + emit zoomIn(); + d += 120; + } } } diff -r 384420567575 -r 3c46b2ac45d3 textabbrev.cpp --- a/textabbrev.cpp Fri Nov 12 11:32:01 2010 +0000 +++ b/textabbrev.cpp Fri Nov 12 16:48:18 2010 +0000 @@ -86,7 +86,7 @@ QString TextAbbrev::abbreviate(QString text, const QFontMetrics &metrics, int &maxWidth, - Policy policy, QString ellipsis) + Policy policy, QString ellipsis, int wrapLines) { if (ellipsis == "") ellipsis = getDefaultEllipsis(); @@ -100,21 +100,62 @@ int truncated = text.length(); QString original = text; - while (tw > maxWidth && truncated > 1) { + if (wrapLines < 2) { - truncated--; + while (tw > maxWidth && truncated > 1) { - if (truncated > ellipsis.length()) { - text = abbreviateTo(original, truncated, policy, ellipsis); - } else { - break; + truncated--; + + if (truncated > ellipsis.length()) { + text = abbreviateTo(original, truncated, policy, ellipsis); + } else { + break; + } + + tw = metrics.width(text); + } + + maxWidth = tw; + return text; + + } else { + + QStringList words = text.split(' ', QString::SkipEmptyParts); + text = ""; + + tw = 0; + int i = 0; + QString good = ""; + int lastUsed = 0; + while (tw < maxWidth && i < words.size()) { + if (text != "") text += " "; + text += words[i++]; + tw = metrics.width(text); + if (tw < maxWidth) { + good = text; + lastUsed = i; + } + } + + if (tw < maxWidth) { + maxWidth = tw; + return text; } - tw = metrics.width(text); + text = good; + + QString remainder; + while (lastUsed < words.size()) { + if (remainder != "") remainder += " "; + remainder += words[lastUsed++]; + } + remainder = abbreviate(remainder, metrics, maxWidth, + policy, ellipsis, wrapLines - 1); + + maxWidth = std::max(maxWidth, tw); + text = text + '\n' + remainder; + return text; } - - maxWidth = tw; - return text; } QStringList diff -r 384420567575 -r 3c46b2ac45d3 textabbrev.h --- a/textabbrev.h Fri Nov 12 11:32:01 2010 +0000 +++ b/textabbrev.h Fri Nov 12 16:48:18 2010 +0000 @@ -57,7 +57,8 @@ const QFontMetrics &metrics, int &maxWidth, Policy policy = ElideEnd, - QString ellipsis = ""); + QString ellipsis = "", + int wrapLines = 1); /** * Abbreviate all of the given texts to the given maximum length,