You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2062 lines
64 KiB
2062 lines
64 KiB
/*
|
|
This file is part of KOrganizer.
|
|
Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
|
|
Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
|
|
|
|
Marcus Bains line.
|
|
Copyright (c) 2001 Ali Rahimi
|
|
|
|
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
As a special exception, permission is given to link this program
|
|
with any edition of TQt, and distribute the resulting executable,
|
|
without including the source code for TQt in the source distribution.
|
|
*/
|
|
#include <assert.h>
|
|
|
|
#include <tqintdict.h>
|
|
#include <tqdatetime.h>
|
|
#include <tqapplication.h>
|
|
#include <tqpopupmenu.h>
|
|
#include <tqcursor.h>
|
|
#include <tqpainter.h>
|
|
#include <tqlabel.h>
|
|
|
|
#include <kdebug.h>
|
|
#include <klocale.h>
|
|
#include <kiconloader.h>
|
|
#include <kglobal.h>
|
|
#include <kmessagebox.h>
|
|
|
|
#include "koagendaitem.h"
|
|
#include "koprefs.h"
|
|
#include "koglobals.h"
|
|
#include "komessagebox.h"
|
|
#include "incidencechanger.h"
|
|
#include "kohelper.h"
|
|
|
|
#include "koagenda.h"
|
|
#include "koagenda.moc"
|
|
#include <korganizer/baseview.h>
|
|
|
|
#include <libkcal/event.h>
|
|
#include <libkcal/todo.h>
|
|
#include <libkcal/dndfactory.h>
|
|
#include <libkcal/icaldrag.h>
|
|
#include <libkcal/vcaldrag.h>
|
|
#include <libkcal/calendar.h>
|
|
#include <libkcal/calendarresources.h>
|
|
#include <libkcal/calhelper.h>
|
|
#include <math.h>
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
MarcusBains::MarcusBains(KOAgenda *_agenda,const char *name )
|
|
: TQFrame(_agenda->viewport(), name), agenda(_agenda)
|
|
{
|
|
setLineWidth(0);
|
|
setMargin(0);
|
|
setBackgroundColor(TQt::red);
|
|
minutes = new TQTimer(this);
|
|
connect(minutes, TQT_SIGNAL(timeout()), this, TQT_SLOT(updateLocation()));
|
|
minutes->start(0, true);
|
|
|
|
mTimeBox = new TQLabel(this);
|
|
mTimeBox->setAlignment(TQt::AlignRight | TQt::AlignBottom);
|
|
TQPalette pal = mTimeBox->palette();
|
|
pal.setColor(TQColorGroup::Foreground, TQt::red);
|
|
mTimeBox->setPalette(pal);
|
|
mTimeBox->setAutoMask(true);
|
|
|
|
agenda->addChild(mTimeBox);
|
|
|
|
mOldTime = TQTime( 0, 0 );
|
|
mOldToday = -1;
|
|
}
|
|
|
|
MarcusBains::~MarcusBains()
|
|
{
|
|
delete minutes;
|
|
}
|
|
|
|
int MarcusBains::todayColumn()
|
|
{
|
|
TQDate currentDate = TQDate::currentDate();
|
|
|
|
DateList dateList = agenda->dateList();
|
|
DateList::ConstIterator it;
|
|
int col = 0;
|
|
for(it = dateList.begin(); it != dateList.end(); ++it) {
|
|
if((*it) == currentDate)
|
|
return KOGlobals::self()->reverseLayout() ?
|
|
agenda->columns() - 1 - col : col;
|
|
++col;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void MarcusBains::updateLocation()
|
|
{
|
|
updateLocationRecalc();
|
|
}
|
|
|
|
void MarcusBains::updateLocationRecalc( bool recalculate )
|
|
{
|
|
TQTime tim = TQTime::currentTime();
|
|
if((tim.hour() == 0) && (mOldTime.hour()==23))
|
|
recalculate = true;
|
|
|
|
int mins = tim.hour()*60 + tim.minute();
|
|
int minutesPerCell = 24 * 60 / agenda->rows();
|
|
int y = int( mins * agenda->gridSpacingY() / minutesPerCell );
|
|
int today = recalculate ? todayColumn() : mOldToday;
|
|
int x = int( agenda->gridSpacingX() * today );
|
|
|
|
mOldTime = tim;
|
|
mOldToday = today;
|
|
|
|
bool hideIt = !( KOPrefs::instance()->mMarcusBainsEnabled );
|
|
|
|
if ( !isHidden() && ( hideIt || ( today < 0 ) ) ) {
|
|
hide();
|
|
mTimeBox->hide();
|
|
return;
|
|
}
|
|
|
|
if ( isHidden() && !hideIt ) {
|
|
show();
|
|
mTimeBox->show();
|
|
}
|
|
|
|
if ( recalculate ) setFixedSize( int( agenda->gridSpacingX() ), 1 );
|
|
agenda->moveChild( this, x, y );
|
|
raise();
|
|
|
|
if(recalculate)
|
|
mTimeBox->setFont(KOPrefs::instance()->mMarcusBainsFont);
|
|
|
|
TQString timeStr = KGlobal::locale()->formatTime(tim, KOPrefs::instance()->mMarcusBainsShowSeconds);
|
|
TQFontMetrics fm = fontMetrics();
|
|
mTimeBox->setText( timeStr );
|
|
TQSize sz( fm.width( timeStr + ' ' ), fm.height() );
|
|
mTimeBox->setFixedSize( sz );
|
|
|
|
if (y-mTimeBox->height()>=0) y-=mTimeBox->height(); else y++;
|
|
if (x-mTimeBox->width()+agenda->gridSpacingX() > 0)
|
|
x += int( agenda->gridSpacingX() - mTimeBox->width() - 1 );
|
|
else x++;
|
|
agenda->moveChild(mTimeBox,x,y);
|
|
mTimeBox->raise();
|
|
mTimeBox->setAutoMask(true);
|
|
|
|
minutes->start(1000,true);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/*
|
|
Create an agenda widget with rows rows and columns columns.
|
|
*/
|
|
KOAgenda::KOAgenda( int columns, int rows, int rowSize, CalendarView *calendarView,
|
|
TQWidget *parent, const char *name, WFlags f )
|
|
: TQScrollView( parent, name, f ), mChanger( 0 )
|
|
{
|
|
mColumns = columns;
|
|
mRows = rows;
|
|
mGridSpacingY = rowSize;
|
|
if ( mGridSpacingY < 4 || mGridSpacingY > 30 ) {
|
|
mGridSpacingY = 10;
|
|
}
|
|
|
|
mCalendarView = calendarView;
|
|
|
|
mAllDayMode = false;
|
|
|
|
init();
|
|
|
|
viewport()->setMouseTracking(true);
|
|
}
|
|
|
|
/*
|
|
Create an agenda widget with columns columns and one row. This is used for
|
|
all-day events.
|
|
*/
|
|
KOAgenda::KOAgenda( int columns, CalendarView *calendarView, TQWidget *parent,
|
|
const char *name, WFlags f ) : TQScrollView( parent, name, f )
|
|
{
|
|
mColumns = columns;
|
|
mRows = 1;
|
|
mGridSpacingY = 24;
|
|
mAllDayMode = true;
|
|
mCalendarView = calendarView;
|
|
setVScrollBarMode( AlwaysOff );
|
|
|
|
init();
|
|
}
|
|
|
|
|
|
KOAgenda::~KOAgenda()
|
|
{
|
|
delete mMarcusBains;
|
|
}
|
|
|
|
|
|
Incidence *KOAgenda::selectedIncidence() const
|
|
{
|
|
return ( mSelectedItem ? mSelectedItem->incidence() : 0 );
|
|
}
|
|
|
|
|
|
TQDate KOAgenda::selectedIncidenceDate() const
|
|
{
|
|
return ( mSelectedItem ? mSelectedItem->itemDate() : TQDate() );
|
|
}
|
|
|
|
const TQString KOAgenda::lastSelectedUid() const
|
|
{
|
|
return mSelectedUid;
|
|
}
|
|
|
|
|
|
void KOAgenda::init()
|
|
{
|
|
mGridSpacingX = 100;
|
|
mDesiredGridSpacingY = KOPrefs::instance()->mHourSize;
|
|
if ( mDesiredGridSpacingY < 4 || mDesiredGridSpacingY > 30 ) {
|
|
mDesiredGridSpacingY = 10;
|
|
}
|
|
|
|
// make sure that there are not more than 24 per day
|
|
mGridSpacingY = (double)height() / (double)mRows;
|
|
if ( mGridSpacingY < mDesiredGridSpacingY ) {
|
|
mGridSpacingY = mDesiredGridSpacingY;
|
|
}
|
|
|
|
mResizeBorderWidth = 8;
|
|
mScrollBorderWidth = 8;
|
|
mScrollDelay = 30;
|
|
mScrollOffset = 10;
|
|
|
|
enableClipper( true );
|
|
|
|
// Grab key strokes for keyboard navigation of agenda. Seems to have no
|
|
// effect. Has to be fixed.
|
|
setFocusPolicy( TQ_WheelFocus );
|
|
|
|
connect( &mScrollUpTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( scrollUp() ) );
|
|
connect( &mScrollDownTimer, TQT_SIGNAL( timeout() ), TQT_SLOT( scrollDown() ) );
|
|
|
|
mStartCell = TQPoint( 0, 0 );
|
|
mEndCell = TQPoint( 0, 0 );
|
|
|
|
mHasSelection = false;
|
|
mSelectionStartPoint = TQPoint( 0, 0 );
|
|
mSelectionStartCell = TQPoint( 0, 0 );
|
|
mSelectionEndCell = TQPoint( 0, 0 );
|
|
|
|
mOldLowerScrollValue = -1;
|
|
mOldUpperScrollValue = -1;
|
|
|
|
mClickedItem = 0;
|
|
|
|
mActionItem = 0;
|
|
mResPair = tqMakePair( static_cast<ResourceCalendar *>( 0 ), TQString() );
|
|
mActionType = NOP;
|
|
mItemMoved = false;
|
|
|
|
mSelectedItem = 0;
|
|
mSelectedUid = TQString();
|
|
|
|
setAcceptDrops( true );
|
|
installEventFilter( this );
|
|
mItems.setAutoDelete( true );
|
|
mItemsToDelete.setAutoDelete( true );
|
|
|
|
resizeContents( int( mGridSpacingX * mColumns ),
|
|
int( mGridSpacingY * mRows ) );
|
|
|
|
viewport()->update();
|
|
viewport()->setBackgroundMode( NoBackground );
|
|
viewport()->setFocusPolicy( TQ_WheelFocus );
|
|
|
|
setMinimumSize( 30, int( mGridSpacingY + 1 ) );
|
|
// setMaximumHeight(mGridSpacingY * mRows + 5);
|
|
|
|
// Disable horizontal scrollbar. This is a hack. The tqgeometry should be
|
|
// controlled in a way that the contents horizontally always fits. Then it is
|
|
// not necessary to turn off the scrollbar.
|
|
setHScrollBarMode( AlwaysOff );
|
|
|
|
setStartTime( KOPrefs::instance()->mDayBegins.time() );
|
|
|
|
calculateWorkingHours();
|
|
|
|
connect( verticalScrollBar(), TQT_SIGNAL( valueChanged( int ) ),
|
|
TQT_SLOT( checkScrollBoundaries( int ) ) );
|
|
|
|
// Create the Marcus Bains line.
|
|
if( mAllDayMode ) {
|
|
mMarcusBains = 0;
|
|
} else {
|
|
mMarcusBains = new MarcusBains( this );
|
|
addChild( mMarcusBains );
|
|
}
|
|
|
|
mTypeAhead = false;
|
|
mTypeAheadReceiver = 0;
|
|
|
|
mReturnPressed = false;
|
|
}
|
|
|
|
|
|
void KOAgenda::clear()
|
|
{
|
|
// kdDebug(5850) << "KOAgenda::clear()" << endl;
|
|
|
|
KOAgendaItem *item;
|
|
for ( item = mItems.first(); item != 0; item = mItems.next() ) {
|
|
removeChild( item );
|
|
}
|
|
mItems.clear();
|
|
mItemsToDelete.clear();
|
|
|
|
mSelectedItem = 0;
|
|
|
|
clearSelection();
|
|
}
|
|
|
|
|
|
void KOAgenda::clearSelection()
|
|
{
|
|
mHasSelection = false;
|
|
mActionType = NOP;
|
|
updateContents();
|
|
}
|
|
|
|
void KOAgenda::marcus_bains()
|
|
{
|
|
if(mMarcusBains) mMarcusBains->updateLocationRecalc( true );
|
|
}
|
|
|
|
|
|
void KOAgenda::changeColumns(int columns)
|
|
{
|
|
if (columns == 0) {
|
|
kdDebug(5850) << "KOAgenda::changeColumns() called with argument 0" << endl;
|
|
return;
|
|
}
|
|
|
|
clear();
|
|
mColumns = columns;
|
|
// setMinimumSize(mColumns * 10, mGridSpacingY + 1);
|
|
// init();
|
|
// update();
|
|
|
|
TQResizeEvent event( size(), size() );
|
|
|
|
TQApplication::sendEvent( this, &event );
|
|
}
|
|
|
|
/*
|
|
This is the eventFilter function, which gets all events from the KOAgendaItems
|
|
contained in the agenda. It has to handle moving and resizing for all items.
|
|
*/
|
|
bool KOAgenda::eventFilter ( TQObject *object, TQEvent *event )
|
|
{
|
|
// kdDebug(5850) << "KOAgenda::eventFilter() " << int( event->type() ) << endl;
|
|
|
|
switch( event->type() ) {
|
|
case TQEvent::MouseButtonPress:
|
|
case TQEvent::MouseButtonDblClick:
|
|
case TQEvent::MouseButtonRelease:
|
|
case TQEvent::MouseMove:
|
|
return eventFilter_mouse( object, TQT_TQMOUSEEVENT( event ) );
|
|
#ifndef TQT_NO_WHEELEVENT
|
|
case TQEvent::Wheel:
|
|
return eventFilter_wheel( object, TQT_TQWHEELEVENT( event ) );
|
|
#endif
|
|
case TQEvent::KeyPress:
|
|
case TQEvent::KeyRelease:
|
|
return eventFilter_key( object, TQT_TQKEYEVENT( event ) );
|
|
|
|
case ( TQEvent::Leave ):
|
|
if ( !mActionItem )
|
|
setCursor( arrowCursor );
|
|
if ( TQT_BASE_OBJECT(object) == TQT_BASE_OBJECT(viewport()) )
|
|
emit leaveAgenda();
|
|
return true;
|
|
|
|
case TQEvent::Enter:
|
|
emit enterAgenda();
|
|
return TQScrollView::eventFilter( object, event );
|
|
|
|
#ifndef KORG_NODND
|
|
case TQEvent::DragEnter:
|
|
case TQEvent::DragMove:
|
|
case TQEvent::DragLeave:
|
|
case TQEvent::Drop:
|
|
// case TQEvent::DragResponse:
|
|
return eventFilter_drag(object, static_cast<TQDropEvent*>(event));
|
|
#endif
|
|
|
|
default:
|
|
return TQScrollView::eventFilter( object, event );
|
|
}
|
|
}
|
|
|
|
bool KOAgenda::eventFilter_drag( TQObject *object, TQDropEvent *de )
|
|
{
|
|
#ifndef KORG_NODND
|
|
TQPoint viewportPos;
|
|
if ( TQT_BASE_OBJECT(object) != TQT_BASE_OBJECT(viewport()) && TQT_BASE_OBJECT(object) != TQT_BASE_OBJECT(this) ) {
|
|
viewportPos = TQT_TQWIDGET( object )->mapToParent( de->pos() );
|
|
} else {
|
|
viewportPos = de->pos();
|
|
}
|
|
|
|
switch ( de->type() ) {
|
|
case TQEvent::DragEnter:
|
|
case TQEvent::DragMove:
|
|
if ( ICalDrag::canDecode( de ) || VCalDrag::canDecode( de ) ) {
|
|
|
|
DndFactory factory( mCalendar );
|
|
Todo *todo = factory.createDropTodo( de );
|
|
if ( todo ) {
|
|
de->accept();
|
|
delete todo;
|
|
} else {
|
|
de->ignore();
|
|
}
|
|
return true;
|
|
} else return false;
|
|
break;
|
|
case TQEvent::DragLeave:
|
|
return false;
|
|
break;
|
|
case TQEvent::Drop:
|
|
{
|
|
if ( !ICalDrag::canDecode( de ) && !VCalDrag::canDecode( de ) ) {
|
|
return false;
|
|
}
|
|
|
|
DndFactory factory( mCalendar );
|
|
Todo *todo = factory.createDropTodo( de );
|
|
|
|
if ( todo ) {
|
|
de->acceptAction();
|
|
TQPoint pos;
|
|
// FIXME: This is a bad hack, as the viewportToContents seems to be off by
|
|
// 2000 (which is the left upper corner of the viewport). It works correctly
|
|
// for agendaItems.
|
|
if ( TQT_BASE_OBJECT(object) == TQT_BASE_OBJECT(this) ) {
|
|
pos = viewportPos + TQPoint( contentsX(), contentsY() );
|
|
} else {
|
|
pos = viewportToContents( viewportPos );
|
|
}
|
|
TQPoint gpos = contentsToGrid( pos );
|
|
emit droppedToDo( todo, gpos, mAllDayMode );
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TQEvent::DragResponse:
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
bool KOAgenda::eventFilter_key( TQObject *, TQKeyEvent *ke )
|
|
{
|
|
// kdDebug(5850) << "KOAgenda::eventFilter_key() " << ke->type() << endl;
|
|
|
|
// If Return is pressed bring up an editor for the current selected time span.
|
|
if ( ke->key() == Key_Return ) {
|
|
if ( ke->type() == TQEvent::KeyPress ) mReturnPressed = true;
|
|
else if ( ke->type() == TQEvent::KeyRelease ) {
|
|
if ( mReturnPressed ) {
|
|
emitNewEventForSelection();
|
|
mReturnPressed = false;
|
|
return true;
|
|
} else {
|
|
mReturnPressed = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ignore all input that does not produce any output
|
|
if ( ke->text().isEmpty() ) return false;
|
|
|
|
if ( ke->type() == TQEvent::KeyPress || ke->type() == TQEvent::KeyRelease ) {
|
|
switch ( ke->key() ) {
|
|
case Key_Escape:
|
|
case Key_Return:
|
|
case Key_Enter:
|
|
case Key_Tab:
|
|
case Key_Backtab:
|
|
case Key_Left:
|
|
case Key_Right:
|
|
case Key_Up:
|
|
case Key_Down:
|
|
case Key_Backspace:
|
|
case Key_Delete:
|
|
case Key_Prior:
|
|
case Key_Next:
|
|
case Key_Home:
|
|
case Key_End:
|
|
case Key_Control:
|
|
case Key_Meta:
|
|
case Key_Alt:
|
|
break;
|
|
default:
|
|
mTypeAheadEvents.append( TQT_TQEVENT( new TQKeyEvent( ke->type(), ke->key(),
|
|
ke->ascii(), ke->state(),
|
|
ke->text(), ke->isAutoRepeat(),
|
|
ke->count() ) ) );
|
|
if ( !mTypeAhead ) {
|
|
mTypeAhead = true;
|
|
emitNewEventForSelection();
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void KOAgenda::emitNewEventForSelection()
|
|
{
|
|
TQPair<ResourceCalendar *, TQString>p = mCalendarView->viewSubResourceCalendar();
|
|
emit newEventSignal( p.first, p.second );
|
|
}
|
|
|
|
void KOAgenda::finishTypeAhead()
|
|
{
|
|
// kdDebug(5850) << "KOAgenda::finishTypeAhead()" << endl;
|
|
if ( typeAheadReceiver() ) {
|
|
for( TQEvent *e = mTypeAheadEvents.first(); e;
|
|
e = mTypeAheadEvents.next() ) {
|
|
// kdDebug(5850) << "sendEvent() " << int( typeAheadReceiver() ) << endl;
|
|
TQApplication::sendEvent( typeAheadReceiver(), e );
|
|
}
|
|
}
|
|
mTypeAheadEvents.clear();
|
|
mTypeAhead = false;
|
|
}
|
|
#ifndef TQT_NO_WHEELEVENT
|
|
bool KOAgenda::eventFilter_wheel ( TQObject *object, TQWheelEvent *e )
|
|
{
|
|
TQPoint viewportPos;
|
|
bool accepted=false;
|
|
if ( ( e->state() & ShiftButton) == ShiftButton ) {
|
|
if ( TQT_BASE_OBJECT(object) != TQT_BASE_OBJECT(viewport()) ) {
|
|
viewportPos = ( (TQWidget *) object )->mapToParent( e->pos() );
|
|
} else {
|
|
viewportPos = e->pos();
|
|
}
|
|
//kdDebug(5850)<< "KOAgenda::eventFilter_wheel: type:"<<
|
|
// e->type()<<" delta: "<< e->delta()<< endl;
|
|
emit zoomView( -e->delta() ,
|
|
contentsToGrid( viewportToContents( viewportPos ) ),
|
|
Qt::Horizontal );
|
|
accepted=true;
|
|
}
|
|
|
|
if ( ( e->state() & ControlButton ) == ControlButton ){
|
|
if ( TQT_BASE_OBJECT(object) != TQT_BASE_OBJECT(viewport()) ) {
|
|
viewportPos = ( (TQWidget *)object )->mapToParent( e->pos() );
|
|
} else {
|
|
viewportPos = e->pos();
|
|
}
|
|
emit zoomView( -e->delta() ,
|
|
contentsToGrid( viewportToContents( viewportPos ) ),
|
|
Qt::Vertical );
|
|
emit mousePosSignal(gridToContents(contentsToGrid(viewportToContents( viewportPos ))));
|
|
accepted=true;
|
|
}
|
|
if (accepted ) e->accept();
|
|
return accepted;
|
|
}
|
|
#endif
|
|
bool KOAgenda::eventFilter_mouse(TQObject *object, TQMouseEvent *me)
|
|
{
|
|
TQPoint viewportPos;
|
|
if (TQT_BASE_OBJECT(object) != TQT_BASE_OBJECT(viewport())) {
|
|
viewportPos = ((TQWidget *)object)->mapToParent(me->pos());
|
|
} else {
|
|
viewportPos = me->pos();
|
|
}
|
|
|
|
switch (me->type()) {
|
|
case TQEvent::MouseButtonPress:
|
|
// kdDebug(5850) << "koagenda: filtered button press" << endl;
|
|
if (TQT_BASE_OBJECT(object) != TQT_BASE_OBJECT(viewport())) {
|
|
if (me->button() == Qt::RightButton) {
|
|
mClickedItem = dynamic_cast<KOAgendaItem *>(object);
|
|
if (mClickedItem) {
|
|
selectItem(mClickedItem);
|
|
emit showIncidencePopupSignal( mCalendar,
|
|
mClickedItem->incidence(),
|
|
mClickedItem->itemDate() );
|
|
} else {
|
|
return TQScrollView::eventFilter( TQT_TQOBJECT(object), TQT_TQEVENT(me) ); // pass through for use by multiagenda
|
|
}
|
|
} else {
|
|
KOAgendaItem* item = dynamic_cast<KOAgendaItem *>(object);
|
|
if (item) {
|
|
Incidence *incidence = item->incidence();
|
|
if ( incidence->isReadOnly() ) {
|
|
mActionItem = 0;
|
|
mResPair = tqMakePair( static_cast<ResourceCalendar *>( 0 ), TQString() );
|
|
} else {
|
|
mActionItem = item;
|
|
mResPair = CalHelper::incSubResourceCalendar( mCalendar, incidence );
|
|
startItemAction(viewportPos);
|
|
}
|
|
// Warning: do selectItem() as late as possible, since all
|
|
// sorts of things happen during this call. Some can lead to
|
|
// this filter being run again and mActionItem being set to
|
|
// null.
|
|
selectItem( item );
|
|
} else {
|
|
return TQScrollView::eventFilter( TQT_TQOBJECT(object), TQT_TQEVENT(me) ); // pass through for use by multiagenda
|
|
}
|
|
}
|
|
} else {
|
|
if ( me->button() == Qt::RightButton ) {
|
|
// if mouse pointer is not in selection, select the cell below the cursor
|
|
TQPoint gpos = contentsToGrid( viewportToContents( viewportPos ) );
|
|
if ( !ptInSelection( gpos ) ) {
|
|
mSelectionStartCell = gpos;
|
|
mSelectionEndCell = gpos;
|
|
mHasSelection = true;
|
|
emit newStartSelectSignal();
|
|
emit newTimeSpanSignal( mSelectionStartCell, mSelectionEndCell );
|
|
updateContents();
|
|
}
|
|
showNewEventPopupSignal();
|
|
} else {
|
|
// if mouse pointer is in selection, don't change selection
|
|
TQPoint gpos = contentsToGrid( viewportToContents( viewportPos ) );
|
|
if ( !ptInSelection( gpos ) ) {
|
|
selectItem(0);
|
|
mActionItem = 0;
|
|
mResPair = tqMakePair( static_cast<ResourceCalendar *>( 0 ), TQString() );
|
|
setCursor(arrowCursor);
|
|
startSelectAction(viewportPos);
|
|
}
|
|
}
|
|
return TQScrollView::eventFilter( TQT_TQOBJECT(object), TQT_TQEVENT(me) ); // pass through for use by multiagenda
|
|
}
|
|
break;
|
|
|
|
case TQEvent::MouseButtonRelease:
|
|
if (mActionItem) {
|
|
endItemAction();
|
|
} else if ( mActionType == SELECT ) {
|
|
endSelectAction( viewportPos );
|
|
}
|
|
// This nasty gridToContents(contentsToGrid(..)) is needed to
|
|
// avoid an offset of a few pixels. Don't ask me why...
|
|
emit mousePosSignal( gridToContents(contentsToGrid(
|
|
viewportToContents( viewportPos ) ) ));
|
|
break;
|
|
|
|
case TQEvent::MouseMove: {
|
|
// This nasty gridToContents(contentsToGrid(..)) is needed to
|
|
// avoid an offset of a few pixels. Don't ask me why...
|
|
TQPoint indicatorPos = gridToContents(contentsToGrid(
|
|
viewportToContents( viewportPos )));
|
|
if (TQT_BASE_OBJECT(object) != TQT_BASE_OBJECT(viewport())) {
|
|
KOAgendaItem *moveItem = dynamic_cast<KOAgendaItem *>(object);
|
|
if (moveItem && !moveItem->incidence()->isReadOnly() ) {
|
|
if (!mActionItem)
|
|
setNoActionCursor(moveItem,viewportPos);
|
|
else {
|
|
performItemAction(viewportPos);
|
|
|
|
if ( mActionType == MOVE ) {
|
|
// show cursor at the current begin of the item
|
|
KOAgendaItem *firstItem = mActionItem->firstMultiItem();
|
|
if (!firstItem) firstItem = mActionItem;
|
|
indicatorPos = gridToContents( TQPoint( firstItem->cellXLeft(),
|
|
firstItem->cellYTop() ) );
|
|
|
|
} else if ( mActionType == RESIZEBOTTOM ) {
|
|
// RESIZETOP is handled correctly, only resizebottom works differently
|
|
indicatorPos = gridToContents( TQPoint( mActionItem->cellXLeft(),
|
|
mActionItem->cellYBottom()+1 ) );
|
|
}
|
|
|
|
} // If we have an action item
|
|
} // If move item && !read only
|
|
} else {
|
|
if ( mActionType == SELECT ) {
|
|
performSelectAction( viewportPos );
|
|
|
|
// show cursor at end of timespan
|
|
if ( ((mStartCell.y() < mEndCell.y()) && (mEndCell.x() >= mStartCell.x())) ||
|
|
(mEndCell.x() > mStartCell.x()) )
|
|
indicatorPos = gridToContents( TQPoint(mEndCell.x(), mEndCell.y()+1) );
|
|
else
|
|
indicatorPos = gridToContents( mEndCell );
|
|
}
|
|
}
|
|
emit mousePosSignal( indicatorPos );
|
|
break; }
|
|
|
|
case TQEvent::MouseButtonDblClick:
|
|
if (TQT_BASE_OBJECT(object) == TQT_BASE_OBJECT(viewport())) {
|
|
selectItem(0);
|
|
TQPair<ResourceCalendar *, TQString>p = mCalendarView->viewSubResourceCalendar();
|
|
emit newEventSignal( p.first, p.second );
|
|
} else {
|
|
KOAgendaItem *doubleClickedItem = dynamic_cast<KOAgendaItem *>( object );
|
|
if ( doubleClickedItem ) {
|
|
selectItem( doubleClickedItem );
|
|
emit editIncidenceSignal( doubleClickedItem->incidence(), doubleClickedItem->itemDate() );
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool KOAgenda::ptInSelection( TQPoint gpos ) const
|
|
{
|
|
if ( !mHasSelection ) {
|
|
return false;
|
|
} else if ( gpos.x()<mSelectionStartCell.x() || gpos.x()>mSelectionEndCell.x() ) {
|
|
return false;
|
|
} else if ( (gpos.x()==mSelectionStartCell.x()) && (gpos.y()<mSelectionStartCell.y()) ) {
|
|
return false;
|
|
} else if ( (gpos.x()==mSelectionEndCell.x()) && (gpos.y()>mSelectionEndCell.y()) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void KOAgenda::startSelectAction( const TQPoint &viewportPos )
|
|
{
|
|
emit newStartSelectSignal();
|
|
|
|
mActionType = SELECT;
|
|
mSelectionStartPoint = viewportPos;
|
|
mHasSelection = true;
|
|
|
|
TQPoint pos = viewportToContents( viewportPos );
|
|
TQPoint gpos = contentsToGrid( pos );
|
|
|
|
// Store new selection
|
|
mStartCell = gpos;
|
|
mEndCell = gpos;
|
|
mSelectionStartCell = gpos;
|
|
mSelectionEndCell = gpos;
|
|
|
|
updateContents();
|
|
}
|
|
|
|
void KOAgenda::performSelectAction(const TQPoint& viewportPos)
|
|
{
|
|
TQPoint pos = viewportToContents( viewportPos );
|
|
TQPoint gpos = contentsToGrid( pos );
|
|
|
|
TQPoint clipperPos = clipper()->
|
|
mapFromGlobal(viewport()->mapToGlobal(viewportPos));
|
|
|
|
// Scroll if cursor was moved to upper or lower end of agenda.
|
|
if (clipperPos.y() < mScrollBorderWidth) {
|
|
mScrollUpTimer.start(mScrollDelay);
|
|
} else if (visibleHeight() - clipperPos.y() <
|
|
mScrollBorderWidth) {
|
|
mScrollDownTimer.start(mScrollDelay);
|
|
} else {
|
|
mScrollUpTimer.stop();
|
|
mScrollDownTimer.stop();
|
|
}
|
|
|
|
if ( gpos != mEndCell ) {
|
|
mEndCell = gpos;
|
|
if ( mStartCell.x()>mEndCell.x() ||
|
|
( mStartCell.x()==mEndCell.x() && mStartCell.y()>mEndCell.y() ) ) {
|
|
// backward selection
|
|
mSelectionStartCell = mEndCell;
|
|
mSelectionEndCell = mStartCell;
|
|
} else {
|
|
mSelectionStartCell = mStartCell;
|
|
mSelectionEndCell = mEndCell;
|
|
}
|
|
|
|
updateContents();
|
|
}
|
|
}
|
|
|
|
void KOAgenda::endSelectAction( const TQPoint ¤tPos )
|
|
{
|
|
mScrollUpTimer.stop();
|
|
mScrollDownTimer.stop();
|
|
|
|
mActionType = NOP;
|
|
|
|
emit newTimeSpanSignal( mSelectionStartCell, mSelectionEndCell );
|
|
|
|
if ( KOPrefs::instance()->mSelectionStartsEditor ) {
|
|
if ( ( mSelectionStartPoint - currentPos ).manhattanLength() >
|
|
TQApplication::startDragDistance() ) {
|
|
emitNewEventForSelection();
|
|
}
|
|
}
|
|
}
|
|
|
|
KOAgenda::MouseActionType KOAgenda::isInResizeArea( bool horizontal,
|
|
const TQPoint &pos, KOAgendaItem*item )
|
|
{
|
|
if (!item) return NOP;
|
|
TQPoint gridpos = contentsToGrid( pos );
|
|
TQPoint contpos = gridToContents( gridpos +
|
|
TQPoint( (KOGlobals::self()->reverseLayout())?1:0, 0 ) );
|
|
|
|
//kdDebug(5850)<<"contpos="<<contpos<<", pos="<<pos<<", gpos="<<gpos<<endl;
|
|
//kdDebug(5850)<<"clXLeft="<<clXLeft<<", clXRight="<<clXRight<<endl;
|
|
|
|
if ( horizontal ) {
|
|
int clXLeft = item->cellXLeft();
|
|
int clXRight = item->cellXRight();
|
|
if ( KOGlobals::self()->reverseLayout() ) {
|
|
int tmp = clXLeft;
|
|
clXLeft = clXRight;
|
|
clXRight = tmp;
|
|
}
|
|
int gridDistanceX = int( pos.x() - contpos.x() );
|
|
if (gridDistanceX < mResizeBorderWidth && clXLeft == gridpos.x() ) {
|
|
if ( KOGlobals::self()->reverseLayout() ) return RESIZERIGHT;
|
|
else return RESIZELEFT;
|
|
} else if ((mGridSpacingX - gridDistanceX) < mResizeBorderWidth &&
|
|
clXRight == gridpos.x() ) {
|
|
if ( KOGlobals::self()->reverseLayout() ) return RESIZELEFT;
|
|
else return RESIZERIGHT;
|
|
} else {
|
|
return MOVE;
|
|
}
|
|
} else {
|
|
int gridDistanceY = int( pos.y() - contpos.y() );
|
|
if (gridDistanceY < mResizeBorderWidth &&
|
|
item->cellYTop() == gridpos.y() &&
|
|
!item->firstMultiItem() ) {
|
|
return RESIZETOP;
|
|
} else if ((mGridSpacingY - gridDistanceY) < mResizeBorderWidth &&
|
|
item->cellYBottom() == gridpos.y() &&
|
|
!item->lastMultiItem() ) {
|
|
return RESIZEBOTTOM;
|
|
} else {
|
|
return MOVE;
|
|
}
|
|
}
|
|
}
|
|
|
|
void KOAgenda::startItemAction(const TQPoint& viewportPos)
|
|
{
|
|
TQPoint pos = viewportToContents( viewportPos );
|
|
mStartCell = contentsToGrid( pos );
|
|
mEndCell = mStartCell;
|
|
|
|
bool noResize = ( mActionItem->incidence()->type() == "Todo");
|
|
|
|
mActionType = MOVE;
|
|
if ( !noResize ) {
|
|
mActionType = isInResizeArea( mAllDayMode, pos, mActionItem );
|
|
}
|
|
|
|
|
|
mActionItem->startMove();
|
|
setActionCursor( mActionType, true );
|
|
}
|
|
|
|
void KOAgenda::performItemAction(const TQPoint& viewportPos)
|
|
{
|
|
// kdDebug(5850) << "viewportPos: " << viewportPos.x() << "," << viewportPos.y() << endl;
|
|
// TQPoint point = viewport()->mapToGlobal(viewportPos);
|
|
// kdDebug(5850) << "Global: " << point.x() << "," << point.y() << endl;
|
|
// point = clipper()->mapFromGlobal(point);
|
|
// kdDebug(5850) << "clipper: " << point.x() << "," << point.y() << endl;
|
|
// kdDebug(5850) << "visible height: " << visibleHeight() << endl;
|
|
TQPoint pos = viewportToContents( viewportPos );
|
|
// kdDebug(5850) << "contents: " << x << "," << y << "\n" << endl;
|
|
TQPoint gpos = contentsToGrid( pos );
|
|
TQPoint clipperPos = clipper()->
|
|
mapFromGlobal(viewport()->mapToGlobal(viewportPos));
|
|
|
|
// Cursor left active agenda area.
|
|
// This starts a drag.
|
|
if ( clipperPos.y() < 0 || clipperPos.y() > visibleHeight() ||
|
|
clipperPos.x() < 0 || clipperPos.x() > visibleWidth() ) {
|
|
if ( mActionType == MOVE ) {
|
|
mScrollUpTimer.stop();
|
|
mScrollDownTimer.stop();
|
|
mActionItem->resetMove();
|
|
placeSubCells( mActionItem );
|
|
emit startDragSignal( mActionItem->incidence() );
|
|
setCursor( arrowCursor );
|
|
mActionItem = 0;
|
|
mResPair = tqMakePair( static_cast<ResourceCalendar *>( 0 ), TQString() );
|
|
mActionType = NOP;
|
|
mItemMoved = false;
|
|
return;
|
|
}
|
|
} else {
|
|
setActionCursor( mActionType );
|
|
}
|
|
|
|
// Scroll if item was moved to upper or lower end of agenda.
|
|
if (clipperPos.y() < mScrollBorderWidth) {
|
|
mScrollUpTimer.start(mScrollDelay);
|
|
} else if (visibleHeight() - clipperPos.y() <
|
|
mScrollBorderWidth) {
|
|
mScrollDownTimer.start(mScrollDelay);
|
|
} else {
|
|
mScrollUpTimer.stop();
|
|
mScrollDownTimer.stop();
|
|
}
|
|
|
|
// Move or resize item if necessary
|
|
if ( mEndCell != gpos ) {
|
|
if ( !mItemMoved ) {
|
|
if ( !mChanger ||
|
|
!mChanger->beginChange( mActionItem->incidence(), mResPair.first, mResPair.second ) ) {
|
|
KMessageBox::information( this, i18n("Unable to lock item for "
|
|
"modification. You cannot make any changes."),
|
|
i18n("Locking Failed"), "AgendaLockingFailed" );
|
|
mScrollUpTimer.stop();
|
|
mScrollDownTimer.stop();
|
|
mActionItem->resetMove();
|
|
placeSubCells( mActionItem );
|
|
setCursor( arrowCursor );
|
|
mActionItem = 0;
|
|
mResPair = tqMakePair( static_cast<ResourceCalendar *>( 0 ), TQString() );
|
|
mActionType = NOP;
|
|
mItemMoved = false;
|
|
return;
|
|
}
|
|
mItemMoved = true;
|
|
}
|
|
mActionItem->raise();
|
|
if (mActionType == MOVE) {
|
|
// Move all items belonging to a multi item
|
|
KOAgendaItem *firstItem = mActionItem->firstMultiItem();
|
|
if (!firstItem) firstItem = mActionItem;
|
|
KOAgendaItem *lastItem = mActionItem->lastMultiItem();
|
|
if (!lastItem) lastItem = mActionItem;
|
|
TQPoint deltapos = gpos - mEndCell;
|
|
KOAgendaItem *moveItem = firstItem;
|
|
while (moveItem) {
|
|
bool changed=false;
|
|
if ( deltapos.x()!=0 ) {
|
|
moveItem->moveRelative( deltapos.x(), 0 );
|
|
changed=true;
|
|
}
|
|
// in agenda's all day view don't try to move multi items, since there are none
|
|
if ( moveItem==firstItem && !mAllDayMode ) { // is the first item
|
|
int newY = deltapos.y() + moveItem->cellYTop();
|
|
// If event start moved earlier than 0:00, it starts the previous day
|
|
if ( newY<0 ) {
|
|
moveItem->expandTop( -moveItem->cellYTop() );
|
|
// prepend a new item at ( x-1, rows()+newY to rows() )
|
|
KOAgendaItem *newFirst = firstItem->prevMoveItem();
|
|
// cell's y values are first and last cell of the bar, so if newY=-1, they need to be the same
|
|
if (newFirst) {
|
|
newFirst->setCellXY(moveItem->cellXLeft()-1, rows()+newY, rows()-1);
|
|
mItems.append( newFirst );
|
|
moveItem->resize( int( mGridSpacingX * newFirst->cellWidth() ),
|
|
int( mGridSpacingY * newFirst->cellHeight() ));
|
|
TQPoint cpos = gridToContents( TQPoint( newFirst->cellXLeft(), newFirst->cellYTop() ) );
|
|
addChild( newFirst, cpos.x(), cpos.y() );
|
|
} else {
|
|
newFirst = insertItem( moveItem->incidence(), moveItem->itemDate(),
|
|
moveItem->cellXLeft()-1, rows()+newY, rows()-1, moveItem->itemPos(), moveItem->itemCount() ) ;
|
|
}
|
|
if (newFirst) newFirst->show();
|
|
moveItem->prependMoveItem(newFirst);
|
|
firstItem=newFirst;
|
|
} else if ( newY>=rows() ) {
|
|
// If event start is moved past 24:00, it starts the next day
|
|
// erase current item (i.e. remove it from the multiItem list)
|
|
firstItem = moveItem->nextMultiItem();
|
|
moveItem->hide();
|
|
mItems.take( mItems.find( moveItem ) );
|
|
removeChild( moveItem );
|
|
mActionItem->removeMoveItem(moveItem);
|
|
moveItem=firstItem;
|
|
// adjust next day's item
|
|
if (moveItem) moveItem->expandTop( rows()-newY );
|
|
} else {
|
|
moveItem->expandTop(deltapos.y());
|
|
}
|
|
changed=true;
|
|
}
|
|
if ( !moveItem->lastMultiItem() && !mAllDayMode ) { // is the last item
|
|
int newY = deltapos.y()+moveItem->cellYBottom();
|
|
if (newY<0) {
|
|
// erase current item
|
|
lastItem = moveItem->prevMultiItem();
|
|
moveItem->hide();
|
|
mItems.take( mItems.find(moveItem) );
|
|
removeChild( moveItem );
|
|
moveItem->removeMoveItem( moveItem );
|
|
moveItem = lastItem;
|
|
moveItem->expandBottom(newY+1);
|
|
} else if (newY>=rows()) {
|
|
moveItem->expandBottom( rows()-moveItem->cellYBottom()-1 );
|
|
// append item at ( x+1, 0 to newY-rows() )
|
|
KOAgendaItem *newLast = lastItem->nextMoveItem();
|
|
if (newLast) {
|
|
newLast->setCellXY( moveItem->cellXLeft()+1, 0, newY-rows()-1 );
|
|
mItems.append(newLast);
|
|
moveItem->resize( int( mGridSpacingX * newLast->cellWidth() ),
|
|
int( mGridSpacingY * newLast->cellHeight() ));
|
|
TQPoint cpos = gridToContents( TQPoint( newLast->cellXLeft(), newLast->cellYTop() ) ) ;
|
|
addChild( newLast, cpos.x(), cpos.y() );
|
|
} else {
|
|
newLast = insertItem( moveItem->incidence(), moveItem->itemDate(),
|
|
moveItem->cellXLeft()+1, 0, newY-rows()-1, moveItem->itemPos(), moveItem->itemCount() ) ;
|
|
}
|
|
moveItem->appendMoveItem( newLast );
|
|
newLast->show();
|
|
lastItem = newLast;
|
|
} else {
|
|
moveItem->expandBottom( deltapos.y() );
|
|
}
|
|
changed=true;
|
|
}
|
|
if (changed) {
|
|
adjustItemPosition( moveItem );
|
|
}
|
|
moveItem = moveItem->nextMultiItem();
|
|
}
|
|
} else if (mActionType == RESIZETOP) {
|
|
if (mEndCell.y() <= mActionItem->cellYBottom()) {
|
|
mActionItem->expandTop(gpos.y() - mEndCell.y());
|
|
adjustItemPosition( mActionItem );
|
|
}
|
|
} else if (mActionType == RESIZEBOTTOM) {
|
|
if (mEndCell.y() >= mActionItem->cellYTop()) {
|
|
mActionItem->expandBottom(gpos.y() - mEndCell.y());
|
|
adjustItemPosition( mActionItem );
|
|
}
|
|
} else if (mActionType == RESIZELEFT) {
|
|
if (mEndCell.x() <= mActionItem->cellXRight()) {
|
|
mActionItem->expandLeft( gpos.x() - mEndCell.x() );
|
|
adjustItemPosition( mActionItem );
|
|
}
|
|
} else if (mActionType == RESIZERIGHT) {
|
|
if (mEndCell.x() >= mActionItem->cellXLeft()) {
|
|
mActionItem->expandRight(gpos.x() - mEndCell.x());
|
|
adjustItemPosition( mActionItem );
|
|
}
|
|
}
|
|
mEndCell = gpos;
|
|
}
|
|
}
|
|
|
|
void KOAgenda::endItemAction()
|
|
{
|
|
// kdDebug(5850) << "KOAgenda::endItemAction() " << endl;
|
|
mActionType = NOP;
|
|
mScrollUpTimer.stop();
|
|
mScrollDownTimer.stop();
|
|
setCursor( arrowCursor );
|
|
bool multiModify = false;
|
|
// FIXME: do the cloning here...
|
|
Incidence* inc = mActionItem->incidence();
|
|
|
|
if ( mStartCell.x() == mEndCell.x() && mStartCell.y() == mEndCell.y() ) {
|
|
// not really moved, so stop any change
|
|
if ( mItemMoved ) {
|
|
mItemMoved = false;
|
|
mChanger->endChange( inc, mResPair.first, mResPair.second );
|
|
}
|
|
}
|
|
|
|
if ( mItemMoved ) {
|
|
Incidence *incToChange = inc;
|
|
if ( mActionItem->incidence()->doesRecur() ) {
|
|
Incidence* oldIncSaved = inc->clone();
|
|
KOGlobals::WhichOccurrences chosenOption;
|
|
incToChange = mCalendarView->singleOccurrenceOrAll( inc,
|
|
KOGlobals::EDIT,
|
|
chosenOption,
|
|
mActionItem->itemDate() );
|
|
|
|
if ( chosenOption == KOGlobals::ONLY_THIS_ONE ||
|
|
chosenOption == KOGlobals::ONLY_FUTURE ) {
|
|
|
|
// FIXME Prompt for this...it is quite possible that the user does not want to broadcast the change
|
|
// That prompting dialog will require the ability to suppress/override the mChanger->endChange GroupWare communication though.
|
|
int autoAnswerGroupWare = 1; // Send all possible GroupWare messages without prompting
|
|
|
|
// Store modification information in case it is needed to recreate the changes with a new actionitem...
|
|
int mai_xl = mActionItem->cellXLeft();
|
|
int mai_xr = mActionItem->cellXRight();
|
|
int mai_yt = mActionItem->cellYTop();
|
|
int mai_yb = mActionItem->cellYBottom();
|
|
|
|
multiModify = true;
|
|
emit startMultiModify( i18n("Dissociate event from recurrence") );
|
|
enableAgendaUpdate( false );
|
|
|
|
mChanger->addIncidence( incToChange, mResPair.first, mResPair.second, this, autoAnswerGroupWare );
|
|
enableAgendaUpdate( true );
|
|
KOGlobals::WhatChanged wc = chosenOption == KOGlobals::ONLY_THIS_ONE ?
|
|
KOGlobals::RECURRENCE_MODIFIED_ONE_ONLY :
|
|
KOGlobals::RECURRENCE_MODIFIED_ALL_FUTURE;
|
|
|
|
mChanger->changeIncidence( oldIncSaved, inc, wc, this, autoAnswerGroupWare );
|
|
|
|
// mActionItem does not exist any more, seeing as we just got done deleting it
|
|
// (by deleting/replacing the original incidence it was created from through
|
|
// user modification of said incidence) above!
|
|
// Therefore we have to find the new KOAgendaItem that matches the new incidence
|
|
// Then we can apply the saved X/Y settings from the original move operation as shown.
|
|
|
|
KOAgendaItem *koai_insertedItem;
|
|
for ( koai_insertedItem = mItems.first(); koai_insertedItem; koai_insertedItem = mItems.next() ) {
|
|
if (koai_insertedItem->incidence() == incToChange) {
|
|
selectItem( koai_insertedItem );
|
|
mSelectedItem->startMove();
|
|
mSelectedItem->setCellY(mai_yt, mai_yb);
|
|
mSelectedItem->setCellX(mai_xl, mai_xr);
|
|
mActionItem = mSelectedItem;
|
|
//mSelectedItem->endMove();
|
|
break;
|
|
}
|
|
}
|
|
|
|
mActionItem->dissociateFromMultiItem();
|
|
mActionItem->setIncidence( incToChange );
|
|
}
|
|
}
|
|
|
|
if ( incToChange ) {
|
|
mActionItem->endMove();
|
|
KOAgendaItem *placeItem = mActionItem->firstMultiItem();
|
|
if ( !placeItem ) {
|
|
placeItem = mActionItem;
|
|
}
|
|
|
|
KOAgendaItem *modif = placeItem;
|
|
|
|
TQPtrList<KOAgendaItem> oldconflictItems = placeItem->conflictItems();
|
|
KOAgendaItem *item;
|
|
for ( item = oldconflictItems.first(); item != 0;
|
|
item = oldconflictItems.next() ) {
|
|
placeSubCells( item );
|
|
}
|
|
while ( placeItem ) {
|
|
placeSubCells( placeItem );
|
|
placeItem = placeItem->nextMultiItem();
|
|
}
|
|
|
|
// Notify about change
|
|
// the agenda view will apply the changes to the actual Incidence*!
|
|
mChanger->endChange( inc, mResPair.first, mResPair.second );
|
|
emit itemModified( modif );
|
|
} else {
|
|
|
|
mActionItem->resetMove();
|
|
placeSubCells( mActionItem );
|
|
|
|
// the item was moved, but not further modified, since it's not recurring
|
|
// make sure the view updates anyhow, with the right item
|
|
mChanger->endChange( inc, mResPair.first, mResPair.second );
|
|
emit itemModified( mActionItem );
|
|
}
|
|
}
|
|
|
|
mActionItem = 0;
|
|
mResPair = tqMakePair( static_cast<ResourceCalendar *>( 0 ), TQString() );
|
|
mItemMoved = false;
|
|
|
|
if ( multiModify ) {
|
|
emit endMultiModify();
|
|
}
|
|
|
|
kdDebug(5850) << "KOAgenda::endItemAction() done" << endl;
|
|
}
|
|
|
|
void KOAgenda::setActionCursor( int actionType, bool acting )
|
|
{
|
|
switch ( actionType ) {
|
|
case MOVE:
|
|
if (acting) setCursor( sizeAllCursor );
|
|
else setCursor( arrowCursor );
|
|
break;
|
|
case RESIZETOP:
|
|
case RESIZEBOTTOM:
|
|
setCursor( sizeVerCursor );
|
|
break;
|
|
case RESIZELEFT:
|
|
case RESIZERIGHT:
|
|
setCursor( sizeHorCursor );
|
|
break;
|
|
default:
|
|
setCursor( arrowCursor );
|
|
}
|
|
}
|
|
|
|
void KOAgenda::setNoActionCursor( KOAgendaItem *moveItem, const TQPoint& viewportPos )
|
|
{
|
|
// kdDebug(5850) << "viewportPos: " << viewportPos.x() << "," << viewportPos.y() << endl;
|
|
// TQPoint point = viewport()->mapToGlobal(viewportPos);
|
|
// kdDebug(5850) << "Global: " << point.x() << "," << point.y() << endl;
|
|
// point = clipper()->mapFromGlobal(point);
|
|
// kdDebug(5850) << "clipper: " << point.x() << "," << point.y() << endl;
|
|
|
|
TQPoint pos = viewportToContents( viewportPos );
|
|
bool noResize = (moveItem && moveItem->incidence() &&
|
|
moveItem->incidence()->type() == "Todo");
|
|
|
|
KOAgenda::MouseActionType resizeType = MOVE;
|
|
if ( !noResize ) resizeType = isInResizeArea( mAllDayMode, pos , moveItem);
|
|
setActionCursor( resizeType );
|
|
}
|
|
|
|
|
|
/** calculate the width of the column subcells of the given item
|
|
*/
|
|
double KOAgenda::calcSubCellWidth( KOAgendaItem *item )
|
|
{
|
|
TQPoint pt, pt1;
|
|
pt = gridToContents( TQPoint( item->cellXLeft(), item->cellYTop() ) );
|
|
pt1 = gridToContents( TQPoint( item->cellXLeft(), item->cellYTop() ) +
|
|
TQPoint( 1, 1 ) );
|
|
pt1 -= pt;
|
|
int maxSubCells = item->subCells();
|
|
double newSubCellWidth;
|
|
if ( mAllDayMode ) {
|
|
newSubCellWidth = double( pt1.y() ) / maxSubCells;
|
|
} else {
|
|
newSubCellWidth = double( pt1.x() ) / maxSubCells;
|
|
}
|
|
return newSubCellWidth;
|
|
}
|
|
|
|
void KOAgenda::adjustItemPosition( KOAgendaItem *item )
|
|
{
|
|
if (!item) return;
|
|
item->resize( int( mGridSpacingX * item->cellWidth() ),
|
|
int( mGridSpacingY * item->cellHeight() ) );
|
|
int clXLeft = item->cellXLeft();
|
|
if ( KOGlobals::self()->reverseLayout() )
|
|
clXLeft = item->cellXRight() + 1;
|
|
TQPoint cpos = gridToContents( TQPoint( clXLeft, item->cellYTop() ) );
|
|
moveChild( item, cpos.x(), cpos.y() );
|
|
}
|
|
|
|
void KOAgenda::placeAgendaItem( KOAgendaItem *item, double subCellWidth )
|
|
{
|
|
// kdDebug(5850) << "KOAgenda::placeAgendaItem(): " << item->incidence()->summary()
|
|
// << " subCellWidth: " << subCellWidth << endl;
|
|
|
|
// "left" upper corner, no subcells yet, RTL layouts have right/left switched, widths are negative then
|
|
TQPoint pt = gridToContents( TQPoint( item->cellXLeft(), item->cellYTop() ) );
|
|
// right lower corner
|
|
TQPoint pt1 = gridToContents( TQPoint( item->cellXLeft() + item->cellWidth(),
|
|
item->cellYBottom()+1 ) );
|
|
|
|
double subCellPos = item->subCell() * subCellWidth;
|
|
|
|
// we need to add 0.01 to make sure we don't loose one pixed due to
|
|
// numerics (i.e. if it would be x.9998, we want the integer, not rounded down.
|
|
double delta=0.01;
|
|
if (subCellWidth<0) delta=-delta;
|
|
int height, width, xpos, ypos;
|
|
if (mAllDayMode) {
|
|
width = pt1.x()-pt.x();
|
|
height = int( subCellPos + subCellWidth + delta ) - int( subCellPos );
|
|
xpos = pt.x();
|
|
ypos = pt.y() + int( subCellPos );
|
|
} else {
|
|
width = int( subCellPos + subCellWidth + delta ) - int( subCellPos );
|
|
height = pt1.y()-pt.y();
|
|
xpos = pt.x() + int( subCellPos );
|
|
ypos = pt.y();
|
|
}
|
|
if ( KOGlobals::self()->reverseLayout() ) { // RTL language/tqlayout
|
|
xpos += width;
|
|
width = -width;
|
|
}
|
|
if ( height<0 ) { // BTT (bottom-to-top) tqlayout ?!?
|
|
ypos += height;
|
|
height = -height;
|
|
}
|
|
item->resize( width, height );
|
|
moveChild( item, xpos, ypos );
|
|
}
|
|
|
|
/*
|
|
Place item in cell and take care that multiple items using the same cell do
|
|
not overlap. This method is not yet optimal. It doesn't use the maximum space
|
|
it can get in all cases.
|
|
At the moment the method has a bug: When an item is placed only the sub cell
|
|
widths of the items are changed, which are within the Y region the item to
|
|
place spans. When the sub cell width change of one of this items affects a
|
|
cell, where other items are, which do not overlap in Y with the item to place,
|
|
the display gets corrupted, although the corruption looks quite nice.
|
|
*/
|
|
void KOAgenda::placeSubCells( KOAgendaItem *placeItem )
|
|
{
|
|
#if 0
|
|
kdDebug(5850) << "KOAgenda::placeSubCells()" << endl;
|
|
if ( placeItem ) {
|
|
Incidence *event = placeItem->incidence();
|
|
if ( !event ) {
|
|
kdDebug(5850) << " event is 0" << endl;
|
|
} else {
|
|
kdDebug(5850) << " event: " << event->summary() << endl;
|
|
}
|
|
} else {
|
|
kdDebug(5850) << " placeItem is 0" << endl;
|
|
}
|
|
kdDebug(5850) << "KOAgenda::placeSubCells()..." << endl;
|
|
#endif
|
|
|
|
TQPtrList<KOrg::CellItem> cells;
|
|
KOAgendaItem *item;
|
|
for ( item = mItems.first(); item != 0; item = mItems.next() ) {
|
|
cells.append( item );
|
|
}
|
|
|
|
TQPtrList<KOrg::CellItem> items = KOrg::CellItem::placeItem( cells,
|
|
placeItem );
|
|
|
|
placeItem->setConflictItems( TQPtrList<KOAgendaItem>() );
|
|
double newSubCellWidth = calcSubCellWidth( placeItem );
|
|
KOrg::CellItem *i;
|
|
for ( i = items.first(); i; i = items.next() ) {
|
|
item = static_cast<KOAgendaItem *>( i );
|
|
placeAgendaItem( item, newSubCellWidth );
|
|
item->addConflictItem( placeItem );
|
|
placeItem->addConflictItem( item );
|
|
}
|
|
if ( items.isEmpty() ) {
|
|
placeAgendaItem( placeItem, newSubCellWidth );
|
|
}
|
|
placeItem->update();
|
|
}
|
|
|
|
int KOAgenda::columnWidth( int column )
|
|
{
|
|
int start = gridToContents( TQPoint( column, 0 ) ).x();
|
|
if (KOGlobals::self()->reverseLayout() )
|
|
column--;
|
|
else
|
|
column++;
|
|
int end = gridToContents( TQPoint( column, 0 ) ).x();
|
|
return end - start;
|
|
}
|
|
/*
|
|
Draw grid in the background of the agenda.
|
|
*/
|
|
void KOAgenda::drawContents(TQPainter* p, int cx, int cy, int cw, int ch)
|
|
{
|
|
TQPixmap db(cw, ch);
|
|
db.fill(KOPrefs::instance()->mAgendaBgColor);
|
|
TQPainter dbp(&db);
|
|
dbp.translate(-cx,-cy);
|
|
|
|
// kdDebug(5850) << "KOAgenda::drawContents()" << endl;
|
|
double lGridSpacingY = mGridSpacingY*2;
|
|
|
|
// Highlight working hours
|
|
if (mWorkingHoursEnable) {
|
|
TQPoint pt1( cx, mWorkingHoursYTop );
|
|
TQPoint pt2( cx+cw, mWorkingHoursYBottom );
|
|
if ( pt2.x() >= pt1.x() /*&& pt2.y() >= pt1.y()*/) {
|
|
int gxStart = contentsToGrid( pt1 ).x();
|
|
int gxEnd = contentsToGrid( pt2 ).x();
|
|
// correct start/end for rtl layouts
|
|
if ( gxStart > gxEnd ) {
|
|
int tmp = gxStart;
|
|
gxStart = gxEnd;
|
|
gxEnd = tmp;
|
|
}
|
|
int xoffset = ( KOGlobals::self()->reverseLayout()?1:0 );
|
|
while( gxStart <= gxEnd ) {
|
|
int xStart = gridToContents( TQPoint( gxStart+xoffset, 0 ) ).x();
|
|
int xWidth = columnWidth( gxStart ) + 1;
|
|
if ( pt2.y() < pt1.y() ) {
|
|
// overnight working hours
|
|
if ( ( (gxStart==0) && !mHolidayMask->at(mHolidayMask->count()-1) ) ||
|
|
( (gxStart>0) && (gxStart<int(mHolidayMask->count())) && (!mHolidayMask->at(gxStart-1) ) ) ) {
|
|
if ( pt2.y() > cy ) {
|
|
dbp.fillRect( xStart, cy, xWidth, pt2.y() - cy + 1,
|
|
KOPrefs::instance()->mWorkingHoursColor);
|
|
}
|
|
}
|
|
if ( (gxStart < int(mHolidayMask->count()-1)) && (!mHolidayMask->at(gxStart)) ) {
|
|
if ( pt1.y() < cy + ch - 1 ) {
|
|
dbp.fillRect( xStart, pt1.y(), xWidth, cy + ch - pt1.y() + 1,
|
|
KOPrefs::instance()->mWorkingHoursColor);
|
|
}
|
|
}
|
|
} else {
|
|
// last entry in holiday mask denotes the previous day not visible (needed for overnight shifts)
|
|
if ( gxStart < int(mHolidayMask->count()-1) && !mHolidayMask->at(gxStart)) {
|
|
dbp.fillRect( xStart, pt1.y(), xWidth, pt2.y() - pt1.y() + 1,
|
|
KOPrefs::instance()->mWorkingHoursColor );
|
|
}
|
|
}
|
|
++gxStart;
|
|
}
|
|
}
|
|
}
|
|
|
|
// draw selection
|
|
if ( mHasSelection ) {
|
|
TQPoint pt, pt1;
|
|
|
|
if ( mSelectionEndCell.x() > mSelectionStartCell.x() ) { // multi day selection
|
|
// draw start day
|
|
pt = gridToContents( mSelectionStartCell );
|
|
pt1 = gridToContents( TQPoint( mSelectionStartCell.x() + 1, mRows + 1 ) );
|
|
dbp.fillRect( TQRect( pt, pt1 ), KOPrefs::instance()->mHighlightColor );
|
|
// draw all other days between the start day and the day of the selection end
|
|
for ( int c = mSelectionStartCell.x() + 1; c < mSelectionEndCell.x(); ++c ) {
|
|
pt = gridToContents( TQPoint( c, 0 ) );
|
|
pt1 = gridToContents( TQPoint( c + 1, mRows + 1 ) );
|
|
dbp.fillRect( TQRect( pt, pt1 ), KOPrefs::instance()->mHighlightColor );
|
|
}
|
|
// draw end day
|
|
pt = gridToContents( TQPoint( mSelectionEndCell.x(), 0 ) );
|
|
pt1 = gridToContents( mSelectionEndCell + TQPoint(1,1) );
|
|
dbp.fillRect( TQRect( pt, pt1), KOPrefs::instance()->mHighlightColor );
|
|
} else { // single day selection
|
|
pt = gridToContents( mSelectionStartCell );
|
|
pt1 = gridToContents( mSelectionEndCell + TQPoint(1,1) );
|
|
dbp.fillRect( TQRect( pt, pt1 ), KOPrefs::instance()->mHighlightColor );
|
|
}
|
|
}
|
|
|
|
TQPen hourPen( KOPrefs::instance()->mAgendaBgColor.dark( 150 ) );
|
|
TQPen halfHourPen( KOPrefs::instance()->mAgendaBgColor.dark( 125 ) );
|
|
dbp.setPen( hourPen );
|
|
|
|
// Draw vertical lines of grid, start with the last line not yet visible
|
|
// kdDebug(5850) << "drawContents cx: " << cx << " cy: " << cy << " cw: " << cw << " ch: " << ch << endl;
|
|
double x = ( int( cx / mGridSpacingX ) ) * mGridSpacingX;
|
|
while (x < cx + cw) {
|
|
dbp.drawLine( int( x ), cy, int( x ), cy + ch );
|
|
x+=mGridSpacingX;
|
|
}
|
|
|
|
// Draw horizontal lines of grid
|
|
double y = ( int( cy / (2*lGridSpacingY) ) ) * 2 * lGridSpacingY;
|
|
while (y < cy + ch) {
|
|
// kdDebug(5850) << " y: " << y << endl;
|
|
dbp.drawLine( cx, int( y ), cx + cw, int( y ) );
|
|
y += 2 * lGridSpacingY;
|
|
}
|
|
y = ( 2 * int( cy / (2*lGridSpacingY) ) + 1) * lGridSpacingY;
|
|
dbp.setPen( halfHourPen );
|
|
while (y < cy + ch) {
|
|
// kdDebug(5850) << " y: " << y << endl;
|
|
dbp.drawLine( cx, int( y ), cx + cw, int( y ) );
|
|
y+=2*lGridSpacingY;
|
|
}
|
|
p->drawPixmap(cx,cy, db);
|
|
}
|
|
|
|
/*
|
|
Convert srcollview contents coordinates to agenda grid coordinates.
|
|
*/
|
|
TQPoint KOAgenda::contentsToGrid ( const TQPoint &pos ) const
|
|
{
|
|
int gx = int( KOGlobals::self()->reverseLayout() ?
|
|
mColumns - pos.x()/mGridSpacingX : pos.x()/mGridSpacingX );
|
|
int gy = int( pos.y()/mGridSpacingY );
|
|
return TQPoint( gx, gy );
|
|
}
|
|
|
|
/*
|
|
Convert agenda grid coordinates to scrollview contents coordinates.
|
|
*/
|
|
TQPoint KOAgenda::gridToContents( const TQPoint &gpos ) const
|
|
{
|
|
int x = int( KOGlobals::self()->reverseLayout() ?
|
|
(mColumns - gpos.x())*mGridSpacingX : gpos.x()*mGridSpacingX );
|
|
int y = int( gpos.y()*mGridSpacingY );
|
|
return TQPoint( x, y );
|
|
}
|
|
|
|
|
|
/*
|
|
Return Y coordinate corresponding to time. Coordinates are rounded to fit into
|
|
the grid.
|
|
*/
|
|
int KOAgenda::timeToY(const TQTime &time)
|
|
{
|
|
// kdDebug(5850) << "Time: " << time.toString() << endl;
|
|
int minutesPerCell = 24 * 60 / mRows;
|
|
// kdDebug(5850) << "minutesPerCell: " << minutesPerCell << endl;
|
|
int timeMinutes = time.hour() * 60 + time.minute();
|
|
// kdDebug(5850) << "timeMinutes: " << timeMinutes << endl;
|
|
int Y = (timeMinutes + (minutesPerCell / 2)) / minutesPerCell;
|
|
// kdDebug(5850) << "y: " << Y << endl;
|
|
// kdDebug(5850) << "\n" << endl;
|
|
return Y;
|
|
}
|
|
|
|
|
|
/*
|
|
Return time corresponding to cell y coordinate. Coordinates are rounded to
|
|
fit into the grid.
|
|
*/
|
|
TQTime KOAgenda::gyToTime(int gy)
|
|
{
|
|
// kdDebug(5850) << "gyToTime: " << gy << endl;
|
|
int secondsPerCell = 24 * 60 * 60/ mRows;
|
|
|
|
int timeSeconds = secondsPerCell * gy;
|
|
|
|
TQTime time( 0, 0, 0 );
|
|
if ( timeSeconds < 24 * 60 * 60 ) {
|
|
time = time.addSecs(timeSeconds);
|
|
} else {
|
|
time.setHMS( 23, 59, 59 );
|
|
}
|
|
// kdDebug(5850) << " gyToTime: " << time.toString() << endl;
|
|
|
|
return time;
|
|
}
|
|
|
|
TQMemArray<int> KOAgenda::minContentsY()
|
|
{
|
|
TQMemArray<int> minArray;
|
|
minArray.fill( timeToY( TQTime(23, 59) ), mSelectedDates.count() );
|
|
for ( KOAgendaItem *item = mItems.first();
|
|
item != 0; item = mItems.next() ) {
|
|
int ymin = item->cellYTop();
|
|
int index = item->cellXLeft();
|
|
if ( index>=0 && index<(int)(mSelectedDates.count()) ) {
|
|
if ( ymin < minArray[index] && mItemsToDelete.findRef( item ) == -1 )
|
|
minArray[index] = ymin;
|
|
}
|
|
}
|
|
|
|
return minArray;
|
|
}
|
|
|
|
TQMemArray<int> KOAgenda::maxContentsY()
|
|
{
|
|
TQMemArray<int> maxArray;
|
|
maxArray.fill( timeToY( TQTime(0, 0) ), mSelectedDates.count() );
|
|
for ( KOAgendaItem *item = mItems.first();
|
|
item != 0; item = mItems.next() ) {
|
|
int ymax = item->cellYBottom();
|
|
int index = item->cellXLeft();
|
|
if ( index>=0 && index<(int)(mSelectedDates.count()) ) {
|
|
if ( ymax > maxArray[index] && mItemsToDelete.findRef( item ) == -1 )
|
|
maxArray[index] = ymax;
|
|
}
|
|
}
|
|
|
|
return maxArray;
|
|
}
|
|
|
|
void KOAgenda::setStartTime( const TQTime &startHour )
|
|
{
|
|
double startPos = ( startHour.hour()/24. + startHour.minute()/1440. +
|
|
startHour.second()/86400. ) * mRows * gridSpacingY();
|
|
setContentsPos( 0, int( startPos ) );
|
|
}
|
|
|
|
|
|
/*
|
|
Insert KOAgendaItem into agenda.
|
|
*/
|
|
KOAgendaItem *KOAgenda::insertItem( Incidence *incidence, const TQDate &qd, int X,
|
|
int YTop, int YBottom, int itemPos, int itemCount )
|
|
{
|
|
if ( mAllDayMode ) {
|
|
kdDebug(5850) << "KOAgenda: calling insertItem in all-day mode is illegal." << endl;
|
|
return 0;
|
|
}
|
|
|
|
mActionType = NOP;
|
|
|
|
KOAgendaItem *agendaItem = new KOAgendaItem( mCalendar, incidence, qd, viewport(), itemPos, itemCount );
|
|
connect( agendaItem, TQT_SIGNAL( removeAgendaItem( KOAgendaItem * ) ),
|
|
TQT_SLOT( removeAgendaItem( KOAgendaItem * ) ) );
|
|
connect( agendaItem, TQT_SIGNAL( showAgendaItem( KOAgendaItem * ) ),
|
|
TQT_SLOT( showAgendaItem( KOAgendaItem * ) ) );
|
|
|
|
if ( YBottom <= YTop ) {
|
|
kdDebug(5850) << "KOAgenda::insertItem(): Text: " << agendaItem->text() << " YSize<0" << endl;
|
|
YBottom = YTop;
|
|
}
|
|
|
|
agendaItem->resize( int( ( X + 1 ) * mGridSpacingX ) -
|
|
int( X * mGridSpacingX ),
|
|
int( YTop * mGridSpacingY ) -
|
|
int( ( YBottom + 1 ) * mGridSpacingY ) );
|
|
agendaItem->setCellXY( X, YTop, YBottom );
|
|
agendaItem->setCellXRight( X );
|
|
agendaItem->setResourceColor( KOHelper::resourceColor( mCalendar, incidence ) );
|
|
agendaItem->installEventFilter( this );
|
|
|
|
addChild( agendaItem, int( X * mGridSpacingX ), int( YTop * mGridSpacingY ) );
|
|
mItems.append( agendaItem );
|
|
|
|
placeSubCells( agendaItem );
|
|
|
|
agendaItem->show();
|
|
|
|
marcus_bains();
|
|
|
|
return agendaItem;
|
|
}
|
|
|
|
/*
|
|
Insert all-day KOAgendaItem into agenda.
|
|
*/
|
|
KOAgendaItem *KOAgenda::insertAllDayItem( Incidence *event, const TQDate &qd,
|
|
int XBegin, int XEnd )
|
|
{
|
|
if ( !mAllDayMode ) {
|
|
kdDebug(5850) << "KOAgenda: calling insertAllDayItem in non all-day mode is illegal." << endl;
|
|
return 0;
|
|
}
|
|
|
|
mActionType = NOP;
|
|
|
|
KOAgendaItem *agendaItem = new KOAgendaItem( mCalendar, event, qd, viewport(), 1, 1 );
|
|
connect( agendaItem, TQT_SIGNAL( removeAgendaItem( KOAgendaItem* ) ),
|
|
TQT_SLOT( removeAgendaItem( KOAgendaItem* ) ) );
|
|
connect( agendaItem, TQT_SIGNAL( showAgendaItem( KOAgendaItem* ) ),
|
|
TQT_SLOT( showAgendaItem( KOAgendaItem* ) ) );
|
|
|
|
agendaItem->setCellXY( XBegin, 0, 0 );
|
|
agendaItem->setCellXRight( XEnd );
|
|
|
|
double startIt = mGridSpacingX * ( agendaItem->cellXLeft() );
|
|
double endIt = mGridSpacingX * ( agendaItem->cellWidth() +
|
|
agendaItem->cellXLeft() );
|
|
|
|
agendaItem->resize( int( endIt ) - int( startIt ), int( mGridSpacingY ) );
|
|
|
|
agendaItem->installEventFilter( this );
|
|
agendaItem->setResourceColor( KOHelper::resourceColor( mCalendar, event ) );
|
|
addChild( agendaItem, int( XBegin * mGridSpacingX ), 0 );
|
|
mItems.append( agendaItem );
|
|
|
|
placeSubCells( agendaItem );
|
|
|
|
agendaItem->show();
|
|
|
|
return agendaItem;
|
|
}
|
|
|
|
|
|
void KOAgenda::insertMultiItem( Event *event, const TQDate &qd, int XBegin, int XEnd,
|
|
int YTop, int YBottom )
|
|
{
|
|
if ( mAllDayMode ) {
|
|
kdDebug(5850) << "KOAgenda: calling insertMultiItem in all-day mode is illegal." << endl;
|
|
return;
|
|
}
|
|
mActionType = NOP;
|
|
|
|
int cellX,cellYTop,cellYBottom;
|
|
TQString newtext;
|
|
int width = XEnd - XBegin + 1;
|
|
int count = 0;
|
|
KOAgendaItem *current = 0;
|
|
TQPtrList<KOAgendaItem> multiItems;
|
|
const int visibleCount = mSelectedDates.first().daysTo( mSelectedDates.last() );
|
|
for ( cellX = XBegin; cellX <= XEnd; ++cellX ) {
|
|
++count;
|
|
//Only add the items that are visible.
|
|
if( cellX >= 0 && cellX <= visibleCount ) {
|
|
if ( cellX == XBegin ) {
|
|
cellYTop = YTop;
|
|
} else {
|
|
cellYTop = 0;
|
|
}
|
|
|
|
if ( cellX == XEnd ) {
|
|
cellYBottom = YBottom;
|
|
} else {
|
|
cellYBottom = rows() - 1;
|
|
}
|
|
|
|
newtext = TQString("(%1/%2): ").tqarg( count ).tqarg( width );
|
|
newtext.append( event->summary() );
|
|
|
|
current = insertItem( event, qd, cellX, cellYTop, cellYBottom, count, width );
|
|
current->setText( newtext );
|
|
multiItems.append( current );
|
|
}
|
|
}
|
|
TQPtrList<KOAgendaItem>::iterator it = multiItems.begin();
|
|
TQPtrList<KOAgendaItem>::iterator e = multiItems.end();
|
|
|
|
if ( it != e ) { // .first asserts if the list is empty
|
|
KOAgendaItem *first = multiItems.first();
|
|
KOAgendaItem *last = multiItems.last();
|
|
KOAgendaItem *prev = 0, *next = 0;
|
|
|
|
while ( it != e ) {
|
|
KOAgendaItem *item = *it;
|
|
++it;
|
|
next = ( it == e ) ? 0 : (*it);
|
|
if ( item ) {
|
|
item->setMultiItem( ( item == first ) ? 0 : first,
|
|
prev, next,
|
|
( item == last ) ? 0 : last );
|
|
}
|
|
prev = item;
|
|
}
|
|
}
|
|
|
|
marcus_bains();
|
|
}
|
|
|
|
void KOAgenda::removeIncidence( Incidence *incidence )
|
|
{
|
|
// First find all items to be deleted and store them
|
|
// in its own list. Otherwise removeAgendaItem will reset
|
|
// the current position and mess this up.
|
|
TQPtrList<KOAgendaItem> itemsToRemove;
|
|
|
|
KOAgendaItem *item = mItems.first();
|
|
while ( item ) {
|
|
if ( item->incidence() == incidence ) {
|
|
itemsToRemove.append( item );
|
|
}
|
|
item = mItems.next();
|
|
}
|
|
item = itemsToRemove.first();
|
|
while ( item ) {
|
|
removeAgendaItem( item );
|
|
item = itemsToRemove.next();
|
|
}
|
|
}
|
|
|
|
void KOAgenda::showAgendaItem( KOAgendaItem *agendaItem )
|
|
{
|
|
if ( !agendaItem ) {
|
|
return;
|
|
}
|
|
|
|
agendaItem->hide();
|
|
addChild( agendaItem );
|
|
if ( !mItems.containsRef( agendaItem ) ) {
|
|
mItems.append( agendaItem );
|
|
}
|
|
placeSubCells( agendaItem );
|
|
|
|
agendaItem->show();
|
|
}
|
|
|
|
bool KOAgenda::removeAgendaItem( KOAgendaItem *item )
|
|
{
|
|
// we found the item. Let's remove it and update the conflicts
|
|
bool taken = false;
|
|
KOAgendaItem *thisItem = item;
|
|
TQPtrList<KOAgendaItem> conflictItems = thisItem->conflictItems();
|
|
removeChild( thisItem );
|
|
|
|
int pos = mItems.find( thisItem );
|
|
if ( pos >= 0 ) {
|
|
mItems.take( pos );
|
|
taken = true;
|
|
}
|
|
|
|
KOAgendaItem *confitem;
|
|
for ( confitem = conflictItems.first(); confitem != 0;
|
|
confitem = conflictItems.next() ) {
|
|
// the item itself is also in its own conflictItems list!
|
|
if ( confitem != thisItem ) placeSubCells(confitem);
|
|
|
|
}
|
|
mItemsToDelete.append( thisItem );
|
|
TQTimer::singleShot( 0, this, TQT_SLOT( deleteItemsToDelete() ) );
|
|
return taken;
|
|
}
|
|
|
|
void KOAgenda::deleteItemsToDelete()
|
|
{
|
|
mItemsToDelete.clear();
|
|
}
|
|
|
|
/*TQSizePolicy KOAgenda::sizePolicy() const
|
|
{
|
|
// Thought this would make the all-day event agenda minimum size and the
|
|
// normal agenda take the remaining space. But it doesnt work. The TQSplitter
|
|
// dont seem to think that an Expanding widget needs more space than a
|
|
// Preferred one.
|
|
// But it doesnt hurt, so it stays.
|
|
if (mAllDayMode) {
|
|
return TQSizePolicy(TQSizePolicy::Expanding,TQSizePolicy::Preferred);
|
|
} else {
|
|
return TQSizePolicy(TQSizePolicy::Expanding,TQSizePolicy::Expanding);
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
Overridden from TQScrollView to provide proper resizing of KOAgendaItems.
|
|
*/
|
|
void KOAgenda::resizeEvent ( TQResizeEvent *ev )
|
|
{
|
|
// kdDebug(5850) << "KOAgenda::resizeEvent" << endl;
|
|
|
|
TQSize newSize( ev->size() );
|
|
if (mAllDayMode) {
|
|
mGridSpacingX = double( newSize.width() - 2 * frameWidth() ) / (double)mColumns;
|
|
mGridSpacingY = newSize.height() - 2 * frameWidth();
|
|
} else {
|
|
int scrollbarWidth = vScrollBarMode() != AlwaysOff ? verticalScrollBar()->width() : 0;
|
|
mGridSpacingX = double( newSize.width() - scrollbarWidth - 2 * frameWidth()) / double(mColumns);
|
|
// make sure that there are not more than 24 per day
|
|
mGridSpacingY = double(newSize.height() - 2 * frameWidth()) / double(mRows);
|
|
if ( mGridSpacingY < mDesiredGridSpacingY )
|
|
mGridSpacingY = mDesiredGridSpacingY;
|
|
}
|
|
calculateWorkingHours();
|
|
TQTimer::singleShot( 0, this, TQT_SLOT( resizeAllContents() ) );
|
|
emit gridSpacingYChanged( mGridSpacingY * 4 );
|
|
TQScrollView::resizeEvent(ev);
|
|
}
|
|
|
|
void KOAgenda::resizeAllContents()
|
|
{
|
|
double subCellWidth;
|
|
if ( mItems.count() > 0 ) {
|
|
KOAgendaItem *item;
|
|
if (mAllDayMode) {
|
|
for ( item=mItems.first(); item != 0; item=mItems.next() ) {
|
|
subCellWidth = calcSubCellWidth( item );
|
|
placeAgendaItem( item, subCellWidth );
|
|
}
|
|
} else {
|
|
for ( item=mItems.first(); item != 0; item=mItems.next() ) {
|
|
subCellWidth = calcSubCellWidth( item );
|
|
placeAgendaItem( item, subCellWidth );
|
|
}
|
|
}
|
|
}
|
|
checkScrollBoundaries();
|
|
marcus_bains();
|
|
}
|
|
|
|
void KOAgenda::scrollUp()
|
|
{
|
|
scrollBy(0,-mScrollOffset);
|
|
}
|
|
|
|
|
|
void KOAgenda::scrollDown()
|
|
{
|
|
scrollBy(0,mScrollOffset);
|
|
}
|
|
|
|
|
|
/*
|
|
Calculates the minimum width
|
|
*/
|
|
int KOAgenda::minimumWidth() const
|
|
{
|
|
// FIXME:: develop a way to dynamically determine the minimum width
|
|
int min = 100;
|
|
|
|
return min;
|
|
}
|
|
|
|
void KOAgenda::updateConfig()
|
|
{
|
|
double oldGridSpacingY = mGridSpacingY;
|
|
|
|
mDesiredGridSpacingY = KOPrefs::instance()->mHourSize;
|
|
if ( mDesiredGridSpacingY < 4 || mDesiredGridSpacingY > 30 ) {
|
|
mDesiredGridSpacingY = 10;
|
|
}
|
|
|
|
// make sure that there are not more than 24 per day
|
|
mGridSpacingY = (double)height() / (double)mRows;
|
|
if ( mGridSpacingY < mDesiredGridSpacingY ) {
|
|
mGridSpacingY = mDesiredGridSpacingY;
|
|
}
|
|
|
|
//can be two doubles equal?, it's better to compare them with an epsilon
|
|
if ( fabs( oldGridSpacingY - mGridSpacingY ) > 0.1 ) {
|
|
resizeContents( int( mGridSpacingX * mColumns ),
|
|
int( mGridSpacingY * mRows ) );
|
|
}
|
|
|
|
calculateWorkingHours();
|
|
|
|
marcus_bains();
|
|
}
|
|
|
|
void KOAgenda::checkScrollBoundaries()
|
|
{
|
|
// Invalidate old values to force update
|
|
mOldLowerScrollValue = -1;
|
|
mOldUpperScrollValue = -1;
|
|
|
|
checkScrollBoundaries(verticalScrollBar()->value());
|
|
}
|
|
|
|
void KOAgenda::checkScrollBoundaries( int v )
|
|
{
|
|
int yMin = int( (v) / mGridSpacingY );
|
|
int yMax = int( ( v + visibleHeight() ) / mGridSpacingY );
|
|
|
|
// kdDebug(5850) << "--- yMin: " << yMin << " yMax: " << yMax << endl;
|
|
|
|
if ( yMin != mOldLowerScrollValue ) {
|
|
mOldLowerScrollValue = yMin;
|
|
emit lowerYChanged(yMin);
|
|
}
|
|
if ( yMax != mOldUpperScrollValue ) {
|
|
mOldUpperScrollValue = yMax;
|
|
emit upperYChanged(yMax);
|
|
}
|
|
}
|
|
|
|
int KOAgenda::visibleContentsYMin()
|
|
{
|
|
int v = verticalScrollBar()->value();
|
|
return int( v / mGridSpacingY );
|
|
}
|
|
|
|
int KOAgenda::visibleContentsYMax()
|
|
{
|
|
int v = verticalScrollBar()->value();
|
|
return int( ( v + visibleHeight() ) / mGridSpacingY );
|
|
}
|
|
|
|
void KOAgenda::deselectItem()
|
|
{
|
|
if ( mSelectedItem.isNull() ) {
|
|
return;
|
|
}
|
|
mSelectedItem->select(false);
|
|
mSelectedItem = 0;
|
|
}
|
|
|
|
void KOAgenda::selectItem(KOAgendaItem *item)
|
|
{
|
|
if ((KOAgendaItem *)mSelectedItem == item) return;
|
|
deselectItem();
|
|
if (item == 0) {
|
|
emit incidenceSelected( 0, TQDate() );
|
|
return;
|
|
}
|
|
mSelectedItem = item;
|
|
mSelectedItem->select();
|
|
assert( mSelectedItem->incidence() );
|
|
mSelectedUid = mSelectedItem->incidence()->uid();
|
|
emit incidenceSelected( mSelectedItem->incidence(), mSelectedItem->itemDate() );
|
|
}
|
|
|
|
void KOAgenda::selectItemByUID( const TQString& uid )
|
|
{
|
|
KOAgendaItem *item;
|
|
for ( item = mItems.first(); item != 0; item = mItems.next() ) {
|
|
if( item->incidence() && item->incidence()->uid() == uid ) {
|
|
selectItem( item );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// This function seems never be called.
|
|
void KOAgenda::keyPressEvent( TQKeyEvent *kev )
|
|
{
|
|
switch(kev->key()) {
|
|
case Key_PageDown:
|
|
verticalScrollBar()->addPage();
|
|
break;
|
|
case Key_PageUp:
|
|
verticalScrollBar()->subtractPage();
|
|
break;
|
|
case Key_Down:
|
|
verticalScrollBar()->addLine();
|
|
break;
|
|
case Key_Up:
|
|
verticalScrollBar()->subtractLine();
|
|
break;
|
|
default:
|
|
;
|
|
}
|
|
}
|
|
|
|
void KOAgenda::calculateWorkingHours()
|
|
{
|
|
mWorkingHoursEnable = !mAllDayMode;
|
|
|
|
TQTime tmp = KOPrefs::instance()->mWorkingHoursStart.time();
|
|
mWorkingHoursYTop = int( 4 * mGridSpacingY *
|
|
( tmp.hour() + tmp.minute() / 60. +
|
|
tmp.second() / 3600. ) );
|
|
tmp = KOPrefs::instance()->mWorkingHoursEnd.time();
|
|
mWorkingHoursYBottom = int( 4 * mGridSpacingY *
|
|
( tmp.hour() + tmp.minute() / 60. +
|
|
tmp.second() / 3600. ) - 1 );
|
|
}
|
|
|
|
|
|
DateList KOAgenda::dateList() const
|
|
{
|
|
return mSelectedDates;
|
|
}
|
|
|
|
void KOAgenda::setDateList(const DateList &selectedDates)
|
|
{
|
|
mSelectedDates = selectedDates;
|
|
marcus_bains();
|
|
}
|
|
|
|
void KOAgenda::setHolidayMask(TQMemArray<bool> *mask)
|
|
{
|
|
mHolidayMask = mask;
|
|
|
|
}
|
|
|
|
void KOAgenda::contentsMousePressEvent ( TQMouseEvent *event )
|
|
{
|
|
kdDebug(5850) << "KOagenda::contentsMousePressEvent(): type: " << event->type() << endl;
|
|
TQScrollView::contentsMousePressEvent(event);
|
|
}
|
|
|
|
void KOAgenda::setTypeAheadReceiver( TQObject *o )
|
|
{
|
|
mTypeAheadReceiver = o;
|
|
}
|
|
|
|
TQObject *KOAgenda::typeAheadReceiver() const
|
|
{
|
|
return mTypeAheadReceiver;
|
|
}
|