Changeset 561 for trunk/src/gui/widgets/qmainwindowlayout.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/gui/widgets/qmainwindowlayout.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtGui module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** … … 238 238 QMainWindowLayout *layout = qobject_cast<QMainWindowLayout*>(mainWindow->layout()); 239 239 Q_ASSERT(layout != 0); 240 layout->widgetAnimator ->animate(centralWidgetItem->widget(), centralWidgetRect, animated);240 layout->widgetAnimator.animate(centralWidgetItem->widget(), centralWidgetRect, animated); 241 241 } 242 242 #endif … … 427 427 } 428 428 429 bool QMainWindowLayoutState::insertGap( QList<int>path, QLayoutItem *item)429 bool QMainWindowLayoutState::insertGap(const QList<int> &path, QLayoutItem *item) 430 430 { 431 431 if (path.isEmpty()) 432 432 return false; 433 433 434 int i = path. takeFirst();434 int i = path.first(); 435 435 436 436 #ifndef QT_NO_TOOLBAR 437 437 if (i == 0) { 438 438 Q_ASSERT(qobject_cast<QToolBar*>(item->widget()) != 0); 439 return toolBarAreaLayout.insertGap(path , item);439 return toolBarAreaLayout.insertGap(path.mid(1), item); 440 440 } 441 441 #endif … … 444 444 if (i == 1) { 445 445 Q_ASSERT(qobject_cast<QDockWidget*>(item->widget()) != 0); 446 return dockAreaLayout.insertGap(path , item);446 return dockAreaLayout.insertGap(path.mid(1), item); 447 447 } 448 448 #endif //QT_NO_DOCKWIDGET … … 451 451 } 452 452 453 void QMainWindowLayoutState::remove( QList<int>path)454 { 455 int i = path. takeFirst();453 void QMainWindowLayoutState::remove(const QList<int> &path) 454 { 455 int i = path.first(); 456 456 457 457 #ifndef QT_NO_TOOLBAR 458 458 if (i == 0) 459 toolBarAreaLayout.remove(path );459 toolBarAreaLayout.remove(path.mid(1)); 460 460 #endif 461 461 462 462 #ifndef QT_NO_DOCKWIDGET 463 463 if (i == 1) 464 dockAreaLayout.remove(path );464 dockAreaLayout.remove(path.mid(1)); 465 465 #endif //QT_NO_DOCKWIDGET 466 466 } … … 491 491 dockAreaLayout.clear(); 492 492 #else 493 centralWidgetRect = QRect( 0, 0, -1, -1);494 #endif 495 496 rect = QRect( 0, 0, -1, -1);493 centralWidgetRect = QRect(); 494 #endif 495 496 rect = QRect(); 497 497 } 498 498 … … 502 502 } 503 503 504 QLayoutItem *QMainWindowLayoutState::item( QList<int>path)505 { 506 int i = path. takeFirst();504 QLayoutItem *QMainWindowLayoutState::item(const QList<int> &path) 505 { 506 int i = path.first(); 507 507 508 508 #ifndef QT_NO_TOOLBAR 509 509 if (i == 0) 510 return toolBarAreaLayout.item(path ).widgetItem;510 return toolBarAreaLayout.item(path.mid(1)).widgetItem; 511 511 #endif 512 512 513 513 #ifndef QT_NO_DOCKWIDGET 514 514 if (i == 1) 515 return dockAreaLayout.item(path ).widgetItem;515 return dockAreaLayout.item(path.mid(1)).widgetItem; 516 516 #endif //QT_NO_DOCKWIDGET 517 517 … … 519 519 } 520 520 521 QRect QMainWindowLayoutState::itemRect( QList<int>path) const522 { 523 int i = path. takeFirst();521 QRect QMainWindowLayoutState::itemRect(const QList<int> &path) const 522 { 523 int i = path.first(); 524 524 525 525 #ifndef QT_NO_TOOLBAR 526 526 if (i == 0) 527 return toolBarAreaLayout.itemRect(path );527 return toolBarAreaLayout.itemRect(path.mid(1)); 528 528 #endif 529 529 530 530 #ifndef QT_NO_DOCKWIDGET 531 531 if (i == 1) 532 return dockAreaLayout.itemRect(path );532 return dockAreaLayout.itemRect(path.mid(1)); 533 533 #endif //QT_NO_DOCKWIDGET 534 534 … … 536 536 } 537 537 538 QRect QMainWindowLayoutState::gapRect( QList<int>path) const539 { 540 int i = path. takeFirst();538 QRect QMainWindowLayoutState::gapRect(const QList<int> &path) const 539 { 540 int i = path.first(); 541 541 542 542 #ifndef QT_NO_TOOLBAR 543 543 if (i == 0) 544 return toolBarAreaLayout.itemRect(path );544 return toolBarAreaLayout.itemRect(path.mid(1)); 545 545 #endif 546 546 547 547 #ifndef QT_NO_DOCKWIDGET 548 548 if (i == 1) 549 return dockAreaLayout.gapRect(path );549 return dockAreaLayout.gapRect(path.mid(1)); 550 550 #endif //QT_NO_DOCKWIDGET 551 551 … … 553 553 } 554 554 555 QLayoutItem *QMainWindowLayoutState::plug( QList<int>path)556 { 557 int i = path. takeFirst();555 QLayoutItem *QMainWindowLayoutState::plug(const QList<int> &path) 556 { 557 int i = path.first(); 558 558 559 559 #ifndef QT_NO_TOOLBAR 560 560 if (i == 0) 561 return toolBarAreaLayout.plug(path );561 return toolBarAreaLayout.plug(path.mid(1)); 562 562 #endif 563 563 564 564 #ifndef QT_NO_DOCKWIDGET 565 565 if (i == 1) 566 return dockAreaLayout.plug(path );566 return dockAreaLayout.plug(path.mid(1)); 567 567 #endif //QT_NO_DOCKWIDGET 568 568 … … 570 570 } 571 571 572 QLayoutItem *QMainWindowLayoutState::unplug( QList<int>path, QMainWindowLayoutState *other)573 { 574 int i = path. takeFirst();572 QLayoutItem *QMainWindowLayoutState::unplug(const QList<int> &path, QMainWindowLayoutState *other) 573 { 574 int i = path.first(); 575 575 576 576 #ifdef QT_NO_TOOLBAR … … 578 578 #else 579 579 if (i == 0) 580 return toolBarAreaLayout.unplug(path , other ? &other->toolBarAreaLayout : 0);580 return toolBarAreaLayout.unplug(path.mid(1), other ? &other->toolBarAreaLayout : 0); 581 581 #endif 582 582 583 583 #ifndef QT_NO_DOCKWIDGET 584 584 if (i == 1) 585 return dockAreaLayout.unplug(path );585 return dockAreaLayout.unplug(path.mid(1)); 586 586 #endif //QT_NO_DOCKWIDGET 587 587 … … 940 940 void QMainWindowLayout::toggleToolBarsVisible() 941 941 { 942 layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible; 943 if (!layoutState.mainWindow->isMaximized()){ 944 QPoint topLeft = parentWidget()->geometry().topLeft(); 945 QRect r = parentWidget()->geometry(); 946 r = layoutState.toolBarAreaLayout.rectHint(r); 947 r.moveTo(topLeft); 948 parentWidget()->setGeometry(r); 949 // widgetAnimator->animate(parentWidget(), r, true); 950 } else{ 951 update(); 942 bool updateNonUnifiedParts = true; 943 #ifdef Q_WS_MAC 944 if (layoutState.mainWindow->unifiedTitleAndToolBarOnMac()) { 945 // If we hit this case, someone has pressed the "toolbar button" which will 946 // toggle the unified toolbar visiblity, because that's what the user wants. 947 // We might be in a situation where someone has hidden all the toolbars 948 // beforehand (maybe in construction), but now they've hit this button and 949 // and are expecting the items to show. What do we do? 950 // 1) Check the visibility of all the toolbars, if one is visible, do nothing, this 951 // preserves what people would expect (these toolbars were visible when I clicked last time). 952 // 2) If NONE are visible, then show them all. Again, this preserves the user expectation 953 // of, "I want to see the toolbars." The user may get more toolbars than expected, but this 954 // is better seeing nothing. 955 // Don't worry about any of this if we are going invisible. This does mean we may get 956 // into issues when switching into and out of fullscreen mode, but this is probably minor. 957 // If we ever need to do hiding, that would have to be taken care of after the unified toolbar 958 // has finished hiding. 959 // People can of course handle the QEvent::ToolBarChange event themselves and do 960 // WHATEVER they want if they don't like what we are doing (though the unified toolbar 961 // will fire regardless). 962 963 // Check if we REALLY need to update the geometry below. If we only have items in the 964 // unified toolbar, all the docks will be empty, so there's very little point 965 // in doing the geometry as Apple will do it (we also avoid flicker in Cocoa as well). 966 // FWIW, layoutState.toolBarAreaLayout.visible and the state of the unified toolbar 967 // visibility can get out of sync. I really don't think it's a big issue. It is kept 968 // to a minimum because we only change the visibility if we absolutely must. 969 // update the "non unified parts." 970 updateNonUnifiedParts = !layoutState.toolBarAreaLayout.isEmpty(); 971 972 // We get this function before the unified toolbar does its thing. 973 // So, the value will be opposite of what we expect. 974 bool goingVisible = !macWindowToolbarIsVisible(qt_mac_window_for(layoutState.mainWindow)); 975 if (goingVisible) { 976 const int ToolBarCount = qtoolbarsInUnifiedToolbarList.size(); 977 bool needAllVisible = true; 978 for (int i = 0; i < ToolBarCount; ++i) { 979 if (!qtoolbarsInUnifiedToolbarList.at(i)->isHidden()) { 980 needAllVisible = false; 981 break; 982 } 983 } 984 if (needAllVisible) { 985 QBoolBlocker blocker(blockVisiblityCheck); // Disable the visibilty check because 986 // the toggle has already happened. 987 for (int i = 0; i < ToolBarCount; ++i) 988 qtoolbarsInUnifiedToolbarList.at(i)->setVisible(true); 989 } 990 } 991 if (!updateNonUnifiedParts) 992 layoutState.toolBarAreaLayout.visible = goingVisible; 993 } 994 #endif 995 if (updateNonUnifiedParts) { 996 layoutState.toolBarAreaLayout.visible = !layoutState.toolBarAreaLayout.visible; 997 if (!layoutState.mainWindow->isMaximized()) { 998 QPoint topLeft = parentWidget()->geometry().topLeft(); 999 QRect r = parentWidget()->geometry(); 1000 r = layoutState.toolBarAreaLayout.rectHint(r); 1001 r.moveTo(topLeft); 1002 parentWidget()->setGeometry(r); 1003 } else { 1004 update(); 1005 } 952 1006 } 953 1007 } … … 1305 1359 return false; 1306 1360 movingSeparatorPos = pos; 1307 separatorMoveTimer ->start();1361 separatorMoveTimer.start(0, this); 1308 1362 return true; 1309 }1310 1311 void QMainWindowLayout::doSeparatorMove()1312 {1313 if (movingSeparator.isEmpty())1314 return;1315 if (movingSeparatorOrigin == movingSeparatorPos)1316 return;1317 1318 layoutState = savedState;1319 layoutState.dockAreaLayout.separatorMove(movingSeparator, movingSeparatorOrigin,1320 movingSeparatorPos,1321 &separatorMoveCache);1322 movingSeparatorPos = movingSeparatorOrigin;1323 1363 } 1324 1364 … … 1328 1368 movingSeparator.clear(); 1329 1369 savedState.clear(); 1330 separatorMoveCache.clear();1331 1370 return result; 1332 1371 } … … 1377 1416 // the widget might in fact have been destroyed by now 1378 1417 if (QWidget *w = ret->widget()) { 1379 widgetAnimator ->abort(w);1418 widgetAnimator.abort(w); 1380 1419 if (w == pluggingWidget) 1381 1420 pluggingWidget = 0; … … 1425 1464 .expandedTo(statusbar->minimumSize())); 1426 1465 sbr.moveBottom(r.bottom()); 1427 QRect vr = QStyle::visualRect( QApplication::layoutDirection(), _r, sbr);1466 QRect vr = QStyle::visualRect(parentWidget()->layoutDirection(), _r, sbr); 1428 1467 statusbar->setGeometry(vr); 1429 1468 r.setBottom(sbr.top() - 1); … … 1544 1583 1545 1584 pluggingWidget = widget; 1546 if (dockOptions & QMainWindow::AnimatedDocks) { 1547 QRect globalRect = currentGapRect; 1548 globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft())); 1549 #ifndef QT_NO_DOCKWIDGET 1550 if (qobject_cast<QDockWidget*>(widget) != 0) { 1551 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(widget->layout()); 1552 if (layout->nativeWindowDeco()) { 1553 globalRect.adjust(0, layout->titleHeight(), 0, 0); 1554 } else { 1555 int fw = widget->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, widget); 1556 globalRect.adjust(-fw, -fw, fw, fw); 1557 } 1585 QRect globalRect = currentGapRect; 1586 globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft())); 1587 #ifndef QT_NO_DOCKWIDGET 1588 if (qobject_cast<QDockWidget*>(widget) != 0) { 1589 QDockWidgetLayout *layout = qobject_cast<QDockWidgetLayout*>(widget->layout()); 1590 if (layout->nativeWindowDeco()) { 1591 globalRect.adjust(0, layout->titleHeight(), 0, 0); 1592 } else { 1593 int fw = widget->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, widget); 1594 globalRect.adjust(-fw, -fw, fw, fw); 1558 1595 } 1559 #endif 1560 widgetAnimator->animate(widget, globalRect, 1561 dockOptions & QMainWindow::AnimatedDocks); 1562 } else { 1563 #ifndef QT_NO_DOCKWIDGET 1564 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) 1565 dw->d_func()->plug(currentGapRect); 1566 #endif 1567 #ifndef QT_NO_TOOLBAR 1568 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) 1569 tb->d_func()->plug(currentGapRect); 1570 #endif 1571 applyState(layoutState); 1572 savedState.clear(); 1573 #ifndef QT_NO_DOCKWIDGET 1574 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion()); 1575 #endif 1576 currentGapPos.clear(); 1577 updateGapIndicator(); 1578 pluggingWidget = 0; 1579 } 1596 } 1597 #endif 1598 widgetAnimator.animate(widget, globalRect, dockOptions & QMainWindow::AnimatedDocks); 1580 1599 1581 1600 return true; 1582 1601 } 1583 1602 1584 void QMainWindowLayout::allAnimationsFinished()1585 {1586 #ifndef QT_NO_DOCKWIDGET1587 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());1588 1589 #ifndef QT_NO_TABBAR1590 foreach (QTabBar *tab_bar, usedTabBars)1591 tab_bar->show();1592 #endif // QT_NO_TABBAR1593 #endif // QT_NO_DOCKWIDGET1594 1595 updateGapIndicator();1596 }1597 1598 1603 void QMainWindowLayout::animationFinished(QWidget *widget) 1599 1604 { 1600 1601 /* This signal is delivered from QWidgetAnimator over a qeued connection. The problem is that 1602 the widget can be deleted. This is handled as follows: 1603 1604 The animator only ever animates widgets that have been added to this layout. If a widget 1605 is deleted during animation, the widget's destructor removes the widget form this layout. 1606 This in turn aborts the animation (see takeAt()) and this signal will never be delivered. 1607 1608 If the widget is deleted after the animation is finished but before this qeued signal 1609 is delivered, the widget is no longer in the layout and we catch it here. The key is that 1610 QMainWindowLayoutState::contains() never dereferences the pointer. */ 1611 1612 if (!layoutState.contains(widget)) 1613 return; 1614 1605 //this function is called from within the Widget Animator whenever an animation is finished 1606 //on a certain widget 1615 1607 #ifndef QT_NO_TOOLBAR 1616 1608 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) { … … 1625 1617 #endif 1626 1618 1627 if (widget != pluggingWidget) 1628 return; 1629 1630 #ifndef QT_NO_DOCKWIDGET 1631 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) 1632 dw->d_func()->plug(currentGapRect); 1633 #endif 1634 #ifndef QT_NO_TOOLBAR 1635 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) 1636 tb->d_func()->plug(currentGapRect); 1637 #endif 1638 1639 applyState(layoutState, false); 1619 if (widget == pluggingWidget) { 1620 1621 #ifndef QT_NO_DOCKWIDGET 1622 if (QDockWidget *dw = qobject_cast<QDockWidget*>(widget)) 1623 dw->d_func()->plug(currentGapRect); 1624 #endif 1625 #ifndef QT_NO_TOOLBAR 1626 if (QToolBar *tb = qobject_cast<QToolBar*>(widget)) 1627 tb->d_func()->plug(currentGapRect); 1628 #endif 1629 1640 1630 #ifndef QT_NO_DOCKWIDGET 1641 1631 #ifndef QT_NO_TABBAR 1642 if (qobject_cast<QDockWidget*>(widget) != 0) { 1643 // info() might return null if the widget is destroyed while 1644 // animating but before the animationFinished signal is received. 1645 if (QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget)) 1646 info->setCurrentTab(widget); 1647 } 1648 #endif 1649 #endif 1650 savedState.clear(); 1651 currentGapPos.clear(); 1652 pluggingWidget = 0; 1632 if (qobject_cast<QDockWidget*>(widget) != 0) { 1633 // info() might return null if the widget is destroyed while 1634 // animating but before the animationFinished signal is received. 1635 if (QDockAreaLayoutInfo *info = layoutState.dockAreaLayout.info(widget)) 1636 info->setCurrentTab(widget); 1637 } 1638 #endif 1639 #endif 1640 1641 savedState.clear(); 1642 currentGapPos.clear(); 1643 pluggingWidget = 0; 1644 //applying the state will make sure that the currentGap is updated correctly 1645 //and all the geometries (especially the one from the central widget) is correct 1646 layoutState.apply(false); 1647 } 1648 1649 if (!widgetAnimator.animating()) { 1650 //all animations are finished 1651 #ifndef QT_NO_DOCKWIDGET 1652 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion()); 1653 #ifndef QT_NO_TABBAR 1654 foreach (QTabBar *tab_bar, usedTabBars) 1655 tab_bar->show(); 1656 #endif // QT_NO_TABBAR 1657 #endif // QT_NO_DOCKWIDGET 1658 } 1659 1653 1660 updateGapIndicator(); 1654 1661 } … … 1683 1690 #endif 1684 1691 #endif // QT_NO_DOCKWIDGET 1692 , widgetAnimator(this) 1693 , pluggingWidget(0) 1694 #ifndef QT_NO_RUBBERBAND 1695 , gapIndicator(new QRubberBand(QRubberBand::Rectangle, mainwindow)) 1696 #endif //QT_NO_RUBBERBAND 1697 #ifdef Q_WS_MAC 1698 , blockVisiblityCheck(false) 1699 #endif 1685 1700 { 1686 1701 #ifndef QT_NO_DOCKWIDGET … … 1688 1703 sep = mainwindow->style()->pixelMetric(QStyle::PM_DockWidgetSeparatorExtent, 0, mainwindow); 1689 1704 #endif 1690 separatorMoveTimer = new QTimer(this);1691 separatorMoveTimer->setSingleShot(true);1692 separatorMoveTimer->setInterval(0);1693 connect(separatorMoveTimer, SIGNAL(timeout()), this, SLOT(doSeparatorMove()));1694 1705 1695 1706 #ifndef QT_NO_TABWIDGET … … 1700 1711 1701 1712 #ifndef QT_NO_RUBBERBAND 1702 gapIndicator = new QRubberBand(QRubberBand::Rectangle, mainwindow);1703 1713 // For accessibility to identify this special widget. 1704 1714 gapIndicator->setObjectName(QLatin1String("qt_rubberband")); 1705 1706 1715 gapIndicator->hide(); 1707 1716 #endif … … 1709 1718 1710 1719 setObjectName(mainwindow->objectName() + QLatin1String("_layout")); 1711 widgetAnimator = new QWidgetAnimator(this);1712 connect(widgetAnimator, SIGNAL(finished(QWidget*)),1713 this, SLOT(animationFinished(QWidget*)), Qt::QueuedConnection);1714 connect(widgetAnimator, SIGNAL(finishedAll()),1715 this, SLOT(allAnimationsFinished()));1716 1720 } 1717 1721 … … 1815 1819 { 1816 1820 #ifndef QT_NO_RUBBERBAND 1817 if (widgetAnimator->animating() || currentGapPos.isEmpty()) { 1818 gapIndicator->hide(); 1819 } else { 1820 if (gapIndicator->geometry() != currentGapRect) 1821 gapIndicator->setGeometry(currentGapRect); 1822 if (!gapIndicator->isVisible()) 1823 gapIndicator->show(); 1824 } 1821 gapIndicator->setVisible(!widgetAnimator.animating() && !currentGapPos.isEmpty()); 1822 gapIndicator->setGeometry(currentGapRect); 1825 1823 #endif 1826 1824 } … … 1983 1981 } 1984 1982 1983 void QMainWindowLayout::timerEvent(QTimerEvent *e) 1984 { 1985 #ifndef QT_NO_DOCKWIDGET 1986 if (e->timerId() == separatorMoveTimer.timerId()) { 1987 //let's move the separators 1988 separatorMoveTimer.stop(); 1989 if (movingSeparator.isEmpty()) 1990 return; 1991 if (movingSeparatorOrigin == movingSeparatorPos) 1992 return; 1993 1994 //when moving the separator, we need to update the previous position 1995 parentWidget()->update(layoutState.dockAreaLayout.separatorRegion()); 1996 1997 layoutState = savedState; 1998 layoutState.dockAreaLayout.separatorMove(movingSeparator, movingSeparatorOrigin, 1999 movingSeparatorPos); 2000 movingSeparatorPos = movingSeparatorOrigin; 2001 } 2002 #endif 2003 QLayout::timerEvent(e); 2004 } 2005 2006 1985 2007 QT_END_NAMESPACE 1986 2008
Note:
See TracChangeset
for help on using the changeset viewer.