• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdenetwork API Reference
  • KDE Home
  • Contact Us
 

kopete/kopete

  • sources
  • kde-4.14
  • kdenetwork
  • kopete
  • kopete
  • config
  • appearance
  • layout
TokenDropTarget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (c) 2009 Thomas Lübking <thomas.luebking@web.de> *
3  * *
4  * This program is free software; you can redistribute it and/or modify *
5  * it under the terms of the GNU General Public License as published by *
6  * the Free Software Foundation; either version 2 of the License, or *
7  * (at your option) any later version. *
8  * *
9  * This program is distributed in the hope that it will be useful, *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12  * GNU General Public License for more details. *
13  * *
14  * You should have received a copy of the GNU General Public License *
15  * along with this program; if not, write to the *
16  * Free Software Foundation, Inc., *
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18  ***************************************************************************/
19 
20 #include "TokenDropTarget.h"
21 
22 #include "Token.h"
23 
24 #include <QDropEvent>
25 #include <QVBoxLayout>
26 
27 #include <QtDebug>
28 
33 class TokenDragger : public QObject
34 {
35 public:
36  TokenDragger( const QString &mimeType, TokenDropTarget *parent ) : QObject(parent), m_mimeType( mimeType )
37  {}
38 protected:
39  bool eventFilter( QObject *o, QEvent *e )
40  {
41  if ( e->type() == QEvent::MouseMove )
42  {
43  if ( static_cast<QMouseEvent*>(e)->buttons() & Qt::LeftButton )
44  return drag( qobject_cast<Token*>(o) );
45  }
46  else if ( e->type() == QEvent::MouseButtonPress )
47  {
48  if ( static_cast<QMouseEvent*>(e)->buttons() & Qt::LeftButton )
49  {
50  setCursor( qobject_cast<QWidget*>(o), Qt::ClosedHandCursor );
51 // m_startPos = me->pos(); // not sure whether i like this...
52 // else if ( event->button() == Qt::MidButton ) // TODO: really kick item on mmbc?
53  }
54  return false;
55  }
56  else if ( e->type() == QEvent::MouseButtonRelease )
57  {
58  if ( static_cast<QMouseEvent*>(e)->buttons() & Qt::LeftButton )
59  setCursor( qobject_cast<QWidget*>(o), Qt::OpenHandCursor );
60  return false;
61  }
62  else if ( e->type() == QEvent::FocusIn )
63  emit static_cast<TokenDropTarget*>( parent() )->focussed( qobject_cast<QWidget*>(o) );
64  else if ( e->type() == QEvent::Hide )
65  {
66  setCursor( qobject_cast<QWidget*>(o), Qt::OpenHandCursor );
67  return false;
68  }
69  return false;
70  }
71 
72 private:
73  bool drag( Token *token )
74  {
75  if ( !token )
76  return false;
77 
78  bool ret = false;
79  bool stacked = token->parentWidget() && qobject_cast<TokenDropTarget*>( token->parentWidget() );
80  if (stacked)
81  token->hide();
82 
83  QPixmap pixmap( token->size() );
84  token->render( &pixmap );
85  QDrag *drag = new QDrag( token );
86  QMimeData *data = new QMimeData;
87 
88  QByteArray itemData;
89  QDataStream dataStream( &itemData, QIODevice::WriteOnly );
90 // dataStream << child->name() << child->iconName() << child->value();
91 
92  data->setData( m_mimeType, itemData );
93  drag->setMimeData( data );
94  drag->setPixmap( pixmap );
95  drag->setHotSpot ( pixmap.rect().center() );
96 
97  Qt::DropAction dropAction = drag->exec( Qt::CopyAction | Qt::MoveAction, Qt::CopyAction );
98 
99  if ( stacked )
100  {
101  if ( dropAction != Qt::MoveAction && dropAction != Qt::CopyAction ) // dragged out
102  {
103  // TODO: nice poof animation? ;-)
104  delete token;
105  emit static_cast<TokenDropTarget*>( parent() )->changed();
106  ret = true; // THIS IS IMPORTANT
107  }
108  // anyway, tell daddy to wipe empty rows NOW
109  static_cast<TokenDropTarget*>(parent())->deleteEmptyRows();
110  }
111  return ret;
112  }
113  inline void setCursor( QWidget *w, Qt::CursorShape shape )
114  {
115  if ( !w )
116  return;
117  w->setCursor( shape );
118  }
119 private:
120  QString m_mimeType;
121  QPoint m_startPos;
122 };
123 
124 
125 TokenDropTarget::TokenDropTarget( const QString &mimeType, QWidget *parent ) : QWidget( parent ),
126 m_tokenDragger( new TokenDragger( mimeType, this ) ),
127 m_tokenFactory( new TokenFactory() )
128 {
129  new QVBoxLayout( this );
130  m_mimeType = mimeType;
131  m_limits[0] = m_limits[1] = 0;
132  // let daddy widget be droppable... ;)
133  parent->setAcceptDrops(true);
134  // ...and handle drop events for him
135  parent->removeEventFilter( this );
136  parent->installEventFilter( this );
137 
138  // visual, maybe there should be spacing? however, frames etc. can have contentmargin.
139  layout()->setSpacing( 0 );
140  // top-align content
141  layout()->addItem( new QSpacerItem( 1, 1, QSizePolicy::Expanding, QSizePolicy::MinimumExpanding ) );
142 }
143 
144 bool
145 TokenDropTarget::accept( QDropEvent *de )
146 {
147  if ( !de->mimeData()->hasFormat( m_mimeType ) )
148  {
149  de->ignore();
150  return false;
151  }
152 
153  if ( de->source() && parentWidget() && de->source()->parentWidget() == parentWidget() )
154  { // move
155  de->setDropAction(Qt::MoveAction);
156  de->accept();
157  }
158  else
159  de->acceptProposedAction();
160  return true;
161 }
162 
163 QHBoxLayout *
164 TokenDropTarget::appendRow()
165 {
166  QHBoxLayout *box = new QHBoxLayout;
167  box->setSpacing( 0 );
168  box->addStretch();
169  static_cast<QVBoxLayout*>(layout())->insertLayout( layout()->count() - 1, box ); // last item is a spacer
170  return box;
171 }
172 
173 QWidget *
174 TokenDropTarget::childAt( const QPoint &pos ) const
175 {
176  for ( int row = 0; row <= rows(); ++row )
177  if ( QHBoxLayout *rowBox = qobject_cast<QHBoxLayout*>( layout()->itemAt( row )->layout() ) )
178  for ( int col = 0; col < rowBox->count(); ++col )
179  if ( QWidget *kid = rowBox->itemAt( col )->widget() )
180  if ( kid->geometry().contains( pos ) )
181  return kid;
182  return NULL;
183 }
184 
185 void
186 TokenDropTarget::clear()
187 {
188  QLayoutItem *row, *col;
189  while( ( row = layout()->takeAt( 0 ) ) )
190  {
191  if ( QLayout *layout = row->layout() )
192  {
193  while( ( col = layout->takeAt( 0 ) ) )
194  {
195  delete col->widget();
196  delete col;
197  }
198  }
199  delete row;
200  }
201  //readd our spacer
202  layout()->addItem( new QSpacerItem( 1, 1, QSizePolicy::Expanding, QSizePolicy::MinimumExpanding ) );
203 }
204 
205 int
206 TokenDropTarget::count( int row ) const
207 {
208  int lower = 0, upper = rows();
209  if ( row > -1 && row < rows() )
210  {
211  lower = row;
212  upper = row + 1;
213  }
214 
215  int c = 0;
216  for ( row = lower; row < upper; ++row )
217  if ( QHBoxLayout *rowBox = qobject_cast<QHBoxLayout*>( layout()->itemAt( row )->layout() ) )
218  c += rowBox->count() - 1;
219  return c;
220 }
221 
222 void
223 TokenDropTarget::deleteEmptyRows()
224 {
225  QBoxLayout *box = 0;
226  for ( int row = 0; row <= rows(); )
227  {
228  box = qobject_cast<QBoxLayout*>( layout()->itemAt( row )->layout() );
229  if ( box && box->count() < 2 ) // sic! last is spacer
230  {
231  layout()->removeItem( box );
232  delete box;
233  }
234  else
235  ++row;
236  }
237 }
238 
239 QList< Token *>
240 TokenDropTarget::drags( int row )
241 {
242  int lower = 0, upper = rows();
243  if ( row > -1 && row < rows() )
244  {
245  lower = row;
246  upper = row + 1;
247  }
248 
249  QList< Token *> list;
250  Token *token;
251  for ( row = lower; row < upper; ++row )
252  if ( QHBoxLayout *rowBox = qobject_cast<QHBoxLayout*>( layout()->itemAt( row )->layout() ) )
253  {
254  for ( int col = 0; col < rowBox->count() - 1; ++col )
255  if ( ( token = qobject_cast<Token*>( rowBox->itemAt( col )->widget() ) ) )
256  list << token;
257  }
258 
259  return list;
260 }
261 
262 void
263 TokenDropTarget::drop( Token *token, const QPoint &pos )
264 {
265  if ( !token )
266  return;
267 
268  // unlayout in case of move
269  if ( QBoxLayout *box = rowBox( token ) )
270  box->removeWidget( token );
271  token->setParent( parentWidget() );
272 
273  QBoxLayout *box = 0;
274  if ( Token *brother = qobject_cast<Token*>( childAt( pos ) ) )
275  { // we hit a sibling, -> prepend
276  QPoint idx;
277  box = rowBox( brother, &idx );
278  if ( pos.x() > brother->geometry().x() + 2*brother->width()/3 )
279  box->insertWidget( idx.x() + 1, token );
280  else
281  box->insertWidget( idx.x(), token );
282  }
283  else
284  {
285  if ( rowLimit() && rows() >= (int)rowLimit() ) // we usually don't want more rows
286  box = qobject_cast<QBoxLayout*>( layout()->itemAt( rows() - 1 )->layout() );
287 
288  if ( !box )
289  {
290  box = rowBox( pos ); // maybe this is on an existing row
291  if ( !box )
292  box = appendRow();
293  }
294  int idx = ( box->count() > 1 && box->itemAt(0)->widget() &&
295  pos.x() < box->itemAt(0)->widget()->geometry().x() ) ? 0 : box->count() - 1;
296  box->insertWidget( idx, token ); // append to existing row
297  }
298  token->show();
299  emit changed();
300 }
301 
302 bool
303 TokenDropTarget::eventFilter( QObject *o, QEvent *ev )
304 {
305  Q_UNUSED( o )
306 
307  if ( ev->type() == QEvent::DragMove ||
308  ev->type() == QEvent::DragEnter )
309  {
310  accept( static_cast<QDropEvent*>( ev ) );
311  return false; // TODO: return accept boolean ?
312  }
313 
314 // if ( ev->type() == QEvent::DragLeave )
315  if ( ev->type() == QEvent::Drop )
316  {
317  QDropEvent *de = static_cast<QDropEvent*>( ev );
318  if ( accept( de ) )
319  {
320  Token *token = qobject_cast<Token*>( de->source() );
321  if ( !token )
322  {
323  QByteArray itemData = de->mimeData()->data( m_mimeType );
324  QDataStream dataStream(&itemData, QIODevice::ReadOnly);
325 
326  QString tokenName;
327  QString tokenIconName;
328  int tokenValue;
329  dataStream >> tokenName;
330  dataStream >> tokenIconName;
331  dataStream >> tokenValue;
332 
333  token = m_tokenFactory->createToken( tokenName, tokenIconName, tokenValue, this );
334  token->removeEventFilter( m_tokenDragger );
335  token->installEventFilter( m_tokenDragger );
336  token->setCursor( Qt::OpenHandCursor );
337  }
338  drop( token, de->pos() );
339  }
340  return false;
341  }
342  return false;
343 }
344 
345 void
346 TokenDropTarget::insertToken( Token *token, int row, int col )
347 {
348  QBoxLayout *box = 0;
349  if ( row > rows() - 1 )
350  box = appendRow();
351  else
352  box = qobject_cast<QBoxLayout*>( layout()->itemAt( row )->layout() );
353  token->setParent( parentWidget() );
354  if ( col < 0 || col > box->count() - 2 )
355  col = box->count() - 1;
356  box->insertWidget( col, token );
357  token->removeEventFilter( m_tokenDragger );
358  token->installEventFilter( m_tokenDragger );
359  token->setCursor( Qt::OpenHandCursor );
360 }
361 
362 int
363 TokenDropTarget::row( Token *token ) const
364 {
365  for ( int row = 0; row <= rows(); ++row )
366  {
367  QBoxLayout *box = qobject_cast<QBoxLayout*>( layout()->itemAt( row )->layout() );
368  if ( box && ( box->indexOf( token ) ) > -1 )
369  return row;
370  }
371  return -1;
372 }
373 
374 int
375 TokenDropTarget::rows() const
376 {
377  return layout()->count() - 1;
378 }
379 
380 QBoxLayout *
381 TokenDropTarget::rowBox( QWidget *w, QPoint *idx ) const
382 {
383  QBoxLayout *box = 0;
384  int col;
385  for ( int row = 0; row <= rows(); ++row )
386  {
387  box = qobject_cast<QBoxLayout*>( layout()->itemAt( row )->layout() );
388  if ( box && ( col = box->indexOf( w ) ) > -1 )
389  {
390  if ( idx )
391  {
392  idx->setX( col );
393  idx->setY( row );
394  }
395  return box;
396  }
397  }
398  return NULL;
399 }
400 
401 QBoxLayout *
402 TokenDropTarget::rowBox( const QPoint &pt ) const
403 {
404  QBoxLayout *box = 0;
405  for ( int row = 0; row <= rows(); ++row )
406  {
407  box = qobject_cast<QBoxLayout*>( layout()->itemAt( row )->layout() );
408  if ( !box )
409  continue;
410  for ( int col = 0; col < box->count(); ++col )
411  {
412  if ( QWidget *w = box->itemAt( col )->widget() )
413  {
414  const QRect &geo = w->geometry();
415  if ( geo.y() <= pt.y() && geo.bottom() >= pt.y() )
416  return box;
417  break; // yes - all widgets are supposed of equal height. we checked on, we checked all
418  }
419  }
420  }
421  return NULL;
422 }
423 
424 void
425 TokenDropTarget::setCustomTokenFactory( TokenFactory * factory )
426 {
427  delete m_tokenFactory;
428  m_tokenFactory = factory;
429 }
430 
QWidget::layout
QLayout * layout() const
QSpacerItem
QDropEvent::source
QWidget * source() const
QDrag::setHotSpot
void setHotSpot(const QPoint &hotspot)
QEvent
QWidget
QEvent::type
Type type() const
QLayout::itemAt
virtual QLayoutItem * itemAt(int index) const =0
QMimeData::data
QByteArray data(const QString &mimeType) const
QWidget::setCursor
void setCursor(const QCursor &)
QDropEvent::mimeData
const QMimeData * mimeData() const
QLayout::addItem
virtual void addItem(QLayoutItem *item)=0
QWidget::lower
void lower()
QDrag::setMimeData
void setMimeData(QMimeData *data)
QByteArray
TokenDropTarget::clear
void clear()
Definition: TokenDropTarget.cpp:186
TokenDropTarget::setCustomTokenFactory
void setCustomTokenFactory(TokenFactory *factory)
Definition: TokenDropTarget.cpp:425
QMimeData::hasFormat
virtual bool hasFormat(const QString &mimeType) const
QDataStream
QDrag::setPixmap
void setPixmap(const QPixmap &pixmap)
QLayoutItem::widget
virtual QWidget * widget()
QLayout
QDropEvent::pos
const QPoint & pos() const
QLayoutItem::layout
virtual QLayout * layout()
TokenDropTarget::childAt
QWidget * childAt(const QPoint &pos) const
Definition: TokenDropTarget.cpp:174
QHBoxLayout
QRect::y
int y() const
QPoint
QBoxLayout::count
virtual int count() const
TokenDropTarget::eventFilter
bool eventFilter(QObject *, QEvent *)
Definition: TokenDropTarget.cpp:303
TokenDropTarget
Definition: TokenDropTarget.h:32
QDropEvent::acceptProposedAction
void acceptProposedAction()
TokenDropTarget::count
virtual int count() const
Definition: TokenDropTarget.h:40
QWidget::setParent
void setParent(QWidget *parent)
QMimeData
QPoint::x
int x() const
QPoint::y
int y() const
TokenDropTarget::rowBox
QBoxLayout * rowBox(QWidget *w, QPoint *idx=0) const
Definition: TokenDropTarget.cpp:381
QLayoutItem
QWidget::geometry
geometry
QLayout::indexOf
virtual int indexOf(QWidget *widget) const
QDrag::exec
Qt::DropAction exec(QFlags< Qt::DropAction > supportedActions)
QWidget::size
size
QLayout::removeWidget
void removeWidget(QWidget *widget)
QRect
TokenDropTarget::deleteEmptyRows
void deleteEmptyRows()
Definition: TokenDropTarget.cpp:223
QEvent::ignore
void ignore()
TokenDropTarget::row
int row(Token *) const
Definition: TokenDropTarget.cpp:363
QObject::installEventFilter
void installEventFilter(QObject *filterObj)
QLayout::removeItem
void removeItem(QLayoutItem *item)
TokenDropTarget::rows
int rows() const
Definition: TokenDropTarget.cpp:375
QObject
QDropEvent
QDrag
QBoxLayout::itemAt
virtual QLayoutItem * itemAt(int index) const
QVBoxLayout
QDropEvent::setDropAction
void setDropAction(Qt::DropAction action)
QObject::eventFilter
virtual bool eventFilter(QObject *watched, QEvent *event)
QString
QList
QWidget::hide
void hide()
TokenDropTarget.h
QPixmap
QWidget::setAcceptDrops
void setAcceptDrops(bool on)
TokenDropTarget::TokenDropTarget
TokenDropTarget(const QString &mimeType, QWidget *parent=0)
Definition: TokenDropTarget.cpp:125
QBoxLayout::addStretch
void addStretch(int stretch)
QWidget::parentWidget
QWidget * parentWidget() const
TokenDropTarget::insertToken
void insertToken(Token *, int row=-1, int col=-1)
Definition: TokenDropTarget.cpp:346
QLayout::count
virtual int count() const =0
QRect::bottom
int bottom() const
QPoint::setX
void setX(int x)
QPoint::setY
void setY(int y)
TokenFactory::createToken
virtual Token * createToken(const QString &text, const QString &iconName, int value, QWidget *parent=0)
Definition: Token.cpp:29
QLayout::setSpacing
void setSpacing(int)
TokenFactory
Definition: Token.h:29
QBoxLayout::insertWidget
void insertWidget(int index, QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
QWidget::show
void show()
QMimeData::setData
void setData(const QString &mimeType, const QByteArray &data)
Token
Definition: Token.h:38
TokenDropTarget::drags
QList< Token * > drags(int row=-1)
Definition: TokenDropTarget.cpp:240
QObject::parent
QObject * parent() const
TokenDropTarget::changed
void changed()
QDropEvent::accept
void accept(bool accept)
QBoxLayout
QObject::removeEventFilter
void removeEventFilter(QObject *obj)
QBoxLayout::setSpacing
void setSpacing(int spacing)
TokenDropTarget::rowLimit
uint rowLimit() const
Definition: TokenDropTarget.h:45
QWidget::render
void render(QPaintDevice *target, const QPoint &targetOffset, const QRegion &sourceRegion, QFlags< QWidget::RenderFlag > renderFlags)
Token.h
QLayout::takeAt
virtual QLayoutItem * takeAt(int index)=0
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:29:08 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kopete/kopete

Skip menu "kopete/kopete"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdenetwork API Reference

Skip menu "kdenetwork API Reference"
  • kget
  • kopete
  •   kopete
  •   libkopete
  • krdc
  • krfb

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal