Compare commits
No commits in common. "master" and "gh-pages" have entirely different histories.
76
.github/CODE_OF_CONDUCT.md
vendored
@ -1,76 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at support@ostinato.org. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
16
.github/CONTRIBUTING.md
vendored
@ -1,16 +0,0 @@
|
||||
# Contributing Guidelines
|
||||
Please use a Pull Request to contribute code. Very small fixes (< 10 lines) can provide the diff via an issue instead of a PR.
|
||||
|
||||
In either case, you agree to the below legal terms and you indicate your acceptance by explicitly adding a comment to the issue or PR stating -
|
||||
|
||||
```
|
||||
I have read the contributing guidelines (CONTRIBUTING.md) and I hereby assign the copyrights of these
|
||||
changes to [Srivats P](https://github.com/pstavirs).
|
||||
```
|
||||
|
||||
## Legal
|
||||
By submitting a Pull Request, you disavow any rights or claims to any changes submitted to the Ostinato project and assign the copyright of those changes to [Srivats P](https://github.com/pstavirs).
|
||||
|
||||
If you cannot or do not want to reassign those rights (your employment contract for your employer may not allow this), you should not submit a PR. Open an issue and someone else can do the work.
|
||||
|
||||
This is a legal way of saying "_If you submit a PR to us, that code becomes ours_". 99.9% of the time that's what you intend anyways; we hope it doesn't scare you away from contributing.
|
1
.github/FUNDING.yml
vendored
@ -1 +0,0 @@
|
||||
github: pstavirs
|
38
.gitignore
vendored
@ -1,38 +0,0 @@
|
||||
# generated object files
|
||||
*.pyc
|
||||
*.o
|
||||
*.a
|
||||
*.dll
|
||||
*.so
|
||||
*.exe
|
||||
*.app
|
||||
drone
|
||||
ostinato
|
||||
|
||||
# Qt generated files
|
||||
ui_*.h
|
||||
moc_*.h
|
||||
moc_*.cpp
|
||||
qrc_*.cpp
|
||||
|
||||
# QMake generated files
|
||||
Makefile*
|
||||
*\object_script.*
|
||||
.qmake.stash
|
||||
|
||||
# protobuf generated files
|
||||
*.pb.h
|
||||
*.pb.cc
|
||||
*_pb2.py
|
||||
|
||||
# ostinato generated files
|
||||
version.cpp
|
||||
pkg_info.json
|
||||
|
||||
# vim swap files
|
||||
*.swp
|
||||
.DS_Store
|
||||
|
||||
# ctags/cscope
|
||||
tags
|
||||
cscope.out
|
49
.travis.yml
@ -1,49 +0,0 @@
|
||||
language: cpp
|
||||
osx_image: xcode11.3
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
|
||||
before_script:
|
||||
- "if [ $TRAVIS_OS_NAME = 'osx' ]; then \
|
||||
ls -lR /usr/local/include/google/protobuf; \
|
||||
which clang++; \
|
||||
clang++ -E -x c++ - -v < /dev/null; \
|
||||
export CPLUS_INCLUDE_PATH=/usr/local/include; \
|
||||
export LIBRARY_PATH=/usr/local/lib; \
|
||||
export PATH=/usr/local/opt/qt/bin:$PATH; \
|
||||
fi"
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- qtbase5-dev
|
||||
- qtscript5-dev
|
||||
- libqt5svg5-dev
|
||||
- libpcap-dev
|
||||
- libprotobuf-dev
|
||||
- protobuf-compiler
|
||||
- libnl-3-dev
|
||||
- libnl-route-3-dev
|
||||
homebrew:
|
||||
packages:
|
||||
- qt5
|
||||
- protobuf
|
||||
script:
|
||||
- QT_SELECT=qt5 qmake -config debug
|
||||
- make
|
||||
|
||||
notifications:
|
||||
email:
|
||||
- secure: "LUIBAz/phzOdxlnFuoC6hfNfl3HAGYTkacVfLu0GsrOgNBhqPqsRszhdFuX/kEdGb18GIcqCQn4tLfFVD9YyjZKFCTjjfTEaUlbHYrear4VU6HihBvhu4I+F8nffJ9y77kyZhUfC9RdgTwWEVdwYMi3rjIK8UggPVV1s/FyE2t+UAjmzdGPAb6uxu9znYpldKtY9FosqccPe7tB5uLLcdbX6ojvsOH7lyQPLclFFS7F2yM9nNNxnRwl1v4KlN6vYwBF2scKB8altEMEGnLJKB41S6piVWyQlXc8FotGJf4fg/6lwmKWBzT/aIw8UH8cxJW2q3sHmdcf/nBhSKojLN5HNIQOJ45Xfw0MKQy2uXGHG15DzYRKjsw6zdb7oVJJCVDiwh1wDvfExgJwpIZJuNsMaGEbSo/TxN+6iPaCf2iyFaCW/KkBt5gmcgck2dA0Xc8qd0z3Zjii7cvuM8awrsmtE7UuX7M/lV9M8w5EaYjhr0R2NwgqvRa0hQv+1Ycec/1eVVfMCMFWNsxmVSkQFFbFP2db195axMzeU13G8RIbPY3JsIUEGw1ykj4nXiH77CLYRfZuKvomjhBkzE+P+EyIxRMH65M4zO9lO7SW01hrHty60jKajt5ljPI5AfuKAFHQvoLOwEMwLwbtEy/ggI/SRAXjsKJbueTHaI4719Gg="
|
||||
|
5
.vimrc
@ -1,5 +0,0 @@
|
||||
set shiftwidth=4
|
||||
set tabstop=8
|
||||
set softtabstop=4
|
||||
set expandtab
|
||||
set cindent
|
674
COPYING
@ -1,674 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. 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
|
||||
them 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 prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. 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.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey 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;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If 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 convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU 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 that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
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.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
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.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
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
|
||||
state 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program 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, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU 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. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
23
README.md
@ -1,23 +0,0 @@
|
||||
# Ostinato
|
||||
|
||||
[![Build Status](https://app.travis-ci.com/pstavirs/ostinato.svg?branch=master)](https://app.travis-ci.com/pstavirs/ostinato)
|
||||
|
||||
This is the code repository for the Ostinato network packet crafter and traffic generator
|
||||
|
||||
Visit https://ostinato.org for demo video and details
|
||||
|
||||
Source License: GPLv3+ (see [COPYING](https://raw.githubusercontent.com/pstavirs/ostinato/master/COPYING))
|
||||
|
||||
## Author's note
|
||||
I have been developing and maintaining Ostinato [single-handedly](https://github.com/pstavirs/ostinato/graphs/contributors) for more than 12 years. And during this time I have grudgingly come around to the view that open source cannot survive and thrive without money. Mixing money with open-source is messy, but I don't see a way forward unless we as a community become open to the idea of talking about it and changing our culture so that money is no longer a bad word.
|
||||
|
||||
I sell binary licenses on [ostinato.org](https://ostinato.org/downloads) to try and cover the costs of development. Please consider buying those - they are priced low enough that you can afford it or you could just as easily expense them to your organisation.
|
||||
|
||||
If you build Ostinato from source and find it useful, please sponsor to keep the lights on and sustain the project.
|
||||
|
||||
[![](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86&style=for-the-badge)](https://github.com/sponsors/pstavirs)
|
||||
|
||||
Read the Ostinato [origin story](https://ostinato.org/about).
|
||||
|
||||
Srivats P<br/>
|
||||
Author, Ostinato
|
211
client/about.ui
@ -1,211 +0,0 @@
|
||||
<ui version="4.0" >
|
||||
<class>About</class>
|
||||
<widget class="QDialog" name="About" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>500</width>
|
||||
<height>327</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>About Ostinato</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget" >
|
||||
<property name="currentIndex" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab" >
|
||||
<attribute name="title" >
|
||||
<string>Ostinato</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap" >
|
||||
<pixmap resource="ostinato.qrc" >:/icons/logo.png</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>21</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4" >
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap" >
|
||||
<pixmap resource="ostinato.qrc" >:/icons/name.png</pixmap>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="versionLabel" >
|
||||
<property name="text" >
|
||||
<string>Version/Revision Placeholder</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="CopyrightLabel" >
|
||||
<property name="text" >
|
||||
<string>Copyright (c) 2007-2023 Srivats P.</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="LinksLabel" >
|
||||
<property name="text" >
|
||||
<string><a href="https://ostinato.org">ostinato.org</a><br><a href="https://twitter.com/ostinato">@ostinato</a></string>
|
||||
</property>
|
||||
<property name="textFormat" >
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="openExternalLinks" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>21</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5" >
|
||||
<property name="text" >
|
||||
<string>Logo (c): Dhiman Sengupta
|
||||
Icons (c): Mark James (http://www.famfamfam.com/lab/icons/silk/)</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2" >
|
||||
<attribute name="title" >
|
||||
<string>License</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<string><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 3 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><p>You should have received a copy of the GNU General Public License along with this program. If not, see <a href="https://www.gnu.org/licenses/">https://www.gnu.org/licenses/</a></p></string>
|
||||
</property>
|
||||
<property name="textFormat" >
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openExternalLinks" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="ostinato.qrc" />
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>About</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>353</x>
|
||||
<y>280</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>286</x>
|
||||
<y>262</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -1,86 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2019 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _APPLY_MESSAGE_H
|
||||
#define _APPLY_MESSAGE_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QMainWindow>
|
||||
#include <QProgressBar>
|
||||
#include <QTimer>
|
||||
|
||||
extern QMainWindow *mainWindow;
|
||||
|
||||
class ApplyMessage: public QDialog
|
||||
{
|
||||
public:
|
||||
ApplyMessage(QWidget *parent = Q_NULLPTR);
|
||||
|
||||
public slots:
|
||||
void show();
|
||||
virtual void done(int r);
|
||||
|
||||
private:
|
||||
QLabel *help_;
|
||||
QTimer *helpTimer_;
|
||||
};
|
||||
|
||||
ApplyMessage::ApplyMessage(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
auto layout = new QVBoxLayout(this);
|
||||
auto message = new QLabel(tr("Pushing configuration changes to agent "
|
||||
"and re-building packets ..."), this);
|
||||
auto progress = new QProgressBar(this);
|
||||
progress->setRange(0, 0);
|
||||
progress->setTextVisible(false);
|
||||
help_ = new QLabel(tr("<b>This may take some time</b>"), this);
|
||||
help_->setAlignment(Qt::AlignCenter);
|
||||
layout->addWidget(message);
|
||||
layout->addWidget(progress);
|
||||
layout->addWidget(help_);
|
||||
|
||||
helpTimer_ = new QTimer(this);
|
||||
helpTimer_->setSingleShot(true);
|
||||
helpTimer_->setInterval(4000);
|
||||
connect(helpTimer_, SIGNAL(timeout()), help_, SLOT(show()));
|
||||
}
|
||||
|
||||
void ApplyMessage::show()
|
||||
{
|
||||
help_->hide(); // shown when helpTimer_ expires
|
||||
|
||||
QWidget *parent = parentWidget();
|
||||
if (!parent)
|
||||
parent = mainWindow;
|
||||
move(parent->frameGeometry().center() - rect().center());
|
||||
setModal(true);
|
||||
QDialog::show();
|
||||
|
||||
helpTimer_->start();
|
||||
}
|
||||
|
||||
void ApplyMessage::done(int r)
|
||||
{
|
||||
helpTimer_->stop();
|
||||
QDialog::done(r);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,159 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "arpstatusmodel.h"
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#include "emulproto.pb.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
|
||||
enum {
|
||||
kIp4Address,
|
||||
kMacAddress,
|
||||
kStatus,
|
||||
kFieldCount
|
||||
};
|
||||
|
||||
static QStringList columns_ = QStringList()
|
||||
<< "IPv4 Address"
|
||||
<< "Mac Address"
|
||||
<< "Status";
|
||||
|
||||
ArpStatusModel::ArpStatusModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
port_ = NULL;
|
||||
deviceIndex_ = -1;
|
||||
neighbors_ = NULL;
|
||||
}
|
||||
|
||||
int ArpStatusModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (!port_ || deviceIndex_ < 0 || parent.isValid())
|
||||
return 0;
|
||||
|
||||
return port_->numArp(deviceIndex_);
|
||||
}
|
||||
|
||||
int ArpStatusModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
|
||||
return columns_.size();
|
||||
}
|
||||
|
||||
QVariant ArpStatusModel::headerData(
|
||||
int section,
|
||||
Qt::Orientation orientation,
|
||||
int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
switch (orientation) {
|
||||
case Qt::Horizontal:
|
||||
return columns_[section];
|
||||
case Qt::Vertical:
|
||||
return QString("%1").arg(section + 1);
|
||||
default:
|
||||
Q_ASSERT(false); // Unreachable
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant ArpStatusModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
QString str;
|
||||
|
||||
if (!port_ || deviceIndex_ < 0 || !index.isValid())
|
||||
return QVariant();
|
||||
|
||||
int arpIdx = index.row();
|
||||
int field = index.column();
|
||||
|
||||
Q_ASSERT(arpIdx < port_->numArp(deviceIndex_));
|
||||
Q_ASSERT(field < kFieldCount);
|
||||
|
||||
const OstEmul::ArpEntry &arp = neighbors_->arp(arpIdx);
|
||||
|
||||
switch (field) {
|
||||
case kIp4Address:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return QHostAddress(arp.ip4()).toString();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kMacAddress:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return QString("%1").arg(arp.mac(), 6*2, 16, QChar('0'))
|
||||
.replace(QRegExp("([0-9a-fA-F]{2}\\B)"), "\\1:")
|
||||
.toUpper();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kStatus:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return arp.mac() ?
|
||||
QString("Resolved") : QString("Failed");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
default:
|
||||
Q_ASSERT(false); // unreachable!
|
||||
break;
|
||||
}
|
||||
|
||||
qWarning("%s: Unsupported field #%d", __FUNCTION__, field);
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Qt::DropActions ArpStatusModel::supportedDropActions() const
|
||||
{
|
||||
return Qt::IgnoreAction; // read-only model, doesn't accept any data
|
||||
}
|
||||
|
||||
void ArpStatusModel::setDeviceIndex(Port *port, int deviceIndex)
|
||||
{
|
||||
beginResetModel();
|
||||
port_ = port;
|
||||
deviceIndex_ = deviceIndex;
|
||||
if (port_)
|
||||
neighbors_ = port_->deviceNeighbors(deviceIndex);
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void ArpStatusModel::updateArpStatus()
|
||||
{
|
||||
// FIXME: why needed?
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _ARP_STATUS_MODEL_H
|
||||
#define _ARP_STATUS_MODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
class Port;
|
||||
namespace OstEmul {
|
||||
class DeviceNeighborList;
|
||||
}
|
||||
|
||||
class ArpStatusModel: public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ArpStatusModel(QObject *parent = 0);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
|
||||
Qt::DropActions supportedDropActions() const;
|
||||
|
||||
void setDeviceIndex(Port *port, int deviceIndex);
|
||||
|
||||
public slots:
|
||||
void updateArpStatus();
|
||||
|
||||
private:
|
||||
Port *port_;
|
||||
int deviceIndex_;
|
||||
const OstEmul::DeviceNeighborList *neighbors_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,221 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "clipboardhelper.h"
|
||||
|
||||
#include "xtableview.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QIcon>
|
||||
#include <QItemSelection>
|
||||
|
||||
#if 0 // change 0 to 1 for debug
|
||||
#define xDebug(...) qDebug(__VA_ARGS__)
|
||||
#else
|
||||
#define xDebug(...)
|
||||
#endif
|
||||
|
||||
ClipboardHelper::ClipboardHelper(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
actionCut_ = new QAction(tr("&Cut"), this);
|
||||
actionCut_->setObjectName(QStringLiteral("actionCut"));
|
||||
actionCut_->setIcon(QIcon(QString::fromUtf8(":/icons/cut.png")));
|
||||
|
||||
actionCopy_ = new QAction(tr("Cop&y"), this);
|
||||
actionCopy_->setObjectName(QStringLiteral("actionCopy"));
|
||||
actionCopy_->setIcon(QIcon(QString::fromUtf8(":/icons/copy.png")));
|
||||
|
||||
actionPaste_ = new QAction(tr("&Paste"), this);
|
||||
actionPaste_->setObjectName(QStringLiteral("actionPaste"));
|
||||
actionPaste_->setIcon(QIcon(QString::fromUtf8(":/icons/paste.png")));
|
||||
|
||||
connect(actionCut_, SIGNAL(triggered()), SLOT(actionTriggered()));
|
||||
connect(actionCopy_, SIGNAL(triggered()), SLOT(actionTriggered()));
|
||||
connect(actionPaste_, SIGNAL(triggered()), SLOT(actionTriggered()));
|
||||
|
||||
// XXX: failsafe in case updation of cut/copy/status causes issues
|
||||
// Temporary for 1 release - will be removed after that
|
||||
if (qEnvironmentVariableIsSet("X-OSTINATO-CCP-STATUS")) {
|
||||
qWarning("FAILSAFE: Cut-Copy-Paste action status will not be updated");
|
||||
return;
|
||||
}
|
||||
|
||||
connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)),
|
||||
SLOT(updateCutCopyStatus(QWidget*, QWidget*)));
|
||||
|
||||
connect(qApp, SIGNAL(focusChanged(QWidget*, QWidget*)),
|
||||
SLOT(updatePasteStatus()));
|
||||
connect(QGuiApplication::clipboard(), SIGNAL(dataChanged()),
|
||||
SLOT(updatePasteStatus()));
|
||||
}
|
||||
|
||||
QList<QAction*> ClipboardHelper::actions()
|
||||
{
|
||||
QList<QAction*> actionList({actionCut_, actionCopy_, actionPaste_});
|
||||
return actionList;
|
||||
}
|
||||
|
||||
void ClipboardHelper::actionTriggered()
|
||||
{
|
||||
QWidget *focusWidget = qApp->focusWidget();
|
||||
|
||||
if (!focusWidget)
|
||||
return;
|
||||
|
||||
// single slot to handle cut/copy/paste - find which action was triggered
|
||||
QString action = sender()->objectName()
|
||||
.remove("action").append("()").toLower();
|
||||
if (focusWidget->metaObject()->indexOfSlot(qPrintable(action)) < 0) {
|
||||
xDebug("%s slot not found for object %s:%s ",
|
||||
qPrintable(action),
|
||||
qPrintable(focusWidget->objectName()),
|
||||
focusWidget->metaObject()->className());
|
||||
return;
|
||||
}
|
||||
|
||||
action.remove("()");
|
||||
QMetaObject::invokeMethod(focusWidget, qPrintable(action),
|
||||
Qt::DirectConnection);
|
||||
}
|
||||
|
||||
void ClipboardHelper::updateCutCopyStatus(QWidget *old, QWidget *now)
|
||||
{
|
||||
xDebug("In %s", __FUNCTION__);
|
||||
|
||||
const XTableView *view = dynamic_cast<XTableView*>(old);
|
||||
if (view) {
|
||||
disconnect(view->selectionModel(),
|
||||
SIGNAL(selectionChanged(const QItemSelection&,
|
||||
const QItemSelection&)),
|
||||
this,
|
||||
SLOT(focusWidgetSelectionChanged(const QItemSelection&,
|
||||
const QItemSelection&)));
|
||||
disconnect(view->model(), SIGNAL(modelReset()),
|
||||
this, SLOT(focusWidgetModelReset()));
|
||||
}
|
||||
|
||||
if (!now) {
|
||||
xDebug("No focus widget to copy from");
|
||||
actionCut_->setEnabled(false);
|
||||
actionCopy_->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const QMetaObject *meta = now->metaObject();
|
||||
if (meta->indexOfSlot("copy()") < 0) {
|
||||
xDebug("Focus Widget (%s) doesn't have a copy slot",
|
||||
qPrintable(now->objectName()));
|
||||
actionCut_->setEnabled(false);
|
||||
actionCopy_->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
view = dynamic_cast<XTableView*>(now);
|
||||
if (view) {
|
||||
connect(view->selectionModel(),
|
||||
SIGNAL(selectionChanged(const QItemSelection&,
|
||||
const QItemSelection&)),
|
||||
SLOT(focusWidgetSelectionChanged(const QItemSelection&,
|
||||
const QItemSelection&)));
|
||||
connect(view->model(), SIGNAL(modelReset()),
|
||||
this, SLOT(focusWidgetModelReset()));
|
||||
if (!view->hasSelection()) {
|
||||
xDebug("%s doesn't have anything selected to copy",
|
||||
qPrintable(view->objectName()));
|
||||
actionCut_->setEnabled(false);
|
||||
actionCopy_->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
xDebug("%s model can cut: %d", qPrintable(view->objectName()),
|
||||
view->canCut());
|
||||
actionCut_->setEnabled(view->canCut());
|
||||
}
|
||||
|
||||
xDebug("%s has a selection and copy slot: copy possible",
|
||||
qPrintable(now->objectName()));
|
||||
actionCopy_->setEnabled(true);
|
||||
}
|
||||
|
||||
void ClipboardHelper::focusWidgetSelectionChanged(
|
||||
const QItemSelection &selected, const QItemSelection &/*deselected*/)
|
||||
{
|
||||
xDebug("In %s", __FUNCTION__);
|
||||
|
||||
// Selection changed in the XTableView that has focus
|
||||
const XTableView *view = dynamic_cast<XTableView*>(qApp->focusWidget());
|
||||
xDebug("canCut:%d empty:%d", view->canCut(), selected.indexes().isEmpty());
|
||||
actionCut_->setEnabled(!selected.indexes().isEmpty()
|
||||
&& view && view->canCut());
|
||||
actionCopy_->setEnabled(!selected.indexes().isEmpty());
|
||||
}
|
||||
|
||||
void ClipboardHelper::updatePasteStatus()
|
||||
{
|
||||
xDebug("In %s", __FUNCTION__);
|
||||
|
||||
QWidget *focusWidget = qApp->focusWidget();
|
||||
if (!focusWidget) {
|
||||
xDebug("No focus widget to paste into");
|
||||
actionPaste_->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const QMimeData *item = QGuiApplication::clipboard()->mimeData();
|
||||
if (!item || item->formats().isEmpty()) {
|
||||
xDebug("Nothing on clipboard to paste");
|
||||
actionPaste_->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const QMetaObject *meta = focusWidget->metaObject();
|
||||
if (meta->indexOfSlot("paste()") < 0) {
|
||||
xDebug("Focus Widget (%s) doesn't have a paste slot",
|
||||
qPrintable(focusWidget->objectName()));
|
||||
actionPaste_->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const XTableView *view = dynamic_cast<XTableView*>(focusWidget);
|
||||
if (view && !view->canPaste(item)) {
|
||||
xDebug("%s cannot accept this item (%s)",
|
||||
qPrintable(view->objectName()),
|
||||
qPrintable(item->formats().join("|")));
|
||||
actionPaste_->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
xDebug("%s can accept this item (%s): paste possible",
|
||||
qPrintable(focusWidget->objectName()),
|
||||
qPrintable(item->formats().join("|")));
|
||||
actionPaste_->setEnabled(true);
|
||||
}
|
||||
|
||||
void ClipboardHelper::focusWidgetModelReset()
|
||||
{
|
||||
xDebug("In %s", __FUNCTION__);
|
||||
|
||||
QWidget *focusWidget = qApp->focusWidget();
|
||||
updateCutCopyStatus(focusWidget, focusWidget); // re-eval cut/copy status
|
||||
}
|
||||
|
||||
#undef xDebug
|
||||
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2020 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _CLIPBOARD_HELPER_H
|
||||
#define _CLIPBOARD_HELPER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
|
||||
class QAction;
|
||||
class QItemSelection;
|
||||
|
||||
class ClipboardHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ClipboardHelper(QObject *parent=nullptr);
|
||||
|
||||
QList<QAction*> actions();
|
||||
|
||||
private slots:
|
||||
void actionTriggered();
|
||||
void updateCutCopyStatus(QWidget *old, QWidget *now);
|
||||
void focusWidgetSelectionChanged(const QItemSelection &selected,
|
||||
const QItemSelection &deselected);
|
||||
void focusWidgetModelReset();
|
||||
void updatePasteStatus();
|
||||
|
||||
private:
|
||||
QAction *actionCut_{nullptr};
|
||||
QAction *actionCopy_{nullptr};
|
||||
QAction *actionPaste_{nullptr};
|
||||
};
|
||||
|
||||
#endif
|
@ -1,357 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "devicegroupdialog.h"
|
||||
|
||||
#include "port.h"
|
||||
#include "spinboxdelegate.h"
|
||||
|
||||
#include "emulproto.pb.h"
|
||||
#include "uint128.h"
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QHostAddress>
|
||||
|
||||
enum { kVlanId, kVlanCount, kVlanStep, kVlanCfi, kVlanPrio, kVlanTpid,
|
||||
kVlanColumns };
|
||||
static QStringList vlanTableColumnHeaders = QStringList()
|
||||
<< "Vlan Id" << "Count" << "Step" << "CFI/DE" << "Prio" << "TPID";
|
||||
|
||||
enum { kIpNone, kIp4, kIp6, kIpDual };
|
||||
static QStringList ipStackItems = QStringList()
|
||||
<< "None" << "IPv4" << "IPv6" << "Dual";
|
||||
|
||||
inline UInt128 UINT128(OstEmul::Ip6Address x)
|
||||
{
|
||||
return UInt128(x.hi(), x.lo());
|
||||
}
|
||||
|
||||
inline OstEmul::Ip6Address IP6ADDR(UInt128 x)
|
||||
{
|
||||
OstEmul::Ip6Address ip;
|
||||
|
||||
ip.set_hi(x.hi64());
|
||||
ip.set_lo(x.lo64());
|
||||
return ip;
|
||||
}
|
||||
|
||||
DeviceGroupDialog::DeviceGroupDialog(
|
||||
Port *port,
|
||||
int deviceGroupIndex,
|
||||
QWidget *parent,
|
||||
Qt::WindowFlags flags)
|
||||
: QDialog(parent, flags), port_(port), index_(deviceGroupIndex)
|
||||
{
|
||||
// Setup the Dialog
|
||||
setupUi(this);
|
||||
|
||||
vlanTagCount->setRange(0, kMaxVlanTags);
|
||||
|
||||
// Populate the Vlan Table with placeholders - we do this so that
|
||||
// user entered values are retained during the lifetime of the dialog
|
||||
// even if user is playing around with number of vlan tags
|
||||
vlans->setRowCount(kMaxVlanTags);
|
||||
vlans->setColumnCount(kVlanColumns);
|
||||
vlans->setHorizontalHeaderLabels(vlanTableColumnHeaders);
|
||||
for (int i = 0; i < kMaxVlanTags; i++) {
|
||||
// Use same default values as defined in .proto
|
||||
vlans->setItem(i, kVlanId,
|
||||
new QTableWidgetItem(QString::number(100*(i+1))));
|
||||
vlans->setItem(i, kVlanCount,
|
||||
new QTableWidgetItem(QString::number(1)));
|
||||
vlans->setItem(i, kVlanStep,
|
||||
new QTableWidgetItem(QString::number(1)));
|
||||
vlans->setItem(i, kVlanCfi,
|
||||
new QTableWidgetItem(QString::number(0)));
|
||||
vlans->setItem(i, kVlanPrio,
|
||||
new QTableWidgetItem(QString::number(0)));
|
||||
vlans->setItem(i, kVlanTpid,
|
||||
new QTableWidgetItem(QString("0x8100")));
|
||||
}
|
||||
|
||||
// Set SpinBoxDelegate for all columns except TPID
|
||||
SpinBoxDelegate *spd = new SpinBoxDelegate(this);
|
||||
spd->setColumnRange(kVlanId, 0, 4095);
|
||||
spd->setColumnRange(kVlanStep, 0, 4095);
|
||||
spd->setColumnRange(kVlanCfi, 0, 1);
|
||||
spd->setColumnRange(kVlanPrio, 0, 7);
|
||||
for (int i = 0; i < kVlanColumns; i++) {
|
||||
if (i != kVlanTpid)
|
||||
vlans->setItemDelegateForColumn(i, spd);
|
||||
}
|
||||
|
||||
vlans->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||
vlans->resizeRowsToContents();
|
||||
|
||||
// Set vlan tag count *after* adding all items, so connected slots
|
||||
// can access the items
|
||||
vlanTagCount->setValue(kMaxVlanTags);
|
||||
|
||||
devicePerVlanCount->setRange(1, 0x7fffffff);
|
||||
|
||||
ipStack->insertItems(0, ipStackItems);
|
||||
|
||||
// TODO: DeviceGroup Traversal; hide buttons for now
|
||||
// NOTE for implementation: Use a QHash<int, deviceGroup*>
|
||||
// to store modified values while traversing; in accept()
|
||||
// update port->deviceGroups[] from the QHash
|
||||
prev->setHidden(true);
|
||||
next->setHidden(true);
|
||||
|
||||
// TODO: Preview devices expanded from deviceGroup configuration
|
||||
// for user convenience
|
||||
|
||||
// setup dialog to auto-resize as widgets are hidden or shown
|
||||
layout()->setSizeConstraint(QLayout::SetFixedSize);
|
||||
|
||||
connect(devicePerVlanCount, SIGNAL(valueChanged(const QString&)),
|
||||
this, SLOT(updateTotalDeviceCount()));
|
||||
|
||||
connect(ip4Address, SIGNAL(textEdited(const QString&)),
|
||||
this, SLOT(updateIp4Gateway()));
|
||||
connect(ip4PrefixLength, SIGNAL(valueChanged(const QString&)),
|
||||
this, SLOT(updateIp4Gateway()));
|
||||
connect(ip6Address, SIGNAL(textEdited(const QString&)),
|
||||
this, SLOT(updateIp6Gateway()));
|
||||
connect(ip6PrefixLength, SIGNAL(valueChanged(const QString&)),
|
||||
this, SLOT(updateIp6Gateway()));
|
||||
|
||||
loadDeviceGroup();
|
||||
}
|
||||
|
||||
void DeviceGroupDialog::accept()
|
||||
{
|
||||
storeDeviceGroup();
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
//
|
||||
// Private Slots
|
||||
//
|
||||
void DeviceGroupDialog::on_vlanTagCount_valueChanged(int value)
|
||||
{
|
||||
Q_ASSERT((value >= 0) && (value <= kMaxVlanTags));
|
||||
|
||||
for (int row = 0; row < kMaxVlanTags; row++)
|
||||
vlans->setRowHidden(row, row >= value);
|
||||
|
||||
vlans->setVisible(value > 0);
|
||||
updateTotalVlanCount();
|
||||
}
|
||||
|
||||
void DeviceGroupDialog::on_vlans_cellChanged(int row, int col)
|
||||
{
|
||||
if (col != kVlanCount)
|
||||
return;
|
||||
|
||||
if (vlans->isRowHidden(row))
|
||||
return;
|
||||
|
||||
updateTotalVlanCount();
|
||||
}
|
||||
|
||||
void DeviceGroupDialog::on_ipStack_currentIndexChanged(int index)
|
||||
{
|
||||
switch (index) {
|
||||
case kIpNone:
|
||||
ip4->hide();
|
||||
ip6->hide();
|
||||
break;
|
||||
case kIp4:
|
||||
ip4->show();
|
||||
ip6->hide();
|
||||
break;
|
||||
case kIp6:
|
||||
ip4->hide();
|
||||
ip6->show();
|
||||
break;
|
||||
case kIpDual:
|
||||
ip4->show();
|
||||
ip6->show();
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(false); // Unreachable!
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceGroupDialog::updateTotalVlanCount()
|
||||
{
|
||||
int count = vlanTagCount->value() ? 1 : 0;
|
||||
for (int i = 0; i < vlanTagCount->value(); i++)
|
||||
count *= vlans->item(i, kVlanCount)->text().toUInt();
|
||||
vlanCount->setValue(count);
|
||||
|
||||
updateTotalDeviceCount();
|
||||
}
|
||||
|
||||
void DeviceGroupDialog::updateTotalDeviceCount()
|
||||
{
|
||||
totalDeviceCount->setValue(qMax(vlanCount->value(), 1)
|
||||
* devicePerVlanCount->value());
|
||||
}
|
||||
|
||||
void DeviceGroupDialog::updateIp4Gateway()
|
||||
{
|
||||
quint32 net = ip4Address->value() & (~0UL << (32 - ip4PrefixLength->value()));
|
||||
ip4Gateway->setValue(net | 0x01);
|
||||
}
|
||||
|
||||
void DeviceGroupDialog::updateIp6Gateway()
|
||||
{
|
||||
UInt128 net = ip6Address->value()
|
||||
& (~UInt128(0, 0) << (128 - ip6PrefixLength->value()));
|
||||
ip6Gateway->setValue(net | UInt128(0, 1));
|
||||
}
|
||||
|
||||
void DeviceGroupDialog::loadDeviceGroup()
|
||||
{
|
||||
const OstProto::DeviceGroup *devGrp = port_->deviceGroupByIndex(index_);
|
||||
int tagCount = 0;
|
||||
// use 1-indexed id so that it matches the port id used in the
|
||||
// RFC 4814 compliant mac addresses assigned by default to deviceGroups
|
||||
// XXX: use deviceGroupId also as part of the id?
|
||||
quint32 id = (port_->id()+1) & 0xff;
|
||||
|
||||
Q_ASSERT(devGrp);
|
||||
|
||||
name->setText(QString::fromStdString(devGrp->core().name()));
|
||||
|
||||
if (devGrp->has_encap() && devGrp->encap().HasExtension(OstEmul::vlan)) {
|
||||
OstEmul::VlanEmulation vlan = devGrp->encap()
|
||||
.GetExtension(OstEmul::vlan);
|
||||
tagCount = vlan.stack_size();
|
||||
for (int i = 0; i < tagCount; i++) {
|
||||
OstEmul::VlanEmulation::Vlan v = vlan.stack(i);
|
||||
vlans->item(i, kVlanPrio)->setText(
|
||||
QString::number((v.vlan_tag() >> 13) & 0x7));
|
||||
vlans->item(i, kVlanCfi)->setText(
|
||||
QString::number((v.vlan_tag() >> 12) & 0x1));
|
||||
vlans->item(i, kVlanId)->setText(
|
||||
QString::number(v.vlan_tag() & 0x0fff));
|
||||
vlans->item(i, kVlanCount)->setText(QString::number(v.count()));
|
||||
vlans->item(i, kVlanStep)->setText(QString::number(v.step()));
|
||||
vlans->item(i, kVlanTpid)->setText(QString("0x%1")
|
||||
.arg(v.tpid(), 0, 16));
|
||||
}
|
||||
}
|
||||
vlanTagCount->setValue(tagCount);
|
||||
|
||||
updateTotalVlanCount();
|
||||
devicePerVlanCount->setValue(devGrp->device_count());
|
||||
|
||||
OstEmul::MacEmulation mac = devGrp->GetExtension(OstEmul::mac);
|
||||
Q_ASSERT(mac.has_address());
|
||||
macAddress->setValue(mac.address());
|
||||
macStep->setValue(mac.step());
|
||||
|
||||
OstEmul::Ip4Emulation ip4 = devGrp->GetExtension(OstEmul::ip4);
|
||||
// If address is not set, assign one from RFC 2544 space - 192.18.0.0/15
|
||||
// Use port Id as the 3rd octet of the address
|
||||
ip4Address->setValue(ip4.has_address() ?
|
||||
ip4.address() : 0xc6120002 | (id << 8));
|
||||
ip4PrefixLength->setValue(ip4.prefix_length());
|
||||
ip4Step->setValue(ip4.has_step()? ip4.step() : 1);
|
||||
ip4Gateway->setValue(ip4.has_default_gateway() ?
|
||||
ip4.default_gateway() : 0xc6120001 | (id << 8));
|
||||
|
||||
OstEmul::Ip6Emulation ip6 = devGrp->GetExtension(OstEmul::ip6);
|
||||
// If address is not set, assign one from RFC 5180 space 2001:0200::/64
|
||||
// Use port Id as the 3rd hextet of the address
|
||||
ip6Address->setValue(ip6.has_address() ?
|
||||
UINT128(ip6.address()) :
|
||||
UInt128((0x200102000000ULL | id) << 16, 2));
|
||||
ip6PrefixLength->setValue(ip6.prefix_length());
|
||||
ip6Step->setValue(ip6.has_step() ? UINT128(ip6.step()) : UInt128(0, 1));
|
||||
ip6Gateway->setValue(ip6.has_default_gateway() ?
|
||||
UINT128(ip6.default_gateway()) :
|
||||
UInt128((0x200102000000ULL | id) << 16, 1));
|
||||
|
||||
int stk = kIpNone;
|
||||
if (devGrp->HasExtension(OstEmul::ip4))
|
||||
if (devGrp->HasExtension(OstEmul::ip6))
|
||||
stk = kIpDual;
|
||||
else
|
||||
stk = kIp4;
|
||||
else if (devGrp->HasExtension(OstEmul::ip6))
|
||||
stk = kIp6;
|
||||
ipStack->setCurrentIndex(stk);
|
||||
}
|
||||
|
||||
void DeviceGroupDialog::storeDeviceGroup()
|
||||
{
|
||||
OstProto::DeviceGroup *devGrp = port_->mutableDeviceGroupByIndex(index_);
|
||||
int tagCount = vlanTagCount->value();
|
||||
|
||||
Q_ASSERT(devGrp);
|
||||
|
||||
devGrp->mutable_core()->set_name(name->text().toStdString());
|
||||
|
||||
OstEmul::VlanEmulation *vlan = devGrp->mutable_encap()
|
||||
->MutableExtension(OstEmul::vlan);
|
||||
vlan->clear_stack();
|
||||
for (int i = 0; i < tagCount; i++) {
|
||||
OstEmul::VlanEmulation::Vlan *v = vlan->add_stack();
|
||||
v->set_vlan_tag(
|
||||
vlans->item(i, kVlanPrio)->text().toUInt() << 13
|
||||
| vlans->item(i, kVlanCfi)->text().toUInt() << 12
|
||||
| vlans->item(i, kVlanId)->text().toUInt());
|
||||
v->set_count(vlans->item(i, kVlanCount)->text().toUInt());
|
||||
v->set_step(vlans->item(i, kVlanStep)->text().toUInt());
|
||||
v->set_tpid(vlans->item(i, kVlanTpid)->text().toUInt(NULL, 16));
|
||||
}
|
||||
|
||||
if (!tagCount)
|
||||
devGrp->clear_encap();
|
||||
|
||||
devGrp->set_device_count(devicePerVlanCount->value());
|
||||
|
||||
OstEmul::MacEmulation *mac = devGrp->MutableExtension(OstEmul::mac);
|
||||
mac->set_address(macAddress->value());
|
||||
mac->set_step(macStep->value());
|
||||
|
||||
if (ipStack->currentIndex() == kIp4
|
||||
|| ipStack->currentIndex() == kIpDual) {
|
||||
OstEmul::Ip4Emulation *ip4 = devGrp->MutableExtension(OstEmul::ip4);
|
||||
ip4->set_address(ip4Address->value());
|
||||
ip4->set_prefix_length(ip4PrefixLength->value());
|
||||
ip4->set_default_gateway(ip4Gateway->value());
|
||||
ip4->set_step(ip4Step->value());
|
||||
|
||||
if (ipStack->currentIndex() == kIp4)
|
||||
devGrp->ClearExtension(OstEmul::ip6);
|
||||
}
|
||||
|
||||
if (ipStack->currentIndex() == kIp6
|
||||
|| ipStack->currentIndex() == kIpDual) {
|
||||
OstEmul::Ip6Emulation *ip6 = devGrp->MutableExtension(OstEmul::ip6);
|
||||
ip6->mutable_address()->CopyFrom(IP6ADDR(ip6Address->value()));
|
||||
ip6->set_prefix_length(ip6PrefixLength->value());
|
||||
ip6->mutable_step()->CopyFrom(IP6ADDR(ip6Step->value()));
|
||||
ip6->mutable_default_gateway()->CopyFrom(IP6ADDR(ip6Gateway->value()));
|
||||
|
||||
if (ipStack->currentIndex() == kIp6)
|
||||
devGrp->ClearExtension(OstEmul::ip4);
|
||||
}
|
||||
|
||||
if (ipStack->currentIndex() == kIpNone) {
|
||||
devGrp->ClearExtension(OstEmul::ip4);
|
||||
devGrp->ClearExtension(OstEmul::ip6);
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _DEVICE_GROUP_DIALOG_H
|
||||
#define _DEVICE_GROUP_DIALOG_H
|
||||
|
||||
#include "ui_devicegroupdialog.h"
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class Port;
|
||||
|
||||
class DeviceGroupDialog: public QDialog, private Ui::DeviceGroupDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DeviceGroupDialog(Port *port, int deviceGroupIndex,
|
||||
QWidget *parent = NULL, Qt::WindowFlags flags = 0);
|
||||
|
||||
virtual void accept();
|
||||
private slots:
|
||||
void on_vlanTagCount_valueChanged(int value);
|
||||
void on_vlans_cellChanged(int row, int col);
|
||||
void on_ipStack_currentIndexChanged(int index);
|
||||
|
||||
void updateTotalVlanCount();
|
||||
void updateTotalDeviceCount();
|
||||
void updateIp4Gateway();
|
||||
void updateIp6Gateway();
|
||||
|
||||
void loadDeviceGroup();
|
||||
void storeDeviceGroup();
|
||||
private:
|
||||
static const int kMaxVlanTags = 4;
|
||||
|
||||
Port *port_;
|
||||
int index_;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,385 +0,0 @@
|
||||
<ui version="4.0" >
|
||||
<class>DeviceGroupDialog</class>
|
||||
<widget class="QDialog" name="DeviceGroupDialog" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>504</width>
|
||||
<height>465</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Devices</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<string>Name</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="name" />
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<string>Vlan Tags</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="vlanTagCount" />
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="vlans" />
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label_11" >
|
||||
<property name="text" >
|
||||
<string>Total Vlans</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="IntEdit" name="vlanCount" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" colspan="2" >
|
||||
<widget class="QLabel" name="label_13" >
|
||||
<property name="text" >
|
||||
<string>Devices Per Vlan</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>devicePerVlanCount</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4" >
|
||||
<widget class="QSpinBox" name="devicePerVlanCount" />
|
||||
</item>
|
||||
<item row="0" column="5" >
|
||||
<widget class="QLabel" name="label_14" >
|
||||
<property name="text" >
|
||||
<string>Total Devices</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="6" >
|
||||
<widget class="IntEdit" name="totalDeviceCount" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_3" >
|
||||
<property name="text" >
|
||||
<string>Mac Address</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="MacEdit" name="macAddress" />
|
||||
</item>
|
||||
<item row="1" column="2" >
|
||||
<widget class="QLabel" name="label_5" >
|
||||
<property name="text" >
|
||||
<string>Step</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3" colspan="2" >
|
||||
<widget class="MacEdit" name="macStep" />
|
||||
</item>
|
||||
<item row="1" column="5" >
|
||||
<widget class="QLabel" name="label_4" >
|
||||
<property name="text" >
|
||||
<string>IP Stack</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="6" >
|
||||
<widget class="QComboBox" name="ipStack" />
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="ip4" >
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label_9" >
|
||||
<property name="text" >
|
||||
<string>IPv4 Address</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="Ip4Edit" name="ip4Address" />
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<widget class="QLabel" name="label_12" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Preferred" hsizetype="Fixed" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>/</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5" >
|
||||
<widget class="QLabel" name="label_8" >
|
||||
<property name="text" >
|
||||
<string>Step</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="6" >
|
||||
<widget class="Ip4Edit" name="ip4Step" />
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_7" >
|
||||
<property name="text" >
|
||||
<string>Gateway</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="Ip4Edit" name="ip4Gateway" />
|
||||
</item>
|
||||
<item row="0" column="3" >
|
||||
<widget class="QSpinBox" name="ip4PrefixLength" >
|
||||
<property name="minimum" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>32</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="ip6" >
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label_10" >
|
||||
<property name="text" >
|
||||
<string>IPv6 Address</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="Ip6Edit" name="ip6Address" />
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<widget class="QLabel" name="label_15" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Preferred" hsizetype="Fixed" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>/</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5" >
|
||||
<widget class="QLabel" name="label_16" >
|
||||
<property name="text" >
|
||||
<string>Step</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="6" >
|
||||
<widget class="Ip6Edit" name="ip6Step" />
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_17" >
|
||||
<property name="text" >
|
||||
<string>Gateway</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="Ip6Edit" name="ip6Gateway" />
|
||||
</item>
|
||||
<item row="0" column="3" >
|
||||
<widget class="QSpinBox" name="ip6PrefixLength" >
|
||||
<property name="minimum" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QToolButton" name="prev" >
|
||||
<property name="text" >
|
||||
<string><</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="next" >
|
||||
<property name="text" >
|
||||
<string>></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>MacEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>macedit.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Ip4Edit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>ip4edit.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Ip6Edit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>ip6edit.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>IntEdit</class>
|
||||
<extends>QSpinBox</extends>
|
||||
<header>intedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>name</tabstop>
|
||||
<tabstop>vlanTagCount</tabstop>
|
||||
<tabstop>vlans</tabstop>
|
||||
<tabstop>devicePerVlanCount</tabstop>
|
||||
<tabstop>macAddress</tabstop>
|
||||
<tabstop>macStep</tabstop>
|
||||
<tabstop>ipStack</tabstop>
|
||||
<tabstop>ip4Address</tabstop>
|
||||
<tabstop>ip4PrefixLength</tabstop>
|
||||
<tabstop>ip4Step</tabstop>
|
||||
<tabstop>ip4Gateway</tabstop>
|
||||
<tabstop>ip6Address</tabstop>
|
||||
<tabstop>ip6PrefixLength</tabstop>
|
||||
<tabstop>ip6Step</tabstop>
|
||||
<tabstop>ip6Gateway</tabstop>
|
||||
<tabstop>prev</tabstop>
|
||||
<tabstop>next</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>DeviceGroupDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>227</x>
|
||||
<y>289</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>DeviceGroupDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>295</x>
|
||||
<y>295</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -1,366 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "devicegroupmodel.h"
|
||||
|
||||
#include "port.h"
|
||||
|
||||
#include "emulproto.pb.h"
|
||||
#include "uint128.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
#include <QMimeData>
|
||||
|
||||
const QLatin1String kDeviceGroupsMimeType(
|
||||
"application/vnd.ostinato.devicegroups");
|
||||
|
||||
enum {
|
||||
kName,
|
||||
kVlanCount,
|
||||
kDeviceCount, // Across all vlans
|
||||
kIp,
|
||||
kIp4Address,
|
||||
kIp6Address,
|
||||
kFieldCount
|
||||
};
|
||||
|
||||
static QStringList columns_ = QStringList()
|
||||
<< "Name"
|
||||
<< "Vlans"
|
||||
<< "Devices"
|
||||
<< "IP Stack"
|
||||
<< "IPv4 Address"
|
||||
<< "IPv6 Address";
|
||||
|
||||
DeviceGroupModel::DeviceGroupModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
port_ = NULL;
|
||||
}
|
||||
|
||||
int DeviceGroupModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (!port_ || parent.isValid())
|
||||
return 0;
|
||||
|
||||
return port_->numDeviceGroups();
|
||||
}
|
||||
|
||||
int DeviceGroupModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
|
||||
return columns_.size();
|
||||
}
|
||||
|
||||
QVariant DeviceGroupModel::headerData(
|
||||
int section,
|
||||
Qt::Orientation orientation,
|
||||
int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
switch (orientation) {
|
||||
case Qt::Horizontal:
|
||||
return columns_[section];
|
||||
case Qt::Vertical:
|
||||
return QString("%1").arg(section + 1);
|
||||
default:
|
||||
Q_ASSERT(false); // Unreachable
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant DeviceGroupModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!port_ || !index.isValid())
|
||||
return QVariant();
|
||||
|
||||
int dgIdx = index.row();
|
||||
int field = index.column();
|
||||
|
||||
Q_ASSERT(dgIdx < port_->numDeviceGroups());
|
||||
Q_ASSERT(field < kFieldCount);
|
||||
|
||||
const OstProto::DeviceGroup *devGrp = port_->deviceGroupByIndex(dgIdx);
|
||||
|
||||
Q_ASSERT(devGrp);
|
||||
|
||||
switch (field) {
|
||||
case kName:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return QString::fromStdString(devGrp->core().name());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kVlanCount:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
if (int v = vlanCount(devGrp))
|
||||
return v;
|
||||
return QString("None");
|
||||
case Qt::TextAlignmentRole:
|
||||
return static_cast<int>(Qt::AlignRight|Qt::AlignVCenter);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kDeviceCount:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return qMax(vlanCount(devGrp), 1)*devGrp->device_count();
|
||||
case Qt::TextAlignmentRole:
|
||||
return static_cast<int>(Qt::AlignRight|Qt::AlignVCenter);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kIp:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
if (devGrp->HasExtension(OstEmul::ip4))
|
||||
if (devGrp->HasExtension(OstEmul::ip6))
|
||||
return QString("Dual Stack");
|
||||
else
|
||||
return QString("IPv4");
|
||||
else if (devGrp->HasExtension(OstEmul::ip6))
|
||||
return QString("IPv6");
|
||||
else
|
||||
return QString("None");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kIp4Address:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
if (devGrp->HasExtension(OstEmul::ip4))
|
||||
return QHostAddress(
|
||||
devGrp->GetExtension(OstEmul::ip4)
|
||||
.address()).toString();
|
||||
else
|
||||
return QString("--");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kIp6Address:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
if (devGrp->HasExtension(OstEmul::ip6)) {
|
||||
OstEmul::Ip6Address ip = devGrp->GetExtension(
|
||||
OstEmul::ip6).address();
|
||||
return QHostAddress(
|
||||
UInt128(ip.hi(), ip.lo()).toArray())
|
||||
.toString();
|
||||
}
|
||||
else
|
||||
return QString("--");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
default:
|
||||
Q_ASSERT(false); // unreachable!
|
||||
break;
|
||||
}
|
||||
|
||||
qWarning("%s: Unsupported field #%d", __FUNCTION__, field);
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool DeviceGroupModel::setData(
|
||||
const QModelIndex & /*index*/,
|
||||
const QVariant & /*value*/,
|
||||
int /*role*/)
|
||||
{
|
||||
if (!port_)
|
||||
return false;
|
||||
|
||||
// TODO; when implementing also implement flags() to
|
||||
// return ItemIsEditable
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList DeviceGroupModel::mimeTypes() const
|
||||
{
|
||||
return QStringList() << kDeviceGroupsMimeType;
|
||||
}
|
||||
|
||||
QMimeData* DeviceGroupModel::mimeData(const QModelIndexList &indexes) const
|
||||
{
|
||||
using ::google::protobuf::uint8;
|
||||
|
||||
if (indexes.isEmpty())
|
||||
return nullptr;
|
||||
|
||||
// indexes may include multiple columns for a row - but we are only
|
||||
// interested in rows 'coz we have a single data for all columns
|
||||
// XXX: use QMap instead of QSet to keep rows in sorted order
|
||||
QMap<int, int> rows;
|
||||
foreach(QModelIndex index, indexes)
|
||||
rows.insert(index.row(), index.row());
|
||||
|
||||
OstProto::DeviceGroupConfigList dgList;
|
||||
dgList.mutable_port_id()->set_id(port_->id());
|
||||
foreach(int row, rows) {
|
||||
OstProto::DeviceGroup *devGrp = dgList.add_device_group();
|
||||
devGrp->CopyFrom(*port_->deviceGroupByIndex(row));
|
||||
}
|
||||
|
||||
QByteArray data;
|
||||
data.resize(dgList.ByteSize());
|
||||
dgList.SerializeWithCachedSizesToArray((uint8*)data.data());
|
||||
//qDebug("copy %s", dgList.DebugString().c_str());
|
||||
//TODO: copy DebugString as text/plain?
|
||||
|
||||
QMimeData *mimeData = new QMimeData();
|
||||
mimeData->setData(kDeviceGroupsMimeType, data);
|
||||
return mimeData; // XXX: caller is expected to take ownership and free!
|
||||
}
|
||||
|
||||
bool DeviceGroupModel::dropMimeData(const QMimeData *data,
|
||||
Qt::DropAction action, int row, int /*column*/,
|
||||
const QModelIndex &parent)
|
||||
{
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
if (!data->hasFormat(kDeviceGroupsMimeType))
|
||||
return false;
|
||||
|
||||
if (action != Qt::CopyAction)
|
||||
return false;
|
||||
|
||||
OstProto::DeviceGroupConfigList dgList;
|
||||
QByteArray ba(data->data(kDeviceGroupsMimeType));
|
||||
dgList.ParseFromArray((void*)ba.constData(), ba.size());
|
||||
//qDebug("paste %s", dgList.DebugString().c_str());
|
||||
|
||||
if ((row < 0) || (row > rowCount(parent)))
|
||||
row = rowCount(parent);
|
||||
|
||||
// Delete rows that we are going to overwrite
|
||||
int c = 0, count = dgList.device_group_size();
|
||||
if (row < rowCount(parent))
|
||||
removeRows(row, qMin(rowCount() - row, count));
|
||||
|
||||
beginInsertRows(parent, row, row+count-1);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (port_->newDeviceGroupAt(row+i, &dgList.device_group(i)))
|
||||
c++;
|
||||
}
|
||||
endInsertRows();
|
||||
|
||||
if (c != count) {
|
||||
qWarning("failed to copy rows in DeviceGroupModel at row %d; "
|
||||
"requested = %d, actual = %d", row, count, c);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceGroupModel::insertRows(
|
||||
int row,
|
||||
int count,
|
||||
const QModelIndex &parent)
|
||||
{
|
||||
int c = 0;
|
||||
|
||||
Q_ASSERT(!parent.isValid());
|
||||
|
||||
beginInsertRows(parent, row, row+count-1);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (port_->newDeviceGroupAt(row))
|
||||
c++;
|
||||
}
|
||||
endInsertRows();
|
||||
|
||||
if (c != count) {
|
||||
qWarning("failed to insert rows in DeviceGroupModel at row %d; "
|
||||
"requested = %d, actual = %d", row, count, c);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceGroupModel::removeRows(
|
||||
int row,
|
||||
int count,
|
||||
const QModelIndex &parent)
|
||||
{
|
||||
int c = 0;
|
||||
|
||||
Q_ASSERT(!parent.isValid());
|
||||
|
||||
beginRemoveRows(parent, row, row+count-1);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (port_->deleteDeviceGroupAt(row))
|
||||
c++;
|
||||
}
|
||||
endRemoveRows();
|
||||
|
||||
if (c != count) {
|
||||
qWarning("failed to delete rows in DeviceGroupModel at row %d; "
|
||||
"requested = %d, actual = %d", row, count, c);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DeviceGroupModel::setPort(Port *port)
|
||||
{
|
||||
beginResetModel();
|
||||
port_ = port;
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
//
|
||||
// ---------------------- Private Methods -----------------------
|
||||
//
|
||||
int DeviceGroupModel::vlanCount(const OstProto::DeviceGroup *deviceGroup) const
|
||||
{
|
||||
if (!deviceGroup->has_encap()
|
||||
|| !deviceGroup->encap().HasExtension(OstEmul::vlan))
|
||||
return 0;
|
||||
|
||||
OstEmul::VlanEmulation vlan = deviceGroup->encap()
|
||||
.GetExtension(OstEmul::vlan);
|
||||
int numTags = vlan.stack_size();
|
||||
int count = 1;
|
||||
|
||||
for (int i = 0; i < numTags; i++)
|
||||
count *= vlan.stack(i).count();
|
||||
|
||||
return count;
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _DEVICE_GROUP_MODEL_H
|
||||
#define _DEVICE_GROUP_MODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QStringList>
|
||||
|
||||
class Port;
|
||||
namespace OstProto {
|
||||
class DeviceGroup;
|
||||
};
|
||||
|
||||
class DeviceGroupModel: public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DeviceGroupModel(QObject *parent = 0);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
bool setData(const QModelIndex &index, const QVariant &value,
|
||||
int role = Qt::EditRole);
|
||||
|
||||
QStringList mimeTypes() const;
|
||||
QMimeData* mimeData(const QModelIndexList &indexes) const;
|
||||
bool dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||
int row, int column, const QModelIndex &parent);
|
||||
|
||||
bool insertRows (int row, int count,
|
||||
const QModelIndex &parent = QModelIndex());
|
||||
bool removeRows (int row, int count,
|
||||
const QModelIndex &parent = QModelIndex());
|
||||
|
||||
void setPort(Port *port);
|
||||
|
||||
private:
|
||||
int vlanCount(const OstProto::DeviceGroup *deviceGroup) const;
|
||||
|
||||
Port *port_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,299 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "devicemodel.h"
|
||||
|
||||
#include "arpstatusmodel.h"
|
||||
#include "ndpstatusmodel.h"
|
||||
#include "port.h"
|
||||
|
||||
#include "emulproto.pb.h"
|
||||
#include "uint128.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QFont>
|
||||
#include <QHostAddress>
|
||||
|
||||
enum {
|
||||
kMacAddress,
|
||||
kVlans,
|
||||
kIp4Address,
|
||||
kIp4Gateway,
|
||||
kIp6Address,
|
||||
kIp6Gateway,
|
||||
kArpInfo,
|
||||
kNdpInfo,
|
||||
kFieldCount
|
||||
};
|
||||
|
||||
static QStringList columns_ = QStringList()
|
||||
<< "Mac"
|
||||
<< "Vlans"
|
||||
<< "IPv4 Address"
|
||||
<< "IPv4 Gateway"
|
||||
<< "IPv6 Address"
|
||||
<< "IPv6 Gateway"
|
||||
<< "ARP"
|
||||
<< "NDP";
|
||||
|
||||
DeviceModel::DeviceModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
port_ = NULL;
|
||||
arpStatusModel_ = new ArpStatusModel(this);
|
||||
ndpStatusModel_ = new NdpStatusModel(this);
|
||||
}
|
||||
|
||||
int DeviceModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (!port_ || parent.isValid())
|
||||
return 0;
|
||||
|
||||
return port_->numDevices();
|
||||
}
|
||||
|
||||
int DeviceModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
|
||||
return columns_.size();
|
||||
}
|
||||
|
||||
QVariant DeviceModel::headerData(
|
||||
int section,
|
||||
Qt::Orientation orientation,
|
||||
int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
switch (orientation) {
|
||||
case Qt::Horizontal:
|
||||
return columns_[section];
|
||||
case Qt::Vertical:
|
||||
return QString("%1").arg(section + 1);
|
||||
default:
|
||||
Q_ASSERT(false); // Unreachable
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant DeviceModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
QString str;
|
||||
|
||||
if (!port_ || !index.isValid())
|
||||
return QVariant();
|
||||
|
||||
int devIdx = index.row();
|
||||
int field = index.column();
|
||||
|
||||
Q_ASSERT(devIdx < port_->numDevices());
|
||||
Q_ASSERT(field < kFieldCount);
|
||||
|
||||
const OstEmul::Device *dev = port_->deviceByIndex(devIdx);
|
||||
|
||||
Q_ASSERT(dev);
|
||||
|
||||
switch (field) {
|
||||
case kMacAddress:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return QString("%1").arg(dev->mac(), 6*2, 16, QChar('0'))
|
||||
.replace(QRegExp("([0-9a-fA-F]{2}\\B)"), "\\1:")
|
||||
.toUpper();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kVlans:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
if (!dev->vlan_size())
|
||||
return QString("None");
|
||||
for (int i = 0; i < dev->vlan_size(); i++)
|
||||
str.append(i == 0 ? "" : ", ")
|
||||
.append(QString::number(dev->vlan(i) & 0xfff));
|
||||
return str;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kIp4Address:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
if (dev->has_ip4_prefix_length())
|
||||
return QString("%1/%2")
|
||||
.arg(QHostAddress(dev->ip4()).toString())
|
||||
.arg(dev->ip4_prefix_length());
|
||||
else
|
||||
return QString("--");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kIp4Gateway:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
if (dev->has_ip4_prefix_length())
|
||||
return QHostAddress(dev->ip4_default_gateway())
|
||||
.toString();
|
||||
else
|
||||
return QString("--");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kIp6Address:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
if (dev->has_ip6_prefix_length()) {
|
||||
OstEmul::Ip6Address ip = dev->ip6();
|
||||
return QString("%1/%2")
|
||||
.arg(QHostAddress(UInt128(ip.hi(), ip.lo())
|
||||
.toArray()).toString())
|
||||
.arg(dev->ip6_prefix_length());
|
||||
}
|
||||
else
|
||||
return QString("--");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kIp6Gateway:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
if (dev->has_ip6_prefix_length()) {
|
||||
OstEmul::Ip6Address ip = dev->ip6_default_gateway();
|
||||
return QHostAddress(
|
||||
UInt128(ip.hi(), ip.lo()).toArray())
|
||||
.toString();
|
||||
}
|
||||
else
|
||||
return QString("--");
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kArpInfo:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
if (dev->has_ip4_prefix_length())
|
||||
return QString("%1/%2")
|
||||
.arg(port_->numArpResolved(devIdx))
|
||||
.arg(port_->numArp(devIdx));
|
||||
else
|
||||
return QString("--");
|
||||
default:
|
||||
if (dev->has_ip4_prefix_length())
|
||||
return drillableStyle(role);
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
case kNdpInfo:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
if (dev->has_ip6_prefix_length())
|
||||
return QString("%1/%2")
|
||||
.arg(port_->numNdpResolved(devIdx))
|
||||
.arg(port_->numNdp(devIdx));
|
||||
else
|
||||
return QString("--");
|
||||
default:
|
||||
if (dev->has_ip6_prefix_length())
|
||||
return drillableStyle(role);
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
|
||||
default:
|
||||
Q_ASSERT(false); // unreachable!
|
||||
break;
|
||||
}
|
||||
|
||||
qWarning("%s: Unsupported field #%d", __FUNCTION__, field);
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Qt::DropActions DeviceModel::supportedDropActions() const
|
||||
{
|
||||
return Qt::IgnoreAction; // read-only model, doesn't accept any data
|
||||
}
|
||||
|
||||
void DeviceModel::setPort(Port *port)
|
||||
{
|
||||
beginResetModel();
|
||||
port_ = port;
|
||||
if (port_)
|
||||
connect(port_, SIGNAL(deviceInfoChanged()), SLOT(updateDeviceList()));
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QAbstractItemModel* DeviceModel::detailModel(const QModelIndex &index)
|
||||
{
|
||||
if (!index.isValid())
|
||||
return NULL;
|
||||
|
||||
switch(index.column()) {
|
||||
case kArpInfo:
|
||||
arpStatusModel_->setDeviceIndex(port_, index.row());
|
||||
return arpStatusModel_;
|
||||
case kNdpInfo:
|
||||
ndpStatusModel_->setDeviceIndex(port_, index.row());
|
||||
return ndpStatusModel_;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceModel::updateDeviceList()
|
||||
{
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
// Style roles for drillable fields
|
||||
QVariant DeviceModel::drillableStyle(int role) const
|
||||
{
|
||||
QFont f;
|
||||
switch (role) {
|
||||
case Qt::ToolTipRole:
|
||||
return QString("Click for details ...");
|
||||
case Qt::ForegroundRole:
|
||||
return QBrush(QColor(Qt::blue));
|
||||
case Qt::FontRole:
|
||||
f.setUnderline(true);
|
||||
return f;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _DEVICE_MODEL_H
|
||||
#define _DEVICE_MODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
|
||||
class ArpStatusModel;
|
||||
class NdpStatusModel;
|
||||
class Port;
|
||||
|
||||
class DeviceModel: public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DeviceModel(QObject *parent = 0);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
|
||||
Qt::DropActions supportedDropActions() const;
|
||||
|
||||
void setPort(Port *port);
|
||||
QAbstractItemModel* detailModel(const QModelIndex &index);
|
||||
|
||||
public slots:
|
||||
void updateDeviceList();
|
||||
|
||||
private:
|
||||
QVariant drillableStyle(int role) const;
|
||||
|
||||
Port *port_;
|
||||
ArpStatusModel *arpStatusModel_;
|
||||
NdpStatusModel *ndpStatusModel_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,302 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "deviceswidget.h"
|
||||
|
||||
#include "clipboardhelper.h"
|
||||
#include "devicegroupdialog.h"
|
||||
#include "port.h"
|
||||
#include "portgrouplist.h"
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QKeyEvent>
|
||||
|
||||
extern ClipboardHelper *clipboardHelper;
|
||||
|
||||
DevicesWidget::DevicesWidget(QWidget *parent)
|
||||
: QWidget(parent), portGroups_(NULL)
|
||||
{
|
||||
setupUi(this);
|
||||
deviceGroupList->setVisible(deviceConfig->isChecked());
|
||||
deviceList->setVisible(deviceInfo->isChecked());
|
||||
setDeviceInfoButtonsVisible(deviceInfo->isChecked());
|
||||
deviceDetail->hide();
|
||||
|
||||
deviceGroupList->verticalHeader()->setDefaultSectionSize(
|
||||
deviceGroupList->verticalHeader()->minimumSectionSize());
|
||||
deviceList->verticalHeader()->setDefaultSectionSize(
|
||||
deviceList->verticalHeader()->minimumSectionSize());
|
||||
deviceDetail->verticalHeader()->setDefaultSectionSize(
|
||||
deviceDetail->verticalHeader()->minimumSectionSize());
|
||||
|
||||
// Populate DeviceGroup Context Menu Actions
|
||||
deviceGroupList->addAction(actionNewDeviceGroup);
|
||||
deviceGroupList->addAction(actionEditDeviceGroup);
|
||||
deviceGroupList->addAction(actionDeleteDeviceGroup);
|
||||
|
||||
// DevicesWidget's actions is an aggegate of all sub-widget's actions
|
||||
addActions(deviceGroupList->actions());
|
||||
|
||||
// Add the clipboard actions to the context menu of deviceGroupList
|
||||
// but not to DeviceWidget's actions since they are already available
|
||||
// in the global Edit Menu
|
||||
QAction *sep = new QAction("Clipboard", this);
|
||||
sep->setSeparator(true);
|
||||
deviceGroupList->addAction(sep);
|
||||
deviceGroupList->addActions(clipboardHelper->actions());
|
||||
}
|
||||
|
||||
void DevicesWidget::setPortGroupList(PortGroupList *portGroups)
|
||||
{
|
||||
portGroups_ = portGroups;
|
||||
|
||||
deviceGroupList->setModel(portGroups_->getDeviceGroupModel());
|
||||
deviceList->setModel(portGroups_->getDeviceModel());
|
||||
|
||||
connect(portGroups_->getDeviceGroupModel(),
|
||||
SIGNAL(rowsInserted(QModelIndex, int, int)),
|
||||
SLOT(updateDeviceViewActions()));
|
||||
connect(portGroups_->getDeviceGroupModel(),
|
||||
SIGNAL(rowsRemoved(QModelIndex, int, int)),
|
||||
SLOT(updateDeviceViewActions()));
|
||||
|
||||
connect(deviceGroupList->selectionModel(),
|
||||
SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
|
||||
SLOT(updateDeviceViewActions()));
|
||||
connect(deviceGroupList->selectionModel(),
|
||||
SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
||||
SLOT(updateDeviceViewActions()));
|
||||
|
||||
connect(deviceList->selectionModel(),
|
||||
SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
|
||||
SLOT(when_deviceList_currentChanged(const QModelIndex&)));
|
||||
|
||||
// FIXME: hardcoding
|
||||
deviceGroupList->resizeColumnToContents(1); // Vlan Count
|
||||
deviceGroupList->resizeColumnToContents(2); // Device Count
|
||||
|
||||
// FIXME: hardcoding
|
||||
deviceList->resizeColumnToContents(1); // Vlan Id(s)
|
||||
deviceList->resizeColumnToContents(6); // ARP Info
|
||||
deviceList->resizeColumnToContents(7); // NDP Info
|
||||
|
||||
updateDeviceViewActions();
|
||||
}
|
||||
|
||||
void DevicesWidget::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == Qt::Key_Escape) {
|
||||
deviceDetail->hide();
|
||||
event->accept();
|
||||
}
|
||||
else
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void DevicesWidget::setCurrentPortIndex(const QModelIndex &portIndex)
|
||||
{
|
||||
Port *port = NULL;
|
||||
|
||||
if (!portGroups_)
|
||||
return;
|
||||
|
||||
// XXX: We assume portIndex corresponds to sourceModel, not proxyModel
|
||||
if (portGroups_->isPort(portIndex))
|
||||
port = &portGroups_->port(portIndex);
|
||||
|
||||
portGroups_->getDeviceGroupModel()->setPort(port);
|
||||
portGroups_->getDeviceModel()->setPort(port);
|
||||
currentPortIndex_ = portIndex;
|
||||
|
||||
updateDeviceViewActions();
|
||||
}
|
||||
|
||||
void DevicesWidget::updateDeviceViewActions()
|
||||
{
|
||||
QItemSelectionModel *devSel = deviceGroupList->selectionModel();
|
||||
|
||||
if (!portGroups_)
|
||||
return;
|
||||
|
||||
// For some reason hasSelection() returns true even if selection size is 0
|
||||
// so additional check for size introduced
|
||||
if (devSel->hasSelection() && (devSel->selection().size() > 0)) {
|
||||
// If more than one non-contiguous ranges selected,
|
||||
// disable "New" and "Edit"
|
||||
if (devSel->selection().size() > 1) {
|
||||
actionNewDeviceGroup->setDisabled(true);
|
||||
actionEditDeviceGroup->setDisabled(true);
|
||||
}
|
||||
else {
|
||||
actionNewDeviceGroup->setEnabled(true);
|
||||
|
||||
// Enable "Edit" only if the single range has a single row
|
||||
if (devSel->selection().at(0).height() > 1)
|
||||
actionEditDeviceGroup->setDisabled(true);
|
||||
else
|
||||
actionEditDeviceGroup->setEnabled(true);
|
||||
}
|
||||
|
||||
// Delete is always enabled as long as we have a selection
|
||||
actionDeleteDeviceGroup->setEnabled(true);
|
||||
}
|
||||
else {
|
||||
qDebug("No device selection");
|
||||
if (portGroups_->isPort(currentPortIndex_))
|
||||
actionNewDeviceGroup->setEnabled(true);
|
||||
else
|
||||
actionNewDeviceGroup->setDisabled(true);
|
||||
actionEditDeviceGroup->setDisabled(true);
|
||||
actionDeleteDeviceGroup->setDisabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// DeviceGroup slots
|
||||
//
|
||||
|
||||
void DevicesWidget::on_deviceInfo_toggled(bool checked)
|
||||
{
|
||||
setDeviceInfoButtonsVisible(checked);
|
||||
deviceGroupList->setHidden(checked);
|
||||
deviceList->setVisible(checked);
|
||||
deviceDetail->hide();
|
||||
}
|
||||
|
||||
void DevicesWidget::on_actionNewDeviceGroup_triggered()
|
||||
{
|
||||
if (!portGroups_)
|
||||
return;
|
||||
|
||||
// In case nothing is selected, insert 1 row at the end
|
||||
int row = portGroups_->getDeviceGroupModel()->rowCount(), count = 1;
|
||||
QItemSelection selection = deviceGroupList->selectionModel()->selection();
|
||||
|
||||
// In case we have a single range selected; insert as many rows as
|
||||
// in the singe selected range before the top of the selected range
|
||||
if (selection.size() == 1) {
|
||||
row = selection.at(0).top();
|
||||
count = selection.at(0).height();
|
||||
}
|
||||
|
||||
portGroups_->getDeviceGroupModel()->insertRows(row, count);
|
||||
}
|
||||
|
||||
void DevicesWidget::on_actionDeleteDeviceGroup_triggered()
|
||||
{
|
||||
QModelIndex index;
|
||||
|
||||
if (!portGroups_)
|
||||
return;
|
||||
|
||||
if (deviceGroupList->selectionModel()->hasSelection()) {
|
||||
while(deviceGroupList->selectionModel()->selectedRows().size()) {
|
||||
index = deviceGroupList->selectionModel()->selectedRows().at(0);
|
||||
portGroups_->getDeviceGroupModel()->removeRows(index.row(), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DevicesWidget::on_actionEditDeviceGroup_triggered()
|
||||
{
|
||||
QItemSelection selection = deviceGroupList->selectionModel()->selection();
|
||||
|
||||
// Ensure we have only one range selected which contains only one row
|
||||
if ((selection.size() == 1) && (selection.at(0).height() == 1))
|
||||
on_deviceGroupList_activated(selection.at(0).topLeft());
|
||||
}
|
||||
|
||||
void DevicesWidget::on_deviceGroupList_activated(const QModelIndex &index)
|
||||
{
|
||||
if (!index.isValid() || !portGroups_)
|
||||
return;
|
||||
|
||||
DeviceGroupDialog dgd(&portGroups_->port(currentPortIndex_), index.row());
|
||||
dgd.exec();
|
||||
}
|
||||
|
||||
void DevicesWidget::on_refresh_clicked()
|
||||
{
|
||||
if (!portGroups_)
|
||||
return;
|
||||
|
||||
Q_ASSERT(portGroups_->isPort(currentPortIndex_));
|
||||
QModelIndex curPortGroup = portGroups_->getPortModel()
|
||||
->parent(currentPortIndex_);
|
||||
Q_ASSERT(curPortGroup.isValid());
|
||||
Q_ASSERT(portGroups_->isPortGroup(curPortGroup));
|
||||
|
||||
deviceDetail->hide();
|
||||
portGroups_->portGroup(curPortGroup)
|
||||
.getDeviceInfo(portGroups_->port(currentPortIndex_).id());
|
||||
}
|
||||
|
||||
void DevicesWidget::on_resolveNeighbors_clicked()
|
||||
{
|
||||
if (!portGroups_)
|
||||
return;
|
||||
|
||||
Q_ASSERT(portGroups_->isPort(currentPortIndex_));
|
||||
QModelIndex curPortGroup = portGroups_->getPortModel()
|
||||
->parent(currentPortIndex_);
|
||||
Q_ASSERT(curPortGroup.isValid());
|
||||
Q_ASSERT(portGroups_->isPortGroup(curPortGroup));
|
||||
|
||||
deviceDetail->hide();
|
||||
QList<uint> portList({portGroups_->port(currentPortIndex_).id()});
|
||||
portGroups_->portGroup(curPortGroup).resolveDeviceNeighbors(&portList);
|
||||
portGroups_->portGroup(curPortGroup).getDeviceInfo(portList.at(0));
|
||||
}
|
||||
|
||||
void DevicesWidget::on_clearNeighbors_clicked()
|
||||
{
|
||||
if (!portGroups_)
|
||||
return;
|
||||
|
||||
Q_ASSERT(portGroups_->isPort(currentPortIndex_));
|
||||
QModelIndex curPortGroup = portGroups_->getPortModel()
|
||||
->parent(currentPortIndex_);
|
||||
Q_ASSERT(curPortGroup.isValid());
|
||||
Q_ASSERT(portGroups_->isPortGroup(curPortGroup));
|
||||
|
||||
deviceDetail->hide();
|
||||
QList<uint> portList({portGroups_->port(currentPortIndex_).id()});
|
||||
portGroups_->portGroup(curPortGroup).clearDeviceNeighbors(&portList);
|
||||
portGroups_->portGroup(curPortGroup).getDeviceInfo(portList.at(0));
|
||||
}
|
||||
|
||||
void DevicesWidget::when_deviceList_currentChanged(const QModelIndex &index)
|
||||
{
|
||||
if (!index.isValid() || !portGroups_)
|
||||
return;
|
||||
|
||||
QAbstractItemModel *detailModel = portGroups_->getDeviceModel()
|
||||
->detailModel(index);
|
||||
|
||||
deviceDetail->setModel(detailModel);
|
||||
deviceDetail->setVisible(detailModel != NULL);
|
||||
}
|
||||
|
||||
void DevicesWidget::setDeviceInfoButtonsVisible(bool show)
|
||||
{
|
||||
refresh->setVisible(show);
|
||||
arpNdpLabel->setVisible(show);
|
||||
resolveNeighbors->setVisible(show);
|
||||
clearNeighbors->setVisible(show);
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2016 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _DEVICES_WIDGET_H
|
||||
#define _DEVICES_WIDGET_H
|
||||
|
||||
#include "ui_deviceswidget.h"
|
||||
#include <QWidget>
|
||||
|
||||
class PortGroupList;
|
||||
|
||||
class DevicesWidget: public QWidget, private Ui::DevicesWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DevicesWidget(QWidget *parent = NULL);
|
||||
void setPortGroupList(PortGroupList *portGroups);
|
||||
|
||||
virtual void keyPressEvent(QKeyEvent *event);
|
||||
|
||||
public slots:
|
||||
void setCurrentPortIndex(const QModelIndex &portIndex);
|
||||
|
||||
private slots:
|
||||
void updateDeviceViewActions();
|
||||
|
||||
void on_deviceInfo_toggled(bool checked);
|
||||
|
||||
void on_actionNewDeviceGroup_triggered();
|
||||
void on_actionDeleteDeviceGroup_triggered();
|
||||
void on_actionEditDeviceGroup_triggered();
|
||||
void on_deviceGroupList_activated(const QModelIndex &index);
|
||||
|
||||
void on_refresh_clicked();
|
||||
void on_resolveNeighbors_clicked();
|
||||
void on_clearNeighbors_clicked();
|
||||
|
||||
void when_deviceList_currentChanged(const QModelIndex &index);
|
||||
|
||||
private:
|
||||
void setDeviceInfoButtonsVisible(bool show);
|
||||
|
||||
PortGroupList *portGroups_;
|
||||
QModelIndex currentPortIndex_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,206 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DevicesWidget</class>
|
||||
<widget class="QWidget" name="DevicesWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>675</width>
|
||||
<height>328</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="deviceConfig">
|
||||
<property name="text">
|
||||
<string>Configuration</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="deviceInfo">
|
||||
<property name="text">
|
||||
<string>Information</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="refresh">
|
||||
<property name="toolTip">
|
||||
<string>Refresh information</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Refresh device and neighbor information</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="ostinato.qrc">
|
||||
<normaloff>:/icons/refresh.png</normaloff>:/icons/refresh.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>131</width>
|
||||
<height>23</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="arpNdpLabel">
|
||||
<property name="text">
|
||||
<string>ARP/ND</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="resolveNeighbors">
|
||||
<property name="toolTip">
|
||||
<string>Resolve Neighbors</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Resolve Device Neighbors on selected port(s)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="ostinato.qrc">
|
||||
<normaloff>:/icons/neighbor_resolve.png</normaloff>:/icons/neighbor_resolve.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="clearNeighbors">
|
||||
<property name="toolTip">
|
||||
<string>Clear Neighbors</string>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Clear Device Neighbors on selected port(s)</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="ostinato.qrc">
|
||||
<normaloff>:/icons/neighbor_clear.png</normaloff>:/icons/neighbor_clear.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="XTableView" name="deviceGroupList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::ActionsContextMenu</enum>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>This is the device group list for the selected port
|
||||
|
||||
A device group is a set of one or more devices/hosts which will be emulated by Ostinato
|
||||
|
||||
Right-click to create/edit a device group</string>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="lineWidth">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="XTableView" name="deviceList">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>No devices being emulated
|
||||
|
||||
To emulate a device, click on Configuration and create a device group</string>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="XTableView" name="deviceDetail">
|
||||
<property name="whatsThis">
|
||||
<string>IP neighbor cache is empty</string>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectRows</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<action name="actionNewDeviceGroup">
|
||||
<property name="icon">
|
||||
<iconset resource="ostinato.qrc">
|
||||
<normaloff>:/icons/devicegroup_add.png</normaloff>:/icons/devicegroup_add.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>New Device Group</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDeleteDeviceGroup">
|
||||
<property name="icon">
|
||||
<iconset resource="ostinato.qrc">
|
||||
<normaloff>:/icons/devicegroup_delete.png</normaloff>:/icons/devicegroup_delete.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete Device Group</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEditDeviceGroup">
|
||||
<property name="icon">
|
||||
<iconset resource="ostinato.qrc">
|
||||
<normaloff>:/icons/devicegroup_edit.png</normaloff>:/icons/devicegroup_edit.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Edit Device Group</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>XTableView</class>
|
||||
<extends>QTableView</extends>
|
||||
<header>xtableview.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="ostinato.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
@ -1,414 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2010 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "dumpview.h"
|
||||
|
||||
#include <QScrollBar>
|
||||
#include <QStylePainter>
|
||||
|
||||
//! \todo Enable Scrollbars
|
||||
|
||||
DumpView::DumpView(QWidget *parent)
|
||||
: QAbstractItemView(parent)
|
||||
{
|
||||
int w, h;
|
||||
|
||||
// NOTE: Monospaced fonts only !!!!!!!!!!!
|
||||
setFont(QFont("Courier"));
|
||||
w = fontMetrics().width('X');
|
||||
h = fontMetrics().height();
|
||||
|
||||
mLineHeight = h;
|
||||
mCharWidth = w;
|
||||
|
||||
mSelectedRow = mSelectedCol = -1;
|
||||
|
||||
// calculate width for offset column and the whitespace that follows it
|
||||
// 0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
|
||||
mOffsetPaneTopRect = QRect(0, 0, w*4, h);
|
||||
mDumpPaneTopRect = QRect(mOffsetPaneTopRect.right()+w*3, 0,
|
||||
w*((8*3-1)+2+(8*3-1)), h);
|
||||
mAsciiPaneTopRect = QRect(mDumpPaneTopRect.right()+w*3, 0,
|
||||
w*(8+1+8), h);
|
||||
qDebug("DumpView::DumpView");
|
||||
}
|
||||
|
||||
QModelIndex DumpView::indexAt(const QPoint &/*point*/) const
|
||||
{
|
||||
#if 0
|
||||
int x = point.x();
|
||||
int row, col;
|
||||
|
||||
if (x > mAsciiPaneTopRect.left())
|
||||
{
|
||||
col = (x - mAsciiPaneTopRect.left()) / mCharWidth;
|
||||
if (col == 8) // don't select whitespace
|
||||
goto _exit;
|
||||
else if (col > 8) // adjust for whitespace
|
||||
col--;
|
||||
}
|
||||
else if (x > mDumpPaneTopRect.left())
|
||||
{
|
||||
col = (x - mDumpPaneTopRect.left()) / (mCharWidth*3);
|
||||
}
|
||||
row = point.y()/mLineHeight;
|
||||
|
||||
if ((col < 16) && (row < ((data.size()+16)/16)))
|
||||
{
|
||||
selrow = row;
|
||||
selcol = col;
|
||||
}
|
||||
else
|
||||
goto _exit;
|
||||
|
||||
// last row check col
|
||||
if ((row == (((data.size()+16)/16) - 1)) && (col >= (data.size() % 16)))
|
||||
goto _exit;
|
||||
|
||||
qDebug("dumpview::selection(%d, %d)", selrow, selcol);
|
||||
|
||||
offset = selrow * 16 + selcol;
|
||||
#if 0
|
||||
for(int i = 0; i < model()->rowCount(parent); i++)
|
||||
{
|
||||
QModelIndex index = model()->index(i, 0, parent);
|
||||
|
||||
if (model()->hasChildren(index))
|
||||
indexAtOffset(offset, index); // Non Leaf
|
||||
else
|
||||
if (
|
||||
dump.append(model()->data(index, Qt::UserRole).toByteArray()); // Leaf
|
||||
// FIXME: Use RawValueRole instead of UserRole
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
_exit:
|
||||
// Clear existing selection
|
||||
selrow = -1;
|
||||
|
||||
#endif
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
void DumpView::scrollTo(const QModelIndex &/*index*/, ScrollHint /*hint*/)
|
||||
{
|
||||
// FIXME: implement scrolling
|
||||
}
|
||||
|
||||
QRect DumpView::visualRect(const QModelIndex &/*index*/) const
|
||||
{
|
||||
// FIXME: calculate actual rect
|
||||
return rect();
|
||||
}
|
||||
|
||||
//protected:
|
||||
int DumpView::horizontalOffset() const
|
||||
{
|
||||
return horizontalScrollBar()->value();
|
||||
}
|
||||
|
||||
bool DumpView::isIndexHidden(const QModelIndex &/*index*/) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
QModelIndex DumpView::moveCursor(CursorAction /*cursorAction*/,
|
||||
Qt::KeyboardModifiers /*modifiers*/)
|
||||
{
|
||||
// FIXME(MED): need to implement movement using cursor
|
||||
return currentIndex();
|
||||
}
|
||||
|
||||
void DumpView::setSelection(const QRect &/*rect*/,
|
||||
QItemSelectionModel::SelectionFlags flags)
|
||||
{
|
||||
// FIXME(HI): calculate indexes using rect
|
||||
selectionModel()->select(QModelIndex(), flags);
|
||||
}
|
||||
|
||||
int DumpView::verticalOffset() const
|
||||
{
|
||||
return verticalScrollBar()->value();
|
||||
}
|
||||
|
||||
QRegion DumpView::visualRegionForSelection(
|
||||
const QItemSelection &/*selection*/) const
|
||||
{
|
||||
// FIXME(HI)
|
||||
return QRegion(rect());
|
||||
}
|
||||
|
||||
//protected slots:
|
||||
void DumpView::dataChanged(const QModelIndex &/*topLeft*/,
|
||||
const QModelIndex &/*bottomRight*/,
|
||||
const QVector<int> &/*roles*/)
|
||||
{
|
||||
// FIXME(HI)
|
||||
update();
|
||||
}
|
||||
|
||||
void DumpView::selectionChanged(const QItemSelection &/*selected*/,
|
||||
const QItemSelection &/*deselected*/)
|
||||
{
|
||||
// FIXME(HI)
|
||||
update();
|
||||
}
|
||||
|
||||
void DumpView::populateDump(QByteArray &dump, int &selOfs, int &selSize,
|
||||
QModelIndex parent)
|
||||
{
|
||||
// FIXME: Use new enum instead of Qt::UserRole
|
||||
//! \todo (low): generalize this for any model not just our pkt model
|
||||
|
||||
Q_ASSERT(!parent.isValid());
|
||||
|
||||
qDebug("!!!! %d $$$$", dump.size());
|
||||
|
||||
for(int i = 0; i < model()->rowCount(parent); i++)
|
||||
{
|
||||
QModelIndex index = model()->index(i, 0, parent);
|
||||
|
||||
Q_ASSERT(index.isValid());
|
||||
|
||||
// Assumption: protocol data is in bytes (not bits)
|
||||
qDebug("%d: %d bytes", i, model()->data(index, Qt::UserRole).toByteArray().size());
|
||||
dump.append(model()->data(index, Qt::UserRole).toByteArray());
|
||||
|
||||
}
|
||||
|
||||
if (selectionModel()->selectedIndexes().size())
|
||||
{
|
||||
int j, bits;
|
||||
QModelIndex index;
|
||||
|
||||
Q_ASSERT(selectionModel()->selectedIndexes().size() == 1);
|
||||
index = selectionModel()->selectedIndexes().at(0);
|
||||
|
||||
if (index.parent().isValid())
|
||||
{
|
||||
// Field
|
||||
|
||||
// SelOfs = SUM(protocol sizes before selected field's protocol) +
|
||||
// SUM(field sizes before selected field)
|
||||
|
||||
selOfs = 0;
|
||||
j = index.parent().row() - 1;
|
||||
while (j >= 0)
|
||||
{
|
||||
selOfs += model()->data(index.parent().sibling(j,0),
|
||||
Qt::UserRole).toByteArray().size();
|
||||
j--;
|
||||
}
|
||||
|
||||
bits = 0;
|
||||
j = index.row() - 1;
|
||||
while (j >= 0)
|
||||
{
|
||||
bits += model()->data(index.sibling(j,0), Qt::UserRole+1).
|
||||
toInt();
|
||||
j--;
|
||||
}
|
||||
selOfs += bits/8;
|
||||
selSize = model()->data(index, Qt::UserRole).toByteArray().size();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Protocol
|
||||
selOfs = 0;
|
||||
j = index.row() - 1;
|
||||
while (j >= 0)
|
||||
{
|
||||
selOfs += model()->data(index.sibling(j,0), Qt::UserRole).
|
||||
toByteArray().size();
|
||||
j--;
|
||||
}
|
||||
selSize = model()->data(index, Qt::UserRole).toByteArray().size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(LOW): rewrite this function - it's a mess!
|
||||
void DumpView::paintEvent(QPaintEvent* /*event*/)
|
||||
{
|
||||
QStylePainter painter(viewport());
|
||||
QRect offsetRect = mOffsetPaneTopRect;
|
||||
QRect dumpRect = mDumpPaneTopRect;
|
||||
QRect asciiRect = mAsciiPaneTopRect;
|
||||
QPalette pal = palette();
|
||||
static QByteArray data;
|
||||
//QByteArray ba;
|
||||
int selOfs = -1, selSize;
|
||||
int curSelOfs, curSelSize;
|
||||
|
||||
qDebug("dumpview::paintEvent");
|
||||
|
||||
// FIXME(LOW): unable to set the self widget's font in constructor
|
||||
painter.setFont(QFont("Courier"));
|
||||
|
||||
// Qt automatically clears the background before we are called
|
||||
// QWidget::paintEvent doc:
|
||||
// When the paint event occurs, the update region has normally
|
||||
// been erased, so you are painting on the widget's background.
|
||||
|
||||
if (model())
|
||||
{
|
||||
data.clear();
|
||||
populateDump(data, selOfs, selSize);
|
||||
}
|
||||
|
||||
// display the offset, dump and ascii panes 8 + 8 bytes on a line
|
||||
for (int i = 0; i < data.size(); i+=16)
|
||||
{
|
||||
QString dumpStr, asciiStr;
|
||||
|
||||
//ba = data.mid(i, 16);
|
||||
|
||||
// display offset
|
||||
painter.drawItemText(offsetRect, Qt::AlignLeft | Qt::AlignTop, pal,
|
||||
true, QString("%1").arg(i, 4, 16, QChar('0')), QPalette::WindowText);
|
||||
// construct the dumpStr and asciiStr
|
||||
for (int j = i; (j < (i+16)) && (j < data.size()); j++)
|
||||
{
|
||||
unsigned char c = data.at(j);
|
||||
|
||||
// extra space after 8 bytes
|
||||
if (((j+8) % 16) == 0)
|
||||
{
|
||||
dumpStr.append(" ");
|
||||
asciiStr.append(" ");
|
||||
}
|
||||
|
||||
dumpStr.append(QString("%1").arg((uint)c, 2, 16, QChar('0')).
|
||||
toUpper()).append(" ");
|
||||
|
||||
if (isPrintable(c))
|
||||
asciiStr.append(QChar(c));
|
||||
else
|
||||
asciiStr.append(QChar('.'));
|
||||
}
|
||||
|
||||
// display dump
|
||||
painter.drawItemText(dumpRect, Qt::AlignLeft | Qt::AlignTop, pal,
|
||||
true, dumpStr, QPalette::WindowText);
|
||||
|
||||
// display ascii
|
||||
painter.drawItemText(asciiRect, Qt::AlignLeft | Qt::AlignTop, pal,
|
||||
true, asciiStr, QPalette::WindowText);
|
||||
|
||||
// if no selection, skip selection painting
|
||||
if (selOfs < 0)
|
||||
goto _next;
|
||||
|
||||
// Check overlap between current row and selection
|
||||
{
|
||||
QRect r1(i, 0, qMin(16, data.size()-i), 8);
|
||||
QRect s1(selOfs, 0, selSize, 8);
|
||||
if (r1.intersects(s1))
|
||||
{
|
||||
QRect t = r1.intersected(s1);
|
||||
|
||||
curSelOfs = t.x();
|
||||
curSelSize = t.width();
|
||||
}
|
||||
else
|
||||
curSelSize = 0;
|
||||
|
||||
}
|
||||
|
||||
// overpaint selection on current row (if any)
|
||||
if (curSelSize > 0)
|
||||
{
|
||||
QRect r;
|
||||
QString selectedAsciiStr, selectedDumpStr;
|
||||
|
||||
qDebug("dumpview::paintEvent - Highlighted (%d, %d)",
|
||||
curSelOfs, curSelSize);
|
||||
|
||||
// construct the dumpStr and asciiStr
|
||||
for (int k = curSelOfs; (k < (curSelOfs + curSelSize)); k++)
|
||||
{
|
||||
unsigned char c = data.at(k);
|
||||
|
||||
// extra space after 8 bytes
|
||||
if (((k+8) % 16) == 0)
|
||||
{
|
||||
// Avoid adding space at the start for fields starting
|
||||
// at second column 8 byte boundary
|
||||
if (k!=curSelOfs)
|
||||
{
|
||||
selectedDumpStr.append(" ");
|
||||
selectedAsciiStr.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
selectedDumpStr.append(QString("%1").arg((uint)c, 2, 16,
|
||||
QChar('0')).toUpper()).append(" ");
|
||||
|
||||
if (isPrintable(c))
|
||||
selectedAsciiStr.append(QChar(c));
|
||||
else
|
||||
selectedAsciiStr.append(QChar('.'));
|
||||
}
|
||||
|
||||
// display dump
|
||||
r = dumpRect;
|
||||
if ((curSelOfs - i) < 8)
|
||||
r.translate(mCharWidth*(curSelOfs-i)*3, 0);
|
||||
else
|
||||
r.translate(mCharWidth*((curSelOfs-i)*3+1), 0);
|
||||
|
||||
// adjust width taking care of selection stretching between
|
||||
// the two 8byte columns
|
||||
if (( (curSelOfs-i) < 8 ) && ( (curSelOfs-i+curSelSize) > 8 ))
|
||||
r.setWidth((curSelSize * 3 + 1) * mCharWidth);
|
||||
else
|
||||
r.setWidth((curSelSize * 3) * mCharWidth);
|
||||
|
||||
painter.fillRect(r, pal.highlight());
|
||||
painter.drawItemText(r, Qt::AlignLeft | Qt::AlignTop, pal,
|
||||
true, selectedDumpStr, QPalette::HighlightedText);
|
||||
|
||||
// display ascii
|
||||
r = asciiRect;
|
||||
if ((curSelOfs - i) < 8)
|
||||
r.translate(mCharWidth*(curSelOfs-i)*1, 0);
|
||||
else
|
||||
r.translate(mCharWidth*((curSelOfs-i)*1+1), 0);
|
||||
|
||||
// adjust width taking care of selection stretching between
|
||||
// the two 8byte columns
|
||||
if (( (curSelOfs-i) < 8 ) && ( (curSelOfs-i+curSelSize) > 8 ))
|
||||
r.setWidth((curSelSize * 1 + 1) * mCharWidth);
|
||||
else
|
||||
r.setWidth((curSelSize * 1) * mCharWidth);
|
||||
|
||||
painter.fillRect(r, pal.highlight());
|
||||
painter.drawItemText(r, Qt::AlignLeft | Qt::AlignTop, pal,
|
||||
true, selectedAsciiStr, QPalette::HighlightedText);
|
||||
}
|
||||
|
||||
_next:
|
||||
// move the rects down
|
||||
offsetRect.translate(0, mLineHeight);
|
||||
dumpRect.translate(0, mLineHeight);
|
||||
asciiRect.translate(0, mLineHeight);
|
||||
}
|
||||
}
|
||||
|
@ -1,62 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2010 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include <QAbstractItemView>
|
||||
|
||||
|
||||
class DumpView: public QAbstractItemView
|
||||
{
|
||||
public:
|
||||
DumpView(QWidget *parent=0);
|
||||
|
||||
QModelIndex indexAt( const QPoint &point ) const;
|
||||
void scrollTo( const QModelIndex &index, ScrollHint hint = EnsureVisible );
|
||||
QRect visualRect( const QModelIndex &index ) const;
|
||||
|
||||
protected:
|
||||
int horizontalOffset() const;
|
||||
bool isIndexHidden( const QModelIndex &index ) const;
|
||||
QModelIndex moveCursor( CursorAction cursorAction,
|
||||
Qt::KeyboardModifiers modifiers );
|
||||
void setSelection( const QRect &rect, QItemSelectionModel::SelectionFlags flags );
|
||||
int verticalOffset() const;
|
||||
QRegion visualRegionForSelection( const QItemSelection &selection ) const;
|
||||
protected slots:
|
||||
void dataChanged( const QModelIndex &topLeft,
|
||||
const QModelIndex &bottomRight,
|
||||
const QVector<int> &roles );
|
||||
void selectionChanged( const QItemSelection &selected,
|
||||
const QItemSelection &deselected );
|
||||
void paintEvent(QPaintEvent *event);
|
||||
|
||||
private:
|
||||
void populateDump(QByteArray &dump, int &selOfs, int &selSize,
|
||||
QModelIndex parent = QModelIndex());
|
||||
bool inline isPrintable(char c)
|
||||
{if ((c >= 32) && (c <= 126)) return true; else return false; }
|
||||
|
||||
private:
|
||||
QRect mOffsetPaneTopRect;
|
||||
QRect mDumpPaneTopRect;
|
||||
QRect mAsciiPaneTopRect;
|
||||
int mSelectedRow, mSelectedCol;
|
||||
int mLineHeight;
|
||||
int mCharWidth;
|
||||
};
|
||||
|
@ -1,98 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2021 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "fieldedit.h"
|
||||
|
||||
FieldEdit::FieldEdit(QWidget *parent)
|
||||
: QLineEdit(parent)
|
||||
{
|
||||
setType(kUInt64);
|
||||
}
|
||||
|
||||
void FieldEdit::setType(FieldType type)
|
||||
{
|
||||
// clear existing contents before changing the validator
|
||||
clear();
|
||||
setPlaceholderText("");
|
||||
|
||||
type_ = type;
|
||||
switch (type_) {
|
||||
case kUInt64:
|
||||
setValidator(&uint64Validator_);
|
||||
if (isMaskMode_)
|
||||
setText("0xFFFFFFFFFFFFFFFF");
|
||||
break;
|
||||
case kMacAddress:
|
||||
setValidator(&macValidator_);
|
||||
setPlaceholderText("00:00:00:00:00:00");
|
||||
if (isMaskMode_)
|
||||
setText("FF:FF:FF:FF:FF:FF");
|
||||
break;
|
||||
case kIp4Address:
|
||||
setValidator(&ip4Validator_);
|
||||
setPlaceholderText("0.0.0.0");
|
||||
if (isMaskMode_)
|
||||
setText("255.255.255.255");
|
||||
break;
|
||||
case kIp6Address:
|
||||
setValidator(&ip6Validator_);
|
||||
setPlaceholderText("::");
|
||||
if (isMaskMode_)
|
||||
setText("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF");
|
||||
break;
|
||||
default:
|
||||
setValidator(nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Applicable only if type is kUInt64
|
||||
void FieldEdit::setRange(quint64 min, quint64 max)
|
||||
{
|
||||
uint64Validator_.setRange(min, max);
|
||||
if (type_ == kUInt64) {
|
||||
setPlaceholderText(QString("%1 - %2").arg(min).arg(max));
|
||||
if (isMaskMode_)
|
||||
setText(QString::number(max, 16).toUpper().prepend("0x"));
|
||||
}
|
||||
}
|
||||
|
||||
void FieldEdit::setMaskMode(bool maskMode)
|
||||
{
|
||||
isMaskMode_ = maskMode;
|
||||
}
|
||||
|
||||
QString FieldEdit::text() const
|
||||
{
|
||||
QString str = QLineEdit::text();
|
||||
|
||||
switch (type_) {
|
||||
case kMacAddress:
|
||||
str.remove(QRegularExpression("[:-]"));
|
||||
str.prepend("0x");
|
||||
break;
|
||||
case kIp4Address:
|
||||
str = QString::number(QHostAddress(str).toIPv4Address());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2021 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _FIELD_EDIT_H
|
||||
#define _FIELD_EDIT_H
|
||||
|
||||
#include "ipv4addressvalidator.h"
|
||||
#include "ipv6addressvalidator.h"
|
||||
#include "macaddressvalidator.h"
|
||||
#include "ulonglongvalidator.h"
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
class FieldEdit: public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum FieldType {
|
||||
kUInt64,
|
||||
kMacAddress,
|
||||
kIp4Address,
|
||||
kIp6Address
|
||||
};
|
||||
FieldEdit(QWidget *parent = 0);
|
||||
|
||||
void setType(FieldType type);
|
||||
void setRange(quint64 min, quint64 max);
|
||||
|
||||
void setMaskMode(bool maskMode);
|
||||
|
||||
QString text() const;
|
||||
|
||||
private:
|
||||
FieldType type_{kUInt64};
|
||||
bool isMaskMode_{false};
|
||||
|
||||
IPv4AddressValidator ip4Validator_;
|
||||
IPv6AddressValidator ip6Validator_;
|
||||
MacAddressValidator macValidator_;
|
||||
ULongLongValidator uint64Validator_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,230 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2021 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "findreplace.h"
|
||||
|
||||
#include "abstractprotocol.h"
|
||||
#include "iputils.h"
|
||||
#include "mandatoryfieldsgroup.h"
|
||||
#include "protocolmanager.h"
|
||||
#include "stream.h"
|
||||
#include "uint128.h"
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
extern ProtocolManager *OstProtocolManager;
|
||||
|
||||
// TODO: It might be useful for this dialog to support a "preview"
|
||||
// of the replacements
|
||||
|
||||
FindReplaceDialog::FindReplaceDialog(Action *action, QWidget *parent)
|
||||
: QDialog(parent), action_(action)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
findMask->setMaskMode(true);
|
||||
replaceMask->setMaskMode(true);
|
||||
|
||||
// Keep things simple and don't use mask(s) (default)
|
||||
useFindMask->setChecked(false);
|
||||
useReplaceMask->setChecked(false);
|
||||
|
||||
// TODO: remove combo protocols - see note in StreamBase::findReplace
|
||||
QStringList protocolList = OstProtocolManager->protocolDatabase();
|
||||
protocolList.sort();
|
||||
protocol->addItems(protocolList);
|
||||
|
||||
// Enable this setting if we have streams selected on input
|
||||
selectedStreamsOnly->setEnabled(action->selectedStreamsOnly);
|
||||
|
||||
// Reset for user input
|
||||
action->selectedStreamsOnly = false;
|
||||
|
||||
QPushButton *ok = buttonBox->button(QDialogButtonBox::Ok);
|
||||
ok->setText(tr("Replace All"));
|
||||
ok->setDisabled(true);
|
||||
|
||||
mandatoryFields_ = new MandatoryFieldsGroup(this);
|
||||
mandatoryFields_->add(protocol);
|
||||
mandatoryFields_->add(field);
|
||||
mandatoryFields_->add(findValue);
|
||||
mandatoryFields_->add(findMask);
|
||||
mandatoryFields_->add(replaceValue);
|
||||
mandatoryFields_->add(replaceMask);
|
||||
mandatoryFields_->setSubmitButton(ok);
|
||||
}
|
||||
|
||||
FindReplaceDialog::~FindReplaceDialog()
|
||||
{
|
||||
delete mandatoryFields_;
|
||||
}
|
||||
|
||||
void FindReplaceDialog::on_protocol_currentIndexChanged(const QString &name)
|
||||
{
|
||||
field->clear();
|
||||
fieldAttrib_.clear();
|
||||
|
||||
Stream stream;
|
||||
AbstractProtocol *protocol = OstProtocolManager->createProtocol(
|
||||
name, &stream);
|
||||
int count = protocol->fieldCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
// XXX: It might be useful to support meta fields too, later!
|
||||
if (!protocol->fieldFlags(i).testFlag(AbstractProtocol::FrameField))
|
||||
continue;
|
||||
|
||||
int bitSize = protocol->fieldData(i, AbstractProtocol::FieldBitSize)
|
||||
.toInt();
|
||||
if (bitSize <= 0) // skip optional fields
|
||||
continue;
|
||||
|
||||
FieldAttrib fieldAttrib;
|
||||
fieldAttrib.index = i; // fieldIndex
|
||||
fieldAttrib.bitSize = bitSize;
|
||||
|
||||
// field and fieldAttrib_ have same count and order of fields
|
||||
fieldAttrib_.append(fieldAttrib);
|
||||
field->addItem(protocol->fieldData(i, AbstractProtocol::FieldName)
|
||||
.toString());
|
||||
}
|
||||
|
||||
protocolId_ = protocol->protocolNumber();
|
||||
delete protocol;
|
||||
}
|
||||
|
||||
void FindReplaceDialog::on_field_currentIndexChanged(int index)
|
||||
{
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
QString fieldName = field->currentText();
|
||||
FieldAttrib fieldAttrib = fieldAttrib_.at(index);
|
||||
|
||||
// Use heuristics to determine field type
|
||||
if (fieldAttrib.bitSize == 48) {
|
||||
findMask->setType(FieldEdit::kMacAddress);
|
||||
findValue->setType(FieldEdit::kMacAddress);
|
||||
replaceMask->setType(FieldEdit::kMacAddress);
|
||||
replaceValue->setType(FieldEdit::kMacAddress);
|
||||
} else if ((fieldAttrib.bitSize == 32)
|
||||
&& (fieldName.contains(QRegularExpression(
|
||||
"address|source|destination",
|
||||
QRegularExpression::CaseInsensitiveOption)))) {
|
||||
findMask->setType(FieldEdit::kIp4Address);
|
||||
findValue->setType(FieldEdit::kIp4Address);
|
||||
replaceMask->setType(FieldEdit::kIp4Address);
|
||||
replaceValue->setType(FieldEdit::kIp4Address);
|
||||
} else if ((fieldAttrib.bitSize == 128)
|
||||
&& (fieldName.contains(QRegularExpression(
|
||||
"address|source|destination",
|
||||
QRegularExpression::CaseInsensitiveOption)))) {
|
||||
findMask->setType(FieldEdit::kIp6Address);
|
||||
findValue->setType(FieldEdit::kIp6Address);
|
||||
replaceMask->setType(FieldEdit::kIp6Address);
|
||||
replaceValue->setType(FieldEdit::kIp6Address);
|
||||
} else {
|
||||
quint64 max = quint64(~0) >> (64-fieldAttrib.bitSize);
|
||||
qDebug("XXXXXX %s bitSize %d max %llx",
|
||||
qPrintable(field->currentText()),
|
||||
fieldAttrib.bitSize, max);
|
||||
|
||||
findMask->setType(FieldEdit::kUInt64);
|
||||
findMask->setRange(0, max);
|
||||
findValue->setType(FieldEdit::kUInt64);
|
||||
findValue->setRange(0, max);
|
||||
|
||||
replaceMask->setType(FieldEdit::kUInt64);
|
||||
replaceMask->setRange(0, max);
|
||||
replaceValue->setType(FieldEdit::kUInt64);
|
||||
replaceValue->setRange(0, max);
|
||||
}
|
||||
}
|
||||
|
||||
void FindReplaceDialog::on_matchAny_toggled(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
findValueLabel->setHidden(true);
|
||||
findValue->setHidden(true);
|
||||
useFindMask->setHidden(true);
|
||||
findMask->setHidden(true);
|
||||
findMaskHint->setHidden(true);
|
||||
} else {
|
||||
findValueLabel->setVisible(true);
|
||||
findValue->setVisible(true);
|
||||
useFindMask->setVisible(true);
|
||||
if (useFindMask->isChecked()) {
|
||||
findMask->setVisible(true);
|
||||
findMaskHint->setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FindReplaceDialog::on_buttonBox_accepted()
|
||||
{
|
||||
FieldAttrib fieldAttrib = fieldAttrib_.at(field->currentIndex());
|
||||
action_->protocolField = QString("%1 %2")
|
||||
.arg(protocol->currentText())
|
||||
.arg(field->currentText());
|
||||
action_->protocolNumber = protocolId_;
|
||||
action_->fieldIndex = fieldAttrib.index;
|
||||
action_->fieldBitSize = fieldAttrib.bitSize;
|
||||
|
||||
if (fieldAttrib.bitSize == 128) { // IPv6 address
|
||||
if (matchAny->isChecked()) {
|
||||
action_->findMask.setValue(UInt128(0));
|
||||
action_->findValue.setValue(UInt128(0));
|
||||
} else {
|
||||
action_->findMask.setValue(
|
||||
useFindMask->isChecked() ?
|
||||
ipUtils::ip6StringToUInt128(findMask->text()) :
|
||||
~UInt128(0));
|
||||
action_->findValue.setValue(
|
||||
ipUtils::ip6StringToUInt128(findValue->text()));
|
||||
}
|
||||
|
||||
action_->replaceMask.setValue(
|
||||
useReplaceMask->isChecked() ?
|
||||
ipUtils::ip6StringToUInt128(replaceMask->text()) :
|
||||
~UInt128(0));
|
||||
action_->replaceValue.setValue(
|
||||
ipUtils::ip6StringToUInt128(replaceValue->text()));
|
||||
} else { // everything else
|
||||
if (matchAny->isChecked()) {
|
||||
action_->findMask.setValue(0);
|
||||
action_->findValue.setValue(0);
|
||||
} else {
|
||||
action_->findMask.setValue(
|
||||
useFindMask->isChecked() ?
|
||||
findMask->text().toULongLong(nullptr, 0) :
|
||||
~quint64(0));
|
||||
action_->findValue.setValue(
|
||||
findValue->text().toULongLong(nullptr, 0));
|
||||
}
|
||||
|
||||
action_->replaceMask.setValue(
|
||||
useReplaceMask->isChecked() ?
|
||||
replaceMask->text().toULongLong(nullptr, 0) :
|
||||
~quint64(0));
|
||||
action_->replaceValue.setValue(QString::number(
|
||||
replaceValue->text().toULongLong(nullptr, 0)));
|
||||
}
|
||||
|
||||
action_->selectedStreamsOnly = selectedStreamsOnly->isChecked();
|
||||
}
|
||||
|
@ -1,71 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2021 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _FIND_REPLACE_H
|
||||
#define _FIND_REPLACE_H
|
||||
|
||||
#include "ui_findreplace.h"
|
||||
|
||||
class MandatoryFieldsGroup;
|
||||
|
||||
class FindReplaceDialog: public QDialog, public Ui::FindReplace
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
struct Action;
|
||||
|
||||
FindReplaceDialog(Action *action, QWidget *parent = 0);
|
||||
~FindReplaceDialog();
|
||||
|
||||
private slots:
|
||||
void on_protocol_currentIndexChanged(const QString &name);
|
||||
void on_field_currentIndexChanged(int index);
|
||||
void on_matchAny_toggled(bool checked);
|
||||
void on_buttonBox_accepted();
|
||||
|
||||
private:
|
||||
struct FieldAttrib;
|
||||
|
||||
quint32 protocolId_{0};
|
||||
Action *action_{nullptr};
|
||||
QList<FieldAttrib> fieldAttrib_;
|
||||
MandatoryFieldsGroup *mandatoryFields_{nullptr};
|
||||
};
|
||||
|
||||
struct FindReplaceDialog::Action
|
||||
{
|
||||
QString protocolField;
|
||||
quint32 protocolNumber;
|
||||
quint32 fieldIndex;
|
||||
int fieldBitSize;
|
||||
QVariant findValue;
|
||||
QVariant findMask;
|
||||
QVariant replaceValue;
|
||||
QVariant replaceMask;
|
||||
|
||||
bool selectedStreamsOnly; // in-out param
|
||||
};
|
||||
|
||||
struct FindReplaceDialog::FieldAttrib
|
||||
{
|
||||
quint32 index;
|
||||
int bitSize;
|
||||
};
|
||||
#endif
|
||||
|
@ -1,265 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FindReplace</class>
|
||||
<widget class="QDialog" name="FindReplace">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>361</width>
|
||||
<height>309</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Find & Replace</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="ostinato.qrc">
|
||||
<normaloff>:/icons/find.png</normaloff>:/icons/find.png</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="find">
|
||||
<property name="title">
|
||||
<string>Find</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="protocolLabel">
|
||||
<property name="text">
|
||||
<string>Protocol</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>protocol</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QComboBox" name="protocol"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="fieldLabel">
|
||||
<property name="text">
|
||||
<string>Field</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>field</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QComboBox" name="field"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="findValueLabel">
|
||||
<property name="text">
|
||||
<string>Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="FieldEdit" name="findValue"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="useFindMask">
|
||||
<property name="text">
|
||||
<string>Mask</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="FieldEdit" name="findMask"/>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLabel" name="findMaskHint">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p align="center">Matches a field only if <span style="white-space:nowrap">(FieldValue &amp; FindMask) = FindValue</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="ostinato.qrc">:/icons/info.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="3">
|
||||
<widget class="QCheckBox" name="matchAny">
|
||||
<property name="text">
|
||||
<string>Match any value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="replace">
|
||||
<property name="title">
|
||||
<string>Replace with</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,1,0">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="replaceValueLabel">
|
||||
<property name="text">
|
||||
<string>Value</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="FieldEdit" name="replaceValue"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="useReplaceMask">
|
||||
<property name="text">
|
||||
<string>Mask</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="FieldEdit" name="replaceMask"/>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="replaceMaskHint">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p align="center">New field value = <span style="white-space:nowrap">(OldFieldValue &amp; ~ReplaceMask) | (ReplaceValue &amp; ReplaceMask)</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="ostinato.qrc">:/icons/info.png</pixmap>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="selectedStreamsOnly">
|
||||
<property name="text">
|
||||
<string>Selected Streams Only</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>FieldEdit</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>fieldedit.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="ostinato.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>FindReplace</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>277</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>FindReplace</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>283</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>useFindMask</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>findMask</receiver>
|
||||
<slot>setVisible(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>60</x>
|
||||
<y>115</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>76</x>
|
||||
<y>119</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>useReplaceMask</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>replaceMask</receiver>
|
||||
<slot>setVisible(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>56</x>
|
||||
<y>228</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>73</x>
|
||||
<y>227</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>useReplaceMask</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>replaceMaskHint</receiver>
|
||||
<slot>setVisible(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>50</x>
|
||||
<y>230</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>333</x>
|
||||
<y>233</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>useFindMask</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>findMaskHint</receiver>
|
||||
<slot>setVisible(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>46</x>
|
||||
<y>116</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>335</x>
|
||||
<y>122</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -1,91 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2010 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "hexlineedit.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
QString & uintToHexStr(quint64 num, QString &hexStr, quint8 octets);
|
||||
|
||||
HexLineEdit::HexLineEdit( QWidget * parent)
|
||||
: QLineEdit(parent)
|
||||
{
|
||||
//QLineEdit::QLineEdit(parent);
|
||||
}
|
||||
|
||||
void HexLineEdit::focusOutEvent(QFocusEvent* /*e*/)
|
||||
{
|
||||
#if 0
|
||||
const QValidator *v = validator();
|
||||
if ( v )
|
||||
{
|
||||
int curpos = cursorPosition();
|
||||
QString str = text();
|
||||
if ( v->validate( str, curpos ) == QValidator::Acceptable )
|
||||
{
|
||||
if ( curpos != cursorPosition() )
|
||||
setCursorPosition( curpos );
|
||||
if ( str != text() )
|
||||
setText( str );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( curpos != cursorPosition() )
|
||||
setCursorPosition( curpos );
|
||||
str = text();
|
||||
v->fixup( str );
|
||||
if ( str != text() )
|
||||
{
|
||||
setText( str );
|
||||
}
|
||||
}
|
||||
}
|
||||
QLineEdit::focusOutEvent( e );
|
||||
emit focusOut();
|
||||
#else
|
||||
#define uintToHexStr(num, bytesize) \
|
||||
QString("%1").arg((num), (bytesize)*2 , 16, QChar('0'))
|
||||
|
||||
bool isOk;
|
||||
ulong num;
|
||||
|
||||
qDebug("before = %s\n", qPrintable(text()));
|
||||
num = text().remove(QChar(' ')).toULong(&isOk, 16);
|
||||
setText(uintToHexStr(num, 4));
|
||||
qDebug("after = %s\n", qPrintable(text()));
|
||||
#undef uintToHexStr
|
||||
#endif
|
||||
}
|
||||
|
||||
#if 0
|
||||
void HexLineEdit::focusInEvent( QFocusEvent *e )
|
||||
{
|
||||
QLineEdit::focusInEvent( e );
|
||||
emit focusIn();
|
||||
}
|
||||
|
||||
void HexLineEdit::keyPressEvent( QKeyEvent *e )
|
||||
{
|
||||
QLineEdit::keyPressEvent( e );
|
||||
if ( e->key() == Key_Enter || e->key() == Key_Return )
|
||||
{
|
||||
setSelection( 0, text().length() );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1,43 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2010 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _HEXLINEEDIT
|
||||
#define _HEXLINEEDIT
|
||||
|
||||
#include <QLineEdit>
|
||||
|
||||
class HexLineEdit : public QLineEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
// Constructors
|
||||
HexLineEdit ( QWidget * parent);
|
||||
|
||||
protected:
|
||||
void focusOutEvent( QFocusEvent *e );
|
||||
//void focusInEvent( QFocusEvent *e );
|
||||
//void keyPressEvent( QKeyEvent *e );
|
||||
|
||||
signals:
|
||||
//void focusIn();
|
||||
void focusOut();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2018 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _ICON_ONLY_DELEGATE
|
||||
#define _ICON_ONLY_DELEGATE
|
||||
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
class IconOnlyDelegate : public QStyledItemDelegate
|
||||
{
|
||||
using QStyledItemDelegate::QStyledItemDelegate;
|
||||
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
QStyleOptionViewItem opt = option;
|
||||
opt.decorationPosition = QStyleOptionViewItem::Top;
|
||||
QStyledItemDelegate::paint(painter, opt, index);
|
||||
}
|
||||
|
||||
QString displayText(const QVariant&, const QLocale&) const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 733 B |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 379 B |
Before Width: | Height: | Size: 345 B |
Before Width: | Height: | Size: 349 B |
Before Width: | Height: | Size: 372 B |
Before Width: | Height: | Size: 454 B |
Before Width: | Height: | Size: 295 B |
Before Width: | Height: | Size: 283 B |
Before Width: | Height: | Size: 287 B |
Before Width: | Height: | Size: 201 B |
Before Width: | Height: | Size: 287 B |
Before Width: | Height: | Size: 592 B |
Before Width: | Height: | Size: 403 B |
Before Width: | Height: | Size: 663 B |
Before Width: | Height: | Size: 648 B |
Before Width: | Height: | Size: 715 B |
Before Width: | Height: | Size: 729 B |
Before Width: | Height: | Size: 745 B |
Before Width: | Height: | Size: 775 B |
Before Width: | Height: | Size: 732 B |
@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="31.44mm" height="31.44mm" version="1.1" viewBox="0 0 31.44 31.44" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<metadata>
|
||||
<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/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g transform="translate(-37.525 -210.5)">
|
||||
<circle cx="53.245" cy="226.22" r="15.72" fill="#e96c59" opacity=".8"/>
|
||||
<path d="m53.419 212.28c-2.0736-0.0217-4.1616 0.41684-6.0884 1.3285-4.4585 2.1095-7.4154 6.2656-7.9501 11.175-0.50808 4.6643 1.5269 9.4967 5.2044 12.359 2.066 1.6079 4.6873 2.6928 7.1183 2.9462 2.643 0.2755 5.2282-0.17492 7.6011-1.3243 1.9456-0.94242 3.6302-2.2856 4.9044-3.9102 3.2672-4.1658 3.8994-9.8451 1.6275-14.62-1.0934-2.298-2.6916-4.1431-4.8639-5.6154-2.245-1.5216-4.8872-2.3101-7.5533-2.338zm-0.0276 2.2048c2.2445 0.0235 4.4688 0.68733 6.3588 1.9683 1.8288 1.2395 3.1743 2.7928 4.0948 4.7274 1.9126 4.0198 1.3803 8.8011-1.3702 12.308-1.0727 1.3677-2.4908 2.4985-4.1288 3.2919-1.9976 0.96764-4.1741 1.3468-6.3992 1.1148-2.0466-0.21332-4.2533-1.1267-5.9926-2.4803-3.096-2.4094-4.8092-6.4777-4.3814-10.404 0.45017-4.1327 2.9394-7.6316 6.6928-9.4075 1.6221-0.76747 3.38-1.1367 5.1257-1.1184z" fill="#f9bbab" opacity=".8"/>
|
||||
<g fill="#fff">
|
||||
<rect x="50.933" y="217.52" width="4.6236" height="12.862" opacity=".8"/>
|
||||
<rect transform="scale(1,-1)" x="50.933" y="-234.92" width="4.6236" height="3.5749" opacity=".8"/>
|
||||
<rect x="50.933" y="217.52" width="4.6236" height="12.862" opacity=".8"/>
|
||||
<rect transform="scale(1,-1)" x="50.933" y="-234.92" width="4.6236" height="3.5749" opacity=".8"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 688 B |
Before Width: | Height: | Size: 659 B |
Before Width: | Height: | Size: 268 B |
Before Width: | Height: | Size: 317 B |
Before Width: | Height: | Size: 293 B |
Before Width: | Height: | Size: 253 B |
Before Width: | Height: | Size: 316 B |
Before Width: | Height: | Size: 286 B |
Before Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 786 B |
Before Width: | Height: | Size: 778 B |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 615 B |
Before Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 775 B |
Before Width: | Height: | Size: 770 B |
Before Width: | Height: | Size: 703 B |
Before Width: | Height: | Size: 781 B |
Before Width: | Height: | Size: 748 B |
Before Width: | Height: | Size: 775 B |
Before Width: | Height: | Size: 796 B |
Before Width: | Height: | Size: 367 B |
Before Width: | Height: | Size: 736 B |
Before Width: | Height: | Size: 432 B |
Before Width: | Height: | Size: 584 B |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 685 B |
Before Width: | Height: | Size: 514 B |
Before Width: | Height: | Size: 435 B |
Before Width: | Height: | Size: 814 B |
Before Width: | Height: | Size: 847 B |
Before Width: | Height: | Size: 859 B |
Before Width: | Height: | Size: 865 B |
Before Width: | Height: | Size: 714 B |
Before Width: | Height: | Size: 749 B |
@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="221.25mm" height="193.24mm" version="1.1" viewBox="0 0 221.25 193.24" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<linearGradient id="linearGradient879" x1="193.48" x2="101.09" y1="198.47" y2="254.08" gradientTransform="matrix(1.7412 0 0 1.7412 -267.69 -212.02)" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#c16602" stop-opacity=".99608" offset="0"/>
|
||||
<stop stop-color="#e8b839" offset="1"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<metadata>
|
||||
<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/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g transform="translate(97.776 -43.224)">
|
||||
<path d="m12.851 49.318 104.53 181.06h-209.07z" fill="#fff" opacity=".8" stroke="url(#linearGradient879)" stroke-linecap="round" stroke-linejoin="round" stroke-opacity=".99216" stroke-width="12.188"/>
|
||||
<path d="m12.851 101.1 62.098 107.56h-124.2z" fill="#f5db61" opacity=".8"/>
|
||||
<rect x=".23388" y="113.27" width="25.235" height="54.405" fill="#c28832" opacity=".8"/>
|
||||
<rect transform="scale(1,-1)" x=".23388" y="-196.48" width="25.235" height="14.793" fill="#c28832" opacity=".8"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.5 KiB |
@ -1,38 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2017 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _JUMP_URL_H
|
||||
#define _JUMP_URL_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
inline QString jumpUrl(
|
||||
QString keyword,
|
||||
QString source="app",
|
||||
QString medium="hint",
|
||||
QString name="help")
|
||||
{
|
||||
return QString("https://jump.ostinato.org/" + keyword + "?"
|
||||
+ "utm_source=" + source + "&"
|
||||
+ "utm_medium=" + medium + "&"
|
||||
+ "utm_campaign=" + name);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
87
client/log.h
@ -1,87 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2018 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _LOG_H
|
||||
#define _LOG_H
|
||||
|
||||
#include "logsmodel.h"
|
||||
|
||||
extern LogsModel *appLogs;
|
||||
|
||||
inline static void logError(QString port, QString message)
|
||||
{
|
||||
appLogs->log(LogsModel::kError, port, message);
|
||||
}
|
||||
|
||||
inline static void logError(quint32 portGroupId, quint32 portId,QString message)
|
||||
{
|
||||
logError(QString("%1-%2").arg(portGroupId).arg(portId), message);
|
||||
}
|
||||
|
||||
inline static void logError(quint32 portGroupId, QString message)
|
||||
{
|
||||
logError(QString("%1-*").arg(portGroupId), message);
|
||||
}
|
||||
|
||||
inline static void logError(QString message)
|
||||
{
|
||||
logError(QString("--"), message);
|
||||
}
|
||||
|
||||
inline static void logWarn(QString port, QString message)
|
||||
{
|
||||
appLogs->log(LogsModel::kWarning, port, message);
|
||||
}
|
||||
|
||||
inline static void logWarn(quint32 portGroupId, quint32 portId,QString message)
|
||||
{
|
||||
logWarn(QString("%1-%2").arg(portGroupId).arg(portId), message);
|
||||
}
|
||||
|
||||
inline static void logWarn(quint32 portGroupId, QString message)
|
||||
{
|
||||
logWarn(QString("%1-*").arg(portGroupId), message);
|
||||
}
|
||||
|
||||
inline static void logWarn(QString message)
|
||||
{
|
||||
logWarn(QString("--"), message);
|
||||
}
|
||||
|
||||
inline static void logInfo(QString port, QString message)
|
||||
{
|
||||
appLogs->log(LogsModel::kInfo, port, message);
|
||||
}
|
||||
|
||||
inline static void logInfo(quint32 portGroupId, quint32 portId,QString message)
|
||||
{
|
||||
logInfo(QString("%1-%2").arg(portGroupId).arg(portId), message);
|
||||
}
|
||||
|
||||
inline static void logInfo(quint32 portGroupId, QString message)
|
||||
{
|
||||
logInfo(QString("%1-*").arg(portGroupId), message);
|
||||
}
|
||||
|
||||
inline static void logInfo(QString message)
|
||||
{
|
||||
logInfo(QString("--"), message);
|
||||
}
|
||||
#endif
|
||||
|
@ -1,152 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2018 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#include "logsmodel.h"
|
||||
|
||||
#include <QBrush>
|
||||
|
||||
// XXX: Keep the enum in sync with it's string
|
||||
enum {
|
||||
kTimeStamp,
|
||||
kLogLevel,
|
||||
kPort,
|
||||
kMessage,
|
||||
kFieldCount
|
||||
};
|
||||
static QStringList columnTitles = QStringList()
|
||||
<< "Timestamp"
|
||||
<< "Level"
|
||||
<< "Port"
|
||||
<< "Message";
|
||||
|
||||
static QStringList levelTitles = QStringList()
|
||||
<< "Info"
|
||||
<< "Warning"
|
||||
<< "Error";
|
||||
|
||||
LogsModel::LogsModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
int LogsModel::rowCount(const QModelIndex &/*parent*/) const
|
||||
{
|
||||
return logs_.size();
|
||||
}
|
||||
|
||||
int LogsModel::columnCount(const QModelIndex &/*parent*/) const
|
||||
{
|
||||
return kFieldCount;
|
||||
}
|
||||
|
||||
QVariant LogsModel::headerData(
|
||||
int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
switch (orientation) {
|
||||
case Qt::Horizontal: // Column Header
|
||||
return columnTitles.at(section);
|
||||
case Qt::Vertical: // Row Header
|
||||
return QVariant();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant LogsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || (index.row() >= logs_.size()))
|
||||
return QVariant();
|
||||
|
||||
if (role == Qt::ForegroundRole) {
|
||||
switch(logs_.at(index.row()).logLevel) {
|
||||
case kError:
|
||||
return QBrush(QColor("darkred"));
|
||||
case kWarning:
|
||||
return QBrush(QColor("orangered"));
|
||||
case kInfo:
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
switch (index.column()) {
|
||||
case kTimeStamp:
|
||||
return logs_.at(index.row()).timeStamp.toString("hh:mm:ss.zzz");
|
||||
case kLogLevel:
|
||||
return levelTitles.at(logs_.at(index.row()).logLevel);
|
||||
case kPort:
|
||||
return logs_.at(index.row()).port;
|
||||
case kMessage:
|
||||
return logs_.at(index.row()).message;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Qt::DropActions LogsModel::supportedDropActions() const
|
||||
{
|
||||
return Qt::IgnoreAction; // read-only model, doesn't accept any data
|
||||
}
|
||||
|
||||
// --------------------------------------------- //
|
||||
// Slots
|
||||
// --------------------------------------------- //
|
||||
void LogsModel::clear()
|
||||
{
|
||||
beginResetModel();
|
||||
logs_.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void LogsModel::setLogLevel(int level)
|
||||
{
|
||||
currentLevel_ = static_cast<LogLevel>(level % kLevelCount);
|
||||
log(currentLevel_, QString("--"),
|
||||
QString("Log level changed to %1 or higher")
|
||||
.arg(levelTitles.at(currentLevel_)));
|
||||
}
|
||||
|
||||
void LogsModel::log(int logLevel,QString port, QString message)
|
||||
{
|
||||
if (logLevel < currentLevel_)
|
||||
return;
|
||||
|
||||
// TODO: discard logs older than some threshold
|
||||
|
||||
//qDebug("adding log %u %s", logs_.size(), qPrintable(message));
|
||||
beginInsertRows(QModelIndex(), logs_.size(), logs_.size());
|
||||
Log l;
|
||||
logs_.append(l);
|
||||
logs_.last().timeStamp = QTime::currentTime();
|
||||
logs_.last().logLevel = logLevel;
|
||||
logs_.last().port = port;
|
||||
// XXX: QTableView does not honour newline unless we increase the
|
||||
// row height, so we replace newlines with semicolon for now
|
||||
logs_.last().message = message.trimmed().replace("\n", "; ");
|
||||
endInsertRows();
|
||||
}
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
Copyright (C) 2018 Srivats P.
|
||||
|
||||
This file is part of "Ostinato"
|
||||
|
||||
This 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 3 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, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
#ifndef _LOGS_MODEL_H
|
||||
#define _LOGS_MODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QTime>
|
||||
|
||||
class LogsModel: public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum LogLevel { // FIXME: use enum class?
|
||||
kInfo,
|
||||
kWarning,
|
||||
kError,
|
||||
kLevelCount
|
||||
};
|
||||
|
||||
public:
|
||||
LogsModel(QObject *parent = 0);
|
||||
|
||||
int rowCount(const QModelIndex &parent=QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent=QModelIndex()) const;
|
||||
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
|
||||
|
||||
Qt::DropActions supportedDropActions() const;
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
void setLogLevel(int level);
|
||||
void log(int logLevel,QString port, QString message);
|
||||
|
||||
private:
|
||||
struct Log {
|
||||
QTime timeStamp;
|
||||
int logLevel;
|
||||
QString port;
|
||||
QString message;
|
||||
};
|
||||
QVector<Log> logs_;
|
||||
LogLevel currentLevel_{kInfo};
|
||||
};
|
||||
#endif
|
||||
|