not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / plasma / applets / tasks / layoutwidget.cpp
blob3366bd9905b9752e7224035a976d066d94714a9a
1 #include "layoutwidget.h"
3 //Taskmanager
4 #include <taskmanager/taskmanager.h>
5 #include <taskmanager/abstractgroupableitem.h>
6 #include <taskmanager/groupmanager.h>
8 // Qt
9 #include <QList>
10 #include <QGraphicsScene>
11 #include <QGraphicsGridLayout>
12 #include <QPainter>
14 #include <math.h>
16 #include "windowtaskitem.h"
17 #include "taskgroupitem.h"
20 //GroupItem Constructor
21 LayoutWidget::LayoutWidget(TaskGroupItem *parent, Tasks *applet)
22 : QObject(parent),
23 m_hasSpacer(false),
24 m_spacer(0),
25 m_groupItem(parent),
26 m_rowSize(1),
27 m_maxRows(1),
28 m_forceRows(false),
29 m_applet(applet),
30 m_layout(0)
32 init();
33 //kDebug();
34 foreach(AbstractTaskItem *item, m_groupItem->memberList()) {
35 addTaskItem(item);
39 LayoutWidget::~LayoutWidget()
41 //kDebug();
45 void LayoutWidget::init()
47 createLayout();
48 //calculatePreferredRowSize();
52 void LayoutWidget::constraintsChanged(Plasma::Constraints constraints)
54 Q_ASSERT(m_applet);
55 //kDebug();
57 if (constraints & Plasma::SizeConstraint) {
58 layoutItems();
62 void LayoutWidget::addTaskItem(AbstractTaskItem * item)
64 //kDebug();
65 if (!item) {
66 kDebug() << "invalid item";
67 return;
69 if (m_itemPositions.contains(item)) {
70 kDebug() << "already in this layout";
71 return;
73 if (item->abstractItem()) {
74 if (item->abstractItem()->isGroupItem()) {
75 connect(static_cast<TaskGroupItem*>(item), SIGNAL(changed()), this, SLOT(update())); //update on expanding group
78 if (m_groupItem->scene() && !item->scene()) {
79 //kDebug() << "layout widget got scene"<<m_groupItem->scene()<< "add item to scene" <<item->scene();
80 m_groupItem->scene()->addItem(item);
81 //kDebug() << "itemScene" << item->scene();
84 if (!insert(m_groupItem->indexOf(item), item)) {
85 kDebug() << "error on insert";
86 return;
88 item->show();
89 //kDebug() << "end";
92 void LayoutWidget::removeTaskItem(AbstractTaskItem * item)
94 if (!remove(item)) {
95 return;
98 //kDebug();
100 if (m_groupItem->scene()) {
101 //kDebug() << "got scene";
102 m_groupItem->scene()->removeItem(item);
103 } else {
104 kDebug() << "No Scene available";
106 //kDebug() << "done";
109 bool LayoutWidget::insert(int index, AbstractTaskItem* item)
111 //kDebug() << item->text() << index;
112 if (!item ) {
113 kDebug() << "error";
114 return false;
116 int listIndex;
117 for (listIndex = 0; listIndex < m_itemPositions.size(); listIndex++) {
118 if (index <= m_groupItem->indexOf(m_itemPositions.at(listIndex))) {
119 break;
123 m_itemPositions.insert(listIndex, item);
125 layoutItems();
126 return true;
129 bool LayoutWidget::remove(AbstractTaskItem* item)
131 if (!item) {
132 kDebug() << "null Item";
135 m_itemPositions.removeAll(item);
136 layoutItems();
137 return true;
140 void LayoutWidget::update()
142 //kDebug();
143 layoutItems();
147 /** size including expanded groups*/
148 int LayoutWidget::size()
150 int groupSize = 0;
152 foreach (AbstractTaskItem *item, m_groupItem->memberList()) {
153 if (!item->abstractItem()) { //this item is a startup task
154 kDebug() << "Error, invalid item in groupMembers";
155 continue;
158 if (item->abstractItem()->isGroupItem()) {
159 TaskGroupItem *group = static_cast<TaskGroupItem*>(item);
160 if (!group->collapsed()) {
161 LayoutWidget *layout = dynamic_cast<LayoutWidget*>(group->layoutWidget());
162 if (!layout) {
163 kDebug() << "Error group has no layout";
164 continue;
166 groupSize += layout->size();// increase number of items since expanded groups occupy several spaces
167 continue;
170 groupSize++;
173 //kDebug() << "group size" << groupSize;
174 return groupSize;
177 //return maximum colums set by the user unless the setting is to high and the items would get unusable
178 int LayoutWidget::maximumRows()
180 int maxRows;
181 if (m_itemPositions.isEmpty()) {
182 return 1;
185 if (m_forceRows) {
186 return m_maxRows;
189 // in this case rows are columns, columns are rows...
190 //TODO basicPreferredSize isn't the optimal source here because it changes because of margins probably
191 QSizeF itemSize = m_itemPositions.first()->basicPreferredSize();
192 if (m_applet->formFactor() == Plasma::Vertical) {
193 maxRows = qMin(qMax(1, int(m_groupItem->geometry().width() / itemSize.width())), m_maxRows);
194 } else {
195 maxRows = qMin(qMax(1, int(m_groupItem->geometry().height() / itemSize.height())), m_maxRows);
197 //kDebug() << "maximum rows: " << maxRows << m_maxRows << m_groupItem->geometry().height() << itemSize.height();
198 return maxRows;
201 //returns a reasonable amount of columns
202 int LayoutWidget::preferredColumns()
204 if (m_forceRows) {
205 m_rowSize = 1;
206 } else {
207 if (m_itemPositions.isEmpty()) {
208 return 1;
211 //TODO basicPreferredSize isn't the optimal source here because it changes because of margins probably
212 QSizeF itemSize = m_itemPositions.first()->basicPreferredSize();
213 //kDebug() << itemSize.width() << m_groupItem->geometry().width();
214 if (m_applet->formFactor() == Plasma::Vertical) {
215 m_rowSize = qMax(1, int(m_groupItem->geometry().height() / itemSize.height()));
216 } else {
217 m_rowSize = qMax(1, int(m_groupItem->geometry().width() / itemSize.width()));
220 //kDebug() << "preferred columns: " << qMax(1, qMin(m_rowSize, size()));
221 return qMax(1, qMin(m_rowSize, size()));
223 // <columns,rows>
224 QPair<int, int> LayoutWidget::gridLayoutSize()
226 int groupSize = size();
227 //the basic settings
228 int columns = preferredColumns();
229 int maxRows = maximumRows();
231 //check for adjustments on columns because there isnt room enough yet for all of the items
232 while (ceil(static_cast<float>(groupSize)/static_cast<float>(columns)) > maxRows) {
233 columns++; // more rows needed than allowed so we add some columns instead
235 //kDebug() << "groupWidth" << columns << maxRows << m_maxRows;
236 int rows;
237 if (m_forceRows) {
238 rows = maxRows;
239 } else {
240 rows = ceil(static_cast<float>(groupSize) / static_cast<float>(columns)); //actually needed rows
243 return QPair <int,int> (columns, rows);
246 void LayoutWidget::createLayout()
248 m_layout = new QGraphicsGridLayout(m_groupItem);
249 m_layout->setContentsMargins(0,0,0,0);
250 m_layout->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));
251 m_layout->setMaximumSize(INT_MAX,INT_MAX);
254 void LayoutWidget::layoutItems()
256 //kDebug();
258 QPair <int,int> grid = gridLayoutSize();
259 int columns = grid.first;
260 int rows = grid.second;
262 //kDebug() << "Laying out with" << columns << rows;
263 //kDebug() << "geometry" << m_groupItem->geometry();
264 int rowHeight = qMax(1, int(m_groupItem->geometry().height() / rows));
265 //kDebug() << "rowHeight" << rowHeight;
266 int columnWidth = qMax(1, int(m_groupItem->geometry().size().width() / columns));
267 //kDebug() << "column width set to " << columnWidth;
269 QSizeF maximumCellSize;
270 if (!m_itemPositions.isEmpty()) {
271 maximumCellSize = m_itemPositions.first()->basicPreferredSize() * 1.8;
274 createLayout(); //its a shame that we have to create a new layout every time but the QGraphicsGridLayout is just to buggy yet
276 if (m_applet->formFactor() == Plasma::Vertical) {
277 m_layout->setHorizontalSpacing(0);
278 m_layout->setVerticalSpacing(2);
279 } else {
280 m_layout->setHorizontalSpacing(2);
281 m_layout->setVerticalSpacing(0);
284 //go through all items of this layoutwidget and populate the layout with items
285 int numberOfItems = 0;
286 foreach (AbstractTaskItem *item, m_itemPositions) {
287 int row;
288 int col;
289 if (!m_forceRows) {
290 if (m_applet->formFactor() == Plasma::Vertical) {
291 row = numberOfItems % columns;
292 col = numberOfItems / columns;
293 } else {
294 row = numberOfItems / columns;
295 col = numberOfItems % columns;
298 } else {
299 if (m_applet->formFactor() == Plasma::Vertical) {
300 row = numberOfItems / rows;
301 col = numberOfItems % rows;
302 } else {
303 row = numberOfItems % rows;
304 col = numberOfItems / rows;
309 m_layout->setColumnPreferredWidth(col, columnWidth);//Somehow this line is absolutely crucial
310 m_layout->setRowPreferredHeight(row, rowHeight);//Somehow this line is absolutely crucial
312 if (maximumCellSize.isValid()) {
313 if (m_applet->formFactor() == Plasma::Vertical) {
314 m_layout->setRowMaximumHeight(row, maximumCellSize.height());
315 } else {
316 m_layout->setColumnMaximumWidth(col, maximumCellSize.width());
320 if (item->abstractItem() && item->abstractItem()->isGroupItem()) {
321 TaskGroupItem *group = static_cast<TaskGroupItem*>(item);
322 if (group->collapsed()) {
323 group->unsplitGroup();
324 m_layout->addItem(item, row, col, 1, 1);
325 } else {
326 LayoutWidget *layout = group->layoutWidget();
327 if (!layout) {
328 kDebug() << "group has no valid layout";
329 continue;
331 int groupRowWidth = layout->numberOfColumns();
333 if ((columns-col) < groupRowWidth) {//we need to split the group
334 int splitIndex = columns - col;//number of items in group that are on this row
335 TaskGroupItem *splitChild = group->splitGroup(splitIndex);
336 m_layout->addItem(item, row, col, 1, splitIndex); //Add the normal item
337 //kDebug() << "add normal item: split index = column span " << splitIndex;
338 if (splitChild) {
339 m_layout->addItem(splitChild, row + 1, 0, 1, groupRowWidth - splitIndex);//also add the second part of the group if there is one
341 //kDebug() << "add split item: column span " << groupRowWidth - splitIndex;
342 } else {
343 group->unsplitGroup();
344 m_layout->addItem(item, row, col, 1, groupRowWidth); //Add the normal item
345 //kDebug() << "add unsplit expanded item over columns " << groupRowWidth;
348 numberOfItems += groupRowWidth - 1;
350 } else {
351 m_layout->addItem(item, row, col, 1, 1);
354 //kDebug() << "addItem at: " << row << col;
355 numberOfItems++;
358 updatePreferredSize();
359 m_groupItem->setLayout(m_layout);
363 void LayoutWidget::updatePreferredSize()
365 //kDebug() << "column count: " << m_layout->columnCount();
367 if (m_layout->count() > 0) {
368 AbstractTaskItem *item = dynamic_cast<AbstractTaskItem *>(m_layout->itemAt(0));
369 Q_ASSERT(item);
370 m_layout->setPreferredSize(item->basicPreferredSize().width()*m_layout->columnCount(), item->basicPreferredSize().height()*m_layout->rowCount());
371 //Empty taskbar, arbitrary small value
372 } else {
373 kDebug() << "Empty layout!!!!!!!!!!!!!!!!!!";
374 if (m_applet->formFactor() == Plasma::Vertical) {
375 m_layout->setPreferredSize(/*m_layout->preferredSize().width()*/10, 10); //since we recreate the layout we don't have the previous values
376 } else {
377 m_layout->setPreferredSize(10, /*m_layout->preferredSize().height()*/10);
380 //kDebug() << "preferred size: " << m_layout->preferredSize();
381 emit sizeHintChanged(Qt::PreferredSize);
384 void LayoutWidget::setMaximumRows(int rows)
386 m_maxRows = rows;
389 void LayoutWidget::setForceRows(bool forceRows)
391 m_forceRows = forceRows;
394 int LayoutWidget::insertionIndexAt(const QPointF &pos)
396 int insertIndex = -1;
397 int row = numberOfRows();
398 int col = numberOfColumns();
400 //if pos is (-1,-1) insert at the end of the panel
401 if (pos.toPoint() == QPoint(-1, -1)) {
402 kDebug() << "Error";
403 return -1;
404 } else {
405 QRectF siblingGeometry;
407 //get correct row
408 for (int i = 0; i < numberOfRows(); i++) {
409 if (m_applet->formFactor() == Plasma::Vertical) {
410 siblingGeometry = m_layout->itemAt(0, i)->geometry();//set geometry of single item
411 if (pos.x() <= siblingGeometry.right()) {
412 row = i;
413 break;
415 } else {
416 siblingGeometry = m_layout->itemAt(i, 0)->geometry();//set geometry of single item
417 if (pos.y() <= siblingGeometry.bottom()) {
418 row = i;
419 break;
423 //and column
424 for (int i = 0; i < numberOfColumns(); i++) {
425 if (m_applet->formFactor() == Plasma::Vertical) {
426 siblingGeometry = m_layout->itemAt(i, 0)->geometry();//set geometry of single item
427 qreal vertMiddle = (siblingGeometry.top() + siblingGeometry.bottom()) / 2.0;
428 if (pos.y() < vertMiddle) {
429 col = i;
430 break;
433 } else {
434 siblingGeometry = m_layout->itemAt(0, i)->geometry();//set geometry of single item
435 qreal horizMiddle = (siblingGeometry.left() + siblingGeometry.right()) / 2.0;
436 //kDebug() << "pos middle " << pos.x() << horizMiddle;
437 if (pos.x() < horizMiddle) {
438 col = i;
439 break;
445 //kDebug() << row << col;
447 if (!m_forceRows) {
448 insertIndex = row * numberOfColumns() + col;
449 } else {
450 insertIndex = col * numberOfRows() + row;
453 if (insertIndex > m_layout->count()) {
454 insertIndex--;
455 //kDebug() << "correction";
458 //kDebug() << "insert Index" << insertIndex;
459 return insertIndex;
462 int LayoutWidget::numberOfRows()
464 if (m_applet->formFactor() == Plasma::Vertical) {
465 return m_layout->columnCount();
466 } else {
467 return m_layout->rowCount();
471 int LayoutWidget::numberOfColumns()
473 if (m_applet->formFactor() == Plasma::Vertical) {
474 return m_layout->rowCount();
475 } else {
476 return m_layout->columnCount();
481 #include "layoutwidget.moc"