/****************************************************************************
**
** Copyright (C) 1999-2006 Frank Hemer <frank@hemer.org>,
**                         Tilo Riemer <riemer@crossvc.com>,
**                         Jose Hernandez <joseh@tesco.net>,
**                         Wim Delvaux <wim.delvaux@chello.be>,
**                         Jose Hernandez <joseh@tesco.net>,
**                         Helmut Koll <HelmutKoll@web.de>,
**                         Joerg Preiss <auba@auba.de>
**
**
**----------------------------------------------------------------------------
**
**----------------------------------------------------------------------------
**
** CrossVC is available under two different licenses:
**
** If CrossVC is linked against the GPLed version of Qt 
** CrossVC is released under the terms of GPL also.
**
** If CrossVC is linked against a nonGPLed version of Qt 
** CrossVC is released under the terms of the 
** CrossVC License for non-Unix platforms (CLNU)
**
**
** CrossVC License for non-Unix platforms (CLNU):
**
** Redistribution and use in binary form, without modification, 
** are permitted provided that the following conditions are met:
**
** 1. Redistributions in binary form must reproduce the above copyright
**    notice, this list of conditions and the following disclaimer in the
**    documentation and/or other materials provided with the distribution.
** 2. It is not permitted to distribute the binary package under a name
**    different than CrossVC.
** 3. The name of the authors may not be used to endorse or promote
**    products derived from this software without specific prior written
**    permission.
** 4. The source code is the creative property of the authors.
**    Extensions and development under the terms of the Gnu Public License
**    are limited to the Unix platform. Any distribution or compilation of 
**    the source code against libraries licensed other than gpl requires 
**    the written permission of the authors.
**
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR 
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 
** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
**
**
** CrossVC License for Unix platforms:
**
** 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, version 2 of the License.
** 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 version 2 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.
**
*****************************************************************************/

#include "config.h"

//----------------------------------------------------------------------------

#include <assert.h>
#include <math.h>

//----------------------------------------------------------------------------

#include <qpopupmenu.h>
#include <qdragobject.h>
#include <qmessagebox.h>
#include <qapplication.h>
#include <qclipboard.h>

//----------------------------------------------------------------------------

#include "CustomizeDialogImpl.h"
#include "globals.h"
#include "FileListView.h"
#include "cvslistview.h"
#include "directory.h"

#include <iostream>

//----------------------------------------------------------------------------

CvsListView::CvsListView(QPopupMenu *menu, QWidget * parent, const char * name)
   : CFileListView(parent, name),
     m_selectedOnPress(false)
{
   /* Use extended selection mode.  When we click on this
    * window we usually want to operate on a single file by using
    * the menu unless the user uses the shift or control key.
    * We don't want to use the standard multiple selection mode
    * because the point in having a tree view is so we can perform
    * the operation on the whole directory hierarchy in one go.
    * If a selected file is clicked, deselect it.
    */
   setSelectionMode (QListView::Extended);

   setAllColumnsShowFocus(true);
   setShowSortIndicator( true);
   addColumn(tr("Name"));
   addColumn(tr("Revision"));
   addColumn(tr("Tag"));
   addColumn(tr("Option"));
   addColumn(tr("State"));
   addColumn(tr("Last updated"));
   addColumn(tr("Modified"));

   connect (this, SIGNAL( doubleClicked( QListViewItem *) ),
	 this, SLOT( selFile( QListViewItem *) ) );
   connect (this, SIGNAL( selectionChanged()),
	 this, SLOT( selectionChanged()));
   m_pMenu = menu;
}

//----------------------------------------------------------------------------

FileListViewItem * CvsListView::firstChild() const {
   return static_cast<FileListViewItem*>(CFileListView::firstChild());
}

//----------------------------------------------------------------------------

void CvsListView::contentsMousePressEvent(QMouseEvent * e)
{
   if (!globalListViewsEnabled) return;
   assert(m_pMenu);   //valid pointer
  
   if (!hasFocus() && !viewport()->hasFocus()) setFocus();

   QListViewItem* item = itemAt(contentsToViewport(e->pos()));
   if (item) m_selectedOnPress = item->isSelected();

   QListView::contentsMousePressEvent( e );

   if (item) {
      if (e->button() == RightButton) {
	 setSelected(item, true);
	 setCurrentItem(item);
	 QPoint offset(10, 30);
	 m_pMenu->popup(mapToGlobal(contentsToViewport(e->pos())) + offset);
      } else if ( (e->button() == LeftButton) && !m_selectedOnPress) {
	 setSelected(item, true);
	 setCurrentItem(item);
      }
   }
}

//----------------------------------------------------------------------------

