/* ====================================================================
 * Copyright (c) 2007-2008  Martin Hauner
 *                          http://subcommander.tigris.org
 *
 * Subcommander is licensed as described in the file doc/COPYING, which
 * you should have received as part of this distribution.
 * ====================================================================
 */

// sc
#include "TreeView.h"

// qt
#include <QtGui/QApplication>
#include <QtGui/QHeaderView>
#include <QtGui/QMouseEvent>
#include <QtGui/QScrollBar>


TreeView::TreeView(QWidget* parent)
: super(parent), _dragTimerId(0)
{
}

void TreeView::mousePressEvent( QMouseEvent* e )
{
  super::mousePressEvent(e);

  if( e->button() == Qt::LeftButton )
    _lastMousePosLeftPress = e->pos();
}

void TreeView::mouseMoveEvent( QMouseEvent* e )
{
  //super::mouseMoveEvent(e);

  _lastMousePos = e->pos();
}

void TreeView::dragEnterEvent( QDragEnterEvent* e )
{
  //super::dragEnterEvent(e);

  _dragTimerId = startTimer(100);
}

void TreeView::dragMoveEvent( QDragMoveEvent* e )
{
  //super::dragMoveEvent(e);

  _lastMousePos = e->pos();
  _lastMouseTime = QTime::currentTime();
}

void TreeView::dragLeaveEvent( QDragLeaveEvent* e )
{
  //dragLeaveEvent(e);

  if( _dragTimerId == 0 )
    return;

  killTimer(_dragTimerId);
  _dragTimerId = 0;
}

void TreeView::dropEvent( QDropEvent* e )
{
  if( _dragTimerId == 0 )
    return;

  killTimer(_dragTimerId);
  _dragTimerId = 0;
}

void TreeView::timerEvent( QTimerEvent* e )
{
  super::timerEvent(e);

  if( e->timerId() != _dragTimerId )
    return;

  int maximum = maximumHeight();
  int visible = visibleHeight();

  if( visible < maximum )
  {
    int delta = calcScrollDelta(_lastMousePos,maximum,visible);
    if( delta != 0 )
    {
      verticalScrollBar()->setValue( verticalScrollBar()->value() + delta );
    }
  }
}

bool TreeView::dragStartable() const
{
  return (_lastMousePosLeftPress - _lastMousePos).manhattanLength() >= QApplication::startDragDistance();
}

int TreeView::maximumHeight()
{
  // auto scroll, max + pageStep = rows
  return (verticalScrollBar()->maximum() + verticalScrollBar()->pageStep()) * sizeHintForRow(0);
}

int TreeView::visibleHeight()
{
  return height() - header()->height() -
    (horizontalScrollBar()->isVisible() ? horizontalScrollBar()->height() : 0 );
}

int TreeView::calcScrollDelta( const QPoint& pos, int maximumHeight, int visibleHeight )
{
  // down fast
  if( pos.y() > visibleHeight - 10 )
  {
    return 2 /*15*/;
  }
  // down slow
  else if( pos.y() > visibleHeight - 20 )
  {
    return 1 /*5*/;
  }
  // up fast
  else if( maximumHeight > 0 && pos.y() < 10 )
  {
    return -2 /*-15*/;
  }
  // up slow
  else if( maximumHeight > 0 && pos.y() < 20 )
  {
    return -1 /*-5*/;
  }
  
  return 0;    
}

void TreeView::autoExpand( QTimerEvent* e )
{
  if( e->timerId() != _dragTimerId )
    return;

  // auto expand
  QPoint pos = viewport()->mapFromGlobal(QCursor::pos());
  if( pos == _lastMousePos && _lastMouseTime.elapsed() > 1000 )
  {
    QModelIndex index = indexAt(_lastMousePos);
    if( index.isValid() )
    {
      setExpanded( index, !isExpanded(index) );
      _lastMouseTime = QTime::currentTime();
    }
  }
}
