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
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"
31 Shopper::Notify
*notify
;
33 // class MainWindow : public QMainWindow
34 MainWindow::MainWindow(QString file
) :
42 init_MainWindow(NULL
);
44 MainWindow::MainWindow(Shopper::List
&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...
64 int xrr_event_base
, xrr_error_base
;
65 int xrr_major
, xrr_minor
;
66 dpy
= XOpenDisplay (NULL
);
69 DEBUG("Couldn't open display\n");
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)
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
),
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()));
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
);
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
);
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
));
207 // If we got a filename then read it in...
209 l
= Shopper::List::from_file(filename
);
210 if (l
) { // If filename valid
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
221 // Now do List specific stuff
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();
233 if (catCombo
->model()) delete catCombo
->model();
236 // and use a list and a new main shopperList widget
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
);
258 void MainWindow::cat_selected(int i
)
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
)
270 on_action_file_quit();
273 void MainWindow::on_action_about()
275 QMessageBox::about(this, tr("About Application"),
276 tr("The <b>Application</b> example demonstrates how to "
277 "write modern GUI applications using Qt, with a menu bar, "
278 "toolbars, and a status bar."));
282 void MainWindow::readSettings()
284 QSettings
settings("dgreaves.com", "Shopper");
285 QPoint pos
= settings
.value("pos", QPoint(200, 200)).toPoint();
286 QSize size
= settings
.value("size", QSize(400, 400)).toSize();
287 filename
= settings
.value("filename", filename
).toString();
292 void MainWindow::writeSettings()
294 QSettings
settings("dgreaves.com", "Shopper");
295 settings
.setValue("pos", pos());
296 settings
.setValue("size", size());
297 settings
.setValue("filename", filename
);
298 DEBUG("Wrote Settings");
303 void MainWindow::on_action_add_item()
305 Shopper::ItemAdd
itemD(this, mylist
);
306 if (itemD
.exec() == QDialog::Accepted
) {
311 void MainWindow::on_action_manage_category()
313 Shopper::CategoryManage
catD(this, mylist
);
318 void MainWindow::on_action_next(){ mylist
->make_next_category_active(); }
319 void MainWindow::on_action_prev(){ mylist
->make_prev_category_active(); }
322 void MainWindow::on_action_clear_wanted() { clear_list(CLEAR_WANTED
); }
323 void MainWindow::on_action_clear_bought() { clear_list(CLEAR_BOUGHT
); }
324 void MainWindow::clear_list(clear_list_mode m
)
326 for (Shopper::List::pItemIter it
= mylist
->itemsI(); it
!= mylist
->itemsEnd(); it
++) {
327 (*it
)->set_bought(false); // Always clear bought
328 if (m
== CLEAR_WANTED
) {
329 (*it
)->set_wanted(false);
332 if (m
== CLEAR_WANTED
) {
333 set_state(Shopper::MAKING_LIST
);
337 void MainWindow::on_action_fullList() { set_state(Shopper::OUT_SHOPPING
); }
338 void MainWindow::on_action_whatsLeft() { set_state(Shopper::WHATS_LEFT
); }
339 void MainWindow::on_action_makingList() { set_state(Shopper::MAKING_LIST
); }
340 void MainWindow::set_state(Shopper::sState s
)
342 Shopper::sState old
= mylist
->get_state();
343 mylist
->set_state(s
); // Set the state
344 if (s
== Shopper::MAKING_LIST
) { // And go to category '1'
345 if (mylist
->get_active_category() == NULL
) { // show category 1 rather than 'Everything'
346 mylist
->make_category_active(**(mylist
->categoriesI()));
349 // And go to category 'Everything' if switching to an 'out shopping' state.
350 if (s
== Shopper::WHATS_LEFT
|| s
== Shopper::OUT_SHOPPING
) {
351 if (old
== Shopper::MAKING_LIST
) mylist
->no_category_active();
353 setWindowTitle("Shopper:" + mylist
->modeText());
355 ////////////////////////////////////////////////////////////////
357 void MainWindow::on_action_file_new()
359 // FIXME: This really ought to check if the user *WANTS* to save...
361 on_action_file_save();
363 create_list_view(new Shopper::List(
365 "<list name='Supermarket' state='0'>"
366 "<category name='Aisle 1 - Dairy'>"
367 "<item desc='Cheese' note='note, no smelly cheese' wanted='1' bought='0'/>"
368 "<item desc='Bacon' note='Extra needed for Gary's butties' wanted='1' bought='0'/>"
370 "<category name='Frozen'>"
371 "<item desc='Peas' note='' wanted='1' bought='0'/>"
372 "<item desc='Prawns' note='' wanted='1' bought='0'/>"
374 "<category name='Veg'>"
375 "<item desc='Potatoes' note='' wanted='0' bought='0'/>"
376 "<item desc='Brocolli' note='' wanted='1' bought='0'/>"
380 notify
->showMessage("Shopper", "Created a sample shopping list");
382 void MainWindow::on_action_file_open()
385 QFileDialog
dialog(this);
386 QString dir
= HOME_DIR
+(filename
==""?DEFAULT_LIST
:filename
);
387 //Handle the response:
388 if ((filename
= dialog
.getOpenFileName(this, "Select a list",dir
, tr("Lists (*.xml)")))
390 // Open file and create a view from it.
391 create_list_view(Shopper::List::from_file(filename
));
392 writeSettings(); // FIXME this should be on success
394 if (mylist
== NULL
) on_action_file_new(); // If CANCEL pressed and there's no list, make a new one
398 ////////////////////////////////////////////////////////////////
399 void MainWindow::on_action_file_save()
401 DEBUG("Saving....\n");
403 on_action_file_saveas();
405 mylist
->to_file(filename
);
408 void MainWindow::on_action_file_saveas()
411 QFileDialog
dialog(this);
412 QString dir
= HOME_DIR
+(filename
==""?DEFAULT_LIST
:filename
);
413 //Handle the response:
414 if ((filename
= dialog
.getSaveFileName(this, "Save list as", dir
, tr("Lists (*.xml)")))
416 // Open file and create a view from it.
418 mylist
->to_file(filename
);
421 void MainWindow::on_action_file_quit()
423 on_action_file_save();
425 close(); //Closes the main window to quit
428 bool MainWindow::on_signal_window_closed()
430 on_action_file_quit();
431 return true; // propogate signal so hide() happens
434 bool MainWindow::on_key_pressed()
440 switch (event->keyval)
451 case GDK_F6: // Fullscreen
452 on_action_fullscreen();
454 case GDK_F7: // Zoom in
455 case GDK_F8: // Zoom out
460 // Returning true would stop the event now
465 void MainWindow::on_action_fullscreen()
468 // unfullscreen(); // gtk
470 // fullscreen(); // gtk
472 full_screen
= !full_screen
;
475 void MainWindow::on_action_rotate()
477 if (! has_rotation
) return;
479 XRRScreenConfiguration
*scr_config
;
480 // Rotation current_rotation;
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
;
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
);
503 void MainWindow::on_action_help()