current state, just to have some history
Dieser Commit ist enthalten in:
Commit
3fd0aa18be
41
.gitignore
vendored
Normale Datei
41
.gitignore
vendored
Normale Datei
@ -0,0 +1,41 @@
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
*.pro.user*
|
||||
*.pro*.user*
|
||||
*.hpp~*
|
||||
*.cpp~*
|
||||
|
||||
.directory
|
||||
.build*
|
||||
build*
|
||||
339
LICENSE
Normale Datei
339
LICENSE
Normale Datei
@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
20
README.md
Normale Datei
20
README.md
Normale Datei
@ -0,0 +1,20 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Third party
|
||||
server:
|
||||
boost 1.71
|
||||
nlohmann's json for modern C++
|
||||
client:
|
||||
Qt 5
|
||||
https://github.com/snowwlex/QtWaitingSpinner
|
||||
6
client/dark.qrc
Normale Datei
6
client/dark.qrc
Normale Datei
@ -0,0 +1,6 @@
|
||||
<RCC>
|
||||
<qresource prefix="/dark">
|
||||
<file alias="run.svg">gfx/dark/run.svg</file>
|
||||
<file alias="stop.svg">gfx/dark/stop.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
86
client/gfx/dark/run.svg
Normale Datei
86
client/gfx/dark/run.svg
Normale Datei
Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist
|
Nachher Breite: | Höhe: | Größe: 8.5 KiB |
86
client/gfx/dark/stop.svg
Normale Datei
86
client/gfx/dark/stop.svg
Normale Datei
@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="96"
|
||||
height="96"
|
||||
viewBox="0 0 25.399999 25.400001"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
sodipodi:docname="stop.svg">
|
||||
<defs
|
||||
id="defs2" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="5.6"
|
||||
inkscape:cx="87.582824"
|
||||
inkscape:cy="31.95405"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1015"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3713"
|
||||
spacingx="0.26458333"
|
||||
empspacing="4" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-nc/4.0/" />
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-nc/4.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://creativecommons.org/ns#Attribution" />
|
||||
<cc:prohibits
|
||||
rdf:resource="http://creativecommons.org/ns#CommercialUse" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-271.59998)">
|
||||
<path
|
||||
style="stroke-width:0.99999994;fill:#cd5c5c;fill-opacity:0.94117647"
|
||||
d="M 18 8 A 9.9999997 9.9999997 0 0 0 8 18 L 8 78 A 9.9999997 9.9999997 0 0 0 18 88 L 78 88 A 9.9999997 9.9999997 0 0 0 88 78 L 88 18 A 9.9999997 9.9999997 0 0 0 78 8 L 18 8 z "
|
||||
transform="matrix(0.26458333,0,0,0.26458333,0,271.59998)"
|
||||
id="path17" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Nachher Breite: | Höhe: | Größe: 2.8 KiB |
208
client/src/dialog/connectdialog.cpp
Normale Datei
208
client/src/dialog/connectdialog.cpp
Normale Datei
@ -0,0 +1,208 @@
|
||||
/**
|
||||
* client/src/dialog/connectdialog.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "connectdialog.hpp"
|
||||
#include <QUdpSocket>
|
||||
#include <QNetworkInterface>
|
||||
#include <QFormLayout>
|
||||
#include <QComboBox>
|
||||
#include <QLineEdit>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QUrl>
|
||||
#include <QTimer>
|
||||
#include "../network/client.hpp"
|
||||
|
||||
ConnectDialog::ConnectDialog(QWidget* parent) :
|
||||
QDialog(parent, Qt::Dialog | Qt::WindowTitleHint | Qt::WindowCloseButtonHint),
|
||||
m_udpSocket{new QUdpSocket(this)},
|
||||
m_server{new QComboBox()},
|
||||
m_username{new QLineEdit()},
|
||||
m_password{new QLineEdit()},
|
||||
m_status{new QLabel()},
|
||||
m_connect{new QPushButton(tr("Connect"))}
|
||||
{
|
||||
setWindowTitle(tr("Connect to server"));
|
||||
|
||||
//m_udpSocket->bind(QHostAddress::Any);
|
||||
|
||||
m_server->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);
|
||||
m_server->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
m_server->setEditable(true);
|
||||
//m_server->addItem("localhost");
|
||||
|
||||
m_password->setEchoMode(QLineEdit::Password);
|
||||
|
||||
m_status->setAlignment(Qt::AlignCenter);
|
||||
m_status->setMinimumWidth(400);
|
||||
|
||||
QFormLayout* formLayout = new QFormLayout();
|
||||
formLayout->setMargin(0);
|
||||
formLayout->addRow(tr("Server"), m_server);
|
||||
formLayout->addRow(tr("Username"), m_username);
|
||||
formLayout->addRow(tr("Password"), m_password);
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->setMargin(0);
|
||||
layout->addLayout(formLayout);
|
||||
layout->addWidget(m_status);
|
||||
layout->addWidget(m_connect, 0, Qt::AlignCenter);
|
||||
layout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
|
||||
setLayout(layout);
|
||||
//setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
|
||||
connect(m_udpSocket, &QUdpSocket::readyRead, this, &ConnectDialog::socketReadyRead);
|
||||
connect(&m_broadcastTimer, &QTimer::timeout, this, &ConnectDialog::broadcast);
|
||||
connect(Client::instance, &Client::stateChanged, this, &ConnectDialog::stateChanged);
|
||||
connect(m_server, static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &ConnectDialog::serverIndexChanged);
|
||||
connect(m_server, &QComboBox::currentTextChanged, this, &ConnectDialog::serverTextChanged);
|
||||
connect(m_connect, &QPushButton::clicked, this, &ConnectDialog::connectClick);
|
||||
m_broadcastTimer.start(1000);
|
||||
broadcast();
|
||||
}
|
||||
|
||||
void ConnectDialog::closeEvent(QCloseEvent*)
|
||||
{
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
void ConnectDialog::setControlsEnabled(bool value)
|
||||
{
|
||||
m_server->setEnabled(value);
|
||||
m_username->setEnabled(value);
|
||||
m_password->setEnabled(value);
|
||||
m_connect->setEnabled(value);
|
||||
}
|
||||
|
||||
void ConnectDialog::broadcast()
|
||||
{
|
||||
// decrement TTL of all discovered servers:
|
||||
for(Servers::iterator it = m_servers.begin(); it != m_servers.end(); )
|
||||
{
|
||||
if(--it.value().second == 0)
|
||||
{
|
||||
for(int i = 0; i < m_server->count(); i++)
|
||||
if(m_server->itemData(i) == it.key())
|
||||
{
|
||||
m_server->removeItem(i);
|
||||
break;
|
||||
}
|
||||
it = m_servers.erase(it);
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
|
||||
// send discovery request on all networks:
|
||||
for(auto& interface : QNetworkInterface::allInterfaces())
|
||||
for(auto& addressEntry : interface.addressEntries())
|
||||
if(!addressEntry.broadcast().isNull())
|
||||
{
|
||||
auto message = Message::newRequest(Message::Command::Discover);
|
||||
m_udpSocket->writeDatagram(reinterpret_cast<const char*>(**message), message->size(), addressEntry.broadcast(), Client::defaultPort);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectDialog::socketReadyRead()
|
||||
{
|
||||
while(m_udpSocket->hasPendingDatagrams())
|
||||
{
|
||||
Message message(m_udpSocket->pendingDatagramSize());
|
||||
QHostAddress host;
|
||||
quint16 port;
|
||||
|
||||
m_udpSocket->readDatagram(static_cast<char*>(*message), message.size(), &host, &port);
|
||||
|
||||
if(message.command() == Message::Command::Discover && message.isResponse() && !message.isError())
|
||||
{
|
||||
QString name = QString::fromUtf8(message.read<QByteArray>());
|
||||
|
||||
QUrl url;
|
||||
url.setHost(host.toString());
|
||||
url.setPort(port);
|
||||
|
||||
auto it = m_servers.find(url);
|
||||
if(it == m_servers.end())
|
||||
{
|
||||
m_servers[url] = {name, defaultTTL};
|
||||
m_server->addItem(url.host() + (url.port() != Client::defaultPort ? ":" + QString::number(url.port()) : "") + " (" + name + ")", url);
|
||||
}
|
||||
else
|
||||
it->second = defaultTTL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectDialog::stateChanged()
|
||||
{
|
||||
switch(Client::instance->state())
|
||||
{
|
||||
case Client::State::Disconnected:
|
||||
m_status->setText("");
|
||||
break;
|
||||
|
||||
case Client::State::Disconnecting:
|
||||
m_status->setText(tr("Disconnecting"));
|
||||
break;
|
||||
|
||||
case Client::State::Connecting:
|
||||
m_status->setText(tr("Connecting"));
|
||||
break;
|
||||
|
||||
case Client::State::Connected:
|
||||
m_status->setText(tr("Connected"));
|
||||
QTimer::singleShot(300, this, &ConnectDialog::close);
|
||||
break;
|
||||
|
||||
case Client::State::SocketError:
|
||||
m_status->setText(Client::instance->errorString());
|
||||
setControlsEnabled(true);
|
||||
break;
|
||||
|
||||
case Client::State::ErrorAuthenticationFailed:
|
||||
m_status->setText(tr("Authentication failed"));
|
||||
break;
|
||||
|
||||
case Client::State::ErrorNewSessionFailed:
|
||||
m_status->setText(tr("Create session failed"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectDialog::serverIndexChanged(int index)
|
||||
{
|
||||
m_url = m_server->itemData(index).toUrl();
|
||||
m_connect->setEnabled(m_url.isValid());
|
||||
}
|
||||
|
||||
void ConnectDialog::serverTextChanged(const QString& text)
|
||||
{
|
||||
QString url{text};
|
||||
m_url = QUrl::fromUserInput(url.remove(QRegularExpression("\\s*\\(.*\\)$")));
|
||||
m_connect->setEnabled(m_url.isValid());
|
||||
}
|
||||
|
||||
void ConnectDialog::connectClick()
|
||||
{
|
||||
setControlsEnabled(false);
|
||||
Client::instance->connectToHost(m_url, m_username->text(), m_password->text());
|
||||
}
|
||||
71
client/src/dialog/connectdialog.hpp
Normale Datei
71
client/src/dialog/connectdialog.hpp
Normale Datei
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* client/src/dialog/connectdialog.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_DIALOG_CONNECTDIALOG_HPP
|
||||
#define CLIENT_DIALOG_CONNECTDIALOG_HPP
|
||||
|
||||
#include <QDialog>
|
||||
#include <QTimer>
|
||||
#include <QMap>
|
||||
#include <QPair>
|
||||
#include <QUrl>
|
||||
|
||||
class QUdpSocket;
|
||||
class QComboBox;
|
||||
class QLineEdit;
|
||||
class QLabel;
|
||||
class QPushButton;
|
||||
|
||||
class ConnectDialog : public QDialog
|
||||
{
|
||||
protected:
|
||||
using Servers = QMap<QUrl, QPair<QString, int>>;
|
||||
|
||||
static constexpr int defaultTTL = 3;
|
||||
|
||||
QUdpSocket* m_udpSocket;
|
||||
Servers m_servers;
|
||||
QTimer m_broadcastTimer;
|
||||
QComboBox* m_server;
|
||||
QLineEdit* m_username;
|
||||
QLineEdit* m_password;
|
||||
QLabel* m_status;
|
||||
QPushButton* m_connect;
|
||||
QUrl m_url;
|
||||
|
||||
void closeEvent(QCloseEvent*) final;
|
||||
void setControlsEnabled(bool value);
|
||||
|
||||
protected slots:
|
||||
void broadcast();
|
||||
void socketReadyRead();
|
||||
void stateChanged();
|
||||
void serverIndexChanged(int index);
|
||||
void serverTextChanged(const QString& text);
|
||||
void connectClick();
|
||||
|
||||
public:
|
||||
ConnectDialog(QWidget* parent = nullptr);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
53
client/src/main.cpp
Normale Datei
53
client/src/main.cpp
Normale Datei
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* client/src/main.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "mainwindow.hpp"
|
||||
#include <QApplication>
|
||||
#ifdef Q_OS_WINDOWS
|
||||
#include <QSettings>
|
||||
#endif
|
||||
#include "network/client.hpp"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication::setOrganizationName("Traintastic");
|
||||
QApplication::setOrganizationDomain("traintastic.org");
|
||||
QApplication::setApplicationName("traintastic-client");
|
||||
QApplication::setApplicationVersion("0.1.0");
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
QSettings::setDefaultFormat(QSettings::IniFormat);
|
||||
#endif
|
||||
|
||||
QApplication app(argc, argv);
|
||||
|
||||
Client client;
|
||||
Client::instance = &client;
|
||||
|
||||
MainWindow mw;
|
||||
mw.show();
|
||||
|
||||
if(client.state() != Client::State::Connected)
|
||||
mw.connectToServer();
|
||||
|
||||
return app.exec();
|
||||
}
|
||||
268
client/src/mainwindow.cpp
Normale Datei
268
client/src/mainwindow.cpp
Normale Datei
@ -0,0 +1,268 @@
|
||||
/**
|
||||
* client/src/mainwindow.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "mainwindow.hpp"
|
||||
#include <QMenuBar>
|
||||
#include <QStatusBar>
|
||||
#include <QMdiArea>
|
||||
#include <QMdiSubWindow>
|
||||
#include <QVBoxLayout>
|
||||
#include <QToolBar>
|
||||
#include <QApplication>
|
||||
#include <QMessageBox>
|
||||
#include <QSettings>
|
||||
#include <QApplication>
|
||||
#include "dialog/connectdialog.hpp"
|
||||
#include "network/client.hpp"
|
||||
#include "subwindow/hardwarelistsubwindow.hpp"
|
||||
#include "subwindow/serversettingssubwindow.hpp"
|
||||
#include "subwindow/serverconsolesubwindow.hpp"
|
||||
|
||||
#define SETTING_PREFIX "mainwindow/"
|
||||
#define SETTING_GEOMETRY SETTING_PREFIX "geometry"
|
||||
#define SETTING_WINDOWSTATE SETTING_PREFIX "windowstate"
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent) :
|
||||
QMainWindow(parent),
|
||||
m_mdiArea{new QMdiArea()}
|
||||
{
|
||||
setWindowTitle("Traintastic");
|
||||
|
||||
QAction* actFullScreen;
|
||||
|
||||
m_mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
m_mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
|
||||
{
|
||||
setMenuBar(new QMenuBar());
|
||||
QMenu* menu;
|
||||
//QMenu* subMenu;
|
||||
//QAction* act;
|
||||
|
||||
menu = menuBar()->addMenu(tr("File"));
|
||||
m_actionConnectToServer = menu->addAction(tr("Connect to server") + "...", this, &MainWindow::connectToServer);
|
||||
m_actionDisconnectFromServer = menu->addAction(tr("Disconnect from server"), this, &MainWindow::disconnectFromServer);
|
||||
menu->addSeparator();
|
||||
m_actionNewWorld = menu->addAction(tr("New world"), this, &MainWindow::newWorld);
|
||||
m_actionLoadWorld = menu->addAction(tr("Load world") + "...", this, &MainWindow::loadWorld);
|
||||
m_actionSaveWorld = menu->addAction(tr("Save world"), this, &MainWindow::saveWorld);
|
||||
menu->addSeparator();
|
||||
m_actionImportWorld = menu->addAction(tr("Import world") + "...", this, &MainWindow::importWorld);
|
||||
m_actionExportWorld = menu->addAction(tr("Export world") + "...", this, &MainWindow::exportWorld);
|
||||
menu->addSeparator();
|
||||
menu->addAction(tr("Quit"), this, &MainWindow::close);
|
||||
|
||||
menu = menuBar()->addMenu(tr("View"));
|
||||
actFullScreen = menu->addAction(tr("Fullscreen"), this, &MainWindow::toggleFullScreen);
|
||||
actFullScreen->setCheckable(true);
|
||||
actFullScreen->setShortcut(Qt::Key_F11);
|
||||
|
||||
menu = menuBar()->addMenu(tr("Objects"));
|
||||
m_actionHardware = menu->addAction(tr("Hardware") + "...", this, &MainWindow::showHardware);
|
||||
|
||||
menu = menuBar()->addMenu(tr("Tools"));
|
||||
menu->addAction(tr("Client settings") + "...");
|
||||
menu->addSeparator();
|
||||
m_actionServerSettings = menu->addAction(tr("Server settings") + "...", this, &MainWindow::showServerSettings);
|
||||
m_actionServerConsole = menu->addAction(tr("Server console") + "...", this, &MainWindow::showServerConsole);
|
||||
|
||||
menu = menuBar()->addMenu(tr("Help"));
|
||||
menu->addAction(tr("Help"));
|
||||
menu->addSeparator();
|
||||
menu->addAction(tr("About Qt") + "...", qApp, &QApplication::aboutQt);
|
||||
menu->addAction(tr("About") + "...", this, &MainWindow::showAbout);
|
||||
}
|
||||
|
||||
QToolBar* toolbar = new QToolBar();
|
||||
m_actionModeRun = toolbar->addAction(QIcon(":/dark/run.svg"), tr("Run"));
|
||||
m_actionModeStop = toolbar->addAction(QIcon(":/dark/stop.svg"), tr("Stop"));
|
||||
m_actionModeEdit = toolbar->addAction(tr("Edit"));
|
||||
toolbar->addSeparator();
|
||||
|
||||
QVBoxLayout* l = new QVBoxLayout();
|
||||
l->setMargin(0);
|
||||
l->addWidget(toolbar);
|
||||
l->addWidget(m_mdiArea);
|
||||
|
||||
QWidget* w = new QWidget();
|
||||
w->setLayout(l);
|
||||
|
||||
setCentralWidget(w);
|
||||
setStatusBar(new QStatusBar());
|
||||
|
||||
QSettings settings;
|
||||
if(settings.contains(SETTING_GEOMETRY))
|
||||
restoreGeometry(settings.value(SETTING_GEOMETRY).toByteArray());
|
||||
if(settings.contains(SETTING_WINDOWSTATE))
|
||||
setWindowState(static_cast<Qt::WindowState>(settings.value(SETTING_WINDOWSTATE).toInt()));
|
||||
actFullScreen->setChecked(isFullScreen());
|
||||
|
||||
connect(Client::instance, &Client::stateChanged, this, &MainWindow::updateActionEnabled);
|
||||
|
||||
updateActionEnabled();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
}
|
||||
|
||||
void MainWindow::connectToServer()
|
||||
{
|
||||
ConnectDialog* d = new ConnectDialog(this);
|
||||
d->setModal(true);
|
||||
d->show();
|
||||
}
|
||||
|
||||
void MainWindow::disconnectFromServer()
|
||||
{
|
||||
Client::instance->disconnectFromHost();
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
QSettings settings;
|
||||
settings.setValue(SETTING_GEOMETRY, saveGeometry());
|
||||
settings.setValue(SETTING_WINDOWSTATE, static_cast<int>(windowState()));
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
void MainWindow::newWorld()
|
||||
{
|
||||
}
|
||||
|
||||
void MainWindow::loadWorld()
|
||||
{
|
||||
}
|
||||
|
||||
void MainWindow::saveWorld()
|
||||
{
|
||||
}
|
||||
|
||||
void MainWindow::importWorld()
|
||||
{
|
||||
}
|
||||
|
||||
void MainWindow::exportWorld()
|
||||
{
|
||||
}
|
||||
|
||||
void MainWindow::toggleFullScreen()
|
||||
{
|
||||
const bool fullScreen = qobject_cast<QAction*>(sender())->isChecked();
|
||||
if(fullScreen == isFullScreen())
|
||||
return;
|
||||
|
||||
if(fullScreen)
|
||||
{
|
||||
m_beforeFullScreenGeometry = saveGeometry();
|
||||
showFullScreen();
|
||||
}
|
||||
else
|
||||
{
|
||||
showNormal(); // required to exit fullscreen mode
|
||||
if(!m_beforeFullScreenGeometry.isEmpty())
|
||||
restoreGeometry(m_beforeFullScreenGeometry);
|
||||
else
|
||||
showMaximized();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::showHardware()
|
||||
{
|
||||
if(!m_mdiSubWindow.hardwareList)
|
||||
{
|
||||
m_mdiSubWindow.hardwareList = new HardwareListSubWindow();
|
||||
m_mdiArea->addSubWindow(m_mdiSubWindow.hardwareList);
|
||||
m_mdiSubWindow.hardwareList->setAttribute(Qt::WA_DeleteOnClose);
|
||||
connect(m_mdiSubWindow.hardwareList, &QMdiSubWindow::destroyed, [=](QObject*){ m_mdiSubWindow.hardwareList = nullptr; });
|
||||
m_mdiSubWindow.hardwareList->show();
|
||||
}
|
||||
else
|
||||
m_mdiArea->setActiveSubWindow(m_mdiSubWindow.hardwareList);
|
||||
}
|
||||
|
||||
void MainWindow::showServerSettings()
|
||||
{
|
||||
if(!m_mdiSubWindow.serverSettings)
|
||||
{
|
||||
m_mdiSubWindow.serverSettings = new ServerSettingsSubWindow();
|
||||
m_mdiArea->addSubWindow(m_mdiSubWindow.serverSettings);
|
||||
m_mdiSubWindow.serverSettings->setAttribute(Qt::WA_DeleteOnClose);
|
||||
connect(m_mdiSubWindow.serverSettings, &QMdiSubWindow::destroyed, [=](QObject*){ m_mdiSubWindow.serverSettings = nullptr; });
|
||||
m_mdiSubWindow.serverSettings->show();
|
||||
}
|
||||
else
|
||||
m_mdiArea->setActiveSubWindow(m_mdiSubWindow.serverSettings);
|
||||
}
|
||||
|
||||
void MainWindow::showServerConsole()
|
||||
{
|
||||
if(!m_mdiSubWindow.serverConsole)
|
||||
{
|
||||
m_mdiSubWindow.serverConsole = new ServerConsoleSubWindow();
|
||||
m_mdiArea->addSubWindow(m_mdiSubWindow.serverConsole);
|
||||
m_mdiSubWindow.serverConsole->setAttribute(Qt::WA_DeleteOnClose);
|
||||
connect(m_mdiSubWindow.serverConsole, &QMdiSubWindow::destroyed, [=](QObject*){ m_mdiSubWindow.serverConsole = nullptr; });
|
||||
m_mdiSubWindow.serverConsole->show();
|
||||
}
|
||||
else
|
||||
m_mdiArea->setActiveSubWindow(m_mdiSubWindow.serverConsole);
|
||||
}
|
||||
|
||||
void MainWindow::showAbout()
|
||||
{
|
||||
QMessageBox::about(this, tr("About Traintastic"),
|
||||
"<h2>Traintastic <small>v" + QApplication::applicationVersion() + "</small></h2>"
|
||||
"<p>Copyright © 2019 Reinder Feenstra</p>"
|
||||
"<p>This program is free software; you can redistribute it and/or"
|
||||
" modify it under the terms of the GNU General Public License"
|
||||
" as published by the Free Software Foundation; either version 2"
|
||||
" of the License, or (at your option) any later version.</p>"
|
||||
"<p>This program is distributed in the hope that it will be useful,"
|
||||
" but WITHOUT ANY WARRANTY; without even the implied warranty of"
|
||||
" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"
|
||||
" GNU General Public License for more details.</p>");
|
||||
}
|
||||
|
||||
void MainWindow::updateActionEnabled()
|
||||
{
|
||||
Client& client = *Client::instance;
|
||||
const bool connected = client.state() == Client::State::Connected;
|
||||
|
||||
m_actionConnectToServer->setEnabled(client.isDisconnected());
|
||||
m_actionConnectToServer->setVisible(!connected);
|
||||
m_actionDisconnectFromServer->setVisible(connected);
|
||||
m_actionNewWorld->setEnabled(connected);
|
||||
m_actionLoadWorld->setEnabled(connected);
|
||||
m_actionSaveWorld->setEnabled(connected && false);
|
||||
m_actionImportWorld->setEnabled(connected);
|
||||
m_actionExportWorld->setEnabled(connected);
|
||||
m_actionHardware->setEnabled(connected);
|
||||
m_actionServerSettings->setEnabled(connected);
|
||||
m_actionServerConsole->setEnabled(connected);
|
||||
m_actionModeRun->setEnabled(false);
|
||||
m_actionModeStop->setEnabled(false);
|
||||
m_actionModeEdit->setEnabled(false);
|
||||
|
||||
//if(client.state() == Client::State::SocketError)
|
||||
// statusBar()->showMessage(client.errorString());
|
||||
}
|
||||
85
client/src/mainwindow.hpp
Normale Datei
85
client/src/mainwindow.hpp
Normale Datei
@ -0,0 +1,85 @@
|
||||
/**
|
||||
* client/src/mainwindow.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_MAINWINDOW_HPP
|
||||
#define CLIENT_MAINWINDOW_HPP
|
||||
#define MAINWINDOW_HPP
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
class QMdiArea;
|
||||
class HardwareListSubWindow;
|
||||
class ServerSettingsSubWindow;
|
||||
class ServerConsoleSubWindow;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
QMdiArea* m_mdiArea;
|
||||
struct
|
||||
{
|
||||
HardwareListSubWindow* hardwareList = nullptr;
|
||||
ServerSettingsSubWindow* serverSettings = nullptr;
|
||||
ServerConsoleSubWindow* serverConsole = nullptr;
|
||||
} m_mdiSubWindow;
|
||||
QAction* m_actionConnectToServer;
|
||||
QAction* m_actionDisconnectFromServer;
|
||||
QAction* m_actionNewWorld;
|
||||
QAction* m_actionLoadWorld;
|
||||
QAction* m_actionSaveWorld;
|
||||
QAction* m_actionImportWorld;
|
||||
QAction* m_actionExportWorld;
|
||||
QAction* m_actionHardware;
|
||||
QAction* m_actionServerSettings;
|
||||
QAction* m_actionServerConsole;
|
||||
QAction* m_actionModeRun;
|
||||
QAction* m_actionModeStop;
|
||||
QAction* m_actionModeEdit;
|
||||
QByteArray m_beforeFullScreenGeometry;
|
||||
|
||||
void closeEvent(QCloseEvent* event) final;
|
||||
void updateActionEnabled();
|
||||
|
||||
protected slots:
|
||||
void disconnectFromServer();
|
||||
void newWorld();
|
||||
void loadWorld();
|
||||
void saveWorld();
|
||||
void importWorld();
|
||||
void exportWorld();
|
||||
void toggleFullScreen();
|
||||
void showHardware();
|
||||
void showServerSettings();
|
||||
void showServerConsole();
|
||||
void showAbout();
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow() override;
|
||||
|
||||
public slots:
|
||||
void connectToServer();
|
||||
};
|
||||
|
||||
#endif
|
||||
462
client/src/network/client.cpp
Normale Datei
462
client/src/network/client.cpp
Normale Datei
@ -0,0 +1,462 @@
|
||||
/**
|
||||
* client/src/network/client.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "client.hpp"
|
||||
#include <QTcpSocket>
|
||||
#include <QUrl>
|
||||
#include <QCryptographicHash>
|
||||
#include <message.hpp>
|
||||
#include "object.hpp"
|
||||
#include "property.hpp"
|
||||
#include "tablemodel.hpp"
|
||||
#include <enum/interfaceitemtype.hpp>
|
||||
#include <enum/propertytype.hpp>
|
||||
|
||||
Client* Client::instance = nullptr;
|
||||
|
||||
Client::Client() :
|
||||
QObject(),
|
||||
m_socket{new QTcpSocket(this)},
|
||||
m_state{State::Disconnected}
|
||||
{
|
||||
connect(m_socket, &QTcpSocket::connected, this, &Client::socketConnected);
|
||||
connect(m_socket, &QTcpSocket::disconnected, this, &Client::socketDisconnected);
|
||||
connect(m_socket, static_cast<void(QTcpSocket::*)(QAbstractSocket::SocketError)>(&QTcpSocket::error), this, &Client::socketError);
|
||||
|
||||
m_socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
|
||||
|
||||
connect(m_socket, &QTcpSocket::readyRead, this, &Client::socketReadyRead);
|
||||
}
|
||||
|
||||
Client::~Client()
|
||||
{
|
||||
}
|
||||
|
||||
bool Client::isDisconnected() const
|
||||
{
|
||||
return m_state != State::Connected && m_state != State::Connecting && m_state != State::Disconnecting;
|
||||
}
|
||||
|
||||
Client::SocketError Client::error() const
|
||||
{
|
||||
return m_socket->error();
|
||||
}
|
||||
|
||||
QString Client::errorString() const
|
||||
{
|
||||
return m_socket->errorString();
|
||||
}
|
||||
|
||||
void Client::connectToHost(const QUrl& url, const QString& username, const QString& password)
|
||||
{
|
||||
m_username = username;
|
||||
if(password.isEmpty())
|
||||
m_password.clear();
|
||||
else
|
||||
m_password = QCryptographicHash::hash(password.toUtf8(), QCryptographicHash::Sha256);
|
||||
setState(State::Connecting);
|
||||
m_socket->connectToHost(url.host(), static_cast<quint16>(url.port(defaultPort)));
|
||||
}
|
||||
|
||||
void Client::disconnectFromHost()
|
||||
{
|
||||
m_socket->disconnectFromHost();
|
||||
}
|
||||
|
||||
void Client::cancelRequest(int requestId)
|
||||
{
|
||||
if(requestId < std::numeric_limits<uint16_t>::min() || requestId > std::numeric_limits<uint16_t>::max())
|
||||
return;
|
||||
|
||||
auto it = m_requestCallback.find(static_cast<uint16_t>(requestId));
|
||||
if(it != m_requestCallback.end())
|
||||
m_requestCallback.erase(it);
|
||||
}
|
||||
|
||||
int Client::getObject(const QString& id, std::function<void(const ObjectPtr&, Message::ErrorCode)> callback)
|
||||
{
|
||||
std::unique_ptr<Message> request{Message::newRequest(Message::Command::GetObject)};
|
||||
request->write(id.toLatin1());
|
||||
send(request,
|
||||
[this, callback](const std::shared_ptr<Message> message)
|
||||
{
|
||||
ObjectPtr object;
|
||||
if(!message->isError())
|
||||
object = readObject(*message);
|
||||
m_objects[object->handle()] = object.data();
|
||||
callback(object, message->errorCode());
|
||||
});
|
||||
return request->requestId();
|
||||
}
|
||||
|
||||
void Client::releaseObject(Object* object)
|
||||
{
|
||||
Q_ASSERT(object);
|
||||
m_objects.remove(object->handle());
|
||||
auto event = Message::newEvent(Message::Command::ReleaseObject, sizeof(object->m_handle));
|
||||
event->write(object->m_handle);
|
||||
send(event);
|
||||
object->m_handle = invalidHandle;
|
||||
}
|
||||
|
||||
void Client::setPropertyBool(Property& property, bool value)
|
||||
{
|
||||
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
||||
event->write(static_cast<Object*>(property.parent())->m_handle);
|
||||
event->write(property.name().toLatin1());
|
||||
event->write(PropertyType::Boolean);
|
||||
event->write(value);
|
||||
send(event);
|
||||
}
|
||||
|
||||
void Client::setPropertyInt64(Property& property, int64_t value)
|
||||
{
|
||||
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
||||
event->write(static_cast<Object*>(property.parent())->m_handle);
|
||||
event->write(property.name().toLatin1());
|
||||
event->write(PropertyType::Integer);
|
||||
event->write(value);
|
||||
send(event);
|
||||
}
|
||||
|
||||
void Client::setPropertyDouble(Property& property, double value)
|
||||
{
|
||||
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
||||
event->write(static_cast<Object*>(property.parent())->m_handle);
|
||||
event->write(property.name().toLatin1());
|
||||
event->write(PropertyType::Float);
|
||||
event->write(value);
|
||||
send(event);
|
||||
}
|
||||
|
||||
void Client::setPropertyString(Property& property, const QString& value)
|
||||
{
|
||||
auto event = Message::newEvent(Message::Command::ObjectSetProperty);
|
||||
event->write(static_cast<Object*>(property.parent())->m_handle);
|
||||
event->write(property.name().toLatin1());
|
||||
event->write(PropertyType::String);
|
||||
event->write(value.toUtf8());
|
||||
send(event);
|
||||
}
|
||||
|
||||
int Client::getTableModel(const QString& id, std::function<void(const TableModelPtr&, Message::ErrorCode)> callback)
|
||||
{
|
||||
std::unique_ptr<Message> request{Message::newRequest(Message::Command::GetTableModel)};
|
||||
request->write(id.toLatin1());
|
||||
send(request,
|
||||
[this, callback](const std::shared_ptr<Message> message)
|
||||
{
|
||||
TableModelPtr tableModel;
|
||||
if(!message->isError())
|
||||
tableModel = readTableModel(*message);
|
||||
m_tableModels[tableModel->handle()] = tableModel.data();
|
||||
callback(tableModel, message->errorCode());
|
||||
});
|
||||
return request->requestId();
|
||||
}
|
||||
|
||||
void Client::releaseTableModel(TableModel* tableModel)
|
||||
{
|
||||
Q_ASSERT(tableModel);
|
||||
m_tableModels.remove(tableModel->handle());
|
||||
auto event = Message::newEvent(Message::Command::ReleaseTableModel, sizeof(tableModel->m_handle));
|
||||
event->write(tableModel->m_handle);
|
||||
send(event);
|
||||
tableModel->m_handle = invalidHandle;
|
||||
}
|
||||
|
||||
void Client::setTableModelRegion(TableModel* tableModel, int columnMin, int columnMax, int rowMin, int rowMax)
|
||||
{
|
||||
auto event = Message::newEvent(Message::Command::TableModelSetRegion);
|
||||
event->write(tableModel->handle());
|
||||
event->write(columnMin);
|
||||
event->write(columnMax);
|
||||
event->write(rowMin);
|
||||
event->write(rowMax);
|
||||
send(event);
|
||||
}
|
||||
|
||||
void Client::send(std::unique_ptr<Message>& message)
|
||||
{
|
||||
Q_ASSERT(!message->isRequest());
|
||||
m_socket->write(static_cast<const char*>(**message), message->size());
|
||||
}
|
||||
|
||||
void Client::send(std::unique_ptr<Message>& message, std::function<void(const std::shared_ptr<Message>&)> callback)
|
||||
{
|
||||
Q_ASSERT(message->isRequest());
|
||||
Q_ASSERT(!m_requestCallback.contains(message->requestId()));
|
||||
m_requestCallback[message->requestId()] = callback;
|
||||
m_socket->write(static_cast<const char*>(**message), message->size());
|
||||
}
|
||||
|
||||
ObjectPtr Client::readObject(const Message& message)
|
||||
{
|
||||
message.readBlock(); // object
|
||||
|
||||
const Handle handle = message.read<Handle>();
|
||||
|
||||
ObjectPtr obj; // get object by handle
|
||||
if(!obj)
|
||||
{
|
||||
const QString classId = QString::fromLatin1(message.read<QByteArray>());
|
||||
obj = QSharedPointer<Object>::create(handle, classId);
|
||||
|
||||
message.readBlock(); // items
|
||||
while(!message.endOfBlock())
|
||||
{
|
||||
message.readBlock(); // item
|
||||
const QString name = QString::fromLatin1(message.read<QByteArray>());
|
||||
const InterfaceItemType type = message.read<InterfaceItemType>();
|
||||
switch(type)
|
||||
{
|
||||
case InterfaceItemType::Property:
|
||||
{
|
||||
const PropertyType propertyType = message.read<PropertyType>();
|
||||
QVariant value;
|
||||
switch(propertyType)
|
||||
{
|
||||
case PropertyType::Boolean:
|
||||
value = message.read<bool>();
|
||||
break;
|
||||
|
||||
case PropertyType::Integer:
|
||||
value = message.read<qint64>();
|
||||
break;
|
||||
|
||||
case PropertyType::Float:
|
||||
value = message.read<double>();
|
||||
break;
|
||||
|
||||
case PropertyType::String:
|
||||
value = QString::fromUtf8(message.read<QByteArray>());
|
||||
break;
|
||||
|
||||
case PropertyType::Object:
|
||||
// TODO
|
||||
break;
|
||||
|
||||
case PropertyType::Invalid:
|
||||
break;
|
||||
}
|
||||
|
||||
Q_ASSERT(value.isValid());
|
||||
if(Q_LIKELY(value.isValid()))
|
||||
obj->m_interfaceItems.add(*new Property(*obj, name, propertyType, value));
|
||||
break;
|
||||
}
|
||||
}
|
||||
message.readBlockEnd(); // end item
|
||||
}
|
||||
message.readBlockEnd(); // end items
|
||||
}
|
||||
|
||||
message.readBlockEnd(); // end object
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
TableModelPtr Client::readTableModel(const Message& message)
|
||||
{
|
||||
message.readBlock(); // model
|
||||
const Handle handle = message.read<Handle>();
|
||||
const QString classId = QString::fromLatin1(message.read<QByteArray>());
|
||||
TableModelPtr tableModel = TableModelPtr::create(handle, classId);
|
||||
const int columnCount = message.read<int>();
|
||||
for(int i = 0; i < columnCount; i++)
|
||||
tableModel->m_columnHeaders.push_back(QString::fromUtf8(message.read<QByteArray>()));
|
||||
Q_ASSERT(tableModel->m_columnHeaders.size() == columnCount);
|
||||
message.read(tableModel->m_rowCount);
|
||||
message.readBlockEnd(); // end model
|
||||
return tableModel;
|
||||
}
|
||||
|
||||
void Client::setState(State state)
|
||||
{
|
||||
if(m_state != state)
|
||||
{
|
||||
m_state = state;
|
||||
emit stateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void Client::processMessage(const std::shared_ptr<Message> message)
|
||||
{
|
||||
if(message->isResponse())
|
||||
{
|
||||
auto it = m_requestCallback.find(message->requestId());
|
||||
if(it != m_requestCallback.end())
|
||||
{
|
||||
it.value()(message);
|
||||
m_requestCallback.erase(it);
|
||||
}
|
||||
}
|
||||
else if(message->isEvent())
|
||||
{
|
||||
switch(message->command())
|
||||
{
|
||||
case Message::Command::ObjectPropertyChanged:
|
||||
if(Object* object = m_objects.value(message->read<Handle>(), nullptr))
|
||||
{
|
||||
if(Property* property = object->getProperty(QString::fromLatin1(message->read<QByteArray>())))
|
||||
{
|
||||
switch(message->read<PropertyType>())
|
||||
{
|
||||
case PropertyType::Boolean:
|
||||
{
|
||||
const bool value = message->read<bool>();
|
||||
property->m_value = value;
|
||||
emit property->valueChanged();
|
||||
emit property->valueChangedBool(value);
|
||||
break;
|
||||
}
|
||||
case PropertyType::Integer:
|
||||
break;
|
||||
|
||||
case PropertyType::Float:
|
||||
break;
|
||||
|
||||
case PropertyType::String:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Message::Command::TableModelColumnHeadersChanged:
|
||||
if(TableModel* model = m_tableModels.value(message->read<Handle>(), nullptr))
|
||||
{
|
||||
const int columnCount = message->read<int>();
|
||||
model->m_columnHeaders.clear();
|
||||
for(int i = 0; i < columnCount; i++)
|
||||
model->m_columnHeaders.push_back(QString::fromUtf8(message->read<QByteArray>()));
|
||||
Q_ASSERT(model->m_columnHeaders.size() == columnCount);
|
||||
}
|
||||
break;
|
||||
|
||||
case Message::Command::TableModelRowCountChanged:
|
||||
if(TableModel* model = m_tableModels.value(message->read<Handle>(), nullptr))
|
||||
model->setRowCount(message->read<int>());
|
||||
break;
|
||||
|
||||
case Message::Command::TableModelUpdateRegion:
|
||||
if(TableModel* model = m_tableModels.value(message->read<Handle>(), nullptr))
|
||||
{
|
||||
const uint32_t columnMin = message->read<uint32_t>();
|
||||
const uint32_t columnMax = message->read<uint32_t>();
|
||||
const uint32_t rowMin = message->read<uint32_t>();
|
||||
const uint32_t rowMax = message->read<uint32_t>();
|
||||
|
||||
model->beginResetModel();
|
||||
|
||||
TableModel::ColumnRow index;
|
||||
QByteArray data;
|
||||
for(index.second = rowMin; index.second <= rowMax; index.second++)
|
||||
for(index.first = columnMin; index.first <= columnMax; index.first++)
|
||||
{
|
||||
message->read(data);
|
||||
model->m_texts[index] = QString::fromUtf8(data);
|
||||
}
|
||||
|
||||
model->endResetModel();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::socketConnected()
|
||||
{
|
||||
std::unique_ptr<Message> request{Message::newRequest(Message::Command::Login)};
|
||||
request->write(m_username.toUtf8());
|
||||
request->write(m_password);
|
||||
send(request,
|
||||
[this](const std::shared_ptr<Message> message)
|
||||
{
|
||||
if(message && message->isResponse() && !message->isError())
|
||||
{
|
||||
std::unique_ptr<Message> request{Message::newRequest(Message::Command::NewSession)};
|
||||
send(request,
|
||||
[this](const std::shared_ptr<Message> message)
|
||||
{
|
||||
if(message && message->isResponse() && !message->isError())
|
||||
{
|
||||
message->read(m_sessionUUID);
|
||||
setState(State::Connected);
|
||||
}
|
||||
else
|
||||
{
|
||||
setState(State::ErrorNewSessionFailed);
|
||||
m_socket->disconnectFromHost();
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
setState(State::ErrorAuthenticationFailed);
|
||||
m_socket->disconnectFromHost();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Client::socketDisconnected()
|
||||
{
|
||||
setState(State::Disconnected);
|
||||
}
|
||||
|
||||
void Client::socketError(QAbstractSocket::SocketError)
|
||||
{
|
||||
setState(State::SocketError);
|
||||
}
|
||||
|
||||
void Client::socketReadyRead()
|
||||
{
|
||||
while(m_socket->bytesAvailable() != 0)
|
||||
{
|
||||
if(!m_readBuffer.message) // read header
|
||||
{
|
||||
m_readBuffer.offset += m_socket->read(reinterpret_cast<char*>(&m_readBuffer.header) + m_readBuffer.offset, sizeof(m_readBuffer.header) - m_readBuffer.offset);
|
||||
if(m_readBuffer.offset == sizeof(m_readBuffer.header))
|
||||
{
|
||||
if(m_readBuffer.header.dataSize != 0)
|
||||
m_readBuffer.message = std::make_shared<Message>(m_readBuffer.header);
|
||||
else
|
||||
processMessage(std::make_shared<Message>(m_readBuffer.header));
|
||||
m_readBuffer.offset = 0;
|
||||
}
|
||||
}
|
||||
else // read data
|
||||
{
|
||||
m_readBuffer.offset += m_socket->read(reinterpret_cast<char*>(m_readBuffer.message->data()) + m_readBuffer.offset, m_readBuffer.message->dataSize() - m_readBuffer.offset);
|
||||
if(m_readBuffer.offset == m_readBuffer.message->dataSize())
|
||||
{
|
||||
processMessage(m_readBuffer.message);
|
||||
m_readBuffer.message.reset();
|
||||
m_readBuffer.offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
122
client/src/network/client.hpp
Normale Datei
122
client/src/network/client.hpp
Normale Datei
@ -0,0 +1,122 @@
|
||||
/**
|
||||
* client/src/network/client.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_NETWORK_CLIENT_HPP
|
||||
#define CLIENT_NETWORK_CLIENT_HPP
|
||||
|
||||
#include <QObject>
|
||||
#include <QAbstractSocket>
|
||||
#include <QMap>
|
||||
#include <QUuid>
|
||||
#include <message.hpp>
|
||||
#include "handle.hpp"
|
||||
#include "objectptr.hpp"
|
||||
#include "tablemodelptr.hpp"
|
||||
|
||||
class QTcpSocket;
|
||||
class Property;
|
||||
|
||||
class Client : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class State
|
||||
{
|
||||
Disconnected = 0,
|
||||
Disconnecting = 1,
|
||||
Connected = 2,
|
||||
Connecting = 3,
|
||||
SocketError = 4,
|
||||
ErrorAuthenticationFailed = 5,
|
||||
ErrorNewSessionFailed = 6,
|
||||
};
|
||||
|
||||
using SocketError = QAbstractSocket::SocketError;
|
||||
|
||||
protected:
|
||||
QTcpSocket* m_socket;
|
||||
State m_state;
|
||||
QString m_username;
|
||||
QByteArray m_password;
|
||||
struct
|
||||
{
|
||||
qint64 offset = 0;
|
||||
Message::Header header;
|
||||
std::shared_ptr<Message> message;
|
||||
} m_readBuffer;
|
||||
QMap<uint16_t, std::function<void(const std::shared_ptr<Message>&)>> m_requestCallback;
|
||||
QUuid m_sessionUUID;
|
||||
QMap<Handle, Object*> m_objects;
|
||||
QMap<Handle, TableModel*> m_tableModels;
|
||||
|
||||
void setState(State state);
|
||||
void processMessage(const std::shared_ptr<Message> message);
|
||||
void send(std::unique_ptr<Message>& message);
|
||||
void send(std::unique_ptr<Message>& message, std::function<void(const std::shared_ptr<Message>&)> callback);
|
||||
|
||||
ObjectPtr readObject(const Message &message);
|
||||
TableModelPtr readTableModel(const Message& message);
|
||||
|
||||
protected slots:
|
||||
void socketConnected();
|
||||
void socketDisconnected();
|
||||
void socketError(QAbstractSocket::SocketError);
|
||||
void socketReadyRead();
|
||||
|
||||
public:
|
||||
static const quint16 defaultPort = 5740;
|
||||
static constexpr int invalidRequestId = -1;
|
||||
|
||||
static Client* instance;
|
||||
|
||||
Client();
|
||||
~Client();
|
||||
|
||||
inline bool isConnected() const { return m_state == State::Connected; }
|
||||
bool isDisconnected() const;
|
||||
State state() const { return m_state; }
|
||||
SocketError error() const;
|
||||
QString errorString() const;
|
||||
|
||||
void connectToHost(const QUrl& url, const QString& username, const QString& password);
|
||||
void disconnectFromHost();
|
||||
|
||||
void cancelRequest(int requestId);
|
||||
|
||||
int getObject(const QString& id, std::function<void(const ObjectPtr&, Message::ErrorCode)> callback);
|
||||
void releaseObject(Object* object);
|
||||
|
||||
void setPropertyBool(Property& property, bool value);
|
||||
void setPropertyInt64(Property& property, int64_t value);
|
||||
void setPropertyDouble(Property& property, double value);
|
||||
void setPropertyString(Property& property, const QString& value);
|
||||
|
||||
int getTableModel(const QString& id, std::function<void(const TableModelPtr&, Message::ErrorCode)> callback);
|
||||
void releaseTableModel(TableModel* tableModel);
|
||||
void setTableModelRegion(TableModel* tableModel, int columnMin, int columnMax, int rowMin, int rowMax);
|
||||
|
||||
signals:
|
||||
void stateChanged();
|
||||
};
|
||||
|
||||
#endif
|
||||
32
client/src/network/handle.hpp
Normale Datei
32
client/src/network/handle.hpp
Normale Datei
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* client/src/network/handle.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_NETWORK_HANDLE_HPP
|
||||
#define CLIENT_NETWORK_HANDLE_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
using Handle = uint32_t;
|
||||
|
||||
constexpr Handle invalidHandle = 0;
|
||||
|
||||
#endif
|
||||
30
client/src/network/interfaceitem.cpp
Normale Datei
30
client/src/network/interfaceitem.cpp
Normale Datei
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* client/src/network/interfaceitem.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "interfaceitem.hpp"
|
||||
#include "object.hpp"
|
||||
|
||||
InterfaceItem::InterfaceItem(Object& object, const QString& name) :
|
||||
QObject(&object),
|
||||
m_name{name}
|
||||
{
|
||||
}
|
||||
44
client/src/network/interfaceitem.hpp
Normale Datei
44
client/src/network/interfaceitem.hpp
Normale Datei
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* client/src/network/interfaceitem.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_NETWORK_INTERFACEITEM_HPP
|
||||
#define CLIENT_NETWORK_INTERFACEITEM_HPP
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Object;
|
||||
|
||||
class InterfaceItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
const QString m_name;
|
||||
|
||||
public:
|
||||
explicit InterfaceItem(Object& object, const QString& name);
|
||||
|
||||
const QString& name() const { return m_name; }
|
||||
const QString& displayName() const { return m_name; }
|
||||
};
|
||||
|
||||
#endif
|
||||
29
client/src/network/interfaceitems.cpp
Normale Datei
29
client/src/network/interfaceitems.cpp
Normale Datei
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* client/src/network/interfaceitems.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "interfaceitems.hpp"
|
||||
#include "interfaceitem.hpp"
|
||||
|
||||
void InterfaceItems::add(InterfaceItem& item)
|
||||
{
|
||||
insert(item.name(), &item);
|
||||
}
|
||||
36
client/src/network/interfaceitems.hpp
Normale Datei
36
client/src/network/interfaceitems.hpp
Normale Datei
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* client/src/network/interfaceitems.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_NETWORK_INTERFACEITEMS_HPP
|
||||
#define CLIENT_NETWORK_INTERFACEITEMS_HPP
|
||||
|
||||
#include <QMap>
|
||||
|
||||
class InterfaceItem;
|
||||
|
||||
class InterfaceItems : public QMap<QString, InterfaceItem*>
|
||||
{
|
||||
public:
|
||||
void add(InterfaceItem& item);
|
||||
};
|
||||
|
||||
#endif
|
||||
47
client/src/network/object.cpp
Normale Datei
47
client/src/network/object.cpp
Normale Datei
@ -0,0 +1,47 @@
|
||||
/**
|
||||
* client/src/network/object.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "object.hpp"
|
||||
#include "client.hpp"
|
||||
#include "property.hpp"
|
||||
|
||||
Object::Object(Handle handle, const QString& classId) :
|
||||
QObject(nullptr),
|
||||
m_handle{handle},
|
||||
m_classId{classId}
|
||||
{
|
||||
}
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
Client::instance->releaseObject(this);
|
||||
}
|
||||
|
||||
const Property* Object::getProperty(const QString& name) const
|
||||
{
|
||||
return dynamic_cast<Property*>(m_interfaceItems.value(name, nullptr));
|
||||
}
|
||||
|
||||
Property* Object::getProperty(const QString& name)
|
||||
{
|
||||
return dynamic_cast<Property*>(m_interfaceItems.value(name, nullptr));
|
||||
}
|
||||
59
client/src/network/object.hpp
Normale Datei
59
client/src/network/object.hpp
Normale Datei
@ -0,0 +1,59 @@
|
||||
/**
|
||||
* client/src/network/object.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_NETWORK_OBJECT_HPP
|
||||
#define CLIENT_NETWORK_OBJECT_HPP
|
||||
|
||||
#include <QObject>
|
||||
#include "handle.hpp"
|
||||
#include "interfaceitems.hpp"
|
||||
|
||||
class Property;
|
||||
|
||||
class Object : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class Client;
|
||||
|
||||
protected:
|
||||
Handle m_handle;
|
||||
const QString m_classId;
|
||||
InterfaceItems m_interfaceItems;
|
||||
|
||||
public:
|
||||
explicit Object(Handle handle, const QString& classId);
|
||||
Object(const Object& copy) = delete;
|
||||
~Object() final;
|
||||
|
||||
Handle handle() const { return m_handle; }
|
||||
|
||||
const QString& classId() const { return m_classId; }
|
||||
|
||||
const InterfaceItems& interfaceItems() const { return m_interfaceItems; }
|
||||
|
||||
const Property* getProperty(const QString& name) const;
|
||||
Property* getProperty(const QString& name);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
32
client/src/network/objectptr.hpp
Normale Datei
32
client/src/network/objectptr.hpp
Normale Datei
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* client/src/network/objectptr.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_NETWORK_OBJECTPTR_HPP
|
||||
#define CLIENT_NETWORK_OBJECTPTR_HPP
|
||||
|
||||
#include <QSharedPointer>
|
||||
|
||||
class Object;
|
||||
|
||||
using ObjectPtr = QSharedPointer<Object>;
|
||||
|
||||
#endif
|
||||
51
client/src/network/property.cpp
Normale Datei
51
client/src/network/property.cpp
Normale Datei
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* client/src/network/property.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "property.hpp"
|
||||
#include "client.hpp"
|
||||
|
||||
Property::Property(Object& object, const QString& name, PropertyType type, const QVariant& value) :
|
||||
InterfaceItem(object, name),
|
||||
m_type{type},
|
||||
m_value{value}
|
||||
{
|
||||
}
|
||||
|
||||
void Property::setValueBool(bool value)
|
||||
{
|
||||
Client::instance->setPropertyBool(*this, value);
|
||||
}
|
||||
|
||||
void Property::setValueInt64(int64_t value)
|
||||
{
|
||||
Client::instance->setPropertyInt64(*this, value);
|
||||
}
|
||||
|
||||
void Property::setValueDouble(double value)
|
||||
{
|
||||
Client::instance->setPropertyDouble(*this, value);
|
||||
}
|
||||
|
||||
void Property::setValueString(const QString& value)
|
||||
{
|
||||
Client::instance->setPropertyString(*this, value);
|
||||
}
|
||||
68
client/src/network/property.hpp
Normale Datei
68
client/src/network/property.hpp
Normale Datei
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* client/src/network/property.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_NETWORK_PROPERTY_HPP
|
||||
#define CLIENT_NETWORK_PROPERTY_HPP
|
||||
|
||||
#include "interfaceitem.hpp"
|
||||
#include <QVariant>
|
||||
#include <enum/propertytype.hpp>
|
||||
//#include "objectptr.hpp"
|
||||
|
||||
class Object;
|
||||
|
||||
class Property : public InterfaceItem
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class Client;
|
||||
|
||||
protected:
|
||||
const PropertyType m_type;
|
||||
QVariant m_value;
|
||||
|
||||
public:
|
||||
explicit Property(Object& object, const QString& name, PropertyType type, const QVariant& value);
|
||||
|
||||
PropertyType type() const { return m_type; }
|
||||
|
||||
bool toBool() const { return m_value.toBool(); }
|
||||
int64_t toInt64() const { return m_value.toLongLong(); }
|
||||
double toDouble() const { return m_value.toDouble(); }
|
||||
QString toString() const { return m_value.toString(); }
|
||||
QVariant toVariant() const { return m_value; }
|
||||
|
||||
signals:
|
||||
void valueChanged();
|
||||
void valueChangedBool(bool newValue);
|
||||
void valueChangedInt64(int64_t newValue);
|
||||
void valueChangedDouble(double newValue);
|
||||
void valueChangedString(const QString& newValue);
|
||||
|
||||
public slots:
|
||||
void setValueBool(bool value);
|
||||
void setValueInt64(int64_t value);
|
||||
void setValueDouble(double value);
|
||||
void setValueString(const QString& value);
|
||||
};
|
||||
|
||||
#endif
|
||||
94
client/src/network/tablemodel.cpp
Normale Datei
94
client/src/network/tablemodel.cpp
Normale Datei
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* client/src/network/tablemodel.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "tablemodel.hpp"
|
||||
#include "client.hpp"
|
||||
|
||||
TableModel::TableModel(Handle handle, const QString& classId, QObject* parent) :
|
||||
QAbstractTableModel(parent),
|
||||
m_handle{handle},
|
||||
m_classId{classId},
|
||||
m_rowCount{0}
|
||||
{
|
||||
}
|
||||
|
||||
TableModel::~TableModel()
|
||||
{
|
||||
Client::instance->releaseTableModel(this);
|
||||
}
|
||||
|
||||
QVariant TableModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if(role == Qt::DisplayRole)
|
||||
{
|
||||
if(orientation == Qt::Vertical)
|
||||
return QString::number(1 + section);
|
||||
else if(orientation == Qt::Horizontal)
|
||||
return m_columnHeaders[section];
|
||||
}
|
||||
|
||||
return QAbstractTableModel::headerData(section, orientation, role);
|
||||
}
|
||||
|
||||
QVariant TableModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if(role == Qt::DisplayRole)
|
||||
return m_texts.value(ColumnRow(index.column(), index.row()));
|
||||
|
||||
return QVariant{};
|
||||
}
|
||||
|
||||
void TableModel::setRegion(int columnMin, int columnMax, int rowMin, int rowMax)
|
||||
{
|
||||
if(m_region.columnMin != columnMin ||
|
||||
m_region.columnMax != columnMax ||
|
||||
m_region.rowMin != rowMin ||
|
||||
m_region.rowMax != rowMax)
|
||||
{
|
||||
m_region.columnMin = columnMin;
|
||||
m_region.columnMax = columnMax;
|
||||
m_region.rowMin = rowMin;
|
||||
m_region.rowMax = rowMax;
|
||||
|
||||
Client::instance->setTableModelRegion(this, m_region.columnMin, m_region.columnMax, m_region.rowMin, m_region.rowMax);
|
||||
}
|
||||
}
|
||||
|
||||
void TableModel::setColumnHeaders(const QVector<QString>& values)
|
||||
{
|
||||
if(m_columnHeaders != values)
|
||||
{
|
||||
beginResetModel();
|
||||
m_columnHeaders = values;
|
||||
endResetModel();
|
||||
}
|
||||
}
|
||||
|
||||
void TableModel::setRowCount(int value)
|
||||
{
|
||||
if(m_rowCount != value)
|
||||
{
|
||||
beginResetModel();
|
||||
m_rowCount = value;
|
||||
endResetModel();
|
||||
}
|
||||
}
|
||||
69
client/src/network/tablemodel.hpp
Normale Datei
69
client/src/network/tablemodel.hpp
Normale Datei
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* client/src/network/tablemodel.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_NETWORK_TABLEMODEL_HPP
|
||||
#define CLIENT_NETWORK_TABLEMODEL_HPP
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include "handle.hpp"
|
||||
|
||||
class TableModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class Client;
|
||||
|
||||
protected:
|
||||
using ColumnRow = std::pair<uint32_t, uint32_t>;
|
||||
|
||||
Handle m_handle;
|
||||
const QString m_classId;
|
||||
QVector<QString> m_columnHeaders;
|
||||
int m_rowCount;
|
||||
struct Region
|
||||
{
|
||||
int rowMin = 0;
|
||||
int rowMax = -1;
|
||||
int columnMin = 0;
|
||||
int columnMax = -1;
|
||||
} m_region;
|
||||
QMap<ColumnRow, QString> m_texts;
|
||||
|
||||
void setColumnHeaders(const QVector<QString>& values);
|
||||
void setRowCount(int value);
|
||||
|
||||
public:
|
||||
explicit TableModel(Handle handle, const QString& classId, QObject* parent = nullptr);
|
||||
~TableModel() final;
|
||||
|
||||
Handle handle() const { return m_handle; }
|
||||
|
||||
int columnCount(const QModelIndex& parent = QModelIndex()) const final { Q_UNUSED(parent); return m_columnHeaders.size(); }
|
||||
int rowCount(const QModelIndex& parent = QModelIndex()) const final { Q_UNUSED(parent); return m_rowCount; }
|
||||
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const final;
|
||||
QVariant data(const QModelIndex& index, int role) const final;
|
||||
|
||||
void setRegion(int columnMin, int columnMax, int rowMin, int rowMax);
|
||||
};
|
||||
|
||||
#endif
|
||||
32
client/src/network/tablemodelptr.hpp
Normale Datei
32
client/src/network/tablemodelptr.hpp
Normale Datei
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* client/src/network/tablemodelptr.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_NETWORK_TABLEMODELPTR_HPP
|
||||
#define CLIENT_NETWORK_TABLEMODELPTR_HPP
|
||||
|
||||
#include <QSharedPointer>
|
||||
|
||||
class TableModel;
|
||||
|
||||
using TableModelPtr = QSharedPointer<TableModel>;
|
||||
|
||||
#endif
|
||||
42
client/src/network/utils.cpp
Normale Datei
42
client/src/network/utils.cpp
Normale Datei
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* client/src/network/utils.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "utils.hpp"
|
||||
|
||||
QString errorCodeToText(Message::ErrorCode ec)
|
||||
{
|
||||
using ErrorCode = Message::ErrorCode;
|
||||
|
||||
Q_ASSERT(ec != ErrorCode::None);
|
||||
|
||||
QString text;
|
||||
switch(ec)
|
||||
{
|
||||
case ErrorCode::UnknownObject:
|
||||
text = "Unknown object";
|
||||
break;
|
||||
|
||||
case ErrorCode::None:
|
||||
break; // silence warning
|
||||
}
|
||||
return QString("Error %1: %2").arg(static_cast<int>(ec)).arg(text);
|
||||
}
|
||||
30
client/src/network/utils.hpp
Normale Datei
30
client/src/network/utils.hpp
Normale Datei
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* client/src/network/utils.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_NETWORK_UTILS_HPP
|
||||
#define CLIENT_NETWORK_UTILS_HPP
|
||||
|
||||
#include <message.hpp>
|
||||
|
||||
QString errorCodeToText(Message::ErrorCode ec);
|
||||
|
||||
#endif // UTILS_HPP
|
||||
50
client/src/subwindow/hardwarelistsubwindow.cpp
Normale Datei
50
client/src/subwindow/hardwarelistsubwindow.cpp
Normale Datei
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* client/src/subwindow/hardwarelistsubwindow.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "hardwarelistsubwindow.hpp"
|
||||
#include <QSettings>
|
||||
#include "../widget/hardwarewidget.hpp"
|
||||
|
||||
#define SETTING_PREFIX "hardwarelistsubwindow/"
|
||||
#define SETTING_GEOMETRY SETTING_PREFIX "geometry"
|
||||
#define SETTING_WINDOWSTATE SETTING_PREFIX "windowstate"
|
||||
|
||||
HardwareListSubWindow::HardwareListSubWindow(QWidget* parent) :
|
||||
QMdiSubWindow(parent)
|
||||
{
|
||||
setWindowTitle(tr("Hardware"));
|
||||
setWidget(new HardwareWidget(this));
|
||||
|
||||
QSettings settings;
|
||||
if(settings.contains(SETTING_GEOMETRY))
|
||||
restoreGeometry(settings.value(SETTING_GEOMETRY).toByteArray());
|
||||
if(settings.contains(SETTING_WINDOWSTATE))
|
||||
setWindowState(static_cast<Qt::WindowState>(settings.value(SETTING_WINDOWSTATE).toInt()));
|
||||
}
|
||||
|
||||
void HardwareListSubWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
QSettings settings;
|
||||
settings.setValue(SETTING_GEOMETRY, saveGeometry());
|
||||
settings.setValue(SETTING_WINDOWSTATE, static_cast<int>(windowState()));
|
||||
QMdiSubWindow::closeEvent(event);
|
||||
}
|
||||
39
client/src/subwindow/hardwarelistsubwindow.hpp
Normale Datei
39
client/src/subwindow/hardwarelistsubwindow.hpp
Normale Datei
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* client/src/subwindow/hardwarelistsubwindow.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_SUBWINDOW_HARDWARELISTSUBWINDOW_HPP
|
||||
#define CLIENT_SUBWINDOW_HARDWARELISTSUBWINDOW_HPP
|
||||
|
||||
#include <QMdiSubWindow>
|
||||
|
||||
class HardwareListSubWindow : public QMdiSubWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event) final;
|
||||
|
||||
public:
|
||||
HardwareListSubWindow(QWidget* parent = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
31
client/src/subwindow/serverconsolesubwindow.cpp
Normale Datei
31
client/src/subwindow/serverconsolesubwindow.cpp
Normale Datei
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* client/src/subwindow/serversettingssubwindow.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "serversettingssubwindow.hpp"
|
||||
#include "../widget/serversettingswidget.hpp"
|
||||
|
||||
ServerSettingsSubWindow::ServerSettingsSubWindow(QWidget* parent) :
|
||||
QMdiSubWindow(parent)
|
||||
{
|
||||
setWindowTitle(tr("Server settings"));
|
||||
setWidget(new ServerSettingsWidget(this));
|
||||
}
|
||||
40
client/src/subwindow/serverconsolesubwindow.hpp
Normale Datei
40
client/src/subwindow/serverconsolesubwindow.hpp
Normale Datei
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* client/src/subwindow/serverconsolesubwindow.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_SUBWINDOW_SERVERCONSOLESUBWINDOW_HPP
|
||||
#define CLIENT_SUBWINDOW_SERVERCONSOLESUBWINDOW_HPP
|
||||
|
||||
#include <QMdiSubWindow>
|
||||
|
||||
class ServerConsoleSubWindow : public QMdiSubWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent*) final;
|
||||
|
||||
public:
|
||||
ServerConsoleSubWindow(QWidget* parent = nullptr);
|
||||
//~ServerConsoleSubWindow() final;
|
||||
};
|
||||
|
||||
#endif
|
||||
35
client/src/subwindow/serversettingssubwindow.cpp
Normale Datei
35
client/src/subwindow/serversettingssubwindow.cpp
Normale Datei
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* client/src/subwindow/serverconsolesubwindow.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "serverconsolesubwindow.hpp"
|
||||
#include "../widget/serverconsolewidget.hpp"
|
||||
|
||||
ServerConsoleSubWindow::ServerConsoleSubWindow(QWidget* parent) :
|
||||
QMdiSubWindow(parent)
|
||||
{
|
||||
setWindowTitle(tr("Server console"));
|
||||
setWidget(new ServerConsoleWidget(this));
|
||||
}
|
||||
|
||||
void ServerConsoleSubWindow::closeEvent(QCloseEvent*)
|
||||
{
|
||||
}
|
||||
36
client/src/subwindow/serversettingssubwindow.hpp
Normale Datei
36
client/src/subwindow/serversettingssubwindow.hpp
Normale Datei
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* client/src/subwindow/serverconsolesubwindow.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_SUBWINDOW_SERVERSETTINGSSUBWINDOW_HPP
|
||||
#define CLIENT_SUBWINDOW_SERVERSETTINGSSUBWINDOW_HPP
|
||||
|
||||
#include <QMdiSubWindow>
|
||||
|
||||
class ServerSettingsSubWindow : public QMdiSubWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ServerSettingsSubWindow(QWidget* parent = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
91
client/src/widget/alertwidget.cpp
Normale Datei
91
client/src/widget/alertwidget.cpp
Normale Datei
@ -0,0 +1,91 @@
|
||||
/**
|
||||
* client/src/widget/alertwidget.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "alertwidget.hpp"
|
||||
#include <QPainter>
|
||||
|
||||
AlertWidget* AlertWidget::error(const QString& text, QWidget* parent)
|
||||
{
|
||||
AlertWidget* w = new AlertWidget(parent);
|
||||
w->setType(Type::Error);
|
||||
w->setText(text);
|
||||
return w;
|
||||
}
|
||||
|
||||
AlertWidget::AlertWidget(QWidget* parent) :
|
||||
QWidget(parent),
|
||||
m_type{Type::Error}
|
||||
{
|
||||
setMinimumWidth(100);
|
||||
setMinimumHeight(qRound(fontMetrics().height() * 1.25));
|
||||
|
||||
updateColors();
|
||||
}
|
||||
|
||||
void AlertWidget::setType(Type value)
|
||||
{
|
||||
if(m_type != value)
|
||||
{
|
||||
m_type = value;
|
||||
updateColors();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void AlertWidget::setText(const QString& value)
|
||||
{
|
||||
if(m_text != value)
|
||||
{
|
||||
m_text = value;
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
void AlertWidget::paintEvent(QPaintEvent*)
|
||||
{
|
||||
const qreal radius = 7;
|
||||
const int textMargin = 5;
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
QPainterPath path;
|
||||
path.addRoundedRect(rect(), radius, radius);
|
||||
painter.fillPath(path, m_backgroundColor);
|
||||
painter.setPen(m_borderColor);
|
||||
painter.drawPath(path);
|
||||
|
||||
painter.setPen(m_textColor);
|
||||
painter.drawText(rect().adjusted(textMargin, 0, -textMargin, 0), Qt::AlignLeft | Qt::AlignVCenter, m_text);
|
||||
}
|
||||
|
||||
void AlertWidget::updateColors()
|
||||
{
|
||||
switch(m_type)
|
||||
{
|
||||
case Type::Error:
|
||||
m_borderColor = Qt::red;
|
||||
m_backgroundColor = Qt::gray;
|
||||
m_textColor = Qt::red;
|
||||
break;
|
||||
}
|
||||
}
|
||||
60
client/src/widget/alertwidget.hpp
Normale Datei
60
client/src/widget/alertwidget.hpp
Normale Datei
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* client/src/widget/alertwidget.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_WIDGET_ALERTWIDGET_HPP
|
||||
#define CLIENT_WIDGET_ALERTWIDGET_HPP
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class AlertWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum class Type
|
||||
{
|
||||
Error,
|
||||
};
|
||||
|
||||
protected:
|
||||
Type m_type;
|
||||
QString m_text;
|
||||
QColor m_backgroundColor;
|
||||
QColor m_borderColor;
|
||||
QColor m_textColor;
|
||||
|
||||
void paintEvent(QPaintEvent* event) final;
|
||||
void updateColors();
|
||||
|
||||
public:
|
||||
static AlertWidget* error(const QString& text, QWidget* parent = nullptr);
|
||||
|
||||
AlertWidget(QWidget* parent = nullptr);
|
||||
|
||||
Type type() const { return m_type; }
|
||||
void setType(Type value);
|
||||
|
||||
const QString& text() const { return m_text; }
|
||||
void setText(const QString& value);
|
||||
};
|
||||
|
||||
#endif
|
||||
31
client/src/widget/commandstationlistwidget.cpp
Normale Datei
31
client/src/widget/commandstationlistwidget.cpp
Normale Datei
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* client/src/widget/commandstationlistwidget.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "commandstationlistwidget.hpp"
|
||||
|
||||
CommandStationListWidget::CommandStationListWidget(const QString& id, QWidget* parent) :
|
||||
ObjectListWidget(id, parent)
|
||||
{
|
||||
addActionAdd();
|
||||
addActionEdit();
|
||||
addActionDelete();
|
||||
}
|
||||
36
client/src/widget/commandstationlistwidget.hpp
Normale Datei
36
client/src/widget/commandstationlistwidget.hpp
Normale Datei
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* client/src/widget/commandstationlistwidget.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_WIDGET_COMMANDSTATIONLISTWIDGET_HPP
|
||||
#define CLIENT_WIDGET_COMMANDSTATIONLISTWIDGET_HPP
|
||||
|
||||
#include "objectlistwidget.hpp"
|
||||
|
||||
class CommandStationListWidget : public ObjectListWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
CommandStationListWidget(const QString& id, QWidget* parent = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
28
client/src/widget/decoderlistwidget.cpp
Normale Datei
28
client/src/widget/decoderlistwidget.cpp
Normale Datei
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* client/src/widget/decoderlistwidget.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "decoderlistwidget.hpp"
|
||||
|
||||
DecoderListWidget::DecoderListWidget(const QString& id, QWidget* parent) :
|
||||
ObjectListWidget(id, parent)
|
||||
{
|
||||
}
|
||||
36
client/src/widget/decoderlistwidget.hpp
Normale Datei
36
client/src/widget/decoderlistwidget.hpp
Normale Datei
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* client/src/widget/decoderlistwidget.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_WIDGET_DECODERLISTWIDGET_HPP
|
||||
#define CLIENT_WIDGET_DECODERLISTWIDGET_HPP
|
||||
|
||||
#include "objectlistwidget.hpp"
|
||||
|
||||
class DecoderListWidget : public ObjectListWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DecoderListWidget(const QString& id, QWidget* parent = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
32
client/src/widget/hardwarewidget.cpp
Normale Datei
32
client/src/widget/hardwarewidget.cpp
Normale Datei
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* client/src/widget/hardwarewidget.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "hardwarewidget.hpp"
|
||||
#include "commandstationlistwidget.hpp"
|
||||
#include "decoderlistwidget.hpp"
|
||||
|
||||
HardwareWidget::HardwareWidget(QWidget* parent) :
|
||||
QTabWidget(parent)
|
||||
{
|
||||
addTab(new CommandStationListWidget("command_station_list", this), tr("Command stations"));
|
||||
addTab(new DecoderListWidget("decoder_list", this), tr("Decoders"));
|
||||
}
|
||||
36
client/src/widget/hardwarewidget.hpp
Normale Datei
36
client/src/widget/hardwarewidget.hpp
Normale Datei
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* client/src/widget/hardwarewidget.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_WIDGET_HARDWAREWIDGET_HPP
|
||||
#define CLIENT_WIDGET_HARDWAREWIDGET_HPP
|
||||
|
||||
#include <QTabWidget>
|
||||
|
||||
class HardwareWidget : public QTabWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
HardwareWidget(QWidget* parent = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
76
client/src/widget/objecteditwidget.cpp
Normale Datei
76
client/src/widget/objecteditwidget.cpp
Normale Datei
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* client/src/widget/objecteditwidget.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "objecteditwidget.hpp"
|
||||
#include <QFormLayout>
|
||||
#include <QtWaitingSpinner/waitingspinnerwidget.h>
|
||||
#include "../network/client.hpp"
|
||||
#include "../network/object.hpp"
|
||||
#include "../network/property.hpp"
|
||||
#include "../network/utils.hpp"
|
||||
#include "../widget/alertwidget.hpp"
|
||||
#include "../widget/propertycheckbox.hpp"
|
||||
|
||||
ObjectEditWidget::ObjectEditWidget(const QString& id, QWidget* parent) :
|
||||
QWidget(parent),
|
||||
m_id{id}
|
||||
{
|
||||
setLayout(new QFormLayout());
|
||||
|
||||
auto* spinner = new WaitingSpinnerWidget(this, true, false);
|
||||
spinner->start();
|
||||
|
||||
m_requestId = Client::instance->getObject(m_id,
|
||||
[this, spinner](const ObjectPtr& object, Message::ErrorCode ec)
|
||||
{
|
||||
m_requestId = Client::invalidRequestId;
|
||||
if(object)
|
||||
{
|
||||
m_object = object;
|
||||
buildForm();
|
||||
}
|
||||
else
|
||||
static_cast<QFormLayout*>(this->layout())->addRow(AlertWidget::error(errorCodeToText(ec)));
|
||||
delete spinner;
|
||||
});
|
||||
}
|
||||
|
||||
ObjectEditWidget::~ObjectEditWidget()
|
||||
{
|
||||
Client::instance->cancelRequest(m_requestId);
|
||||
}
|
||||
|
||||
void ObjectEditWidget::buildForm()
|
||||
{
|
||||
QFormLayout* l = static_cast<QFormLayout*>(this->layout());
|
||||
|
||||
for(auto item : m_object->interfaceItems())
|
||||
if(Property* property = dynamic_cast<Property*>(item))
|
||||
{
|
||||
QWidget* w = nullptr;
|
||||
|
||||
if(property->type() == PropertyType::Boolean)
|
||||
w = new PropertyCheckBox(*property);
|
||||
|
||||
l->addRow(property->displayName(), w);
|
||||
}
|
||||
}
|
||||
45
client/src/widget/objecteditwidget.hpp
Normale Datei
45
client/src/widget/objecteditwidget.hpp
Normale Datei
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* client/src/widget/objecteditwidget.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_WIDGET_OBJECTEDITWIDGET_HPP
|
||||
#define CLIENT_WIDGET_OBJECTEDITWIDGET_HPP
|
||||
|
||||
#include <QWidget>
|
||||
#include "../network/objectptr.hpp"
|
||||
|
||||
class ObjectEditWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
const QString m_id;
|
||||
int m_requestId;
|
||||
ObjectPtr m_object;
|
||||
|
||||
virtual void buildForm();
|
||||
|
||||
public:
|
||||
explicit ObjectEditWidget(const QString& id, QWidget* parent = nullptr);
|
||||
~ObjectEditWidget() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
109
client/src/widget/objectlistwidget.cpp
Normale Datei
109
client/src/widget/objectlistwidget.cpp
Normale Datei
@ -0,0 +1,109 @@
|
||||
/**
|
||||
* client/src/widget/objectlistwidget.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "objectlistwidget.hpp"
|
||||
#include <QVBoxLayout>
|
||||
#include <QToolBar>
|
||||
#include <QTableView>
|
||||
#include <QtWaitingSpinner/waitingspinnerwidget.h>
|
||||
#include "tablewidget.hpp"
|
||||
#include "../network/client.hpp"
|
||||
//#include "../network/object.hpp"
|
||||
#include "../network/tablemodel.hpp"
|
||||
#include "../network/utils.hpp"
|
||||
#include "../widget/alertwidget.hpp"
|
||||
|
||||
ObjectListWidget::ObjectListWidget(const QString& id, QWidget* parent) :
|
||||
QWidget(parent),
|
||||
m_id{id},
|
||||
m_toolbar{new QToolBar()},
|
||||
m_actionAdd{nullptr},
|
||||
m_actionEdit{nullptr},
|
||||
m_actionDelete{nullptr},
|
||||
m_tableWidget{new TableWidget()}
|
||||
{
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->setMargin(0);
|
||||
layout->addWidget(m_toolbar);
|
||||
layout->addWidget(m_tableWidget);
|
||||
setLayout(layout);
|
||||
|
||||
auto* spinner = new WaitingSpinnerWidget(this, true, false);
|
||||
spinner->start();
|
||||
|
||||
m_requestId = Client::instance->getObject(m_id,
|
||||
[this, spinner](const ObjectPtr& object, Message::ErrorCode ec)
|
||||
{
|
||||
m_requestId = Client::invalidRequestId;
|
||||
if(object)
|
||||
{
|
||||
m_object = object;
|
||||
|
||||
m_requestId = Client::instance->getTableModel(m_id,
|
||||
[this, spinner](const TableModelPtr& tableModel, Message::ErrorCode ec)
|
||||
{
|
||||
if(tableModel)
|
||||
{
|
||||
m_requestId = Client::invalidRequestId;
|
||||
|
||||
m_tableWidget->setTableModel(tableModel);
|
||||
|
||||
delete spinner;
|
||||
}
|
||||
else
|
||||
static_cast<QVBoxLayout*>(this->layout())->insertWidget(0, AlertWidget::error(errorCodeToText(ec)));
|
||||
});
|
||||
}
|
||||
else
|
||||
static_cast<QVBoxLayout*>(this->layout())->insertWidget(0, AlertWidget::error(errorCodeToText(ec)));
|
||||
});
|
||||
}
|
||||
|
||||
ObjectListWidget::~ObjectListWidget()
|
||||
{
|
||||
Client::instance->cancelRequest(m_requestId);
|
||||
}
|
||||
|
||||
void ObjectListWidget::addActionAdd()
|
||||
{
|
||||
Q_ASSERT(!m_actionAdd);
|
||||
m_actionAdd = m_toolbar->addAction(tr("Add"));
|
||||
}
|
||||
|
||||
void ObjectListWidget::addActionEdit()
|
||||
{
|
||||
Q_ASSERT(!m_actionEdit);
|
||||
m_actionEdit = m_toolbar->addAction(tr("Edit"));
|
||||
m_actionEdit->setEnabled(false);
|
||||
}
|
||||
|
||||
void ObjectListWidget::addActionDelete()
|
||||
{
|
||||
Q_ASSERT(!m_actionDelete);
|
||||
m_actionDelete = m_toolbar->addAction(tr("Delete"));
|
||||
m_actionDelete->setEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
55
client/src/widget/objectlistwidget.hpp
Normale Datei
55
client/src/widget/objectlistwidget.hpp
Normale Datei
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* client/src/widget/objectlistwidget.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_WIDGET_OBJECTLISTWIDGET_HPP
|
||||
#define CLIENT_WIDGET_OBJECTLISTWIDGET_HPP
|
||||
|
||||
#include <QWidget>
|
||||
#include "../network/objectptr.hpp"
|
||||
|
||||
class QToolBar;
|
||||
class TableWidget;
|
||||
|
||||
class ObjectListWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
const QString m_id;
|
||||
int m_requestId;
|
||||
ObjectPtr m_object;
|
||||
QToolBar* m_toolbar;
|
||||
QAction* m_actionAdd;
|
||||
QAction* m_actionEdit;
|
||||
QAction* m_actionDelete;
|
||||
TableWidget* m_tableWidget;
|
||||
|
||||
void addActionAdd();
|
||||
void addActionEdit();
|
||||
void addActionDelete();
|
||||
|
||||
public:
|
||||
explicit ObjectListWidget(const QString& id, QWidget* parent = nullptr);
|
||||
~ObjectListWidget() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
34
client/src/widget/propertycheckbox.cpp
Normale Datei
34
client/src/widget/propertycheckbox.cpp
Normale Datei
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* client/src/widget/propertycheckbox.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "propertycheckbox.hpp"
|
||||
#include "../network/property.hpp"
|
||||
|
||||
PropertyCheckBox::PropertyCheckBox(Property& property, QWidget* parent) :
|
||||
QCheckBox(parent),
|
||||
m_property{property}
|
||||
{
|
||||
Q_ASSERT(m_property.type() == PropertyType::Boolean);
|
||||
setChecked(m_property.toBool());
|
||||
connect(&m_property, &Property::valueChangedBool, this, &PropertyCheckBox::setChecked);
|
||||
connect(this, &PropertyCheckBox::toggled, &m_property, &Property::setValueBool);
|
||||
}
|
||||
39
client/src/widget/propertycheckbox.hpp
Normale Datei
39
client/src/widget/propertycheckbox.hpp
Normale Datei
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* client/src/widget/propertycheckbox.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_WIDGET_PROPERTYCHECKBOX_HPP
|
||||
#define CLIENT_WIDGET_PROPERTYCHECKBOX_HPP
|
||||
|
||||
#include <QCheckBox>
|
||||
|
||||
class Property;
|
||||
|
||||
class PropertyCheckBox : public QCheckBox
|
||||
{
|
||||
protected:
|
||||
Property& m_property;
|
||||
|
||||
public:
|
||||
PropertyCheckBox(Property& property, QWidget* parent = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
79
client/src/widget/serverconsolewidget.cpp
Normale Datei
79
client/src/widget/serverconsolewidget.cpp
Normale Datei
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* client/src/widget/serverconsolewidget.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "serverconsolewidget.hpp"
|
||||
#include <QVBoxLayout>
|
||||
//#include <QToolBar>
|
||||
#include <QTableView>
|
||||
#include <QtWaitingSpinner/waitingspinnerwidget.h>
|
||||
#include "tablewidget.hpp"
|
||||
#include "../network/client.hpp"
|
||||
//#include "../network/object.hpp"
|
||||
#include "../network/tablemodel.hpp"
|
||||
#include "../network/utils.hpp"
|
||||
#include "../widget/alertwidget.hpp"
|
||||
|
||||
ServerConsoleWidget::ServerConsoleWidget(QWidget* parent) :
|
||||
QWidget(parent),
|
||||
m_tableWidget{new TableWidget()}
|
||||
{
|
||||
QVBoxLayout* layout = new QVBoxLayout();
|
||||
layout->setMargin(0);
|
||||
//layout->addWidget(new QToolBar());
|
||||
layout->addWidget(m_tableWidget);
|
||||
setLayout(layout);
|
||||
|
||||
auto* spinner = new WaitingSpinnerWidget(this, true, false);
|
||||
spinner->start();
|
||||
|
||||
m_requestId = Client::instance->getObject(objectId,
|
||||
[this, spinner](const ObjectPtr& object, Message::ErrorCode ec)
|
||||
{
|
||||
m_requestId = Client::invalidRequestId;
|
||||
if(object)
|
||||
{
|
||||
m_object = object;
|
||||
|
||||
m_requestId = Client::instance->getTableModel(objectId,
|
||||
[this, spinner](const TableModelPtr& tableModel, Message::ErrorCode ec)
|
||||
{
|
||||
if(tableModel)
|
||||
{
|
||||
m_requestId = Client::invalidRequestId;
|
||||
|
||||
m_tableWidget->setTableModel(tableModel);
|
||||
|
||||
delete spinner;
|
||||
}
|
||||
else
|
||||
static_cast<QVBoxLayout*>(this->layout())->insertWidget(0, AlertWidget::error(errorCodeToText(ec)));
|
||||
});
|
||||
}
|
||||
else
|
||||
static_cast<QVBoxLayout*>(this->layout())->insertWidget(0, AlertWidget::error(errorCodeToText(ec)));
|
||||
});
|
||||
}
|
||||
|
||||
ServerConsoleWidget::~ServerConsoleWidget()
|
||||
{
|
||||
Client::instance->cancelRequest(m_requestId);
|
||||
}
|
||||
46
client/src/widget/serverconsolewidget.hpp
Normale Datei
46
client/src/widget/serverconsolewidget.hpp
Normale Datei
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* client/src/widget/serverconsolewidget.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_WIDGET_SERVERCONSOLEWIDGET_HPP
|
||||
#define CLIENT_WIDGET_SERVERCONSOLEWIDGET_HPP
|
||||
|
||||
#include <QWidget>
|
||||
#include "../network/objectptr.hpp"
|
||||
#include "../network/tablemodelptr.hpp"
|
||||
|
||||
class TableWidget;
|
||||
|
||||
class ServerConsoleWidget : public QWidget
|
||||
{
|
||||
protected:
|
||||
static constexpr char const* objectId = "console";
|
||||
|
||||
int m_requestId;
|
||||
ObjectPtr m_object;
|
||||
TableWidget* m_tableWidget;
|
||||
|
||||
public:
|
||||
ServerConsoleWidget(QWidget* parent = nullptr);
|
||||
~ServerConsoleWidget() final;
|
||||
};
|
||||
|
||||
#endif
|
||||
28
client/src/widget/serversettingswidget.cpp
Normale Datei
28
client/src/widget/serversettingswidget.cpp
Normale Datei
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* client/src/widget/serversettingswidget.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "serversettingswidget.hpp"
|
||||
|
||||
ServerSettingsWidget::ServerSettingsWidget(QWidget* parent) :
|
||||
ObjectEditWidget("settings", parent)
|
||||
{
|
||||
}
|
||||
36
client/src/widget/serversettingswidget.hpp
Normale Datei
36
client/src/widget/serversettingswidget.hpp
Normale Datei
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* client/src/widget/serversettingswidget.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_WIDGET_SERVERSETTINGSWIDGET_HPP
|
||||
#define CLIENT_WIDGET_SERVERSETTINGSWIDGET_HPP
|
||||
|
||||
#include "objecteditwidget.hpp"
|
||||
|
||||
class ServerSettingsWidget : public ObjectEditWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ServerSettingsWidget(QWidget* parent = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
79
client/src/widget/tablewidget.cpp
Normale Datei
79
client/src/widget/tablewidget.cpp
Normale Datei
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* client/src/widget/tablewidget.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "tablewidget.hpp"
|
||||
#include <QHeaderView>
|
||||
#include <QScrollBar>
|
||||
#include "../network/tablemodel.hpp"
|
||||
|
||||
TableWidget::TableWidget(QWidget* parent) :
|
||||
QTableView(parent)
|
||||
{
|
||||
setVerticalScrollMode(QAbstractItemView::ScrollPerItem);
|
||||
setWordWrap(false);
|
||||
verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
|
||||
verticalHeader()->setDefaultSectionSize(fontMetrics().height());
|
||||
horizontalHeader()->setDefaultSectionSize(fontMetrics().height());
|
||||
}
|
||||
|
||||
void TableWidget::setTableModel(const TableModelPtr& model)
|
||||
{
|
||||
Q_ASSERT(!m_model);
|
||||
m_model = model;
|
||||
setModel(m_model.data());
|
||||
|
||||
connect(m_model.data(), &TableModel::modelReset, this, &TableWidget::updateRegion);
|
||||
connect(horizontalScrollBar(), &QScrollBar::rangeChanged, this, &TableWidget::updateRegion);
|
||||
connect(horizontalScrollBar(), &QScrollBar::valueChanged, this, &TableWidget::updateRegion);
|
||||
connect(verticalScrollBar(), &QScrollBar::rangeChanged, this, &TableWidget::updateRegion);
|
||||
connect(verticalScrollBar(), &QScrollBar::valueChanged, this, &TableWidget::updateRegion);
|
||||
|
||||
updateRegion();
|
||||
}
|
||||
|
||||
void TableWidget::updateRegion()
|
||||
{
|
||||
const int columnCount = m_model->columnCount();
|
||||
const int rowCount = m_model->rowCount();
|
||||
|
||||
if(columnCount == 0 || rowCount == 0)
|
||||
return;
|
||||
|
||||
const QRect r = viewport()->rect();
|
||||
const QModelIndex topLeft = indexAt(r.topLeft());
|
||||
|
||||
int rowMin = qMax(topLeft.row(), 0);
|
||||
int rowMax = indexAt(r.bottomLeft()).row();
|
||||
if(rowMax == -1)
|
||||
rowMax = rowCount - 1;
|
||||
else
|
||||
rowMax = qMin(rowMax + 1, rowCount - 1);
|
||||
|
||||
int columnMin = qMax(topLeft.column(), 0);
|
||||
int columnMax = indexAt(r.topRight()).column();
|
||||
if(columnMax == -1)
|
||||
columnMax = columnCount - 1;
|
||||
else
|
||||
columnMax = qMin(columnMax + 1, columnCount - 1);
|
||||
|
||||
m_model->setRegion(columnMin, columnMax, rowMin, rowMax);
|
||||
}
|
||||
45
client/src/widget/tablewidget.hpp
Normale Datei
45
client/src/widget/tablewidget.hpp
Normale Datei
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* client/src/widget/tablewidget.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef CLIENT_WIDGET_TABLEWIDGET_HPP
|
||||
#define CLIENT_WIDGET_TABLEWIDGET_HPP
|
||||
|
||||
#include <QTableView>
|
||||
#include "../network/tablemodelptr.hpp"
|
||||
|
||||
class TableWidget : public QTableView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
TableModelPtr m_model;
|
||||
|
||||
protected slots:
|
||||
void updateRegion();
|
||||
|
||||
public:
|
||||
TableWidget(QWidget* parent = nullptr);
|
||||
|
||||
void setTableModel(const TableModelPtr& model);
|
||||
};
|
||||
|
||||
#endif
|
||||
277
client/thirdparty/QtWaitingSpinner/waitingspinnerwidget.cpp
vendored
Normale Datei
277
client/thirdparty/QtWaitingSpinner/waitingspinnerwidget.cpp
vendored
Normale Datei
@ -0,0 +1,277 @@
|
||||
/* Original Work Copyright (c) 2012-2014 Alexander Turkin
|
||||
Modified 2014 by William Hallatt
|
||||
Modified 2015 by Jacob Dawid
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// Own includes
|
||||
#include "waitingspinnerwidget.h"
|
||||
|
||||
// Standard includes
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
// Qt includes
|
||||
#include <QPainter>
|
||||
#include <QTimer>
|
||||
|
||||
WaitingSpinnerWidget::WaitingSpinnerWidget(QWidget *parent,
|
||||
bool centerOnParent,
|
||||
bool disableParentWhenSpinning)
|
||||
: QWidget(parent),
|
||||
_centerOnParent(centerOnParent),
|
||||
_disableParentWhenSpinning(disableParentWhenSpinning) {
|
||||
initialize();
|
||||
}
|
||||
|
||||
WaitingSpinnerWidget::WaitingSpinnerWidget(Qt::WindowModality modality,
|
||||
QWidget *parent,
|
||||
bool centerOnParent,
|
||||
bool disableParentWhenSpinning)
|
||||
: QWidget(parent, Qt::Dialog | Qt::FramelessWindowHint),
|
||||
_centerOnParent(centerOnParent),
|
||||
_disableParentWhenSpinning(disableParentWhenSpinning){
|
||||
initialize();
|
||||
|
||||
// We need to set the window modality AFTER we've hidden the
|
||||
// widget for the first time since changing this property while
|
||||
// the widget is visible has no effect.
|
||||
setWindowModality(modality);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::initialize() {
|
||||
_color = Qt::black;
|
||||
_roundness = 100.0;
|
||||
_minimumTrailOpacity = 3.14159265358979323846;
|
||||
_trailFadePercentage = 80.0;
|
||||
_revolutionsPerSecond = 1.57079632679489661923;
|
||||
_numberOfLines = 20;
|
||||
_lineLength = 10;
|
||||
_lineWidth = 2;
|
||||
_innerRadius = 10;
|
||||
_currentCounter = 0;
|
||||
_isSpinning = false;
|
||||
|
||||
_timer = new QTimer(this);
|
||||
connect(_timer, SIGNAL(timeout()), this, SLOT(rotate()));
|
||||
updateSize();
|
||||
updateTimer();
|
||||
hide();
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::paintEvent(QPaintEvent *) {
|
||||
updatePosition();
|
||||
QPainter painter(this);
|
||||
painter.fillRect(this->rect(), Qt::transparent);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
if (_currentCounter >= _numberOfLines) {
|
||||
_currentCounter = 0;
|
||||
}
|
||||
|
||||
painter.setPen(Qt::NoPen);
|
||||
for (int i = 0; i < _numberOfLines; ++i) {
|
||||
painter.save();
|
||||
painter.translate(_innerRadius + _lineLength,
|
||||
_innerRadius + _lineLength);
|
||||
qreal rotateAngle =
|
||||
static_cast<qreal>(360 * i) / static_cast<qreal>(_numberOfLines);
|
||||
painter.rotate(rotateAngle);
|
||||
painter.translate(_innerRadius, 0);
|
||||
int distance =
|
||||
lineCountDistanceFromPrimary(i, _currentCounter, _numberOfLines);
|
||||
QColor color =
|
||||
currentLineColor(distance, _numberOfLines, _trailFadePercentage,
|
||||
_minimumTrailOpacity, _color);
|
||||
painter.setBrush(color);
|
||||
// TODO improve the way rounded rect is painted
|
||||
painter.drawRoundedRect(
|
||||
QRect(0, -_lineWidth / 2, _lineLength, _lineWidth), _roundness,
|
||||
_roundness, Qt::RelativeSize);
|
||||
painter.restore();
|
||||
}
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::start() {
|
||||
updatePosition();
|
||||
_isSpinning = true;
|
||||
show();
|
||||
|
||||
if(parentWidget() && _disableParentWhenSpinning) {
|
||||
parentWidget()->setEnabled(false);
|
||||
}
|
||||
|
||||
if (!_timer->isActive()) {
|
||||
_timer->start();
|
||||
_currentCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::stop() {
|
||||
_isSpinning = false;
|
||||
hide();
|
||||
|
||||
if(parentWidget() && _disableParentWhenSpinning) {
|
||||
parentWidget()->setEnabled(true);
|
||||
}
|
||||
|
||||
if (_timer->isActive()) {
|
||||
_timer->stop();
|
||||
_currentCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::setNumberOfLines(int lines) {
|
||||
_numberOfLines = lines;
|
||||
_currentCounter = 0;
|
||||
updateTimer();
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::setLineLength(int length) {
|
||||
_lineLength = length;
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::setLineWidth(int width) {
|
||||
_lineWidth = width;
|
||||
updateSize();
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::setInnerRadius(int radius) {
|
||||
_innerRadius = radius;
|
||||
updateSize();
|
||||
}
|
||||
|
||||
QColor WaitingSpinnerWidget::color() {
|
||||
return _color;
|
||||
}
|
||||
|
||||
qreal WaitingSpinnerWidget::roundness() {
|
||||
return _roundness;
|
||||
}
|
||||
|
||||
qreal WaitingSpinnerWidget::minimumTrailOpacity() {
|
||||
return _minimumTrailOpacity;
|
||||
}
|
||||
|
||||
qreal WaitingSpinnerWidget::trailFadePercentage() {
|
||||
return _trailFadePercentage;
|
||||
}
|
||||
|
||||
qreal WaitingSpinnerWidget::revolutionsPersSecond() {
|
||||
return _revolutionsPerSecond;
|
||||
}
|
||||
|
||||
int WaitingSpinnerWidget::numberOfLines() {
|
||||
return _numberOfLines;
|
||||
}
|
||||
|
||||
int WaitingSpinnerWidget::lineLength() {
|
||||
return _lineLength;
|
||||
}
|
||||
|
||||
int WaitingSpinnerWidget::lineWidth() {
|
||||
return _lineWidth;
|
||||
}
|
||||
|
||||
int WaitingSpinnerWidget::innerRadius() {
|
||||
return _innerRadius;
|
||||
}
|
||||
|
||||
bool WaitingSpinnerWidget::isSpinning() const {
|
||||
return _isSpinning;
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::setRoundness(qreal roundness) {
|
||||
_roundness = std::max(0.0, std::min(100.0, roundness));
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::setColor(QColor color) {
|
||||
_color = color;
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::setRevolutionsPerSecond(qreal revolutionsPerSecond) {
|
||||
_revolutionsPerSecond = revolutionsPerSecond;
|
||||
updateTimer();
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::setTrailFadePercentage(qreal trail) {
|
||||
_trailFadePercentage = trail;
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::setMinimumTrailOpacity(qreal minimumTrailOpacity) {
|
||||
_minimumTrailOpacity = minimumTrailOpacity;
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::rotate() {
|
||||
++_currentCounter;
|
||||
if (_currentCounter >= _numberOfLines) {
|
||||
_currentCounter = 0;
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::updateSize() {
|
||||
int size = (_innerRadius + _lineLength) * 2;
|
||||
setFixedSize(size, size);
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::updateTimer() {
|
||||
_timer->setInterval(1000 / (_numberOfLines * _revolutionsPerSecond));
|
||||
}
|
||||
|
||||
void WaitingSpinnerWidget::updatePosition() {
|
||||
if (parentWidget() && _centerOnParent) {
|
||||
move(parentWidget()->width() / 2 - width() / 2,
|
||||
parentWidget()->height() / 2 - height() / 2);
|
||||
}
|
||||
}
|
||||
|
||||
int WaitingSpinnerWidget::lineCountDistanceFromPrimary(int current, int primary,
|
||||
int totalNrOfLines) {
|
||||
int distance = primary - current;
|
||||
if (distance < 0) {
|
||||
distance += totalNrOfLines;
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
QColor WaitingSpinnerWidget::currentLineColor(int countDistance, int totalNrOfLines,
|
||||
qreal trailFadePerc, qreal minOpacity,
|
||||
QColor color) {
|
||||
if (countDistance == 0) {
|
||||
return color;
|
||||
}
|
||||
const qreal minAlphaF = minOpacity / 100.0;
|
||||
int distanceThreshold =
|
||||
static_cast<int>(ceil((totalNrOfLines - 1) * trailFadePerc / 100.0));
|
||||
if (countDistance > distanceThreshold) {
|
||||
color.setAlphaF(minAlphaF);
|
||||
} else {
|
||||
qreal alphaDiff = color.alphaF() - minAlphaF;
|
||||
qreal gradient = alphaDiff / static_cast<qreal>(distanceThreshold + 1);
|
||||
qreal resultAlpha = color.alphaF() - gradient * countDistance;
|
||||
|
||||
// If alpha is out of bounds, clip it.
|
||||
resultAlpha = std::min(1.0, std::max(0.0, resultAlpha));
|
||||
color.setAlphaF(resultAlpha);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
114
client/thirdparty/QtWaitingSpinner/waitingspinnerwidget.h
vendored
Normale Datei
114
client/thirdparty/QtWaitingSpinner/waitingspinnerwidget.h
vendored
Normale Datei
@ -0,0 +1,114 @@
|
||||
/* Original Work Copyright (c) 2012-2014 Alexander Turkin
|
||||
Modified 2014 by William Hallatt
|
||||
Modified 2015 by Jacob Dawid
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Qt includes
|
||||
#include <QWidget>
|
||||
#include <QTimer>
|
||||
#include <QColor>
|
||||
|
||||
class WaitingSpinnerWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/*! Constructor for "standard" widget behaviour - use this
|
||||
* constructor if you wish to, e.g. embed your widget in another. */
|
||||
WaitingSpinnerWidget(QWidget *parent = nullptr,
|
||||
bool centerOnParent = true,
|
||||
bool disableParentWhenSpinning = true);
|
||||
|
||||
/*! Constructor - use this constructor to automatically create a modal
|
||||
* ("blocking") spinner on top of the calling widget/window. If a valid
|
||||
* parent widget is provided, "centreOnParent" will ensure that
|
||||
* QtWaitingSpinner automatically centres itself on it, if not,
|
||||
* "centreOnParent" is ignored. */
|
||||
WaitingSpinnerWidget(Qt::WindowModality modality,
|
||||
QWidget *parent = nullptr,
|
||||
bool centerOnParent = true,
|
||||
bool disableParentWhenSpinning = true);
|
||||
|
||||
public slots:
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
public:
|
||||
void setColor(QColor color);
|
||||
void setRoundness(qreal roundness);
|
||||
void setMinimumTrailOpacity(qreal minimumTrailOpacity);
|
||||
void setTrailFadePercentage(qreal trail);
|
||||
void setRevolutionsPerSecond(qreal revolutionsPerSecond);
|
||||
void setNumberOfLines(int lines);
|
||||
void setLineLength(int length);
|
||||
void setLineWidth(int width);
|
||||
void setInnerRadius(int radius);
|
||||
void setText(QString text);
|
||||
|
||||
QColor color();
|
||||
qreal roundness();
|
||||
qreal minimumTrailOpacity();
|
||||
qreal trailFadePercentage();
|
||||
qreal revolutionsPersSecond();
|
||||
int numberOfLines();
|
||||
int lineLength();
|
||||
int lineWidth();
|
||||
int innerRadius();
|
||||
|
||||
bool isSpinning() const;
|
||||
|
||||
private slots:
|
||||
void rotate();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *paintEvent);
|
||||
|
||||
private:
|
||||
static int lineCountDistanceFromPrimary(int current, int primary,
|
||||
int totalNrOfLines);
|
||||
static QColor currentLineColor(int distance, int totalNrOfLines,
|
||||
qreal trailFadePerc, qreal minOpacity,
|
||||
QColor color);
|
||||
|
||||
void initialize();
|
||||
void updateSize();
|
||||
void updateTimer();
|
||||
void updatePosition();
|
||||
|
||||
private:
|
||||
QColor _color;
|
||||
qreal _roundness; // 0..100
|
||||
qreal _minimumTrailOpacity;
|
||||
qreal _trailFadePercentage;
|
||||
qreal _revolutionsPerSecond;
|
||||
int _numberOfLines;
|
||||
int _lineLength;
|
||||
int _lineWidth;
|
||||
int _innerRadius;
|
||||
|
||||
private:
|
||||
WaitingSpinnerWidget(const WaitingSpinnerWidget&);
|
||||
WaitingSpinnerWidget& operator=(const WaitingSpinnerWidget&);
|
||||
|
||||
QTimer *_timer;
|
||||
bool _centerOnParent;
|
||||
bool _disableParentWhenSpinning;
|
||||
int _currentCounter;
|
||||
bool _isSpinning;
|
||||
};
|
||||
74
client/traintastic-client.pro
Normale Datei
74
client/traintastic-client.pro
Normale Datei
@ -0,0 +1,74 @@
|
||||
QT += core gui widgets network
|
||||
|
||||
TARGET = traintastic-client
|
||||
TEMPLATE = app
|
||||
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
greaterThan(QT_MINOR_VERSION, 11): { # >= 5.12
|
||||
CONFIG += c++17
|
||||
} else {
|
||||
QMAKE_CXXFLAGS += -std=c++17
|
||||
}
|
||||
|
||||
INCLUDEPATH += \
|
||||
../shared/src \
|
||||
thirdparty
|
||||
|
||||
SOURCES += \
|
||||
src/main.cpp \
|
||||
src/mainwindow.cpp \
|
||||
src/dialog/connectdialog.cpp \
|
||||
src/subwindow/hardwarelistsubwindow.cpp \
|
||||
src/network/client.cpp \
|
||||
src/network/object.cpp \
|
||||
src/subwindow/serverconsolesubwindow.cpp \
|
||||
thirdparty/QtWaitingSpinner/waitingspinnerwidget.cpp \
|
||||
src/widget/alertwidget.cpp \
|
||||
src/network/utils.cpp \
|
||||
src/network/tablemodel.cpp \
|
||||
src/widget/serverconsolewidget.cpp \
|
||||
src/widget/tablewidget.cpp \
|
||||
src/widget/objectlistwidget.cpp \
|
||||
src/widget/hardwarewidget.cpp \
|
||||
src/widget/decoderlistwidget.cpp \
|
||||
src/widget/commandstationlistwidget.cpp \
|
||||
src/widget/objecteditwidget.cpp \
|
||||
src/widget/serversettingswidget.cpp \
|
||||
src/subwindow/serversettingssubwindow.cpp \
|
||||
src/network/property.cpp \
|
||||
src/network/interfaceitems.cpp \
|
||||
src/network/interfaceitem.cpp \
|
||||
src/widget/propertycheckbox.cpp
|
||||
|
||||
HEADERS += \
|
||||
src/mainwindow.hpp \
|
||||
src/dialog/connectdialog.hpp \
|
||||
src/subwindow/hardwarelistsubwindow.hpp \
|
||||
src/network/client.hpp \
|
||||
src/network/object.hpp \
|
||||
../shared/src/message.hpp \
|
||||
src/subwindow/serverconsolesubwindow.hpp \
|
||||
thirdparty/QtWaitingSpinner/waitingspinnerwidget.h \
|
||||
src/widget/alertwidget.hpp \
|
||||
src/network/utils.hpp \
|
||||
src/network/tablemodel.hpp \
|
||||
src/network/tablemodelptr.hpp \
|
||||
src/network/handle.hpp \
|
||||
src/network/objectptr.hpp \
|
||||
src/widget/serverconsolewidget.hpp \
|
||||
src/widget/tablewidget.hpp \
|
||||
src/widget/objectlistwidget.hpp \
|
||||
src/widget/commandstationlistwidget.hpp \
|
||||
src/widget/hardwarewidget.hpp \
|
||||
src/widget/decoderlistwidget.hpp \
|
||||
src/widget/objecteditwidget.hpp \
|
||||
src/widget/serversettingswidget.hpp \
|
||||
src/subwindow/serversettingssubwindow.hpp \
|
||||
src/network/property.hpp \
|
||||
src/network/interfaceitems.hpp \
|
||||
src/network/interfaceitem.hpp \
|
||||
src/widget/propertycheckbox.hpp
|
||||
|
||||
RESOURCES += \
|
||||
dark.qrc
|
||||
8
lang/en-us.txt
Normale Datei
8
lang/en-us.txt
Normale Datei
@ -0,0 +1,8 @@
|
||||
## Traintastic language file: English (US)
|
||||
|
||||
language:en-us=English
|
||||
languaga:nl-nl=Dutch
|
||||
|
||||
settings:localhost_only=Localhost only
|
||||
settings:port=Port
|
||||
#settings:default_world=
|
||||
7
lang/nl-nl.txt
Normale Datei
7
lang/nl-nl.txt
Normale Datei
@ -0,0 +1,7 @@
|
||||
## Traintastic language file: Dutch (NL)
|
||||
|
||||
language:en-us=Engels
|
||||
language:nl-nl=Nederlands
|
||||
|
||||
settings:localhost_only=Alleen localhost
|
||||
settings:port=Poort
|
||||
50
server/CMakeLists.txt
Normale Datei
50
server/CMakeLists.txt
Normale Datei
@ -0,0 +1,50 @@
|
||||
cmake_minimum_required(VERSION 3.9)
|
||||
project(traintastic-server VERSION 0.1.0 DESCRIPTION "Traintastic server")
|
||||
include(GNUInstallDirs)
|
||||
|
||||
#find_package(PkgConfig REQUIRED)
|
||||
find_package(Lua 5.3 REQUIRED)
|
||||
#pkg_check_modules(USBXPRESSNET REQUIRED IMPORTED_TARGET usbxpressnet)
|
||||
|
||||
find_path(USBXPRESSNET_INCLUDE_DIR usbxpressnet.h)
|
||||
#message(${USBXPRESSNET_INCLUDE_DIR})
|
||||
find_library(USBXPRESSNET_LIB usbxpressnet)
|
||||
#message(${USBXPRESSNET_LIB})
|
||||
#if(NOT USBXPRESSNET_LIB)
|
||||
# message(FATAL_ERROR "usbxpressnet library not found")
|
||||
#endif()
|
||||
|
||||
file(GLOB SOURCES
|
||||
"src/*.cpp"
|
||||
"src/core/*.cpp"
|
||||
"src/hardware/commandstation/*.cpp"
|
||||
"src/hardware/commandstation/protocol/*.cpp"
|
||||
"src/hardware/decoder/*.cpp"
|
||||
"src/lua/*.cpp"
|
||||
"thirdparty/boost/libs/program_options/src/*.cpp")
|
||||
|
||||
add_executable(traintastic-server ${SOURCES})
|
||||
|
||||
add_definitions(
|
||||
-DVERSION=${PROJECT_VERSION}
|
||||
-DBOOST_ALL_NO_LIB
|
||||
-DBOOST_ERROR_CODE_HEADER_ONLY
|
||||
-DBOOST_CHRONO_HEADER_ONLY
|
||||
-DBOOST_ASIO_HEADER_ONLY
|
||||
-DBOOST_SYSTEM_NO_DEPRECATED)
|
||||
|
||||
target_include_directories(traintastic-server PRIVATE
|
||||
../shared/src/
|
||||
thirdparty
|
||||
thirdparty/boost
|
||||
${LUA_INCLUDE_DIR}
|
||||
${USBXPRESSNET_INCLUDE_DIR})
|
||||
|
||||
target_link_libraries(traintastic-server
|
||||
pthread
|
||||
stdc++fs
|
||||
${LUA_LIBRARIES}
|
||||
${USBXPRESSNET_LIB})
|
||||
# PkgConfig::USBXPRESSNET)
|
||||
|
||||
set_target_properties(traintastic-server PROPERTIES CXX_STANDARD 17)
|
||||
119
server/FindLua.cmake
Normale Datei
119
server/FindLua.cmake
Normale Datei
@ -0,0 +1,119 @@
|
||||
# Locate Lua library
|
||||
# This module defines
|
||||
# LUA_EXECUTABLE, if found
|
||||
# LUA_FOUND, if false, do not try to link to Lua
|
||||
# LUA_LIBRARIES
|
||||
# LUA_INCLUDE_DIR, where to find lua.h
|
||||
# LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8)
|
||||
#
|
||||
# Note that the expected include convention is
|
||||
# #include "lua.h"
|
||||
# and not
|
||||
# #include <lua/lua.h>
|
||||
# This is because, the lua location is not standardized and may exist
|
||||
# in locations other than lua/
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2007-2009 Kitware, Inc.
|
||||
# Modified to support Lua 5.2 by LuaDist 2012
|
||||
# Modified to support Lua 5.3 by Reinder Feenstra 2019
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see accompanying file Copyright.txt for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
# (To distribute this file outside of CMake, substitute the full
|
||||
# License text for the above reference.)
|
||||
#
|
||||
# The required version of Lua can be specified using the
|
||||
# standard syntax, e.g. FIND_PACKAGE(Lua 5.1)
|
||||
# Otherwise the module will search for any available Lua implementation
|
||||
|
||||
# Always search for non-versioned lua first (recommended)
|
||||
SET(_POSSIBLE_LUA_INCLUDE include include/lua)
|
||||
SET(_POSSIBLE_LUA_EXECUTABLE lua)
|
||||
SET(_POSSIBLE_LUA_LIBRARY lua)
|
||||
|
||||
# Determine possible naming suffixes (there is no standard for this)
|
||||
IF(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR)
|
||||
SET(_POSSIBLE_SUFFIXES "${Lua_FIND_VERSION_MAJOR}${Lua_FIND_VERSION_MINOR}" "${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}" "-${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}")
|
||||
ELSE(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR)
|
||||
SET(_POSSIBLE_SUFFIXES "53" "5.3" "-5.3" "52" "5.2" "-5.2" "51" "5.1" "-5.1")
|
||||
ENDIF(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR)
|
||||
|
||||
# Set up possible search names and locations
|
||||
FOREACH(_SUFFIX ${_POSSIBLE_SUFFIXES})
|
||||
LIST(APPEND _POSSIBLE_LUA_INCLUDE "include/lua${_SUFFIX}")
|
||||
LIST(APPEND _POSSIBLE_LUA_EXECUTABLE "lua${_SUFFIX}")
|
||||
LIST(APPEND _POSSIBLE_LUA_LIBRARY "lua${_SUFFIX}")
|
||||
ENDFOREACH(_SUFFIX)
|
||||
|
||||
# Find the lua executable
|
||||
FIND_PROGRAM(LUA_EXECUTABLE
|
||||
NAMES ${_POSSIBLE_LUA_EXECUTABLE}
|
||||
)
|
||||
|
||||
# Find the lua header
|
||||
FIND_PATH(LUA_INCLUDE_DIR lua.h
|
||||
HINTS
|
||||
$ENV{LUA_DIR}
|
||||
PATH_SUFFIXES ${_POSSIBLE_LUA_INCLUDE}
|
||||
PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local
|
||||
/usr
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt
|
||||
)
|
||||
|
||||
# Find the lua library
|
||||
FIND_LIBRARY(LUA_LIBRARY
|
||||
NAMES ${_POSSIBLE_LUA_LIBRARY}
|
||||
HINTS
|
||||
$ENV{LUA_DIR}
|
||||
PATH_SUFFIXES lib64 lib
|
||||
PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local
|
||||
/usr
|
||||
/sw
|
||||
/opt/local
|
||||
/opt/csw
|
||||
/opt
|
||||
)
|
||||
|
||||
IF(LUA_LIBRARY)
|
||||
# include the math library for Unix
|
||||
IF(UNIX AND NOT APPLE)
|
||||
FIND_LIBRARY(LUA_MATH_LIBRARY m)
|
||||
SET( LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries")
|
||||
# For Windows and Mac, don't need to explicitly include the math library
|
||||
ELSE(UNIX AND NOT APPLE)
|
||||
SET( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries")
|
||||
ENDIF(UNIX AND NOT APPLE)
|
||||
ENDIF(LUA_LIBRARY)
|
||||
|
||||
# Determine Lua version
|
||||
IF(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h")
|
||||
FILE(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"")
|
||||
|
||||
STRING(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}")
|
||||
UNSET(lua_version_str)
|
||||
ENDIF()
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua
|
||||
REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR
|
||||
VERSION_VAR LUA_VERSION_STRING)
|
||||
|
||||
MARK_AS_ADVANCED(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY LUA_EXECUTABLE)
|
||||
|
||||
33
server/src/core/abstractproperty.cpp
Normale Datei
33
server/src/core/abstractproperty.cpp
Normale Datei
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* server/src/core/abstractproperty.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "abstractproperty.hpp"
|
||||
#include "object.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
void AbstractProperty::changed()
|
||||
{
|
||||
std::cout << "AbstractProperty::changed" << std::endl;
|
||||
|
||||
m_object.propertyChanged(m_object, *this);
|
||||
}
|
||||
139
server/src/core/abstractproperty.hpp
Normale Datei
139
server/src/core/abstractproperty.hpp
Normale Datei
@ -0,0 +1,139 @@
|
||||
/**
|
||||
* server/src/core/abstractproperty.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_ABSTRACTPROPERTY_HPP
|
||||
#define SERVER_CORE_ABSTRACTPROPERTY_HPP
|
||||
|
||||
#include "interfaceitem.hpp"
|
||||
#include <enum/propertytype.hpp>
|
||||
#include "propertyflags.hpp"
|
||||
#include "objectptr.hpp"
|
||||
#include <cassert>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
class AbstractProperty : public InterfaceItem
|
||||
{
|
||||
protected:
|
||||
const PropertyType m_type;
|
||||
PropertyFlags m_flags;
|
||||
|
||||
void changed();
|
||||
|
||||
public:
|
||||
AbstractProperty(Object& object, const std::string& name, PropertyType type, PropertyFlags flags) :
|
||||
InterfaceItem{object, name},
|
||||
m_type{type},
|
||||
m_flags{flags}
|
||||
{
|
||||
assert(type != PropertyType::Invalid);
|
||||
assert(is_access_valid(flags) && is_store_valid(flags));
|
||||
}
|
||||
|
||||
bool isConstant() const
|
||||
{
|
||||
return false;//!is_empty(m_flags & PropertyFlags::Constant);
|
||||
}
|
||||
|
||||
bool isReadable() const
|
||||
{
|
||||
return true;//!is_empty(m_flags & (PropertyFlags::Constant | PropertyFlags::ReadOnly));
|
||||
}
|
||||
|
||||
bool isWriteable() const
|
||||
{
|
||||
return true;//!is_empty(m_flags & PropertyFlags::WriteOnly);
|
||||
}
|
||||
|
||||
PropertyType type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
virtual bool toBool() const = 0;
|
||||
virtual int64_t toInt64() const = 0;
|
||||
virtual double toDouble() const = 0;
|
||||
virtual std::string toString() const = 0;
|
||||
virtual ObjectPtr toObject() const = 0;
|
||||
|
||||
virtual void fromBool(bool value) = 0;
|
||||
virtual void fromInt64(int64_t value) = 0;
|
||||
virtual void fromDouble(double value) = 0;
|
||||
virtual void fromString(const std::string& value) = 0;
|
||||
virtual void fromObject(const ObjectPtr& value) = 0;
|
||||
|
||||
nlohmann::json toJSON() const
|
||||
{
|
||||
switch(type())
|
||||
{
|
||||
case PropertyType::Boolean:
|
||||
return toBool();
|
||||
|
||||
case PropertyType::Integer:
|
||||
return toInt64();
|
||||
|
||||
case PropertyType::Float:
|
||||
return toDouble();
|
||||
|
||||
case PropertyType::String:
|
||||
return toString();
|
||||
|
||||
// TODO: case nlohmann::json::value_t::object:
|
||||
// TODO: case nlohmann::json::value_t::array:
|
||||
|
||||
default:
|
||||
throw std::runtime_error("unsupported type");
|
||||
}
|
||||
}
|
||||
|
||||
void fromJSON(const nlohmann::json& value)
|
||||
{
|
||||
switch(value.type())
|
||||
{
|
||||
// TODO: case nlohmann::json::value_t::null:
|
||||
|
||||
case nlohmann::json::value_t::boolean:
|
||||
fromBool(value);
|
||||
break;
|
||||
|
||||
case nlohmann::json::value_t::number_integer:
|
||||
case nlohmann::json::value_t::number_unsigned:
|
||||
fromInt64(value);
|
||||
break;
|
||||
|
||||
case nlohmann::json::value_t::number_float:
|
||||
fromDouble(value);
|
||||
break;
|
||||
|
||||
case nlohmann::json::value_t::string:
|
||||
fromString(value);
|
||||
break;
|
||||
|
||||
// TODO: case nlohmann::json::value_t::object:
|
||||
// TODO: case nlohmann::json::value_t::array:
|
||||
|
||||
default:
|
||||
throw std::runtime_error("unsupported JSON type");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
281
server/src/core/client.cpp
Normale Datei
281
server/src/core/client.cpp
Normale Datei
@ -0,0 +1,281 @@
|
||||
/**
|
||||
* server/src/core/client.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "client.hpp"
|
||||
//#include "console.hpp"
|
||||
//#include "objectregistry.hpp"
|
||||
#include "traintastic.hpp"
|
||||
#include "eventloop.hpp"
|
||||
#include "session.hpp"
|
||||
|
||||
Client::Client(Traintastic& server, const std::string& id, boost::asio::ip::tcp::socket socket) :
|
||||
m_server{server},
|
||||
m_socket(std::move(socket)),
|
||||
m_id{id},
|
||||
m_authenticated{false}//,
|
||||
//m_lastObjectHandle{0}
|
||||
{
|
||||
m_socket.set_option(boost::asio::socket_base::linger(true, 0));
|
||||
m_socket.set_option(boost::asio::ip::tcp::no_delay(true));
|
||||
|
||||
Traintastic::instance->console->info(id, "Connected");
|
||||
}
|
||||
|
||||
Client::~Client()
|
||||
{
|
||||
try
|
||||
{
|
||||
m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
m_socket.close();
|
||||
}
|
||||
|
||||
void Client::start()
|
||||
{
|
||||
doReadHeader();
|
||||
}
|
||||
|
||||
void Client::doReadHeader()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
boost::asio::async_read(m_socket,
|
||||
boost::asio::buffer(&m_readBuffer.header, sizeof(m_readBuffer.header)),
|
||||
[this, self](const boost::system::error_code& e, std::size_t)
|
||||
{
|
||||
if(!e)
|
||||
{
|
||||
m_readBuffer.message.reset(new Message(m_readBuffer.header));
|
||||
if(m_readBuffer.message->dataSize() == 0)
|
||||
{
|
||||
if(m_readBuffer.message->command() != Message::Command::Ping)
|
||||
EventLoop::call(&Client::processMessage, this, m_readBuffer.message);
|
||||
else
|
||||
; // TODO: ping hier replyen
|
||||
m_readBuffer.message.reset();
|
||||
doReadHeader();
|
||||
}
|
||||
else
|
||||
doReadData();
|
||||
}
|
||||
else if(e == boost::asio::error::eof || e == boost::asio::error::connection_aborted || e == boost::asio::error::connection_reset)
|
||||
connectionLost();
|
||||
else
|
||||
connectionError("readheader", e.message());
|
||||
});
|
||||
}
|
||||
|
||||
void Client::doReadData()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
boost::asio::async_read(m_socket,
|
||||
boost::asio::buffer(m_readBuffer.message->data(), m_readBuffer.message->dataSize()),
|
||||
[this, self](const boost::system::error_code& ec, std::size_t)
|
||||
{
|
||||
if(!ec)
|
||||
{
|
||||
if(m_readBuffer.message->command() != Message::Command::Ping)
|
||||
EventLoop::call(&Client::processMessage, this, m_readBuffer.message);
|
||||
else
|
||||
; // TODO: ping hier replyen
|
||||
m_readBuffer.message.reset();
|
||||
doReadHeader();
|
||||
}
|
||||
else if(ec == boost::asio::error::eof || ec == boost::asio::error::connection_aborted || ec == boost::asio::error::connection_reset)
|
||||
connectionLost();
|
||||
else
|
||||
connectionError("readdata", ec.message());
|
||||
});
|
||||
}
|
||||
|
||||
void Client::doWrite()
|
||||
{
|
||||
auto self(shared_from_this());
|
||||
boost::asio::async_write(m_socket, boost::asio::buffer(**m_writeQueue.front(), m_writeQueue.front()->size()),
|
||||
[this, self](const boost::system::error_code& ec, std::size_t)
|
||||
{
|
||||
if(!ec)
|
||||
{
|
||||
m_writeQueue.pop();
|
||||
if(!m_writeQueue.empty())
|
||||
doWrite();
|
||||
}
|
||||
else
|
||||
connectionError("write", ec.message());
|
||||
});
|
||||
}
|
||||
|
||||
void Client::processMessage(const std::shared_ptr<Message> message)
|
||||
{
|
||||
if(m_authenticated && m_session)
|
||||
{
|
||||
if(m_session->processMessage(*message))
|
||||
return;
|
||||
}
|
||||
else if(m_authenticated && !m_session)
|
||||
{
|
||||
if(message->command() == Message::Command::NewSession && message->type() == Message::Type::Request)
|
||||
{
|
||||
m_session = std::make_shared<Session>(shared_from_this());
|
||||
Traintastic::instance->console->notice(m_id, "Created new session");
|
||||
auto response = Message::newResponse(message->command(), message->requestId());
|
||||
response->write(m_session->uuid());
|
||||
sendMessage(std::move(response));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(message->command() == Message::Command::Login && message->type() == Message::Type::Request)
|
||||
{
|
||||
m_authenticated = true; // oke for now, login can be added later :)
|
||||
Traintastic::instance->console->notice(m_id, "Logged in anonymously");
|
||||
sendMessage(Message::newResponse(message->command(), message->requestId()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(message->type() == Message::Type::Request)
|
||||
{
|
||||
Traintastic::instance->console->debug(m_id, "Received invalid command: " + std::to_string(static_cast<uint8_t>(message->command())));
|
||||
|
||||
|
||||
usleep(10*1000*1000);
|
||||
|
||||
|
||||
sendMessage(Message::newErrorResponse(message->command(), message->requestId(), Message::ErrorCode::InvalidCommand));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
switch(message.command())
|
||||
{
|
||||
case Message::Command::None:
|
||||
break;
|
||||
|
||||
case Message::Command::CreateObject:
|
||||
if(message.isRequest())
|
||||
{
|
||||
const std::string id = message.read();
|
||||
m_server.console->debug(m_id, std::string("CreateObject: id=") + id);
|
||||
//std::unique_ptr<Message> response = Message::newResponse(message.command(), message.requestId());
|
||||
//response->add(ObjectRegistry::instance->exists(id));
|
||||
//sendMessage(std::move(response));
|
||||
}
|
||||
break;
|
||||
|
||||
case Message::Command::IsObject:
|
||||
if(message.isRequest())
|
||||
{
|
||||
const std::string id = message.read();
|
||||
m_server.console->debug(m_id, std::string("IsObject: id=") + id);
|
||||
std::unique_ptr<Message> response = Message::newResponse(message.command(), message.requestId());
|
||||
response->add(ObjectRegistry::instance->exists(id));
|
||||
sendMessage(std::move(response));
|
||||
}
|
||||
break;
|
||||
|
||||
case Message::Command::GetObject:
|
||||
if(message.isRequest())
|
||||
{
|
||||
std::string id = message.read();
|
||||
m_server.console->debug(m_id, std::string("GetObject: id=") + id);
|
||||
ObjectPtr p = ObjectRegistry::instance->get(id);
|
||||
if(p)
|
||||
{
|
||||
ObjectHandle handle = 0;//subscribeObject(p);
|
||||
std::unique_ptr<Message> response = Message::newResponse(message.command(), message.requestId());
|
||||
response->add(handle);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
sendMessage(std::move(response));
|
||||
}
|
||||
else
|
||||
sendMessage(Message::newErrorResponse(message.command(), message.requestId(), Message::ErrorCode::UnknownObjectId, std::string("No object exists with id `") + id + "`"));
|
||||
}
|
||||
break;
|
||||
|
||||
case Message::Command::ReleaseObject:
|
||||
if(message.isRequest())
|
||||
{
|
||||
ObjectHandle handle = message.read<ObjectHandle>();
|
||||
m_server.console->debug(m_id, std::string("ReleaseObject: handle=") + std::to_string(handle));
|
||||
if(false)//unsubscribeObject(handle))
|
||||
sendMessage(std::move(Message::newResponse(message.command(), message.requestId())));
|
||||
else
|
||||
sendMessage(std::move(Message::newErrorResponse(message.command(), message.requestId(), Message::ErrorCode::InvalidHandle)));
|
||||
}
|
||||
break;
|
||||
|
||||
case Message::Command::SetProperty:
|
||||
if(message.isRequest())
|
||||
{
|
||||
ObjectHandle handle = message.read<ObjectHandle>();
|
||||
std::string name = message.read();
|
||||
m_server.console->debug(m_id, std::string("SetProperty: handle=") + std::to_string(handle) + ", name=" + name);
|
||||
ObjectPtr object;// = getObject(handle);
|
||||
AbstractProperty* property;
|
||||
//if(!object)
|
||||
// sendMessage(std::move(Message::newErrorResponse(message.command(), message.requestId(), Message::ErrorCode::InvalidHandle)));
|
||||
//else if(!(property = object->getProperty(name)))
|
||||
// sendMessage(std::move(Message::newErrorResponse(message.command(), message.requestId(), Message::ErrorCode::InvalidProperty)));
|
||||
//else if(!readPropertyValue(message, property))
|
||||
sendMessage(std::move(Message::newErrorResponse(message.command(), message.requestId(), Message::ErrorCode::InvalidValue)));
|
||||
}
|
||||
break;
|
||||
|
||||
case Message::Command::PropertyChanged:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void Client::sendMessage(std::unique_ptr<Message> message)
|
||||
{
|
||||
bool wasEmpty = m_writeQueue.empty();
|
||||
m_writeQueue.emplace(std::move(message));
|
||||
if(wasEmpty)
|
||||
doWrite();
|
||||
}
|
||||
|
||||
void Client::connectionLost()
|
||||
{
|
||||
m_server.console->info(m_id, "Connection lost");
|
||||
disconnect();
|
||||
}
|
||||
|
||||
void Client::connectionError(const std::string& where, const std::string& what)
|
||||
{
|
||||
m_server.console->error(m_id, what + " [" + where + "]");
|
||||
disconnect();
|
||||
}
|
||||
|
||||
void Client::disconnect()
|
||||
{
|
||||
m_server.clientGone(shared_from_this());
|
||||
}
|
||||
84
server/src/core/client.hpp
Normale Datei
84
server/src/core/client.hpp
Normale Datei
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* server/src/core/client.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_CLIENT_HPP
|
||||
#define SERVER_CORE_CLIENT_HPP
|
||||
|
||||
//#include "Message.hpp"
|
||||
//#include "MessageQueue.hpp"
|
||||
//#include <thread>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
//#include <deque>
|
||||
//#include <list>
|
||||
//#include <condition_variable>
|
||||
#include <boost/asio.hpp>
|
||||
//#include "connection-callback.hpp"
|
||||
//#include "status.hpp"
|
||||
//#include <chrono>
|
||||
//#include <cmath>
|
||||
#include "objectptr.hpp"
|
||||
#include <message.hpp>
|
||||
|
||||
class Traintastic;
|
||||
class Session;
|
||||
|
||||
class Client : public std::enable_shared_from_this<Client>
|
||||
{
|
||||
friend class Session;
|
||||
|
||||
protected:
|
||||
using ObjectHandle = uint32_t;
|
||||
|
||||
Traintastic& m_server;
|
||||
boost::asio::ip::tcp::socket m_socket;
|
||||
const std::string m_id;
|
||||
struct
|
||||
{
|
||||
Message::Header header;
|
||||
std::shared_ptr<Message> message;
|
||||
} m_readBuffer;
|
||||
std::queue<std::unique_ptr<Message>> m_writeQueue;
|
||||
bool m_authenticated;
|
||||
std::shared_ptr<Session> m_session;
|
||||
//ObjectHandle m_lastObjectHandle;
|
||||
//std::map<ObjectHandle,ObjectPtr> m_objects;
|
||||
|
||||
void doReadHeader();
|
||||
void doReadData();
|
||||
void doWrite();
|
||||
|
||||
void processMessage(const std::shared_ptr<Message> message);
|
||||
void sendMessage(std::unique_ptr<Message> message);
|
||||
|
||||
void connectionLost();
|
||||
void connectionError(const std::string& where, const std::string& what);
|
||||
void disconnect();
|
||||
|
||||
public:
|
||||
Client(Traintastic& server, const std::string& id, boost::asio::ip::tcp::socket socket);
|
||||
virtual ~Client();
|
||||
|
||||
void start();
|
||||
};
|
||||
|
||||
#endif
|
||||
123
server/src/core/console.cpp
Normale Datei
123
server/src/core/console.cpp
Normale Datei
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* server/src/core/console.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "console.hpp"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include "consoletablemodel.hpp"
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const Console::Level& value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
case Console::Level::Debug:
|
||||
out << "[debug] ";
|
||||
break;
|
||||
|
||||
case Console::Level::Info:
|
||||
out << "[info] ";
|
||||
break;
|
||||
|
||||
case Console::Level::Notice:
|
||||
out << "[notice] ";
|
||||
break;
|
||||
|
||||
case Console::Level::Warning:
|
||||
out << "[warning] ";
|
||||
break;
|
||||
|
||||
case Console::Level::Error:
|
||||
out << "[error] ";
|
||||
break;
|
||||
|
||||
case Console::Level::Critical:
|
||||
out << "[critical]";
|
||||
break;
|
||||
|
||||
case Console::Level::Fatal:
|
||||
out << "[fatal] ";
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string to_string(const Console::Level& value)
|
||||
{
|
||||
switch(value)
|
||||
{
|
||||
case Console::Level::Debug:
|
||||
return "Debug";
|
||||
|
||||
case Console::Level::Info:
|
||||
return "Info";
|
||||
|
||||
case Console::Level::Notice:
|
||||
return "Notice";
|
||||
|
||||
case Console::Level::Warning:
|
||||
return "Warning";
|
||||
|
||||
case Console::Level::Error:
|
||||
return "Error";
|
||||
|
||||
case Console::Level::Critical:
|
||||
return "Critical";
|
||||
|
||||
case Console::Level::Fatal:
|
||||
return "Fatal";
|
||||
}
|
||||
assert(false);
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
Console::Console() :
|
||||
IdObject("console"),
|
||||
count{this, "count", 1000, PropertyFlags::AccessWWW}
|
||||
{
|
||||
m_interfaceItems.add(count);
|
||||
}
|
||||
|
||||
void Console::log(Level level, const std::string& id, const std::string& message)
|
||||
{
|
||||
const auto now = std::chrono::system_clock::now();
|
||||
const auto tm = std::chrono::system_clock::to_time_t(now);
|
||||
const auto us = std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()) % 1000000;
|
||||
|
||||
std::ostream& ss = (level >= Level::Error) ? std::cerr : std::cout;
|
||||
ss << std::put_time(std::localtime(&tm), "%F %T") << '.' << std::setfill('0') << std::setw(6) << us.count() << ' ' << level << ' ' << id << ": " << message << std::endl;
|
||||
|
||||
m_logs.push_back({
|
||||
.time_s = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count(),
|
||||
.time_us = static_cast<uint32_t>(us.count()),
|
||||
.level = level,
|
||||
.id = id,
|
||||
.message = message});
|
||||
|
||||
for(auto& model : m_models)
|
||||
model->logAdded();
|
||||
}
|
||||
|
||||
TableModelPtr Console::getModel()
|
||||
{
|
||||
return std::make_shared<ConsoleTableModel>(*this);
|
||||
}
|
||||
84
server/src/core/console.hpp
Normale Datei
84
server/src/core/console.hpp
Normale Datei
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* server/src/core/console.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_CONSOLE_HPP
|
||||
#define SERVER_CORE_CONSOLE_HPP
|
||||
|
||||
#include "idobject.hpp"
|
||||
#include "table.hpp"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
class ConsoleTableModel;
|
||||
|
||||
class Console : public IdObject, public Table
|
||||
{
|
||||
friend class ConsoleTableModel;
|
||||
|
||||
public:
|
||||
enum class Level
|
||||
{
|
||||
Debug = 0,
|
||||
Info = 1,
|
||||
Notice = 2,
|
||||
Warning = 3,
|
||||
Error = 4,
|
||||
Critical = 5,
|
||||
Fatal = 6,
|
||||
};
|
||||
|
||||
protected:
|
||||
struct Log
|
||||
{
|
||||
int64_t time_s;
|
||||
uint32_t time_us;
|
||||
Level level;
|
||||
std::string id;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
std::vector<Log> m_logs;
|
||||
std::vector<ConsoleTableModel*> m_models;
|
||||
|
||||
public:
|
||||
CLASS_ID("console");
|
||||
|
||||
Property<uint32_t> count;
|
||||
|
||||
Console();
|
||||
|
||||
void log(Level level, const std::string& id, const std::string& message);
|
||||
|
||||
inline void debug(const std::string& id, const std::string& message) { log(Level::Debug, id, message); }
|
||||
inline void info(const std::string& id, const std::string& message) { log(Level::Info, id, message); }
|
||||
inline void notice(const std::string& id, const std::string& message) { log(Level::Notice, id, message); }
|
||||
inline void warning(const std::string& id, const std::string& message) { log(Level::Warning, id, message); }
|
||||
inline void error(const std::string& id, const std::string& message) { log(Level::Error, id, message); }
|
||||
inline void critical(const std::string& id, const std::string& message) { log(Level::Critical, id, message); }
|
||||
inline void fatal(const std::string& id, const std::string& message) { log(Level::Fatal, id, message); }
|
||||
|
||||
TableModelPtr getModel() final;
|
||||
};
|
||||
|
||||
std::string to_string(const Console::Level& value);
|
||||
|
||||
#endif
|
||||
88
server/src/core/consoletablemodel.cpp
Normale Datei
88
server/src/core/consoletablemodel.cpp
Normale Datei
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* server/src/core/consoletablemodel.cpp - Console table model
|
||||
*
|
||||
* This file is part of the traintastic source code
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "consoletablemodel.hpp"
|
||||
#include "console.hpp"
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
|
||||
constexpr uint32_t columnTime = 0;
|
||||
constexpr uint32_t columnLevel = 1;
|
||||
constexpr uint32_t columnId = 2;
|
||||
constexpr uint32_t columnMessage = 3;
|
||||
|
||||
ConsoleTableModel::ConsoleTableModel(Console& console) :
|
||||
TableModel(),
|
||||
m_console{console}
|
||||
{
|
||||
m_console.m_models.push_back(this);
|
||||
setColumnHeaders({"Time", "Level", "Object", "Message"});
|
||||
setRowCount(m_console.m_logs.size());
|
||||
}
|
||||
|
||||
ConsoleTableModel::~ConsoleTableModel()
|
||||
{
|
||||
auto it = std::find(m_console.m_models.begin(), m_console.m_models.end(), this);
|
||||
assert(it != m_console.m_models.end());
|
||||
m_console.m_models.erase(it);
|
||||
}
|
||||
|
||||
std::string ConsoleTableModel::getText(uint32_t column, uint32_t row) const
|
||||
{
|
||||
if(row < rowCount())
|
||||
{
|
||||
const auto& log = m_console.m_logs[row];
|
||||
|
||||
switch(column)
|
||||
{
|
||||
case columnTime:
|
||||
{
|
||||
const std::chrono::time_point<std::chrono::system_clock> time(std::chrono::seconds(log.time_s));
|
||||
const auto tm = std::chrono::system_clock::to_time_t(time);
|
||||
std::string s;
|
||||
s.resize(32);
|
||||
size_t n = strftime(s.data(), s.size(), "%F %T", std::localtime(&tm));
|
||||
n += snprintf(s.data() + n, s.size() - n, ".%06u", log.time_us);
|
||||
s.resize(n);
|
||||
return s;
|
||||
}
|
||||
case columnLevel:
|
||||
return to_string(log.level);
|
||||
|
||||
case columnId:
|
||||
return log.id;
|
||||
|
||||
case columnMessage:
|
||||
return log.message;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void ConsoleTableModel::logAdded()
|
||||
{
|
||||
setRowCount(m_console.m_logs.size());
|
||||
}
|
||||
48
server/src/core/consoletablemodel.hpp
Normale Datei
48
server/src/core/consoletablemodel.hpp
Normale Datei
@ -0,0 +1,48 @@
|
||||
/**
|
||||
* server/src/core/consoletablemodel.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_CONSOLETABLEMODEL_HPP
|
||||
#define SERVER_CORE_CONSOLETABLEMODEL_HPP
|
||||
|
||||
#include "tablemodel.hpp"
|
||||
|
||||
class Console;
|
||||
|
||||
class ConsoleTableModel : public TableModel
|
||||
{
|
||||
friend class Console;
|
||||
|
||||
protected:
|
||||
Console& m_console;
|
||||
|
||||
void logAdded();
|
||||
|
||||
public:
|
||||
CLASS_ID("console_table_model")
|
||||
|
||||
ConsoleTableModel(Console& console);
|
||||
~ConsoleTableModel() final;
|
||||
|
||||
std::string getText(uint32_t column, uint32_t row) const final;
|
||||
};
|
||||
|
||||
#endif
|
||||
120
server/src/core/eventloop.hpp
Normale Datei
120
server/src/core/eventloop.hpp
Normale Datei
@ -0,0 +1,120 @@
|
||||
/**
|
||||
* server/src/core/eventloop.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_EVENTLOOP_HPP
|
||||
#define SERVER_CORE_EVENTLOOP_HPP
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
class EventLoop
|
||||
{
|
||||
private:
|
||||
inline static EventLoop* s_instance;
|
||||
std::queue<std::function<void()>> m_queue;
|
||||
std::mutex m_queueMutex;
|
||||
std::condition_variable m_condition;
|
||||
bool m_run;
|
||||
std::thread m_thread;
|
||||
|
||||
EventLoop() :
|
||||
m_run{true},
|
||||
m_thread(&EventLoop::run, this)
|
||||
{
|
||||
}
|
||||
|
||||
EventLoop(const EventLoop&) = delete;
|
||||
|
||||
~EventLoop()
|
||||
{
|
||||
}
|
||||
|
||||
void add(std::function<void()>&& f)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_queueMutex);
|
||||
m_queue.emplace(f);
|
||||
m_condition.notify_one();
|
||||
}
|
||||
|
||||
void run()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_queueMutex);
|
||||
|
||||
while(m_run)
|
||||
{
|
||||
if(m_queue.empty())
|
||||
m_condition.wait(lock, [this]{ return !m_queue.empty(); });
|
||||
|
||||
if(m_queue.empty())
|
||||
continue; // a suspisius wakeup may occur
|
||||
|
||||
std::function<void()>& f{m_queue.front()};
|
||||
|
||||
lock.unlock();
|
||||
|
||||
try
|
||||
{
|
||||
f();
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
|
||||
lock.lock();
|
||||
|
||||
m_queue.pop();
|
||||
}
|
||||
}
|
||||
|
||||
void exit()
|
||||
{
|
||||
add([this](){ m_run = false; });
|
||||
m_thread.join();
|
||||
}
|
||||
|
||||
public:
|
||||
static void start()
|
||||
{
|
||||
s_instance = new EventLoop();
|
||||
}
|
||||
|
||||
static void stop()
|
||||
{
|
||||
s_instance->exit();
|
||||
delete s_instance;
|
||||
s_instance = nullptr;
|
||||
}
|
||||
|
||||
template<typename _Callable, typename... _Args>
|
||||
inline static void call(_Callable&& __f, _Args&&... __args)
|
||||
{
|
||||
s_instance->add(std::bind(__f, __args...));
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
116
server/src/core/handlelist.hpp
Normale Datei
116
server/src/core/handlelist.hpp
Normale Datei
@ -0,0 +1,116 @@
|
||||
/**
|
||||
* server/src/core/handlelist.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_HANDLELIST_HPP
|
||||
#define SERVER_CORE_HANDLELIST_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
#include <unordered_map>
|
||||
|
||||
template<typename Thandle, typename Titem>
|
||||
class HandleList
|
||||
{
|
||||
public:
|
||||
using Handle = Thandle;
|
||||
|
||||
protected:
|
||||
Handle m_nextHandle;
|
||||
std::unordered_map<Handle, Titem> m_handleToItem;
|
||||
std::unordered_map<Titem, Handle> m_itemToHandle;
|
||||
|
||||
public:
|
||||
static const Handle invalidHandle = 0;
|
||||
|
||||
HandleList() :
|
||||
m_nextHandle{invalidHandle + 1}
|
||||
{
|
||||
}
|
||||
|
||||
Titem getItem(Handle handle) const
|
||||
{
|
||||
auto it = m_handleToItem.find(handle);
|
||||
return it != m_handleToItem.end() ? it->second : nullptr;
|
||||
}
|
||||
|
||||
Handle addItem(const Titem& item)
|
||||
{
|
||||
if(!item)
|
||||
return invalidHandle;
|
||||
|
||||
auto it = m_itemToHandle.find(item);
|
||||
if(it == m_itemToHandle.end())
|
||||
{
|
||||
Handle handle = m_nextHandle;
|
||||
m_handleToItem.emplace(handle, item);
|
||||
m_itemToHandle.emplace(item, handle);
|
||||
assert(m_handleToItem.size() == m_itemToHandle.size());
|
||||
if(++m_nextHandle == invalidHandle)
|
||||
m_nextHandle++;
|
||||
return handle;
|
||||
}
|
||||
else
|
||||
return it->second;
|
||||
}
|
||||
|
||||
Handle getHandle(const Titem& item)
|
||||
{
|
||||
if(item)
|
||||
{
|
||||
auto it = m_itemToHandle.find(item);
|
||||
if(it != m_itemToHandle.end())
|
||||
return it->second;
|
||||
}
|
||||
return invalidHandle;
|
||||
}
|
||||
|
||||
void removeHandle(const Thandle& handle)
|
||||
{
|
||||
auto it = m_handleToItem.find(handle);
|
||||
if(it != m_handleToItem.end())
|
||||
{
|
||||
m_itemToHandle.erase(it->second);
|
||||
m_handleToItem.erase(it);
|
||||
assert(m_handleToItem.size() == m_itemToHandle.size());
|
||||
}
|
||||
}
|
||||
|
||||
void removeItem(const Titem& item)
|
||||
{
|
||||
auto it = m_itemToHandle.find(item);
|
||||
if(it != m_itemToHandle.end())
|
||||
{
|
||||
m_handleToItem.erase(it->second);
|
||||
m_itemToHandle.erase(it);
|
||||
assert(m_handleToItem.size() == m_itemToHandle.size());
|
||||
}
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_handleToItem.clear();
|
||||
m_itemToHandle.clear();
|
||||
assert(m_handleToItem.size() == m_itemToHandle.size());
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
28
server/src/core/idobject.cpp
Normale Datei
28
server/src/core/idobject.cpp
Normale Datei
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Traintastic
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra <reinderfeenstra@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "idobject.hpp"
|
||||
|
||||
IdObject::IdObject(const std::string& _id) :
|
||||
Object{},
|
||||
id{this, "id", _id, PropertyFlags::AccessWCC}
|
||||
{
|
||||
m_interfaceItems.add(id);
|
||||
}
|
||||
37
server/src/core/idobject.hpp
Normale Datei
37
server/src/core/idobject.hpp
Normale Datei
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* server/src/core/idobject.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_IDOBJECT_HPP
|
||||
#define SERVER_CORE_IDOBJECT_HPP
|
||||
|
||||
#include "object.hpp"
|
||||
#include "property.hpp"
|
||||
|
||||
class IdObject : public Object
|
||||
{
|
||||
public:
|
||||
Property<std::string> id;
|
||||
|
||||
IdObject(const std::string& _id);
|
||||
};
|
||||
|
||||
#endif
|
||||
58
server/src/core/interfaceitem.hpp
Normale Datei
58
server/src/core/interfaceitem.hpp
Normale Datei
@ -0,0 +1,58 @@
|
||||
/**
|
||||
* server/src/core/interfaceitem.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_INTERFACEITEM_HPP
|
||||
#define SERVER_CORE_INTERFACEITEM_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
class Object;
|
||||
|
||||
class InterfaceItem
|
||||
{
|
||||
protected:
|
||||
Object& m_object;
|
||||
const std::string m_name;
|
||||
|
||||
public:
|
||||
InterfaceItem(Object& object, const std::string& name) :
|
||||
m_object{object},
|
||||
m_name{name}
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~InterfaceItem()
|
||||
{
|
||||
}
|
||||
|
||||
Object& object() const
|
||||
{
|
||||
return m_object;
|
||||
}
|
||||
|
||||
const std::string& name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
29
server/src/core/interfaceitems.cpp
Normale Datei
29
server/src/core/interfaceitems.cpp
Normale Datei
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* server/src/core/interfaceitems.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "interfaceitems.hpp"
|
||||
#include "interfaceitem.hpp"
|
||||
|
||||
void InterfaceItems::add(InterfaceItem& item)
|
||||
{
|
||||
emplace(item.name(), item);
|
||||
}
|
||||
37
server/src/core/interfaceitems.hpp
Normale Datei
37
server/src/core/interfaceitems.hpp
Normale Datei
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* server/src/core/interfaceitems.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_INTERFACEITEMS_HPP
|
||||
#define SERVER_CORE_INTERFACEITEMS_HPP
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class InterfaceItem;
|
||||
|
||||
class InterfaceItems : public std::map<std::string, InterfaceItem&>
|
||||
{
|
||||
public:
|
||||
void add(InterfaceItem& item);
|
||||
};
|
||||
|
||||
#endif
|
||||
56
server/src/core/object.cpp
Normale Datei
56
server/src/core/object.cpp
Normale Datei
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* server/src/core/object.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "object.hpp"
|
||||
//#include "abstractmethod.hpp"
|
||||
#include "abstractproperty.hpp"
|
||||
|
||||
Object::Object()
|
||||
{
|
||||
}
|
||||
|
||||
Object::~Object()
|
||||
{
|
||||
}
|
||||
|
||||
InterfaceItem* Object::getItem(const std::string& name)
|
||||
{
|
||||
auto it = m_interfaceItems.find(name);
|
||||
return (it != m_interfaceItems.end()) ? &it->second : nullptr;
|
||||
}
|
||||
|
||||
//AbstractMethod* Object::getMethod(const std::string& name)
|
||||
//{
|
||||
// return dynamic_cast<AbstractMethod*>(getItem(name));
|
||||
//}
|
||||
|
||||
AbstractProperty* Object::getProperty(const std::string& name)
|
||||
{
|
||||
return dynamic_cast<AbstractProperty*>(getItem(name));
|
||||
}
|
||||
|
||||
//void Object::log(LogLevel level, const std::string& message) const
|
||||
//{
|
||||
// auto p = m_instance.lock();
|
||||
// if(p)
|
||||
// p->consoleLog(level, message);
|
||||
//}
|
||||
67
server/src/core/object.hpp
Normale Datei
67
server/src/core/object.hpp
Normale Datei
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* server/src/core/object.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_OBJECT_HPP
|
||||
#define SERVER_CORE_OBJECT_HPP
|
||||
|
||||
#include "objectptr.hpp"
|
||||
#include <boost/signals2/signal.hpp>
|
||||
#include "interfaceitems.hpp"
|
||||
|
||||
#define CLASS_ID(id) \
|
||||
public: \
|
||||
static constexpr std::string_view classId = id; \
|
||||
const std::string_view& getClassId() const override { return classId; }
|
||||
|
||||
class AbstractMethod;
|
||||
class AbstractProperty;
|
||||
|
||||
class Object : public std::enable_shared_from_this<Object>
|
||||
{
|
||||
protected:
|
||||
InterfaceItems m_interfaceItems;
|
||||
|
||||
//void log(LogLevel level, const std::string& message) const;
|
||||
//inline void logError(const std::string& message) const { log(LogLevel::Error, message); }
|
||||
|
||||
public:
|
||||
boost::signals2::signal<void (Object& object, AbstractProperty&)> propertyChanged;
|
||||
|
||||
Object();
|
||||
virtual ~Object();
|
||||
|
||||
template <typename Derived>
|
||||
std::shared_ptr<Derived> shared_ptr()
|
||||
{
|
||||
return std::static_pointer_cast<Derived>(shared_from_this());
|
||||
}
|
||||
|
||||
virtual const std::string_view& getClassId() const = 0;
|
||||
|
||||
const InterfaceItems& interfaceItems() const { return m_interfaceItems; }
|
||||
|
||||
InterfaceItem* getItem(const std::string& name);
|
||||
//AbstractMethod* getMethod(const std::string& name);
|
||||
AbstractProperty* getProperty(const std::string& name);
|
||||
};
|
||||
|
||||
#endif
|
||||
68
server/src/core/objectlist.hpp
Normale Datei
68
server/src/core/objectlist.hpp
Normale Datei
@ -0,0 +1,68 @@
|
||||
/**
|
||||
* server/src/core/objectlist.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_OBJECTLIST_HPP
|
||||
#define SERVER_CORE_OBJECTLIST_HPP
|
||||
|
||||
#include "idobject.hpp"
|
||||
#include "table.hpp"
|
||||
|
||||
template<typename T>
|
||||
class ObjectListTableModel;
|
||||
|
||||
template<typename T>
|
||||
class ObjectList : public IdObject, public Table
|
||||
{
|
||||
friend class ObjectListTableModel<T>;
|
||||
|
||||
static_assert(std::is_base_of<IdObject, T>::value);
|
||||
|
||||
protected:
|
||||
std::vector<std::shared_ptr<T>> m_items;
|
||||
std::vector<ObjectListTableModel<T>*> m_models;
|
||||
|
||||
public:
|
||||
Property<uint32_t> length;
|
||||
|
||||
ObjectList(const std::string& _id) :
|
||||
IdObject{_id},
|
||||
length{this, "length", 0, PropertyFlags::AccessRRR}
|
||||
{
|
||||
}
|
||||
|
||||
const std::shared_ptr<T>& operator[](uint32_t index)
|
||||
{
|
||||
assert(index < m_items.size());
|
||||
return m_items[index];
|
||||
}
|
||||
|
||||
void add(const std::shared_ptr<T>& object)
|
||||
{
|
||||
m_items.push_back(object);
|
||||
const auto size = m_items.size();
|
||||
length = size;
|
||||
for(auto& model : m_models)
|
||||
model->setRowCount(size);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
55
server/src/core/objectlisttablemodel.hpp
Normale Datei
55
server/src/core/objectlisttablemodel.hpp
Normale Datei
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* server/src/core/objectlisttablemodel.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_OBJECTLISTTABLEMODEL_HPP
|
||||
#define SERVER_CORE_OBJECTLISTTABLEMODEL_HPP
|
||||
|
||||
#include "tablemodel.hpp"
|
||||
#include "objectlist.hpp"
|
||||
|
||||
template<typename T>
|
||||
class ObjectListTableModel : public TableModel
|
||||
{
|
||||
protected:
|
||||
ObjectList<T>& m_list;
|
||||
|
||||
const T& getItem(uint32_t row) const { return *m_list.m_items[row]; }
|
||||
//T& getItem(uint32_t row) { return *m_list.m_items[row]; }
|
||||
|
||||
public:
|
||||
ObjectListTableModel(ObjectList<T>& list) :
|
||||
TableModel(),
|
||||
m_list{list}
|
||||
{
|
||||
m_list.m_models.push_back(this);
|
||||
setRowCount(m_list.m_items.size());
|
||||
}
|
||||
|
||||
~ObjectListTableModel() override
|
||||
{
|
||||
auto it = std::find(m_list.m_models.begin(), m_list.m_models.end(), this);
|
||||
assert(it != m_list.m_models.end());
|
||||
m_list.m_models.erase(it);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
164
server/src/core/objectproperty.hpp
Normale Datei
164
server/src/core/objectproperty.hpp
Normale Datei
@ -0,0 +1,164 @@
|
||||
/**
|
||||
* server/src/core/objectproperty.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_OBJECTPROPERTY_HPP
|
||||
#define SERVER_CORE_OBJECTPROPERTY_HPP
|
||||
|
||||
#include "abstractproperty.hpp"
|
||||
#include "to.hpp"
|
||||
#include <functional>
|
||||
|
||||
template<class T>
|
||||
class ObjectProperty : public AbstractProperty
|
||||
{
|
||||
public:
|
||||
using OnSet = std::function<bool(const std::shared_ptr<T>& value)>;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<T> m_value;
|
||||
OnSet m_onSet;
|
||||
|
||||
public:
|
||||
ObjectProperty(Object* object, const std::string& name, const std::shared_ptr<T>& value, PropertyFlags flags) :
|
||||
AbstractProperty(*object, name, PropertyType::Object, flags),
|
||||
m_value{value}
|
||||
{
|
||||
}
|
||||
|
||||
ObjectProperty(Object* object, const std::string& name, nullptr_t, PropertyFlags flags) :
|
||||
ObjectProperty(object, name, std::shared_ptr<T>(), flags)
|
||||
{
|
||||
}
|
||||
|
||||
ObjectProperty(Object* object, const std::string& name, const std::shared_ptr<T>& value, PropertyFlags flags, OnSet onSet) :
|
||||
ObjectProperty(object, name, value, flags)
|
||||
{
|
||||
m_onSet = onSet;
|
||||
}
|
||||
|
||||
ObjectProperty(Object* object, const std::string& name, nullptr_t, PropertyFlags flags, OnSet onSet) :
|
||||
ObjectProperty(object, name, std::shared_ptr<T>(), flags, onSet)
|
||||
{
|
||||
}
|
||||
|
||||
const std::shared_ptr<T>& value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void setValue(const std::shared_ptr<T>& value)
|
||||
{
|
||||
assert(isWriteable());
|
||||
if(isWriteable() && m_value != value)
|
||||
{
|
||||
m_value = value;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
inline const T* operator ->() const
|
||||
{
|
||||
return m_value.get();
|
||||
}
|
||||
|
||||
inline T* operator ->()
|
||||
{
|
||||
return m_value.get();
|
||||
}
|
||||
|
||||
inline const T& operator *() const
|
||||
{
|
||||
return *m_value;
|
||||
}
|
||||
|
||||
inline T& operator *()
|
||||
{
|
||||
return *m_value;
|
||||
}
|
||||
|
||||
ObjectProperty<T>& operator =(const std::shared_ptr<T>& value)
|
||||
{
|
||||
setValue(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool toBool() const final
|
||||
{
|
||||
throw conversion_error();
|
||||
}
|
||||
|
||||
int64_t toInt64() const final
|
||||
{
|
||||
throw conversion_error();
|
||||
}
|
||||
|
||||
double toDouble() const final
|
||||
{
|
||||
throw conversion_error();
|
||||
}
|
||||
|
||||
std::string toString() const final
|
||||
{
|
||||
throw conversion_error();
|
||||
}
|
||||
|
||||
ObjectPtr toObject() const final
|
||||
{
|
||||
return std::dynamic_pointer_cast<Object>(m_value);
|
||||
}
|
||||
|
||||
void fromBool(bool value) final
|
||||
{
|
||||
throw conversion_error();
|
||||
}
|
||||
|
||||
void fromInt64(int64_t value) final
|
||||
{
|
||||
throw conversion_error();
|
||||
}
|
||||
|
||||
void fromDouble(double value) final
|
||||
{
|
||||
throw conversion_error();
|
||||
}
|
||||
|
||||
void fromString(const std::string& value) final
|
||||
{
|
||||
throw conversion_error();
|
||||
}
|
||||
|
||||
void fromObject(const ObjectPtr& value) final
|
||||
{
|
||||
if(value)
|
||||
{
|
||||
std::shared_ptr<T> v = std::dynamic_pointer_cast<T>(value);
|
||||
if(v)
|
||||
setValue(v);
|
||||
else
|
||||
throw conversion_error();
|
||||
}
|
||||
else
|
||||
setValue(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
33
server/src/core/objectptr.hpp
Normale Datei
33
server/src/core/objectptr.hpp
Normale Datei
@ -0,0 +1,33 @@
|
||||
/**
|
||||
* server/src/core/objectptr.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_OBJECTPTR_HPP
|
||||
#define SERVER_CORE_OBJECTPTR_HPP
|
||||
|
||||
#include <memory>
|
||||
|
||||
class Object;
|
||||
|
||||
using ObjectPtr = std::shared_ptr<Object>;
|
||||
using ObjectPtrWeak = std::weak_ptr<Object>;
|
||||
|
||||
#endif
|
||||
28
server/src/core/output.cpp
Normale Datei
28
server/src/core/output.cpp
Normale Datei
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Traintastic
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra <reinderfeenstra@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "output.hpp"
|
||||
|
||||
Output::Output(const std::string& _id) :
|
||||
IdObject{_id},
|
||||
value{this, "value", false, PropertyFlags::AccessWWW}
|
||||
{
|
||||
m_interfaceItems.add(value);
|
||||
}
|
||||
36
server/src/core/output.hpp
Normale Datei
36
server/src/core/output.hpp
Normale Datei
@ -0,0 +1,36 @@
|
||||
/**
|
||||
* server/src/core/output.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_OUTPUT_HPP
|
||||
#define SERVER_CORE_OUTPUT_HPP
|
||||
|
||||
#include "idobject.hpp"
|
||||
|
||||
class Output : public IdObject
|
||||
{
|
||||
public:
|
||||
Property<bool> value;
|
||||
|
||||
Output(const std::string& _id);
|
||||
};
|
||||
|
||||
#endif
|
||||
140
server/src/core/property.hpp
Normale Datei
140
server/src/core/property.hpp
Normale Datei
@ -0,0 +1,140 @@
|
||||
/**
|
||||
* server/src/core/property.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_PROPERTY_HPP
|
||||
#define SERVER_CORE_PROPERTY_HPP
|
||||
|
||||
#include "abstractproperty.hpp"
|
||||
#include "propertytypetraits.hpp"
|
||||
#include "to.hpp"
|
||||
#include <functional>
|
||||
|
||||
template<typename T>
|
||||
class Property : public AbstractProperty
|
||||
{
|
||||
public:
|
||||
using OnChanged = std::function<void(const T& value)>;
|
||||
using OnSet = std::function<bool(T& value)>;
|
||||
|
||||
protected:
|
||||
T m_value;
|
||||
OnChanged m_onChanged;
|
||||
OnSet m_onSet;
|
||||
|
||||
public:
|
||||
Property(Object* object, const std::string& name, const T& value, PropertyFlags flags) :
|
||||
AbstractProperty(*object, name, property_type<T>::value, flags),
|
||||
m_value{value}
|
||||
{
|
||||
//static_assert(property_type<T>::value != PropertyType::Invalid);
|
||||
}
|
||||
|
||||
Property(Object* object, const std::string& name, const T& value, PropertyFlags flags, OnChanged onChanged) :
|
||||
Property(object, name, value, flags)
|
||||
{
|
||||
m_onChanged = onChanged;
|
||||
}
|
||||
|
||||
Property(Object* object, const std::string& name, const T& value, PropertyFlags flags, OnSet onSet) :
|
||||
Property(object, name, value, flags)
|
||||
{
|
||||
m_onSet = onSet;
|
||||
}
|
||||
|
||||
T value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void setValue(T value)
|
||||
{
|
||||
assert(isWriteable());
|
||||
if(isWriteable() && (!m_onSet || m_onSet(value)) && m_value != value)
|
||||
{
|
||||
m_value = value;
|
||||
changed();
|
||||
}
|
||||
}
|
||||
|
||||
operator T() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
Property<T>& operator =(const T& value)
|
||||
{
|
||||
setValue(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool toBool() const final
|
||||
{
|
||||
return to<bool>(m_value);
|
||||
}
|
||||
|
||||
int64_t toInt64() const final
|
||||
{
|
||||
return to<int64_t>(m_value);
|
||||
}
|
||||
|
||||
double toDouble() const final
|
||||
{
|
||||
return to<double>(m_value);
|
||||
}
|
||||
|
||||
std::string toString() const final
|
||||
{
|
||||
return to<std::string>(m_value);
|
||||
}
|
||||
|
||||
ObjectPtr toObject() const final
|
||||
{
|
||||
throw conversion_error();
|
||||
}
|
||||
|
||||
void fromBool(bool value) final
|
||||
{
|
||||
setValue(to<T>(value));
|
||||
}
|
||||
|
||||
void fromInt64(int64_t value) final
|
||||
{
|
||||
setValue(to<T>(value));
|
||||
}
|
||||
|
||||
void fromDouble(double value) final
|
||||
{
|
||||
setValue(to<T>(value));
|
||||
}
|
||||
|
||||
void fromString(const std::string& value) final
|
||||
{
|
||||
setValue(to<T>(value));
|
||||
}
|
||||
|
||||
void fromObject(const ObjectPtr& value) final
|
||||
{
|
||||
throw conversion_error();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
94
server/src/core/propertyflags.hpp
Normale Datei
94
server/src/core/propertyflags.hpp
Normale Datei
@ -0,0 +1,94 @@
|
||||
/**
|
||||
* server/src/core/propertyflags.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_PROPERTYFLAGS_HPP
|
||||
#define SERVER_CORE_PROPERTYFLAGS_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class PropertyFlags : uint32_t
|
||||
{
|
||||
// Access:
|
||||
EditConstant = 1 << 0,
|
||||
EditReadOnly = 2 << 0,
|
||||
EditReadWrite = 3 << 0,
|
||||
StopConstant = 1 << 2,
|
||||
StopReadOnly = 2 << 2,
|
||||
StopReadWrite = 3 << 2,
|
||||
RunConstant = 1 << 4,
|
||||
RunReadOnly = 2 << 4,
|
||||
RunReadWrite = 3 << 4,
|
||||
|
||||
AccessRRR = PropertyFlags::EditReadOnly | PropertyFlags::StopReadOnly | PropertyFlags::RunReadOnly,
|
||||
AccessRRW = PropertyFlags::EditReadOnly | PropertyFlags::StopReadOnly | PropertyFlags::RunReadWrite,
|
||||
AccessRWW = PropertyFlags::EditReadOnly | PropertyFlags::StopReadWrite | PropertyFlags::RunReadWrite,
|
||||
AccessWCC = PropertyFlags::EditReadWrite | PropertyFlags::StopConstant | PropertyFlags::RunConstant,
|
||||
AccessWWW = PropertyFlags::EditReadWrite | PropertyFlags::StopReadWrite | PropertyFlags::RunReadWrite,
|
||||
// Store:
|
||||
NoStore = 1 << 6,
|
||||
Store = 2 << 6,
|
||||
StoreState = 3 << 6,
|
||||
};
|
||||
|
||||
constexpr PropertyFlags operator| (const PropertyFlags& lhs, const PropertyFlags& rhs)
|
||||
{
|
||||
return static_cast<PropertyFlags>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs));
|
||||
}
|
||||
|
||||
constexpr PropertyFlags& operator|= (PropertyFlags& lhs, const PropertyFlags& rhs)
|
||||
{
|
||||
return lhs = lhs | rhs;
|
||||
}
|
||||
|
||||
constexpr PropertyFlags operator& (const PropertyFlags& lhs, const PropertyFlags& rhs)
|
||||
{
|
||||
return static_cast<PropertyFlags>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs));
|
||||
}
|
||||
|
||||
constexpr PropertyFlags& operator&= (PropertyFlags& lhs, const PropertyFlags& rhs)
|
||||
{
|
||||
return lhs = lhs & rhs;
|
||||
}
|
||||
|
||||
constexpr bool is_empty(const PropertyFlags value)
|
||||
{
|
||||
return value == static_cast<PropertyFlags>(0);
|
||||
}
|
||||
|
||||
//constexpr PropertyFlags PropertyFlagsAccessMask = PropertyFlags::Constant | PropertyFlags::ReadOnly | PropertyFlags::WriteOnly;
|
||||
//constexpr PropertyFlags PropertyFlagsStoreMask = PropertyFlags::NoStore | PropertyFlags::Store | PropertyFlags::StoreState;
|
||||
|
||||
constexpr bool is_access_valid(const PropertyFlags value)
|
||||
{
|
||||
return true;
|
||||
//const PropertyFlags access = value & PropertyFlagsAccessMask;
|
||||
//return (access == PropertyFlags::Constant) || !is_empty(access & PropertyFlags::ReadWrite);
|
||||
}
|
||||
|
||||
constexpr bool is_store_valid(const PropertyFlags value)
|
||||
{
|
||||
return true;
|
||||
//const PropertyFlags store = value & PropertyFlagsStoreMask;
|
||||
//return (store == PropertyFlags::NoStore) || (store == PropertyFlags::Store) || (store == PropertyFlags::StoreState);
|
||||
}
|
||||
|
||||
#endif
|
||||
40
server/src/core/propertytypetraits.hpp
Normale Datei
40
server/src/core/propertytypetraits.hpp
Normale Datei
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* server/src/core/propertytypetraits.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_PROPERTYTYPETRAITS_HPP
|
||||
#define SERVER_CORE_PROPERTYTYPETRAITS_HPP
|
||||
|
||||
#include <enum/propertytype.hpp>
|
||||
#include "objectptr.hpp"
|
||||
|
||||
template<typename T>
|
||||
struct property_type
|
||||
{
|
||||
static constexpr PropertyType value =
|
||||
std::is_same<T, bool>::value ? PropertyType::Boolean : (
|
||||
std::is_integral<T>::value ? PropertyType::Integer : (
|
||||
std::is_floating_point<T>::value ? PropertyType::Float : (
|
||||
std::is_same<T, std::string>::value ? PropertyType::String : (
|
||||
PropertyType::Invalid))));
|
||||
};
|
||||
|
||||
#endif
|
||||
318
server/src/core/session.cpp
Normale Datei
318
server/src/core/session.cpp
Normale Datei
@ -0,0 +1,318 @@
|
||||
/**
|
||||
* server/src/core/session.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "session.hpp"
|
||||
#include <boost/uuid/random_generator.hpp>
|
||||
#include "traintastic.hpp"
|
||||
#include "client.hpp"
|
||||
#include "abstractproperty.hpp"
|
||||
#include <enum/interfaceitemtype.hpp>
|
||||
#include "tablemodel.hpp"
|
||||
#include "world.hpp"
|
||||
|
||||
#include "settings.hpp"
|
||||
|
||||
#include "../hardware/commandstation/commandstationlist.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
Session::Session(const std::shared_ptr<Client>& client) :
|
||||
m_client{client},
|
||||
m_uuid{boost::uuids::random_generator()()}
|
||||
{
|
||||
}
|
||||
|
||||
bool Session::processMessage(const Message& message)
|
||||
{
|
||||
switch(message.command())
|
||||
{
|
||||
case Message::Command::GetObject:
|
||||
case Message::Command::GetTableModel:
|
||||
{
|
||||
std::string id;
|
||||
message.read(id);
|
||||
|
||||
ObjectPtr obj;
|
||||
if(id == "console")
|
||||
obj = Traintastic::instance->console.toObject();
|
||||
else if(id == "settings")
|
||||
obj = Traintastic::instance->settings.toObject();
|
||||
else if(id == "command_station_list")
|
||||
obj = Traintastic::instance->world->commandStationList;
|
||||
|
||||
if(obj)
|
||||
{
|
||||
switch(message.command())
|
||||
{
|
||||
case Message::Command::GetObject:
|
||||
{
|
||||
Traintastic::instance->console->debug(m_client->m_id, "GetObject: " + id);
|
||||
auto response = Message::newResponse(message.command(), message.requestId());
|
||||
writeObject(*response, obj);
|
||||
m_client->sendMessage(std::move(response));
|
||||
break;
|
||||
}
|
||||
case Message::Command::GetTableModel:
|
||||
{
|
||||
if(Table* table = dynamic_cast<Table*>(obj.get()))
|
||||
{
|
||||
TableModelPtr model = table->getModel();
|
||||
assert(model);
|
||||
Traintastic::instance->console->debug(m_client->m_id, "GetTableModel: " + id);
|
||||
auto response = Message::newResponse(message.command(), message.requestId());
|
||||
writeTableModel(*response, model);
|
||||
m_client->sendMessage(std::move(response));
|
||||
|
||||
model->columnHeadersChanged = [this](const TableModelPtr& model)
|
||||
{
|
||||
auto event = Message::newEvent(Message::Command::TableModelColumnHeadersChanged);
|
||||
event->write(m_handles.getHandle(std::dynamic_pointer_cast<Object>(model)));
|
||||
event->write(model->columnCount());
|
||||
for(const std::string& text : model->columnHeaders())
|
||||
event->write(text);
|
||||
m_client->sendMessage(std::move(event));
|
||||
};
|
||||
|
||||
model->rowCountChanged = [this](const TableModelPtr& model)
|
||||
{
|
||||
auto event = Message::newEvent(Message::Command::TableModelRowCountChanged);
|
||||
event->write(m_handles.getHandle(std::dynamic_pointer_cast<Object>(model)));
|
||||
event->write(model->rowCount());
|
||||
m_client->sendMessage(std::move(event));
|
||||
};
|
||||
|
||||
model->updateRegion = [this](const TableModelPtr& model, const TableModel::Region& region)
|
||||
{
|
||||
std::cout << "updateRegion " << region.columnMin << " " << region.columnMax << " " << region.rowMin << " " << region.rowMax << std::endl;
|
||||
|
||||
auto event = Message::newEvent(Message::Command::TableModelUpdateRegion);
|
||||
event->write(m_handles.getHandle(std::dynamic_pointer_cast<Object>(model)));
|
||||
event->write(region.columnMin);
|
||||
event->write(region.columnMax);
|
||||
event->write(region.rowMin);
|
||||
event->write(region.rowMax);
|
||||
|
||||
for(uint32_t row = region.rowMin; row <= region.rowMax; row++)
|
||||
for(uint32_t column = region.columnMin; column <= region.columnMax; column++)
|
||||
event->write(model->getText(column, row));
|
||||
|
||||
m_client->sendMessage(std::move(event));
|
||||
};
|
||||
/*
|
||||
void TableModel::sendRegion(uint32_t columnMin, uint32_t columnMax, uint32_t rowMin, uint32_t rowMax)
|
||||
{
|
||||
auto event = Message::newEvent(Message::Command::TableModelUpdateRegion);
|
||||
event->write(m_handle);
|
||||
|
||||
for(uint32_t row = rowMin; row <= rowMax; row++)
|
||||
for(uint32_t column = columnMin; column <= columnMax; column++)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
else
|
||||
m_client->sendMessage(Message::newErrorResponse(message.command(), message.requestId(), Message::ErrorCode::ObjectNotTable));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Traintastic::instance->console->debug(m_client->m_id, "UnknownObject: " + id);
|
||||
m_client->sendMessage(Message::newErrorResponse(message.command(), message.requestId(), Message::ErrorCode::UnknownObject));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case Message::Command::ReleaseObject:
|
||||
{
|
||||
Handle handle = message.read<Handle>();
|
||||
Traintastic::instance->console->debug(m_client->m_id, "ReleaseObject: " + std::to_string(handle));
|
||||
m_handles.removeHandle(handle);
|
||||
break;
|
||||
}
|
||||
case Message::Command::ObjectSetProperty:
|
||||
{
|
||||
if(ObjectPtr object = m_handles.getItem(message.read<Handle>()))
|
||||
{
|
||||
if(AbstractProperty* property = object->getProperty(message.read<std::string>()))
|
||||
{
|
||||
switch(message.read<PropertyType>())
|
||||
{
|
||||
case PropertyType::Boolean:
|
||||
property->fromBool(message.read<bool>());
|
||||
break;
|
||||
|
||||
case PropertyType::Integer:
|
||||
property->fromInt64(message.read<int64_t>());
|
||||
break;
|
||||
|
||||
case PropertyType::Float:
|
||||
property->fromDouble(message.read<double>());
|
||||
break;
|
||||
|
||||
case PropertyType::String:
|
||||
property->fromString(message.read<std::string>());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Message::Command::ReleaseTableModel:
|
||||
{
|
||||
Handle handle = message.read<Handle>();
|
||||
Traintastic::instance->console->debug(m_client->m_id, "ReleaseTableModel: " + std::to_string(handle));
|
||||
m_handles.removeHandle(handle);
|
||||
break;
|
||||
}
|
||||
case Message::Command::TableModelSetRegion:
|
||||
{
|
||||
TableModelPtr model = std::dynamic_pointer_cast<TableModel>(m_handles.getItem(message.read<Handle>()));
|
||||
if(model)
|
||||
{
|
||||
TableModel::Region region;
|
||||
message.read(region.columnMin);
|
||||
message.read(region.columnMax);
|
||||
message.read(region.rowMin);
|
||||
message.read(region.rowMax);
|
||||
//std::cout << "TableModelSetRegion " << region.columnMin << " " << region.columnMax << " " << region.rowMin << " " << region.rowMax << std::endl;
|
||||
model->setRegion(region);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Session::writeObject(Message& message, const ObjectPtr& object)
|
||||
{
|
||||
message.writeBlock(); // object
|
||||
|
||||
auto handle = m_handles.getHandle(object);
|
||||
if(handle == Handles::invalidHandle)
|
||||
{
|
||||
using namespace std::placeholders;
|
||||
|
||||
handle = m_handles.addItem(object);
|
||||
|
||||
m_propertyChanged.emplace(handle, object->propertyChanged.connect(std::bind(&Session::objectPropertyChanged, this, std::placeholders::_1, std::placeholders::_2)));
|
||||
|
||||
message.write(handle);
|
||||
message.write(object->getClassId());
|
||||
|
||||
message.writeBlock(); // items
|
||||
for(auto& it : object->interfaceItems())
|
||||
{
|
||||
InterfaceItem& item = it.second;
|
||||
|
||||
message.writeBlock(); // item
|
||||
message.write(item.name());
|
||||
|
||||
if(AbstractProperty* property = dynamic_cast<AbstractProperty*>(&item))
|
||||
{
|
||||
message.write(InterfaceItemType::Property);
|
||||
message.write(property->type());
|
||||
switch(property->type())
|
||||
{
|
||||
case PropertyType::Boolean:
|
||||
message.write(property->toBool());
|
||||
break;
|
||||
|
||||
case PropertyType::Integer:
|
||||
message.write(property->toInt64());
|
||||
break;
|
||||
|
||||
case PropertyType::Float:
|
||||
message.write(property->toDouble());
|
||||
break;
|
||||
|
||||
case PropertyType::String:
|
||||
message.write(property->toString());
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
message.writeBlockEnd(); // end item
|
||||
}
|
||||
message.writeBlockEnd(); // end items
|
||||
}
|
||||
else
|
||||
message.write(handle);
|
||||
|
||||
message.writeBlockEnd(); // end object
|
||||
}
|
||||
|
||||
void Session::writeTableModel(Message& message, const TableModelPtr& model)
|
||||
{
|
||||
message.writeBlock(); // model
|
||||
assert(m_handles.getHandle(std::dynamic_pointer_cast<Object>(model)) == Handles::invalidHandle);
|
||||
auto handle = m_handles.addItem(std::dynamic_pointer_cast<Object>(model));
|
||||
message.write(handle);
|
||||
message.write(model->getClassId());
|
||||
message.write(model->columnCount());
|
||||
for(const std::string& text : model->columnHeaders())
|
||||
message.write(text);
|
||||
message.write(model->rowCount());
|
||||
message.writeBlockEnd(); // end model
|
||||
}
|
||||
|
||||
void Session::objectPropertyChanged(Object& object, AbstractProperty& property)
|
||||
{
|
||||
std::cout << "objectPropertyChanged " << property.name() << std::endl;
|
||||
|
||||
auto event = Message::newEvent(Message::Command::ObjectPropertyChanged);
|
||||
event->write(m_handles.getHandle(object.shared_from_this()));
|
||||
event->write(property.name());
|
||||
event->write(property.type());
|
||||
switch(property.type())
|
||||
{
|
||||
case PropertyType::Boolean:
|
||||
event->write(property.toBool());
|
||||
break;
|
||||
|
||||
case PropertyType::Integer:
|
||||
event->write(property.toInt64());
|
||||
break;
|
||||
|
||||
case PropertyType::Float:
|
||||
event->write(property.toDouble());
|
||||
break;
|
||||
|
||||
case PropertyType::String:
|
||||
event->write(property.toString());
|
||||
break;
|
||||
}
|
||||
m_client->sendMessage(std::move(event));
|
||||
}
|
||||
63
server/src/core/session.hpp
Normale Datei
63
server/src/core/session.hpp
Normale Datei
@ -0,0 +1,63 @@
|
||||
/**
|
||||
* server/src/core/session.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_SESSION_HPP
|
||||
#define SERVER_CORE_SESSION_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/signals2/connection.hpp>
|
||||
#include <message.hpp>
|
||||
#include "handlelist.hpp"
|
||||
#include "objectptr.hpp"
|
||||
#include "tablemodelptr.hpp"
|
||||
|
||||
class Client;
|
||||
class AbstractProperty;
|
||||
|
||||
class Session : public std::enable_shared_from_this<Session>
|
||||
{
|
||||
friend class Client;
|
||||
|
||||
protected:
|
||||
using Handle = uint32_t;
|
||||
using Handles = HandleList<Handle, ObjectPtr>;
|
||||
|
||||
std::shared_ptr<Client> m_client;
|
||||
boost::uuids::uuid m_uuid;
|
||||
Handles m_handles;
|
||||
std::unordered_map<Handle, boost::signals2::connection> m_propertyChanged;
|
||||
|
||||
bool processMessage(const Message& message);
|
||||
|
||||
void writeObject(Message& message, const ObjectPtr& object);
|
||||
void writeTableModel(Message& message, const TableModelPtr& model);
|
||||
|
||||
void objectPropertyChanged(Object& object, AbstractProperty& property);
|
||||
|
||||
public:
|
||||
Session(const std::shared_ptr<Client>& client);
|
||||
|
||||
const boost::uuids::uuid& uuid() const { return m_uuid; }
|
||||
};
|
||||
|
||||
#endif
|
||||
84
server/src/core/settings.cpp
Normale Datei
84
server/src/core/settings.cpp
Normale Datei
@ -0,0 +1,84 @@
|
||||
/**
|
||||
* server/src/core/settings.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "settings.hpp"
|
||||
#include <fstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "traintastic.hpp"
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
const std::string Settings::id{Settings::classId};
|
||||
|
||||
Settings::Settings(const std::filesystem::path& filename) :
|
||||
Object{},
|
||||
m_filename{filename},
|
||||
localhostOnly{this, "localhost_only", true, PropertyFlags::AccessWCC},
|
||||
port{this, "port", defaultPort, PropertyFlags::AccessWCC},
|
||||
discoverable{this, "discoverable", true, PropertyFlags::AccessWWW},
|
||||
defaultWorld{this, "default_world", "", PropertyFlags::AccessWWW}
|
||||
{
|
||||
m_interfaceItems.add(localhostOnly);
|
||||
m_interfaceItems.add(port);
|
||||
m_interfaceItems.add(discoverable);
|
||||
m_interfaceItems.add(defaultWorld);
|
||||
|
||||
load();
|
||||
}
|
||||
|
||||
void Settings::load()
|
||||
{
|
||||
std::ifstream file(m_filename);
|
||||
if(file.is_open())
|
||||
{
|
||||
Traintastic::instance->console->debug(id, "Settings file: " + m_filename.string());
|
||||
json settings = json::parse(file);
|
||||
for(auto& [name, value] : settings.items())
|
||||
{
|
||||
AbstractProperty* property = getProperty(name);
|
||||
if(property)
|
||||
property->fromJSON(value);
|
||||
else
|
||||
Traintastic::instance->console->warning(id, "Setting `" + name + "` doesn't exist");
|
||||
}
|
||||
Traintastic::instance->console->info(id, "Loaded settings");
|
||||
}
|
||||
else
|
||||
Traintastic::instance->console->info(id, "Settings file not found, using defaults");
|
||||
}
|
||||
|
||||
void Settings::save()
|
||||
{
|
||||
json settings = json::object();
|
||||
for(const auto& it : m_interfaceItems)
|
||||
if(AbstractProperty* property = dynamic_cast<AbstractProperty*>(&it.second))
|
||||
settings[property->name()] = property->toJSON();
|
||||
|
||||
std::ofstream file(m_filename);
|
||||
if(file.is_open())
|
||||
{
|
||||
file << settings.dump(2);
|
||||
Traintastic::instance->console->notice(id, "Saved settings");
|
||||
}
|
||||
else
|
||||
Traintastic::instance->console->critical(id, "Can't write to settings file");
|
||||
}
|
||||
53
server/src/core/settings.hpp
Normale Datei
53
server/src/core/settings.hpp
Normale Datei
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* server/src/core/settings.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_SETTINGS_HPP
|
||||
#define SERVER_CORE_SETTINGS_HPP
|
||||
|
||||
#include "object.hpp"
|
||||
#include "stdfilesystem.hpp"
|
||||
#include "property.hpp"
|
||||
|
||||
class Settings : public Object
|
||||
{
|
||||
protected:
|
||||
static const std::string id;
|
||||
|
||||
const std::filesystem::path m_filename;
|
||||
|
||||
void load();
|
||||
void save();
|
||||
|
||||
public:
|
||||
CLASS_ID("settings");
|
||||
|
||||
static constexpr uint16_t defaultPort = 5740; //!< unoffical, not (yet) assigned by IANA
|
||||
|
||||
Property<bool> localhostOnly;
|
||||
Property<uint16_t> port;
|
||||
Property<bool> discoverable;
|
||||
Property<std::string> defaultWorld;
|
||||
|
||||
Settings(const std::filesystem::path& filename);
|
||||
};
|
||||
|
||||
#endif
|
||||
35
server/src/core/stdfilesystem.hpp
Normale Datei
35
server/src/core/stdfilesystem.hpp
Normale Datei
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* server/src/core/stdfilesystem.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_STDFILESYSTEM_HPP
|
||||
#define SERVER_CORE_STDFILESYSTEM_HPP
|
||||
|
||||
#if __GNUC__ < 8
|
||||
#include <experimental/filesystem>
|
||||
namespace std {
|
||||
namespace filesystem = experimental::filesystem::v1;
|
||||
}
|
||||
#else
|
||||
#include <filesystem>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
34
server/src/core/table.hpp
Normale Datei
34
server/src/core/table.hpp
Normale Datei
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* server/src/core/table.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_TABLE_HPP
|
||||
#define SERVER_CORE_TABLE_HPP
|
||||
|
||||
#include "tablemodelptr.hpp"
|
||||
|
||||
class Table
|
||||
{
|
||||
public:
|
||||
virtual TableModelPtr getModel() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
75
server/src/core/tablemodel.cpp
Normale Datei
75
server/src/core/tablemodel.cpp
Normale Datei
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* server/src/core/tablemodel.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "tablemodel.hpp"
|
||||
|
||||
TableModel::TableModel() :
|
||||
Object(),
|
||||
m_rowCount{0}
|
||||
{
|
||||
}
|
||||
|
||||
void TableModel::setRegion(const Region& value)
|
||||
{
|
||||
if(m_region != value)
|
||||
{
|
||||
if(!(value <= m_region))
|
||||
{
|
||||
Region update = value;
|
||||
|
||||
if(update.columnMin == m_region.columnMin && update.columnMax == m_region.columnMax)
|
||||
{
|
||||
if(update.rowMin < m_region.rowMin && update.rowMax <= m_region.rowMax) // extend/move top
|
||||
update.rowMax = m_region.rowMin - 1;
|
||||
else if(update.rowMin >= m_region.rowMin && update.rowMax > m_region.rowMax) // extend/move bottom
|
||||
update.rowMin = m_region.rowMax + 1;
|
||||
}
|
||||
|
||||
m_region = value;
|
||||
|
||||
if(updateRegion)
|
||||
updateRegion(shared_ptr<TableModel>(), update);
|
||||
}
|
||||
else
|
||||
m_region = value;
|
||||
}
|
||||
}
|
||||
|
||||
void TableModel::setColumnHeaders(const std::vector<std::string>& values)
|
||||
{
|
||||
if(m_columnHeaders != values)
|
||||
{
|
||||
m_columnHeaders = values;
|
||||
if(columnHeadersChanged)
|
||||
columnHeadersChanged(shared_ptr<TableModel>());
|
||||
}
|
||||
}
|
||||
|
||||
void TableModel::setRowCount(uint32_t value)
|
||||
{
|
||||
if(m_rowCount != value)
|
||||
{
|
||||
m_rowCount = value;
|
||||
if(rowCountChanged)
|
||||
rowCountChanged(shared_ptr<TableModel>());
|
||||
}
|
||||
}
|
||||
107
server/src/core/tablemodel.hpp
Normale Datei
107
server/src/core/tablemodel.hpp
Normale Datei
@ -0,0 +1,107 @@
|
||||
/**
|
||||
* server/src/core/tablemodel.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_TABLEMODEL_HPP
|
||||
#define SERVER_CORE_TABLEMODEL_HPP
|
||||
|
||||
#include "object.hpp"
|
||||
//#include <vector>
|
||||
#include <functional>
|
||||
#include "tablemodelptr.hpp"
|
||||
|
||||
class TableModel : public Object
|
||||
{
|
||||
public:
|
||||
struct Region
|
||||
{
|
||||
uint32_t columnMin;
|
||||
uint32_t columnMax;
|
||||
uint32_t rowMin;
|
||||
uint32_t rowMax;
|
||||
|
||||
|
||||
Region() :
|
||||
columnMin{0},
|
||||
columnMax{0},
|
||||
rowMin{0},
|
||||
rowMax{0}
|
||||
{
|
||||
}
|
||||
|
||||
Region(uint32_t _columnMin, uint32_t _columnMax, uint32_t _rowMin, uint32_t _rowMax) :
|
||||
columnMin{_columnMin},
|
||||
columnMax{_columnMax},
|
||||
rowMin{_rowMin},
|
||||
rowMax{_rowMax}
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const Region& rhs) const
|
||||
{
|
||||
return
|
||||
this->columnMin == rhs.columnMin &&
|
||||
this->columnMax == rhs.columnMax &&
|
||||
this->rowMin == rhs.rowMin &&
|
||||
this->rowMax == rhs.rowMax;
|
||||
}
|
||||
|
||||
bool operator!=(const Region& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
bool operator<=(const Region& rhs) const
|
||||
{
|
||||
return
|
||||
this->columnMin >= rhs.columnMin &&
|
||||
this->columnMax <= rhs.columnMax &&
|
||||
this->rowMin >= rhs.rowMin &&
|
||||
this->rowMax <= rhs.rowMax;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_columnHeaders;
|
||||
uint32_t m_rowCount;
|
||||
Region m_region;
|
||||
|
||||
protected:
|
||||
void setColumnHeaders(const std::vector<std::string>& values);
|
||||
void setRowCount(uint32_t value);
|
||||
|
||||
public:
|
||||
std::function<void(const TableModelPtr&)> columnHeadersChanged;
|
||||
std::function<void(const TableModelPtr&)> rowCountChanged;
|
||||
std::function<void(const TableModelPtr&, const Region& region)> updateRegion;
|
||||
|
||||
TableModel();
|
||||
|
||||
const std::vector<std::string>& columnHeaders() const { return m_columnHeaders; }
|
||||
uint32_t columnCount() const { return m_columnHeaders.size(); }
|
||||
uint32_t rowCount() const { return m_rowCount; }
|
||||
|
||||
virtual std::string getText(uint32_t column, uint32_t row) const = 0;
|
||||
|
||||
void setRegion(const Region& value);
|
||||
};
|
||||
|
||||
#endif
|
||||
32
server/src/core/tablemodelptr.hpp
Normale Datei
32
server/src/core/tablemodelptr.hpp
Normale Datei
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* server/src/core/tablemodelptr.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_TABLEMODELPTR_HPP
|
||||
#define SERVER_CORE_TABLEMODELPTR_HPP
|
||||
|
||||
#include <memory>
|
||||
|
||||
class TableModel;
|
||||
|
||||
using TableModelPtr = std::shared_ptr<TableModel>;
|
||||
|
||||
#endif
|
||||
76
server/src/core/to.hpp
Normale Datei
76
server/src/core/to.hpp
Normale Datei
@ -0,0 +1,76 @@
|
||||
/**
|
||||
* server/src/core/to.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_TO_HPP
|
||||
#define SERVER_CORE_TO_HPP
|
||||
|
||||
#include <type_traits>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
#include <cmath>
|
||||
|
||||
class conversion_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
conversion_error() :
|
||||
std::runtime_error("conversion error")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class out_of_range_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
out_of_range_error() :
|
||||
std::runtime_error("out of range error")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
template<typename To, typename From>
|
||||
To to(const From& value)
|
||||
{
|
||||
if constexpr(std::is_same<To, From>::value)
|
||||
return value;
|
||||
else if constexpr(!std::is_same<To, bool>::value && std::is_integral<To>::value && !std::is_same<From, bool>::value && std::is_integral<From>::value)
|
||||
{
|
||||
if constexpr(std::numeric_limits<To>::min() <= std::numeric_limits<From>::min() && std::numeric_limits<To>::max() >= std::numeric_limits<From>::max())
|
||||
return value;
|
||||
else if(value >= std::numeric_limits<To>::min() && value <= std::numeric_limits<To>::max())
|
||||
return value;
|
||||
else
|
||||
throw out_of_range_error();
|
||||
}
|
||||
else if constexpr(std::is_floating_point<To>::value && (std::is_integral<From>::value || std::is_floating_point<From>::value))
|
||||
return value;
|
||||
else if constexpr(std::is_integral<To>::value && std::is_floating_point<From>::value)
|
||||
{
|
||||
if(value >= std::numeric_limits<To>::min() && value <= std::numeric_limits<To>::max())
|
||||
return static_cast<To>(std::round(value));
|
||||
else
|
||||
throw out_of_range_error();
|
||||
}
|
||||
|
||||
throw conversion_error();
|
||||
}
|
||||
|
||||
#endif
|
||||
275
server/src/core/traintastic.cpp
Normale Datei
275
server/src/core/traintastic.cpp
Normale Datei
@ -0,0 +1,275 @@
|
||||
/**
|
||||
* server/src/core/traintastic.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "traintastic.hpp"
|
||||
#include <fstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <boost/uuid/nil_generator.hpp>
|
||||
#include <boost/uuid/string_generator.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include "eventloop.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "client.hpp"
|
||||
#include "world.hpp"
|
||||
#include "worldlist.hpp"
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
const std::string Traintastic::id{Traintastic::classId};
|
||||
|
||||
std::unique_ptr<Traintastic> Traintastic::instance;
|
||||
|
||||
Traintastic::Traintastic(const std::filesystem::path& dataDir) :
|
||||
Object{},
|
||||
m_dataDir{std::filesystem::absolute(dataDir)},
|
||||
m_ioContext{},
|
||||
m_acceptor{m_ioContext},
|
||||
m_socketTCP{m_ioContext},
|
||||
m_socketUDP{m_ioContext},
|
||||
console{this, "console", std::make_shared<Console>(), PropertyFlags::AccessRRR},
|
||||
settings{this, "settings", nullptr, PropertyFlags::AccessRRR},
|
||||
world{this, "world", nullptr, PropertyFlags::AccessRRR},
|
||||
worldList{this, "world_list", nullptr, PropertyFlags::AccessRRR}
|
||||
{
|
||||
m_interfaceItems.add(console);
|
||||
m_interfaceItems.add(settings);
|
||||
m_interfaceItems.add(world);
|
||||
m_interfaceItems.add(worldList);
|
||||
}
|
||||
|
||||
Traintastic::~Traintastic()
|
||||
{
|
||||
assert(m_ioContext.stopped());
|
||||
}
|
||||
|
||||
bool Traintastic::run()
|
||||
{
|
||||
settings = std::make_shared<Settings>(m_dataDir / "settings.json");
|
||||
worldList = std::make_shared<WorldList>(m_dataDir / "world");
|
||||
|
||||
if(!settings->defaultWorld.value().empty())
|
||||
{
|
||||
boost::uuids::uuid uuid;
|
||||
try
|
||||
{
|
||||
uuid = boost::uuids::string_generator()(settings->defaultWorld.value());
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
uuid = boost::uuids::nil_generator()();
|
||||
console->error(id, "Invalid default world uuid");
|
||||
}
|
||||
|
||||
if(!uuid.is_nil())
|
||||
loadWorld(uuid);
|
||||
}
|
||||
else
|
||||
newWorld();
|
||||
|
||||
if(!start())
|
||||
return false;
|
||||
|
||||
auto work = std::make_shared<boost::asio::io_service::work>(m_ioContext);
|
||||
m_ioContext.run();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Traintastic::shutdown()
|
||||
{
|
||||
console->notice(id, "Shutting down");
|
||||
|
||||
m_ioContext.stop();
|
||||
}
|
||||
|
||||
bool Traintastic::start()
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
|
||||
m_acceptor.open(boost::asio::ip::tcp::v4(), ec);
|
||||
if(ec)
|
||||
{
|
||||
console->fatal(id, ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_acceptor.bind(boost::asio::ip::tcp::endpoint(settings->localhostOnly ? boost::asio::ip::address_v4::loopback() : boost::asio::ip::address_v4::any(), settings->port), ec);
|
||||
if(ec)
|
||||
{
|
||||
console->fatal(id, ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_acceptor.listen(5, ec);
|
||||
if(ec)
|
||||
{
|
||||
console->fatal(id, ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(settings->discoverable)
|
||||
{
|
||||
if(settings->port == Settings::defaultPort)
|
||||
{
|
||||
m_socketUDP.open(boost::asio::ip::udp::v4(), ec);
|
||||
if(ec)
|
||||
{
|
||||
console->fatal(id, ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_socketUDP.bind(boost::asio::ip::udp::endpoint(boost::asio::ip::address_v4::any(), Settings::defaultPort), ec);
|
||||
if(ec)
|
||||
{
|
||||
console->fatal(id, "bind: " + ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
console->notice(id, "Discovery enabled");
|
||||
doReceive();
|
||||
}
|
||||
else
|
||||
console->warning(id, std::string("Discovery disabled, only allowed on port ") + std::to_string(Settings::defaultPort));
|
||||
}
|
||||
else
|
||||
console->notice(id, "Discovery disabled");
|
||||
|
||||
console->notice(id, std::string("Listening at ") + m_acceptor.local_endpoint().address().to_string() + ":" + std::to_string(m_acceptor.local_endpoint().port()));
|
||||
doAccept();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Traintastic::stop()
|
||||
{
|
||||
m_acceptor.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Traintastic::newWorld()
|
||||
{
|
||||
world = std::make_shared<World>();
|
||||
console->notice(id, "Created new world");
|
||||
}
|
||||
|
||||
void Traintastic::loadWorld(const boost::uuids::uuid& uuid)
|
||||
{
|
||||
if(const WorldList::WorldInfo* info = worldList->find(uuid))
|
||||
loadWorld(info->path);
|
||||
else
|
||||
console->error(id, "World " + to_string(uuid) + " doesn't exist");
|
||||
}
|
||||
|
||||
void Traintastic::loadWorld(const std::filesystem::path& path)
|
||||
{
|
||||
try
|
||||
{
|
||||
world = std::make_shared<World>(path / "traintastic.json");
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
console->critical(id, std::string("Loading world failed: ") + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void Traintastic::saveWorld()
|
||||
{
|
||||
}
|
||||
|
||||
void Traintastic::clientGone(const std::shared_ptr<Client>& client)
|
||||
{
|
||||
}
|
||||
|
||||
void Traintastic::doReceive()
|
||||
{
|
||||
m_socketUDP.async_receive_from(boost::asio::buffer(m_udpBuffer), m_remoteEndpoint,
|
||||
[this](const boost::system::error_code& ec, std::size_t bytesReceived)
|
||||
{
|
||||
if(!ec)
|
||||
{
|
||||
if(bytesReceived == sizeof(Message::Header))
|
||||
{
|
||||
Message message(*reinterpret_cast<Message::Header*>(m_udpBuffer.data()));
|
||||
|
||||
if(!settings->localhostOnly || m_remoteEndpoint.address().is_loopback())
|
||||
{
|
||||
if(message.dataSize() == 0)
|
||||
{
|
||||
std::unique_ptr<Message> response = processMessage(message);
|
||||
if(response)
|
||||
{
|
||||
m_socketUDP.async_send_to(boost::asio::buffer(**response, response->size()), m_remoteEndpoint,
|
||||
[this](const boost::system::error_code&, std::size_t)
|
||||
{
|
||||
doReceive();
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
doReceive();
|
||||
}
|
||||
else
|
||||
console->error(id, ec.message());
|
||||
});
|
||||
}
|
||||
|
||||
std::unique_ptr<Message> Traintastic::processMessage(const Message& message)
|
||||
{
|
||||
if(message.command() == Message::Command::Discover && message.isRequest())
|
||||
{
|
||||
std::unique_ptr<Message> response = Message::newResponse(message.command(), message.requestId());
|
||||
response->write(boost::asio::ip::host_name());
|
||||
return std::move(response);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Traintastic::doAccept()
|
||||
{
|
||||
m_acceptor.async_accept(m_socketTCP,
|
||||
[this](boost::system::error_code ec)
|
||||
{
|
||||
EventLoop::call(
|
||||
[this, ec]()
|
||||
{
|
||||
if(!ec)
|
||||
{
|
||||
try
|
||||
{
|
||||
std::shared_ptr<Client> client = std::make_shared<Client>(*this, "client[" + m_socketTCP.remote_endpoint().address().to_string() + ":" + std::to_string(m_socketTCP.remote_endpoint().port()) + "]", std::move(m_socketTCP));
|
||||
client->start();
|
||||
m_clients.push_back(client);
|
||||
doAccept();
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
console->critical(id, e.what());
|
||||
}
|
||||
}
|
||||
else
|
||||
console->error(id, ec.message());
|
||||
});
|
||||
});
|
||||
}
|
||||
89
server/src/core/traintastic.hpp
Normale Datei
89
server/src/core/traintastic.hpp
Normale Datei
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* server/src/core/traintastic.hpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef SERVER_CORE_TRAINTASTIC_HPP
|
||||
#define SERVER_CORE_TRAINTASTIC_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include "stdfilesystem.hpp"
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include "object.hpp"
|
||||
#include "objectproperty.hpp"
|
||||
#include "console.hpp"
|
||||
|
||||
class Client;
|
||||
class Message;
|
||||
class Settings;
|
||||
class World;
|
||||
class WorldList;
|
||||
|
||||
class Traintastic : public Object
|
||||
{
|
||||
friend class Client;
|
||||
|
||||
private:
|
||||
const std::filesystem::path m_dataDir;
|
||||
boost::asio::io_context m_ioContext;
|
||||
boost::asio::ip::tcp::acceptor m_acceptor;
|
||||
boost::asio::ip::tcp::socket m_socketTCP;
|
||||
boost::asio::ip::udp::socket m_socketUDP;
|
||||
std::array<char, 8> m_udpBuffer;
|
||||
boost::asio::ip::udp::endpoint m_remoteEndpoint;
|
||||
std::list<std::shared_ptr<Client>> m_clients;
|
||||
|
||||
bool start();
|
||||
bool stop();
|
||||
|
||||
void newWorld();
|
||||
void loadWorld(const boost::uuids::uuid& uuid);
|
||||
void loadWorld(const std::filesystem::path& path);
|
||||
|
||||
void saveWorld();
|
||||
|
||||
void doReceive();
|
||||
std::unique_ptr<Message> processMessage(const Message& message);
|
||||
void doAccept();
|
||||
|
||||
protected:
|
||||
void clientGone(const std::shared_ptr<Client>& client);
|
||||
|
||||
public:
|
||||
CLASS_ID("traintastic");
|
||||
|
||||
static const std::string id;
|
||||
static std::unique_ptr<Traintastic> instance;
|
||||
|
||||
ObjectProperty<Console> console;
|
||||
ObjectProperty<Settings> settings;
|
||||
ObjectProperty<World> world;
|
||||
ObjectProperty<WorldList> worldList;
|
||||
|
||||
Traintastic(const std::filesystem::path& dataDir);
|
||||
~Traintastic() final;
|
||||
|
||||
bool run();
|
||||
void shutdown();
|
||||
};
|
||||
|
||||
#endif
|
||||
81
server/src/core/world.cpp
Normale Datei
81
server/src/core/world.cpp
Normale Datei
@ -0,0 +1,81 @@
|
||||
/**
|
||||
* server/src/core/world.cpp
|
||||
*
|
||||
* This file is part of the traintastic source code.
|
||||
*
|
||||
* Copyright (C) 2019 Reinder Feenstra
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "world.hpp"
|
||||
#include <fstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <boost/uuid/random_generator.hpp>
|
||||
#include <boost/uuid/string_generator.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include "traintastic.hpp"
|
||||
#include "../hardware/commandstation/commandstationlist.hpp"
|
||||
#include "../hardware/decoder/decoderlist.hpp"
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
const std::string World::id{World::classId};
|
||||
|
||||
World::World() :
|
||||
Object(),
|
||||
m_uuid{boost::uuids::random_generator()()},
|
||||
name{this, "name", "", PropertyFlags::AccessWCC},
|
||||
commandStationList{std::make_shared<CommandStationList>("command_station_list")},
|
||||
decoderList{std::make_shared<DecoderList>("decoder_list")}
|
||||
{
|
||||
}
|
||||
|
||||
World::World(const std::filesystem::path& filename) :
|
||||
World()
|
||||
{
|
||||
m_filename = filename;
|
||||
load();
|
||||
}
|
||||
|
||||
void World::load()
|
||||
{
|
||||
std::ifstream file(m_filename);
|
||||
if(file.is_open())
|
||||
{
|
||||
json world = json::parse(file);
|
||||
m_uuid = boost::uuids::string_generator()(std::string(world["uuid"]));
|
||||
name = world[name.name()];
|
||||
Traintastic::instance->console->notice(id, "Loaded world " + name.value());
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Can't open file");
|
||||
}
|
||||
|
||||
void World::save()
|
||||
{
|
||||
json world;
|
||||
world["uuid"] = to_string(m_uuid);
|
||||
world[name.name()] = name.value();
|
||||
|
||||
std::ofstream file(m_filename);
|
||||
if(file.is_open())
|
||||
{
|
||||
file << world.dump(2);
|
||||
Traintastic::instance->console->notice(id, "Saved world " + name.value());
|
||||
}
|
||||
else
|
||||
Traintastic::instance->console->critical(id, "Can't write to world file");
|
||||
}
|
||||
Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden Mehr anzeigen
Laden…
x
In neuem Issue referenzieren
Einen Benutzer sperren