1 /* Copyright 2009-2014 e-soul.org. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without modification, are permitted provided
4 * that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and
7 * the following disclaimer.
8 * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
9 * and the following disclaimer in the documentation and/or other materials provided with the
10 * distribution.
11 *
12 * THIS SOFTWARE IS PROVIDED BY E-SOUL.ORG ``AS IS'' AND ANY EXPRESS OR IMPLIED
13 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
14 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL E-SOUL.ORG
15 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
17 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
18 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
19 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
20 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
21 *
22 * The views and conclusions contained in the software and documentation are those of the authors and
23 * should not be interpreted as representing official policies, either expressed or implied, of e-soul.org.
24 */
25
26 #include <sstream>
27
28 #include <QSystemTrayIcon>
29 #include <QTimer>
30 #include <QStringList>
31 #include <QStringListModel>
32 #include <QListView>
33 #include <QPushButton>
34 #include <QVBoxLayout>
35 #include <QAction>
36 #include <QMenu>
37 #include <QMenuBar>
38 #include <QCloseEvent>
39 #include <QApplication>
40 #include <QMenu>
41
42 #include "Trac.hh"
43 #include "PortChecker.hh"
44 #include "PreferencesDialog.hh"
45
Trac()46 Trac::Trac()
47 {
48 // initialization
49 oldList = NULL;
50 model = new QStringListModel;
51 prefs = new Preferences;
52 prefs->load();
53
54 // UI initialization
55 checkNowButton = new QPushButton(tr("Check Now"));
56 QObject::connect(checkNowButton, SIGNAL(clicked()), this, SLOT(onCheckNow()));
57
58 QListView* listView = new QListView;
59 listView->setModel(model);
60
61 QLabel* listLabel = new QLabel(tr("There are updates for the following ports:"));
62 totalLabel = new QLabel(tr("Total: "));
63
64 QVBoxLayout *layout = new QVBoxLayout();
65 layout->addWidget(checkNowButton);
66 layout->addWidget(listLabel);
67 layout->addWidget(listView);
68 layout->addWidget(totalLabel);
69
70 QWidget* widget = new QWidget;
71 setCentralWidget(widget);
72 widget->setLayout(layout);
73
74 QMenu* programmeMenu = createProgrammeMenu();
75 initMenuBar(programmeMenu);
76 initTrayIcon(programmeMenu);
77 initTimer();
78 }
79
~Trac()80 Trac::~Trac()
81 {
82 }
83
onCheckNow()84 void Trac::onCheckNow()
85 {
86 check();
87 }
88
check()89 void Trac::check()
90 {
91 timer->stop();
92 checkNowButton->setEnabled(false);
93 checkNowButton->setText(tr("Checking, please wait..."));
94 //FIXME is a new port checker really needed?
95 pc = new PortChecker(prefs);
96 QObject::connect(pc, SIGNAL(finished()), this, SLOT(getList()));
97 pc->start(QThread::NormalPriority);
98 }
99
exitProgramme()100 void Trac::exitProgramme()
101 {
102 prefs->persist();
103 QApplication::quit();
104 }
105
closeEvent(QCloseEvent * event)106 void Trac::closeEvent(QCloseEvent *event)
107 {
108 hide();
109 event->ignore();
110 }
111
getList()112 void Trac::getList()
113 {
114 QStringList* list = pc->getList();
115 delete pc;
116 model->setStringList(*list);
117 bool newList = false;
118 if(oldList != NULL)
119 {
120 newList = !equal(list, oldList);
121 delete oldList;
122 }
123 else
124 {
125 newList = true;
126 }
127 oldList = list;
128 if(newList && !list->isEmpty())
129 {
130 trayIcon->showMessage(tr("Port updates"), tr("A new list of port updates is available."));
131 //FIXME remove hardcoded path
132 trayIcon->setIcon(QIcon(tr("/usr/local/share/portrac/updates-available.png")));
133 trayIcon->setToolTip(tr("Portrac: updates available"));
134 }
135 else if(list->isEmpty())
136 {
137 //FIXME remove hardcoded path
138 trayIcon->setIcon(QIcon(tr("/usr/local/share/portrac/up-to-date.png")));
139 trayIcon->setToolTip(tr("Portrac: up to date"));
140 }
141 timer->start(determineCheckInterval());
142 checkNowButton->setEnabled(true);
143 checkNowButton->setText(tr("Check Now"));
144
145 updateTotalLabel(list);
146 }
147
preferences()148 void Trac::preferences()
149 {
150 PreferencesDialog* pd = new PreferencesDialog(this, prefs);
151 pd->show();
152 /*
153 this dialog sets Qt::WA_DeleteOnClose
154 therefore no delete call needed
155 */
156 }
157
equal(QStringList * list1,QStringList * list2)158 bool Trac::equal(QStringList* list1, QStringList* list2)
159 {
160 if(list1->size() == list2->size())
161 {
162 for(int i = 0; i < list1->size(); i++)
163 {
164 if(list1->at(i).compare(list2->at(i)) != 0)
165 {
166 return false;
167 }
168 }
169 return true;
170 }
171 return false;
172 }
173
determineCheckInterval()174 int Trac::determineCheckInterval()
175 {
176 int multiplier = atoi(prefs->getPreference(CHECK_INTERVAL_PREF).c_str());
177 return DEFAULT_TIMER_INTERVAL * multiplier;
178 }
179
updateTotalLabel(QStringList * list)180 void Trac::updateTotalLabel(QStringList* list)
181 {
182 ostringstream oss("Total: ", ios_base::app);
183 oss << list->size();
184 QString tl(oss.str().c_str());
185 totalLabel->setText(tl);
186 }
187
createProgrammeMenu()188 QMenu* Trac::createProgrammeMenu()
189 {
190 QAction* preferencesAct = new QAction(tr("&Preferences"), this);
191 preferencesAct->setStatusTip(tr("Choose your preferences."));
192 QObject::connect(preferencesAct, SIGNAL(triggered()), this, SLOT(preferences()));
193
194 QAction* exitAct = new QAction(tr("&Exit"), this);
195 exitAct->setStatusTip(tr("Exit this programme."));
196 QObject::connect(exitAct, SIGNAL(triggered()), this, SLOT(exitProgramme()));
197
198 QMenu* programmeMenu = new QMenu(tr("&Programme"), menuBar());
199 programmeMenu->addAction(preferencesAct);
200 programmeMenu->addAction(exitAct);
201
202 return programmeMenu;
203 }
204
initMenuBar(QMenu * programmeMenu)205 void Trac::initMenuBar(QMenu* programmeMenu)
206 {
207 menuBar()->addMenu(programmeMenu);
208 }
209
trayActivated(QSystemTrayIcon::ActivationReason reason)210 void Trac::trayActivated(QSystemTrayIcon::ActivationReason reason)
211 {
212 if(reason == QSystemTrayIcon::Context)
213 {
214 trayIcon->contextMenu()->exec();
215 }
216 else
217 {
218 if(!isVisible()) {
219 show();
220 setWindowState(Qt::WindowActive);
221 } else {
222 hide();
223 }
224 }
225 }
226
initTrayIcon(QMenu * programmeMenu)227 void Trac::initTrayIcon(QMenu* programmeMenu)
228 {
229 trayIcon = new QSystemTrayIcon(this);
230 //FIXME remove hardcoded path
231 trayIcon->setIcon(QIcon(tr("/usr/local/share/portrac/portrac.png")));
232 trayIcon->setToolTip(tr("Portrac"));
233 trayIcon->setContextMenu(programmeMenu);
234 trayIcon->show();
235 QObject::connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
236 QObject::connect(trayIcon, SIGNAL(messageClicked()), this, SLOT(show()));
237 }
238
initTimer()239 void Trac::initTimer()
240 {
241 timer = new QTimer(this);
242 QObject::connect(timer, SIGNAL(timeout()), this, SLOT(check()));
243 timer->start(determineCheckInterval());
244 }
245