void CvsListView::contentsMouseReleaseEvent(QMouseEvent * e)
{
   if (!globalListViewsEnabled) return;

   QListViewItem* item = itemAt(contentsToViewport(e->pos()));
   QListView::contentsMouseReleaseEvent( e );
   if ( item && (e->button() == LeftButton) && m_selectedOnPress) {
      setCurrentItem(item);
      setSelected(item, false);
   }
}

//----------------------------------------------------------------------------

void CvsListView::keyPressEvent ( QKeyEvent * e ) 
{
   if (!globalListViewsEnabled) return;

   QListView::keyPressEvent( e );

   if (e->key() == Qt::Key_Return) {
      if (currentItem()) {
	 setSelected(currentItem(), true);
	 m_pMenu->popup(mapToGlobal(QPoint(60, 40)));
      }
   } else if (e->key() == Qt::Key_Escape) {
      FileListViewItem * item = firstChild();
      while (item) {
	 if (item->isSelected()) setSelected(item,false);
	 item = item->nextSibling();
      }
   }
}

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------

CvsDirListView::CvsDirListView(QPopupMenu *menu, QWidget * parent, const char * name)
   : QListView(parent, name)
{

   m_xDeltaAutoScroll = qApp->desktop()->width()/100;//autoscroll x sensitivity
   m_yDeltaAutoScroll = qApp->desktop()->height()/50;//autoscroll y sensitivity

   m_pMenu = menu;

   m_pDropMenu = new QPopupMenu(this);
   moveItem = m_pDropMenu->insertItem( tr("move"), this, SLOT(moveFiles()) );
   copyItem = m_pDropMenu->insertItem( tr("copy"), this, SLOT(copyFiles()) );
   copyTreeItem = m_pDropMenu->insertItem( tr("copy tree"), this, SLOT(copyTree()) );
   m_pDropMenu->insertSeparator();
   addAsciiItem = m_pDropMenu->insertItem( tr("cvs add ascii"), this, SLOT(copyCvsFilesAscii()) );
   addBinaryItem = m_pDropMenu->insertItem( tr("cvs add binary"), this, SLOT(copyCvsFilesBinary()) );

   m_pDropCvsMenu = new QPopupMenu(this);
   cvsMoveItem = m_pDropCvsMenu->insertItem( tr("move"), this, SLOT(moveFiles()) );
   cvsCopyItem = m_pDropCvsMenu->insertItem( tr("copy"), this, SLOT(copyFiles()) );
   m_pDropCvsMenu->insertSeparator();
   cvsMoveCvsItem = m_pDropCvsMenu->insertItem( tr("cvs move"), this, SLOT(moveCvsFiles()) );
   cvsAddAsciiItem = m_pDropCvsMenu->insertItem( tr("cvs add ascii"), this, SLOT(copyCvsFilesAscii()) );
   cvsAddBinaryItem = m_pDropCvsMenu->insertItem( tr("cvs add binary"), this, SLOT(copyCvsFilesBinary()) );


   connect (this, SIGNAL( selectionChanged()),
	 this, SLOT( selectionChanged()));

   setAcceptDrops(TRUE);
   setDragAutoScroll(false);
   m_lastSelectedItem = NULL;
   m_itemOnDragEnter = NULL;
   m_openList.clear();
   m_openTimer = new QTimer(this);
   connect(m_openTimer,SIGNAL(timeout()),this,SLOT(openLastSelectedItem()) );
   m_scrollUpTimer = new QTimer(this);
   connect(m_scrollUpTimer,SIGNAL(timeout()),this,SLOT(scrollUp()) );
   m_scrollDownTimer = new QTimer(this);
   connect(m_scrollDownTimer,SIGNAL(timeout()),this,SLOT(scrollDown()) );
   m_scrollLeftTimer = new QTimer(this);
   connect(m_scrollLeftTimer,SIGNAL(timeout()),this,SLOT(scrollLeft()) );
   m_scrollRightTimer = new QTimer(this);
   connect(m_scrollRightTimer,SIGNAL(timeout()),this,SLOT(scrollRight()) );
}

//----------------------------------------------------------------------------

DirBase * CvsDirListView::selectedItem() const {
   Directory * dir = static_cast <Directory *> (QListView::selectedItem ());
   return dir;
}

//----------------------------------------------------------------------------

DirBase * CvsDirListView::selectCurrentItem () const {
   QListViewItem * d = currentItem ();
   if (d) {
      d->setSelected (true);
      return selectedItem ();
   }
   return NULL;
}

//----------------------------------------------------------------------------

