├── .gitignore
├── LICENSE
├── README.md
├── _config.yml
├── bin
├── Kalendar-beta-1.2.1-win32.rar
├── Kalendar-stable-2.8.2-x86_64
└── tools
│ ├── Add Facebook Event.sh
│ └── FBEventTool.jar
├── icon
├── kalendar.png
├── kalendar.xcf
└── kalendar_circle.png
├── screencast.gif
├── screenshot.png
├── screenshot2.png
└── src
├── Kalendar.pro
├── Kalendar.pro.user.3148a8b
├── main.cpp
├── model
├── category.h
├── date.h
└── event.h
├── persistence
├── pmanager.cpp
├── pmanager.h
├── securepmanager.cpp
└── securepmanager.h
├── test
├── Makefile
├── main.cpp
├── persistence
│ ├── pmanager_test.cpp
│ └── pmanager_test.h
├── test.cpp
├── test.h
└── util
│ ├── dateutil_test.cpp
│ ├── dateutil_test.h
│ ├── eventutil_test.cpp
│ └── eventutil_test.h
├── tools
├── .classpath
├── .project
├── .settings
│ └── org.eclipse.jdt.core.prefs
└── fbeventplugin
│ ├── FBEvent.java
│ ├── FBParser.java
│ └── MainWindow.java
├── util
├── dateutil.cpp
├── dateutil.h
├── eventutil.cpp
├── eventutil.h
├── linuxnotifymanager.cpp
├── linuxnotifymanager.h
├── notifymanager.h
├── pluginmanager.cpp
└── pluginmanager.h
└── view
├── categorydialog.cpp
├── categorydialog.h
├── categoryeditdialog.cpp
├── categoryeditdialog.h
├── categoryselectdialog.cpp
├── categoryselectdialog.h
├── customdialog.cpp
├── customdialog.h
├── eventdialog.cpp
├── eventdialog.h
├── monthview.cpp
├── monthview.h
├── qframe_extended.h
├── qlabel_event.cpp
├── qlabel_event.h
├── qpushbutton_extended.cpp
├── qpushbutton_extended.h
├── qwidget_extended.cpp
├── qwidget_extended.h
├── settings.cpp
├── settings.h
├── ui_categorydialog.h
├── ui_categoryeditdialog.h
├── ui_categoryselectdialog.h
├── ui_customdialog.h
├── ui_eventdialog.h
├── ui_kalendar.h
├── ui_monthview.h
├── ui_settings.h
└── view.h
/.gitignore:
--------------------------------------------------------------------------------
1 | src/Kalendar.pro.user
2 | *.gch
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 | {one line to give the program's name and a brief idea of what it does.}
635 | Copyright (C) {year} {name of author}
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | {project} Copyright (C) {year} {fullname}
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Kalendar
2 |
3 | 
4 |
5 | Kalendar is a cross-platform Gregorian calendar application written in C++ with the Qt5 library for the gui. This project **is not related** with KDE. I'm trying to keep Kalendar as simple as possible and I want to avoid annoying dependencies (so you can easly install it everywhere). This calendar is offline and it doesn't support synchronization with online calendars at the moment.
6 |
7 | The project was inspired by gnome-calendar, but I'm writing it from scratch.
8 |
9 | FEATURES:
10 | * Support multiple calendars (i.e. databases)
11 | * Manage your events
12 | * Manage your TODOs
13 | * Notify future events
14 | * iCal format support
15 | * External tools support (e.g. Facebook plugin)
16 | * Desktop Environment independent
17 |
18 | TODO:
19 | * External plugins support
20 | * Year view for long-term events
21 | * Add an encryption layer
22 | * Improve support for recurrent events
23 | * Implement search function
24 |
25 | *Warning:* This application isn't compatible with 32 bit systems (see: [year 2038 problem](https://en.wikipedia.org/wiki/Year_2038_problem) ), but you can make it compatible adding `#define BIT32` inside `event.h`.
26 |
27 | ### Screenshot
28 |
29 | Screenshot from Kalendar-stable-2.7
30 | 
31 |
32 | Screenshot from Kalendar-stable-2.0
33 | 
34 |
35 | ### Screencast
36 |
37 | Screencast from Kalendar-alpha-1.3-x86\_64 (**OLD**)
38 | 
39 |
40 | ### Motivations
41 | I need to schedule my time in a more efficient way. I don't like online calendars like google calendar for the privacy issues. I looked for some good calendar applications, but there are just a couple of such calendars. This is a shame, because linux exists from so many years and the users need to have a good calendar application. The two main calendar applications are: gnome-desktop and korganizer. Their problems are a lot of dependencies and complicated compilation. So, I decided to develop a simple but powerful calendar with painless compilation, without dependencies and desktop environment (almost) independent.
42 |
43 | ### Compilation
44 |
45 | You need to have `qmake`. In Fedora you can find it inside the `qt-devel` package.
46 |
47 | You need to install also `sqlite3` developer package. In Fedora the package is called `sqlite-devel`.
48 |
49 | After you've installed these packages, you can run `qmake` (or `qmake-qt5` in Fedora) inside the src folder and then the `make` command.
50 | You should get the Kalendar executable inside the same folder.
51 |
52 | Note: Kalendar will create the following folder: ~/kalendar, so remember to delete it if you decide to delete Kalendar.
53 |
54 | ### Further Notes
55 |
56 | In the `tools` folder, you can put **sh** or **bat** scripts that will be integrated in the tools menu of the application. The plugins at the moment are only external tools. They require to run `kalendar` without the absolute path, so (on linux) you should create the script `/bin/kalendar` with the following content:
57 |
58 | ```
59 | #! /bin/bash
60 | cd /absolute/path/to/the/bin/directory/
61 | ./Kalendar-version "$@"
62 | ```
63 | Remember to give the right permissions with `# chmod +x /bin/kalendar`. To see the effects of the plugins you may need to restart the application or refresh the view.
64 | If you create a desktop file, use `kalendar` for the **Exec** field.
65 |
66 | ### Tips
67 |
68 | If you right-click on an event, it'll be deleted. If you middle-click on an event, it'll be selected. Once an event is selected, you can move it with A (backward) or F (forward) keys and resize it using S and D keys. Press Canc to cancel the selection.
69 | Press **c** to easily switch among your calendars.
70 |
71 | ### License
72 | GPLv3+
73 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-tactile
--------------------------------------------------------------------------------
/bin/Kalendar-beta-1.2.1-win32.rar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/echo-devim/kalendar/f9bbb2d96300503476fb8110d7be6c2cc5c3cf80/bin/Kalendar-beta-1.2.1-win32.rar
--------------------------------------------------------------------------------
/bin/Kalendar-stable-2.8.2-x86_64:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/echo-devim/kalendar/f9bbb2d96300503476fb8110d7be6c2cc5c3cf80/bin/Kalendar-stable-2.8.2-x86_64
--------------------------------------------------------------------------------
/bin/tools/Add Facebook Event.sh:
--------------------------------------------------------------------------------
1 | SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
2 | java -jar $SCRIPTPATH/FBEventTool.jar
3 |
--------------------------------------------------------------------------------
/bin/tools/FBEventTool.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/echo-devim/kalendar/f9bbb2d96300503476fb8110d7be6c2cc5c3cf80/bin/tools/FBEventTool.jar
--------------------------------------------------------------------------------
/icon/kalendar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/echo-devim/kalendar/f9bbb2d96300503476fb8110d7be6c2cc5c3cf80/icon/kalendar.png
--------------------------------------------------------------------------------
/icon/kalendar.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/echo-devim/kalendar/f9bbb2d96300503476fb8110d7be6c2cc5c3cf80/icon/kalendar.xcf
--------------------------------------------------------------------------------
/icon/kalendar_circle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/echo-devim/kalendar/f9bbb2d96300503476fb8110d7be6c2cc5c3cf80/icon/kalendar_circle.png
--------------------------------------------------------------------------------
/screencast.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/echo-devim/kalendar/f9bbb2d96300503476fb8110d7be6c2cc5c3cf80/screencast.gif
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/echo-devim/kalendar/f9bbb2d96300503476fb8110d7be6c2cc5c3cf80/screenshot.png
--------------------------------------------------------------------------------
/screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/echo-devim/kalendar/f9bbb2d96300503476fb8110d7be6c2cc5c3cf80/screenshot2.png
--------------------------------------------------------------------------------
/src/Kalendar.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2016-03-09T17:50:52
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += core gui
8 |
9 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
10 |
11 | TARGET = Kalendar
12 | TEMPLATE = app
13 |
14 |
15 | SOURCES += main.cpp\
16 | persistence/pmanager.cpp \
17 | test/test.cpp \
18 | test/persistence/pmanager_test.cpp \
19 | view/monthview.cpp \
20 | util/dateutil.cpp \
21 | test/util/dateutil_test.cpp \
22 | view/eventdialog.cpp \
23 | view/qwidget_extended.cpp \
24 | view/qlabel_event.cpp \
25 | view/categorydialog.cpp \
26 | view/qpushbutton_extended.cpp \
27 | view/customdialog.cpp \
28 | view/categoryeditdialog.cpp \
29 | view/categoryselectdialog.cpp \
30 | util/linuxnotifymanager.cpp \
31 | persistence/securepmanager.cpp \
32 | util/eventutil.cpp \
33 | test/util/eventutil_test.cpp \
34 | util/pluginmanager.cpp \
35 | view/settings.cpp
36 |
37 | HEADERS += model/event.h \
38 | persistence/pmanager.h \
39 | model/category.h \
40 | test/test.h \
41 | test/persistence/pmanager_test.h \
42 | model/category.h \
43 | model/event.h \
44 | view/monthview.h \
45 | view/qframe_extended.h \
46 | model/date.h \
47 | util/dateutil.h \
48 | test/util/dateutil_test.h \
49 | view/eventdialog.h \
50 | view/qwidget_extended.h \
51 | view/qlabel_event.h \
52 | view/view.h \
53 | view/categorydialog.h \
54 | view/qpushbutton_extended.h \
55 | view/customdialog.h \
56 | view/categoryeditdialog.h \
57 | view/categoryselectdialog.h \
58 | util/notifymanager.h \
59 | util/linuxnotifymanager.h \
60 | persistence/securepmanager.h \
61 | util/eventutil.h \
62 | test/util/eventutil_test.h \
63 | util/pluginmanager.h \
64 | view/settings.h
65 |
66 | QMAKE_LIBS += -lsqlite3
67 | QMAKE_LIBS += -lstdc++fs
68 | QMAKE_CXXFLAGS += -std=c++11
69 |
70 | #For DEBUG purpose
71 | #QMAKE_CXXFLAGS += -g
72 |
--------------------------------------------------------------------------------
/src/Kalendar.pro.user.3148a8b:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | EnvironmentId
7 | {3148a8be-7f16-4f3b-be24-d7503ad26e51}
8 |
9 |
10 | ProjectExplorer.Project.ActiveTarget
11 | 0
12 |
13 |
14 | ProjectExplorer.Project.EditorSettings
15 |
16 | true
17 | false
18 | true
19 |
20 | Cpp
21 |
22 | CppGlobal
23 |
24 |
25 |
26 | QmlJS
27 |
28 | QmlJSGlobal
29 |
30 |
31 | 2
32 | UTF-8
33 | false
34 | 4
35 | false
36 | 80
37 | true
38 | true
39 | 1
40 | true
41 | false
42 | 0
43 | true
44 | true
45 | 0
46 | 8
47 | true
48 | 1
49 | true
50 | true
51 | true
52 | false
53 |
54 |
55 |
56 | ProjectExplorer.Project.PluginSettings
57 |
58 |
59 |
60 | ProjectExplorer.Project.Target.0
61 |
62 | Desktop
63 | Desktop
64 | {7f49c389-e746-4569-bc59-db60707f3f5a}
65 | 0
66 | 0
67 | 0
68 |
69 | /home/greg/Scrivania/Varie/qt/build-Kalendar-Desktop-Debug
70 |
71 |
72 | true
73 | qmake
74 |
75 | QtProjectManager.QMakeBuildStep
76 | true
77 |
78 | false
79 | false
80 | false
81 |
82 |
83 | true
84 | Make
85 |
86 | Qt4ProjectManager.MakeStep
87 |
88 | -w
89 | -r
90 |
91 | false
92 |
93 |
94 |
95 | 2
96 | Build
97 |
98 | ProjectExplorer.BuildSteps.Build
99 |
100 |
101 |
102 | true
103 | Make
104 |
105 | Qt4ProjectManager.MakeStep
106 |
107 | -w
108 | -r
109 |
110 | true
111 | clean
112 |
113 |
114 | 1
115 | Clean
116 |
117 | ProjectExplorer.BuildSteps.Clean
118 |
119 | 2
120 | false
121 |
122 | Debug
123 |
124 | Qt4ProjectManager.Qt4BuildConfiguration
125 | 2
126 | true
127 |
128 |
129 | /home/greg/Scrivania/Varie/qt/build-Kalendar-Desktop-Release
130 |
131 |
132 | true
133 | qmake
134 |
135 | QtProjectManager.QMakeBuildStep
136 | false
137 |
138 | false
139 | false
140 | false
141 |
142 |
143 | true
144 | Make
145 |
146 | Qt4ProjectManager.MakeStep
147 |
148 | -w
149 | -r
150 |
151 | false
152 |
153 |
154 |
155 | 2
156 | Build
157 |
158 | ProjectExplorer.BuildSteps.Build
159 |
160 |
161 |
162 | true
163 | Make
164 |
165 | Qt4ProjectManager.MakeStep
166 |
167 | -w
168 | -r
169 |
170 | true
171 | clean
172 |
173 |
174 | 1
175 | Clean
176 |
177 | ProjectExplorer.BuildSteps.Clean
178 |
179 | 2
180 | false
181 |
182 | Release
183 |
184 | Qt4ProjectManager.Qt4BuildConfiguration
185 | 0
186 | true
187 |
188 |
189 | /home/greg/Scrivania/Varie/qt/build-Kalendar-Desktop-Profile
190 |
191 |
192 | true
193 | qmake
194 |
195 | QtProjectManager.QMakeBuildStep
196 | true
197 |
198 | false
199 | true
200 | false
201 |
202 |
203 | true
204 | Make
205 |
206 | Qt4ProjectManager.MakeStep
207 |
208 | -w
209 | -r
210 |
211 | false
212 |
213 |
214 |
215 | 2
216 | Build
217 |
218 | ProjectExplorer.BuildSteps.Build
219 |
220 |
221 |
222 | true
223 | Make
224 |
225 | Qt4ProjectManager.MakeStep
226 |
227 | -w
228 | -r
229 |
230 | true
231 | clean
232 |
233 |
234 | 1
235 | Clean
236 |
237 | ProjectExplorer.BuildSteps.Clean
238 |
239 | 2
240 | false
241 |
242 | Profile
243 |
244 | Qt4ProjectManager.Qt4BuildConfiguration
245 | 0
246 | true
247 |
248 | 3
249 |
250 |
251 | 0
252 | Deploy
253 |
254 | ProjectExplorer.BuildSteps.Deploy
255 |
256 | 1
257 | Deploy locally
258 |
259 | ProjectExplorer.DefaultDeployConfiguration
260 |
261 | 1
262 |
263 |
264 | false
265 | false
266 | 1000
267 |
268 | true
269 |
270 | false
271 | false
272 | false
273 | false
274 | true
275 | 0.01
276 | 10
277 | true
278 | 1
279 | 25
280 |
281 | 1
282 | true
283 | false
284 | true
285 | valgrind
286 |
287 | 0
288 | 1
289 | 2
290 | 3
291 | 4
292 | 5
293 | 6
294 | 7
295 | 8
296 | 9
297 | 10
298 | 11
299 | 12
300 | 13
301 | 14
302 |
303 | 2
304 |
305 | Kalendar
306 | Kalendar2
307 | Qt4ProjectManager.Qt4RunConfiguration:/home/greg/Scrivania/Varie/qt/Kalendar/src/Kalendar.pro
308 | true
309 |
310 | Kalendar.pro
311 | false
312 | false
313 |
314 | /home/greg/Scrivania/Varie/qt/build-Kalendar-Desktop-Debug
315 | 3768
316 | false
317 | true
318 | false
319 | false
320 | true
321 |
322 | 1
323 |
324 |
325 |
326 | ProjectExplorer.Project.TargetCount
327 | 1
328 |
329 |
330 | ProjectExplorer.Project.Updater.FileVersion
331 | 18
332 |
333 |
334 | Version
335 | 18
336 |
337 |
338 |
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include "view/monthview.h"
2 | #include "persistence/securepmanager.h"
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "test/test.h"
9 | #include "util/linuxnotifymanager.h"
10 | #include "util/eventutil.h"
11 |
12 | #define RUN_TESTS 0
13 |
14 | int main(int argc, char *argv[])
15 | {
16 | QApplication a(argc, argv);
17 | int ret = 0;
18 | #if RUN_TESTS
19 | Test t;
20 | t.test_persistence();
21 | t.test_util();
22 | #else
23 | bool cli = false;
24 | QCommandLineParser parser;
25 | parser.addHelpOption();
26 | parser.addOptions({
27 | {{"n", "notify"},
28 | QCoreApplication::translate("main", "Notify the events in the future starting from today"),
29 | QCoreApplication::translate("main", "notifynextdays")},
30 | {{"a", "add"},
31 | QCoreApplication::translate("main", "Add an event"),
32 | QCoreApplication::translate("main", "event")},
33 | {{"d", "delete"},
34 | QCoreApplication::translate("main", "Delete an event"),
35 | QCoreApplication::translate("main", "event")},
36 | });
37 | parser.process(a);
38 | if ((cli = parser.isSet("add"))) {
39 | QString event = parser.value("add");
40 | SecurePManager spm;
41 | spm.add_event(EventUtil::parseString(event.toStdString()));
42 | } else if((cli = parser.isSet("delete"))) {
43 | /* TODO: implement deletion by id */
44 | QString eventName = parser.value("delete");
45 | SecurePManager spm;
46 | for (Event *e : spm.get_all_events()) {
47 | if (e->getName() == eventName.toStdString())
48 | spm.remove_event(e);
49 | }
50 | } else if ((cli = parser.isSet("notify"))) {
51 | /* Show notifications about the events in the next days */
52 | QString notify = parser.value("notify");
53 | LinuxNotifyManager nm;
54 | if (!nm.notifyEvents(notify.toInt())) {
55 | printf("Error in notifyEvents");
56 | ret = 1;
57 | }
58 | }
59 | MonthView window;
60 | if (!cli) {
61 | window.show();
62 | ret = a.exec();
63 | }
64 | #endif
65 | return ret;
66 | }
67 |
--------------------------------------------------------------------------------
/src/model/category.h:
--------------------------------------------------------------------------------
1 | #ifndef CATEGORY_H
2 | #define CATEGORY_H
3 |
4 | using namespace std;
5 |
6 | class Category
7 | {
8 | private:
9 | unsigned int id;
10 | string name;
11 | string color;
12 |
13 | public:
14 | Category (Category &category) {
15 | this->name = category.getName();
16 | this->color = category.getColor();
17 | this->id = category.getId();
18 | }
19 |
20 | Category(unsigned int id, const string &name, const string &color) {
21 | this->name = name;
22 | this->color = color;
23 | if (id == 0)
24 | this->id = static_cast (hash()(this->name + this->color));
25 | else
26 | this->id = id;
27 | }
28 |
29 | ~Category() {
30 | }
31 |
32 | string getName() { return name; }
33 | string getColor() { return color; }
34 | unsigned int getId() { return id; }
35 |
36 | bool equals(Category &c) {
37 | return (this->id == c.getId());
38 | }
39 |
40 | long hashcode() {
41 | return static_cast (this->id);
42 | }
43 | };
44 |
45 | #endif // CATEGORY_H
46 |
--------------------------------------------------------------------------------
/src/model/date.h:
--------------------------------------------------------------------------------
1 | #ifndef DATE_H
2 | #define DATE_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | using namespace std;
9 |
10 | class Date {
11 | private:
12 | int mday; //month day
13 | int wday; //week day
14 | int month;
15 | int year;
16 | public:
17 | Date() {}
18 |
19 | Date(int mday, int wday, int month, int year) {
20 | this->mday = mday;
21 | this->wday = wday;
22 | this->month = month;
23 | this->year = year;
24 | }
25 | int getMonthDay() { return mday; }
26 | int getWeekDay() { return wday; }
27 | int getMonth() { return month; }
28 | int getYear() { return year; }
29 | void setMonthDay(int mday) { this->mday = mday; }
30 | void setWeekDay(int wday) { this->wday = wday; }
31 | void setMonth(int month) { this->month = month; }
32 | void setYear(int year) { this->year = year; }
33 | //TODO: maybe it can be useful to add the method: isHoliday()
34 |
35 | int compareTo (Date &d) {
36 | int ret;
37 | ret = this->year - d.getYear();
38 | if (ret != 0) return ret;
39 | else { //Same year, compare months
40 | ret = this->month - d.getMonth();
41 | if (ret != 0) return ret;
42 | else { //Same year and month, compare days
43 | ret = this->mday - d.getMonthDay();
44 | return ret;
45 | }
46 | }
47 | }
48 |
49 | Date& operator=(Date d) {
50 | this->mday = d.getMonthDay();
51 | this->wday = d.getWeekDay();
52 | this->month = d.getMonth();
53 | this->year = d.getYear();
54 | return *this;
55 | }
56 |
57 | bool operator==(Date &d) {
58 | return (this->mday == d.getMonthDay()) &&
59 | (this->wday == d.getWeekDay()) &&
60 | (this->month == d.getMonth()) &&
61 | (this->year == d.getYear());
62 | }
63 |
64 | string toString(bool weekday) {
65 | /* In this project the standard format for dates is: d/m/y */
66 | char sdate[11];
67 | snprintf(sdate, 11, "%02d/%02d/%d", this->mday, this->month, this->year);
68 | string ret (sdate);
69 | if (weekday)
70 | ret += " Week-day: " + to_string(this->wday);
71 | return ret;
72 | }
73 | };
74 |
75 | #endif
76 |
--------------------------------------------------------------------------------
/src/model/event.h:
--------------------------------------------------------------------------------
1 | #ifndef EVENT_H
2 | #define EVENT_H
3 |
4 | #include
5 |
6 | #include "category.h"
7 |
8 | /* A todo is defined as an event with special dates, they are the following:
9 | * start = end = 29/01/2105 09:40 , the UTC timestamp is: 4262665200
10 | * Note: this value is incompatible for 32bit systems due to the 2038 year bug (Reference: https://en.wikipedia.org/wiki/Year_2038_problem)
11 | * The todo is only an high-level concept managed by the logic view, thus the persistence part consider them as normal events. */
12 | //#define BIT32
13 | #ifndef BIT32
14 | // As explained above, this is for 64 bit systems
15 | #define TODO_DATE 4262665200
16 | #else
17 | // 2147437133 is the 18 Jan 2038, the maximum value representable with a 32 bit system
18 | #define TODO_DATE 2147437133
19 | #endif
20 |
21 | using namespace std;
22 |
23 | class Event
24 | {
25 | private:
26 | unsigned int id;
27 | string name;
28 | string description;
29 | string place;
30 | Category *category;
31 | /* Timestamp */
32 | time_t start;
33 | time_t end;
34 |
35 | public:
36 | Event(Event &event) {
37 | this->name = event.getName();
38 | this->description = event.getDescription();
39 | this->place = event.getPlace();
40 | this->category = new Category(*event.getCategory());
41 | this->id = event.getId();
42 | this->start = event.getStart();
43 | this->end = event.getEnd();
44 | }
45 |
46 | Event(unsigned int id, string name, const string &description, const string &place, Category *category, time_t start, time_t end) {
47 | this->name = name;
48 | this->description = description;
49 | this->place = place;
50 | if (category == NULL) {
51 | /* An event with a NULL category is inconsistent, it shouldn't exist */
52 | this->category = NULL;
53 | fprintf(stderr, "Event %d (%s) received NULL category.\n", id, name.c_str());
54 | } else
55 | this->category = new Category(*category);
56 | this->start = start;
57 | this->end = end;
58 | if (id == 0)
59 | /* The returned value from the hash function could be bigger than an integer, so be careful with normal integers.
60 | * I use an unsigned integer to have always a positive number (also with the overflow). */
61 | this->id = static_cast (hash()(this->name + this->description + this->place)) + (this->category ? this->category->getId() : 0) + static_cast ((this->start / 1000) + (this->end - this->start));
62 | else
63 | this->id = id;
64 | }
65 |
66 | ~Event() {
67 | if (this->category != NULL) delete this->category;
68 | }
69 |
70 | void setInvalid() {
71 | this->id = 65535;
72 | }
73 |
74 | bool isInvalid() {
75 | return this->id == 65535;
76 | }
77 |
78 | unsigned int getId() { return id; }
79 | string getName() { return name; }
80 | string getDescription() { return description; }
81 | string getPlace() { return place; }
82 | Category *getCategory() { return category; }
83 | time_t getStart() { return start; }
84 | time_t getEnd() { return end; }
85 |
86 | bool equals(Event &e) {
87 | return (this->id == e.getId());
88 | }
89 |
90 | long hashcode() {
91 | return this->id;
92 | }
93 | };
94 |
95 | #endif // EVENT_H
96 |
--------------------------------------------------------------------------------
/src/persistence/pmanager.cpp:
--------------------------------------------------------------------------------
1 | #include "pmanager.h"
2 |
3 | #include
4 |
5 | PManager::PManager(string database)
6 | {
7 | if (database != DEFAULT_DATABASE_NAME) db_name = database;
8 | init_db(db_name);
9 | }
10 |
11 | PManager::~PManager() {
12 | sqlite3_close(this->db);
13 | }
14 |
15 | string PManager::get_db_folder() {
16 | return this->db_folder;
17 | }
18 |
19 | void PManager::init_db(string db_name) {
20 | /* Close an already open database */
21 | if (this->db != NULL) {
22 | sqlite3_close(this->db);
23 | }
24 | /* Open the database (will be created if it doesn't exist) */
25 | this->db_folder = string(getpwuid(getuid())->pw_dir) + string("/" FOLDER_NAME "/");
26 | this->db_path = this->db_folder + string(db_name);
27 | ifstream dbfile(this->db_path.c_str());
28 | bool db_not_exists = !dbfile;
29 | if (db_not_exists) {
30 | mkdir((string(getpwuid(getuid())->pw_dir) + string("/" FOLDER_NAME)).c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
31 | ofstream new_dbfile(this->db_path.c_str());
32 | new_dbfile.close();
33 | }
34 |
35 | int rc = sqlite3_open(this->db_path.c_str(), &this->db);
36 | char *err_msg = 0;
37 |
38 | if (rc != SQLITE_OK) {
39 |
40 | fprintf(stderr, "Cannot open database: %s\n", sqlite3_errmsg(this->db));
41 | sqlite3_free(err_msg);
42 | sqlite3_close(this->db);
43 | }
44 |
45 | if (db_not_exists) {
46 | const char *sql = "CREATE TABLE Categories(id UNSIGNED INTEGER PRIMARY KEY, name TEXT, color TEXT);"
47 | "CREATE TABLE Events(id UNSIGNED INTEGER PRIMARY KEY, name TEXT, description TEXT,"
48 | "place TEXT, category UNSIGNED INTEGER, start DATETIME, end DATETIME, child UNSIGNED INTEGER,"
49 | "FOREIGN KEY(category) REFERENCES Categories(id) ON DELETE RESTRICT,"
50 | "FOREIGN KEY(child) REFERENCES Events(id) ON DELETE CASCADE);"
51 | "INSERT INTO Categories VALUES(1, 'Default', '#1022A0');"
52 | "PRAGMA foreign_keys = ON;";
53 |
54 | rc = sqlite3_exec(this->db, sql, 0, 0, &err_msg);
55 |
56 | if (rc != SQLITE_OK ) {
57 | fprintf(stderr, "SQL error: %s\n", err_msg);
58 | sqlite3_free(err_msg);
59 | sqlite3_close(this->db);
60 | }
61 | }
62 | }
63 |
64 | void PManager::set_db(string database) {
65 | db_name = database;
66 | init_db(db_name);
67 | }
68 |
69 | string PManager::get_db_name() {
70 | return db_name;
71 | }
72 |
73 | vector PManager::get_db_list() {
74 | vector db_list;
75 | for (experimental::filesystem::directory_entry e : experimental::filesystem::directory_iterator(this->db_path.substr(0, this->db_path.find_last_of('/') ))) {
76 | experimental::filesystem::path p = e.path();
77 | if (p.extension() == ".sql")
78 | db_list.push_back(p.filename());
79 | }
80 | return db_list;
81 | }
82 |
83 | string PManager::filterSpecialChars(string str) {
84 | int start_pos = 0;
85 | string to = "’";
86 | while((str.find('\'', start_pos)) != std::string::npos) {
87 | start_pos = str.find('\'', start_pos);
88 | str.replace(start_pos, 1, to);
89 | start_pos += to.length();
90 | }
91 | return str;
92 | }
93 |
94 | bool PManager::add_event(Event *e, Event *child) {
95 | char *err_msg = 0;
96 | sqlite3_stmt *stmt;
97 | string filteredName, filteredDescription, filteredPlace;
98 | if ((e->getName().length() < 3) || (difftime(e->getStart(), e->getEnd()) > 0) || (e->getCategory() == NULL)) return false;
99 | int rc = sqlite3_prepare_v2(this->db, "INSERT INTO Events VALUES(?, ?, ?, ?, ?, ?, ?, ?);", -1, &stmt, NULL);
100 | if (rc != SQLITE_OK ) {
101 | fprintf(stderr, "SQL error in prepare: %s\n", sqlite3_errmsg(this->db));
102 | sqlite3_free(err_msg);
103 | sqlite3_close(this->db);
104 | return false;
105 | }
106 | sqlite3_bind_int64 (stmt, 1, e->getId());
107 | filteredName = filterSpecialChars(e->getName());
108 | sqlite3_bind_text(stmt, 2, filteredName.c_str(), filteredName.length(), 0);
109 | filteredDescription = filterSpecialChars(e->getDescription());
110 | sqlite3_bind_text(stmt, 3, filteredDescription.c_str(), filteredDescription.length(), 0);
111 | filteredPlace = filterSpecialChars(e->getPlace());
112 | sqlite3_bind_text(stmt, 4, filteredPlace.c_str(), filteredPlace.length(), 0);
113 | sqlite3_bind_int64(stmt, 5, e->getCategory()->getId());
114 | sqlite3_bind_int64(stmt, 6, e->getStart());
115 | sqlite3_bind_int64(stmt, 7, e->getEnd());
116 | if (child != NULL)
117 | sqlite3_bind_int64(stmt, 8, child->getId());
118 | else
119 | sqlite3_bind_null(stmt, 8);
120 | //commit
121 | rc = sqlite3_step(stmt);
122 | if (rc != SQLITE_DONE ) {
123 | fprintf(stderr, "SQL error in commit: %s\n", sqlite3_errmsg(this->db));
124 | sqlite3_free(err_msg);
125 | return false;
126 | }
127 | //free memory
128 | sqlite3_finalize(stmt);
129 | return true;
130 | }
131 |
132 | bool PManager::replace_event(Event *old_event, Event *new_event) {
133 | char *err_msg = 0;
134 | sqlite3_stmt *stmt;
135 | string filteredName, filteredDescription, filteredPlace;
136 | if ((new_event->getName().length() < 3) || (difftime(new_event->getStart(), new_event->getEnd()) > 0) || (new_event->getCategory() == NULL)) return false;
137 | int rc = sqlite3_prepare_v2(this->db, "UPDATE Events SET id=?, name=?, description=?, place=?, category=?, start=?, end=? WHERE id=?;", -1, &stmt, NULL);
138 | if (rc != SQLITE_OK ) {
139 | fprintf(stderr, "SQL error in prepare: %s\n", sqlite3_errmsg(this->db));
140 | sqlite3_free(err_msg);
141 | return false;
142 | }
143 | sqlite3_bind_int64(stmt, 1, new_event->getId());
144 | filteredName = filterSpecialChars(new_event->getName());
145 | sqlite3_bind_text(stmt, 2, filteredName.c_str(), filteredName.length(), 0);
146 | filteredDescription = filterSpecialChars(new_event->getDescription());
147 | sqlite3_bind_text(stmt, 3, filteredDescription.c_str(), filteredDescription.length(), 0);
148 | filteredPlace = filterSpecialChars(new_event->getPlace());
149 | sqlite3_bind_text(stmt, 4, filteredPlace.c_str(), filteredPlace.length(), 0);
150 | sqlite3_bind_int64(stmt, 5, new_event->getCategory()->getId());
151 | sqlite3_bind_int64(stmt, 6, new_event->getStart());
152 | sqlite3_bind_int64(stmt, 7, new_event->getEnd());
153 | sqlite3_bind_int64(stmt, 8, old_event->getId());
154 | //commit
155 | rc = sqlite3_step(stmt);
156 | if (rc != SQLITE_DONE ) {
157 | fprintf(stderr, "SQL error in commit: %s\n", sqlite3_errmsg(this->db));
158 | sqlite3_free(err_msg);
159 | return false;
160 | }
161 | //free memory
162 | sqlite3_finalize(stmt);
163 | return true;
164 | }
165 |
166 | bool PManager::replace_category(Category *old_category, Category *new_category) {
167 | char *err_msg = 0;
168 | char sql[1024];
169 | if (new_category->getName().length() < 3) return false;
170 | snprintf(sql, 1024, "UPDATE Categories SET name='%s', color='%s' WHERE id=%u;", filterSpecialChars(new_category->getName()).c_str(), filterSpecialChars(new_category->getColor()).c_str(), old_category->getId());
171 | int rc = sqlite3_exec(this->db, sql, 0, 0, &err_msg);
172 | if (rc != SQLITE_OK ) {
173 | fprintf(stderr, "SQL error: %s\n", err_msg);
174 | sqlite3_free(err_msg);
175 | return false;
176 | }
177 | return true;
178 | }
179 |
180 | list PManager::get_events(Category *c) {
181 | if (c == NULL) return this->get_all_events();
182 | list result;
183 | sqlite3_stmt *res;
184 | int rc = sqlite3_prepare_v2(this->db, "SELECT * FROM Events WHERE category = ?;", -1, &res, NULL);
185 | if (rc != SQLITE_OK) {
186 | fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(db));
187 | return result;
188 | }
189 | sqlite3_bind_int64(res, 1, (long)c->getId());
190 | while ((rc = sqlite3_step(res)) == SQLITE_ROW) {
191 | unsigned long id = (unsigned long)sqlite3_column_int(res, 0);
192 | string name((const char*)sqlite3_column_text(res, 1));
193 | string description((const char*)sqlite3_column_text(res, 2));
194 | string place((const char*)sqlite3_column_text(res, 3));
195 | Category *category = this->get_category((unsigned long)sqlite3_column_int64(res, 4));
196 | if (category == NULL) {
197 | fprintf(stderr, "Error: Received NULL category\n");
198 | continue;
199 | }
200 | time_t start = (unsigned long)sqlite3_column_int64(res, 5);
201 | time_t end = (unsigned long)sqlite3_column_int64(res, 6);
202 | Event *e = new Event(id, name, description, place, category, start, end);
203 |
204 | result.push_front(e);
205 | }
206 | sqlite3_finalize(res);
207 | return result;
208 | }
209 |
210 | list PManager::get_events_of_month(int month, int year) {
211 | list result;
212 |
213 | /* A large number of countries use daylight saving time (DST) (called also summer time).
214 | * We need to manage DST. Most of the countries start to use DST between 1 March and 1 April,
215 | * but the dates where the DST ends are different. For example in Europe DST ends before 1 November, instead in U.S.A.
216 | * DST ends after the 1 November. We must calculate for the current user if DST ends before or after 1 November (geolocation dependent).
217 | * The following lines of code use localtime function that takes into account the location of the user. */
218 | time_t threshold = 26262000; // = 1 November 1970
219 | std::tm *t = localtime(&threshold);
220 | /* From documentation:
221 | * The Daylight Saving Time flag (tm_isdst) is greater than zero if Daylight Saving Time is in effect,
222 | * zero if Daylight Saving Time is not in effect,
223 | * and less than zero if the information is not available.
224 | */
225 | int s = 0;
226 | if (t->tm_isdst > 0) s = 1; //if tm_isdst is negative, s will have the default value
227 |
228 | std::tm tm;
229 | tm.tm_sec = 0;
230 | tm.tm_min = 0;
231 | tm.tm_hour = 0;
232 | tm.tm_mday = 1;
233 | tm.tm_mon = month - 1; // Assuming month represents Jan with 1
234 | tm.tm_year = year - 1900; // Assuming year is the AD year number
235 | tm.tm_isdst = ((tm.tm_mon > 2) && (tm.tm_mon < 10+s)); // 10 is November
236 | long first_month = static_cast (mktime(&tm)); //first of month
237 | tm.tm_mon = tm.tm_mon + 1; //This could be 12, but isn't a problem
238 | tm.tm_isdst = ((tm.tm_mon > 2) && (tm.tm_mon < 10+s));
239 | long last_month = static_cast (mktime(&tm)); //last of month
240 | if ((first_month == -1) || (last_month == -1)) {
241 | fprintf(stderr, "Failed to calculate timestamp\n");
242 | return result;
243 | }
244 | sqlite3_stmt *res;
245 | int rc = sqlite3_prepare_v2(this->db, "SELECT * FROM Events WHERE (start >= ? AND start < ?) OR (end >= ? AND end < ?);", -1, &res, NULL);
246 | if (rc != SQLITE_OK) {
247 | fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(db));
248 | return result;
249 | }
250 | sqlite3_bind_int64(res, 1, first_month);
251 | sqlite3_bind_int64(res, 2, last_month);
252 | sqlite3_bind_int64(res, 3, first_month);
253 | sqlite3_bind_int64(res, 4, last_month);
254 | while ((rc = sqlite3_step(res)) == SQLITE_ROW) {
255 | unsigned long id = (unsigned long)sqlite3_column_int(res, 0);
256 | string name((const char*)sqlite3_column_text(res, 1));
257 | string description((const char*)sqlite3_column_text(res, 2));
258 | string place((const char*)sqlite3_column_text(res, 3));
259 | Category *category = this->get_category((unsigned long)sqlite3_column_int64(res, 4));
260 | if (category == NULL) {
261 | fprintf(stderr, "Error: Received NULL category\n");
262 | continue;
263 | }
264 | time_t start = (unsigned long)sqlite3_column_int64(res, 5);
265 | time_t end = (unsigned long)sqlite3_column_int64(res, 6);
266 | Event *e = new Event(id, name, description, place, category, start, end);
267 |
268 | result.push_front(e);
269 | }
270 | sqlite3_finalize(res);
271 | return result;
272 | }
273 |
274 | bool PManager::remove_db() {
275 | /* Delete the database file, but not the folder */
276 | return (std::remove(this->db_path.c_str()) == 0);
277 | }
278 |
279 | bool PManager::remove_event(Event *e) {
280 | char *err_msg = 0;
281 | char sql[1024];
282 | snprintf(sql, 1024, "DELETE FROM Events WHERE id = %u;", e->getId());
283 | int rc = sqlite3_exec(this->db, sql, 0, 0, &err_msg);
284 | if (rc != SQLITE_OK ) {
285 | fprintf(stderr, "SQL error: %s\n", err_msg);
286 | sqlite3_free(err_msg);
287 | return false;
288 | }
289 | return true;
290 | }
291 |
292 | bool PManager::add_category(Category *c) {
293 | char *err_msg = 0;
294 | char sql[1024];
295 | if (c->getName().length() < 3) return false;
296 | snprintf(sql, 1024, "INSERT INTO Categories VALUES(%u, '%s', '%s');", c->getId(), filterSpecialChars(c->getName()).c_str(), filterSpecialChars(c->getColor()).c_str());
297 | int rc = sqlite3_exec(this->db, sql, 0, 0, &err_msg);
298 | if (rc != SQLITE_OK ) {
299 | fprintf(stderr, "SQL error: %s\n", err_msg);
300 | sqlite3_free(err_msg);
301 | return false;
302 | }
303 | return true;
304 | }
305 |
306 | vector PManager::get_categories() {
307 | vector result;
308 | sqlite3_stmt *res;
309 | char sql[1024];
310 | snprintf(sql, 1024, "SELECT * FROM Categories;");
311 | int rc = sqlite3_prepare_v2(this->db, sql, -1, &res, 0);
312 | if (rc != SQLITE_OK) {
313 | fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(db));
314 | return result;
315 | }
316 | while ((rc = sqlite3_step(res)) == SQLITE_ROW) {
317 |
318 | Category *c = new Category( sqlite3_column_int(res, 0),
319 | string((const char*)sqlite3_column_text(res, 1)),
320 | string((const char*)sqlite3_column_text(res, 2)));
321 |
322 | result.push_back(c);
323 | }
324 | sqlite3_finalize(res);
325 | return result;
326 | }
327 |
328 | bool PManager::remove_category(Category *c) {
329 | char *err_msg = 0;
330 | char sql[1024];
331 | snprintf(sql, 1024, "PRAGMA foreign_keys = ON; DELETE FROM Categories WHERE id = %u;", c->getId());
332 | int rc = sqlite3_exec(this->db, sql, 0, 0, &err_msg);
333 | if (rc != SQLITE_OK ) {
334 | fprintf(stderr, "SQL error: %s\n", err_msg);
335 | sqlite3_free(err_msg);
336 | //Don't close the db
337 | return false;
338 | }
339 | return true;
340 | }
341 |
342 | Category* PManager::get_category(unsigned int id) {
343 | sqlite3_stmt *res;
344 | char sql[1024];
345 | snprintf(sql, 1024, "SELECT * FROM Categories WHERE id = %u;", id);
346 | int rc = sqlite3_prepare_v2(this->db, sql, -1, &res, 0);
347 | if (rc != SQLITE_OK) {
348 | fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(db));
349 | return NULL;
350 | }
351 | if ((rc = sqlite3_step(res)) == SQLITE_ROW) {
352 | Category *category = new Category( sqlite3_column_int(res, 0),
353 | string((const char*)sqlite3_column_text(res, 1)),
354 | string((const char*)sqlite3_column_text(res, 2)));
355 | sqlite3_finalize(res);
356 | return category;
357 | } else
358 | return NULL;
359 | }
360 |
361 | bool PManager::remove_past_events(time_t timestamp) {
362 | char *err_msg = 0;
363 | char sql[1024];
364 | snprintf(sql, 1024, "DELETE FROM Events WHERE end <= %ld;", static_cast (timestamp));
365 | int rc = sqlite3_exec(this->db, sql, 0, 0, &err_msg);
366 | if (rc != SQLITE_OK ) {
367 | fprintf(stderr, "SQL error: %s\n", err_msg);
368 | sqlite3_free(err_msg);
369 | return false;
370 | }
371 | return true;
372 | }
373 |
374 | list PManager::get_all_events() {
375 | list result;
376 | sqlite3_stmt *res;
377 | char sql[1024];
378 | snprintf(sql, 1024, "SELECT * FROM Events ORDER BY start DESC;");
379 | int rc = sqlite3_prepare_v2(this->db, sql, -1, &res, 0);
380 | if (rc != SQLITE_OK) {
381 | fprintf(stderr, "Failed to fetch data: %s\n", sqlite3_errmsg(db));
382 | return result;
383 | }
384 | while ((rc = sqlite3_step(res)) == SQLITE_ROW) {
385 | unsigned long id = (unsigned long)sqlite3_column_int(res, 0);
386 | string name((const char*)sqlite3_column_text(res, 1));
387 | string description((const char*)sqlite3_column_text(res, 2));
388 | string place((const char*)sqlite3_column_text(res, 3));
389 | Category *category = this->get_category((unsigned long)sqlite3_column_int64(res, 4));
390 | if (category == NULL) {
391 | fprintf(stderr, "Error: Received NULL category\n");
392 | continue;
393 | }
394 | time_t start = (unsigned long)sqlite3_column_int64(res, 5);
395 | time_t end = (unsigned long)sqlite3_column_int64(res, 6);
396 | Event *e = new Event(id, name, description, place, category, start, end);
397 |
398 | result.push_front(e);
399 | }
400 | sqlite3_finalize(res);
401 | return result;
402 | }
403 |
404 | int PManager::save_db(string path) {
405 | if (path.length() < 5) return 0;
406 | if (path.substr(path.length()-4, 4) != ".kal") path += ".kal";
407 | int counter = 0;
408 | ofstream file;
409 | file.open(path);
410 | //TODO: An event with a description too long can exceed the buffer, use sqlite3_prepare_v2
411 | char sql[4096];
412 | vector categories_list = get_categories();
413 | for (Category *category : categories_list) {
414 | snprintf(sql, 4096, "INSERT INTO Categories VALUES(%u, '%s', '%s');", category->getId(), category->getName().c_str(), category->getColor().c_str());
415 | file << sql << endl;
416 | delete category;
417 | counter++;
418 | }
419 | list events_list = get_all_events();
420 | for (Event *event : events_list) {
421 | string description_single_line = event->getDescription();
422 | size_t start_pos = 0;
423 | while((start_pos = description_single_line.find("\n", start_pos)) != std::string::npos) {
424 | description_single_line.replace(start_pos, 1, "\\n");
425 | start_pos += 2;
426 | }
427 | snprintf(sql, 1024, "INSERT INTO Events VALUES(%u, '%s', '%s', '%s', %u, %ld, %ld);", event->getId(), event->getName().c_str(), description_single_line.c_str(), event->getPlace().c_str(), event->getCategory()->getId(), event->getStart(), event->getEnd());
428 | file << sql << endl;
429 | delete event;
430 | counter++;
431 | }
432 | file.close();
433 | return counter;
434 | }
435 |
436 | /* it's easy load a crafted file with malicious queries (e.g. "DELETE ... ")
437 | * we assume the user knows the source and the content of the file.
438 | */
439 | int PManager::load_db(string path) {
440 | if ((path.length() < 5) || (path.substr(path.length()-4, 4) != ".kal")) return 0;
441 | ifstream file;
442 | string line;
443 | int rc;
444 | int counter = 0;
445 | char *err_msg = 0;
446 | file.open(path);
447 | while ( getline (file,line) && (line.substr(0, 6) == "INSERT") ) {
448 | //Transform line into a multiline (replacing \n)
449 | size_t start_pos = 0;
450 | while((start_pos = line.find("\\n", start_pos)) != std::string::npos) {
451 | line.replace(start_pos, 2, "\n");
452 | start_pos += 1;
453 | }
454 | rc = sqlite3_exec(this->db, line.c_str(), 0, 0, &err_msg);
455 | if (rc != SQLITE_OK ) {
456 | fprintf(stderr, "SQL error: %s\n", err_msg);
457 | sqlite3_free(err_msg);
458 | } else counter++;
459 | }
460 | file.close();
461 | return counter;
462 | }
463 |
464 | int PManager::import_db_iCal_format(string path, Category *category) {
465 | auto category_id = category->getId();
466 | if ((path.length() < 5) || (path.substr(path.length()-4, 4) != ".ics")) return 0;
467 | ifstream file;
468 | string line;
469 | string pattern;
470 | string summary;
471 | string location;
472 | string description;
473 | bool found_description = false;
474 | int counter = 0;
475 | struct tm start;
476 | start.tm_sec = start.tm_min = start.tm_hour = start.tm_wday = start.tm_yday = start.tm_year = start.tm_mday = start.tm_mon = 0;
477 | struct tm end;
478 | end.tm_sec = end.tm_min = end.tm_hour = end.tm_wday = end.tm_yday = end.tm_year = end.tm_mday = end.tm_mon = 0;
479 | /* Look at the explanation in get_events_of_month */
480 | time_t threshold = 26262000; // = 1 November 1970
481 | std::tm *t = localtime(&threshold);
482 | int s = 0;
483 | if (t->tm_isdst > 0) s = 1;
484 |
485 | file.open(path);
486 | while ( getline (file,line) ) {
487 | pattern = "DTSTART;VALUE=DATE:";
488 | if (line.find(pattern) == 0) { //if line starts with the pattern
489 | found_description = false;
490 | string date = line.substr(pattern.length(),line.length()-pattern.length());
491 | start.tm_year = stoi(date.substr(0,4)) - 1900;
492 | start.tm_mon = stoi(date.substr(4,2)) - 1;
493 | start.tm_mday = stoi(date.substr(6,2));
494 | start.tm_hour = 8;
495 | start.tm_isdst = ((start.tm_mon > 2) && (start.tm_mon < 10+s));
496 | continue;
497 | }
498 | pattern = "DTEND;VALUE=DATE:";
499 | if (line.find(pattern) == 0) {
500 | found_description = false;
501 | string date = line.substr(pattern.length(),line.length()-pattern.length());
502 | end.tm_year = stoi(date.substr(0,4)) - 1900;
503 | end.tm_mon = stoi(date.substr(4,2)) - 1;
504 | end.tm_mday = stoi(date.substr(6,2)) - 1; /* -1 is to get the day before, mktime will normalize it */
505 | end.tm_hour = 22;
506 | end.tm_isdst = ((end.tm_mon > 2) && (end.tm_mon < 10+s));
507 | continue;
508 | }
509 | pattern = "SUMMARY:";
510 | if (line.find(pattern) == 0) {
511 | found_description = false;
512 | summary = line.substr(pattern.length(),line.length()-pattern.length());
513 | continue;
514 | }
515 | pattern = "LOCATION:";
516 | if (line.find(pattern) == 0) {
517 | found_description = false;
518 | location = line.substr(pattern.length(),line.length()-pattern.length());
519 | if (location.length() < 3) location = "";
520 | continue;
521 | }
522 | pattern = "DESCRIPTION:";
523 | if (line.find(pattern) == 0) {
524 | found_description = true;
525 | description = line.substr(pattern.length(),line.length()-pattern.length());
526 | if (description.length() < 3) description = "";
527 | continue;
528 | }
529 | pattern = "END:VEVENT";
530 | if (line.find(pattern) == 0) {
531 | found_description = false;
532 | if (this->add_event(new Event(0,summary,description,location,this->get_category(category_id),mktime(&start),mktime(&end))))
533 | counter++;
534 | else
535 | printf("Error: %s not imported\n", summary.c_str());
536 | /* Reset optional variables to import the next event without old values */
537 | location = "";
538 | description = "";
539 | continue;
540 | }
541 | if (found_description) { /* Multi-line description */
542 | description = description + "\n" + line;
543 | }
544 | }
545 | file.close();
546 | return counter;
547 | }
548 |
549 | int PManager::export_db_iCal_format(list events, string path) {
550 | if (path.length() < 5) return 0;
551 | if (path.substr(path.length()-4, 4) != ".ics") path = path + ".ics";
552 | char buff[9];
553 | ofstream file;
554 | file.open(path);
555 | file << "BEGIN:VCALENDAR" << endl;
556 | file << "CALSCALE:GREGORIAN" << endl;
557 | for (Event *event : events) {
558 | file << "BEGIN:VEVENT" << endl;
559 | time_t tmp = event->getStart();
560 | strftime(buff, sizeof(buff),"%Y%m%d",localtime((const time_t*)&tmp));
561 | file << "DTSTART;VALUE=DATE:" << buff << endl;
562 | tmp = event->getEnd();
563 | struct tm *end = localtime((const time_t*)&tmp);
564 | end->tm_mday += 1;
565 | tmp = mktime(end);
566 | strftime(buff, sizeof(buff),"%Y%m%d",localtime((const time_t*)&tmp));
567 | file << "DTEND;VALUE=DATE:" << buff << endl;
568 | file << "UID:" << to_string(event->getId()) << endl;
569 | file << "DESCRIPTION:" << event->getDescription() << endl;
570 | file << "LOCATION:" << event->getPlace() << endl;
571 | file << "SUMMARY:" << event->getName() << endl;
572 | file << "END:VEVENT" << endl;
573 | }
574 | file << "END:VCALENDAR" << endl;
575 | file.close();
576 | return events.size();
577 | }
578 |
--------------------------------------------------------------------------------
/src/persistence/pmanager.h:
--------------------------------------------------------------------------------
1 | #ifndef PMANAGER_H
2 | #define PMANAGER_H
3 |
4 | #include /* Version: 3.9.2 */
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include "../model/event.h"
16 | #include "../model/category.h"
17 |
18 | #define FOLDER_NAME "kalendar"
19 | #define DEFAULT_DATABASE_NAME "default.sql"
20 |
21 | using namespace std;
22 | static string db_name = DEFAULT_DATABASE_NAME;
23 |
24 | class PManager
25 | {
26 | private:
27 | sqlite3 *db = NULL;
28 | string db_path;
29 | string db_folder;
30 | string filterSpecialChars(string str);
31 |
32 | public:
33 | PManager(string database = DEFAULT_DATABASE_NAME);
34 | ~PManager();
35 | void init_db(string db_name);
36 | void set_db(string database);
37 | string get_db_name();
38 | string get_db_folder();
39 | vector get_db_list();
40 | bool add_event (Event *e, Event *child = NULL);
41 | bool replace_event (Event *old_event, Event *new_event); //return true also if old_event doesn't exist
42 | bool remove_event(Event *e);
43 | bool remove_db();
44 | list get_events_of_month(int month, int year);
45 | list get_events(Category *c);
46 | list get_all_events();
47 | bool add_category (Category *c);
48 | /* Note: the id will not be changed (to avoid to change the events with a reference to the category */
49 | bool replace_category(Category *old_category, Category *new_category);
50 | bool remove_category(Category *c);
51 | vector get_categories();
52 | Category *get_category(unsigned int id);
53 | bool remove_past_events(time_t timestamp);
54 | int save_db(string path);
55 | int export_db_iCal_format(list events, string path);
56 | int load_db(string path);
57 | int import_db_iCal_format(string path,Category *category);
58 | };
59 |
60 | #endif // PMANAGER_H
61 |
--------------------------------------------------------------------------------
/src/persistence/securepmanager.cpp:
--------------------------------------------------------------------------------
1 | #include "securepmanager.h"
2 | #include
3 |
4 | SecurePManager::SecurePManager(string database) : PManager(database)
5 | {
6 |
7 | }
8 |
--------------------------------------------------------------------------------
/src/persistence/securepmanager.h:
--------------------------------------------------------------------------------
1 | #ifndef SECUREPMANAGER_H
2 | #define SECUREPMANAGER_H
3 |
4 | #include "pmanager.h"
5 |
6 | /* Proxy class to encrypt data on disk */
7 | //TODO: override PManager functions to encrypt/decrypt data. Use AES-256, implement it in util.
8 | class SecurePManager : public PManager
9 | {
10 | public:
11 | SecurePManager(string database = DEFAULT_DATABASE_NAME);
12 | };
13 |
14 | #endif // SECUREPMANAGER_H
15 |
--------------------------------------------------------------------------------
/src/test/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | g++ -std=c++11 main.cpp test.cpp persistence/pmanager_test.cpp util/timeutil_test.cpp ../persistence/pmanager.cpp ../util/timeutil.cpp -o test -lsqlite3
3 |
4 | clean:
5 | rm test
6 |
--------------------------------------------------------------------------------
/src/test/main.cpp:
--------------------------------------------------------------------------------
1 | #include "test.h"
2 |
3 | int main(int argc, char **argv) {
4 | Test test;
5 | test.test_all();
6 | return 0;
7 | }
8 |
--------------------------------------------------------------------------------
/src/test/persistence/pmanager_test.cpp:
--------------------------------------------------------------------------------
1 | #include "pmanager_test.h"
2 |
3 | #include
4 |
5 | PManagerTest::PManagerTest()
6 | {
7 | time_t timestamp = 966038400L; // = 20/12/1999 I think it's better than time(NULL);
8 | string test("test_string");
9 | string specialchars("'/--\"#@");
10 | /* Categories */
11 | this->valid_default_category = new Category(1, string("Default"), string("#1022A0"));
12 | this->valid_category = new Category(0, test, test);
13 | this->valid_category_2 = new Category(100, test, test);
14 | this->noname_category = new Category(0, string(""), test);
15 | this->specialchars_category = new Category(0, specialchars, specialchars);
16 | /* Events */
17 | this->valid_event = new Event(0, test, test, test, this->valid_default_category, timestamp, timestamp + 100);
18 | this->valid_event_2 = new Event(100, test, test, test, this->valid_default_category, timestamp - 500, timestamp + 1000000); //starts from current month, ends the next month
19 | this->valid_event_3 = new Event(80, test, test, test, this->valid_category_2, timestamp - 500, timestamp + 1000000);
20 | /* Invalid Events */
21 | this->event_with_null_category = new Event(0, test, test, test, NULL, timestamp, timestamp);
22 | this->event_with_invalid_category = new Event(0, test, test, test, new Category(99, test, test), timestamp, timestamp);
23 | this->noname_event = new Event(1, string(""), test, test, new Category(1, test, test), timestamp, timestamp + 100);
24 | this->invalid_time_event = new Event(1, test, test, test, new Category(1, test, test), timestamp, timestamp - 100);
25 | this->specialchars_event = new Event(1, specialchars, specialchars, specialchars, new Category(1, specialchars, specialchars), timestamp, timestamp + 100);
26 | }
27 |
28 | PManagerTest::~PManagerTest() {
29 | delete this->valid_event;
30 | delete this->valid_event_2;
31 | delete this->valid_event_3;
32 | delete this->noname_event;
33 | delete this->invalid_time_event;
34 | delete this->noname_category;
35 | delete this->valid_category;
36 | delete this->specialchars_category;
37 | delete this->valid_category_2;
38 | delete this->valid_default_category;
39 | delete this->specialchars_event;
40 | delete this->event_with_invalid_category;
41 | delete this->event_with_null_category;
42 | }
43 |
44 | void PManagerTest::test_all() {
45 | test_get_db_name();
46 | test_remove_db();
47 | test_init_db();
48 | test_get_db_list();
49 | test_add_event();
50 | test_get_events_of_month();
51 | test_remove_event();
52 | test_add_category();
53 | test_get_categories();
54 | test_remove_category();
55 | test_get_category();
56 | test_edit_event();
57 | test_get_all_events();
58 | test_get_events();
59 | test_remove_past_events();
60 | test_edit_category();
61 | test_set_db();
62 | test_load_db();
63 | test_save_db();
64 | test_import_db_iCal_format();
65 | test_export_db_iCal_format();
66 | }
67 |
68 | void PManagerTest::test_get_db_name() {
69 | Test::print("test_get_db_name ");
70 | PManager pm;
71 | bool ret = (pm.get_db_name() == DEFAULT_DATABASE_NAME);
72 | PManager pm2("test.sql");
73 | ASSERT (ret && (pm2.get_db_name() == "test.sql"))
74 | pm.remove_db();
75 | pm2.remove_db();
76 | }
77 |
78 | void PManagerTest::test_remove_db() {
79 | Test::print("test_remove_db ");
80 | PManager pm;
81 | bool ret = pm.remove_db();
82 | if (pm.get_db_name() != DEFAULT_DATABASE_NAME) {
83 | ret = ret && !std::experimental::filesystem::exists(pm.get_db_folder() + pm.get_db_name());
84 | } else {
85 | ret = ret && std::experimental::filesystem::exists(pm.get_db_folder() + pm.get_db_name());
86 | }
87 | ASSERT (ret)
88 | }
89 |
90 | void PManagerTest::test_init_db() {
91 | Test::print("test_init_db ");
92 | PManager pm;
93 | pm.init_db("test.sql");
94 | ASSERT (std::experimental::filesystem::exists(pm.get_db_folder() + "test.sql"))
95 | pm.remove_db();
96 | }
97 |
98 | void PManagerTest::test_get_db_list() {
99 | Test::print("test_get_db_list ");
100 | string names[] = {"test1.sql", "test2.sql"};
101 | PManager pm;
102 | pm.remove_db();
103 | pm.init_db(names[0]);
104 | bool ret = (std::experimental::filesystem::exists(pm.get_db_folder() + names[0]));
105 | pm.remove_db();
106 | pm.init_db(names[1]);
107 | ASSERT (ret && std::experimental::filesystem::exists(pm.get_db_folder() + names[1]))
108 | pm.remove_db();
109 | }
110 |
111 | void PManagerTest::test_add_event() {
112 | Test::print("test_add_event ");
113 | PManager pm;
114 | ASSERT ((!(pm.add_event(this->noname_event))) &&
115 | (!(pm.add_event(this->invalid_time_event))) &&
116 | (!(pm.add_event(this->event_with_invalid_category))) &&
117 | (!(pm.add_event(this->event_with_null_category))) &&
118 | (pm.add_event(this->specialchars_event)) &&
119 | (pm.add_event(this->valid_event)))
120 | pm.remove_db();
121 | }
122 |
123 | void PManagerTest::test_get_events_of_month() {
124 | Test::print("test_get_events_of_month ");
125 | bool ret = false, ret2 = false;
126 | PManager pm;
127 | pm.add_event(this->valid_event);
128 | time_t timestamp = this->valid_event->getStart();
129 | struct tm *current_time = localtime(×tamp);
130 | list events = pm.get_events_of_month(current_time->tm_mon + 1, current_time->tm_year + 1900); // tm_mon is from 0 to 11, we need to have 1 - 12
131 | if (!(events.empty())) {
132 | list::iterator it = events.begin();
133 | ret = this->valid_event->equals(**it); // *it has type Event*
134 | delete *it;
135 | }
136 | pm.add_event(this->valid_event_2);
137 | timestamp = this->valid_event_2->getEnd();
138 | current_time = localtime(×tamp);
139 | events = pm.get_events_of_month(current_time->tm_mon + 1, current_time->tm_year + 1900);
140 | if (!(events.empty())) {
141 | list::iterator it = events.begin();
142 | ret2 = this->valid_event_2->equals(**it); // *it has type Event*
143 | delete *it;
144 | }
145 | ASSERT (ret && ret2)
146 | pm.remove_db();
147 | }
148 |
149 | void PManagerTest::test_remove_event() {
150 | Test::print("test_remove_event ");
151 | bool ret;
152 | PManager pm;
153 | pm.add_event(this->valid_event);
154 | pm.add_event(this->valid_event_2);
155 | ret = pm.remove_event(this->valid_event);
156 | time_t timestamp = this->valid_event->getStart();
157 | struct tm *current_time = localtime(×tamp);
158 | list events = pm.get_events_of_month(current_time->tm_mon + 1, current_time->tm_year + 1900);
159 | if (events.size() == 1) {
160 | list::iterator it = events.begin();
161 | ret = ret && this->valid_event_2->equals(**it); // *it has type Event*
162 | delete *it;
163 | } else ret = false;
164 | ASSERT (ret)
165 | pm.remove_db();
166 | }
167 |
168 | void PManagerTest::test_add_category() {
169 | Test::print("test_add_category ");
170 | PManager pm;
171 | ASSERT ((!(pm.add_category(this->noname_category))) && (pm.add_category(this->valid_category)))
172 | pm.remove_db();
173 | }
174 |
175 | void PManagerTest::test_get_categories() {
176 | Test::print("test_get_categories ");
177 | bool ret = false;
178 | PManager pm;
179 | pm.add_category(this->valid_category);
180 | vector categories = pm.get_categories();
181 | if (!(categories.empty())) {
182 | vector::iterator it = categories.begin();
183 | ret = (this->valid_category->equals(**it) || this->valid_default_category->equals(**it)); // *it has type Category*
184 | delete *it;
185 | it++;
186 | ret = ret && (this->valid_category->equals(**it) || this->valid_default_category->equals(**it)); // *it has type Category*
187 | delete *it;
188 | }
189 | ASSERT (ret)
190 | pm.remove_db();
191 | }
192 |
193 | void PManagerTest::test_remove_category() {
194 | Test::print("test_remove_category ");
195 | bool ret;
196 | PManager pm;
197 | pm.add_category(this->valid_category);
198 | pm.add_category(this->valid_category_2);
199 | ret = pm.remove_category(this->valid_category);
200 | ret = ret && pm.remove_category(this->valid_default_category); //Delete the default category
201 | vector categories = pm.get_categories();
202 | if (categories.size() == 1) {
203 | vector::iterator it = categories.begin();
204 | ret = ret && this->valid_category_2->equals(**it); // *it has type Category*
205 | delete *it;
206 | } else ret = false;
207 | ret = ret && pm.remove_category(this->valid_category_2);
208 | ret = ret && (pm.get_categories().size() == 0);
209 | pm.add_category(this->valid_default_category);
210 | pm.add_event(this->valid_event);
211 | ret = ret && (!pm.remove_category(this->valid_default_category)); //try to delete the default category, but it's referenced by valid_event, so the function should fails
212 | categories = pm.get_categories();
213 | if (categories.size() == 1) {
214 | vector::iterator it = categories.begin();
215 | ret = ret && this->valid_default_category->equals(**it); // *it has type Category*
216 | delete *it;
217 | } else ret = false;
218 | ASSERT (ret)
219 | pm.remove_db();
220 | }
221 |
222 | void PManagerTest::test_get_category() {
223 | Test::print("test_get_category ");
224 | PManager pm;
225 | pm.add_category(this->valid_category);
226 | ASSERT ((pm.get_category(this->valid_category->getId()))->equals(*this->valid_category))
227 | pm.remove_db();
228 | }
229 |
230 | void PManagerTest::test_edit_event() {
231 | Test::print("test_edit_event ");
232 | PManager pm;
233 | pm.add_event(this->valid_event);
234 | ASSERT (pm.replace_event(this->valid_event, this->valid_event_2) &&
235 | (!pm.replace_event(this->valid_event_2, this->noname_event)))
236 | pm.remove_db();
237 | }
238 |
239 | void PManagerTest::test_get_all_events() {
240 | Test::print("test_get_all_events ");
241 | bool ret = false, ret2 = false;
242 | PManager pm;
243 | pm.add_event(this->valid_event);
244 | pm.add_event(this->valid_event_2);
245 | list events = pm.get_all_events();
246 | if (!(events.empty())) {
247 | list::iterator it = events.begin();
248 | ret = this->valid_event_2->equals(**it); // *it has type Event*
249 | delete *it;
250 | it++;
251 | ret2 = this->valid_event->equals(**it);
252 | delete *it;
253 | }
254 | ASSERT (ret && ret2)
255 | pm.remove_db();
256 | }
257 |
258 | void PManagerTest::test_get_events() {
259 | Test::print("test_get_events ");
260 | bool ret = false;
261 | PManager pm;
262 | pm.add_event(this->valid_event);
263 | pm.add_category(this->valid_category_2);
264 | pm.add_event(this->valid_event_3);
265 | list events_cat1 = pm.get_events(this->valid_default_category);
266 | ret = (events_cat1.size() == 1);
267 | list::iterator it1 = events_cat1.begin();
268 | ret = ret && this->valid_event->equals(**it1);
269 | delete *it1;
270 | list events_cat2 = pm.get_events(this->valid_category_2);
271 | ret = ret && (events_cat2.size() == 1);
272 | list::iterator it2 = events_cat2.begin();
273 | ret = ret && this->valid_event_3->equals(**it2);
274 | delete *it2;
275 | list events = pm.get_events(NULL);
276 | ret = ret && (events.size() == 2);
277 | ASSERT (ret)
278 | pm.remove_db();
279 | }
280 |
281 | void PManagerTest::test_remove_past_events() {
282 | Test::print("test_remove_past_events ");
283 | bool ret;
284 | PManager pm;
285 | pm.add_event(this->valid_event);
286 | pm.add_event(this->valid_event_2);
287 | ret = pm.remove_past_events(this->valid_event_2->getEnd()-1);
288 | list events = pm.get_all_events();
289 | if (events.size() == 1) {
290 | list::iterator it = events.begin();
291 | ret = ret && this->valid_event_2->equals(**it); // *it has type Event*
292 | delete *it;
293 | } else ret = false;
294 | ASSERT (ret)
295 | pm.remove_db();
296 | }
297 |
298 | void PManagerTest::test_edit_category() {
299 | Test::print("test_edit_category ");
300 | PManager pm;
301 | pm.add_category(this->valid_category);
302 | ASSERT (!pm.replace_category(this->valid_category, this->noname_category) &&
303 | (pm.replace_category(this->valid_category, this->valid_category_2)))
304 | pm.remove_db();
305 | }
306 |
307 | void PManagerTest::test_set_db() {
308 | Test::print("test_set_db ");
309 | PManager pm;
310 | pm.init_db("test.sql");
311 | pm.set_db(DEFAULT_DATABASE_NAME);
312 | bool ret (pm.get_db_name() == DEFAULT_DATABASE_NAME);
313 | pm.add_category(this->valid_category);
314 | pm.add_event(this->valid_event);
315 | pm.set_db("test.sql");
316 | ret = ret && (pm.get_db_name() == "test.sql");
317 | pm.add_category(this->valid_category_2);
318 | pm.add_event(this->valid_event_2);
319 | pm.add_event(this->valid_event_3);
320 | pm.set_db(DEFAULT_DATABASE_NAME);
321 | ret = ret && (pm.get_db_name() == DEFAULT_DATABASE_NAME);
322 | ret = ret && ((pm.get_all_events().size() == 1) &&
323 | (pm.get_all_events().front()->equals(*this->valid_event)));
324 | pm.remove_db();
325 | pm.set_db("test.sql");
326 | ret = ret && (pm.get_db_name() == "test.sql");
327 | ASSERT (ret && (pm.get_all_events().size() == 2))
328 | pm.remove_db();
329 | }
330 |
331 | void PManagerTest::test_load_db() {
332 | Test::print("test_load_db ");
333 | bool ret;
334 | PManager pm;
335 | ofstream file;
336 | file.open("testdb.kal");
337 | file << "INSERT INTO Categories VALUES(" << this->valid_category->getId() << ",'" << this->valid_category->getName() << "','" << this->valid_category->getColor() << "');" << endl;
338 | file << "INSERT INTO Events VALUES(" << this->valid_event->getId() << ",'" << this->valid_event->getName() << "','" << this->valid_event->getDescription() << "','" << this->valid_event->getPlace() << "'," << this->valid_event->getCategory()->getId() << "," << this->valid_event->getStart() << "," << this->valid_event->getEnd() << ", NULL);" << endl;
339 | file.close();
340 | ret = pm.load_db("");
341 | ret = !ret && pm.load_db("notexist");
342 | ret = !ret && pm.load_db("testdb.kal");
343 | Category *category = pm.get_category(this->valid_category->getId());
344 | ret = ret && category->equals(*this->valid_category);
345 | delete category;
346 | list events = pm.get_all_events();
347 | if (events.size() == 1) {
348 | list::iterator it = events.begin();
349 | ret = ret && this->valid_event->equals(**it); // *it has type Event*
350 | delete *it;
351 | } else ret = false;
352 | pm.remove_db();
353 | remove("testdb.kal");
354 | ASSERT (ret)
355 | }
356 |
357 | void PManagerTest::test_save_db() {
358 | Test::print("test_save_db ");
359 | bool ret;
360 | PManager pm;
361 | ifstream file;
362 | string line;
363 | char insert_event[1024];
364 | char insert_category[1024];
365 | snprintf(insert_event, 1024, "INSERT INTO Events VALUES(%u, '%s', '%s', '%s', %u, %ld, %ld);", this->valid_event->getId(), this->valid_event->getName().c_str(), this->valid_event->getDescription().c_str(), this->valid_event->getPlace().c_str(), this->valid_event->getCategory()->getId(), this->valid_event->getStart(), this->valid_event->getEnd());
366 | snprintf(insert_category, 1024, "INSERT INTO Categories VALUES(%u, '%s', '%s');", this->valid_default_category->getId(), this->valid_default_category->getName().c_str(), this->valid_default_category->getColor().c_str());
367 | pm.add_event(this->valid_event);
368 | ret = pm.save_db("testdb");
369 | file.open("testdb.kal");
370 | getline (file,line);
371 | ret = ret && ((line == insert_category) || (line == insert_event));
372 | getline (file,line);
373 | ret = ret && ((line == insert_event) || (line == insert_category));
374 | getline (file,line);
375 | ret = ret && (line == "");
376 | file.close();
377 | pm.remove_db();
378 | remove("testdb.kal");
379 | ASSERT (ret)
380 | }
381 |
382 | void PManagerTest::test_import_db_iCal_format() {
383 | Test::print("test_import_db_iCal_format ");
384 | PManager pm;
385 | ofstream file;
386 | bool ret;
387 | ret = pm.import_db_iCal_format("",this->valid_default_category);
388 | ret = !ret && !pm.import_db_iCal_format("notexists",this->valid_default_category);
389 | file.open("temp.ics");
390 | file << "BEGIN:VEVENT" << endl << "UID:0" << endl << "DTSTART;VALUE=DATE:20161231" << endl << "DTEND;VALUE=DATE:20170101" << endl << "SUMMARY:test" << endl << "DESCRIPTION:multi\nline\ndescription" << endl << "END:VEVENT" << endl;
391 | file << "BEGIN:VEVENT" << endl << "UID:1" << endl << "DTSTART;VALUE=DATE:20130512" << endl << "DTEND;VALUE=DATE:20130513" << endl << "SUMMARY:test2" << endl << "END:VEVENT" << endl;
392 | file.close();
393 | ret = ret && pm.import_db_iCal_format("temp.ics",this->valid_default_category);
394 | list events = pm.get_all_events();
395 | if (events.size() == 2) {
396 | list::iterator it = events.begin();
397 | ret = ret && ((**it).getName() == "test2");
398 | ret = ret && ((**it).getCategory()->getId() == this->valid_default_category->getId());
399 | //TODO: checks if the following test is correct
400 | ret = ret && ((**it).getStart() < (**it).getEnd());
401 | delete *it;
402 | } else ret = false;
403 | pm.remove_db();
404 | remove("temp.ics");
405 | ASSERT (ret)
406 | }
407 |
408 | void PManagerTest::test_export_db_iCal_format() {
409 | Test::print("test_export_db_iCal_format ");
410 | string line;
411 | PManager pm;
412 | pm.add_event(this->valid_event);
413 | ifstream file;
414 | bool ret;
415 | ret = pm.export_db_iCal_format(pm.get_all_events(),"");
416 | ret = !ret && pm.export_db_iCal_format(pm.get_all_events(),"temp.ics");
417 | file.open("temp.ics");
418 | int linenumber = 0;
419 | while ( getline (file,line,'\n') ) {
420 |
421 | if (linenumber == 0) {
422 | ret = ret && (line == "BEGIN:VCALENDAR");
423 | linenumber++;
424 | continue;
425 | }
426 | if (linenumber == 3) {
427 | char buff[9];
428 | time_t start = this->valid_event->getStart();
429 | strftime(buff, sizeof(buff),"%Y%m%d",localtime((const time_t*)&start));
430 | ret = ret && (line == string("DTSTART;VALUE=DATE:") + string(buff));
431 | linenumber++;
432 | continue;
433 | }
434 | if (linenumber == 5) {
435 | ret = ret && (line == string("UID:") + to_string(this->valid_event->getId()));
436 | linenumber++;
437 | continue;
438 | }
439 | if (linenumber == 8) {
440 | ret = ret && (line == string("SUMMARY:") + this->valid_event->getName());
441 | linenumber++;
442 | continue;
443 | }
444 | linenumber++;
445 | }
446 | file.close();
447 | pm.remove_db();
448 | remove("temp.ics");
449 | ASSERT (ret)
450 | }
451 |
--------------------------------------------------------------------------------
/src/test/persistence/pmanager_test.h:
--------------------------------------------------------------------------------
1 | #ifndef PMANAGERTEST_H
2 | #define PMANAGERTEST_H
3 |
4 | #include
5 |
6 | #include "../test.h"
7 | #include "../../persistence/pmanager.h"
8 |
9 | class PManagerTest
10 | {
11 | private:
12 | Event *valid_event;
13 | Event *valid_event_2;
14 | Event *valid_event_3;
15 | Event *noname_event;
16 | Event *specialchars_event;
17 | Event *invalid_time_event;
18 | Event *event_with_invalid_category;
19 | Event *event_with_null_category;
20 | Category *valid_category;
21 | Category *valid_category_2;
22 | Category *valid_default_category;
23 | Category *noname_category;
24 | Category *specialchars_category;
25 |
26 | public:
27 | PManagerTest();
28 | ~PManagerTest();
29 | void test_all();
30 | void test_init_db();
31 | void test_add_event();
32 | void test_remove_event();
33 | void test_add_category();
34 | void test_get_events_of_month();
35 | void test_remove_category();
36 | void test_get_categories();
37 | void test_remove_db();
38 | void test_get_category();
39 | void test_edit_event();
40 | void test_get_events();
41 | void test_get_all_events();
42 | void test_remove_past_events();
43 | void test_edit_category();
44 | void test_load_db();
45 | void test_save_db();
46 | void test_import_db_iCal_format();
47 | void test_export_db_iCal_format();
48 | void test_get_db_name();
49 | void test_set_db();
50 | void test_get_db_list();
51 | };
52 |
53 | #endif // PMANAGERTEST_H
54 |
--------------------------------------------------------------------------------
/src/test/test.cpp:
--------------------------------------------------------------------------------
1 | #include "test.h"
2 |
3 | Test::Test()
4 | {
5 |
6 | }
7 |
8 | void Test::test_all() {
9 | test_persistence();
10 | test_util();
11 | }
12 |
13 | void Test::test_persistence() {
14 | print("\nStarting persistence tests\n");
15 | PManagerTest pmt;
16 | pmt.test_all();
17 | }
18 | void Test::test_util() {
19 | print("\nStarting util tests\n");
20 | DateUtilTest dut;
21 | dut.test_all();
22 | printf("date util disabilitato\n");
23 | EventUtilTest eut;
24 | eut.test_all();
25 | }
26 |
--------------------------------------------------------------------------------
/src/test/test.h:
--------------------------------------------------------------------------------
1 | #ifndef TEST_H
2 | #define TEST_H
3 |
4 | #include
5 | #include "persistence/pmanager_test.h"
6 | #include "util/dateutil_test.h"
7 | #include "util/eventutil_test.h"
8 |
9 | #define ASSERT(X) if (X) Test::print_green("passed\n"); else { Test::print_red("fail\n"); exit(1); }
10 |
11 | using namespace std;
12 |
13 | /* Unit testing class */
14 |
15 | class Test
16 | {
17 | public:
18 | Test();
19 | void test_all();
20 | void test_persistence();
21 | void test_util();
22 | /* fflush needed to see the output on the Application Output of QT Creator */
23 | static void print_green(string s) { printf("\033[32m%s\033[39m", s.c_str()); fflush(stdout); }
24 | static void print_red(string s) { printf("\033[31m%s\033[39m", s.c_str()); fflush(stdout); }
25 | static void print(string s) { printf("%s", s.c_str()); fflush(stdout); }
26 | };
27 |
28 | #endif // TEST_H
29 |
--------------------------------------------------------------------------------
/src/test/util/dateutil_test.cpp:
--------------------------------------------------------------------------------
1 | #include "dateutil_test.h"
2 |
3 | #include
4 |
5 | DateUtilTest::DateUtilTest()
6 | {
7 | this->mar_10_2016 = new Date(10, 4, 3, 2016);
8 | this->may_1_2102 = new Date(1, 1, 5, 2102);
9 | this->sep_28_1927 = new Date(28, 3, 9, 1927);
10 | this->jan_1_2015 = new Date(1, 4, 1, 2015);
11 | this->dec_31_2014 = new Date(31, 3, 12, 2014);
12 | this->feb_29_2016 = new Date(29, 1, 2, 2016);
13 | this->mar_1_2015 = new Date(1, 7, 3, 2015);
14 | this->mar_1_2016 = new Date(1, 2, 3, 2016);
15 | this->mar_1_2017 = new Date(1, 3, 3, 2017);
16 | this->mar_1_2018 = new Date(1, 4, 3, 2018);
17 | this->sep_1_1927 = new Date(1, 4, 9, 1927);
18 | this->jan_12_2015 = new Date(12, 1, 1, 2015);
19 | this->jan_31_2015 = new Date(31, 6, 1, 2015);
20 | this->feb_21_2016 = new Date(21, 7, 2, 2016);
21 | this->feb_1_2016 = new Date(1, 1, 2, 2016);
22 | this->dec_14_2014 = new Date(14, 7, 12, 2014);
23 | this->aug_20_2000 = new Date(20, 7, 8, 2000);
24 | this->aug_21_2000 = new Date(21, 1, 8, 2000);
25 | }
26 |
27 | DateUtilTest::~DateUtilTest()
28 | {
29 | delete this->mar_10_2016;
30 | delete this->may_1_2102;
31 | delete this->sep_28_1927;
32 | delete this->jan_1_2015;
33 | delete this->dec_31_2014;
34 | delete this->feb_29_2016;
35 | delete this->mar_1_2015;
36 | delete this->mar_1_2016;
37 | delete this->mar_1_2017;
38 | delete this->mar_1_2018;
39 | delete this->sep_1_1927;
40 | delete this->jan_12_2015;
41 | delete this->feb_21_2016;
42 | delete this->feb_1_2016;
43 | delete this->dec_14_2014;
44 | delete this->aug_20_2000;
45 | delete this->aug_21_2000;
46 | }
47 |
48 | void DateUtilTest::test_all() {
49 | test_get_days_in_month();
50 | test_literal2numeric_day_of_week();
51 | test_numeric2literal_day_of_week();
52 | test_get_literal_month();
53 | test_date_from_timestamp();
54 | test_get_first_day_of_month();
55 | test_get_last_day_of_month();
56 | test_increase_month();
57 | test_decrease_month();
58 | test_increase_day();
59 | test_decrease_day();
60 | test_increase_year();
61 | test_decrease_year();
62 | test_is_leap();
63 | }
64 |
65 | void DateUtilTest::test_get_days_in_month() {
66 | Test::print("test_get_days_in_month ");
67 | ASSERT ((DateUtil::get_days_in_month(this->feb_29_2016->getMonth(), this->feb_29_2016->getYear()) == 29) &&
68 | (DateUtil::get_days_in_month(this->jan_1_2015->getMonth(), this->jan_1_2015->getYear()) == 31) && //January
69 | (DateUtil::get_days_in_month(this->sep_28_1927->getMonth(), this->sep_28_1927->getYear()) == 30))
70 | }
71 |
72 | void DateUtilTest::test_literal2numeric_day_of_week() {
73 | Test::print("test_literal2numeric_day_of_week ");
74 | ASSERT ((DateUtil::literal2numeric_day_of_week(string("Monday")) == 1) &&
75 | (DateUtil::literal2numeric_day_of_week(string("Sunday")) == 7) &&
76 | (DateUtil::literal2numeric_day_of_week(string("Thursday")) == 4) &&
77 | (DateUtil::literal2numeric_day_of_week(string("")) == -1))
78 | }
79 |
80 | void DateUtilTest::test_numeric2literal_day_of_week() {
81 | Test::print("test_numeric2literal_day_of_week ");
82 | ASSERT ((DateUtil::numeric2literal_day_of_week(1) == string("Monday")) &&
83 | (DateUtil::numeric2literal_day_of_week(7) == string("Sunday")) &&
84 | (DateUtil::numeric2literal_day_of_week(2) == string("Tuesday")) &&
85 | (DateUtil::numeric2literal_day_of_week(0) == string("")) &&
86 | (DateUtil::numeric2literal_day_of_week(8) == string("")))
87 | }
88 |
89 | void DateUtilTest::test_get_literal_month() {
90 | Test::print("test_timeutil_get_literal_month ");
91 | ASSERT ((DateUtil::get_literal_month(1) == string("January")) &&
92 | (DateUtil::get_literal_month(12) == string("December")) &&
93 | (DateUtil::get_literal_month(8) == string("August")) &&
94 | (DateUtil::get_literal_month(0) == string("")) &&
95 | (DateUtil::get_literal_month(13) == string("")))
96 | }
97 |
98 | void DateUtilTest::test_get_first_day_of_month() {
99 | Test::print("test_get_first_day_of_month ");
100 | ASSERT ((DateUtil::get_first_day_of_month(*this->jan_1_2015) == *this->jan_1_2015) &&
101 | (DateUtil::get_first_day_of_month(*this->mar_10_2016) == *this->mar_1_2016) &&
102 | (DateUtil::get_first_day_of_month(*this->sep_28_1927) == *this->sep_1_1927) &&
103 | (DateUtil::get_first_day_of_month(*this->jan_12_2015)) == *this->jan_1_2015 &&
104 | (DateUtil::get_first_day_of_month(*this->feb_21_2016)) == *this->feb_1_2016)
105 | }
106 |
107 | void DateUtilTest::test_date_from_timestamp() {
108 | Test::print("test_date_from_timestamp ");
109 | ASSERT ((DateUtil::date_from_timestamp(1420070400)) == *this->jan_1_2015 &&
110 | (DateUtil::date_from_timestamp(1419984000)) == *this->dec_31_2014 &&
111 | (DateUtil::date_from_timestamp(1456012800)) == *this->feb_21_2016 &&
112 | (DateUtil::date_from_timestamp(4175884800)) == *this->may_1_2102 &&
113 | /* remember: the timestamp will be converted into an unsigned long */
114 | (DateUtil::date_from_timestamp(-1333670400)) == *this->sep_28_1927)
115 | }
116 |
117 | void DateUtilTest::test_get_last_day_of_month() {
118 | Test::print("test_get_last_day_of_month ");
119 | ASSERT ((DateUtil::get_last_day_of_month(*this->feb_21_2016)) == *this->feb_29_2016 &&
120 | (DateUtil::get_last_day_of_month(*this->dec_14_2014)) == *this->dec_31_2014)
121 | }
122 |
123 | void DateUtilTest::test_increase_month() {
124 | Test::print("test_increase_month ");
125 | ASSERT (DateUtil::increase_month(*this->feb_1_2016) == *this->mar_1_2016 &&
126 | DateUtil::increase_month(*this->dec_31_2014) == *this->jan_31_2015)
127 | }
128 |
129 | void DateUtilTest::test_decrease_month() {
130 | Test::print("test_decrease_month ");
131 | ASSERT (DateUtil::decrease_month(*this->mar_1_2016) == *this->feb_1_2016 &&
132 | DateUtil::decrease_month(*this->jan_31_2015) == *this->dec_31_2014)
133 | }
134 |
135 | void DateUtilTest::test_increase_day() {
136 | Test::print("test_increase_day ");
137 | ASSERT (DateUtil::increase_day(*this->feb_29_2016) == *this->mar_1_2016 &&
138 | DateUtil::increase_day(*this->dec_31_2014) == *this->jan_1_2015 &&
139 | DateUtil::increase_day(*this->aug_20_2000) == *this->aug_21_2000)
140 | }
141 |
142 | void DateUtilTest::test_decrease_day() {
143 | Test::print("test_decrease_day ");
144 | ASSERT (DateUtil::decrease_day(*this->mar_1_2016) == *this->feb_29_2016 &&
145 | DateUtil::decrease_day(*this->jan_1_2015) == *this->dec_31_2014 &&
146 | DateUtil::decrease_day(*this->aug_21_2000) == *this->aug_20_2000)
147 | }
148 |
149 | void DateUtilTest::test_increase_year() {
150 | Test::print("test_increase_year ");
151 | ASSERT (DateUtil::increase_year(*this->feb_29_2016) == *this->mar_1_2017 &&
152 | DateUtil::increase_year(*this->mar_1_2016) == *this->mar_1_2017 &&
153 | DateUtil::increase_year(*this->mar_1_2017) == *this->mar_1_2018 &&
154 | DateUtil::increase_year(*this->mar_1_2015) == *this->mar_1_2016)
155 | }
156 |
157 | void DateUtilTest::test_decrease_year() {
158 | Test::print("test_decrease_year ");
159 | ASSERT (DateUtil::decrease_year(*this->mar_1_2017) == *this->mar_1_2016 &&
160 | DateUtil::decrease_year(*this->mar_1_2018) == *this->mar_1_2017 &&
161 | DateUtil::decrease_year(*this->mar_1_2016) == *this->mar_1_2015)
162 | }
163 |
164 | void DateUtilTest::test_is_leap() {
165 | Test::print("test_is_leap ");
166 | ASSERT (DateUtil::is_leap(this->mar_1_2016->getYear()) &&
167 | DateUtil::is_leap(this->aug_20_2000->getYear()) &&
168 | !DateUtil::is_leap(this->jan_12_2015->getYear()))
169 | }
170 |
--------------------------------------------------------------------------------
/src/test/util/dateutil_test.h:
--------------------------------------------------------------------------------
1 | #ifndef DATEUTILTEST_H
2 | #define DATEUTILTEST_H
3 |
4 | #include "../test.h"
5 | #include "../../util/dateutil.h"
6 |
7 | class DateUtilTest
8 | {
9 | private:
10 | Date *mar_10_2016;
11 | Date *sep_28_1927;
12 | Date *feb_29_2016;
13 | Date *jan_1_2015;
14 | Date *dec_31_2014;
15 | Date *may_1_2102;
16 | Date *mar_1_2015;
17 | Date *mar_1_2016;
18 | Date *mar_1_2017;
19 | Date *mar_1_2018;
20 | Date *sep_1_1927;
21 | Date *jan_12_2015;
22 | Date *feb_21_2016;
23 | Date *feb_1_2016;
24 | Date *dec_14_2014;
25 | Date *jan_31_2015;
26 | Date *aug_20_2000;
27 | Date *aug_21_2000;
28 |
29 | public:
30 | DateUtilTest();
31 | ~DateUtilTest();
32 | void test_all();
33 | void test_get_literal_month();
34 | void test_numeric2literal_day_of_week();
35 | void test_literal2numeric_day_of_week();
36 | void test_get_days_in_month();
37 | void test_date_from_timestamp();
38 | void test_get_first_day_of_month();
39 | void test_get_last_day_of_month();
40 | void test_increase_month();
41 | void test_decrease_month();
42 | void test_increase_day();
43 | void test_decrease_day();
44 | void test_increase_year();
45 | void test_decrease_year();
46 | void test_is_leap();
47 | };
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/src/test/util/eventutil_test.cpp:
--------------------------------------------------------------------------------
1 | #include "eventutil_test.h"
2 |
3 | EventUtilTest::EventUtilTest()
4 | {
5 | time_t timestamp = 966038400L;
6 | string category("Default");
7 | string title("event title");
8 | string place("place");
9 | string description("this is a really complex description. Infact, there are several characters and white-spaces.");
10 | /* Events */
11 | this->valid_event = new Event(0, title, description, place, new Category(1, category, category), timestamp, timestamp + 100);
12 | this->event_with_null_category = new Event(0, title, description, place, NULL, timestamp, timestamp + 100);
13 | this->str_valid_event = title + "##" + description + "##" + place + "##" + category + "##" + to_string(timestamp) + "##" + to_string(timestamp + 100);
14 | this->str_event_title_only = title;
15 | this->str_event_with_invalid_category = title + "##" + description + "##" + place + "##Doesnt_exists##" + to_string(timestamp) + "##" + to_string(timestamp + 100);
16 | this->str_notitle_event = "##" + description + "##" + place + "##" + category + "##" + to_string(timestamp) + "##" + to_string(timestamp + 100);
17 | }
18 |
19 | EventUtilTest::~EventUtilTest() {
20 | delete this->valid_event;
21 | delete this->event_with_null_category;
22 | }
23 |
24 | void EventUtilTest::test_all() {
25 | test_parseString();
26 | }
27 |
28 | void EventUtilTest::test_parseString() {
29 | Test::print("test_parseString");
30 | ASSERT (EventUtil::parseString(this->str_valid_event)->equals(*this->valid_event) &&
31 | EventUtil::parseString(this->str_event_with_invalid_category)->equals(*this->event_with_null_category) &&
32 | EventUtil::parseString(this->str_event_title_only) == NULL &&
33 | EventUtil::parseString(this->str_notitle_event) == NULL)
34 | }
35 |
--------------------------------------------------------------------------------
/src/test/util/eventutil_test.h:
--------------------------------------------------------------------------------
1 | #ifndef EVENTUTIL_TEST_H
2 | #define EVENTUTIL_TEST_H
3 |
4 | #include "../test.h"
5 | #include "../../util/eventutil.h"
6 |
7 | class EventUtilTest
8 | {
9 | private:
10 | Event *valid_event;
11 | Event *event_with_null_category;
12 | string str_valid_event;
13 | string str_notitle_event;
14 | string str_event_with_invalid_category;
15 | string str_event_title_only;
16 |
17 | public:
18 | EventUtilTest();
19 | ~EventUtilTest();
20 | void test_all();
21 | void test_parseString();
22 | };
23 |
24 | #endif // EVENTUTIL_TEST_H
25 |
--------------------------------------------------------------------------------
/src/tools/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/tools/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | FacebookEventPlugin
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/tools/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.8
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.source=1.8
12 |
--------------------------------------------------------------------------------
/src/tools/fbeventplugin/FBEvent.java:
--------------------------------------------------------------------------------
1 | package fbeventplugin;
2 |
3 | import java.time.ZonedDateTime;
4 | import java.time.ZonedDateTime;
5 | import java.util.Date;
6 |
7 | public class FBEvent {
8 | private String title;
9 | private String description;
10 | private String place;
11 | private ZonedDateTime start;
12 | private ZonedDateTime end;
13 |
14 | @Override
15 | public String toString() {
16 | return "FBEvent [title=" + title + ", description=" + description + ", place=" + place + ", start=" + start.toString()
17 | + ", end=" + end.toString() + "]";
18 | }
19 |
20 | public FBEvent(String title, String description, String place, ZonedDateTime start, ZonedDateTime end) {
21 | super();
22 | this.title = title;
23 | this.description = description;
24 | this.place = place;
25 | this.start = start;
26 | this.end = end;
27 | }
28 |
29 | public String getTitle() {
30 | return title;
31 | }
32 | public void setTitle(String title) {
33 | this.title = title;
34 | }
35 | public String getDescription() {
36 | return description;
37 | }
38 | public void setDescription(String description) {
39 | this.description = description;
40 | }
41 | public String getPlace() {
42 | return place;
43 | }
44 | public void setPlace(String place) {
45 | this.place = place;
46 | }
47 | public ZonedDateTime getStart() {
48 | return start;
49 | }
50 | public void setStart(ZonedDateTime start) {
51 | this.start = start;
52 | }
53 | public ZonedDateTime getEnd() {
54 | return end;
55 | }
56 | public void setEnd(ZonedDateTime end) {
57 | this.end = end;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/tools/fbeventplugin/FBParser.java:
--------------------------------------------------------------------------------
1 | package fbeventplugin;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.InputStreamReader;
5 | import java.net.HttpURLConnection;
6 | import java.net.URL;
7 | import java.sql.Timestamp;
8 | import java.text.DateFormat;
9 | import java.text.ParseException;
10 | import java.text.SimpleDateFormat;
11 | import java.time.ZonedDateTime;
12 | import java.util.Date;
13 |
14 | public class FBParser {
15 |
16 | private String filterSpecialChars(String str) {
17 | return str.replaceAll("'", "'")
18 | .replaceAll(""", "\\\"")
19 | .replaceAll("@", "@")
20 | .replaceAll("
", "\r\n")
21 | .replaceAll("(?s)<[^>]*>(\\s*<[^>]*>)*", " ");
22 | }
23 |
24 | private FBEvent createEvent(String html) {
25 | String title;
26 | String description;
27 | String place;
28 | ZonedDateTime start = null;
29 | ZonedDateTime end = null;
30 |
31 | int pos = html.indexOf("pageTitle") + 11;
32 | title = filterSpecialChars(html.substring(pos, html.indexOf("", pos)));
38 | } catch (Exception e) {
39 | System.err.println("Exception occurred in date parsing: "+e.getMessage());
40 | return null;
41 | }
42 | pos = html.indexOf("fcg\">", html.indexOf("event-permalink-location", pos)) + 5;
43 | place = html.substring(pos, html.indexOf("...", "");
46 | description = filterSpecialChars(html.substring(pos, html.indexOf("
4 |
5 | static string months[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
6 | static string week_days[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
7 |
8 | DateUtil::DateUtil()
9 | {
10 |
11 | }
12 |
13 | Date DateUtil::get_current_date() {
14 | return date_from_timestamp(static_cast (time(NULL)));
15 | }
16 |
17 | string DateUtil::get_literal_month(int m) {
18 | if ((m < 1) || (m > 12))
19 | return string("");
20 | else
21 | return months[m-1];
22 | }
23 |
24 | string DateUtil::numeric2literal_day_of_week(int d) {
25 | if ((d < 1) || (d > 7))
26 | return string("");
27 | else
28 | return week_days[d-1];
29 | }
30 |
31 | int DateUtil::literal2numeric_day_of_week(const string &d) {
32 | int i = 0;
33 | for (i = 0; i < 7; i++) {
34 | if (d == week_days[i])
35 | return i+1;
36 | }
37 | return -1;
38 | }
39 |
40 | bool DateUtil::is_leap(int year) {
41 | return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
42 | }
43 |
44 | int DateUtil::get_days_in_month(int month, int year) {
45 | int numberOfDays;
46 | if (month == 4 || month == 6 || month == 9 || month == 11)
47 | numberOfDays = 30;
48 | else if (month == 2)
49 | {
50 | if (is_leap(year))
51 | numberOfDays = 29;
52 | else
53 | numberOfDays = 28;
54 | }
55 | else
56 | numberOfDays = 31;
57 | return numberOfDays;
58 | }
59 |
60 | /* Assume to receive a valid timestamp */
61 | Date DateUtil::date_from_timestamp(time_t timestamp) {
62 | const time_t t = timestamp;
63 | struct tm *tm = localtime(&t);
64 | Date date(tm->tm_mday, tm->tm_wday ?: 7, tm->tm_mon + 1, tm->tm_year + 1900);
65 | //free(tm); segfault?
66 | return date;
67 | }
68 |
69 | Date DateUtil::get_first_day_of_month(Date &date) {
70 | int wday = date.getWeekDay() - (date.getMonthDay() % 7) + 1;
71 | //Normalization
72 | if (wday <= 0) wday += 7;
73 | else if (wday > 7) wday -= 7;
74 | return Date(1, wday, date.getMonth(), date.getYear());
75 | }
76 |
77 | Date DateUtil::get_last_day_of_month(Date &date) {
78 | Date first_day = get_first_day_of_month(date);
79 | int tot_days = get_days_in_month(date.getMonth(), date.getYear());
80 | int wday = ((tot_days % 7) ?: 7) + first_day.getWeekDay() - 1;
81 | return Date(tot_days, wday, date.getMonth(), date.getYear());
82 | }
83 |
84 | //Attention: each month has a different number of days (e.g. 31 doesn't exist in february)
85 | //Assume to get a valid time (i.e. no negative numbers, etc.)
86 | Date DateUtil::increase_month(Date date) {
87 | Date last_day_curr_month = get_last_day_of_month(date);
88 | Date first_day_next_month;
89 | if (date.getMonth() < 12) {
90 | first_day_next_month = Date(1, (last_day_curr_month.getWeekDay() % 7) + 1, date.getMonth() + 1, date.getYear());
91 | } else { //Go to next year
92 | first_day_next_month = Date(1, (last_day_curr_month.getWeekDay() % 7) + 1, 1, date.getYear() + 1);
93 | }
94 | return Date(date.getMonthDay(), ((date.getMonthDay() % 7) ?: 7) + first_day_next_month.getWeekDay() - 1, first_day_next_month.getMonth(), first_day_next_month.getYear());
95 | }
96 |
97 | //Assume to get a valid time (i.e. no negative numbers, etc.)
98 | Date DateUtil::decrease_month(Date date) {
99 | Date first_day_curr_month = get_first_day_of_month(date);
100 | Date last_day_prev_month;
101 | if (date.getMonth() > 1) {
102 | last_day_prev_month = Date(get_days_in_month(date.getMonth() - 1, date.getYear()), (first_day_curr_month.getWeekDay() - 1) ?: 7, date.getMonth() - 1, date.getYear());
103 | } else { //Go to previous year
104 | last_day_prev_month = Date(get_days_in_month(12, date.getYear() - 1), (first_day_curr_month.getWeekDay() - 1) ?: 7, 12, date.getYear() - 1);
105 | }
106 | Date first_day_prev_month = get_first_day_of_month(last_day_prev_month);
107 | return Date(date.getMonthDay(), ((date.getMonthDay() % 7) ?: 7) + first_day_prev_month.getWeekDay() - 1, last_day_prev_month.getMonth(), last_day_prev_month.getYear());
108 | }
109 |
110 | Date DateUtil::increase_day(Date date) {
111 | Date last_day_curr_month = get_last_day_of_month(date);
112 | if (date.getMonthDay() < last_day_curr_month.getMonthDay())
113 | return Date(date.getMonthDay() + 1, ((date.getWeekDay() + 1) % 7) ?: 7, date.getMonth(), date.getYear());
114 | else { //This is the last day of the current month
115 | Date next_month = increase_month(date);
116 | return get_first_day_of_month(next_month);
117 | }
118 | }
119 |
120 | Date DateUtil::decrease_day(Date date) {
121 | if (date.getMonthDay() > 1)
122 | return Date(date.getMonthDay() - 1, (date.getWeekDay() - 1) ?: 7, date.getMonth(), date.getYear());
123 | else { //This is the first day of the current month
124 | Date previous_month = decrease_month(date);
125 | return get_last_day_of_month(previous_month);
126 | }
127 | }
128 |
129 | Date DateUtil::increase_year(Date date) {
130 | if ((date.getMonthDay() == 29) && (date.getMonth() == 2)) /* Leap year */
131 | return Date(1, ((date.getWeekDay() + 2) % 7) ?: 7, date.getMonth() + 1, date.getYear() + 1);
132 | else {
133 | int offset = 1;
134 | if (is_leap(date.getYear() + 1))
135 | offset = 2;
136 | return Date(date.getMonthDay(), ((date.getWeekDay() + offset) % 7) ?: 7, date.getMonth(), date.getYear() + 1);
137 | }
138 | }
139 |
140 | Date DateUtil::decrease_year(Date date) {
141 | int weekday = ((date.getWeekDay() - 1) % 7) ?: 7;
142 | if (is_leap(date.getYear()))
143 | weekday = ((weekday - 1) % 7) ?: 7;
144 | return Date(date.getMonthDay(), weekday, date.getMonth(), date.getYear() - 1);
145 | }
146 |
--------------------------------------------------------------------------------
/src/util/dateutil.h:
--------------------------------------------------------------------------------
1 | #ifndef DATEUTIL_H
2 | #define DATEUTIL_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include "../model/date.h"
9 |
10 | #define SECONDS_IN_1DAY 86400
11 |
12 | using namespace std;
13 |
14 | class DateUtil
15 | {
16 | public:
17 | DateUtil();
18 | static Date get_current_date();
19 | static string get_literal_month(int m); /* 1 => January, ... */
20 | static string numeric2literal_day_of_week(int d); /* Monday => 1, Tuesday => 2, ... */
21 | static int literal2numeric_day_of_week(const string &d); /* 1 => Monday, 2 => Tuesday, ... */
22 | static int get_days_in_month(int month, int year);
23 | static Date date_from_timestamp(time_t timestamp);
24 | static Date get_first_day_of_month(Date &date);
25 | static Date get_last_day_of_month(Date &date);
26 | static Date increase_month(Date date);
27 | static Date decrease_month(Date date);
28 | static Date increase_day(Date date);
29 | static Date decrease_day(Date date);
30 | static Date increase_year(Date date);
31 | static Date decrease_year(Date date);
32 | static bool is_leap(int year);
33 | };
34 |
35 | #endif
36 |
--------------------------------------------------------------------------------
/src/util/eventutil.cpp:
--------------------------------------------------------------------------------
1 | #include "eventutil.h"
2 |
3 | #include
4 |
5 | Event* EventUtil::parseString(const string &str_event) {
6 | string str = str_event;
7 | size_t pos = 0;
8 | string token[6];
9 | string delimiter("##");
10 | int i = 0;
11 | while ((pos = str.find(delimiter)) != std::string::npos) {
12 | token[i] = str.substr(0, pos);
13 | str.erase(0, pos + delimiter.length());
14 | i++;
15 | }
16 | if ((i < 5) || (token[0] == "")) return NULL;
17 | token[5] = str;
18 | Category *category = NULL;
19 | SecurePManager spm;
20 | vector categories = spm.get_categories();
21 | for (Category *c : categories) {
22 | if (token[3] == c->getName()) {
23 | category = new Category(*c);
24 | break;
25 | }
26 | }
27 | return new Event(0,token[0],token[1],token[2],category,stol(token[4]),stol(token[5]));
28 | }
29 |
--------------------------------------------------------------------------------
/src/util/eventutil.h:
--------------------------------------------------------------------------------
1 | #ifndef EVENTUTIL_H
2 | #define EVENTUTIL_H
3 |
4 | #include
5 | #include "../model/event.h"
6 | #include "../persistence/securepmanager.h"
7 |
8 | using namespace std;
9 |
10 | class EventUtil
11 | {
12 | public:
13 | static Event *parseString(const string &str_event);
14 | };
15 |
16 | #endif // EVENTUTIL_H
17 |
--------------------------------------------------------------------------------
/src/util/linuxnotifymanager.cpp:
--------------------------------------------------------------------------------
1 | #include "linuxnotifymanager.h"
2 |
3 | #include
4 |
5 | LinuxNotifyManager::LinuxNotifyManager()
6 | {
7 |
8 | }
9 |
10 | /* Send a notification with all the future events starting from the current date to the specified day */
11 | bool LinuxNotifyManager::notifyEvents(int dayoffset) {
12 | bool ret = true;
13 | PManager pm;
14 | Date current = DateUtil::get_current_date();
15 | Date untildate = current;
16 | for (int i = 0; i < dayoffset; i++) {
17 | untildate = DateUtil::increase_day(untildate);
18 | }
19 |
20 | list events = pm.get_events_of_month(current.getMonth(), current.getYear());
21 | if (untildate.getMonth() != current.getMonth()) //if untildate is in the next month, I'll append all the events of the next month
22 | events.splice(events.end(), pm.get_events_of_month(untildate.getMonth(), untildate.getYear()));
23 | for (Event *event : events) {
24 | Date start = DateUtil::date_from_timestamp(event->getStart());
25 | if ((start.compareTo(current) >= 0) && (start.compareTo(untildate) <= 0)) {
26 | /* Send a notification */
27 | ret = ret && this->notifyEvent(event);
28 | }
29 | }
30 | return ret;
31 | }
32 |
33 | bool LinuxNotifyManager::notifyEvent(Event *e) {
34 | QProcess process;
35 | Date start = DateUtil::date_from_timestamp(e->getStart());
36 | Date today = DateUtil::get_current_date();
37 | Date tomorrow = DateUtil::increase_day(today);
38 | QString title(start.toString(false).c_str());
39 | if (start == today)
40 | title = QString("Today");
41 | else if (start == tomorrow)
42 | title = QString("Tomorrow");
43 | process.start("notify-send", QStringList() << "-i" << ICON_NAME << title << e->getName().c_str());
44 | return process.waitForFinished();
45 | }
46 |
--------------------------------------------------------------------------------
/src/util/linuxnotifymanager.h:
--------------------------------------------------------------------------------
1 | #ifndef LINUXNOTIFYMANAGER_H
2 | #define LINUXNOTIFYMANAGER_H
3 |
4 | #include
5 | #include "../persistence/pmanager.h"
6 | #include "notifymanager.h"
7 | #include "dateutil.h"
8 |
9 | #define ICON_NAME "appointment-new" /* TODO: choose a better icon */
10 |
11 | class LinuxNotifyManager : public NotifyManager
12 | {
13 | public:
14 | LinuxNotifyManager();
15 | bool notifyEvents(int dayoffset);
16 | private:
17 | bool notifyEvent(Event *e);
18 | };
19 |
20 | #endif // LINUXNOTIFYMANAGER_H
21 |
--------------------------------------------------------------------------------
/src/util/notifymanager.h:
--------------------------------------------------------------------------------
1 | #ifndef NOTIFYMANAGER_H
2 | #define NOTIFYMANAGER_H
3 |
4 |
5 | class NotifyManager
6 | {
7 | public:
8 | virtual ~NotifyManager() {}
9 | virtual bool notifyEvents(int day) = 0;
10 | };
11 |
12 | #endif // NOTIFYMANAGER_H
13 |
--------------------------------------------------------------------------------
/src/util/pluginmanager.cpp:
--------------------------------------------------------------------------------
1 | #include "pluginmanager.h"
2 |
3 | PluginManager::PluginManager()
4 | {
5 | experimental::filesystem::path dir(TOOLS_FOLDER);
6 | experimental::filesystem::create_directory(dir);
7 | for (experimental::filesystem::directory_entry e : experimental::filesystem::directory_iterator(TOOLS_FOLDER)) {
8 | experimental::filesystem::path p = e.path();
9 | if ((p.extension() == ".sh") || (p.extension() == ".bat"))
10 | this->tools.push_back(p.filename());
11 | }
12 | }
13 |
14 | void PluginManager::runTool(const string &name) {
15 | string cmd = string(TOOLS_FOLDER) + "/\"" + name +"\"";
16 | system(cmd.c_str());
17 | }
18 |
19 | vector PluginManager::get_tools() {
20 | return this->tools;
21 | }
22 |
--------------------------------------------------------------------------------
/src/util/pluginmanager.h:
--------------------------------------------------------------------------------
1 | #ifndef PLUGINMANAGER_H
2 | #define PLUGINMANAGER_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #define TOOLS_FOLDER "tools"
9 |
10 | using namespace std;
11 |
12 | class PluginManager
13 | {
14 | private:
15 | vector tools;
16 |
17 | public:
18 | PluginManager();
19 | void runTool(const string &name);
20 | vector get_tools();
21 | };
22 |
23 | #endif // PLUGINMANAGER_H
24 |
--------------------------------------------------------------------------------
/src/view/categorydialog.cpp:
--------------------------------------------------------------------------------
1 | #include "categorydialog.h"
2 |
3 | #include
4 | #include
5 |
6 | CategoryDialog::CategoryDialog(View *parentView, QWidget *parent) :
7 | QDialog(parent),
8 | ui(new Ui::CategoryDialog)
9 | {
10 | this->parent = parentView;
11 | this->setFixedWidth(300);
12 | this->setFixedHeight(400);
13 | this->setWindowTitle("Category Manager");
14 | this->pm = new PManager;
15 | QVBoxLayout *layout = new QVBoxLayout;
16 | this->list_widget = new QListWidget;
17 | connect(this->list_widget, &QListWidget::itemClicked, this, &CategoryDialog::on_item_click);
18 | load_categories();
19 | QPushButton *button_add = new QPushButton("&Add new category");
20 | QPushButton *button_cancel = new QPushButton("&Cancel");
21 | connect(button_cancel, &QPushButton::clicked, this, &CategoryDialog::on_button_cancel_click);
22 | connect(button_add, &QPushButton::clicked, this, &CategoryDialog::on_button_add_click);
23 | layout->addWidget(this->list_widget);
24 | layout->addWidget(button_add);
25 | layout->addWidget(button_cancel);
26 | this->setLayout(layout);
27 | }
28 |
29 | CategoryDialog::~CategoryDialog()
30 | {
31 | delete ui;
32 | delete pm;
33 | for (Category *category : this->category_list) delete category;
34 | }
35 |
36 | void CategoryDialog::load_categories() {
37 | for (Category *category : this->category_list) delete category;
38 | this->category_list = this->pm->get_categories();
39 | this->list_widget->clear();
40 | for (Category *category : this->category_list) {
41 | QPixmap pixmap(ICON_SIZE, ICON_SIZE);
42 | pixmap.fill(QColor(category->getColor().c_str()));
43 | this->list_widget->addItem(new QListWidgetItem(QIcon(pixmap), QString(category->getName().c_str())));
44 | }
45 | }
46 |
47 | void CategoryDialog::on_item_click() {
48 | CategoryEditDialog *category_edit_dialog = new CategoryEditDialog(this);
49 | category_edit_dialog->show();
50 | }
51 |
52 | void CategoryDialog::on_button_cancel_click() {
53 | this->close();
54 | delete this;
55 | }
56 |
57 | void CategoryDialog::on_button_add_click() {
58 | CategoryEditDialog *category_edit_dialog = new CategoryEditDialog(this);
59 | category_edit_dialog->show();
60 | }
61 |
62 | vector CategoryDialog::getCategoryList() {
63 | return this->category_list;
64 | }
65 |
66 | QListWidget* CategoryDialog::getListWidget() {
67 | return this->list_widget;
68 | }
69 |
70 | PManager* CategoryDialog::getPManager() {
71 | return this->pm;
72 | }
73 | View* CategoryDialog::getParentView() {
74 | return this->parent;
75 | }
76 |
--------------------------------------------------------------------------------
/src/view/categorydialog.h:
--------------------------------------------------------------------------------
1 | #ifndef CATEGORYDIALOG_H
2 | #define CATEGORYDIALOG_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "ui_categorydialog.h"
11 | #include "persistence/pmanager.h"
12 | #include "categoryeditdialog.h"
13 | #include "view.h"
14 |
15 | #define DEFAULT_COLOR "#1022A0"
16 | #define ICON_SIZE 10
17 |
18 | namespace Ui {
19 | class CategoryDialog;
20 | }
21 |
22 | class CategoryDialog : public QDialog
23 | {
24 | Q_OBJECT
25 |
26 | private:
27 | Ui::CategoryDialog *ui;
28 | QListWidget *list_widget;
29 | vector category_list;
30 | PManager *pm;
31 | View *parent;
32 |
33 | public:
34 | explicit CategoryDialog(View *parentView, QWidget *parent = 0);
35 | ~CategoryDialog();
36 | QListWidget *getListWidget();
37 | vector getCategoryList();
38 | PManager* getPManager();
39 | View* getParentView();
40 | void load_categories();
41 |
42 | public slots:
43 | void on_button_cancel_click();
44 | void on_button_add_click();
45 | void on_item_click();
46 | };
47 |
48 | #endif // CATEGORYDIALOG_H
49 |
--------------------------------------------------------------------------------
/src/view/categoryeditdialog.cpp:
--------------------------------------------------------------------------------
1 | #include "categoryeditdialog.h"
2 |
3 | CategoryEditDialog::CategoryEditDialog(CategoryDialog *parentDialog, QWidget *parent) :
4 | QDialog(parent),
5 | ui(new Ui::CategoryEditDialog)
6 | {
7 | this->parentDialog = parentDialog;
8 | Category *selected_category = NULL;
9 | if (this->parentDialog->getListWidget()->selectedItems().size() != 0)
10 | selected_category = this->parentDialog->getCategoryList()[this->parentDialog->getListWidget()->currentIndex().row()];
11 | QVBoxLayout *vl = new QVBoxLayout;
12 | QHBoxLayout *hl = new QHBoxLayout;
13 | QHBoxLayout *hl2 = new QHBoxLayout;
14 | button_color = new QPushButton;
15 | if (selected_category != NULL)
16 | this->selected_color = QColor(selected_category->getColor().c_str());
17 | else
18 | this->selected_color = QColor(DEFAULT_COLOR);
19 | QPixmap pixmap(ICON_SIZE, ICON_SIZE);
20 | pixmap.fill(this->selected_color);
21 | button_color->setIcon(QIcon(pixmap));
22 | edit_name = new QLineEdit;
23 | if (selected_category != NULL)
24 | edit_name->setText(selected_category->getName().c_str());
25 | else
26 | edit_name->setPlaceholderText("Type a name for the new category");
27 | hl->addWidget(edit_name);
28 | hl->addWidget(button_color);
29 | connect(button_color, &QPushButton::clicked, this, &CategoryEditDialog::on_button_color_click);
30 | QPushButton *button_save = new QPushButton("&Save");
31 | QPushButton *button_delete = new QPushButton("&Delete");
32 | connect(button_delete, &QPushButton::clicked, this, &CategoryEditDialog::on_button_delete_click);
33 | connect(button_save, &QPushButton::clicked, this, &CategoryEditDialog::on_button_save_click);
34 | hl2->addWidget(button_save);
35 | hl2->addWidget(button_delete);
36 | vl->addLayout(hl);
37 | vl->addLayout(hl2);
38 | this->setModal(true);
39 | this->setWindowFlags(Qt::WindowCloseButtonHint);
40 | this->setWindowTitle("Category Edit Dialog");
41 | setLayout(vl);
42 | }
43 |
44 | CategoryEditDialog::~CategoryEditDialog() {
45 | delete this->ui;
46 | }
47 |
48 | void CategoryEditDialog::on_button_save_click() {
49 | if(this->edit_name->text().length() < 3) {
50 | QMessageBox::critical(this, "Error", "The name must have a length greater than 2", QMessageBox::Ok);
51 | return;
52 | }
53 | Category category(0, this->edit_name->text().toStdString(), this->selected_color.name().toStdString());
54 | //Create new category
55 | if ((this->parentDialog->getListWidget()->selectedItems().size() == 0) && (this->parentDialog->getPManager()->add_category(&category))) {
56 | this->parentDialog->load_categories();
57 | this->close();
58 | delete this;
59 | }else //Change the selected category
60 | if (this->parentDialog->getPManager()->replace_category(this->parentDialog->getCategoryList()[this->parentDialog->getListWidget()->currentIndex().row()], &category)) {
61 | this->parentDialog->load_categories();
62 | this->parentDialog->getParentView()->refresh_events();
63 | this->close();
64 | delete this;
65 | } else {
66 | QMessageBox::critical(this, "Error", "Persistence error. Try with a different name or color.");
67 | }
68 | }
69 |
70 | void CategoryEditDialog::on_button_delete_click() {
71 | if (this->parentDialog->getListWidget()->selectedItems().size() == 0) {
72 | QMessageBox::critical(this, "Error", "No category selected", QMessageBox::Ok);
73 | return;
74 | }
75 | QString selected_category = this->parentDialog->getListWidget()->selectedItems().at(0)->text();
76 | QMessageBox::StandardButton reply;
77 | reply = QMessageBox::question(this, "Confirm", QString("Do you want to delete ") + selected_category + QString("?"), QMessageBox::Yes|QMessageBox::No);
78 | if (reply == QMessageBox::Yes) {
79 | if (!this->parentDialog->getPManager()->remove_category(this->parentDialog->getCategoryList()[this->parentDialog->getListWidget()->currentIndex().row()]))
80 | QMessageBox::critical(this, "Error", "Persistence error. You can't remove a category used by events. First remove these events and then try again.");
81 | else {
82 | this->parentDialog->load_categories();
83 | this->close();
84 | delete this;
85 | }
86 | }
87 | }
88 |
89 | void CategoryEditDialog::on_button_color_click() {
90 | QColor color = QColorDialog::getColor(QColor(this->selected_color));
91 | if (color.isValid()) {
92 | this->selected_color = color;
93 | QPixmap pixmap(ICON_SIZE, ICON_SIZE);
94 | pixmap.fill(QColor(this->selected_color));
95 | button_color->setIcon(QIcon(pixmap));
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/view/categoryeditdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef CATEGORYEDITDIALOG_H
2 | #define CATEGORYEDITDIALOG_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "ui_categoryeditdialog.h"
11 | #include "model/category.h"
12 | #include "categorydialog.h"
13 |
14 | //We need this forward declaration to avoid circular dependencies among headers
15 | class CategoryDialog;
16 |
17 | namespace Ui {
18 | class CategoryEditDialog;
19 | }
20 |
21 | class CategoryEditDialog : public QDialog
22 | {
23 | Q_OBJECT
24 |
25 | private:
26 | Ui::CategoryEditDialog *ui;
27 | CategoryDialog *parentDialog;
28 | QColor selected_color;
29 | QLineEdit *edit_name;
30 | QPushButton *button_color;
31 |
32 | public:
33 | explicit CategoryEditDialog(CategoryDialog *parentDialog, QWidget *parent = 0);
34 | ~CategoryEditDialog();
35 |
36 | public slots:
37 | void on_button_delete_click();
38 | void on_button_save_click();
39 | void on_button_color_click();
40 | };
41 |
42 | #endif
43 |
--------------------------------------------------------------------------------
/src/view/categoryselectdialog.cpp:
--------------------------------------------------------------------------------
1 | #include "categoryselectdialog.h"
2 |
3 | #include
4 |
5 | CategorySelectDialog::CategorySelectDialog(View *parentView, QString text, QWidget *parent) :
6 | QDialog(parent),
7 | ui(new Ui::CategorySelectDialog)
8 | {
9 | this->parent = parentView;
10 | this->setWindowTitle("Category Selector");
11 | this->pm = new PManager;
12 | this->selected_category = NULL;
13 | QHBoxLayout *button_layout = new QHBoxLayout;
14 | QVBoxLayout *main_layout = new QVBoxLayout;
15 | this->list_categories = new QComboBox;
16 | load_categories();
17 | QPushButton *button_ok = new QPushButton("OK");
18 | QPushButton *button_cancel = new QPushButton("Cancel");
19 | button_cancel->setFixedWidth(50);
20 | button_ok->setFixedWidth(50);
21 | connect(button_cancel, &QPushButton::clicked, this, &CategorySelectDialog::on_button_cancel_click);
22 | connect(button_ok, &QPushButton::clicked, this, &CategorySelectDialog::on_button_ok_click);
23 | QLabel *message = new QLabel(text);
24 | main_layout->addWidget(message);
25 | main_layout->addWidget(this->list_categories);
26 | button_layout->addWidget(button_ok);
27 | button_layout->addWidget(button_cancel);
28 | main_layout->addLayout(button_layout);
29 | this->setLayout(main_layout);
30 | }
31 |
32 | void CategorySelectDialog::load_categories() {
33 | for (Category *category : this->category_list) delete category;
34 | this->category_list = this->pm->get_categories();
35 | for (Category *category : category_list) {
36 | QPixmap pixmap(10, 10);
37 | pixmap.fill(QColor(category->getColor().c_str()));
38 | this->list_categories->addItem(QIcon(pixmap), QString(category->getName().c_str()));
39 | }
40 | }
41 |
42 | void CategorySelectDialog::on_button_cancel_click() {
43 | this->selected_category = NULL;
44 | this->close();
45 | delete this;
46 | }
47 |
48 | void CategorySelectDialog::on_button_ok_click() {
49 | for (Category *c : this->category_list) {
50 | if (this->list_categories->currentText().toStdString() == c->getName()) {
51 | this->selected_category = new Category(*c);
52 | break;
53 | }
54 | }
55 | this->close();
56 | delete this;
57 | }
58 |
59 | Category* CategorySelectDialog::getSelectedCategory() {
60 | return this->selected_category;
61 | }
62 |
63 | CategorySelectDialog::~CategorySelectDialog()
64 | {
65 | delete ui;
66 | delete pm;
67 | for (Category *category : this->category_list) delete category;
68 | }
69 |
--------------------------------------------------------------------------------
/src/view/categoryselectdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef CATEGORYSELECTDIALOG_H
2 | #define CATEGORYSELECTDIALOG_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "ui_categoryselectdialog.h"
11 | #include "view.h"
12 | #include "persistence/pmanager.h"
13 | #include "categorydialog.h"
14 |
15 | namespace Ui {
16 | class CategorySelectDialog;
17 | }
18 |
19 | class CategorySelectDialog : public QDialog
20 | {
21 | Q_OBJECT
22 |
23 | private:
24 | Ui::CategorySelectDialog *ui;
25 | QComboBox *list_categories;
26 | vector category_list;
27 | PManager *pm;
28 | View *parent;
29 | Category *selected_category;
30 |
31 | public:
32 | explicit CategorySelectDialog(View *parentView, QString text, QWidget *parent = 0);
33 | ~CategorySelectDialog();
34 | void load_categories();
35 | Category *getSelectedCategory();
36 |
37 | public slots:
38 | void on_button_cancel_click();
39 | void on_button_ok_click();
40 | };
41 |
42 | #endif // CATEGORYSELECTDIALOG_H
43 |
--------------------------------------------------------------------------------
/src/view/customdialog.cpp:
--------------------------------------------------------------------------------
1 | #include "customdialog.h"
2 |
3 | #include
4 |
5 | CustomDialog::CustomDialog(QLayout *layout, QWidget *parent) :
6 | QDialog(parent),
7 | ui(new Ui::CustomDialog)
8 | {
9 | this->setWindowFlags(Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint);
10 | setLayout(layout);
11 | }
12 |
13 | CustomDialog::~CustomDialog()
14 | {
15 | delete ui;
16 | }
17 |
18 | void CustomDialog::keyPressEvent(QKeyEvent *e) {
19 | if(e->key() != Qt::Key_Escape)
20 | QDialog::keyPressEvent(e);
21 | else {
22 | this->close();
23 | delete this;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/view/customdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef CUSTOMDIALOG_H
2 | #define CUSTOMDIALOG_H
3 |
4 | #include "ui_customdialog.h"
5 | #include
6 | #include
7 | #include
8 |
9 | namespace Ui {
10 | class CustomDialog;
11 | }
12 |
13 | class CustomDialog : public QDialog
14 | {
15 | Q_OBJECT
16 |
17 | public:
18 | explicit CustomDialog(QLayout *layout, QWidget *parent = 0);
19 | ~CustomDialog();
20 |
21 | protected:
22 | virtual void keyPressEvent(QKeyEvent *e);
23 |
24 | private:
25 | Ui::CustomDialog *ui;
26 | };
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/src/view/eventdialog.cpp:
--------------------------------------------------------------------------------
1 | #include "eventdialog.h"
2 |
3 | #include
4 |
5 | void EventDialog::setEvent(Event *event) {
6 | this->everyMonth->setEnabled(false); /* Not supported for now */
7 | this->everyYear->setEnabled(false);
8 | this->event = event;
9 | if (event != NULL) {
10 | this->edit_name->setText(event->getName().c_str());
11 | this->edit_description->setPlainText(event->getDescription().c_str());
12 | this->edit_place->setText(event->getPlace().c_str());
13 | int index = 0;
14 | for (Category *category : category_list) {
15 | if (category->getName() == event->getCategory()->getName())
16 | this->edit_category->setCurrentIndex(index);
17 | index++;
18 | }
19 |
20 | if (event->getStart() == TODO_DATE) {
21 | Date today = DateUtil::get_current_date();
22 | /* Set the current date, so if the user uncheck the "TODO" there is already a valid date set */
23 | this->edit_start->setDateTime(QDateTime(QDate(today.getYear(), today.getMonth(), today.getMonthDay())));
24 | this->edit_start->setEnabled(false);
25 | this->edit_end->setDateTime(QDateTime(QDate(today.getYear(), today.getMonth(), today.getMonthDay())));
26 | this->edit_end->setEnabled(false);
27 | this->cbtodo->setChecked(true);
28 | } else {
29 | this->edit_start->setDateTime(QDateTime::fromTime_t(event->getStart()));
30 | this->edit_end->setDateTime(QDateTime::fromTime_t(event->getEnd()));
31 | }
32 | this->button_delete->setEnabled(true);
33 | }
34 | }
35 |
36 | EventDialog::EventDialog(View *parentView, Date start_date, Date end_date, QWidget *parent) :
37 | QDialog(parent),
38 | ui(new Ui::EventDialog)
39 | {
40 | this->parent = parentView;
41 | this->setFixedWidth(400);
42 | this->setFixedHeight(500);
43 | this->setModal(true);
44 | this->setWindowTitle("Event Manager");
45 |
46 | this->pm = new SecurePManager;
47 | this->event = NULL;
48 |
49 | QVBoxLayout *main_layout = new QVBoxLayout;
50 | QHBoxLayout *first_row = new QHBoxLayout;
51 | QLabel *label_name = new QLabel("Name: ");
52 | this->edit_name = new QLineEdit;
53 | this->edit_name->setMaxLength(100);
54 | first_row->addWidget(label_name);
55 | first_row->addWidget(this->edit_name);
56 | main_layout->addLayout(first_row);
57 | QHBoxLayout *second_row = new QHBoxLayout;
58 | QLabel *label_place = new QLabel("Place: ");
59 | this->edit_place = new QLineEdit;
60 | second_row->addWidget(label_place);
61 | second_row->addWidget(this->edit_place);
62 | main_layout->addLayout(second_row);
63 | main_layout->addWidget(new QLabel("Description: "));
64 | this->edit_description = new QPlainTextEdit;
65 | main_layout->addWidget(this->edit_description);
66 | QHBoxLayout *third_row = new QHBoxLayout;
67 | QLabel *label_category = new QLabel("Category: ");
68 | this->edit_category = new QComboBox;
69 | this->category_list = this->pm->get_categories();
70 | for (Category *category : category_list) {
71 | QPixmap pixmap(10, 10);
72 | pixmap.fill(QColor(category->getColor().c_str()));
73 | this->edit_category->addItem(QIcon(pixmap), QString(category->getName().c_str()));
74 | }
75 | third_row->addWidget(label_category);
76 | third_row->addWidget(this->edit_category);
77 | main_layout->addLayout(third_row);
78 | QHBoxLayout *fourth_row = new QHBoxLayout;
79 | QLabel *label_todo = new QLabel("TODO: ");
80 | this->cbtodo = new QCheckBox;
81 | connect(cbtodo, &QCheckBox::toggled, this, &EventDialog::on_checkbox_todo_toggle);
82 | fourth_row->addWidget(label_todo);
83 | fourth_row->addWidget(cbtodo);
84 | main_layout->addLayout(fourth_row);
85 | QHBoxLayout *fifth_row = new QHBoxLayout;
86 | QLabel *label_start = new QLabel("Start: ");
87 | this->edit_start = new QDateTimeEdit;
88 | this->edit_start->setCalendarPopup(true);
89 | QDateTime todoDate = QDateTime::fromTime_t(TODO_DATE);
90 | this->edit_start->setDateTime(QDateTime(QDate(start_date.getYear(), start_date.getMonth(), start_date.getMonthDay())));
91 | //I set a specific hour because the default is the midnight, but this could lead more easily problems caused by daylight saving time
92 | this->edit_start->setTime(QTime(8,0,0));
93 | connect(this->edit_start, &QDateTimeEdit::dateTimeChanged, this, &EventDialog::on_date_start_change);
94 | fifth_row->addWidget(label_start);
95 | fifth_row->addWidget(this->edit_start);
96 | main_layout->addLayout(fifth_row);
97 | QHBoxLayout *sixth_row = new QHBoxLayout;
98 | QLabel *label_end = new QLabel("End: ");
99 | this->edit_end = new QDateTimeEdit;
100 | this->edit_end->setCalendarPopup(true);
101 | this->edit_end->setDateTime(QDateTime(QDate(end_date.getYear(), end_date.getMonth(), end_date.getMonthDay())));
102 | this->edit_end->setTime(QTime(9,0,0));
103 | sixth_row->addWidget(label_end);
104 | sixth_row->addWidget(this->edit_end);
105 | main_layout->addLayout(sixth_row);
106 | QHBoxLayout *seventh_row = new QHBoxLayout;
107 | QLabel *label_recurrent = new QLabel("Recurrence: ");
108 | this->everyMonth = new QRadioButton("Monthly");
109 | this->everyYear = new QRadioButton("Yearly");
110 | this->options = new QGroupBox;
111 | seventh_row->addWidget(label_recurrent);
112 | seventh_row->addWidget(this->everyMonth);
113 | seventh_row->addWidget(this->everyYear);
114 | options->setLayout(seventh_row);
115 | main_layout->addWidget(options);
116 | QHBoxLayout *last_row = new QHBoxLayout;
117 | QPushButton *button_cancel = new QPushButton("&Cancel");
118 | connect(button_cancel, &QPushButton::clicked, this, &EventDialog::on_button_cancel_click);
119 | button_delete = new QPushButton("&Delete");
120 | button_delete->setEnabled(false);
121 | connect(button_delete, &QPushButton::clicked, this, &EventDialog::on_button_delete_click);
122 | QPushButton *button_save = new QPushButton("&Save");
123 | connect(button_save, &QPushButton::clicked, this, &EventDialog::on_button_save_click);
124 | last_row->addWidget(button_cancel);
125 | last_row->addWidget(button_delete);
126 | last_row->addWidget(button_save);
127 | main_layout->addLayout(last_row);
128 |
129 | this->setLayout(main_layout);
130 | }
131 |
132 | EventDialog::~EventDialog()
133 | {
134 | delete ui;
135 | delete this->pm;
136 | for (Category *c : this->category_list) delete c;
137 | }
138 |
139 | void EventDialog::on_button_cancel_click() {
140 | this->close();
141 | delete this;
142 | }
143 |
144 | void EventDialog::on_button_delete_click() {
145 | this->pm->remove_event(this->event);
146 | this->event->setInvalid();
147 | refresh();
148 | }
149 |
150 | void EventDialog::refresh() {
151 | this->parent->refresh_events();
152 | this->close();
153 | delete this;
154 | }
155 |
156 | void EventDialog::on_button_save_click() {
157 | QProgressBar *bar = new QProgressBar;
158 | bool ret = true;
159 | bool isTodo = !this->edit_start->isEnabled();
160 |
161 | if (this->edit_name->text().length() < 3) {
162 | QMessageBox::critical(this, "Error", "The name must have a length greater than 2", QMessageBox::Ok);
163 | return;
164 | }
165 |
166 | if (isTodo) {
167 | QDateTime todoDate = QDateTime::fromTime_t(TODO_DATE);
168 | this->edit_start->setDateTime(todoDate);
169 | this->edit_end->setDateTime(todoDate);
170 | } else {
171 | if (this->edit_start->dateTime() > this->edit_end->dateTime()) {
172 | QMessageBox::critical(this, "Error", "Invalid range of time selected", QMessageBox::Ok);
173 | return;
174 | }
175 | }
176 |
177 | Category *category = NULL;
178 | for (Category *c : this->category_list) {
179 | if (this->edit_category->currentText().toStdString() == c->getName()) {
180 | category = new Category(*c);
181 | break;
182 | }
183 | }
184 |
185 | QDateTime start = this->edit_start->dateTime();
186 | QDateTime end = this->edit_end->dateTime();
187 | Event *newEvent = new Event(0, this->edit_name->text().toStdString(), this->edit_description->toPlainText().toStdString(), this->edit_place->text().toStdString(), category, start.toTime_t(), end.toTime_t());
188 |
189 | /* If the users has changed an existent event, I'll call the right function */
190 | if ((this->event != NULL) && (this->pm->replace_event(this->event, newEvent))) {
191 | refresh();
192 | this->event = new Event(*newEvent);
193 | } else if ((this->event == NULL) && (this->everyMonth->isChecked() || this->everyYear->isChecked())) {
194 | int reply = QMessageBox::warning(this, "Attention", "A recurrent event is considered as multiple independent events, after this operation you can modify it only as a single event.", QMessageBox::Yes | QMessageBox::No);
195 | if (reply == QMessageBox::Yes) {
196 | int offset = 8; /* Add the same event to the next 8 years */
197 | if (this->everyMonth->isChecked()) offset = 24; /* Add the same event to every month of the next 2 years */
198 | bar->setRange(0, offset);
199 | this->layout()->addWidget(bar);
200 | Event *previous = NULL;
201 | for (int i = 0; i < offset; i++) {
202 | ret = ret && this->pm->add_event(newEvent, previous);
203 | if (previous != NULL) delete previous;
204 | previous = newEvent;
205 | if (!ret) break;
206 | if (this->everyMonth->isChecked()) {
207 | start = start.addMonths(1);
208 | end = end.addMonths(1);
209 | } else {
210 | start = start.addYears(1);
211 | end = end.addYears(1);
212 | }
213 | newEvent = new Event(0, this->edit_name->text().toStdString(), this->edit_description->toPlainText().toStdString(), this->edit_place->text().toStdString(), category, start.toTime_t(), end.toTime_t());
214 | bar->setValue(i);
215 | QCoreApplication::processEvents();
216 | }
217 | delete previous;
218 | if (ret) {
219 | delete newEvent;
220 | refresh();
221 | }
222 | }
223 | } else if ((this->event == NULL) && (this->pm->add_event(newEvent))) { //else I'll create a new Event
224 | delete newEvent;
225 | refresh();
226 | } else
227 | ret = false;
228 |
229 | if (!ret) {
230 | QMessageBox::critical(this, "Error", "Persistence error. Try with a different name.", QMessageBox::Ok);
231 | delete bar;
232 | }
233 | }
234 |
235 | void EventDialog::on_checkbox_todo_toggle(bool checked) {
236 | this->edit_start->setEnabled(!checked);
237 | this->edit_end->setEnabled(!checked);
238 | this->options->setEnabled(!checked);
239 | }
240 |
241 | void EventDialog::on_date_start_change() {
242 | if (this->edit_start->date() > this->edit_end->date())
243 | this->edit_end->setDate(this->edit_start->date());
244 | if (this->edit_start->time() > this->edit_end->time())
245 | this->edit_end->setTime(this->edit_start->time().addSecs(60*60));
246 | }
247 |
248 | Event* EventDialog::getEvent() {
249 | return this->event;
250 | }
251 |
--------------------------------------------------------------------------------
/src/view/eventdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef EVENTDIALOG_H
2 | #define EVENTDIALOG_H
3 |
4 | #include "ui_eventdialog.h"
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 | #include "util/dateutil.h"
23 | #include "view.h"
24 | #include "persistence/securepmanager.h"
25 |
26 | namespace Ui {
27 | class EventDialog;
28 | }
29 |
30 | class EventDialog : public QDialog
31 | {
32 | Q_OBJECT
33 |
34 | private:
35 | Ui::EventDialog *ui;
36 | QLineEdit *edit_name;
37 | QLineEdit *edit_place;
38 | QComboBox *edit_category;
39 | QDateTimeEdit *edit_start;
40 | QDateTimeEdit *edit_end;
41 | QPlainTextEdit *edit_description;
42 | QPushButton *button_delete;
43 | QCheckBox *cbtodo;
44 | QRadioButton *everyMonth;
45 | QRadioButton *everyYear;
46 | QGroupBox *options;
47 | View *parent;
48 | PManager *pm;
49 | Event *event;
50 | vector category_list;
51 | void refresh();
52 |
53 | public:
54 | explicit EventDialog(View *parentView, Date start_date = Date(), Date end_date = Date(), QWidget *parent = 0);
55 | ~EventDialog();
56 | void setEvent(Event *event);
57 | Event* getEvent();
58 |
59 | public slots:
60 | void on_button_cancel_click();
61 | void on_button_save_click();
62 | void on_button_delete_click();
63 | void on_date_start_change();
64 | void on_checkbox_todo_toggle(bool checked);
65 | };
66 |
67 | #endif // EVENTDIALOG_H
68 |
--------------------------------------------------------------------------------
/src/view/monthview.h:
--------------------------------------------------------------------------------
1 | #ifndef MONTHVIEW_H
2 | #define MONTHVIEW_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include "ui_monthview.h"
21 | #include "view/eventdialog.h"
22 | #include "view/qframe_extended.h"
23 | #include "view/qwidget_extended.h"
24 | #include "view/categorydialog.h"
25 | #include "view.h"
26 | #include "util/dateutil.h"
27 | #include "qlabel_event.h"
28 | #include "qpushbutton_extended.h"
29 | #include "view/customdialog.h"
30 | #include "view/categoryselectdialog.h"
31 | #include "util/pluginmanager.h"
32 | #include "view/settings.h"
33 |
34 | /* Gets the current month displayed using an hack. Infact, the cell in the middle will have always a value setted.
35 | * This should be used when you don't care about the day */
36 | #define CURRENT_MONTH *this->frames[21]->getDate()
37 |
38 | /* Style Sheets */
39 | #define MAINWINDOW_STYLE "#mainwindow { background-color: #FFFFFF; border: 2px solid #DDDDFF; }"
40 |
41 | #define LABELDATE_STYLE "QLabel { color: #000000; qproperty-alignment: AlignCenter; padding-left: 100px; padding-right: 100px; font-size: 20px; }"
42 |
43 | #define TODOSBUTTON_STYLE "QPushButton { border: 1px solid #000000; color: #000000; padding: 5px; font-weight: bold; border-radius: 10px; } QPushButton:hover { color: #2222BB; }"
44 |
45 | #define CELL_STYLE "QFrame { background-color: #FFFFFF; color: #000000; border: 1px outset #CCCCCC; }" \
46 | "QFrame#holiday { background-color: #FFF5F5; }" \
47 | "QLabel { border: none; font-size: 16px; padding: 5px; background-color:rgba(0,0,0,0); }" \
48 | "QLabel#today { background-color: #FFFF88; color: #FF0000; border: 1px solid #FF0000;}" \
49 | "QFrame#selected { background-color: #EEEEFF; }" \
50 | "QLabel#header { font-weight: bold; }" \
51 | "QFrame#header { background-color: #DDDDFF; }" \
52 | "QFrame#disabled { background-color: #EFEFEF; }"
53 |
54 | namespace Ui {
55 | class MonthView;
56 | }
57 |
58 | class MonthView : public QMainWindow, public View
59 | {
60 | Q_OBJECT
61 |
62 | private:
63 | QSettings settings;
64 | Category *selected_category;
65 | PluginManager *plm;
66 | QVBoxLayout *layout;
67 | QLabel *label_date;
68 | QLabelEvent *selected_event;
69 | QPushButton *todobutton;
70 | Date *selection_start;
71 | Date *selection_end;
72 | Ui::MonthView *ui;
73 | PManager *pm;
74 | QFrameExtended *frames[42]; //I have a 7x7 grid, but without consider the first row I've a total of 6x7 cells
75 | QMenu *dbMenu;
76 | void display_days(Date date);
77 | void remove_events_from_all_frames();
78 | void remove_events_from_frame(int i);
79 | QLabelEvent *createLabelEvent(Event *event);
80 | QFrameExtended *createQFrameExtended(Date *date);
81 | void createMenu();
82 | void on_button_extended_click(int index);
83 | CustomDialog *show_progress_bar(QString title);
84 | void refresh_db_menu();
85 |
86 | protected:
87 | void contextMenuEvent(QContextMenuEvent *event) Q_DECL_OVERRIDE;
88 |
89 | public:
90 | explicit MonthView(QWidget *parent = 0);
91 | void refresh_events();
92 | void refresh_todos();
93 | void display_events(Date date, Category *category = NULL);
94 | ~MonthView();
95 |
96 | public slots:
97 | void on_mouse_press(QFrameExtended *frame);
98 | void on_mouse_release(QFrameExtended *frame);
99 | void on_mouse_move(QFrameExtended *frame);
100 | void on_back_button_click();
101 | void on_next_button_click();
102 | void on_event_click(QLabelEvent *label_event, Qt::MouseButton button);
103 | void on_event_key_press(int key);
104 | void on_todo_button_click();
105 | void keyPressEvent(QKeyEvent* e);
106 |
107 |
108 | private slots:
109 | void exit();
110 | void delete_db();
111 | void save_database();
112 | void load_database();
113 | void import_events();
114 | void export_events();
115 | void add_event();
116 | void edit_categories();
117 | void show_agenda(bool only_todos = false);
118 | void show_monthview();
119 | void filter_by_category();
120 | void run_tool(string tool);
121 | void switch_db(string db);
122 | void create_database();
123 | void show_settings();
124 | };
125 |
126 | #endif // MONTHVIEW_H
127 |
--------------------------------------------------------------------------------
/src/view/qframe_extended.h:
--------------------------------------------------------------------------------
1 | #ifndef QFRAMEEXTENDED_H
2 | #define QFRAMEEXTENDED_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include "util/dateutil.h"
8 |
9 | class QFrameExtended : public QFrame
10 | {
11 | Q_OBJECT
12 |
13 | private:
14 | Date *date;
15 |
16 | public:
17 | explicit QFrameExtended(QWidget *parent = 0) : QFrame(parent), date(NULL) { }
18 | ~QFrameExtended() { delete this->date; }
19 | Date* getDate() { return date; }
20 | void setDate(Date *d) {
21 | if (this->date != NULL) delete this->date;
22 | this->date = d;
23 | }
24 |
25 | };
26 |
27 | #endif // QFRAMEEXTENDED_H
28 |
--------------------------------------------------------------------------------
/src/view/qlabel_event.cpp:
--------------------------------------------------------------------------------
1 | #include "qlabel_event.h"
2 |
3 | #include
4 |
5 | QLabelEvent::QLabelEvent(QWidget *parent) : QLabel(parent)
6 | {
7 | this->event = NULL;
8 | }
9 |
10 | QLabelEvent::~QLabelEvent() {
11 | if (this->event != NULL)
12 | delete this->event;
13 | }
14 |
15 | void QLabelEvent::mousePressEvent(QMouseEvent *e) {
16 | emit clicked(this, e->button());
17 | }
18 |
19 | void QLabelEvent::keyPressEvent(QKeyEvent *e) {
20 | emit keyPressed(e->key());
21 | }
22 |
23 | void QLabelEvent::setEvent(Event *event) {
24 | if (this->event != NULL) delete this->event;
25 | this->event = event;
26 | this->drawUI();
27 | }
28 |
29 | Event* QLabelEvent::getEvent() {
30 | return this->event;
31 | }
32 |
33 | bool QLabelEvent::markSelection(bool selected) {
34 | if (this->event == NULL) return false;
35 | if (selected)
36 | this->setObjectName("selected");
37 | else
38 | this->setObjectName("");
39 | //Update the ui
40 | this->setStyleSheet(this->styleSheet());
41 | return true;
42 | }
43 |
44 | bool QLabelEvent::drawInvalidEvent() {
45 | if (this->event == NULL) return false;
46 | this->setText(QString("") + QString(this->event->getName().c_str()) + QString(""));
47 | this->setStyleSheet(QString("QLabel { font-size: 14px; background-color : #AAAAAA; color: #000000; };"));
48 | this->setFixedHeight(26);
49 | this->setMargin(0);
50 | this->setEnabled(false);
51 | return true;
52 | }
53 |
54 | bool QLabelEvent::drawUI() {
55 | if (this->event == NULL) return false;
56 | if (this->event->isInvalid()) return drawInvalidEvent();
57 |
58 | this->setText(this->event->getName().c_str());
59 | QString textColor("#000000");
60 | if (is_color_dark(this->event->getCategory()->getColor()))
61 | textColor = "#FFFFFF";
62 | this->setStyleSheet(QString("QLabel#selected {border-top: 1px solid #FF0000; border-bottom: 1px solid #FF0000; font-weight: bold; font-size: 13px;} QLabel { font-size: 14px; border-radius: 2px; background-color : ") + QString(this->event->getCategory()->getColor().c_str()) + QString("; color: ") + textColor + QString("};"));
63 | this->setFixedHeight(26);
64 | this->setMargin(0);
65 | QString tooltip_text;
66 | if (this->event->getName().length() > 20)
67 | tooltip_text = QString("Name: ") + this->event->getName().c_str() + QString("\n");
68 | if (this->event->getPlace() != "")
69 | tooltip_text = tooltip_text + QString("Place: ") + this->event->getPlace().c_str() + QString("\n");
70 | if (this->event->getDescription() != "")
71 | tooltip_text = tooltip_text + QString("Description: ") + this->event->getDescription().c_str();
72 | this->setToolTip(tooltip_text);
73 | return true;
74 | }
75 |
76 | /* This is an utility function and should be moved in another class, but for the moment no one else is using it. */
77 | bool QLabelEvent::is_color_dark(string colorName) {
78 | QColor color(colorName.c_str());
79 | //Formula to calculate luminance from ITU-R BT.709
80 | int l = 0.2126 * color.red() + 0.7152 * color.green() + 0.0722 * color.blue();
81 | if (l < 50)
82 | return true;
83 | else
84 | return false;
85 | }
86 |
87 |
--------------------------------------------------------------------------------
/src/view/qlabel_event.h:
--------------------------------------------------------------------------------
1 | #ifndef QLABELEVENT_H
2 | #define QLABELEVENT_H
3 |
4 | #include
5 | #include
6 | #include "model/event.h"
7 |
8 | class QLabelEvent : public QLabel
9 | {
10 | Q_OBJECT
11 | private:
12 | Event *event;
13 |
14 | public:
15 | explicit QLabelEvent(QWidget *parent = 0);
16 | ~QLabelEvent();
17 | bool markSelection(bool selected);
18 | void setEvent(Event *event);
19 | Event* getEvent();
20 | bool drawUI();
21 | bool is_color_dark(string colorName);
22 |
23 | private:
24 | bool drawInvalidEvent();
25 |
26 | protected:
27 | virtual void mousePressEvent(QMouseEvent *e);
28 | virtual void keyPressEvent(QKeyEvent *e);
29 |
30 | signals:
31 | void clicked(QLabelEvent *event, Qt::MouseButton button);
32 | void keyPressed(int key);
33 |
34 | public slots:
35 |
36 | };
37 |
38 | #endif // QLABELEVENT_H
39 |
--------------------------------------------------------------------------------
/src/view/qpushbutton_extended.cpp:
--------------------------------------------------------------------------------
1 | #include "qpushbutton_extended.h"
2 |
3 | #include
4 |
5 | QPushButtonExtended::QPushButtonExtended(const char *text, QWidget *parent) : QPushButton(text, parent)
6 | {
7 | //clicked can't be overwritten
8 | connect(this, &QPushButtonExtended::clicked, this, &QPushButtonExtended::button_clicked);
9 | }
10 |
11 | void QPushButtonExtended::button_clicked() {
12 | emit on_click(this->index);
13 | }
14 |
15 | void QPushButtonExtended::setIndex(int index) {
16 | this->index = index;
17 | }
18 |
--------------------------------------------------------------------------------
/src/view/qpushbutton_extended.h:
--------------------------------------------------------------------------------
1 | #ifndef QPUSHBUTTONEXTENDED_H
2 | #define QPUSHBUTTONEXTENDED_H
3 |
4 | #include
5 |
6 | class QPushButtonExtended : public QPushButton
7 | {
8 | Q_OBJECT
9 | private:
10 | int index;
11 |
12 | public:
13 | explicit QPushButtonExtended(const char *text, QWidget *parent = 0);
14 | void setIndex(int index);
15 | void button_clicked();
16 |
17 | signals:
18 | void on_click(int index);
19 |
20 | public slots:
21 | };
22 |
23 | #endif // QPUSHBUTTONEXTENDED_H
24 |
--------------------------------------------------------------------------------
/src/view/qwidget_extended.cpp:
--------------------------------------------------------------------------------
1 | #include "qwidget_extended.h"
2 | #include "qframe_extended.h"
3 | #include
4 |
5 | QWidgetExtended::QWidgetExtended(QWidget *parent) : QWidget(parent)
6 | {
7 |
8 | }
9 |
10 | void QWidgetExtended::signalEvent(QMouseEvent *event, int code) {
11 | QFrameExtended frame;
12 | QWidget *widget = this->childAt(event->pos());
13 | if (widget != NULL) {
14 | QString widgetClassName(widget->metaObject()->className());
15 | //I don't use explicitly the string because if one day someone changes the name of the class, the compiler will output an error
16 | QString className(frame.metaObject()->className());
17 | if (widgetClassName == className) {
18 | switch(code) {
19 | case PRESSED:
20 | emit mousePress(dynamic_cast (widget));
21 | break;
22 | case RELEASED:
23 | emit mouseRelease(dynamic_cast (widget));
24 | break;
25 | case MOVED:
26 | emit mouseMove(dynamic_cast (widget));
27 | break;
28 | }
29 | }
30 | }
31 | }
32 |
33 | void QWidgetExtended::mousePressEvent(QMouseEvent *event) {
34 | signalEvent(event, PRESSED);
35 | }
36 |
37 | void QWidgetExtended::mouseReleaseEvent(QMouseEvent *event) {
38 | signalEvent(event, RELEASED);
39 | }
40 |
41 | void QWidgetExtended::mouseMoveEvent(QMouseEvent *event) {
42 | signalEvent(event, MOVED);
43 | }
44 |
45 | /* This method needs to be overrided to allow CSS styling also for QWidgetExtended */
46 | void QWidgetExtended::paintEvent(QPaintEvent *pe) {
47 | QStyleOption opt;
48 | opt.initFrom(this);
49 | QStylePainter p(this);
50 | p.drawPrimitive(QStyle::PE_Widget, opt);
51 | }
52 |
--------------------------------------------------------------------------------
/src/view/qwidget_extended.h:
--------------------------------------------------------------------------------
1 | #ifndef QWIDGETEXTENDED_H
2 | #define QWIDGETEXTENDED_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include "qframe_extended.h"
12 |
13 | enum { PRESSED, RELEASED, MOVED };
14 |
15 | class QWidgetExtended : public QWidget
16 | {
17 | Q_OBJECT
18 |
19 | private:
20 | void signalEvent(QMouseEvent *, int code);
21 |
22 | public:
23 | explicit QWidgetExtended(QWidget *parent = 0);
24 |
25 | protected:
26 | virtual void mousePressEvent(QMouseEvent *);
27 | virtual void mouseReleaseEvent(QMouseEvent *);
28 | virtual void mouseMoveEvent(QMouseEvent *);
29 | virtual void paintEvent(QPaintEvent *pe);
30 |
31 | signals:
32 | void mousePress(QFrameExtended *);
33 | void mouseRelease(QFrameExtended *);
34 | void mouseMove(QFrameExtended *);
35 |
36 | };
37 |
38 | #endif
39 |
--------------------------------------------------------------------------------
/src/view/settings.cpp:
--------------------------------------------------------------------------------
1 | #include "settings.h"
2 |
3 | #include
4 |
5 | const QString SettingsValues::past_months_expiration = "PastMonthsExpiration";
6 |
7 | Settings::Settings(QWidget *parent) :
8 | QDialog(parent),
9 | ui(new Ui::Settings)
10 | {
11 | this->setWindowFlags(Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint);
12 | this->setWindowTitle("Settings");
13 | QVBoxLayout *main_layout = new QVBoxLayout;
14 | QHBoxLayout *row1 = new QHBoxLayout;
15 | QLabel *lblPastMonthExpiration = new QLabel("Delete all events older than (months): ");
16 | this->pastMonthsExpiration = new QSpinBox;
17 | pastMonthsExpiration->setRange(0, 120);
18 | pastMonthsExpiration->setSingleStep(1);
19 | pastMonthsExpiration->setValue(2);
20 | pastMonthsExpiration->setFixedWidth(100);
21 | row1->addWidget(lblPastMonthExpiration);
22 | row1->addWidget(pastMonthsExpiration);
23 | QHBoxLayout *lastRow = new QHBoxLayout;
24 | QPushButton *btnCancel = new QPushButton("Cancel");
25 | QPushButton *btnSave = new QPushButton("Save");
26 | connect(btnCancel, &QPushButton::clicked, this, &Settings::on_button_cancel_click);
27 | connect(btnSave, &QPushButton::clicked, this, &Settings::on_button_save_click);
28 | lastRow->addWidget(btnCancel);
29 | lastRow->addWidget(btnSave);
30 | main_layout->addLayout(row1);
31 | main_layout->addLayout(lastRow);
32 | setLayout(main_layout);
33 | }
34 |
35 | Settings::~Settings()
36 | {
37 | delete ui;
38 | }
39 |
40 | void Settings::on_button_cancel_click() {
41 | this->close();
42 | }
43 |
44 | void Settings::on_button_save_click() {
45 | QSettings settings;
46 | settings.setValue(SettingsValues::past_months_expiration, this->pastMonthsExpiration->value());
47 | this->close();
48 | }
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/view/settings.h:
--------------------------------------------------------------------------------
1 | #ifndef SETTINGS_H
2 | #define SETTINGS_H
3 |
4 | #include "ui_settings.h"
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include "../persistence/securepmanager.h"
15 |
16 | namespace Ui {
17 | class Settings;
18 | }
19 |
20 | struct SettingsValues {
21 | /* initialization in settings.cpp */
22 | static const QString past_months_expiration;
23 | };
24 |
25 | class Settings : public QDialog
26 | {
27 | Q_OBJECT
28 |
29 | private:
30 | QSpinBox *pastMonthsExpiration;
31 | Ui::Settings *ui;
32 |
33 | public:
34 | explicit Settings(QWidget *parent = 0);
35 | ~Settings();
36 | void on_button_cancel_click();
37 | void on_button_save_click();
38 |
39 | protected:
40 |
41 | };
42 |
43 | #endif // SETTINGS_H
44 |
--------------------------------------------------------------------------------
/src/view/ui_categorydialog.h:
--------------------------------------------------------------------------------
1 | /********************************************************************************
2 | ** Form generated from reading UI file 'eventdialog.ui'
3 | **
4 | ** Created by: Qt User Interface Compiler version 5.5.1
5 | **
6 | ** WARNING! All changes made in this file will be lost when recompiling UI file!
7 | ********************************************************************************/
8 |
9 | #ifndef UI_CATEGORYDIALOG_H
10 | #define UI_CATEGORYDIALOG_H
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | QT_BEGIN_NAMESPACE
20 |
21 | class Ui_CategoryDialog
22 | {
23 | public:
24 |
25 | void setupUi(QDialog *CategoryDialog)
26 | {
27 | if (CategoryDialog->objectName().isEmpty())
28 | CategoryDialog->setObjectName(QStringLiteral("CategoryDialog"));
29 | CategoryDialog->resize(400, 300);
30 |
31 | retranslateUi(CategoryDialog);
32 |
33 | QMetaObject::connectSlotsByName(CategoryDialog);
34 | } // setupUi
35 |
36 | void retranslateUi(QDialog *CategoryDialog)
37 | {
38 | CategoryDialog->setWindowTitle(QApplication::translate("CategoryDialog", "Dialog", 0));
39 | } // retranslateUi
40 |
41 | };
42 |
43 | namespace Ui {
44 | class CategoryDialog: public Ui_CategoryDialog {};
45 | } // namespace Ui
46 |
47 | QT_END_NAMESPACE
48 |
49 | #endif // UI_CATEGORYDIALOG_H
50 |
--------------------------------------------------------------------------------
/src/view/ui_categoryeditdialog.h:
--------------------------------------------------------------------------------
1 | /********************************************************************************
2 | ** Form generated from reading UI file 'eventdialog.ui'
3 | **
4 | ** Created by: Qt User Interface Compiler version 5.5.1
5 | **
6 | ** WARNING! All changes made in this file will be lost when recompiling UI file!
7 | ********************************************************************************/
8 |
9 | #ifndef UI_CATEGORYEDITDIALOG_H
10 | #define UI_CATEGORYEDITDIALOG_H
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | QT_BEGIN_NAMESPACE
20 |
21 | class Ui_CategoryEditDialog
22 | {
23 | public:
24 |
25 | void setupUi(QDialog *CategoryEditDialog)
26 | {
27 | if (CategoryEditDialog->objectName().isEmpty())
28 | CategoryEditDialog->setObjectName(QStringLiteral("CategoryEditDialog"));
29 | CategoryEditDialog->resize(400, 300);
30 |
31 | retranslateUi(CategoryEditDialog);
32 |
33 | QMetaObject::connectSlotsByName(CategoryEditDialog);
34 | } // setupUi
35 |
36 | void retranslateUi(QDialog *CategoryEditDialog)
37 | {
38 | CategoryEditDialog->setWindowTitle(QApplication::translate("CategoryEditDialog", "Dialog", 0));
39 | } // retranslateUi
40 |
41 | };
42 |
43 | namespace Ui {
44 | class CategoryEditDialog: public Ui_CategoryEditDialog {};
45 | } // namespace Ui
46 |
47 | QT_END_NAMESPACE
48 |
49 | #endif // UI_CATEGORYEDITDIALOG_H
50 |
--------------------------------------------------------------------------------
/src/view/ui_categoryselectdialog.h:
--------------------------------------------------------------------------------
1 | /********************************************************************************
2 | ** Form generated from reading UI file 'eventdialog.ui'
3 | **
4 | ** Created by: Qt User Interface Compiler version 5.5.1
5 | **
6 | ** WARNING! All changes made in this file will be lost when recompiling UI file!
7 | ********************************************************************************/
8 |
9 | #ifndef UI_CATEGORYSELECTDIALOG_H
10 | #define UI_CATEGORYSELECTDIALOG_H
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | QT_BEGIN_NAMESPACE
20 |
21 | class Ui_CategorySelectDialog
22 | {
23 | public:
24 |
25 | void setupUi(QDialog *CategorySelectDialog)
26 | {
27 | if (CategorySelectDialog->objectName().isEmpty())
28 | CategorySelectDialog->setObjectName(QStringLiteral("CategorySelectDialog"));
29 | CategorySelectDialog->resize(400, 300);
30 |
31 | retranslateUi(CategorySelectDialog);
32 |
33 | QMetaObject::connectSlotsByName(CategorySelectDialog);
34 | } // setupUi
35 |
36 | void retranslateUi(QDialog *CategorySelectDialog)
37 | {
38 | CategorySelectDialog->setWindowTitle(QApplication::translate("CategorySelectDialog", "Dialog", 0));
39 | } // retranslateUi
40 |
41 | };
42 |
43 | namespace Ui {
44 | class CategorySelectDialog: public Ui_CategorySelectDialog {};
45 | } // namespace Ui
46 |
47 | QT_END_NAMESPACE
48 |
49 | #endif // UI_CATEGORYSELECTDIALOG_H
50 |
--------------------------------------------------------------------------------
/src/view/ui_customdialog.h:
--------------------------------------------------------------------------------
1 | /********************************************************************************
2 | ** Form generated from reading UI file 'eventdialog.ui'
3 | **
4 | ** Created by: Qt User Interface Compiler version 5.5.1
5 | **
6 | ** WARNING! All changes made in this file will be lost when recompiling UI file!
7 | ********************************************************************************/
8 |
9 | #ifndef UI_CUSTOMDIALOG_H
10 | #define UI_CUSTOMDIALOG_H
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | QT_BEGIN_NAMESPACE
20 |
21 | class Ui_CustomDialog
22 | {
23 | public:
24 |
25 | void setupUi(QDialog *CustomDialog)
26 | {
27 | if (CustomDialog->objectName().isEmpty())
28 | CustomDialog->setObjectName(QStringLiteral("CustomDialog"));
29 | CustomDialog->resize(400, 300);
30 |
31 | CustomDialog->setWindowTitle(QApplication::translate("CustomDialog", "Dialog", 0));
32 |
33 | QMetaObject::connectSlotsByName(CustomDialog);
34 | } // setupUi
35 |
36 | };
37 |
38 | namespace Ui {
39 | class CustomDialog: public Ui_CustomDialog {};
40 | } // namespace Ui
41 |
42 | QT_END_NAMESPACE
43 |
44 | #endif
45 |
--------------------------------------------------------------------------------
/src/view/ui_eventdialog.h:
--------------------------------------------------------------------------------
1 | /********************************************************************************
2 | ** Form generated from reading UI file 'eventdialog.ui'
3 | **
4 | ** Created by: Qt User Interface Compiler version 5.5.1
5 | **
6 | ** WARNING! All changes made in this file will be lost when recompiling UI file!
7 | ********************************************************************************/
8 |
9 | #ifndef UI_EVENTDIALOG_H
10 | #define UI_EVENTDIALOG_H
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | QT_BEGIN_NAMESPACE
20 |
21 | class Ui_EventDialog
22 | {
23 | public:
24 |
25 | void setupUi(QDialog *EventDialog)
26 | {
27 | if (EventDialog->objectName().isEmpty())
28 | EventDialog->setObjectName(QStringLiteral("EventDialog"));
29 | EventDialog->resize(400, 300);
30 |
31 | retranslateUi(EventDialog);
32 |
33 | QMetaObject::connectSlotsByName(EventDialog);
34 | } // setupUi
35 |
36 | void retranslateUi(QDialog *EventDialog)
37 | {
38 | EventDialog->setWindowTitle(QApplication::translate("EventDialog", "Dialog", 0));
39 | } // retranslateUi
40 |
41 | };
42 |
43 | namespace Ui {
44 | class EventDialog: public Ui_EventDialog {};
45 | } // namespace Ui
46 |
47 | QT_END_NAMESPACE
48 |
49 | #endif // UI_EVENTDIALOG_H
50 |
--------------------------------------------------------------------------------
/src/view/ui_kalendar.h:
--------------------------------------------------------------------------------
1 | /********************************************************************************
2 | ** Form generated from reading UI file 'kalendar.ui'
3 | **
4 | ** Created by: Qt User Interface Compiler version 5.5.1
5 | **
6 | ** WARNING! All changes made in this file will be lost when recompiling UI file!
7 | ********************************************************************************/
8 |
9 | #ifndef UI_KALENDAR_H
10 | #define UI_KALENDAR_H
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 | #include
22 |
23 | QT_BEGIN_NAMESPACE
24 |
25 | class Ui_Kalendar
26 | {
27 | public:
28 | QMenuBar *menuBar;
29 | QToolBar *mainToolBar;
30 | QWidget *centralWidget;
31 | QStatusBar *statusBar;
32 |
33 | void setupUi(QMainWindow *Kalendar)
34 | {
35 | if (Kalendar->objectName().isEmpty())
36 | Kalendar->setObjectName(QStringLiteral("Kalendar"));
37 | Kalendar->resize(400, 300);
38 | menuBar = new QMenuBar(Kalendar);
39 | menuBar->setObjectName(QStringLiteral("menuBar"));
40 | Kalendar->setMenuBar(menuBar);
41 | mainToolBar = new QToolBar(Kalendar);
42 | mainToolBar->setObjectName(QStringLiteral("mainToolBar"));
43 | Kalendar->addToolBar(mainToolBar);
44 | centralWidget = new QWidget(Kalendar);
45 | centralWidget->setObjectName(QStringLiteral("centralWidget"));
46 | Kalendar->setCentralWidget(centralWidget);
47 | statusBar = new QStatusBar(Kalendar);
48 | statusBar->setObjectName(QStringLiteral("statusBar"));
49 | Kalendar->setStatusBar(statusBar);
50 |
51 | retranslateUi(Kalendar);
52 |
53 | QMetaObject::connectSlotsByName(Kalendar);
54 | } // setupUi
55 |
56 | void retranslateUi(QMainWindow *Kalendar)
57 | {
58 | Kalendar->setWindowTitle(QApplication::translate("Kalendar", "Kalendar", 0));
59 | } // retranslateUi
60 |
61 | };
62 |
63 | namespace Ui {
64 | class Kalendar: public Ui_Kalendar {};
65 | } // namespace Ui
66 |
67 | QT_END_NAMESPACE
68 |
69 | #endif // UI_KALENDAR_H
70 |
--------------------------------------------------------------------------------
/src/view/ui_monthview.h:
--------------------------------------------------------------------------------
1 | /********************************************************************************
2 | ** Form generated from reading UI file 'monthview.ui'
3 | **
4 | ** Created by: Qt User Interface Compiler version 5.5.1
5 | **
6 | ** WARNING! All changes made in this file will be lost when recompiling UI file!
7 | ********************************************************************************/
8 |
9 | #ifndef UI_MONTHVIEW_H
10 | #define UI_MONTHVIEW_H
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 |
22 | QT_BEGIN_NAMESPACE
23 |
24 | class Ui_MonthView
25 | {
26 | public:
27 | QMenuBar *menubar;
28 | QWidget *centralwidget;
29 | QStatusBar *statusbar;
30 |
31 | void setupUi(QMainWindow *MonthView)
32 | {
33 | if (MonthView->objectName().isEmpty())
34 | MonthView->setObjectName(QStringLiteral("MonthView"));
35 | MonthView->resize(800, 600);
36 | menubar = new QMenuBar(MonthView);
37 | menubar->setObjectName(QStringLiteral("menubar"));
38 | MonthView->setMenuBar(menubar);
39 | centralwidget = new QWidget(MonthView);
40 | centralwidget->setObjectName(QStringLiteral("centralwidget"));
41 | MonthView->setCentralWidget(centralwidget);
42 | statusbar = new QStatusBar(MonthView);
43 | statusbar->setObjectName(QStringLiteral("statusbar"));
44 | MonthView->setStatusBar(statusbar);
45 |
46 | retranslateUi(MonthView);
47 |
48 | QMetaObject::connectSlotsByName(MonthView);
49 | } // setupUi
50 |
51 | void retranslateUi(QMainWindow *MonthView)
52 | {
53 | MonthView->setWindowTitle(QApplication::translate("MonthView", "MainWindow", 0));
54 | } // retranslateUi
55 |
56 | };
57 |
58 | namespace Ui {
59 | class MonthView: public Ui_MonthView {};
60 | } // namespace Ui
61 |
62 | QT_END_NAMESPACE
63 |
64 | #endif // UI_MONTHVIEW_H
65 |
--------------------------------------------------------------------------------
/src/view/ui_settings.h:
--------------------------------------------------------------------------------
1 | /********************************************************************************
2 | ** Form generated from reading UI file 'eventdialog.ui'
3 | **
4 | ** Created by: Qt User Interface Compiler version 5.5.1
5 | **
6 | ** WARNING! All changes made in this file will be lost when recompiling UI file!
7 | ********************************************************************************/
8 |
9 | #ifndef UI_CUSTOMDIALOG_H
10 | #define UI_CUSTOMDIALOG_H
11 |
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 |
19 | QT_BEGIN_NAMESPACE
20 |
21 | class Ui_Settings
22 | {
23 | public:
24 |
25 | void setupUi(QDialog *Settings)
26 | {
27 | if (Settings->objectName().isEmpty())
28 | Settings->setObjectName(QStringLiteral("Settings"));
29 | Settings->resize(400, 300);
30 |
31 | Settings->setWindowTitle(QApplication::translate("Settings", "Dialog", 0));
32 |
33 | QMetaObject::connectSlotsByName(Settings);
34 | } // setupUi
35 |
36 | };
37 |
38 | namespace Ui {
39 | class Settings: public Ui_Settings {};
40 | } // namespace Ui
41 |
42 | QT_END_NAMESPACE
43 |
44 | #endif
45 |
--------------------------------------------------------------------------------
/src/view/view.h:
--------------------------------------------------------------------------------
1 | #ifndef VIEW_H
2 | #define VIEW_H
3 |
4 | #include "model/date.h"
5 | #include "model/category.h"
6 |
7 | /* Abstract Class */
8 | class View
9 | {
10 | public:
11 | //pure virtual functions
12 | virtual void refresh_events() = 0;
13 | virtual void display_events(Date date, Category *category) = 0;
14 | };
15 |
16 | #endif // VIEW_H
17 |
--------------------------------------------------------------------------------