Category dialog draws, moves, deletes - still needs popups to handle deleting items
[shopper.git] / src / shopperList.cc
blob16599dc25c1b7e0cb2fc0fdc0b09bc226a455524
1 /* Shopper
2 * Copyright (C) 2008 David Greaves
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 1
22 #include "shopper.h"
24 #include <iostream>
25 #include <sstream>
26 #include <string>
27 #include <fstream>
28 #include <list>
29 #include <set>
30 #include <algorithm>
31 #include <signal.h>
32 #include "shopperList.h"
34 using namespace std;
36 std::basic_ostream<char>& operator<<(std::basic_ostream<char>& os, const
37 QString& str) {
38 return os << qPrintable(str);
41 namespace Shopper
43 ////////////////////////////////////////////////////////////////
44 // Category
45 int Category::id_master = 0;
46 Category::Category(sparseCategory dummy) // SPARSE constructor for ListParser
48 Category::Category() :
49 id (Category::id_master++)
52 Category::Category(const Category &src)
54 DEBUG("\n\n\nCategory copy SCREAMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM\n\n\n");
55 exit(1);
57 Category::Category(QString name) :
58 id (Category::id_master++),
59 name(name)
61 Category::~Category()
63 emit deleted();
66 void Category::dbg() {
67 DEBUG("\nCat name : " << name <<
68 "\n id : " << id <<
69 "\n");
72 // Operator
73 bool operator< (const Category &a, const Category &b)
75 return (a.id < b.id);
77 bool cat_cmp (const Category *a, const Category *b)
79 return (a->id < b->id);
81 // cmp (user defined)
82 // bool user_cmp (const Category &a, const Category &b)
83 // {
84 // return (a.pos < b.pos);
85 // }
87 // accessors
88 QString Category::print_id()
90 return "id";
92 int Category::get_id() { return id; }
93 void Category::set_id(int i)
95 id = i;
96 emit changed();
98 void Category::set_name(QString n)
100 name = n;
101 emit changed();
103 QString Category::get_name() { return name; }
104 int Category::get_size() {
105 DEBUG("Category size is " << items.size() << "\n");
106 return items.size();
109 void Category::add(Item &it)
111 DEBUG("Category add item " << it.get_desc() << "\n");
112 items.push_back(&it);
114 void Category::rm(Item &it)
116 DEBUG("Category remove item " << it.get_desc() << "\n");
117 items.remove(&it);
121 Category::pItemIter Category::itemsI() {return items.begin();}
122 Category::pItemIter Category::itemsEnd(){return items.end();}
123 ////////////////////////////////////////////////////////////////
124 // Item
125 int Item::id_master = 0;
127 Item::Item(sparseItem dummy) : // SPARSE constructor for ListParser
128 id (Item::id_master++),
129 category (NULL)
131 Item::Item() :
132 id (Item::id_master++),
133 category (NULL)
136 Item::Item(Category &c, QString d, QString n, bool w, bool b) :
137 id (Item::id_master++),
138 category (&c),
139 desc (d),
140 note (n),
141 wanted (w),
142 bought (b)
144 DEBUG("Created an item from parts\n");
147 Item::~Item()
149 emit deleted();
152 void Item::dbg() {
153 DEBUG(
154 "\nItem desc : " << desc <<
155 "\n id : " << id <<
156 "\n note : " << note <<
157 "\n bought : " << (bought ? "true":"false") <<
158 "\n wanted : " << (wanted ? "true":"false") <<
159 "\n category : " << category->get_name() <<
160 "\n");
162 // accessors
163 QString Item::print_id(){return "id";}
164 int Item::get_id(){return id;}
165 void Item::set_id(int i){id=i;}
166 void Item::set_desc(QString d){
167 desc = d;
168 emit changed();
170 QString Item::get_desc(){return desc;}
172 void Item::set_note(QString n)
174 note = n;
175 emit changed();
177 QString Item::get_note(){return note;}
178 void Item::set_wanted(bool w)
180 if (wanted !=w) {
181 DEBUG("Wanted\n");
182 wanted =w;
183 emit changed();
186 bool Item::get_wanted(){return wanted;}
187 void Item::set_bought(bool b)
189 if (bought != b) {
190 DEBUG("Bought\n");
191 bought = b;
192 emit changed();
195 bool Item::get_bought(){return bought;}
196 void Item::set_category(Category *c){
197 category = c;
198 emit changed();
200 Category* Item::get_category(){return category;}
202 ////////////////////////////////////////////////////////////////
203 // List
205 List::List() :
206 name("Sainsburys"),
207 state(MAKING_LIST),
208 active_category(NULL)
210 // No items, no categories
211 DEBUG("\n\n\nMAKING NEW LIST\n\n\n");
213 List::List(QString dump)
215 DEBUG("\n\n\nMAKING NEW LIST FROM STRING\n\n\n");
216 ListParser parse(this);
217 parse.from_string(dump);
218 } // initiate from a dump
219 List::~List()
221 for(list<Category*>::iterator catI = categories.begin();
222 catI != categories.end(); ++catI) {
223 delete *catI;
225 for(list<Item*>::iterator itI = items.begin();
226 itI != items.end(); ++itI) {
227 delete *itI;
232 List* List::from_file(QString filename)
234 // open file
235 std::ifstream file(filename.toAscii());
236 if (!file) {
237 return NULL;
239 // Read xml as a stream
240 std::stringstream xml;
241 xml << file.rdbuf();
242 std::string sxml(xml.str());
243 QString qxml(sxml.c_str());
244 // Create new list and return it
245 return new Shopper::List(qxml); // FIXME: may not succeed.
248 void List::to_file(QString filename)
250 std::ofstream outf(filename.toAscii());
251 if (!outf) {
252 DEBUG("Couldn't open " << filename << " for writing\n");
253 exit(1);
255 outf << *this ;
258 List::operator QString() {return QString("XML here");} // a ustring representation of a List (XML)
260 // an ostream representation of a List (XML)
261 std::ostream& operator <<(std::ostream &out, const List &l)
263 DEBUG("in << operator\n");
264 // XMLWriter w(&l);
265 // DEBUG(w.write(cerr));
266 DEBUG("written XML\n");
267 // return w.write(out);
270 void List::add(Item &it)
272 if (categories.empty()) {
273 cerr << "Adding an item but there are no categories\n";
274 exit(1); // FIXME - is this a no-op or an exception or...
276 DEBUG("Add item " << it.get_desc() << "\n");
277 items.push_back(&it);
278 it.get_category()->add(it);
279 emit item_list_changed();
281 void List::rm(Item &it)
283 DEBUG("Remove item " << it.get_desc() << "\n");
284 items.remove(&it);
285 it.get_category()->rm(it);
286 emit item_list_changed();
287 delete &it;
290 void List::add(Category &cat)
292 DEBUG("Add category " << cat.get_name());
293 if (categories.empty())
295 DEBUG(" made active\n");
296 categories.push_back(&cat);
297 make_category_active(cat);
298 } else {
299 list<Category*>::iterator low = lower_bound(categories.begin(),categories.end(), &cat, &cat_cmp);
300 categories.insert(low, &cat);
301 resequence();
303 DEBUG("\n");
304 emit category_list_changed();
306 void List::rm(Category &cat)
308 if (categories.size() == 1) return;
309 DEBUG("Removing category\n");
310 if (is_category_active(cat)) cycle_active_category(true);
311 for(list<Item*>::iterator itemI = cat.items.begin();
312 itemI != cat.items.end(); itemI=cat.items.erase(itemI)) {
313 (**itemI).dbg();
314 DEBUG("Removing an item from list");
315 rm(**itemI);
317 categories.remove(&cat);
318 resequence();
319 emit category_list_changed();
320 delete &cat;
323 // accessors
324 QString List::get_name(){return name;}
325 void List::set_name(QString)
327 emit changed();
329 sState List::get_state(){
330 return state;
332 void List::set_state(sState s)
334 if (state != s){
335 state = s;
336 emit state_changed();
340 // Category filtering
341 Category* List::get_active_category()
343 return(active_category);
345 bool List::is_category_active(Category &c) // empty set = all active
347 return (active_category == NULL || active_category == &c);
348 // If using a set for multiple active categories
349 // return (active_categories.empty() || ( active_categories.find(c) != active_categories.end() ));;
351 void List::cycle_active_category(bool f)
353 List::pCategoryIter begin = categories.begin();
354 List::pCategoryIter end = categories.end();
355 if (active_category == NULL) { // use first or last element as 'next'
356 active_category = f ? *(begin) : *(categories.rbegin());
357 } else {
358 List::pCategoryIter c =
359 find(begin, end, active_category);
360 if (c == end) {
361 DEBUG("Not found - shouldn't happen\n");
362 exit(1);
364 if (f) {
365 active_category = (++c == end)?NULL:*c;
366 } else {
367 active_category = (c == begin)?NULL:*--c;
372 void List::make_next_category_active()
374 cycle_active_category(true);
375 emit active_category_changed();
377 void List::make_prev_category_active()
379 cycle_active_category(false);
380 emit active_category_changed();
382 void List::make_category_active(Category &c)
384 if (active_category != &c) {
385 active_category = &c;
386 // If using a set for multiple active categories
387 // active_categories.insert(c);
388 emit active_category_changed();
391 void List::make_category_inactive(Category &c)
393 if (active_category != NULL) {
394 active_category = NULL;
395 // If using a set for multiple active categories
396 // active_categories.erase(c);
397 emit active_category_changed();
400 void List::no_category_active()
402 if (active_category != NULL) {
403 active_category = NULL;
404 emit active_category_changed();
408 void List::resequence()
410 int id = 0;
411 for(list<Category*>::iterator catI = categories.begin();
412 catI != categories.end(); ++catI) {
413 (*catI)->set_id(id++);
416 void List::reorder()
418 categories.sort(&cat_cmp);
421 void List::swap_categories(Category *a, Category *b)
423 int a_id = a->get_id();
424 DEBUG("a id is : " << a->get_id()
425 << " b id is : " << b->get_id()
426 << "\n");
427 a->set_id(b->get_id());
428 DEBUG("Now set b\n");
429 b->set_id(a_id);
430 DEBUG("a id is : " << a->get_id()
431 << " b id is : " << b->get_id()
432 << "\n");
433 reorder();
434 DEBUG("Reorder done\n");
436 void List::swap_categories(int a, int b)
438 /*Category *c1 = cat_by_id[a];
439 Category *c2 = cat_by_id[b];
440 c1->set_id(b);
441 c2->set_id(a);
442 cat_by_id[a] = c2;
443 cat_by_id[b] = c1;
444 reorder();*/
447 QString List::modeText()
449 return modeText(state);
451 QString List::modeText(sState s)
453 switch (s) {
454 case WHATS_LEFT :
455 return(QString("What's Left"));
456 case OUT_SHOPPING:
457 return(QString("Full List"));
458 case MAKING_LIST:
459 return(QString("Making List"));
460 default:
461 return(QString("BAD State"));
464 List::pItemIter List::itemsI() { return items.begin(); }
465 List::pCategoryIter List::categoriesI(){ return categories.begin(); }
466 List::pItemIter List::itemsEnd() { return items.end(); }
467 List::pCategoryIter List::categoriesEnd(){ return categories.end(); }
469 void List::boughtNothing(){} // marks all items as not bought
470 void List::newList(){} // marks all items as not wanted