void CvsDirListView::selectionChanged() {

   DirBase *dir = (DirBase *)currentItem();
   if(!dir) {
      return;
   }

   bool tmp = false;
   QListViewItem *myChild = firstChild();
   tmp = anySelected(myChild);

   //currentItem() returns an item, even if not selected,
   //this is poorly documented in QListView::currentItem().
   //currentItem() only returns the item having the keyboard focus
   if (dir->isSelected()) {
//       dir->activateItem(FALSE);
      emit dirClicked(dir);
      OldItem = dir;
      setStatusBarText( dir->fullName());
   } else {
      OldItem = NULL;
   }
   Dialog::g_showWarning = true;
   emit showDirMenu(tmp);
}

//----------------------------------------------------------------------------

bool CvsDirListView::anySelected(QListViewItem *myChild) {

   while(myChild) {
      if (myChild->isSelected()) {
	 return true;
      }
      QListViewItem *deeperChild = myChild->firstChild();
      if (deeperChild) {
	 if (anySelected(deeperChild)) {
	    return true;
	 }
      }
      myChild = myChild->nextSibling();
   }
   return false;
}

//----------------------------------------------------------------------------

void CvsDirListView::keyPressEvent ( QKeyEvent * e ) {

   if (!globalListViewsEnabled) return;

   QListView::keyPressEvent( e );

   if(e->key() == Qt::Key_Return) {   
      if (currentItem()) {
	 setSelected(currentItem(), true);
	 popupMenu( (DirBase*)currentItem(), mapToGlobal(QPoint(60, 40)));
      }

   } else if( ((e->key() == Qt::Key_Up) ||
		    (e->key() == Qt::Key_Down) ||
		    (e->key() == Qt::Key_Left) ||
		    (e->key() == Qt::Key_Right)) &&
	 currentItem()) {
      setSelected(currentItem(), true);

   } else if ( ( e->key() == Qt::Key_Space) && currentItem()) {
      emit dirClicked((DirBase*)currentItem());
   }
}

//----------------------------------------------------------------------------

void CvsDirListView::keyReleaseEvent ( QKeyEvent * e ) 
{
   QListView::keyReleaseEvent( e );
   emit typed();
}

//----------------------------------------------------------------------------

void CvsDirListView::contentsMouseDoubleClickEvent ( QMouseEvent * e )
{
   if (!globalListViewsEnabled) return;

   QListView::contentsMouseDoubleClickEvent ( e );
}

//----------------------------------------------------------------------------

void CvsDirListView::contentsMouseMoveEvent ( QMouseEvent * e ) 
{
   if (!globalListViewsEnabled) return;

   QListView::contentsMouseMoveEvent ( e );
}

//----------------------------------------------------------------------------

void CvsDirListView::contentsMousePressEvent ( QMouseEvent * e ) 
{
   if (!globalListViewsEnabled) return;

   assert(m_pMenu);   //valid pointer
   DirBase* dirItem;
   
   if ( (dirItem = (DirBase*)itemAt(contentsToViewport(e->pos())) ) == NULL ) return ;
   
   if(!hasFocus() && !viewport()->hasFocus())
      setFocus();
  
   if (e->button() == RightButton){
      setSelected(dirItem, true);
      setCurrentItem(dirItem);
      QPoint offset(10, 5);
      popupMenu( dirItem, mapToGlobal(contentsToViewport(e->pos())) + offset);
   } else {
      bool sameDirClicked = false;
      if ( (dirItem == OldItem) && (!DirWatch::b_isActive) ) {
         sameDirClicked = true;
      }
      bool open = dirItem->isOpen ();
      QListView::contentsMousePressEvent ( e );
      if (sameDirClicked && (open == dirItem->isOpen ())) {
         emit dirClicked (dirItem);
      }
   }
   e->accept();
}

//----------------------------------------------------------------------------

void CvsDirListView::contentsMouseReleaseEvent ( QMouseEvent * e )
{
   if (!globalListViewsEnabled) return;

   QListView::contentsMouseReleaseEvent ( e );
}

//----------------------------------------------------------------------------

DirBase * CvsDirListView::find( QString S ) {

   DirBase * D2, *D = (DirBase *)firstChild();
   while( D ) {
      if( ( D2 = D->searchDirOfPath( S ) ) ) 
	 return D2;
      D = D->nextSibling();
   }
   return 0;
}

//----------------------------------------------------------------------------

DirBase * CvsDirListView::findBestMatch( QString S ) {

   DirBase * D2, *D = (DirBase *)firstChild();
   while( D ) {
      if( ( D2 = D->searchLastValidDirOfPath( S ) ) ) 
	 return D2;
      D = D->nextSibling();
   }
   return 0;
}

//----------------------------------------------------------------------------

void CvsDirListView::resizeEvent (QResizeEvent *e)
{
   QListView::resizeEvent (e);

   /* Expand or shrink the only column in the
    * list view so it always ocuppies the visible
    * width of the widget.
    */
   //!!! setColumnWidth (0, visibleWidth());
}

//----------------------------------------------------------------------------

