Move from SLabel to ActiveLabel
[shopper.git] / src / ui / CategoryDialog.cc
blob4800fcae79cc5cdf53c16adc9e65ddabd4e77a96
1 /* Shopper
2 * Copyright (C) 2008 David Greaves <david@dgreaves.com>
4 * This software is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 2.1 of
7 * the License, or (at your option) any later version.
9 * This software is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this software; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17 * 02110-1301 USA
20 //#define DEBUG_SHOPPER
21 #include "CategoryDialog.h"
22 #include "shopper.h" // automake, i8n, gettext
24 #include "shopperList.h"
25 #include "LabelEntry.h"
27 #include <QDesktopWidget>
28 #include <QToolButton>
29 #include <QPushButton>
30 #include <QVBoxLayout>
31 #include <QDialogButtonBox>
32 #include <QScrollArea>
33 #include <QObject>
34 #include <QStyle>
35 #include <QString>
36 #include <QLabel>
37 #include <QApplication>
39 namespace Shopper
41 struct CategoryDialog::Private {
42 // Data
43 Shopper::List *mylist;
44 Shopper::Category *mycat;
46 // UI
47 QFingerScrollArea *areaS;
48 QVBoxLayout *areaL;
49 QWidget *area;
52 ////////////////////////////////////////////////////////////////
53 // Public
54 CategoryManage::CategoryManage(QWidget * parent, Shopper::List* l) :
55 CategoryDialog(parent, l, 0)
58 ////////////////////////////////////////////////////////////////
59 // Private class CategoryDialog : public QDialog
60 CategoryDialog::CategoryDialog(QWidget * parent, Shopper::List* l, Shopper::Category* cat) :
61 QDialog(parent)
63 _ENTER;
64 p= new Private;
65 p->mylist = l;
66 p->mycat = cat;
67 p->area = 0;
68 // Make the dialog tall and not too wide.
69 resize(qApp->desktop()->screenGeometry().width()*70/100,
70 qApp->desktop()->screenGeometry().height()*90/100);
72 // Buttons
73 QDialogButtonBox* bbox = new QDialogButtonBox(Qt::Horizontal, this);
74 bbox->addButton(tr("Done"), QDialogButtonBox::AcceptRole);
75 connect(bbox, SIGNAL(accepted()), this, SLOT(accept()));
77 connect(bbox->addButton(tr("Add Category"), QDialogButtonBox::ActionRole),
78 SIGNAL(clicked()),
79 this, SLOT(add_category()));
81 // Scroll area with category views
82 p->areaS = new QFingerScrollArea(this);
83 p->areaS->setWidgetResizable(true);
85 // moved from update
86 p->area = new QWidget;
87 p->areaL = new QVBoxLayout(p->area);
88 p->area->setLayout(p->areaL); // set the layout and take parentage of all children
89 p->areaS->setWidget(p->area); // add area to the scroller
91 // Build them up
92 QVBoxLayout* vbox = new QVBoxLayout;
93 vbox->addWidget(p->areaS);
94 vbox->addWidget(bbox);
95 setLayout(vbox);
96 show();
97 // add the categories to the area.
98 update_area();
100 // Now connect the List's category_list_changed() signal to this object's updater
101 connect (l, SIGNAL(category_list_changed()),
102 this, SLOT(update_area()));
104 // When a category is added make sure the scroll area is in the right place
105 // and the CatView is focused. This needs to be a queued connection.
106 connect (this, SIGNAL(categoryAdded(CatView *)),
107 this, SLOT(highlightCategory(CatView *)), Qt::QueuedConnection);
110 CategoryDialog::~CategoryDialog()
112 delete p;
115 void CategoryDialog::update_area()
117 _ENTER;
118 // Clean up our old widgets
119 QObject *child;
120 QWidget *wChild;
121 foreach (child, p->area->children()){
122 if (child->isWidgetType()) {
123 wChild = static_cast<QWidget*>(child);
124 DEBUG("Kill a child " << child->metaObject()->className() );
125 p->areaL->removeWidget(wChild);
126 wChild->deleteLater();
130 // lots of these
131 CatView *cv;
132 int pos;
133 Shopper::List::pCategoryIter begin =p->mylist->categoriesI(),
134 end = p->mylist->categoriesEnd();
135 Shopper::List::pCategoryIter catI;
136 for(catI = begin, pos=0; catI != end; ++catI,++pos)
138 cv = new CatView(**catI, *(p->mylist), p->area);
139 p->areaL->addWidget(cv); // add CatView to the layout
140 connect(cv, SIGNAL(move_up()),
141 this, SLOT(move_up()));
142 connect(cv, SIGNAL(move_down()),
143 this, SLOT(move_down()));
144 if (catI == begin) cv->set_pos(pos,-1); // size of -1 won't be reached
146 cv->set_pos(pos-1,pos-1); // Now we know the end
149 void CategoryDialog::add_category()
151 _ENTER;
152 // Create a new category
153 p->mycat = new Shopper::Category("New Category");
154 p->mylist->add(*p->mycat);
155 p->mylist->make_category_active(*p->mycat);
157 // Give the scrollbar chance to update with all the new widgets
158 qApp->processEvents();
160 // Adding the category should update the area to include the new cv...
161 // so find it and emit a change which will be scheduled to occur from
162 // the event loop.
163 QObject *child;
164 foreach (child, p->area->children()){
165 if (child->isWidgetType()) {
166 CatView *cv;
167 cv = dynamic_cast<CatView *>(child);
168 if (cv && cv->get_cat() == p->mycat) {
169 emit categoryAdded(cv);
170 return;
176 void CategoryDialog::highlightCategory(CatView *cv)
178 cv->activate();
179 p->areaS->ensureWidgetVisible(cv);
182 #define DOWN_SCREEN 1
183 #define UP_SCREEN -1
184 void CategoryDialog::move_up()
186 _ENTER;
187 CatView *src = static_cast<CatView*>(this->sender());
188 move(src, UP_SCREEN);
190 void CategoryDialog::move_down()
192 _ENTER;
193 CatView *src = static_cast<CatView*>(this->sender());
194 move(src, DOWN_SCREEN);
196 void CategoryDialog::move(CatView* src, int direction)
198 _ENTER;
199 int pos = p->areaL->indexOf(src);
200 int max = p->areaL->count()-1;
201 DEBUG("src at pos=" << pos << "/"<<max<<" direction=" << direction);
203 if (direction == DOWN_SCREEN and pos == max) return; // moving 'down' the screen
204 if (direction == UP_SCREEN and pos == 0) return;
206 QLayoutItem *li = p->areaL->itemAt(pos+direction);
207 if (li == 0) {
208 DEBUG("No item found at pos=" << pos << " direction=" << direction);
209 return;
211 CatView *that = static_cast<CatView*>(p->areaL->itemAt(pos+direction)->widget());
212 Q_ASSERT(that != 0);
214 p->areaL->removeWidget(src);
215 p->areaL->insertWidget(pos+direction, src);
216 p->mylist->swap_categories(src->get_cat(), that->get_cat());
217 src->set_pos(pos+direction,max);
218 that->set_pos(pos,max);
219 p->area->show();
222 ////////////////////////////////////////////////////////////////
223 ////////////////////////////////////////////////////////////////
224 ////////////////////////////////////////////////////////////////
226 // The widget shows the state of a category
227 // it can move up or down and edits the relevant category.
228 struct CatView::Private {
229 LabelEntry *name;
230 // UI
231 QToolButton *up_b;
232 QToolButton *down_b;
234 // member data
235 Category *mycat;
236 List *mylist;
239 CatView::CatView(Category &cat, List &lst, QWidget *parent) :
240 QWidget(parent)
242 _ENTER;
243 p= new Private;
244 p->mycat = &cat;
245 p->mylist = &lst;
246 // UI
247 p->name = new LabelEntry(cat.get_name(), this);
248 p->up_b = new QToolButton(this);
249 p->up_b->setArrowType(Qt::UpArrow);
250 p->down_b = new QToolButton(this);
251 p->down_b->setArrowType(Qt::DownArrow);
252 QToolButton *del_b = new QToolButton(this);
253 del_b->setIcon(style()->standardIcon(QStyle::SP_TrashIcon));
254 QHBoxLayout *box = new QHBoxLayout(this);
256 box->addWidget(del_b);
257 box->addWidget(p->name,1);
258 box->addWidget(p->up_b);
259 box->addWidget(p->down_b);
260 setLayout(box);
262 // Respond to changing the label
263 connect(p->name, SIGNAL(changed()),
264 this, SLOT(name_changed()));
265 // Respond to del
266 connect(del_b, SIGNAL(clicked()),
267 this, SLOT(delete_category()));
268 // Respond to up
269 connect(p->up_b, SIGNAL(clicked()),
270 this, SIGNAL(move_up()));
271 // Respond to down
272 connect(p->down_b, SIGNAL(clicked()),
273 this, SIGNAL(move_down()));
275 // Make the container visible according to visibility logic
276 DEBUG("CatView created for " <<cat.get_name());
279 CatView::~CatView()
281 delete p;
284 void CatView::delete_category()
286 DEBUG("Delete Category");
288 // Message
289 QString l;
290 int s = p->mycat->get_size();
291 if (s > 0) {
292 l = "Category '" + p->mycat->get_name()
293 + "' has " + QString::number(s)
294 + " items. Delete them all? ";
295 } else {
296 l = "Delete empty category '" + p->mycat->get_name() + "'?";
299 QDialog dia(this);
300 dia.setWindowTitle("Are you sure?");
302 QVBoxLayout vbox(&dia);
303 QDialogButtonBox bbox(QDialogButtonBox::Yes | QDialogButtonBox::No, Qt::Horizontal, &dia);
304 connect(&bbox, SIGNAL(accepted()), &dia, SLOT(accept()));
305 connect(&bbox, SIGNAL(rejected()), &dia, SLOT(reject()));
306 vbox.addWidget(new QLabel(l, &dia));
307 vbox.addWidget(&bbox);
308 dia.setLayout(&vbox);
310 if (dia.exec() == QDialog::Accepted)
312 //FIX Hildon::Banner::show_information(*this, "Deleted category " + p->mycat->get_name());
313 p->mylist->rm(*p->mycat);
317 void CatView::name_changed()
319 p->mycat->set_name(p->name->getText());
321 void CatView::set_pos(int pos, int size)
323 _ENTER;
324 if (pos == 0) p->up_b->hide(); else p->up_b->show();
325 if (pos == size) p->down_b->hide(); else p->down_b->show();
326 show();
329 void CatView::activate()
331 _ENTER;
332 p->name->label_clicked();
335 Category * CatView::get_cat()
337 return p->mycat;