-rw-r--r-- | korganizer/koagendaview.cpp | 16 | ||||
-rw-r--r-- | microkde/KDGanttMinimizeSplitter.cpp | 7 |
2 files changed, 16 insertions, 7 deletions
diff --git a/korganizer/koagendaview.cpp b/korganizer/koagendaview.cpp index 99f547a..667ff2a 100644 --- a/korganizer/koagendaview.cpp +++ b/korganizer/koagendaview.cpp @@ -1,597 +1,605 @@ /* This file is part of KOrganizer. Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include <qhbox.h> #include <qvbox.h> #include <qlabel.h> #include <qframe.h> #include <qlayout.h> #ifndef KORG_NOSPLITTER #include <qsplitter.h> #endif #include <qfont.h> #include <qfontmetrics.h> #include <qpopupmenu.h> #include <qtooltip.h> #include <qpainter.h> #include <qpushbutton.h> #include <qapplication.h> #include <kapplication.h> #include <KDGanttMinimizeSplitter.h> #include <kdebug.h> #include <kstandarddirs.h> #include <kiconloader.h> #include <klocale.h> #include <kconfig.h> #include <kglobal.h> #include "calendarview.h" #include "koviewmanager.h" #include <libkcal/calendar.h> #include <libkcal/icaldrag.h> #include <libkcal/dndfactory.h> #include <kcalendarsystem.h> #include "koglobals.h" #ifndef KORG_NOPLUGINS #include "kocore.h" #endif #include "koprefs.h" #include "koagenda.h" #include "koagendaitem.h" #ifndef KORG_NOPRINTER #include "calprinter.h" #endif #include "koagendaview.h" //#include "koagendaview.moc" //extern bool globalFlagBlockPainting; extern int globalFlagBlockAgenda; extern int globalFlagBlockStartup; extern int globalFlagBlockAgendaItemPaint; extern int globalFlagBlockAgendaItemUpdate; extern int globalFlagBlockLabel; using namespace KOrg; TimeLabels::TimeLabels(int rows,QWidget *parent,const char *name,WFlags f) : QScrollView(parent,name,f) { myPix.resize( 1, 1 ); mRows = rows; mRedrawNeeded = true; setMinimumHeight( 20 ); mCellHeight = KOPrefs::instance()->mHourSize*4; enableClipper(true); setHScrollBarMode(AlwaysOff); setVScrollBarMode(AlwaysOff); resizeContents(50,mRows * mCellHeight); viewport()->setBackgroundMode( PaletteBackground ); } void TimeLabels::setCellHeight(int height) { mCellHeight = height; } /* Optimization so that only the "dirty" portion of the scroll view is redrawn. Unfortunately, this is not called by default paintEvent() method. */ void TimeLabels::drawContents(QPainter *p,int cx, int cy, int cw, int ch) { // if ( globalFlagBlockAgenda ) // return; // bug: the parameters cx, cy, cw, ch are the areas that need to be // redrawn, not the area of the widget. unfortunately, this // code assumes the latter... // now, for a workaround... // these two assignments fix the weird redraw bug mRedrawNeeded = true; if ( mRedrawNeeded ) { cx = contentsX() + frameWidth()*2; cw = contentsWidth() ; // end of workaround int cell = ((int)(cy/mCellHeight)); int y = cell * mCellHeight; QFontMetrics fm = fontMetrics(); QString hour; QString suffix; int timeHeight = fm.ascent(); QFont nFont = p->font(); if (!KGlobal::locale()->use12Clock()) suffix = "00"; if ( timeHeight > mCellHeight ) { timeHeight = mCellHeight-1; int pointS = nFont.pointSize(); while ( pointS > 4 ) { nFont.setPointSize( pointS ); fm = QFontMetrics( nFont ); if ( fm.ascent() < mCellHeight ) break; -- pointS; } fm = QFontMetrics( nFont ); timeHeight = fm.ascent(); } //timeHeight -= (timeHeight/4-2); QFont sFont = nFont; sFont.setPointSize( sFont.pointSize()/2 ); QFontMetrics fmS( sFont ); int sHei = fmS.ascent() ; //sHei -= (sHei/4-2); - int startW = this->width() - 2*frameWidth()-1; + int startW = this->width() - frameWidth()-2; int tw2 = fmS.width(suffix); while (y < cy + ch) { p->drawLine(cx,y,cw,y); hour.setNum(cell); // handle 24h and am/pm time formats if (KGlobal::locale()->use12Clock()) { if (cell > 11) suffix = "pm"; else suffix = "am"; if (cell == 0) hour.setNum(12); if (cell > 12) hour.setNum(cell - 12); tw2 = fmS.width(suffix); } // center and draw the time label int timeWidth = fm.width(hour); int offset = startW - timeWidth - tw2 ; p->setFont( nFont ); p->drawText( offset, y+ timeHeight, hour); p->setFont( sFont ); offset = startW - tw2+1; p->drawText( offset, y+ sHei, suffix); // increment indices y += mCellHeight; cell++; } } else { //qDebug("NO redraw "); } // double buffer not yet implemented //bitBlt (this, 0, 0, &myPix, 0 ,0,width(), height() ,CopyROP); //mRedrawNeeded = false; } /** Calculates the minimum width. */ int TimeLabels::minimumWidth() const { return mMiniWidth; } /** updates widget's internal state */ void TimeLabels::updateConfig() { mRedrawNeeded = true; // set the font // config->setGroup("Fonts"); // QFont font = config->readFontEntry("TimeBar Font"); setFont(KOPrefs::instance()->mTimeBarFont); - QString test = "20oo"; + QString test = "20"; if (KGlobal::locale()->use12Clock()) - test = "12mi"; - mMiniWidth = fontMetrics().width(test) + frameWidth()*2 +1 ; + test = "12"; + mMiniWidth = fontMetrics().width(test); + if (KGlobal::locale()->use12Clock()) + test = "pm"; + else + test = "00"; + QFont sFont = font(); + sFont.setPointSize( sFont.pointSize()/2 ); + QFontMetrics fmS( sFont ); + mMiniWidth += fmS.width( test ) + frameWidth()*2 +4 ; // update geometry restrictions based on new settings setFixedWidth( mMiniWidth ); // update HourSize mCellHeight = KOPrefs::instance()->mHourSize*4; resizeContents(50,mRows * mCellHeight); } /** update time label positions */ void TimeLabels::positionChanged() { int adjustment = mAgenda->contentsY(); setContentsPos(0, adjustment); } /** */ void TimeLabels::setAgenda(KOAgenda* agenda) { mAgenda = agenda; } void TimeLabels::contentsMousePressEvent ( QMouseEvent * e) { mMouseDownY = e->pos().y(); mOrgCap = topLevelWidget()->caption(); } void TimeLabels::contentsMouseMoveEvent ( QMouseEvent * e ) { int diff = mMouseDownY - e->pos().y(); if ( diff < 10 && diff > -10 ) return; int tSize = KOPrefs::instance()->mHourSize + (diff/10) ; if ( tSize < 4 ) tSize = 4; if ( tSize > 22 ) tSize = 22; tSize = (tSize-2)/2; topLevelWidget()->setCaption(i18n("New Agendasize: %1").arg(tSize)); } void TimeLabels::contentsMouseReleaseEvent ( QMouseEvent * e ) { topLevelWidget()->setCaption( mOrgCap ); int diff = mMouseDownY - e->pos().y(); if ( diff < 10 && diff > -10 ) return; int tSize = KOPrefs::instance()->mHourSize + (diff/10); if ( tSize < 4 ) tSize = 4; if ( tSize > 22 ) tSize = 22; tSize = (tSize/2)*2; if ( tSize == KOPrefs::instance()->mHourSize ) return; KOPrefs::instance()->mHourSize = tSize; emit scaleChanged(); } /** This is called in response to repaint() */ void TimeLabels::paintEvent(QPaintEvent*) { // kdDebug() << "paintevent..." << endl; // this is another hack! // QPainter painter(this); //QString c repaintContents(contentsX(), contentsY(), visibleWidth(), visibleHeight()); } //////////////////////////////////////////////////////////////////////////// EventIndicator::EventIndicator(Location loc,QWidget *parent,const char *name) : QFrame(parent,name) { mColumns = 1; mTopBox = 0; mLocation = loc; mTopLayout = 0; mPaintWidget = 0; mXOffset = 0; if (mLocation == Top) mPixmap = SmallIcon("1uparrow"); else mPixmap = SmallIcon("1downarrow"); mEnabled.resize(mColumns); mEnabled.fill( false ); setMinimumHeight(mPixmap.height()); } EventIndicator::~EventIndicator() { } void EventIndicator::drawContents(QPainter *p) { // kdDebug() << "======== top: " << contentsRect().top() << " bottom " << // contentsRect().bottom() << " left " << contentsRect().left() << " right " << contentsRect().right() << endl; KDGanttSplitterHandle* han = 0; if ( mPaintWidget ) han = mPaintWidget->firstHandle(); if ( ! han ) { int i; for(i=0;i<mColumns;++i) { if (mEnabled[i]) { int cellWidth = contentsRect().right()/mColumns; int xOffset = KOGlobals::self()->reverseLayout() ? (mColumns - 1 - i)*cellWidth + (cellWidth -mPixmap.width())/2 : i*cellWidth + (cellWidth -mPixmap.width()) /2; p->drawPixmap(QPoint(1+xOffset,0),mPixmap); } } } else { han->repaint(); //mPaintWidget->setBackgroundColor( red ); QPainter pa( han ); int i; bool setColor = false; for(i=0;i<mColumns;++i) { if (mEnabled[i]) { setColor = true; int cellWidth = contentsRect().right()/mColumns; int xOffset = KOGlobals::self()->reverseLayout() ? (mColumns - 1 - i)*cellWidth + cellWidth/2 -mPixmap.width()/2 : i*cellWidth + cellWidth/2 -mPixmap.width()/2; pa.drawPixmap(QPoint(mXOffset + xOffset,0),mPixmap); //qDebug("222draw pix %d ",xOffset ); } } pa.end(); } } void EventIndicator::setXOffset( int x ) { mXOffset = x; } void EventIndicator::setPaintWidget( KDGanttMinimizeSplitter * w ) { mPaintWidget = w; setMaximumHeight(0); setMinimumHeight(0); } void EventIndicator::changeColumns(int columns) { mColumns = columns; mEnabled.resize(mColumns); update(); } void EventIndicator::enableColumn(int column, bool enable) { mEnabled[column] = enable; } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// KOAgendaView::KOAgendaView(Calendar *cal,QWidget *parent,const char *name) : KOEventView (cal,parent,name) { mBlockUpdating = true; mStartHour = 8; mSelectedDates.append(QDate::currentDate()); mLayoutDayLabels = 0; mDayLabelsFrame = 0; mDayLabels = 0; bool isRTL = KOGlobals::self()->reverseLayout(); QPixmap expandPix; if ( KOPrefs::instance()->mVerticalScreen ) { expandPix = SmallIcon( "1updownarrow" ); } else { expandPix = SmallIcon("1leftrightarrow" ); } QBoxLayout *topLayout = new QVBoxLayout(this); // Create day name labels for agenda columns // Create agenda splitter mSplitterAgenda = new KDGanttMinimizeSplitter( Qt::Vertical, this); mSplitterAgenda->setMinimizeDirection ( KDGanttMinimizeSplitter::Up ); topLayout->addWidget( mSplitterAgenda ); mAllDayFrame = new QHBox(mSplitterAgenda); mAllDayFrame->setFocusPolicy(NoFocus); QWidget *agendaFrame = new QWidget(mSplitterAgenda); agendaFrame->setFocusPolicy(NoFocus); // Create all-day agenda widget mDummyAllDayLeft = new QVBox( mAllDayFrame ); mExpandButton = new QPushButton(mDummyAllDayLeft); mExpandButton->setPixmap( expandPix ); int widebut = mExpandButton->sizeHint().width()+4; int heibut = mExpandButton->sizeHint().height()+4; if ( heibut > widebut ) widebut = heibut ; //mExpandButton->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, // QSizePolicy::Fixed ) ); mExpandButton->setFixedSize( widebut, widebut); connect( mExpandButton, SIGNAL( clicked() ), SIGNAL( toggleExpand() ) ); mExpandButton->setFocusPolicy(NoFocus); mAllDayAgenda = new KOAgenda(1,mAllDayFrame); mAllDayAgenda->setFocusPolicy(NoFocus); QLabel *dummyAllDayRight = new QLabel (mAllDayFrame); // Create event context menu for all day agenda mAllDayAgendaPopup = eventPopup(); connect(mAllDayAgenda,SIGNAL(showIncidencePopupSignal(Incidence *)), mAllDayAgendaPopup,SLOT(showIncidencePopup(Incidence *))); // Create agenda frame QGridLayout *agendaLayout = new QGridLayout(agendaFrame,4,3); // QHBox *agendaFrame = new QHBox(splitterAgenda); // create event indicator bars mEventIndicatorTop = new EventIndicator(EventIndicator::Top,agendaFrame); #ifndef DESKTOP_VERSION // FIX mEventIndicatorTop->setPaintWidget( mSplitterAgenda ); #endif mDayLabelsFrame = new QHBox(agendaFrame); //topLayout->addWidget(mDayLabelsFrame); mDayLabels = new QFrame (mDayLabelsFrame); mLayoutDayLabels = new QHBoxLayout(mDayLabels); agendaLayout->addMultiCellWidget(mDayLabelsFrame ,0,0,0,2); agendaLayout->addWidget(mEventIndicatorTop,1,1); mEventIndicatorBottom = new EventIndicator(EventIndicator::Bottom, agendaFrame); agendaLayout->addWidget(mEventIndicatorBottom,3,1); QWidget *dummyAgendaRight = new QWidget(agendaFrame); agendaLayout->addWidget(dummyAgendaRight,1,2); // Create time labels mTimeLabels = new TimeLabels(24,agendaFrame); agendaLayout->addWidget(mTimeLabels,2,0); connect(mTimeLabels,SIGNAL( scaleChanged()), this,SLOT(updateConfig())); // Create agenda mAgenda = new KOAgenda(1,96,KOPrefs::instance()->mHourSize,agendaFrame); agendaLayout->addMultiCellWidget(mAgenda,2,2,1,2); agendaLayout->setColStretch(1,1); mAgenda->setFocusPolicy(NoFocus); // Create event context menu for agenda mAgendaPopup = eventPopup(); mAgendaPopup->addAdditionalItem(QIconSet(SmallIcon("bell")), i18n("Toggle Alarm"),mAgenda, SLOT(popupAlarm()),true); connect(mAgenda,SIGNAL(showIncidencePopupSignal(Incidence *)), mAgendaPopup,SLOT(showIncidencePopup(Incidence *))); // make connections between dependent widgets mTimeLabels->setAgenda(mAgenda); // Update widgets to reflect user preferences // updateConfig(); // createDayLabels(); // these blank widgets make the All Day Event box line up with the agenda dummyAllDayRight->setFixedWidth(mAgenda->verticalScrollBar()->width()); dummyAgendaRight->setFixedWidth(mAgenda->verticalScrollBar()->width()); mDummyAllDayLeft->setFixedWidth(mTimeLabels->width()); // Scrolling connect(mAgenda->verticalScrollBar(),SIGNAL(valueChanged(int)), mTimeLabels, SLOT(positionChanged())); connect(mTimeLabels->verticalScrollBar(),SIGNAL(valueChanged(int)), SLOT(setContentsPos(int))); connect(mAgenda,SIGNAL(showDateView( int, int)),SLOT(slotShowDateView( int, int ))); connect(mAllDayAgenda,SIGNAL(showDateView( int, int )), SLOT(slotShowDateView( int, int ) )); // Create/Show/Edit/Delete Event connect(mAgenda,SIGNAL(newEventSignal(int,int)), SLOT(newEvent(int,int))); connect(mAgenda,SIGNAL(newTodoSignal(int,int)), SLOT(newTodo(int,int))); connect(mAgenda,SIGNAL(newEventSignal(int,int,int,int)), SLOT(newEvent(int,int,int,int))); connect(mAllDayAgenda,SIGNAL(newEventSignal(int,int)), SLOT(newEventAllDay(int,int))); connect(mAllDayAgenda,SIGNAL(newTodoSignal(int,int)), SLOT(newTodoAllDay(int,int))); connect(mAllDayAgenda,SIGNAL(newEventSignal(int,int,int,int)), SLOT(newEventAllDay(int,int))); connect(mAgenda,SIGNAL(newTimeSpanSignal(int,int,int,int)), SLOT(newTimeSpanSelected(int,int,int,int))); connect(mAllDayAgenda,SIGNAL(newTimeSpanSignal(int,int,int,int)), SLOT(newTimeSpanSelectedAllDay(int,int,int,int))); connect(mAgenda,SIGNAL(newStartSelectSignal()),SLOT(updateView())); connect(mAllDayAgenda,SIGNAL(newStartSelectSignal()),SLOT(updateView())); connect(mAgenda,SIGNAL(editIncidenceSignal(Incidence *)), SIGNAL(editIncidenceSignal(Incidence *))); connect(mAllDayAgenda,SIGNAL(editIncidenceSignal(Incidence *)), SIGNAL(editIncidenceSignal(Incidence *))); connect(mAgenda,SIGNAL(showIncidenceSignal(Incidence *)), SIGNAL(showIncidenceSignal(Incidence *))); connect(mAllDayAgenda,SIGNAL(showIncidenceSignal(Incidence *)), SIGNAL(showIncidenceSignal(Incidence *))); connect(mAgenda,SIGNAL(deleteIncidenceSignal(Incidence *)), SIGNAL(deleteIncidenceSignal(Incidence *))); connect(mAllDayAgenda,SIGNAL(deleteIncidenceSignal(Incidence *)), SIGNAL(deleteIncidenceSignal(Incidence *))); connect(mAgenda,SIGNAL(itemModified(KOAgendaItem *, int )), SLOT(updateEventDates(KOAgendaItem *, int ))); connect(mAllDayAgenda,SIGNAL(itemModified(KOAgendaItem *, int )), SLOT(updateEventDates(KOAgendaItem *, int))); // event indicator update connect(mAgenda,SIGNAL(lowerYChanged(int)), SLOT(updateEventIndicatorTop(int))); connect(mAgenda,SIGNAL(upperYChanged(int)), SLOT(updateEventIndicatorBottom(int))); // drag signals /* connect(mAgenda,SIGNAL(startDragSignal(Event *)), SLOT(startDrag(Event *))); connect(mAllDayAgenda,SIGNAL(startDragSignal(Event *)), SLOT(startDrag(Event *))); */ // synchronize selections connect( mAgenda, SIGNAL( incidenceSelected( Incidence * ) ), mAllDayAgenda, SLOT( deselectItem() ) ); connect( mAllDayAgenda, SIGNAL( incidenceSelected( Incidence * ) ), mAgenda, SLOT( deselectItem() ) ); connect( mAgenda, SIGNAL( incidenceSelected( Incidence * ) ), SIGNAL( incidenceSelected( Incidence * ) ) ); connect( mAllDayAgenda, SIGNAL( incidenceSelected( Incidence * ) ), SIGNAL( incidenceSelected( Incidence * ) ) ); connect( mAgenda, SIGNAL( resizedSignal() ), SLOT( updateConfig( ) ) ); connect( mAgenda, SIGNAL( addToCalSignal(Incidence *, Incidence *) ), SLOT( addToCalSlot(Incidence *, Incidence * ) ) ); connect( mAllDayAgenda, SIGNAL( addToCalSignal(Incidence * ,Incidence *) ), SLOT( addToCalSlot(Incidence * , Incidence *) ) ); // connect( mAgenda, SIGNAL( cloneIncidenceSignal(Incidence *) ), SIGNAL( cloneIncidenceSignal(Incidence *) ) ); //connect( mAllDayAgenda, SIGNAL( cloneIncidenceSignal(Incidence *) ), SIGNAL( cloneIncidenceSignal(Incidence *) ) ); } void KOAgendaView::toggleAllDay() { if ( mSplitterAgenda->firstHandle() ) mSplitterAgenda->firstHandle()->toggle(); } void KOAgendaView::addToCalSlot(Incidence * inc, Incidence * incOld ) { calendar()->addIncidence( inc ); if ( incOld ) { if ( incOld->type() == "Todo" ) emit todoMoved((Todo*)incOld, KOGlobals::EVENTEDITED ); else emit incidenceChanged(incOld, KOGlobals::EVENTEDITED); } } KOAgendaView::~KOAgendaView() { delete mAgendaPopup; delete mAllDayAgendaPopup; delete KOAgendaItem::paintPix(); delete KOAgendaItem::paintPixSel(); } void KOAgendaView::resizeEvent( QResizeEvent* e ) { diff --git a/microkde/KDGanttMinimizeSplitter.cpp b/microkde/KDGanttMinimizeSplitter.cpp index d675517..6cb1f31 100644 --- a/microkde/KDGanttMinimizeSplitter.cpp +++ b/microkde/KDGanttMinimizeSplitter.cpp @@ -297,777 +297,778 @@ void KDGanttSplitterHandle::paintEvent( QPaintEvent * ) p.translate( 0, 1 ); for ( QValueList<QPointArray>::Iterator it = list.begin(); it != list.end(); ++it ) { if ( index == _activeButton ) { /* if ( ! _collapsed ) { p.save(); // p.translate( parentWidget()->style().pixelMetric( QStyle::PM_ButtonShiftHorizontal ), // parentWidget()->style().pixelMetric( QStyle::PM_ButtonShiftVertical ) ); p.translate( -1, 0 ); p.drawPolygon( *it, true ); p.restore(); } else */ p.drawPolygon( *it, true ); } else { /* if ( ! _collapsed ) { p.save(); p.translate( -1, 0 ); p.drawPolygon( *it, true ); p.restore(); } else */ p.drawPolygon( *it, true ); } index++; } // Draw the lines between the arrows if ( s->minimizeDirection() == KDGanttMinimizeSplitter::Left || s->minimizeDirection() == KDGanttMinimizeSplitter::Right ) { int mid = height()/2; p.drawLine ( 1, mid - sw, 1, mid + sw ); p.drawLine ( 3, mid - sw, 3, mid + sw ); } else if ( s->minimizeDirection() == KDGanttMinimizeSplitter::Up || s->minimizeDirection() == KDGanttMinimizeSplitter::Down ) { int mid = width()/2; p.drawLine( mid -sw, 1, mid +sw, 1 ); p.drawLine( mid -sw, 3, mid +sw, 3 ); } bitBlt( this, 0, 0, &buffer ); } #endif class QSplitterLayoutStruct { public: KDGanttMinimizeSplitter::ResizeMode mode; QCOORD sizer; bool isSplitter; QWidget *wid; }; class QSplitterData { public: QSplitterData() : opaque( FALSE ), firstShow( TRUE ) {} QPtrList<QSplitterLayoutStruct> list; bool opaque; bool firstShow; }; void kdganttGeomCalc( QMemArray<QLayoutStruct> &chain, int start, int count, int pos, int space, int spacer ); #endif // DOXYGEN_SKIP_INTERNAL /*! \class KDGanttMinimizeSplitter KDGanttMinimizeSplitter.h \brief The KDGanttMinimizeSplitter class implements a splitter widget with minimize buttons. This class (and its documentation) is largely a copy of Qt's QSplitter; the copying was necessary because QSplitter is not extensible at all. QSplitter and its documentation are licensed according to the GPL and the Qt Professional License (if you hold such a license) and are (C) Trolltech AS. A splitter lets the user control the size of child widgets by dragging the boundary between the children. Any number of widgets may be controlled. To show a QListBox, a QListView and a QTextEdit side by side: \code KDGanttMinimizeSplitter *split = new KDGanttMinimizeSplitter( parent ); QListBox *lb = new QListBox( split ); QListView *lv = new QListView( split ); QTextEdit *ed = new QTextEdit( split ); \endcode In KDGanttMinimizeSplitter, the boundary can be either horizontal or vertical. The default is horizontal (the children are side by side) but you can use setOrientation( QSplitter::Vertical ) to set it to vertical. Use setResizeMode() to specify that a widget should keep its size when the splitter is resized. Although KDGanttMinimizeSplitter normally resizes the children only at the end of a resize operation, if you call setOpaqueResize( TRUE ) the widgets are resized as often as possible. The initial distribution of size between the widgets is determined by the initial size of each widget. You can also use setSizes() to set the sizes of all the widgets. The function sizes() returns the sizes set by the user. If you hide() a child, its space will be distributed among the other children. It will be reinstated when you show() it again. It is also possible to reorder the widgets within the splitter using moveToFirst() and moveToLast(). */ static QSize minSize( const QWidget* /*w*/ ) { return QSize(0,0); } // This is the original version of minSize static QSize minSizeHint( const QWidget* w ) { QSize min = w->minimumSize(); QSize s; if ( min.height() <= 0 || min.width() <= 0 ) s = w->minimumSizeHint(); if ( min.height() > 0 ) s.setHeight( min.height() ); if ( min.width() > 0 ) s.setWidth( min.width() ); return s.expandedTo(QSize(0,0)); } /*! Constructs a horizontal splitter with the \a parent and \a name arguments being passed on to the QFrame constructor. */ KDGanttMinimizeSplitter::KDGanttMinimizeSplitter( QWidget *parent, const char *name ) :QFrame(parent,name,WPaintUnclipped) { mRubberBand = 0; mFirstHandle = 0; #if QT_VERSION >= 232 orient = Horizontal; init(); #endif } /*! Constructs a splitter with orientation \a o with the \a parent and \a name arguments being passed on to the QFrame constructor. */ KDGanttMinimizeSplitter::KDGanttMinimizeSplitter( Orientation o, QWidget *parent, const char *name ) :QFrame(parent,name,WPaintUnclipped) { mRubberBand = 0; mFirstHandle = 0; #if QT_VERSION >= 232 orient = o; init(); #endif } /*! Destroys the splitter and any children. */ KDGanttMinimizeSplitter::~KDGanttMinimizeSplitter() { #if QT_VERSION >= 232 data->list.setAutoDelete( TRUE ); delete data; #endif if ( mRubberBand ) delete mRubberBand; } #if QT_VERSION >= 232 void KDGanttMinimizeSplitter::init() { data = new QSplitterData; if ( orient == Horizontal ) setSizePolicy( QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Minimum) ); else setSizePolicy( QSizePolicy(QSizePolicy::Minimum,QSizePolicy::Expanding) ); #ifndef DESKTOP_VERSION setOpaqueResize( false ); #else setOpaqueResize( true ); #endif } #endif void KDGanttMinimizeSplitter::toggle() { if ( mFirstHandle ) mFirstHandle->toggle(); else qDebug("KDGanttMinimizeSplitter::toggle::sorry, handle not available "); } /*! \brief the orientation of the splitter By default the orientation is horizontal (the widgets are side by side). The possible orientations are Qt:Vertical and Qt::Horizontal (the default). */ void KDGanttMinimizeSplitter::setOrientation( Orientation o ) { #if QT_VERSION >= 232 if ( orient == o ) return; orient = o; if ( orient == Horizontal ) setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Minimum ) ); else setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Expanding ) ); QSplitterLayoutStruct *s = data->list.first(); while ( s ) { if ( s->isSplitter ) ((KDGanttSplitterHandle*)s->wid)->setOrientation( o ); s = data->list.next(); // ### next at end of loop, no iterator } recalc( isVisible() ); #endif } #if QT_VERSION >= 232 /*! \reimp */ void KDGanttMinimizeSplitter::resizeEvent( QResizeEvent * ) { doResize(); } /* Inserts the widget \a w at the end (or at the beginning if \a first is TRUE) of the splitter's list of widgets. It is the responsibility of the caller of this function to make sure that \a w is not already in the splitter and to call recalcId if needed. (If \a first is TRUE, then recalcId is very probably needed.) */ QSplitterLayoutStruct *KDGanttMinimizeSplitter::addWidget( QWidget *w, bool first ) { QSplitterLayoutStruct *s; KDGanttSplitterHandle *newHandle = 0; if ( data->list.count() > 0 ) { s = new QSplitterLayoutStruct; s->mode = KeepSize; QString tmp = "qt_splithandle_"; tmp += w->name(); newHandle = new KDGanttSplitterHandle( orientation(), this, tmp.latin1() ); if ( ! mFirstHandle ) mFirstHandle = newHandle; s->wid = newHandle; newHandle->setId(data->list.count()); s->isSplitter = TRUE; s->sizer = pick( newHandle->sizeHint() ); if ( first ) data->list.insert( 0, s ); else data->list.append( s ); } s = new QSplitterLayoutStruct; s->mode = Stretch; s->wid = w; if ( !testWState( WState_Resized ) && w->sizeHint().isValid() ) s->sizer = pick( w->sizeHint() ); else s->sizer = pick( w->size() ); s->isSplitter = FALSE; if ( first ) data->list.insert( 0, s ); else data->list.append( s ); if ( newHandle && isVisible() ) newHandle->show(); //will trigger sending of post events return s; } /*! Tells the splitter that a child widget has been inserted or removed. The event is passed in \a c. */ void KDGanttMinimizeSplitter::childEvent( QChildEvent *c ) { if ( c->type() == QEvent::ChildInserted ) { if ( !c->child()->isWidgetType() ) return; if ( ((QWidget*)c->child())->testWFlags( WType_TopLevel ) ) return; QSplitterLayoutStruct *s = data->list.first(); while ( s ) { if ( s->wid == c->child() ) return; s = data->list.next(); } addWidget( (QWidget*)c->child() ); recalc( isVisible() ); } else if ( c->type() == QEvent::ChildRemoved ) { QSplitterLayoutStruct *p = 0; if ( data->list.count() > 1 ) p = data->list.at(1); //remove handle _after_ first widget. QSplitterLayoutStruct *s = data->list.first(); while ( s ) { if ( s->wid == c->child() ) { data->list.removeRef( s ); delete s; if ( p && p->isSplitter ) { data->list.removeRef( p ); delete p->wid; //will call childEvent delete p; } recalcId(); doResize(); return; } p = s; s = data->list.next(); } } } /*! Shows a rubber band at position \a p. If \a p is negative, the rubber band is removed. */ void KDGanttMinimizeSplitter::setRubberband( int p ) { #ifdef DESKTOP_VERSION QPainter paint( this ); paint.setPen( gray ); paint.setBrush( gray ); paint.setRasterOp( XorROP ); QRect r = contentsRect(); const int rBord = 3; //Themable???? #if QT_VERSION >= 0x030000 int sw = style().pixelMetric(QStyle::PM_SplitterWidth, this); #else int sw = style().splitterWidth(); #endif if ( orient == Horizontal ) { if ( opaqueOldPos >= 0 ) paint.drawRect( opaqueOldPos + sw/2 - rBord , r.y(), 2*rBord, r.height() ); if ( p >= 0 ) paint.drawRect( p + sw/2 - rBord, r.y(), 2*rBord, r.height() ); } else { if ( opaqueOldPos >= 0 ) paint.drawRect( r.x(), opaqueOldPos + sw/2 - rBord, r.width(), 2*rBord ); if ( p >= 0 ) paint.drawRect( r.x(), p + sw/2 - rBord, r.width(), 2*rBord ); } opaqueOldPos = p; #else if ( !mRubberBand ) { mRubberBand = new QFrame( 0, "rubber", WStyle_NoBorder | WStyle_Customize | WStyle_StaysOnTop); mRubberBand->setFrameStyle( Box | Raised ); - mRubberBand->setPalette( QPalette ( Qt::red.light(),Qt::red.dark() ) ); + //mRubberBand->setPalette( QPalette ( Qt::red.light(),Qt::red.dark() ) ); + mRubberBand->setPalette( QPalette ( QColor( 178,18,188), QColor( 242,27,255 ) )); } QRect r = contentsRect(); static int rBord = 0; //Themable???? if ( !rBord ) { if (QApplication::desktop()->width() <= 320 ) - rBord = 4; + rBord = 3; else - rBord = 5; + rBord = 4; } int sw = style().splitterWidth(); if ( orient == Horizontal ) { if ( p >= 0 ) { QPoint geo = mapToGlobal (QPoint ( p + sw/2 - rBord, r.y())); mRubberBand->setGeometry( geo.x(), geo.y(), 2*rBord, r.height() ); } } else { if ( p >= 0 ) { QPoint geo = mapToGlobal (QPoint ( r.x(), p + sw/2 - rBord)); mRubberBand->setGeometry( geo.x(), geo.y(), r.width(), 2*rBord); } } opaqueOldPos = p; if ( ! mRubberBand->isVisible() ) { mRubberBand->show(); } #endif } /*! \reimp */ bool KDGanttMinimizeSplitter::event( QEvent *e ) { if ( e->type() == QEvent::LayoutHint || ( e->type() == QEvent::Show && data->firstShow ) ) { recalc( isVisible() ); if ( e->type() == QEvent::Show ) data->firstShow = FALSE; } return QWidget::event( e ); } /*! \obsolete Draws the splitter handle in the rectangle described by \a x, \a y, \a w, \a h using painter \a p. \sa QStyle::drawPrimitive() */ void KDGanttMinimizeSplitter::drawSplitter( QPainter *p, QCOORD x, QCOORD y, QCOORD w, QCOORD h ) { #if 0 // LR style().drawPrimitive(QStyle::PE_Splitter, p, QRect(x, y, w, h), colorGroup(), (orientation() == Qt::Horizontal ? QStyle::Style_Horizontal : 0)); #endif } /*! Returns the id of the splitter to the right of or below the widget \a w, or 0 if there is no such splitter (i.e. it is either not in this KDGanttMinimizeSplitter or it is at the end). */ int KDGanttMinimizeSplitter::idAfter( QWidget* w ) const { QSplitterLayoutStruct *s = data->list.first(); bool seen_w = FALSE; while ( s ) { if ( s->isSplitter && seen_w ) return data->list.at(); if ( !s->isSplitter && s->wid == w ) seen_w = TRUE; s = data->list.next(); } return 0; } /*! Moves the left/top edge of the splitter handle with id \a id as close as possible to position \a p, which is the distance from the left (or top) edge of the widget. For Arabic and Hebrew the layout is reversed, and using this function to set the position of the splitter might lead to unexpected results, since in Arabic and Hebrew the position of splitter one is to the left of the position of splitter zero. \sa idAfter() */ void KDGanttMinimizeSplitter::moveSplitter( QCOORD p, int id ) { p = adjustPos( p, id ); QSplitterLayoutStruct *s = data->list.at(id); int oldP = orient == Horizontal ? s->wid->x() : s->wid->y(); bool upLeft; if ( false && orient == Horizontal ) { p += s->wid->width(); upLeft = p > oldP; } else upLeft = p < oldP; moveAfter( p, id, upLeft ); moveBefore( p-1, id-1, upLeft ); storeSizes(); } void KDGanttMinimizeSplitter::setG( QWidget *w, int p, int s, bool isSplitter ) { if ( orient == Horizontal ) { if ( false && orient == Horizontal && !isSplitter ) p = contentsRect().width() - p - s; w->setGeometry( p, contentsRect().y(), s, contentsRect().height() ); } else w->setGeometry( contentsRect().x(), p, contentsRect().width(), s ); } /* Places the right/bottom edge of the widget at \a id at position \a pos. \sa idAfter() */ void KDGanttMinimizeSplitter::moveBefore( int pos, int id, bool upLeft ) { if( id < 0 ) return; QSplitterLayoutStruct *s = data->list.at(id); if ( !s ) return; QWidget *w = s->wid; if ( w->isHidden() ) { moveBefore( pos, id-1, upLeft ); } else if ( s->isSplitter ) { int pos1, pos2; int dd = s->sizer; if( false && orient == Horizontal ) { pos1 = pos; pos2 = pos + dd; } else { pos2 = pos - dd; pos1 = pos2 + 1; } if ( upLeft ) { setG( w, pos1, dd, TRUE ); moveBefore( pos2, id-1, upLeft ); } else { moveBefore( pos2, id-1, upLeft ); setG( w, pos1, dd, TRUE ); } } else { int dd, newLeft, nextPos; if( false && orient == Horizontal ) { dd = w->geometry().right() - pos; dd = QMAX( pick(minSize(w)), QMIN(dd, pick(w->maximumSize()))); newLeft = pos+1; nextPos = newLeft + dd; } else { dd = pos - pick( w->pos() ) + 1; dd = QMAX( pick(minSize(w)), QMIN(dd, pick(w->maximumSize()))); newLeft = pos-dd+1; nextPos = newLeft - 1; } setG( w, newLeft, dd, TRUE ); moveBefore( nextPos, id-1, upLeft ); } } /* Places the left/top edge of the widget at \a id at position \a pos. \sa idAfter() */ void KDGanttMinimizeSplitter::moveAfter( int pos, int id, bool upLeft ) { QSplitterLayoutStruct *s = id < int(data->list.count()) ? data->list.at(id) : 0; if ( !s ) return; QWidget *w = s->wid; if ( w->isHidden() ) { moveAfter( pos, id+1, upLeft ); } else if ( pick( w->pos() ) == pos ) { //No need to do anything if it's already there. return; } else if ( s->isSplitter ) { int dd = s->sizer; int pos1, pos2; if( false && orient == Horizontal ) { pos2 = pos - dd; pos1 = pos2 + 1; } else { pos1 = pos; pos2 = pos + dd; } if ( upLeft ) { setG( w, pos1, dd, TRUE ); moveAfter( pos2, id+1, upLeft ); } else { moveAfter( pos2, id+1, upLeft ); setG( w, pos1, dd, TRUE ); } } else { int left = pick( w->pos() ); int right, dd,/* newRight,*/ newLeft, nextPos; if ( false && orient == Horizontal ) { dd = pos - left + 1; dd = QMAX( pick(minSize(w)), QMIN(dd, pick(w->maximumSize()))); newLeft = pos-dd+1; nextPos = newLeft - 1; } else { right = pick( w->geometry().bottomRight() ); dd = right - pos + 1; dd = QMAX( pick(minSize(w)), QMIN(dd, pick(w->maximumSize()))); /*newRight = pos+dd-1;*/ newLeft = pos; nextPos = newLeft + dd; } setG( w, newLeft, dd, TRUE ); /*if( right != newRight )*/ moveAfter( nextPos, id+1, upLeft ); } } void KDGanttMinimizeSplitter::expandPos( int id, int* min, int* max ) { QSplitterLayoutStruct *s = data->list.at(id-1); QWidget* w = s->wid; *min = pick( w->mapToParent( QPoint(0,0) ) ); if ( (uint) id == data->list.count() ) { pick( size() ); } else { QSplitterLayoutStruct *s = data->list.at(id+1); QWidget* w = s->wid; *max = pick( w->mapToParent( QPoint( w->width(), w->height() ) ) ) -8; } } /*! Returns the valid range of the splitter with id \a id in \a *min and \a *max. \sa idAfter() */ void KDGanttMinimizeSplitter::getRange( int id, int *min, int *max ) { int minB = 0; //before int maxB = 0; int minA = 0; int maxA = 0; //after int n = data->list.count(); if ( id < 0 || id >= n ) return; int i; for ( i = 0; i < id; i++ ) { QSplitterLayoutStruct *s = data->list.at(i); if ( s->wid->isHidden() ) { //ignore } else if ( s->isSplitter ) { minB += s->sizer; maxB += s->sizer; } else { minB += pick( minSize(s->wid) ); maxB += pick( s->wid->maximumSize() ); } } for ( i = id; i < n; i++ ) { QSplitterLayoutStruct *s = data->list.at(i); if ( s->wid->isHidden() ) { //ignore } else if ( s->isSplitter ) { minA += s->sizer; maxA += s->sizer; } else { minA += pick( minSize(s->wid) ); maxA += pick( s->wid->maximumSize() ); } } QRect r = contentsRect(); if ( orient == Horizontal && false ) { #if QT_VERSION >= 0x030000 int splitterWidth = style().pixelMetric(QStyle::PM_SplitterWidth, this); #else int splitterWidth = style().splitterWidth(); #endif if ( min ) *min = pick(r.topRight()) - QMIN( maxB, pick(r.size())-minA ) - splitterWidth; if ( max ) *max = pick(r.topRight()) - QMAX( minB, pick(r.size())-maxA ) - splitterWidth; } else { if ( min ) *min = pick(r.topLeft()) + QMAX( minB, pick(r.size())-maxA ); if ( max ) *max = pick(r.topLeft()) + QMIN( maxB, pick(r.size())-minA ); } } /*! Returns the closest legal position to \a p of the splitter with id \a id. \sa idAfter() */ int KDGanttMinimizeSplitter::adjustPos( int p, int id ) { int min = 0; int max = 0; getRange( id, &min, &max ); p = QMAX( min, QMIN( p, max ) ); return p; } void KDGanttMinimizeSplitter::doResize() { QRect r = contentsRect(); int i; int n = data->list.count(); QMemArray<QLayoutStruct> a( n ); for ( i = 0; i< n; i++ ) { a[i].init(); QSplitterLayoutStruct *s = data->list.at(i); if ( s->wid->isHidden() ) { a[i].stretch = 0; a[i].sizeHint = a[i].minimumSize = 0; a[i].maximumSize = 0; } else if ( s->isSplitter ) { a[i].stretch = 0; a[i].sizeHint = a[i].minimumSize = a[i].maximumSize = s->sizer; a[i].empty = FALSE; } else if ( s->mode == KeepSize ) { a[i].stretch = 0; a[i].minimumSize = pick( minSize(s->wid) ); a[i].sizeHint = s->sizer; a[i].maximumSize = pick( s->wid->maximumSize() ); a[i].empty = FALSE; } else if ( s->mode == FollowSizeHint ) { a[i].stretch = 0; a[i].minimumSize = a[i].sizeHint = pick( s->wid->sizeHint() ); a[i].maximumSize = pick( s->wid->maximumSize() ); a[i].empty = FALSE; } else { //proportional a[i].stretch = s->sizer; a[i].maximumSize = pick( s->wid->maximumSize() ); a[i].sizeHint = a[i].minimumSize = pick( minSize(s->wid) ); a[i].empty = FALSE; } } kdganttGeomCalc( a, 0, n, pick( r.topLeft() ), pick( r.size() ), 0 ); for ( i = 0; i< n; i++ ) { QSplitterLayoutStruct *s = data->list.at(i); setG( s->wid, a[i].pos, a[i].size ); } } void KDGanttMinimizeSplitter::recalc( bool update ) { int fi = 2*frameWidth(); int maxl = fi; int minl = fi; int maxt = QWIDGETSIZE_MAX; int mint = fi; int n = data->list.count(); bool first = TRUE; /* The splitter before a hidden widget is always hidden. The splitter before the first visible widget is hidden. The splitter before any other visible widget is visible. */ for ( int i = 0; i< n; i++ ) { QSplitterLayoutStruct *s = data->list.at(i); if ( !s->isSplitter ) { QSplitterLayoutStruct *p = (i > 0) ? p = data->list.at( i-1 ) : 0; if ( p && p->isSplitter ) if ( first || s->wid->isHidden() ) p->wid->hide(); //may trigger new recalc |