void CvsDirListView::popupMenu(DirBase *, QPoint point) {
   m_pMenu->popup(point);
}

//----------------------------------------------------------------------------

void CvsDirListView::dragEnterEvent(QDragEnterEvent* event)
{
   event->accept(QUriDrag::canDecode(event) );
   m_lastSelectedItem = NULL;
   m_openList.clear();
   m_itemOnDragEnter = static_cast<DirBase*>(currentItem());
   m_xScrollPos = verticalScrollBar()->value();
   m_yScrollPos = horizontalScrollBar()->value();
}

//----------------------------------------------------------------------------

void CvsDirListView::dragMoveEvent ( QDragMoveEvent * event) {

   DirBase * item = static_cast<DirBase*>(itemAt(event->pos()));
   if (item && ( item != m_lastSelectedItem) ) {
      setSelected(item,TRUE);
      triggerUpdate();
      if ( m_lastSelectedItem && (!item->fullName().startsWith(m_lastSelectedItem->fullName())) && (m_openList.findRef(m_lastSelectedItem) != -1) ) {
	 m_openList.take()->setOpen(FALSE);
      }
      m_lastSelectedItem = item;
      m_openTimer->start(500);
   }
   QPoint p = event->pos();
   if (p.y() >= (visibleHeight()/2) ) setScrollDownTimer(visibleHeight()-p.y());
   else setScrollUpTimer(p.y());
   if (p.x() >= (visibleWidth()/2) ) setScrollRightTimer(visibleWidth()-p.x());
   else setScrollLeftTimer(p.x());
}

//----------------------------------------------------------------------------

void CvsDirListView::setScrollUpTimer(int val) {
   //   qDebug("+dist: "+QString::number(val) );
   if (val > m_yDeltaAutoScroll) m_scrollUpTimer->stop();
   else {
      double m_d = (double)val;
      m_scrollUpTimer->start( ((int)sqrt(m_d))*50 );
   }
}

//----------------------------------------------------------------------------

void CvsDirListView::scrollUp() {
   //   qDebug("scrollUp");
   scrollBy(0,-5);
}

//----------------------------------------------------------------------------

void CvsDirListView::setScrollDownTimer(int val) {
   //   qDebug("-dist: "+QString::number(val) );
   if ( (val > m_yDeltaAutoScroll) || (val <= 0) ) m_scrollDownTimer->stop();
   else {
      double m_d = (double)val;
      m_scrollDownTimer->start( ((int)sqrt(m_d))*50 );
   }
}

//----------------------------------------------------------------------------

void CvsDirListView::scrollDown() {
   //   qDebug("scrollDown");
   scrollBy(0,+5);
}

//----------------------------------------------------------------------------

void CvsDirListView::setScrollLeftTimer(int val) {
   //   qDebug("+dist: "+QString::number(val) );
   if (val > m_xDeltaAutoScroll) m_scrollLeftTimer->stop();
   else {
      double m_d = (double)val;
      m_scrollLeftTimer->start( ((int)sqrt(m_d))*50 );
   }
}

//----------------------------------------------------------------------------

void CvsDirListView::scrollLeft() {
   //   qDebug("scrollUp");
   scrollBy(-5,0);
}

//----------------------------------------------------------------------------

void CvsDirListView::setScrollRightTimer(int val) {
   //   qDebug("-dist: "+QString::number(val) );
   if ( (val > m_xDeltaAutoScroll) || (val <= 0) ) m_scrollRightTimer->stop();
   else {
      double m_d = (double)val;
      m_scrollRightTimer->start( ((int)sqrt(m_d))*50 );
   }
}

//----------------------------------------------------------------------------

void CvsDirListView::scrollRight() {
   //   qDebug("scrollDown");
   scrollBy(+5,0);
}

//----------------------------------------------------------------------------

void CvsDirListView::dragLeaveEvent ( QDragLeaveEvent * ) {
   resetDrag();
}

//----------------------------------------------------------------------------

void CvsDirListView::resetDrag() {
   m_openTimer->stop();
   m_scrollUpTimer->stop();
   m_scrollDownTimer->stop();
   m_scrollLeftTimer->stop();
   m_scrollRightTimer->stop();
   for (DirBase * dir = m_openList.first(); dir; dir = m_openList.next()) {
      dir->setOpen(FALSE);
   }

   if (m_itemOnDragEnter) setSelected(m_itemOnDragEnter,true);
   verticalScrollBar()->setValue(m_xScrollPos);
   horizontalScrollBar()->setValue(m_yScrollPos);
   m_itemOnDragEnter = NULL;
}

//----------------------------------------------------------------------------

