Fixed menu->quit
[shopper.git] / src / ui / mainwindow.cc
blob1e9cc94609c6cf116784b3bb86b16ce8e16b0711
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
21 #define DEBUG_SHOPPER 1
22 #include "shopper.h" // automake, i8n, gettext
24 #include "mainwindow.h"
25 #include "CatListModel.h"
26 #include "CategoryDialog.h"
27 #include "ItemDialog.h"
28 #include "notify.h"
30 // Global variable
31 Shopper::Notify *notify;
33 // class MainWindow : public QMainWindow
34 MainWindow::MainWindow(QString file) :
35 mylist(NULL),
36 lv(NULL),
37 filename(file),
38 full_screen(false),
39 catCombo(NULL),
40 has_rotation(false)
42 init_MainWindow(NULL);
44 MainWindow::MainWindow(Shopper::List &l) :
45 mylist(NULL),
46 lv(NULL),
47 filename(""),
48 full_screen(false),
49 catCombo(NULL),
50 has_rotation(false)
52 init_MainWindow(&l);
55 void MainWindow::init_MainWindow(Shopper::List *l)
57 // The constructor handles only 'one off' stuff - main menu,
58 // buttons etc. Anything List specific is seperated off to
59 // handle_list() so it can be reused when opening new lists
61 // xrandr detection from adv-backlight...
62 #ifdef XRANDR
63 Display *dpy;
64 int xrr_event_base, xrr_error_base;
65 int xrr_major, xrr_minor;
66 dpy = XOpenDisplay (NULL);
67 if (dpy == NULL)
69 DEBUG("Couldn't open display\n");
70 has_rotation = false;
71 } else {
72 if (XRRQueryExtension (dpy, &xrr_event_base, &xrr_error_base) == false
73 || XRRQueryVersion (dpy, &xrr_major, &xrr_minor) == 0 || xrr_major != 1 || xrr_minor < 1)
74 has_rotation = false;
75 else
76 has_rotation = true;
77 XCloseDisplay (dpy);
79 #endif
80 // Actions
81 // UI components
82 QAction *addItemAct = new QAction(qApp->style()->standardIcon(QStyle::SP_FileIcon),
83 tr("Add Item"), this);
84 addItemAct->setStatusTip(tr("Add an item to the list"));
85 connect(addItemAct, SIGNAL(triggered()), this, SLOT(on_action_add_item()));
87 QAction *manageCatAct = new QAction(qApp->style()->standardIcon(QStyle::SP_DirIcon),
88 tr("Manage Categories"), this);
89 manageCatAct->setStatusTip(tr("Manage the list of categories"));
90 connect(manageCatAct, SIGNAL(triggered()), this, SLOT(on_action_manage_category()));
92 QAction *clearWantedAct = new QAction(qApp->style()->standardIcon(QStyle::SP_FileDialogListView),
93 tr("Clear Wanted"), this);
94 clearWantedAct->setStatusTip(tr("Clear the items marked as 'wanted'"));
95 connect(clearWantedAct, SIGNAL(triggered()), this, SLOT(on_action_clear_wanted()));
97 QAction *emptyBasketAct = new QAction(qApp->style()->standardIcon(QStyle::SP_FileDialogListView),
98 tr("Empty Basket"), this);
99 emptyBasketAct->setStatusTip(tr("Clear the items marked as 'in the basket'"));
100 connect(emptyBasketAct, SIGNAL(triggered()), this, SLOT(on_action_clear_bought()));
102 QAction *fullListAct = new QAction(qApp->style()->standardIcon(QStyle::SP_FileDialogListView),
103 tr("Out Shopping: Full List"), this);
104 fullListAct->setStatusTip(tr("Show the full list (items in the basket will be visible and ticked)"));
105 connect(fullListAct, SIGNAL(triggered()), this, SLOT(on_action_fullList()));
107 QAction *whatsLeftAct = new QAction(qApp->style()->standardIcon(QStyle::SP_FileDialogListView),
108 tr("Out Shopping: What's Left"), this);
109 whatsLeftAct->setStatusTip(tr("Show what's left to get"));
110 connect(whatsLeftAct, SIGNAL(triggered()), this, SLOT(on_action_whatsLeft()));
112 QAction *makingListAct = new QAction(qApp->style()->standardIcon(QStyle::SP_FileDialogListView),
113 tr("Making List"), this);
114 makingListAct->setStatusTip(tr("Pick items to get when you go shopping"));
115 connect(makingListAct, SIGNAL(triggered()), this, SLOT(on_action_makingList()));
117 QAction *newAct = new QAction(qApp->style()->standardIcon(QStyle::SP_FileDialogListView),
118 tr("New List"), this);
119 newAct->setStatusTip(tr("Add an item to the list"));
120 connect(newAct, SIGNAL(triggered()), this, SLOT(on_action_file_new()));
122 QAction *openAct = new QAction(qApp->style()->standardIcon(QStyle::SP_DialogOpenButton),
123 tr("Open List"), this);
124 openAct->setStatusTip(tr("Open a new list"));
125 connect(openAct, SIGNAL(triggered()), this, SLOT(on_action_file_open()));
127 QAction *saveAct = new QAction(qApp->style()->standardIcon(QStyle::SP_DialogSaveButton),
128 tr("Save List"), this);
129 saveAct->setStatusTip(tr("Save the list"));
130 connect(saveAct, SIGNAL(triggered()), this, SLOT(on_action_file_save()));
132 QAction *saveAsAct = new QAction(qApp->style()->standardIcon(QStyle::SP_DialogSaveButton),
133 tr("Save List As..."), this);
134 saveAsAct->setStatusTip(tr("Save the list with a new name"));
135 connect(saveAsAct, SIGNAL(triggered()), this, SLOT(on_action_file_saveas()));
137 QAction *quitAct = new QAction(qApp->style()->standardIcon(QStyle::SP_BrowserStop),
138 tr("Quit"), this);
139 quitAct->setStatusTip(tr("Finish"));
140 connect(quitAct, SIGNAL(triggered()), this, SLOT(on_action_file_quit()));
142 QAction *aboutAct = new QAction(qApp->style()->standardIcon(QStyle::SP_MessageBoxInformation),
143 tr("About..."), this);
144 aboutAct->setStatusTip(tr("About Shopper..."));
145 connect(aboutAct, SIGNAL(triggered()), this, SLOT(on_action_about()));
147 // Defined in class to be available elsewhere
148 nextAct = new QAction(qApp->style()->standardIcon(QStyle::SP_MediaSkipForward),
149 tr("Next Category"), this);
150 nextAct->setStatusTip(tr("View the next category"));
151 connect(nextAct, SIGNAL(triggered()), this, SLOT(on_action_next()));
153 QAction *prevAct = new QAction(qApp->style()->standardIcon(QStyle::SP_MediaSkipBackward),
154 tr("Prev Category"), this);
155 prevAct->setStatusTip(tr("View the previous category"));
156 connect(prevAct, SIGNAL(triggered()), this, SLOT(on_action_prev()));
158 // Menus
159 menuBar()->addAction(addItemAct);
160 menuBar()->addAction(manageCatAct);
162 QMenu *clearMenu = menuBar()->addMenu(tr("Clear List"));
163 clearMenu->addAction(clearWantedAct);
164 clearMenu->addAction(emptyBasketAct);
166 QMenu *modeMenu = menuBar()->addMenu(tr("Mode"));
167 modeMenu->addAction(fullListAct);
168 modeMenu->addAction(whatsLeftAct);
169 modeMenu->addAction(makingListAct);
171 menuBar()->addSeparator();
173 QMenu *fileMenu = menuBar()->addMenu(tr("File"));
174 fileMenu->addAction(newAct);
175 fileMenu->addAction(openAct);
176 fileMenu->addAction(saveAct);
177 fileMenu->addAction(saveAsAct);
178 fileMenu->addAction(quitAct);
180 QMenu *helpMenu = menuBar()->addMenu(tr("Help"));
181 helpMenu->addAction(aboutAct);
183 // Toolbar
184 buttonBar = addToolBar(tr("Buttons"));
185 addToolBar(Qt::BottomToolBarArea, buttonBar); // move it to the right area
186 buttonBar->addAction(addItemAct);
187 buttonBar->addAction(manageCatAct);
188 buttonBar->addSeparator();
189 buttonBar->addAction(fullListAct);
190 buttonBar->addAction(whatsLeftAct);
191 buttonBar->addAction(makingListAct);
192 buttonBar->addSeparator();
193 buttonBar->addAction(prevAct);
194 buttonBar->addAction(nextAct);
196 // Status
197 statusBar()->showMessage(tr("Ready"));
199 // Notify is a SystemTrayIcon used for notify messages
200 // Note this is a globally accessible object - nothing to do with MainWin except we parent it
201 notify=new Shopper::Notify(style()->standardIcon(QStyle::SP_FileDialogListView));
202 notify->show();
204 // size and position
205 readSettings();
207 // If we got a filename then read it in...
208 if (l == NULL) {
209 l = Shopper::List::from_file(filename);
210 if (l) { // If filename valid
211 create_list_view(l);
212 } else { // If filename wasn't read
213 on_action_file_new();
214 while (!mylist) { // mylist and list_view are done in a file_open()
215 DEBUG("Couldn't open " << filename << " for reading\n");
216 on_action_file_open();
217 // FIXME :: Popup dialog box and allow new/open
220 } else {
221 // Now do List specific stuff
222 create_list_view(l);
224 _LEAVE;
226 void MainWindow::create_list_view(Shopper::List *list)
228 // Remove the old listview... and any data
229 if (mylist) mylist->deleteLater();
230 if (lv) lv->deleteLater();
231 if (catCombo)
233 if (catCombo->model()) delete catCombo->model();
234 delete catCombo;
236 // and use a list and a new main shopperList widget
237 mylist = list;
238 lv = new Shopper::ListView(*list, this);
239 setCentralWidget(lv);
240 // GUI: set title, add the view, update the menu
241 setWindowTitle("Shopper:"+mylist->modeText());
242 // Make sure there's a menu to show to enable the popup functionality
244 catCombo = new QComboBox();
245 Shopper::CatListModel *clmodel = new Shopper::CatListModel(*mylist);
246 catCombo->setModel(clmodel);
247 catCombo->setModelColumn(1);
248 catCombo->setCurrentIndex(clmodel->currentIndex());
249 connect(catCombo, SIGNAL(activated(int)),
250 this, SLOT(cat_selected(int)));
251 connect(clmodel, SIGNAL(currentChanged(int)),
252 catCombo, SLOT(setCurrentIndex(int)));
253 buttonBar->insertWidget(nextAct, catCombo);
255 _LEAVE;
258 void MainWindow::cat_selected(int i)
260 _ENTER;
261 QVariant v = catCombo->itemData(catCombo->currentIndex());
262 Shopper::Category *c = v.value<Shopper::Category*>();
263 mylist->make_category_active(*c);
267 void MainWindow::closeEvent(QCloseEvent *event)
269 event->accept();
272 void MainWindow::on_action_about()
274 QMessageBox::about(this, tr("About Application"),
275 tr("The <b>Application</b> example demonstrates how to "
276 "write modern GUI applications using Qt, with a menu bar, "
277 "toolbars, and a status bar."));
281 void MainWindow::readSettings()
283 QSettings settings("dgreaves", "Shopper");
284 QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
285 QSize size = settings.value("size", QSize(400, 400)).toSize();
286 resize(size);
287 move(pos);
290 void MainWindow::writeSettings()
292 QSettings settings("dgreaves", "shopper");
293 settings.setValue("pos", pos());
294 settings.setValue("size", size());
297 // Action handlers
298 // Add item
299 void MainWindow::on_action_add_item()
301 Shopper::ItemAdd itemD(this, mylist);
302 if (itemD.exec() == QDialog::Accepted) {
303 DEBUG("\nADDED:\n");
307 void MainWindow::on_action_manage_category()
309 Shopper::CategoryManage catD(this, mylist);
310 catD.exec();
313 // Category cycle
314 void MainWindow::on_action_next(){ mylist->make_next_category_active(); }
315 void MainWindow::on_action_prev(){ mylist->make_prev_category_active(); }
317 // Clear List
318 void MainWindow::on_action_clear_wanted() { clear_list(CLEAR_WANTED); }
319 void MainWindow::on_action_clear_bought() { clear_list(CLEAR_BOUGHT); }
320 void MainWindow::clear_list(clear_list_mode m)
322 for (Shopper::List::pItemIter it = mylist->itemsI(); it != mylist->itemsEnd(); it++) {
323 (*it)->set_bought(false); // Always clear bought
324 if (m == CLEAR_WANTED) {
325 (*it)->set_wanted(false);
328 if (m == CLEAR_WANTED) {
329 set_state(Shopper::MAKING_LIST);
332 // Shopping mode
333 void MainWindow::on_action_fullList() { set_state(Shopper::OUT_SHOPPING); }
334 void MainWindow::on_action_whatsLeft() { set_state(Shopper::WHATS_LEFT); }
335 void MainWindow::on_action_makingList() { set_state(Shopper::MAKING_LIST); }
336 void MainWindow::set_state(Shopper::sState s)
338 Shopper::sState old = mylist->get_state();
339 mylist->set_state(s); // Set the state
340 if (s == Shopper::MAKING_LIST) { // And go to category '1'
341 if (mylist->get_active_category() == NULL) { // show category 1 rather than 'Everything'
342 mylist->make_category_active(**(mylist->categoriesI()));
345 // And go to category 'Everything' if switching to an 'out shopping' state.
346 if (s == Shopper::WHATS_LEFT || s == Shopper::OUT_SHOPPING) {
347 if (old == Shopper::MAKING_LIST) mylist->no_category_active();
349 setWindowTitle("Shopper:" + mylist->modeText());
351 ////////////////////////////////////////////////////////////////
352 // File Handling
353 void MainWindow::on_action_file_new()
355 // FIXME: This really ought to check if the user *WANTS* to save...
356 if (mylist)
357 on_action_file_save();
358 filename="";
359 create_list_view(new Shopper::List(
360 QString(
361 "<list name='Supermarket' state='0'>"
362 "<category name='Aisle 1 - Dairy'>"
363 "<item desc='Cheese' note='note, no smelly cheese' wanted='1' bought='0'/>"
364 "<item desc='Bacon' note='Extra needed for Gary&apos;s butties' wanted='1' bought='0'/>"
365 "</category>"
366 "<category name='Frozen'>"
367 "<item desc='Peas' note='' wanted='1' bought='0'/>"
368 "<item desc='Prawns' note='' wanted='1' bought='0'/>"
369 "</category>"
370 "<category name='Veg'>"
371 "<item desc='Potatoes' note='' wanted='0' bought='0'/>"
372 "<item desc='Brocolli' note='' wanted='1' bought='0'/>"
373 "</category>"
374 "</list>"
375 )));
376 notify->showMessage("Shopper", "Created a sample shopping list");
378 void MainWindow::on_action_file_open()
380 // Get a filename
381 QFileDialog dialog(this);
382 QString dir = HOME_DIR+(filename==""?DEFAULT_LIST:filename);
383 //Handle the response:
384 if ((filename = dialog.getOpenFileName(this, "Select a list",dir, tr("Lists (*.xml)")))
385 != "") {
386 // Open file and create a view from it.
387 create_list_view(Shopper::List::from_file(filename));
388 save_filename(filename); // FIXME this should be on success
389 } else {
390 if (mylist == NULL) on_action_file_new(); // If CANCEL pressed and there's no list, make a new one
394 ////////////////////////////////////////////////////////////////
395 void MainWindow::on_action_file_save()
397 DEBUG("Saving....\n");
398 if (filename=="") {
399 on_action_file_saveas();
400 } else {
401 mylist->to_file(filename);
404 void MainWindow::on_action_file_saveas()
406 // Get a filename
407 QFileDialog dialog(this);
408 QString dir = HOME_DIR+(filename==""?DEFAULT_LIST:filename);
409 //Handle the response:
410 if ((filename = dialog.getSaveFileName(this, "Save list as", dir, tr("Lists (*.xml)")))
411 != "") {
412 // Open file and create a view from it.
413 save_filename(filename);
414 mylist->to_file(filename);
417 void MainWindow::on_action_file_quit()
419 on_action_file_save();
420 // FIXME
421 close(); //Closes the main window to stop the Gtk::Main::run().
424 bool MainWindow::on_signal_window_closed()
426 on_action_file_quit();
427 return true; // propogate signal so hide() happens
430 bool MainWindow::on_key_pressed()
433 if(!event)
434 return false;
436 switch (event->keyval)
438 case GDK_Up:
439 case GDK_Down:
440 case GDK_Left:
441 case GDK_Right:
442 case GDK_Return:
443 case GDK_Escape:
444 case GDK_F4: // Menu
445 case GDK_F5: // Home
446 break;
447 case GDK_F6: // Fullscreen
448 on_action_fullscreen();
449 return true;
450 case GDK_F7: // Zoom in
451 case GDK_F8: // Zoom out
452 default:
453 break;
456 // Returning true would stop the event now
457 return false;
461 void MainWindow::on_action_fullscreen()
463 if (full_screen){
464 // unfullscreen(); // gtk
465 } else {
466 // fullscreen(); // gtk
468 full_screen = !full_screen;
470 void MainWindow::save_filename(QString name)
472 DEBUG("Save "<<name);
475 void MainWindow::on_action_rotate()
477 if (! has_rotation) return;
479 XRRScreenConfiguration *scr_config;
480 // Rotation current_rotation;
481 int size;
482 // int i;
483 Display *dpy;
484 int screen;
486 dpy = XOpenDisplay (NULL);
487 screen = DefaultScreen (dpy);
488 scr_config = XRRGetScreenInfo (dpy, RootWindow (dpy, screen));
489 size = XRRConfigCurrentConfiguration (scr_config, &rotation);
491 if (rotation == RR_Rotate_0) {
492 rotation = RR_Rotate_90;
493 } else {
494 rotation = RR_Rotate_0; // always rotate back to 0
497 XRRSetScreenConfig (dpy, scr_config, RootWindow (dpy, screen), size, rotation, CurrentTime);
498 XRRFreeScreenConfigInfo (scr_config);
499 XCloseDisplay (dpy);
503 void MainWindow::on_action_help()