void CvsDirListView::openLastSelectedItem() {
   if (m_lastSelectedItem && !m_lastSelectedItem->isOpen()) {
      QStringList list;
      for (DirBase * dir = m_openList.first(); dir; dir = m_openList.next()) {
	 list.append(dir->fullName());
      }
      QString dirRemoved;
      m_lastSelectedItem->setOpen(TRUE,dirRemoved);
      if (dirRemoved.isEmpty()) {
	 if (m_lastSelectedItem->isOpen()) m_openList.append(m_lastSelectedItem);
      } else {
	 QStringList::Iterator it;
	 unsigned int idx = m_openList.count();
	 it = list.end();
	 while (it != list.begin()) {
	    --it;
	    --idx;
	    if ( (*it).startsWith(dirRemoved)) {
	       m_openList.remove(idx);
	    }
	 }
	 m_lastSelectedItem = NULL;
      }
   }
}

//----------------------------------------------------------------------------

void CvsDirListView::dropEvent(QDropEvent* event) {

   m_openTimer->stop();
   m_scrollUpTimer->stop();
   m_scrollDownTimer->stop();
   m_scrollLeftTimer->stop();
   m_scrollRightTimer->stop();
   QStrList list;
   m_DropStringList.clear();
   if ( QUriDrag::decode(event, list) ) {
      m_pDropDir = static_cast<DirBase*>(itemAt(event->pos()));
      if (m_pDropDir) {
	 if (m_pDropDir->isVirtual()) return;
	 if (!m_pDropDir->isSelected() ) setSelected(m_pDropDir,TRUE);
      }
      char * p;
      bool filesOnly = TRUE;
      bool dirsOnly = TRUE;
      bool isFromLinCVS = TRUE;
      bool isCvsRegistered = TRUE;
      bool binaryOnly = TRUE;
      bool asciiOnly = TRUE;
      for (p = list.first(); p; p=list.next()) {
	 QString file = QUriDrag::uriToLocalFile(p);
	 if (!file.isEmpty()) {
	    int pos = file.findRev("/");
	    QString path = file.left(pos);
	    QString relFileName = file.mid(pos+1);
	    DirBase * dragDir = find(path);
	    if (dragDir) {//if file is dragged from LinCVS, its dir must be found
	       if (!dragDir->isControlled(relFileName)) isCvsRegistered = FALSE;
	       else if (dragDir->isBinary(relFileName)) {
		  asciiOnly = FALSE;
	       } else {
		  binaryOnly = FALSE;
	       }
	    } else {
	       isFromLinCVS = FALSE;
	    }
	    m_DropStringList.append(file);
	    if (QFileInfo(file).isDir()) filesOnly = FALSE;
	    else dirsOnly = FALSE;
	 }
      }
      if (m_pDropDir) {
	 QPoint offset(10, 5);
	 bool reset = false;
	 if (filesOnly) {
	    if (isFromLinCVS) {
	       m_pDropCvsMenu->setItemEnabled(cvsMoveCvsItem,isCvsRegistered);
	       m_pDropCvsMenu->setItemEnabled(cvsAddAsciiItem,asciiOnly);
	       m_pDropCvsMenu->setItemEnabled(cvsAddBinaryItem,binaryOnly);
	  
	       if (m_pDropCvsMenu->exec(mapToGlobal(event->pos())+offset) == -1) reset = true;
	    } else {
	       m_pDropMenu->setItemEnabled(moveItem,TRUE);
	       m_pDropMenu->setItemEnabled(copyItem,TRUE);
	       m_pDropMenu->setItemEnabled(copyTreeItem,FALSE);
	       m_pDropMenu->setItemEnabled(addAsciiItem,TRUE);
	       m_pDropMenu->setItemEnabled(addBinaryItem,TRUE);

	       if (m_pDropMenu->exec(mapToGlobal(event->pos())+offset) == -1) reset = true;
	    }

	 } else {//dirs and files, copy the tree without cvs action
	    m_pDropMenu->setItemEnabled(moveItem,FALSE);
	    m_pDropMenu->setItemEnabled(copyItem,FALSE);
	    m_pDropMenu->setItemEnabled(copyTreeItem,TRUE);
	    m_pDropMenu->setItemEnabled(addAsciiItem,FALSE);
	    m_pDropMenu->setItemEnabled(addBinaryItem,FALSE);

	    if (m_pDropMenu->exec(mapToGlobal(event->pos())+offset) == -1) reset = true;
	 }
	 if (reset) {
	    m_pDropDir = NULL;
	    resetDrag();
	 }
      } else if (dirsOnly) {//only dirs choosen, add as new project
	 for (QStringList::Iterator it = m_DropStringList.begin(); it != m_DropStringList.end(); ++it) {
	    emit folderDropped(*it);
	 }
      }
   }
}

//----------------------------------------------------------------------------

void CvsDirListView::paste(QStringList copiedList) {//copiedList is latest list of files that were copied to clipboard from LinCVS

   m_pDropDir = static_cast<DirBase*>(currentItem());
   if(!m_pDropDir || m_pDropDir->isVirtual()) {
      return;
   }

   QPoint point;
   if (itemRect(m_pDropDir).isValid()) {
      point = contentsToViewport(QPoint(0,m_pDropDir->itemPos()));
   } else {
      point.setY(y()+(height()/2) );
   }
   point.setX(x());

   m_DropStringList.clear();

   QClipboard *cb = QApplication::clipboard();
   QStringList uris;
   if (QUriDrag::decodeLocalFiles(cb->data(QClipboard::Clipboard),uris)) {

      bool isFromLinCVS = (uris == copiedList);

      bool filesOnly = TRUE;
      bool dirsOnly = TRUE;
      bool isCvsRegistered = TRUE;
      bool binaryOnly = TRUE;
      bool asciiOnly = TRUE;
      QStringList::Iterator it;
      for (it = uris.begin(); it != uris.end(); ++it) {

	 int pos = (*it).findRev("/");
	 QString path = (*it).left(pos);
	 QString relFileName = (*it).mid(pos+1);
	 DirBase * dragDir = find(path);

	 if (dragDir) {//if file was copied from LinCVS, its dir must be found
	    if (!dragDir->isControlled(relFileName)) isCvsRegistered = FALSE;
	    else if (dragDir->isBinary(relFileName)) {
	       asciiOnly = FALSE;
	    } else {
	       binaryOnly = FALSE;
	    }
	 }

	 if (!(*it).isEmpty()) {
	    m_DropStringList.append((*it));
	    if (QFileInfo((*it)).isDir()) filesOnly = FALSE;
	    else dirsOnly = FALSE;
	 }

      }
      m_itemOnDragEnter = NULL;
      if (m_pDropDir) {
	 QPoint offset(10, 5);
	 if (filesOnly) {
	    if (isFromLinCVS) {
	       m_pDropCvsMenu->setItemEnabled(cvsMoveCvsItem,isCvsRegistered);
	       m_pDropCvsMenu->setItemEnabled(cvsAddAsciiItem,asciiOnly);
	       m_pDropCvsMenu->setItemEnabled(cvsAddBinaryItem,binaryOnly);
	  
	       m_pDropCvsMenu->popup(mapToGlobal(point)+offset);
	    } else {
	       m_pDropMenu->setItemEnabled(moveItem,TRUE);
	       m_pDropMenu->setItemEnabled(copyItem,TRUE);
	       m_pDropMenu->setItemEnabled(copyTreeItem,FALSE);
	       m_pDropMenu->setItemEnabled(addAsciiItem,TRUE);
	       m_pDropMenu->setItemEnabled(addBinaryItem,TRUE);
	  
	       m_pDropMenu->popup(mapToGlobal(point)+offset);
	    }
	 } else {//dirs and files, copy the tree without cvs action
	    m_pDropMenu->setItemEnabled(moveItem,FALSE);
	    m_pDropMenu->setItemEnabled(copyItem,FALSE);
	    m_pDropMenu->setItemEnabled(copyTreeItem,TRUE);
	    m_pDropMenu->setItemEnabled(addAsciiItem,FALSE);
	    m_pDropMenu->setItemEnabled(addBinaryItem,FALSE);

	    if (m_pDropMenu->exec(mapToGlobal(point)+offset) == -1) resetDrag();
	    m_pDropDir = NULL;
	 }
      } else if (dirsOnly) {//only dirs choosen, add as new project
	 for (QStringList::Iterator it = m_DropStringList.begin(); it != m_DropStringList.end(); ++it) {
	    emit folderDropped(*it);
	 }
      }
   }
}

//----------------------------------------------------------------------------

void CvsDirListView::moveFiles() {
   assert(m_pDropDir);
   bool moved = FALSE;
   for (QStringList::Iterator it = m_DropStringList.begin(); it != m_DropStringList.end(); ++it) {
      int pos = (*it).findRev("/");
      QString dst = m_pDropDir->fullName()+(*it).mid(pos);
      if (QFileInfo(dst).exists()) {
	 int res = QMessageBox::warning(this,
	       tr("Move file(s)"),
	       tr("File exists")+": "+dst+"\n"+tr("skip?"),
	       QMessageBox::Ok,
	       QMessageBox::Abort);
	 if (res== QMessageBox::Abort) {
	    if (m_itemOnDragEnter) resetDrag();
	    return;
	 }
	 else continue;
      } else {
	 QFileInfo fInfo(*it);
	 int permission = 0;
	 if (fInfo.isReadable()) permission = (permission | READABLE);
	 if (fInfo.isWritable()) permission = (permission | WRITEABLE);
	 if (fInfo.isExecutable()) permission = (permission | EXECUTABLE);
	 if (!m_pDropDir->copyFile(*it,dst,permission,true)) {
	    if (QMessageBox::warning(this,
		      tr("Move file(s)"),
		      tr("Moving")+"\n"+(*it)+"\n-->"+dst+"\n"+tr("failed, continue?"),
		      QMessageBox::Ok,
		      QMessageBox::Abort) == QMessageBox::Abort) {
	       if (m_itemOnDragEnter) resetDrag();
	       return;
	    }
	 } else {
	    DirBase * dir = find( (*it).left(pos) );
	    if (dir) {
	       QString file = (*it).mid(pos+1);
	       if (!dir->setEntryState(file,ES_missing)) {
		  dir->removeNonControlled(file);
	       }
	    }
	    moved = TRUE;
	 }
      }
   }

   m_pDropDir = NULL;
   if (m_itemOnDragEnter && !moved) resetDrag();
}

//----------------------------------------------------------------------------

void CvsDirListView::copyFiles() {
   assert(m_pDropDir);
   bool copied = FALSE;
   for (QStringList::Iterator it = m_DropStringList.begin(); it != m_DropStringList.end(); ++it) {
      QString dst = m_pDropDir->fullName()+(*it).mid( (*it).findRev("/"));
      if (QFileInfo(dst).exists()) {
	 int res = QMessageBox::warning(this,
	       tr("Copy file(s)"),
	       tr("File exists")+": "+dst+"\n"+tr("skip?"),
	       QMessageBox::Ok,
	       QMessageBox::Abort);
	 if (res == QMessageBox::Abort) {
	    if (m_itemOnDragEnter) resetDrag();
	    return;
	 }
	 else continue;
      } else {
	 QFileInfo fInfo(*it);
	 int permission = 0;
	 if (fInfo.isReadable()) permission = (permission | READABLE);
	 if (fInfo.isWritable()) permission = (permission | WRITEABLE);
	 if (fInfo.isExecutable()) permission = (permission | EXECUTABLE);
	 if (!m_pDropDir->copyFile(*it,dst,permission)) {
	    if (QMessageBox::warning(this,
		      tr("Copy file(s)"),
		      tr("Copying")+"\n"+(*it)+"\n-->"+dst+"\n"+tr("failed, continue?"),
		      QMessageBox::Ok,
		      QMessageBox::Abort) == QMessageBox::Abort) {
	       if (m_itemOnDragEnter) resetDrag();
	       return;
	    }
	 } else copied = TRUE;
      }
   }

   m_pDropDir = NULL;
   if (m_itemOnDragEnter && !copied) resetDrag();
}

//----------------------------------------------------------------------------

void CvsDirListView::copyTree() {
   assert(m_pDropDir);
   bool copied = FALSE;
   for (QStringList::Iterator it = m_DropStringList.begin(); it != m_DropStringList.end(); ++it) {
      QString dst = m_pDropDir->fullName()+(*it).mid( (*it).findRev("/"));
      QFileInfo fInfo(*it);

      if (QFileInfo(dst).exists()) {
	 int res = QMessageBox::warning(this,
	       tr("Copy tree"),
	       tr("File exists")+": "+dst+"\n"+tr("skip?"),
	       QMessageBox::Ok,
	       QMessageBox::Abort);
	 if (res == QMessageBox::Abort) {
	    if (m_itemOnDragEnter) resetDrag();
	    return;
	 }
	 else continue;
      }
    
      if (fInfo.isDir()) {

	 if (!m_pDropDir->recCopyTree(*it,m_pDropDir->fullName(),false)) {
	    if (QMessageBox::warning(this,
		      tr("Copy tree"),
		      tr("Copying")+"\n"+(*it)+"\n-->"+dst+"\n"+tr("failed, continue?"),
		      QMessageBox::Ok,
		      QMessageBox::Abort) == QMessageBox::Abort) {
	       if (m_itemOnDragEnter) resetDrag();
	       return;
	    }
	 } else copied = TRUE;
      } else if (fInfo.isFile()) {
	 int permission = 0;
	 if (fInfo.isReadable()) permission = (permission | READABLE);
	 if (fInfo.isWritable()) permission = (permission | WRITEABLE);
	 if (fInfo.isExecutable()) permission = (permission | EXECUTABLE);
	 if (!m_pDropDir->copyFile(*it,dst,permission)) {
	    if (QMessageBox::warning(this,
		      tr("Copy file"),
		      tr("Copying")+"\n"+(*it)+"\n-->"+dst+"\n"+tr("failed, continue?"),
		      QMessageBox::Ok,
		      QMessageBox::Abort) == QMessageBox::Abort) {
	       if (m_itemOnDragEnter) resetDrag();
	       return;
	    }
	 } else copied = TRUE;
      }
   }

   m_pDropDir = NULL;
   if (m_itemOnDragEnter && !copied) resetDrag();
}

//----------------------------------------------------------------------------

void CvsDirListView::moveCvsFiles() {
   assert(m_pDropDir);
   QStringList moveFiles;
   for (QStringList::Iterator it = m_DropStringList.begin(); it != m_DropStringList.end(); ++it) {
      QString dst = m_pDropDir->fullName()+(*it).mid( (*it).findRev("/"));
      if (QFileInfo(dst).exists()) {
	 int res = QMessageBox::warning(this,
	       tr("Move file(s)"),
	       tr("File exists")+": "+dst+"\n"+tr("skip?"),
	       QMessageBox::Ok,
	       QMessageBox::Abort);
	 if (res == QMessageBox::Abort) {
	    if (m_itemOnDragEnter) resetDrag();
	    return;
	 }
	 else continue;
      } else {
	 QFileInfo fInfo(*it);
	 int permission = 0;
	 if (fInfo.isReadable()) permission = (permission | READABLE);
	 if (fInfo.isWritable()) permission = (permission | WRITEABLE);
	 if (fInfo.isExecutable()) permission = (permission | EXECUTABLE);
	 if (!m_pDropDir->copyFile(*it,dst,permission,TRUE)) {
	    if (QMessageBox::warning(this,
		      tr("Move file(s)"),
		      tr("Moving")+"\n"+(*it)+"\n-->"+dst+"\n"+tr("failed, continue?"),
		      QMessageBox::Ok,
		      QMessageBox::Abort) == QMessageBox::Abort) {
	       if (m_itemOnDragEnter) resetDrag();
	       return;
	    }
	 } else {
	    moveFiles.append(*it);
	 }
      }
   }
   if (!moveFiles.isEmpty()) {
      emit moveCvsFiles(m_pDropDir->fullName(),moveFiles);
   } else  if (m_itemOnDragEnter) resetDrag();

   m_pDropDir = NULL;
   m_DropStringList.clear();
}

//----------------------------------------------------------------------------

void CvsDirListView::copyCvsFilesAscii() {
   copyCvsFiles(FALSE);
}

void CvsDirListView::copyCvsFilesBinary() {
   copyCvsFiles(TRUE);
}

void CvsDirListView::copyCvsFiles(bool binary) {
   assert(m_pDropDir);
   QStringList files;
   for (QStringList::Iterator it = m_DropStringList.begin(); it != m_DropStringList.end(); ++it) {
      QString dst = m_pDropDir->fullName()+(*it).mid( (*it).findRev("/"));
      if (QFileInfo(dst).exists()) {
	 int res = QMessageBox::warning(this,
	       tr("Copy file(s)"),
	       tr("File exists")+": "+dst+"\n"+tr("skip?"),
	       QMessageBox::Ok,
	       QMessageBox::Abort);
	 if ( res== QMessageBox::Abort) {
	    if (m_itemOnDragEnter) resetDrag();
	    return;
	 } else {
	    continue;
	 }
      } else {
	 QFileInfo fInfo(*it);
	 int permission = 0;
	 if (fInfo.isReadable()) permission = (permission | READABLE);
	 if (fInfo.isWritable()) permission = (permission | WRITEABLE);
	 if (fInfo.isExecutable()) permission = (permission | EXECUTABLE);
	 if (!m_pDropDir->copyFile(*it,dst,permission)) {
	    if (QMessageBox::warning(this,
		      tr("Copy file(s)"),
		      tr("Copying")+"\n"+(*it)+"\n-->"+dst+"\n"+tr("failed, continue?"),
		      QMessageBox::Ok,
		      QMessageBox::Abort) == QMessageBox::Abort) {
	       if (m_itemOnDragEnter) resetDrag();
	       return;
	    }
	 } else {
	    files.append( m_pDropDir->fullName()+(*it).mid( (*it).findRev("/")) );
	 }
      }
   }
   if (!files.isEmpty()) {
      emit addCvsFiles(files,binary);
   } else if (m_itemOnDragEnter) resetDrag();

   m_pDropDir = NULL;
   m_DropStringList.clear();
}

//----------------------------------------------------------------------------

bool CvsDirListView::validate(GuardedDir & dir) {
   if (!dir) {
      DirBase * d = NULL;
      if ( !(d = find(dir.getGuardedName())) ) return false;
      dir.reassignDir(d);
   }
   return true;
}

//----------------------------------------------------------------------------

void CvsDirListView::setStatusBarText( const QString & txt, int ms) {
   emit setStatusText( txt, ms);
}



syntax highlighted by Code2HTML, v. 0.9.1