NOX: Removed GUI stuff from the drone app. Changes may not compile
33
.hgignore
Normal file
@ -0,0 +1,33 @@
|
||||
syntax: glob
|
||||
|
||||
# generated object files
|
||||
*.o
|
||||
*.a
|
||||
*.exe
|
||||
*.app
|
||||
drone
|
||||
ostinato
|
||||
|
||||
# Qt generated files
|
||||
ui_*.h
|
||||
moc_*.cpp
|
||||
qrc_*.cpp
|
||||
|
||||
# QMake generated files
|
||||
Makefile*
|
||||
*\object_script.*
|
||||
|
||||
# protobuf generated files
|
||||
*.pb.h
|
||||
*.pb.cc
|
||||
|
||||
# ostinato generated files
|
||||
version.cpp
|
||||
|
||||
# vim swap files
|
||||
*.swp
|
||||
.DS_Store
|
||||
|
||||
# ctags
|
||||
tags
|
||||
|
5
.vimrc
Normal file
@ -0,0 +1,5 @@
|
||||
set shiftwidth=4
|
||||
set tabstop=8
|
||||
set softtabstop=4
|
||||
set expandtab
|
||||
set cindent
|
674
COPYING
Normal file
@ -0,0 +1,674 @@
|
||||
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>.
|
192
client/about.ui
Normal file
@ -0,0 +1,192 @@
|
||||
<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="label_3" >
|
||||
<property name="text" >
|
||||
<string>Copyright (c) 2007-2012 Srivats P.</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignCenter</set>
|
||||
</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="http://www.gnu.org/licenses/">http://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>
|
||||
</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>
|
408
client/dumpview.cpp
Normal file
@ -0,0 +1,408 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
//! \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*/)
|
||||
{
|
||||
// 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"));
|
||||
|
||||
// set a white background
|
||||
painter.fillRect(rect(), QBrush(QColor(Qt::white)));
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
61
client/dumpview.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
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 <QtGui> // FIXME: High
|
||||
|
||||
|
||||
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 );
|
||||
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 > 48) && (c < 126)) return true; else return false; }
|
||||
|
||||
private:
|
||||
QRect mOffsetPaneTopRect;
|
||||
QRect mDumpPaneTopRect;
|
||||
QRect mAsciiPaneTopRect;
|
||||
int mSelectedRow, mSelectedCol;
|
||||
int mLineHeight;
|
||||
int mCharWidth;
|
||||
};
|
||||
|
91
client/hexlineedit.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
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", text().toAscii().data());
|
||||
num = text().remove(QChar(' ')).toULong(&isOk, 16);
|
||||
setText(uintToHexStr(num, 4));
|
||||
qDebug("after = %s\n", text().toAscii().data());
|
||||
#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
|
||||
|
43
client/hexlineedit.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
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
|
||||
|
BIN
client/icons/about.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
client/icons/arrow_down.png
Normal file
After Width: | Height: | Size: 379 B |
BIN
client/icons/arrow_left.png
Normal file
After Width: | Height: | Size: 345 B |
BIN
client/icons/arrow_right.png
Normal file
After Width: | Height: | Size: 349 B |
BIN
client/icons/arrow_up.png
Normal file
After Width: | Height: | Size: 372 B |
BIN
client/icons/bullet_error.png
Normal file
After Width: | Height: | Size: 454 B |
BIN
client/icons/bullet_green.png
Normal file
After Width: | Height: | Size: 295 B |
BIN
client/icons/bullet_orange.png
Normal file
After Width: | Height: | Size: 283 B |
BIN
client/icons/bullet_red.png
Normal file
After Width: | Height: | Size: 287 B |
BIN
client/icons/bullet_white.png
Normal file
After Width: | Height: | Size: 201 B |
BIN
client/icons/bullet_yellow.png
Normal file
After Width: | Height: | Size: 287 B |
BIN
client/icons/control_play.png
Normal file
After Width: | Height: | Size: 592 B |
BIN
client/icons/control_stop.png
Normal file
After Width: | Height: | Size: 403 B |
BIN
client/icons/deco_exclusive.png
Normal file
After Width: | Height: | Size: 793 B |
BIN
client/icons/delete.png
Normal file
After Width: | Height: | Size: 715 B |
BIN
client/icons/exit.png
Normal file
After Width: | Height: | Size: 688 B |
BIN
client/icons/gaps.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
client/icons/logo.icns
Normal file
BIN
client/icons/logo.ico
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
client/icons/logo.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
client/icons/magnifier.png
Normal file
After Width: | Height: | Size: 615 B |
BIN
client/icons/name.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
client/icons/portgroup_add.png
Normal file
After Width: | Height: | Size: 781 B |
BIN
client/icons/portgroup_connect.png
Normal file
After Width: | Height: | Size: 748 B |
BIN
client/icons/portgroup_delete.png
Normal file
After Width: | Height: | Size: 775 B |
BIN
client/icons/portgroup_disconnect.png
Normal file
After Width: | Height: | Size: 796 B |
BIN
client/icons/portstats_clear.png
Normal file
After Width: | Height: | Size: 367 B |
BIN
client/icons/portstats_clear_all.png
Normal file
After Width: | Height: | Size: 736 B |
BIN
client/icons/portstats_filter.png
Normal file
After Width: | Height: | Size: 432 B |
BIN
client/icons/preferences.png
Normal file
After Width: | Height: | Size: 584 B |
BIN
client/icons/qt.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
client/icons/sound_mute.png
Normal file
After Width: | Height: | Size: 474 B |
BIN
client/icons/sound_none.png
Normal file
After Width: | Height: | Size: 417 B |
BIN
client/icons/stream_add.png
Normal file
After Width: | Height: | Size: 814 B |
BIN
client/icons/stream_delete.png
Normal file
After Width: | Height: | Size: 847 B |
BIN
client/icons/stream_edit.png
Normal file
After Width: | Height: | Size: 865 B |
88
client/main.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
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 "mainwindow.h"
|
||||
#include "../common/ostprotolib.h"
|
||||
#include "../common/protocolmanager.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QSettings>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
extern const char* version;
|
||||
extern const char* revision;
|
||||
extern ProtocolManager *OstProtocolManager;
|
||||
|
||||
QSettings *appSettings;
|
||||
QMainWindow *mainWindow;
|
||||
|
||||
#if defined(Q_OS_WIN32)
|
||||
QString kGzipPathDefaultValue;
|
||||
QString kDiffPathDefaultValue;
|
||||
QString kAwkPathDefaultValue;
|
||||
#endif
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
int exitCode;
|
||||
|
||||
#if defined(Q_OS_WIN32)
|
||||
kGzipPathDefaultValue = app.applicationDirPath() + "/gzip.exe";
|
||||
kDiffPathDefaultValue = app.applicationDirPath() + "/diff.exe";
|
||||
kAwkPathDefaultValue = app.applicationDirPath() + "/gawk.exe";
|
||||
#endif
|
||||
|
||||
app.setApplicationName("Ostinato");
|
||||
app.setOrganizationName("Ostinato");
|
||||
app.setProperty("version", version);
|
||||
app.setProperty("revision", revision);
|
||||
|
||||
OstProtocolManager = new ProtocolManager();
|
||||
|
||||
/* (Portable Mode) If we have a .ini file in the same directory as the
|
||||
executable, we use that instead of the platform specific location
|
||||
and format for the settings */
|
||||
QString portableIni = QCoreApplication::applicationDirPath()
|
||||
+ "/ostinato.ini";
|
||||
if (QFile::exists(portableIni))
|
||||
appSettings = new QSettings(portableIni, QSettings::IniFormat);
|
||||
else
|
||||
appSettings = new QSettings();
|
||||
|
||||
OstProtoLib::setExternalApplicationPaths(
|
||||
appSettings->value(kTsharkPathKey, kTsharkPathDefaultValue).toString(),
|
||||
appSettings->value(kGzipPathKey, kGzipPathDefaultValue).toString(),
|
||||
appSettings->value(kDiffPathKey, kDiffPathDefaultValue).toString(),
|
||||
appSettings->value(kAwkPathKey, kAwkPathDefaultValue).toString());
|
||||
|
||||
mainWindow = new MainWindow;
|
||||
mainWindow->show();
|
||||
exitCode = app.exec();
|
||||
|
||||
delete mainWindow;
|
||||
delete appSettings;
|
||||
delete OstProtocolManager;
|
||||
google::protobuf::ShutdownProtobufLibrary();
|
||||
|
||||
return exitCode;
|
||||
}
|
135
client/mainwindow.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
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 "mainwindow.h"
|
||||
|
||||
#if 0
|
||||
#include "dbgthread.h"
|
||||
#endif
|
||||
|
||||
#include "portgrouplist.h"
|
||||
#include "portstatswindow.h"
|
||||
#include "portswindow.h"
|
||||
#include "preferences.h"
|
||||
#include "settings.h"
|
||||
#include "ui_about.h"
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QProcess>
|
||||
|
||||
extern const char* version;
|
||||
extern const char* revision;
|
||||
|
||||
PortGroupList *pgl;
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow (parent)
|
||||
{
|
||||
QString serverApp = QCoreApplication::applicationDirPath();
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
// applicationDirPath() does not return bundle, but executable inside bundle
|
||||
serverApp.replace("Ostinato.app", "drone.app");
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
serverApp.append("/drone.exe");
|
||||
#else
|
||||
serverApp.append("/drone");
|
||||
#endif
|
||||
|
||||
localServer_ = new QProcess(this);
|
||||
localServer_->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
localServer_->start(serverApp, QStringList());
|
||||
|
||||
pgl = new PortGroupList;
|
||||
|
||||
portsWindow = new PortsWindow(pgl, this);
|
||||
statsWindow = new PortStatsWindow(pgl, this);
|
||||
portsDock = new QDockWidget(tr("Ports and Streams"), this);
|
||||
portsDock->setObjectName("portsDock");
|
||||
portsDock->setFeatures(
|
||||
portsDock->features() & ~QDockWidget::DockWidgetClosable);
|
||||
statsDock = new QDockWidget(tr("Statistics"), this);
|
||||
statsDock->setObjectName("statsDock");
|
||||
statsDock->setFeatures(
|
||||
statsDock->features() & ~QDockWidget::DockWidgetClosable);
|
||||
|
||||
setupUi(this);
|
||||
|
||||
menuFile->insertActions(menuFile->actions().at(0), portsWindow->actions());
|
||||
|
||||
statsDock->setWidget(statsWindow);
|
||||
addDockWidget(Qt::BottomDockWidgetArea, statsDock);
|
||||
portsDock->setWidget(portsWindow);
|
||||
addDockWidget(Qt::TopDockWidgetArea, portsDock);
|
||||
|
||||
QRect geom = appSettings->value(kApplicationWindowGeometryKey).toRect();
|
||||
if (!geom.isNull())
|
||||
setGeometry(geom);
|
||||
QByteArray layout = appSettings->value(kApplicationWindowLayout)
|
||||
.toByteArray();
|
||||
if (layout.size())
|
||||
restoreState(layout, 0);
|
||||
|
||||
connect(actionFileExit, SIGNAL(triggered()), this, SLOT(close()));
|
||||
connect(actionAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
|
||||
#if 0
|
||||
{
|
||||
DbgThread *dbg = new DbgThread(pgl);
|
||||
dbg->start();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete pgl;
|
||||
localServer_->terminate();
|
||||
localServer_->waitForFinished();
|
||||
delete localServer_;
|
||||
|
||||
QByteArray layout = saveState(0);
|
||||
appSettings->setValue(kApplicationWindowLayout, layout);
|
||||
appSettings->setValue(kApplicationWindowGeometryKey, geometry());
|
||||
}
|
||||
|
||||
void MainWindow::on_actionPreferences_triggered()
|
||||
{
|
||||
Preferences *preferences = new Preferences();
|
||||
|
||||
preferences->exec();
|
||||
|
||||
delete preferences;
|
||||
}
|
||||
|
||||
void MainWindow::on_actionHelpAbout_triggered()
|
||||
{
|
||||
QDialog *aboutDialog = new QDialog;
|
||||
|
||||
Ui::About about;
|
||||
about.setupUi(aboutDialog);
|
||||
about.versionLabel->setText(
|
||||
QString("Version: %1 Revision: %2").arg(version).arg(revision));
|
||||
|
||||
aboutDialog->exec();
|
||||
|
||||
delete aboutDialog;
|
||||
}
|
||||
|
53
client/mainwindow.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
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 _MAIN_WINDOW_H
|
||||
#define _MAIN_WINDOW_H
|
||||
|
||||
#include "ui_mainwindow.h"
|
||||
#include <QMainWindow>
|
||||
|
||||
class PortsWindow;
|
||||
class PortStatsWindow;
|
||||
|
||||
class QDockWidget;
|
||||
class QProcess;
|
||||
|
||||
class MainWindow : public QMainWindow, private Ui::MainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
QProcess *localServer_;
|
||||
PortsWindow *portsWindow;
|
||||
PortStatsWindow *statsWindow;
|
||||
QDockWidget *portsDock;
|
||||
QDockWidget *statsDock;
|
||||
|
||||
public:
|
||||
MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
public slots:
|
||||
void on_actionPreferences_triggered();
|
||||
void on_actionHelpAbout_triggered();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
84
client/mainwindow.ui
Normal file
@ -0,0 +1,84 @@
|
||||
<ui version="4.0" >
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>700</width>
|
||||
<height>550</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Ostinato</string>
|
||||
</property>
|
||||
<property name="windowIcon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/about.png</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget" />
|
||||
<widget class="QMenuBar" name="menubar" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>700</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile" >
|
||||
<property name="title" >
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="separator" />
|
||||
<addaction name="actionPreferences" />
|
||||
<addaction name="actionFileExit" />
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp" >
|
||||
<property name="title" >
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<addaction name="actionHelpAbout" />
|
||||
<addaction name="actionAboutQt" />
|
||||
</widget>
|
||||
<addaction name="menuFile" />
|
||||
<addaction name="menuHelp" />
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar" />
|
||||
<action name="actionFileExit" >
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/exit.png</iconset>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>E&xit</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHelpAbout" >
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/about.png</iconset>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>&About</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPreferences" >
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/preferences.png</iconset>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Preferences</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAboutQt" >
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/qt.png</iconset>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>About Qt</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="ostinato.qrc" />
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
542
client/modeltest.cpp
Normal file
@ -0,0 +1,542 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2007 Trolltech ASA. All rights reserved.
|
||||
**
|
||||
** This file is part of the Qt Concurrent project on Trolltech Labs.
|
||||
**
|
||||
** This file may be used under the terms of the GNU General Public
|
||||
** License version 2.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of
|
||||
** this file. Please review the following information to ensure GNU
|
||||
** General Public Licensing requirements will be met:
|
||||
** http://www.trolltech.com/products/qt/opensource.html
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** review the following information:
|
||||
** http://www.trolltech.com/products/qt/licensing.html or contact the
|
||||
** sales department at sales@trolltech.com.
|
||||
**
|
||||
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtGui/QtGui>
|
||||
|
||||
#include "modeltest.h"
|
||||
|
||||
Q_DECLARE_METATYPE(QModelIndex)
|
||||
|
||||
/*!
|
||||
Connect to all of the models signals. Whenever anything happens recheck everything.
|
||||
*/
|
||||
ModelTest::ModelTest(QAbstractItemModel *_model, QObject *parent) : QObject(parent), model(_model), fetchingMore(false)
|
||||
{
|
||||
Q_ASSERT(model);
|
||||
|
||||
connect(model, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)),
|
||||
this, SLOT(runAllTests()));
|
||||
connect(model, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)),
|
||||
this, SLOT(runAllTests()));
|
||||
connect(model, SIGNAL(columnsInserted(const QModelIndex &, int, int)),
|
||||
this, SLOT(runAllTests()));
|
||||
connect(model, SIGNAL(columnsRemoved(const QModelIndex &, int, int)),
|
||||
this, SLOT(runAllTests()));
|
||||
connect(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
|
||||
this, SLOT(runAllTests()));
|
||||
connect(model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)),
|
||||
this, SLOT(runAllTests()));
|
||||
connect(model, SIGNAL(layoutAboutToBeChanged ()), this, SLOT(runAllTests()));
|
||||
connect(model, SIGNAL(layoutChanged ()), this, SLOT(runAllTests()));
|
||||
connect(model, SIGNAL(modelReset ()), this, SLOT(runAllTests()));
|
||||
connect(model, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
|
||||
this, SLOT(runAllTests()));
|
||||
connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
|
||||
this, SLOT(runAllTests()));
|
||||
connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
|
||||
this, SLOT(runAllTests()));
|
||||
connect(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
|
||||
this, SLOT(runAllTests()));
|
||||
|
||||
// Special checks for inserting/removing
|
||||
connect(model, SIGNAL(layoutAboutToBeChanged()),
|
||||
this, SLOT(layoutAboutToBeChanged()));
|
||||
connect(model, SIGNAL(layoutChanged()),
|
||||
this, SLOT(layoutChanged()));
|
||||
|
||||
connect(model, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
|
||||
this, SLOT(rowsAboutToBeInserted(const QModelIndex &, int, int)));
|
||||
connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
|
||||
this, SLOT(rowsAboutToBeRemoved(const QModelIndex &, int, int)));
|
||||
connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
|
||||
this, SLOT(rowsInserted(const QModelIndex &, int, int)));
|
||||
connect(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
|
||||
this, SLOT(rowsRemoved(const QModelIndex &, int, int)));
|
||||
|
||||
runAllTests();
|
||||
}
|
||||
|
||||
void ModelTest::runAllTests()
|
||||
{
|
||||
if (fetchingMore)
|
||||
return;
|
||||
nonDestructiveBasicTest();
|
||||
rowCount();
|
||||
columnCount();
|
||||
hasIndex();
|
||||
index();
|
||||
parent();
|
||||
data();
|
||||
}
|
||||
|
||||
/*!
|
||||
nonDestructiveBasicTest tries to call a number of the basic functions (not all)
|
||||
to make sure the model doesn't outright segfault, testing the functions that makes sense.
|
||||
*/
|
||||
void ModelTest::nonDestructiveBasicTest()
|
||||
{
|
||||
Q_ASSERT(model->buddy(QModelIndex()) == QModelIndex());
|
||||
model->canFetchMore(QModelIndex());
|
||||
Q_ASSERT(model->columnCount(QModelIndex()) >= 0);
|
||||
Q_ASSERT(model->data(QModelIndex()) == QVariant());
|
||||
fetchingMore = true;
|
||||
model->fetchMore(QModelIndex());
|
||||
fetchingMore = false;
|
||||
Qt::ItemFlags flags = model->flags(QModelIndex());
|
||||
Q_ASSERT(flags == Qt::ItemIsDropEnabled || flags == 0);
|
||||
model->hasChildren(QModelIndex());
|
||||
model->hasIndex(0, 0);
|
||||
model->headerData(0, Qt::Horizontal);
|
||||
model->index(0, 0);
|
||||
Q_ASSERT(model->index(-1, -1) == QModelIndex());
|
||||
model->itemData(QModelIndex());
|
||||
QVariant cache;
|
||||
model->match(QModelIndex(), -1, cache);
|
||||
model->mimeTypes();
|
||||
Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
|
||||
Q_ASSERT(model->rowCount() >= 0);
|
||||
QVariant variant;
|
||||
model->setData(QModelIndex(), variant, -1);
|
||||
model->setHeaderData(-1, Qt::Horizontal, QVariant());
|
||||
model->setHeaderData(0, Qt::Horizontal, QVariant());
|
||||
model->setHeaderData(999999, Qt::Horizontal, QVariant());
|
||||
QMap<int, QVariant> roles;
|
||||
model->sibling(0, 0, QModelIndex());
|
||||
model->span(QModelIndex());
|
||||
model->supportedDropActions();
|
||||
}
|
||||
|
||||
/*!
|
||||
Tests model's implementation of QAbstractItemModel::rowCount() and hasChildren()
|
||||
|
||||
Models that are dynamically populated are not as fully tested here.
|
||||
*/
|
||||
void ModelTest::rowCount()
|
||||
{
|
||||
// check top row
|
||||
QModelIndex topIndex = model->index(0, 0, QModelIndex());
|
||||
int rows = model->rowCount(topIndex);
|
||||
Q_ASSERT(rows >= 0);
|
||||
if (rows > 0)
|
||||
Q_ASSERT(model->hasChildren(topIndex) == true);
|
||||
|
||||
QModelIndex secondLevelIndex = model->index(0, 0, topIndex);
|
||||
if (secondLevelIndex.isValid()) { // not the top level
|
||||
// check a row count where parent is valid
|
||||
rows = model->rowCount(secondLevelIndex);
|
||||
Q_ASSERT(rows >= 0);
|
||||
if (rows > 0)
|
||||
Q_ASSERT(model->hasChildren(secondLevelIndex) == true);
|
||||
}
|
||||
|
||||
// The models rowCount() is tested more extensively in checkChildren(),
|
||||
// but this catches the big mistakes
|
||||
}
|
||||
|
||||
/*!
|
||||
Tests model's implementation of QAbstractItemModel::columnCount() and hasChildren()
|
||||
*/
|
||||
void ModelTest::columnCount()
|
||||
{
|
||||
// check top row
|
||||
QModelIndex topIndex = model->index(0, 0, QModelIndex());
|
||||
Q_ASSERT(model->columnCount(topIndex) >= 0);
|
||||
|
||||
// check a column count where parent is valid
|
||||
QModelIndex childIndex = model->index(0, 0, topIndex);
|
||||
if (childIndex.isValid())
|
||||
Q_ASSERT(model->columnCount(childIndex) >= 0);
|
||||
|
||||
// columnCount() is tested more extensively in checkChildren(),
|
||||
// but this catches the big mistakes
|
||||
}
|
||||
|
||||
/*!
|
||||
Tests model's implementation of QAbstractItemModel::hasIndex()
|
||||
*/
|
||||
void ModelTest::hasIndex()
|
||||
{
|
||||
// Make sure that invalid values returns an invalid index
|
||||
Q_ASSERT(model->hasIndex(-2, -2) == false);
|
||||
Q_ASSERT(model->hasIndex(-2, 0) == false);
|
||||
Q_ASSERT(model->hasIndex(0, -2) == false);
|
||||
|
||||
int rows = model->rowCount();
|
||||
int columns = model->columnCount();
|
||||
|
||||
// check out of bounds
|
||||
Q_ASSERT(model->hasIndex(rows, columns) == false);
|
||||
Q_ASSERT(model->hasIndex(rows + 1, columns + 1) == false);
|
||||
|
||||
if (rows > 0)
|
||||
Q_ASSERT(model->hasIndex(0, 0) == true);
|
||||
|
||||
// hasIndex() is tested more extensively in checkChildren(),
|
||||
// but this catches the big mistakes
|
||||
}
|
||||
|
||||
/*!
|
||||
Tests model's implementation of QAbstractItemModel::index()
|
||||
*/
|
||||
void ModelTest::index()
|
||||
{
|
||||
// Make sure that invalid values returns an invalid index
|
||||
Q_ASSERT(model->index(-2, -2) == QModelIndex());
|
||||
Q_ASSERT(model->index(-2, 0) == QModelIndex());
|
||||
Q_ASSERT(model->index(0, -2) == QModelIndex());
|
||||
|
||||
int rows = model->rowCount();
|
||||
int columns = model->columnCount();
|
||||
|
||||
if (rows == 0)
|
||||
return;
|
||||
|
||||
// Catch off by one errors
|
||||
Q_ASSERT(model->index(rows, columns) == QModelIndex());
|
||||
Q_ASSERT(model->index(0, 0).isValid() == true);
|
||||
|
||||
// Make sure that the same index is *always* returned
|
||||
QModelIndex a = model->index(0, 0);
|
||||
QModelIndex b = model->index(0, 0);
|
||||
Q_ASSERT(a == b);
|
||||
|
||||
// index() is tested more extensively in checkChildren(),
|
||||
// but this catches the big mistakes
|
||||
}
|
||||
|
||||
/*!
|
||||
Tests model's implementation of QAbstractItemModel::parent()
|
||||
*/
|
||||
void ModelTest::parent()
|
||||
{
|
||||
// Make sure the model wont crash and will return an invalid QModelIndex
|
||||
// when asked for the parent of an invalid index.
|
||||
Q_ASSERT(model->parent(QModelIndex()) == QModelIndex());
|
||||
|
||||
if (model->rowCount() == 0)
|
||||
return;
|
||||
|
||||
// Column 0 | Column 1 |
|
||||
// QModelIndex() | |
|
||||
// \- topIndex | topIndex1 |
|
||||
// \- childIndex | childIndex1 |
|
||||
|
||||
// Common error test #1, make sure that a top level index has a parent
|
||||
// that is a invalid QModelIndex.
|
||||
QModelIndex topIndex = model->index(0, 0, QModelIndex());
|
||||
Q_ASSERT(model->parent(topIndex) == QModelIndex());
|
||||
|
||||
// Common error test #2, make sure that a second level index has a parent
|
||||
// that is the first level index.
|
||||
if (model->rowCount(topIndex) > 0) {
|
||||
QModelIndex childIndex = model->index(0, 0, topIndex);
|
||||
qDebug("topIndex RCI %x %x %llx", topIndex.row(), topIndex.column(), topIndex.internalId());
|
||||
qDebug("topIndex I %llx", topIndex.internalId());
|
||||
qDebug("childIndex RCI %x %x %llx", childIndex.row(), childIndex.column(), childIndex.internalId());
|
||||
Q_ASSERT(model->parent(childIndex) == topIndex);
|
||||
}
|
||||
|
||||
// Common error test #3, the second column should NOT have the same children
|
||||
// as the first column in a row.
|
||||
// Usually the second column shouldn't have children.
|
||||
QModelIndex topIndex1 = model->index(0, 1, QModelIndex());
|
||||
if (model->rowCount(topIndex1) > 0) {
|
||||
QModelIndex childIndex = model->index(0, 0, topIndex);
|
||||
QModelIndex childIndex1 = model->index(0, 0, topIndex1);
|
||||
Q_ASSERT(childIndex != childIndex1);
|
||||
}
|
||||
|
||||
// Full test, walk n levels deep through the model making sure that all
|
||||
// parent's children correctly specify their parent.
|
||||
checkChildren(QModelIndex());
|
||||
}
|
||||
|
||||
/*!
|
||||
Called from the parent() test.
|
||||
|
||||
A model that returns an index of parent X should also return X when asking
|
||||
for the parent of the index.
|
||||
|
||||
This recursive function does pretty extensive testing on the whole model in an
|
||||
effort to catch edge cases.
|
||||
|
||||
This function assumes that rowCount(), columnCount() and index() already work.
|
||||
If they have a bug it will point it out, but the above tests should have already
|
||||
found the basic bugs because it is easier to figure out the problem in
|
||||
those tests then this one.
|
||||
*/
|
||||
void ModelTest::checkChildren(const QModelIndex &parent, int currentDepth)
|
||||
{
|
||||
// First just try walking back up the tree.
|
||||
QModelIndex p = parent;
|
||||
while (p.isValid())
|
||||
p = p.parent();
|
||||
|
||||
// For models that are dynamically populated
|
||||
if (model->canFetchMore(parent)) {
|
||||
fetchingMore = true;
|
||||
model->fetchMore(parent);
|
||||
fetchingMore = false;
|
||||
}
|
||||
|
||||
int rows = model->rowCount(parent);
|
||||
int columns = model->columnCount(parent);
|
||||
|
||||
if (rows > 0)
|
||||
Q_ASSERT(model->hasChildren(parent));
|
||||
|
||||
// Some further testing against rows(), columns(), and hasChildren()
|
||||
Q_ASSERT(rows >= 0);
|
||||
Q_ASSERT(columns >= 0);
|
||||
if (rows > 0)
|
||||
Q_ASSERT(model->hasChildren(parent) == true);
|
||||
|
||||
//qDebug() << "parent:" << model->data(parent).toString() << "rows:" << rows
|
||||
// << "columns:" << columns << "parent column:" << parent.column();
|
||||
|
||||
Q_ASSERT(model->hasIndex(rows + 1, 0, parent) == false);
|
||||
for (int r = 0; r < rows; ++r) {
|
||||
if (model->canFetchMore(parent)) {
|
||||
fetchingMore = true;
|
||||
model->fetchMore(parent);
|
||||
fetchingMore = false;
|
||||
}
|
||||
Q_ASSERT(model->hasIndex(r, columns + 1, parent) == false);
|
||||
for (int c = 0; c < columns; ++c) {
|
||||
Q_ASSERT(model->hasIndex(r, c, parent) == true);
|
||||
QModelIndex index = model->index(r, c, parent);
|
||||
// rowCount() and columnCount() said that it existed...
|
||||
Q_ASSERT(index.isValid() == true);
|
||||
|
||||
// index() should always return the same index when called twice in a row
|
||||
QModelIndex modifiedIndex = model->index(r, c, parent);
|
||||
Q_ASSERT(index == modifiedIndex);
|
||||
|
||||
// Make sure we get the same index if we request it twice in a row
|
||||
QModelIndex a = model->index(r, c, parent);
|
||||
QModelIndex b = model->index(r, c, parent);
|
||||
Q_ASSERT(a == b);
|
||||
|
||||
// Some basic checking on the index that is returned
|
||||
Q_ASSERT(index.model() == model);
|
||||
Q_ASSERT(index.row() == r);
|
||||
Q_ASSERT(index.column() == c);
|
||||
// While you can technically return a QVariant usually this is a sign
|
||||
// of an bug in data() Disable if this really is ok in your model.
|
||||
//Q_ASSERT(model->data(index, Qt::DisplayRole).isValid() == true);
|
||||
|
||||
// If the next test fails here is some somewhat useful debug you play with.
|
||||
/*
|
||||
if (model->parent(index) != parent) {
|
||||
qDebug() << r << c << currentDepth << model->data(index).toString()
|
||||
<< model->data(parent).toString();
|
||||
qDebug() << index << parent << model->parent(index);
|
||||
// And a view that you can even use to show the model.
|
||||
//QTreeView view;
|
||||
//view.setModel(model);
|
||||
//view.show();
|
||||
}*/
|
||||
|
||||
// Check that we can get back our real parent.
|
||||
QModelIndex p = model->parent(index);
|
||||
//qDebug() << "child:" << index;
|
||||
//qDebug() << p;
|
||||
//qDebug() << parent;
|
||||
Q_ASSERT(model->parent(index) == parent);
|
||||
|
||||
// recursively go down the children
|
||||
if (model->hasChildren(index) && currentDepth < 10 ) {
|
||||
//qDebug() << r << c << "has children" << model->rowCount(index);
|
||||
checkChildren(index, ++currentDepth);
|
||||
}/* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/
|
||||
|
||||
// make sure that after testing the children that the index doesn't change.
|
||||
QModelIndex newerIndex = model->index(r, c, parent);
|
||||
Q_ASSERT(index == newerIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Tests model's implementation of QAbstractItemModel::data()
|
||||
*/
|
||||
void ModelTest::data()
|
||||
{
|
||||
// Invalid index should return an invalid qvariant
|
||||
Q_ASSERT(!model->data(QModelIndex()).isValid());
|
||||
|
||||
if (model->rowCount() == 0)
|
||||
return;
|
||||
|
||||
// A valid index should have a valid QVariant data
|
||||
Q_ASSERT(model->index(0, 0).isValid());
|
||||
|
||||
// shouldn't be able to set data on an invalid index
|
||||
Q_ASSERT(model->setData(QModelIndex(), QLatin1String("foo"), Qt::DisplayRole) == false);
|
||||
|
||||
// General Purpose roles that should return a QString
|
||||
QVariant variant = model->data(model->index(0, 0), Qt::ToolTipRole);
|
||||
if (variant.isValid()) {
|
||||
Q_ASSERT(qVariantCanConvert<QString>(variant));
|
||||
}
|
||||
variant = model->data(model->index(0, 0), Qt::StatusTipRole);
|
||||
if (variant.isValid()) {
|
||||
Q_ASSERT(qVariantCanConvert<QString>(variant));
|
||||
}
|
||||
variant = model->data(model->index(0, 0), Qt::WhatsThisRole);
|
||||
if (variant.isValid()) {
|
||||
Q_ASSERT(qVariantCanConvert<QString>(variant));
|
||||
}
|
||||
|
||||
// General Purpose roles that should return a QSize
|
||||
variant = model->data(model->index(0, 0), Qt::SizeHintRole);
|
||||
if (variant.isValid()) {
|
||||
Q_ASSERT(qVariantCanConvert<QSize>(variant));
|
||||
}
|
||||
|
||||
// General Purpose roles that should return a QFont
|
||||
QVariant fontVariant = model->data(model->index(0, 0), Qt::FontRole);
|
||||
if (fontVariant.isValid()) {
|
||||
Q_ASSERT(qVariantCanConvert<QFont>(fontVariant));
|
||||
}
|
||||
|
||||
// Check that the alignment is one we know about
|
||||
QVariant textAlignmentVariant = model->data(model->index(0, 0), Qt::TextAlignmentRole);
|
||||
if (textAlignmentVariant.isValid()) {
|
||||
int alignment = textAlignmentVariant.toInt();
|
||||
Q_ASSERT(alignment == Qt::AlignLeft ||
|
||||
alignment == Qt::AlignRight ||
|
||||
alignment == Qt::AlignHCenter ||
|
||||
alignment == Qt::AlignJustify ||
|
||||
alignment == Qt::AlignTop ||
|
||||
alignment == Qt::AlignBottom ||
|
||||
alignment == Qt::AlignVCenter ||
|
||||
alignment == Qt::AlignCenter ||
|
||||
alignment == Qt::AlignAbsolute ||
|
||||
alignment == Qt::AlignLeading ||
|
||||
alignment == Qt::AlignTrailing);
|
||||
}
|
||||
|
||||
// General Purpose roles that should return a QColor
|
||||
QVariant colorVariant = model->data(model->index(0, 0), Qt::BackgroundColorRole);
|
||||
if (colorVariant.isValid()) {
|
||||
Q_ASSERT(qVariantCanConvert<QColor>(colorVariant));
|
||||
}
|
||||
|
||||
colorVariant = model->data(model->index(0, 0), Qt::TextColorRole);
|
||||
if (colorVariant.isValid()) {
|
||||
Q_ASSERT(qVariantCanConvert<QColor>(colorVariant));
|
||||
}
|
||||
|
||||
// Check that the "check state" is one we know about.
|
||||
QVariant checkStateVariant = model->data(model->index(0, 0), Qt::CheckStateRole);
|
||||
if (checkStateVariant.isValid()) {
|
||||
int state = checkStateVariant.toInt();
|
||||
Q_ASSERT(state == Qt::Unchecked ||
|
||||
state == Qt::PartiallyChecked ||
|
||||
state == Qt::Checked);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Store what is about to be inserted to make sure it actually happens
|
||||
|
||||
\sa rowsInserted()
|
||||
*/
|
||||
void ModelTest::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end)
|
||||
{
|
||||
Q_UNUSED(end);
|
||||
Changing c;
|
||||
c.parent = parent;
|
||||
c.oldSize = model->rowCount(parent);
|
||||
c.last = model->data(model->index(start - 1, 0, parent));
|
||||
c.next = model->data(model->index(start, 0, parent));
|
||||
insert.push(c);
|
||||
}
|
||||
|
||||
/*!
|
||||
Confirm that what was said was going to happen actually did
|
||||
|
||||
\sa rowsAboutToBeInserted()
|
||||
*/
|
||||
void ModelTest::rowsInserted(const QModelIndex & parent, int start, int end)
|
||||
{
|
||||
Changing c = insert.pop();
|
||||
Q_ASSERT(c.parent == parent);
|
||||
Q_ASSERT(c.oldSize + (end - start + 1) == model->rowCount(parent));
|
||||
Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
|
||||
/*
|
||||
if (c.next != model->data(model->index(end + 1, 0, c.parent))) {
|
||||
qDebug() << start << end;
|
||||
for (int i=0; i < model->rowCount(); ++i)
|
||||
qDebug() << model->index(i, 0).data().toString();
|
||||
qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent));
|
||||
}
|
||||
*/
|
||||
Q_ASSERT(c.next == model->data(model->index(end + 1, 0, c.parent)));
|
||||
}
|
||||
|
||||
void ModelTest::layoutAboutToBeChanged()
|
||||
{
|
||||
for (int i = 0; i < qBound(0, model->rowCount(), 100); ++i)
|
||||
changing.append(QPersistentModelIndex(model->index(i, 0)));
|
||||
}
|
||||
|
||||
void ModelTest::layoutChanged()
|
||||
{
|
||||
for (int i = 0; i < changing.count(); ++i) {
|
||||
QPersistentModelIndex p = changing[i];
|
||||
Q_ASSERT(p == model->index(p.row(), p.column(), p.parent()));
|
||||
}
|
||||
changing.clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
Store what is about to be inserted to make sure it actually happens
|
||||
|
||||
\sa rowsRemoved()
|
||||
*/
|
||||
void ModelTest::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
|
||||
{
|
||||
Changing c;
|
||||
c.parent = parent;
|
||||
c.oldSize = model->rowCount(parent);
|
||||
c.last = model->data(model->index(start - 1, 0, parent));
|
||||
c.next = model->data(model->index(end + 1, 0, parent));
|
||||
remove.push(c);
|
||||
}
|
||||
|
||||
/*!
|
||||
Confirm that what was said was going to happen actually did
|
||||
|
||||
\sa rowsAboutToBeRemoved()
|
||||
*/
|
||||
void ModelTest::rowsRemoved(const QModelIndex & parent, int start, int end)
|
||||
{
|
||||
Changing c = remove.pop();
|
||||
Q_ASSERT(c.parent == parent);
|
||||
Q_ASSERT(c.oldSize - (end - start + 1) == model->rowCount(parent));
|
||||
Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent)));
|
||||
Q_ASSERT(c.next == model->data(model->index(start, 0, c.parent)));
|
||||
}
|
||||
|
76
client/modeltest.h
Normal file
@ -0,0 +1,76 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2007 Trolltech ASA. All rights reserved.
|
||||
**
|
||||
** This file is part of the Qt Concurrent project on Trolltech Labs.
|
||||
**
|
||||
** This file may be used under the terms of the GNU General Public
|
||||
** License version 2.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of
|
||||
** this file. Please review the following information to ensure GNU
|
||||
** General Public Licensing requirements will be met:
|
||||
** http://www.trolltech.com/products/qt/opensource.html
|
||||
**
|
||||
** If you are unsure which license is appropriate for your use, please
|
||||
** review the following information:
|
||||
** http://www.trolltech.com/products/qt/licensing.html or contact the
|
||||
** sales department at sales@trolltech.com.
|
||||
**
|
||||
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef MODELTEST_H
|
||||
#define MODELTEST_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QAbstractItemModel>
|
||||
#include <QtCore/QStack>
|
||||
|
||||
class ModelTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModelTest(QAbstractItemModel *model, QObject *parent = 0);
|
||||
|
||||
private Q_SLOTS:
|
||||
void nonDestructiveBasicTest();
|
||||
void rowCount();
|
||||
void columnCount();
|
||||
void hasIndex();
|
||||
void index();
|
||||
void parent();
|
||||
void data();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void runAllTests();
|
||||
void layoutAboutToBeChanged();
|
||||
void layoutChanged();
|
||||
void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end);
|
||||
void rowsInserted(const QModelIndex & parent, int start, int end);
|
||||
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
|
||||
void rowsRemoved(const QModelIndex & parent, int start, int end);
|
||||
|
||||
private:
|
||||
void checkChildren(const QModelIndex &parent, int currentDepth = 0);
|
||||
|
||||
QAbstractItemModel *model;
|
||||
|
||||
struct Changing
|
||||
{
|
||||
QModelIndex parent;
|
||||
int oldSize;
|
||||
QVariant last;
|
||||
QVariant next;
|
||||
};
|
||||
QStack<Changing> insert;
|
||||
QStack<Changing> remove;
|
||||
|
||||
bool fetchingMore;
|
||||
|
||||
QList<QPersistentModelIndex> changing;
|
||||
};
|
||||
|
||||
#endif
|
4
client/modeltest.pri
Normal file
@ -0,0 +1,4 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
DEPENDPATH += $$PWD
|
||||
SOURCES += $$PWD/modeltest.cpp
|
||||
HEADERS += $$PWD/modeltest.h
|
88
client/ostinato.pro
Normal file
@ -0,0 +1,88 @@
|
||||
TEMPLATE = app
|
||||
CONFIG += qt
|
||||
macx: TARGET = Ostinato
|
||||
win32:RC_FILE = ostinato.rc
|
||||
macx:ICON = icons/logo.icns
|
||||
QT += network script xml
|
||||
INCLUDEPATH += "../rpc/" "../common/"
|
||||
win32 {
|
||||
CONFIG(debug, debug|release) {
|
||||
LIBS += -L"../common/debug" -lostproto
|
||||
LIBS += -L"../rpc/debug" -lpbrpc
|
||||
POST_TARGETDEPS += \
|
||||
"../common/debug/libostproto.a" \
|
||||
"../rpc/debug/libpbrpc.a"
|
||||
} else {
|
||||
LIBS += -L"../common/release" -lostproto
|
||||
LIBS += -L"../rpc/release" -lpbrpc
|
||||
POST_TARGETDEPS += \
|
||||
"../common/release/libostproto.a" \
|
||||
"../rpc/release/libpbrpc.a"
|
||||
}
|
||||
} else {
|
||||
LIBS += -L"../common" -lostproto
|
||||
LIBS += -L"../rpc" -lpbrpc
|
||||
POST_TARGETDEPS += "../common/libostproto.a" "../rpc/libpbrpc.a"
|
||||
}
|
||||
LIBS += -lprotobuf
|
||||
LIBS += -L"../extra/qhexedit2/$(OBJECTS_DIR)/" -lqhexedit2
|
||||
RESOURCES += ostinato.qrc
|
||||
HEADERS += \
|
||||
dumpview.h \
|
||||
hexlineedit.h \
|
||||
mainwindow.h \
|
||||
packetmodel.h \
|
||||
port.h \
|
||||
portconfigdialog.h \
|
||||
portgroup.h \
|
||||
portgrouplist.h \
|
||||
portmodel.h \
|
||||
portstatsmodel.h \
|
||||
portstatsfilterdialog.h \
|
||||
portstatswindow.h \
|
||||
portswindow.h \
|
||||
preferences.h \
|
||||
settings.h \
|
||||
streamconfigdialog.h \
|
||||
streamlistdelegate.h \
|
||||
streammodel.h
|
||||
|
||||
FORMS += \
|
||||
about.ui \
|
||||
mainwindow.ui \
|
||||
portconfigdialog.ui \
|
||||
portstatsfilter.ui \
|
||||
portstatswindow.ui \
|
||||
portswindow.ui \
|
||||
preferences.ui \
|
||||
streamconfigdialog.ui
|
||||
|
||||
SOURCES += \
|
||||
dumpview.cpp \
|
||||
stream.cpp \
|
||||
hexlineedit.cpp \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
packetmodel.cpp \
|
||||
port.cpp \
|
||||
portconfigdialog.cpp \
|
||||
portgroup.cpp \
|
||||
portgrouplist.cpp \
|
||||
portmodel.cpp \
|
||||
portstatsmodel.cpp \
|
||||
portstatsfilterdialog.cpp \
|
||||
portstatswindow.cpp \
|
||||
portswindow.cpp \
|
||||
preferences.cpp \
|
||||
streamconfigdialog.cpp \
|
||||
streamlistdelegate.cpp \
|
||||
streammodel.cpp
|
||||
|
||||
|
||||
QMAKE_DISTCLEAN += object_script.*
|
||||
|
||||
include(../install.pri)
|
||||
include(../version.pri)
|
||||
|
||||
# TODO(LOW): Test only
|
||||
CONFIG(debug, debug|release):include(modeltest.pri)
|
38
client/ostinato.qrc
Normal file
@ -0,0 +1,38 @@
|
||||
<RCC>
|
||||
<qresource prefix="/" >
|
||||
<file>icons/about.png</file>
|
||||
<file>icons/arrow_down.png</file>
|
||||
<file>icons/arrow_left.png</file>
|
||||
<file>icons/arrow_right.png</file>
|
||||
<file>icons/arrow_up.png</file>
|
||||
<file>icons/bullet_error.png</file>
|
||||
<file>icons/bullet_green.png</file>
|
||||
<file>icons/bullet_orange.png</file>
|
||||
<file>icons/bullet_red.png</file>
|
||||
<file>icons/bullet_white.png</file>
|
||||
<file>icons/bullet_yellow.png</file>
|
||||
<file>icons/control_play.png</file>
|
||||
<file>icons/control_stop.png</file>
|
||||
<file>icons/deco_exclusive.png</file>
|
||||
<file>icons/delete.png</file>
|
||||
<file>icons/exit.png</file>
|
||||
<file>icons/gaps.png</file>
|
||||
<file>icons/logo.png</file>
|
||||
<file>icons/magnifier.png</file>
|
||||
<file>icons/name.png</file>
|
||||
<file>icons/portgroup_add.png</file>
|
||||
<file>icons/portgroup_connect.png</file>
|
||||
<file>icons/portgroup_delete.png</file>
|
||||
<file>icons/portgroup_disconnect.png</file>
|
||||
<file>icons/portstats_clear.png</file>
|
||||
<file>icons/portstats_clear_all.png</file>
|
||||
<file>icons/portstats_filter.png</file>
|
||||
<file>icons/preferences.png</file>
|
||||
<file>icons/qt.png</file>
|
||||
<file>icons/sound_mute.png</file>
|
||||
<file>icons/sound_none.png</file>
|
||||
<file>icons/stream_add.png</file>
|
||||
<file>icons/stream_delete.png</file>
|
||||
<file>icons/stream_edit.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
1
client/ostinato.rc
Normal file
@ -0,0 +1 @@
|
||||
IDI_ICON1 ICON DISCARDABLE "icons/logo.ico"
|
244
client/packetmodel.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
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 <QHostAddress>
|
||||
|
||||
#include "packetmodel.h"
|
||||
#include "../common/protocollistiterator.h"
|
||||
#include "../common/abstractprotocol.h"
|
||||
|
||||
PacketModel::PacketModel(QObject *parent)
|
||||
: QAbstractItemModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void PacketModel::setSelectedProtocols(ProtocolListIterator &iter)
|
||||
{
|
||||
QList<const AbstractProtocol*> currentProtocols;
|
||||
|
||||
iter.toFront();
|
||||
while (iter.hasNext())
|
||||
currentProtocols.append(iter.next());
|
||||
|
||||
if (mSelectedProtocols != currentProtocols)
|
||||
{
|
||||
mSelectedProtocols = currentProtocols;
|
||||
reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
emit layoutAboutToBeChanged();
|
||||
emit layoutChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int PacketModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
IndexId parentId;
|
||||
|
||||
// qDebug("in %s", __FUNCTION__);
|
||||
|
||||
// Parent == Invalid i.e. Invisible Root.
|
||||
// ==> Children are Protocol (Top Level) Items
|
||||
if (!parent.isValid())
|
||||
return mSelectedProtocols.size();
|
||||
|
||||
// Parent - Valid Item
|
||||
parentId.w = parent.internalId();
|
||||
switch(parentId.ws.type)
|
||||
{
|
||||
case ITYP_PROTOCOL:
|
||||
return mSelectedProtocols.at(parentId.ws.protocol)->frameFieldCount();
|
||||
case ITYP_FIELD:
|
||||
return 0;
|
||||
default:
|
||||
qWarning("%s: Unhandled ItemType", __FUNCTION__);
|
||||
}
|
||||
|
||||
Q_ASSERT(1 == 0); // Unreachable code
|
||||
qWarning("%s: Catch all - need to investigate", __FUNCTION__);
|
||||
return 0; // catch all
|
||||
}
|
||||
|
||||
int PacketModel::columnCount(const QModelIndex &/*parent*/) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QModelIndex PacketModel::index(int row, int col, const QModelIndex &parent) const
|
||||
{
|
||||
QModelIndex index;
|
||||
IndexId id, parentId;
|
||||
|
||||
if (!hasIndex(row, col, parent))
|
||||
goto _exit;
|
||||
|
||||
// Parent is Invisible Root
|
||||
// Request for a Protocol Item
|
||||
if (!parent.isValid())
|
||||
{
|
||||
id.w = 0;
|
||||
id.ws.type = ITYP_PROTOCOL;
|
||||
id.ws.protocol = row;
|
||||
index = createIndex(row, col, id.w);
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
// Parent is a Valid Item
|
||||
parentId.w = parent.internalId();
|
||||
id.w = parentId.w;
|
||||
switch(parentId.ws.type)
|
||||
{
|
||||
case ITYP_PROTOCOL:
|
||||
id.ws.type = ITYP_FIELD;
|
||||
index = createIndex(row, col, id.w);
|
||||
goto _exit;
|
||||
|
||||
case ITYP_FIELD:
|
||||
Q_ASSERT(1 == 0); // Unreachable code
|
||||
goto _exit;
|
||||
|
||||
default:
|
||||
qWarning("%s: Unhandled ItemType", __FUNCTION__);
|
||||
}
|
||||
|
||||
Q_ASSERT(1 == 0); // Unreachable code
|
||||
|
||||
_exit:
|
||||
return index;
|
||||
}
|
||||
|
||||
QModelIndex PacketModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
QModelIndex parentIndex;
|
||||
IndexId id, parentId;
|
||||
|
||||
if (!index.isValid())
|
||||
return QModelIndex();
|
||||
|
||||
id.w = index.internalId();
|
||||
parentId.w = id.w;
|
||||
switch(id.ws.type)
|
||||
{
|
||||
case ITYP_PROTOCOL:
|
||||
// return invalid index for invisible root
|
||||
goto _exit;
|
||||
|
||||
case ITYP_FIELD:
|
||||
parentId.ws.type = ITYP_PROTOCOL;
|
||||
parentIndex = createIndex(id.ws.protocol, 0, parentId.w);
|
||||
goto _exit;
|
||||
|
||||
default:
|
||||
qWarning("%s: Unhandled ItemType", __FUNCTION__);
|
||||
}
|
||||
|
||||
Q_ASSERT(1 == 1); // Unreachable code
|
||||
|
||||
_exit:
|
||||
return parentIndex;
|
||||
}
|
||||
|
||||
QVariant PacketModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
IndexId id;
|
||||
int fieldIdx = 0;
|
||||
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
id.w = index.internalId();
|
||||
|
||||
if (id.ws.type == ITYP_FIELD)
|
||||
{
|
||||
const AbstractProtocol *p = mSelectedProtocols.at(id.ws.protocol);
|
||||
int n = index.row() + 1;
|
||||
|
||||
while (n)
|
||||
{
|
||||
if (p->fieldFlags(fieldIdx).testFlag(AbstractProtocol::FrameField))
|
||||
n--;
|
||||
fieldIdx++;
|
||||
}
|
||||
fieldIdx--;
|
||||
}
|
||||
|
||||
// FIXME(HI): Relook at this completely
|
||||
if (role == Qt::UserRole)
|
||||
{
|
||||
switch(id.ws.type)
|
||||
{
|
||||
case ITYP_PROTOCOL:
|
||||
qDebug("*** %d/%d", id.ws.protocol, mSelectedProtocols.size());
|
||||
return mSelectedProtocols.at(id.ws.protocol)->
|
||||
protocolFrameValue();
|
||||
|
||||
case ITYP_FIELD:
|
||||
return mSelectedProtocols.at(id.ws.protocol)->fieldData(
|
||||
fieldIdx, AbstractProtocol::FieldFrameValue);
|
||||
|
||||
default:
|
||||
qWarning("%s: Unhandled ItemType", __FUNCTION__);
|
||||
}
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
// FIXME: Use a new enum here instead of UserRole
|
||||
if (role == (Qt::UserRole+1))
|
||||
{
|
||||
switch(id.ws.type)
|
||||
{
|
||||
case ITYP_PROTOCOL:
|
||||
return mSelectedProtocols.at(id.ws.protocol)->
|
||||
protocolFrameValue().size();
|
||||
|
||||
case ITYP_FIELD:
|
||||
return mSelectedProtocols.at(id.ws.protocol)->fieldData(
|
||||
fieldIdx, AbstractProtocol::FieldBitSize);
|
||||
|
||||
default:
|
||||
qWarning("%s: Unhandled ItemType", __FUNCTION__);
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
switch(id.ws.type)
|
||||
{
|
||||
case ITYP_PROTOCOL:
|
||||
return QString("%1 (%2)")
|
||||
.arg(mSelectedProtocols.at(id.ws.protocol)->shortName())
|
||||
.arg(mSelectedProtocols.at(id.ws.protocol)->name());
|
||||
|
||||
case ITYP_FIELD:
|
||||
return mSelectedProtocols.at(id.ws.protocol)->fieldData(fieldIdx,
|
||||
AbstractProtocol::FieldName).toString() + QString(" : ") +
|
||||
mSelectedProtocols.at(id.ws.protocol)->fieldData(fieldIdx,
|
||||
AbstractProtocol::FieldTextValue).toString();
|
||||
|
||||
default:
|
||||
qWarning("%s: Unhandled ItemType", __FUNCTION__);
|
||||
}
|
||||
|
||||
Q_ASSERT(1 == 1); // Unreachable code
|
||||
|
||||
return QVariant();
|
||||
}
|
61
client/packetmodel.h
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
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 _PACKET_MODEL_H
|
||||
#define _PACKET_MODEL_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
class ProtocolListIterator;
|
||||
class AbstractProtocol;
|
||||
|
||||
class PacketModel: public QAbstractItemModel
|
||||
{
|
||||
|
||||
public:
|
||||
PacketModel(QObject *parent = 0);
|
||||
void setSelectedProtocols(ProtocolListIterator &iter);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QVariant headerData(int /*section*/, Qt::Orientation /*orientation*/,
|
||||
int /*role= Qt::DisplayRole*/) const {
|
||||
return QVariant();
|
||||
}
|
||||
QModelIndex index (int row, int col, const QModelIndex & parent = QModelIndex() ) const;
|
||||
QModelIndex parent(const QModelIndex &index) const;
|
||||
|
||||
private:
|
||||
typedef union _IndexId
|
||||
{
|
||||
quint32 w;
|
||||
struct
|
||||
{
|
||||
quint16 type;
|
||||
#define ITYP_PROTOCOL 1
|
||||
#define ITYP_FIELD 2
|
||||
quint16 protocol; // protocol is valid for both ITYPs
|
||||
} ws;
|
||||
} IndexId;
|
||||
|
||||
QList<const AbstractProtocol*> mSelectedProtocols;
|
||||
};
|
||||
#endif
|
||||
|
573
client/port.cpp
Normal file
@ -0,0 +1,573 @@
|
||||
/*
|
||||
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 "port.h"
|
||||
|
||||
#include "abstractfileformat.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMainWindow>
|
||||
#include <QProgressDialog>
|
||||
#include <QVariant>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <vector>
|
||||
|
||||
extern QMainWindow *mainWindow;
|
||||
|
||||
uint Port::mAllocStreamId = 0;
|
||||
|
||||
static const int kEthOverhead = 20;
|
||||
|
||||
uint Port::newStreamId()
|
||||
{
|
||||
return mAllocStreamId++;
|
||||
}
|
||||
|
||||
Port::Port(quint32 id, quint32 portGroupId)
|
||||
{
|
||||
mPortId = id;
|
||||
d.mutable_port_id()->set_id(id);
|
||||
stats.mutable_port_id()->set_id(id);
|
||||
mPortGroupId = portGroupId;
|
||||
capFile_ = NULL;
|
||||
}
|
||||
|
||||
Port::~Port()
|
||||
{
|
||||
qDebug("%s", __FUNCTION__);
|
||||
while (!mStreams.isEmpty())
|
||||
delete mStreams.takeFirst();
|
||||
}
|
||||
|
||||
void Port::updatePortConfig(OstProto::Port *port)
|
||||
{
|
||||
d.MergeFrom(*port);
|
||||
}
|
||||
|
||||
void Port::updateStreamOrdinalsFromIndex()
|
||||
{
|
||||
for (int i=0; i < mStreams.size(); i++)
|
||||
mStreams[i]->setOrdinal(i);
|
||||
}
|
||||
|
||||
void Port::reorderStreamsByOrdinals()
|
||||
{
|
||||
qSort(mStreams.begin(), mStreams.end(), StreamBase::StreamLessThan);
|
||||
}
|
||||
|
||||
void Port::recalculateAverageRates()
|
||||
{
|
||||
double pps = 0;
|
||||
double bps = 0;
|
||||
int n = 0;
|
||||
|
||||
foreach (Stream* s, mStreams)
|
||||
{
|
||||
if (!s->isEnabled())
|
||||
continue;
|
||||
|
||||
double r = s->averagePacketRate();
|
||||
pps += r;
|
||||
bps += r * (s->frameLenAvg() + kEthOverhead) * 8;
|
||||
n++;
|
||||
|
||||
if ((transmitMode() == OstProto::kSequentialTransmit)
|
||||
&& (s->nextWhat() == Stream::e_nw_stop))
|
||||
break;
|
||||
}
|
||||
|
||||
if (n)
|
||||
{
|
||||
switch (transmitMode())
|
||||
{
|
||||
case OstProto::kSequentialTransmit:
|
||||
avgPacketsPerSec_ = pps/n;
|
||||
avgBitsPerSec_ = bps/n;
|
||||
break;
|
||||
case OstProto::kInterleavedTransmit:
|
||||
avgPacketsPerSec_ = pps;
|
||||
avgBitsPerSec_ = bps;
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(false); // Unreachable!!
|
||||
}
|
||||
numActiveStreams_ = n;
|
||||
}
|
||||
else
|
||||
avgPacketsPerSec_ = avgBitsPerSec_ = numActiveStreams_ = 0;
|
||||
|
||||
qDebug("%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__,
|
||||
avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_);
|
||||
|
||||
emit portRateChanged(mPortGroupId, mPortId);
|
||||
|
||||
}
|
||||
|
||||
void Port::setAveragePacketRate(double packetsPerSec)
|
||||
{
|
||||
double rate;
|
||||
double pps = 0;
|
||||
double bps = 0;
|
||||
int n = 0;
|
||||
|
||||
qDebug("@%s: packetsPerSec = %g", __FUNCTION__, packetsPerSec);
|
||||
qDebug("@%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__,
|
||||
avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_);
|
||||
foreach (Stream* s, mStreams)
|
||||
{
|
||||
if (!s->isEnabled())
|
||||
continue;
|
||||
|
||||
switch (transmitMode())
|
||||
{
|
||||
case OstProto::kSequentialTransmit:
|
||||
rate = s->averagePacketRate() * (packetsPerSec/avgPacketsPerSec_);
|
||||
break;
|
||||
case OstProto::kInterleavedTransmit:
|
||||
rate = s->averagePacketRate() +
|
||||
((s->averagePacketRate()/avgPacketsPerSec_) *
|
||||
(packetsPerSec - avgPacketsPerSec_));
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(false); // Unreachable!!
|
||||
}
|
||||
|
||||
qDebug("cur stream pps = %g", s->averagePacketRate());
|
||||
|
||||
s->setAveragePacketRate(rate);
|
||||
|
||||
qDebug("new stream pps = %g", s->averagePacketRate());
|
||||
|
||||
double r = s->averagePacketRate();
|
||||
pps += r;
|
||||
bps += r * (s->frameLenAvg() + kEthOverhead) * 8;
|
||||
n++;
|
||||
|
||||
if ((transmitMode() == OstProto::kSequentialTransmit)
|
||||
&& (s->nextWhat() == Stream::e_nw_stop))
|
||||
break;
|
||||
}
|
||||
|
||||
if (n)
|
||||
{
|
||||
switch (transmitMode())
|
||||
{
|
||||
case OstProto::kSequentialTransmit:
|
||||
avgPacketsPerSec_ = pps/n;
|
||||
avgBitsPerSec_ = bps/n;
|
||||
break;
|
||||
case OstProto::kInterleavedTransmit:
|
||||
avgPacketsPerSec_ = pps;
|
||||
avgBitsPerSec_ = bps;
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(false); // Unreachable!!
|
||||
}
|
||||
numActiveStreams_ = n;
|
||||
}
|
||||
else
|
||||
avgPacketsPerSec_ = avgBitsPerSec_ = numActiveStreams_ = 0;
|
||||
|
||||
qDebug("%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__,
|
||||
avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_);
|
||||
|
||||
emit portRateChanged(mPortGroupId, mPortId);
|
||||
}
|
||||
|
||||
void Port::setAverageBitRate(double bitsPerSec)
|
||||
{
|
||||
double rate;
|
||||
double pps = 0;
|
||||
double bps = 0;
|
||||
int n = 0;
|
||||
|
||||
qDebug("@%s: bitsPerSec = %g", __FUNCTION__, bitsPerSec);
|
||||
qDebug("@%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__,
|
||||
avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_);
|
||||
foreach (Stream* s, mStreams)
|
||||
{
|
||||
if (!s->isEnabled())
|
||||
continue;
|
||||
|
||||
switch (transmitMode())
|
||||
{
|
||||
case OstProto::kSequentialTransmit:
|
||||
rate = s->averagePacketRate() * (bitsPerSec/avgBitsPerSec_);
|
||||
qDebug("rate = %g", rate);
|
||||
break;
|
||||
case OstProto::kInterleavedTransmit:
|
||||
rate = s->averagePacketRate()
|
||||
+ ((s->averagePacketRate()/avgPacketsPerSec_)
|
||||
* ((bitsPerSec - avgBitsPerSec_)
|
||||
/ ((s->frameLenAvg()+kEthOverhead)*8)));
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(false); // Unreachable!!
|
||||
}
|
||||
|
||||
qDebug("cur stream pps = %g", s->averagePacketRate());
|
||||
|
||||
s->setAveragePacketRate(rate);
|
||||
|
||||
qDebug("new stream pps = %g", s->averagePacketRate());
|
||||
|
||||
double r = s->averagePacketRate();
|
||||
pps += r;
|
||||
bps += r * (s->frameLenAvg() + kEthOverhead) * 8;
|
||||
n++;
|
||||
|
||||
if ((transmitMode() == OstProto::kSequentialTransmit)
|
||||
&& (s->nextWhat() == Stream::e_nw_stop))
|
||||
break;
|
||||
}
|
||||
|
||||
if (n)
|
||||
{
|
||||
switch (transmitMode())
|
||||
{
|
||||
case OstProto::kSequentialTransmit:
|
||||
avgPacketsPerSec_ = pps/n;
|
||||
avgBitsPerSec_ = bps/n;
|
||||
break;
|
||||
case OstProto::kInterleavedTransmit:
|
||||
avgPacketsPerSec_ = pps;
|
||||
avgBitsPerSec_ = bps;
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(false); // Unreachable!!
|
||||
}
|
||||
numActiveStreams_ = n;
|
||||
}
|
||||
else
|
||||
avgPacketsPerSec_ = avgBitsPerSec_ = numActiveStreams_ = 0;
|
||||
|
||||
qDebug("%s: avgPps = %g avgBps = %g numActive = %d", __FUNCTION__,
|
||||
avgPacketsPerSec_, avgBitsPerSec_, numActiveStreams_);
|
||||
emit portRateChanged(mPortGroupId, mPortId);
|
||||
}
|
||||
|
||||
bool Port::newStreamAt(int index, OstProto::Stream const *stream)
|
||||
{
|
||||
Stream *s = new Stream;
|
||||
|
||||
if (index > mStreams.size())
|
||||
return false;
|
||||
|
||||
if (stream)
|
||||
s->protoDataCopyFrom(*stream);
|
||||
|
||||
s->setId(newStreamId());
|
||||
mStreams.insert(index, s);
|
||||
updateStreamOrdinalsFromIndex();
|
||||
recalculateAverageRates();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Port::deleteStreamAt(int index)
|
||||
{
|
||||
if (index >= mStreams.size())
|
||||
return false;
|
||||
|
||||
delete mStreams.takeAt(index);
|
||||
updateStreamOrdinalsFromIndex();
|
||||
recalculateAverageRates();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Port::insertStream(uint streamId)
|
||||
{
|
||||
Stream *s = new Stream;
|
||||
|
||||
s->setId(streamId);
|
||||
|
||||
// FIXME(MED): If a stream with id already exists, what do we do?
|
||||
mStreams.append(s);
|
||||
|
||||
// Update mAllocStreamId to take into account the stream id received
|
||||
// from server
|
||||
if (mAllocStreamId <= streamId)
|
||||
mAllocStreamId = streamId + 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Port::updateStream(uint streamId, OstProto::Stream *stream)
|
||||
{
|
||||
int i, streamIndex;
|
||||
|
||||
for (i = 0; i < mStreams.size(); i++)
|
||||
{
|
||||
if (streamId == mStreams[i]->id())
|
||||
goto _found;
|
||||
}
|
||||
|
||||
qDebug("%s: Invalid stream id %d", __FUNCTION__, streamId);
|
||||
return false;
|
||||
|
||||
_found:
|
||||
streamIndex = i;
|
||||
|
||||
mStreams[streamIndex]->protoDataCopyFrom(*stream);
|
||||
reorderStreamsByOrdinals();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Port::getDeletedStreamsSinceLastSync(
|
||||
OstProto::StreamIdList &streamIdList)
|
||||
{
|
||||
streamIdList.clear_stream_id();
|
||||
for (int i = 0; i < mLastSyncStreamList.size(); i++)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < mStreams.size(); j++)
|
||||
{
|
||||
if (mLastSyncStreamList[i] == mStreams[j]->id())
|
||||
break;
|
||||
}
|
||||
|
||||
if (j < mStreams.size())
|
||||
{
|
||||
// stream still exists!
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// stream has been deleted since last sync
|
||||
OstProto::StreamId *s;
|
||||
|
||||
s = streamIdList.add_stream_id();
|
||||
s->set_id(mLastSyncStreamList.at(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Port::getNewStreamsSinceLastSync(
|
||||
OstProto::StreamIdList &streamIdList)
|
||||
{
|
||||
streamIdList.clear_stream_id();
|
||||
for (int i = 0; i < mStreams.size(); i++)
|
||||
{
|
||||
if (mLastSyncStreamList.contains(mStreams[i]->id()))
|
||||
{
|
||||
// existing stream!
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// new stream!
|
||||
OstProto::StreamId *s;
|
||||
|
||||
s = streamIdList.add_stream_id();
|
||||
s->set_id(mStreams[i]->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Port::getModifiedStreamsSinceLastSync(
|
||||
OstProto::StreamConfigList &streamConfigList)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
//streamConfigList.mutable_port_id()->set_id(mPortId);
|
||||
for (int i = 0; i < mStreams.size(); i++)
|
||||
{
|
||||
OstProto::Stream *s;
|
||||
|
||||
s = streamConfigList.add_stream();
|
||||
mStreams[i]->protoDataCopyInto(*s);
|
||||
}
|
||||
qDebug("Done %s", __FUNCTION__);
|
||||
}
|
||||
|
||||
void Port::when_syncComplete()
|
||||
{
|
||||
//reorderStreamsByOrdinals();
|
||||
|
||||
mLastSyncStreamList.clear();
|
||||
for (int i=0; i<mStreams.size(); i++)
|
||||
mLastSyncStreamList.append(mStreams[i]->id());
|
||||
}
|
||||
|
||||
void Port::updateStats(OstProto::PortStats *portStats)
|
||||
{
|
||||
OstProto::PortState oldState;
|
||||
|
||||
oldState = stats.state();
|
||||
stats.MergeFrom(*portStats);
|
||||
|
||||
if (oldState.link_state() != stats.state().link_state())
|
||||
{
|
||||
qDebug("portstate changed");
|
||||
emit portDataChanged(mPortGroupId, mPortId);
|
||||
}
|
||||
}
|
||||
|
||||
bool Port::openStreams(QString fileName, bool append, QString &error)
|
||||
{
|
||||
bool ret = false;
|
||||
QDialog *optDialog;
|
||||
QProgressDialog progress("Opening Streams", "Cancel", 0, 0, mainWindow);
|
||||
OstProto::StreamConfigList streams;
|
||||
AbstractFileFormat *fmt = AbstractFileFormat::fileFormatFromFile(fileName);
|
||||
|
||||
if (fmt == NULL)
|
||||
goto _fail;
|
||||
|
||||
if ((optDialog = fmt->openOptionsDialog()))
|
||||
{
|
||||
int ret;
|
||||
optDialog->setParent(mainWindow, Qt::Dialog);
|
||||
ret = optDialog->exec();
|
||||
optDialog->setParent(0, Qt::Dialog);
|
||||
if (ret == QDialog::Rejected)
|
||||
goto _user_opt_cancel;
|
||||
}
|
||||
|
||||
progress.setAutoReset(false);
|
||||
progress.setAutoClose(false);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.show();
|
||||
|
||||
mainWindow->setDisabled(true);
|
||||
progress.setEnabled(true); // to override the mainWindow disable
|
||||
|
||||
connect(fmt, SIGNAL(status(QString)),&progress,SLOT(setLabelText(QString)));
|
||||
connect(fmt, SIGNAL(target(int)), &progress, SLOT(setMaximum(int)));
|
||||
connect(fmt, SIGNAL(progress(int)), &progress, SLOT(setValue(int)));
|
||||
connect(&progress, SIGNAL(canceled()), fmt, SLOT(cancel()));
|
||||
|
||||
fmt->openStreamsOffline(fileName, streams, error);
|
||||
qDebug("after open offline");
|
||||
|
||||
while (!fmt->isFinished())
|
||||
qApp->processEvents();
|
||||
qDebug("wait over for offline operation");
|
||||
|
||||
if (!fmt->result())
|
||||
goto _fail;
|
||||
|
||||
// process any remaining events posted from the thread
|
||||
for (int i = 0; i < 10; i++)
|
||||
qApp->processEvents();
|
||||
|
||||
if (!append)
|
||||
{
|
||||
int n = numStreams();
|
||||
|
||||
progress.setLabelText("Deleting existing streams...");
|
||||
progress.setRange(0, n);
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
if (progress.wasCanceled())
|
||||
goto _user_cancel;
|
||||
deleteStreamAt(0);
|
||||
progress.setValue(i);
|
||||
if (i % 32 == 0)
|
||||
qApp->processEvents();
|
||||
}
|
||||
}
|
||||
|
||||
progress.setLabelText("Constructing new streams...");
|
||||
progress.setRange(0, streams.stream_size());
|
||||
for (int i = 0; i < streams.stream_size(); i++)
|
||||
{
|
||||
if (progress.wasCanceled())
|
||||
goto _user_cancel;
|
||||
newStreamAt(mStreams.size(), &streams.stream(i));
|
||||
progress.setValue(i);
|
||||
if (i % 32 == 0)
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
_user_cancel:
|
||||
emit streamListChanged(mPortGroupId, mPortId);
|
||||
_user_opt_cancel:
|
||||
ret = true;
|
||||
|
||||
_fail:
|
||||
progress.close();
|
||||
mainWindow->setEnabled(true);
|
||||
recalculateAverageRates();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Port::saveStreams(QString fileName, QString fileType, QString &error)
|
||||
{
|
||||
bool ret = false;
|
||||
QProgressDialog progress("Saving Streams", "Cancel", 0, 0, mainWindow);
|
||||
AbstractFileFormat *fmt = AbstractFileFormat::fileFormatFromType(fileType);
|
||||
OstProto::StreamConfigList streams;
|
||||
|
||||
if (fmt == NULL)
|
||||
goto _fail;
|
||||
|
||||
progress.setAutoReset(false);
|
||||
progress.setAutoClose(false);
|
||||
progress.setMinimumDuration(0);
|
||||
progress.show();
|
||||
|
||||
mainWindow->setDisabled(true);
|
||||
progress.setEnabled(true); // to override the mainWindow disable
|
||||
|
||||
connect(fmt, SIGNAL(status(QString)),&progress,SLOT(setLabelText(QString)));
|
||||
connect(fmt, SIGNAL(target(int)), &progress, SLOT(setMaximum(int)));
|
||||
connect(fmt, SIGNAL(progress(int)), &progress, SLOT(setValue(int)));
|
||||
connect(&progress, SIGNAL(canceled()), fmt, SLOT(cancel()));
|
||||
|
||||
progress.setLabelText("Preparing Streams...");
|
||||
progress.setRange(0, mStreams.size());
|
||||
streams.mutable_port_id()->set_id(0);
|
||||
for (int i = 0; i < mStreams.size(); i++)
|
||||
{
|
||||
OstProto::Stream *s = streams.add_stream();
|
||||
mStreams[i]->protoDataCopyInto(*s);
|
||||
|
||||
if (progress.wasCanceled())
|
||||
goto _user_cancel;
|
||||
progress.setValue(i);
|
||||
if (i % 32 == 0)
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
fmt->saveStreamsOffline(streams, fileName, error);
|
||||
qDebug("after save offline");
|
||||
|
||||
while (!fmt->isFinished())
|
||||
qApp->processEvents();
|
||||
qDebug("wait over for offline operation");
|
||||
|
||||
ret = fmt->result();
|
||||
goto _exit;
|
||||
|
||||
_user_cancel:
|
||||
goto _exit;
|
||||
|
||||
_fail:
|
||||
error = QString("Unsupported File Type - %1").arg(fileType);
|
||||
goto _exit;
|
||||
|
||||
_exit:
|
||||
progress.close();
|
||||
mainWindow->setEnabled(true);
|
||||
return ret;
|
||||
}
|
147
client/port.h
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
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 _PORT_H
|
||||
#define _PORT_H
|
||||
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QTemporaryFile>
|
||||
|
||||
#include "stream.h"
|
||||
|
||||
//class StreamModel;
|
||||
|
||||
class Port : public QObject {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
static uint mAllocStreamId;
|
||||
|
||||
OstProto::Port d;
|
||||
OstProto::PortStats stats;
|
||||
QTemporaryFile *capFile_;
|
||||
|
||||
// FIXME(HI): consider removing mPortId as it is duplicated inside 'd'
|
||||
quint32 mPortId;
|
||||
quint32 mPortGroupId;
|
||||
QString mUserAlias; // user defined
|
||||
|
||||
double avgPacketsPerSec_;
|
||||
double avgBitsPerSec_;
|
||||
int numActiveStreams_;
|
||||
|
||||
QList<quint32> mLastSyncStreamList;
|
||||
QList<Stream*> mStreams; // sorted by stream's ordinal value
|
||||
|
||||
uint newStreamId();
|
||||
void updateStreamOrdinalsFromIndex();
|
||||
void reorderStreamsByOrdinals();
|
||||
|
||||
|
||||
public:
|
||||
enum AdminStatus { AdminDisable, AdminEnable };
|
||||
|
||||
// FIXME(HIGH): default args is a hack for QList operations on Port
|
||||
Port(quint32 id = 0xFFFFFFFF, quint32 pgId = 0xFFFFFFFF);
|
||||
~Port();
|
||||
|
||||
quint32 portGroupId() const { return mPortGroupId; }
|
||||
const QString& userAlias() const { return mUserAlias; }
|
||||
|
||||
quint32 id() const
|
||||
{ return d.port_id().id(); }
|
||||
const QString name() const
|
||||
{ return QString().fromStdString(d.name()); }
|
||||
const QString description() const
|
||||
{ return QString().fromStdString(d.description()); }
|
||||
const QString notes() const
|
||||
{ return QString().fromStdString(d.notes()); }
|
||||
AdminStatus adminStatus()
|
||||
{ return (d.is_enabled()?AdminEnable:AdminDisable); }
|
||||
bool hasExclusiveControl()
|
||||
{ return d.is_exclusive_control(); }
|
||||
OstProto::TransmitMode transmitMode()
|
||||
{ return d.transmit_mode(); }
|
||||
double averagePacketRate()
|
||||
{ return avgPacketsPerSec_; }
|
||||
double averageBitRate()
|
||||
{ return avgBitsPerSec_; }
|
||||
|
||||
//void setAdminEnable(AdminStatus status) { mAdminStatus = status; }
|
||||
void setAlias(QString &alias) { mUserAlias = alias; }
|
||||
//void setExclusive(bool flag);
|
||||
|
||||
int numStreams() { return mStreams.size(); }
|
||||
Stream* streamByIndex(int index)
|
||||
{
|
||||
Q_ASSERT(index < mStreams.size());
|
||||
return mStreams[index];
|
||||
}
|
||||
OstProto::LinkState linkState()
|
||||
{ return stats.state().link_state(); }
|
||||
|
||||
OstProto::PortStats getStats() { return stats; }
|
||||
QTemporaryFile* getCaptureFile()
|
||||
{
|
||||
delete capFile_;
|
||||
capFile_ = new QTemporaryFile();
|
||||
return capFile_;
|
||||
}
|
||||
|
||||
// FIXME(MED): naming inconsistency - PortConfig/Stream; also retVal
|
||||
void updatePortConfig(OstProto::Port *port);
|
||||
|
||||
//! Used by StreamModel
|
||||
//@{
|
||||
bool newStreamAt(int index, OstProto::Stream const *stream = NULL);
|
||||
bool deleteStreamAt(int index);
|
||||
//@}
|
||||
|
||||
//! Used by MyService::Stub to update from config received from server
|
||||
//@{
|
||||
bool insertStream(uint streamId);
|
||||
bool updateStream(uint streamId, OstProto::Stream *stream);
|
||||
//@}
|
||||
|
||||
void getDeletedStreamsSinceLastSync(OstProto::StreamIdList &streamIdList);
|
||||
void getNewStreamsSinceLastSync(OstProto::StreamIdList &streamIdList);
|
||||
void getModifiedStreamsSinceLastSync(
|
||||
OstProto::StreamConfigList &streamConfigList);
|
||||
|
||||
void when_syncComplete();
|
||||
|
||||
void setAveragePacketRate(double packetsPerSec);
|
||||
void setAverageBitRate(double bitsPerSec);
|
||||
// FIXME(MED): Bad Hack! port should not need an external trigger to
|
||||
// recalculate - refactor client side domain objects and model objects
|
||||
void recalculateAverageRates();
|
||||
void updateStats(OstProto::PortStats *portStats);
|
||||
|
||||
bool openStreams(QString fileName, bool append, QString &error);
|
||||
bool saveStreams(QString fileName, QString fileType, QString &error);
|
||||
|
||||
signals:
|
||||
void portRateChanged(int portGroupId, int portId);
|
||||
void portDataChanged(int portGroupId, int portId);
|
||||
void streamListChanged(int portGroupId, int portId);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
57
client/portconfigdialog.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright (C) 2011 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 "portconfigdialog.h"
|
||||
|
||||
PortConfigDialog::PortConfigDialog(OstProto::Port &portConfig, QWidget *parent)
|
||||
: QDialog(parent), portConfig_(portConfig)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
setupUi(this);
|
||||
|
||||
switch(portConfig_.transmit_mode())
|
||||
{
|
||||
case OstProto::kSequentialTransmit:
|
||||
sequentialStreamsButton->setChecked(true);
|
||||
break;
|
||||
case OstProto::kInterleavedTransmit:
|
||||
interleavedStreamsButton->setChecked(true);
|
||||
break;
|
||||
default:
|
||||
Q_ASSERT(false); // Unreachable!!!
|
||||
break;
|
||||
}
|
||||
|
||||
exclusiveControlButton->setChecked(portConfig_.is_exclusive_control());
|
||||
}
|
||||
|
||||
void PortConfigDialog::accept()
|
||||
{
|
||||
if (sequentialStreamsButton->isChecked())
|
||||
portConfig_.set_transmit_mode(OstProto::kSequentialTransmit);
|
||||
else if (interleavedStreamsButton->isChecked())
|
||||
portConfig_.set_transmit_mode(OstProto::kInterleavedTransmit);
|
||||
else
|
||||
Q_ASSERT(false); // Unreachable!!!
|
||||
|
||||
portConfig_.set_is_exclusive_control(exclusiveControlButton->isChecked());
|
||||
|
||||
QDialog::accept();
|
||||
}
|
39
client/portconfigdialog.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
Copyright (C) 2011 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 _PORT_CONFIG_DIALOG_H
|
||||
#define _PORT_CONFIG_DIALOG_H
|
||||
|
||||
#include "ui_portconfigdialog.h"
|
||||
#include "protocol.pb.h"
|
||||
#include <QDialog>
|
||||
|
||||
class PortConfigDialog : public QDialog, public Ui::PortConfigDialog
|
||||
{
|
||||
public:
|
||||
PortConfigDialog(OstProto::Port &portConfig, QWidget *parent);
|
||||
|
||||
private:
|
||||
virtual void accept();
|
||||
|
||||
OstProto::Port &portConfig_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
109
client/portconfigdialog.ui
Normal file
@ -0,0 +1,109 @@
|
||||
<ui version="4.0" >
|
||||
<class>PortConfigDialog</class>
|
||||
<widget class="QDialog" name="PortConfigDialog" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>244</width>
|
||||
<height>160</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Port Config</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QGroupBox" name="transmitModeBox" >
|
||||
<property name="title" >
|
||||
<string>Transmit Mode</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QRadioButton" name="sequentialStreamsButton" >
|
||||
<property name="text" >
|
||||
<string>Sequential Streams</string>
|
||||
</property>
|
||||
<property name="checked" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="interleavedStreamsButton" >
|
||||
<property name="text" >
|
||||
<string>Interleaved Streams</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="exclusiveControlButton" >
|
||||
<property name="text" >
|
||||
<string>Exclusive Control</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</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>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>PortConfigDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>PortConfigDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
838
client/portgroup.cpp
Normal file
@ -0,0 +1,838 @@
|
||||
/*
|
||||
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 "portgroup.h"
|
||||
|
||||
#include "settings.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCursor>
|
||||
#include <QMainWindow>
|
||||
#include <QMessageBox>
|
||||
#include <QProcess>
|
||||
#include <QTemporaryFile>
|
||||
#include <QTimer>
|
||||
#include <QtGlobal>
|
||||
|
||||
using ::google::protobuf::NewCallback;
|
||||
|
||||
extern QMainWindow *mainWindow;
|
||||
|
||||
quint32 PortGroup::mPortGroupAllocId = 0;
|
||||
|
||||
PortGroup::PortGroup(QHostAddress ip, quint16 port)
|
||||
{
|
||||
// Allocate an id for self
|
||||
mPortGroupId = PortGroup::mPortGroupAllocId++;
|
||||
|
||||
portIdList_ = new OstProto::PortIdList;
|
||||
portStatsList_ = new OstProto::PortStatsList;
|
||||
|
||||
statsController = new PbRpcController(portIdList_, portStatsList_);
|
||||
isGetStatsPending_ = false;
|
||||
|
||||
reconnect = false;
|
||||
reconnectAfter = kMinReconnectWaitTime;
|
||||
reconnectTimer = new QTimer(this);
|
||||
reconnectTimer->setSingleShot(true);
|
||||
connect(reconnectTimer, SIGNAL(timeout()),
|
||||
this, SLOT(on_reconnectTimer_timeout()));
|
||||
|
||||
rpcChannel = new PbRpcChannel(ip, port);
|
||||
serviceStub = new OstProto::OstService::Stub(rpcChannel);
|
||||
|
||||
// FIXME(LOW):Can't for my life figure out why this ain't working!
|
||||
//QMetaObject::connectSlotsByName(this);
|
||||
connect(rpcChannel, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
|
||||
this, SLOT(on_rpcChannel_stateChanged(QAbstractSocket::SocketState)));
|
||||
connect(rpcChannel, SIGNAL(connected()),
|
||||
this, SLOT(on_rpcChannel_connected()));
|
||||
connect(rpcChannel, SIGNAL(disconnected()),
|
||||
this, SLOT(on_rpcChannel_disconnected()));
|
||||
connect(rpcChannel, SIGNAL(error(QAbstractSocket::SocketError)),
|
||||
this, SLOT(on_rpcChannel_error(QAbstractSocket::SocketError)));
|
||||
|
||||
connect(this, SIGNAL(portListChanged(quint32)),
|
||||
this, SLOT(when_portListChanged(quint32)), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
PortGroup::~PortGroup()
|
||||
{
|
||||
qDebug("PortGroup Destructor");
|
||||
// Disconnect and free rpc channel etc.
|
||||
PortGroup::disconnectFromHost();
|
||||
delete serviceStub;
|
||||
delete rpcChannel;
|
||||
delete statsController;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------
|
||||
// Slots
|
||||
// ------------------------------------------------
|
||||
void PortGroup::on_reconnectTimer_timeout()
|
||||
{
|
||||
reconnectAfter *= 2;
|
||||
if (reconnectAfter > kMaxReconnectWaitTime)
|
||||
reconnectAfter = kMaxReconnectWaitTime;
|
||||
|
||||
connectToHost();
|
||||
}
|
||||
|
||||
void PortGroup::on_rpcChannel_stateChanged(QAbstractSocket::SocketState state)
|
||||
{
|
||||
qDebug("state changed %d", state);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case QAbstractSocket::UnconnectedState:
|
||||
case QAbstractSocket::ClosingState:
|
||||
break;
|
||||
|
||||
default:
|
||||
emit portGroupDataChanged(mPortGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
void PortGroup::on_rpcChannel_connected()
|
||||
{
|
||||
OstProto::Void *void_ = new OstProto::Void;
|
||||
OstProto::PortIdList *portIdList = new OstProto::PortIdList;
|
||||
|
||||
qDebug("connected\n");
|
||||
emit portGroupDataChanged(mPortGroupId);
|
||||
|
||||
reconnectAfter = kMinReconnectWaitTime;
|
||||
|
||||
qDebug("requesting portlist ...");
|
||||
|
||||
PbRpcController *controller = new PbRpcController(void_, portIdList);
|
||||
serviceStub->getPortIdList(controller, void_, portIdList,
|
||||
NewCallback(this, &PortGroup::processPortIdList, controller));
|
||||
}
|
||||
|
||||
void PortGroup::on_rpcChannel_disconnected()
|
||||
{
|
||||
qDebug("disconnected\n");
|
||||
emit portListAboutToBeChanged(mPortGroupId);
|
||||
|
||||
while (!mPorts.isEmpty())
|
||||
delete mPorts.takeFirst();
|
||||
|
||||
emit portListChanged(mPortGroupId);
|
||||
emit portGroupDataChanged(mPortGroupId);
|
||||
|
||||
if (reconnect)
|
||||
{
|
||||
qDebug("starting reconnect timer for %d ms ...", reconnectAfter);
|
||||
reconnectTimer->start(reconnectAfter);
|
||||
}
|
||||
}
|
||||
|
||||
void PortGroup::on_rpcChannel_error(QAbstractSocket::SocketError socketError)
|
||||
{
|
||||
qDebug("%s: error %d", __FUNCTION__, socketError);
|
||||
emit portGroupDataChanged(mPortGroupId);
|
||||
|
||||
qDebug("%s: state %d", __FUNCTION__, rpcChannel->state());
|
||||
if ((rpcChannel->state() == QAbstractSocket::UnconnectedState) && reconnect)
|
||||
{
|
||||
qDebug("starting reconnect timer for %d ms...", reconnectAfter);
|
||||
reconnectTimer->start(reconnectAfter);
|
||||
}
|
||||
}
|
||||
|
||||
void PortGroup::when_portListChanged(quint32 /*portGroupId*/)
|
||||
{
|
||||
if (state() == QAbstractSocket::ConnectedState && numPorts() <= 0)
|
||||
{
|
||||
QMessageBox::warning(NULL, tr("No ports in portgroup"),
|
||||
QString("The portgroup %1:%2 does not contain any ports!\n\n"
|
||||
"Packet Transmit/Capture requires elevated privileges. "
|
||||
"Please ensure that you are running 'drone' - the server "
|
||||
"component of Ostinato with admin/root OR setuid privilege.\n\n"
|
||||
"For more information see "
|
||||
"http://code.google.com/p/ostinato/wiki/FAQ#"
|
||||
"Q._Port_group_has_no_interfaces")
|
||||
.arg(serverAddress().toString())
|
||||
.arg(int(serverPort())));
|
||||
}
|
||||
}
|
||||
|
||||
void PortGroup::processPortIdList(PbRpcController *controller)
|
||||
{
|
||||
OstProto::PortIdList *portIdList
|
||||
= static_cast<OstProto::PortIdList*>(controller->response());
|
||||
|
||||
Q_ASSERT(portIdList != NULL);
|
||||
|
||||
qDebug("got a portlist ...");
|
||||
|
||||
if (controller->Failed())
|
||||
{
|
||||
qDebug("%s: rpc failed", __FUNCTION__);
|
||||
goto _error_exit;
|
||||
}
|
||||
|
||||
emit portListAboutToBeChanged(mPortGroupId);
|
||||
|
||||
for(int i = 0; i < portIdList->port_id_size(); i++)
|
||||
{
|
||||
Port *p;
|
||||
|
||||
p = new Port(portIdList->port_id(i).id(), mPortGroupId);
|
||||
connect(p, SIGNAL(portDataChanged(int, int)),
|
||||
this, SIGNAL(portGroupDataChanged(int, int)));
|
||||
qDebug("before port append\n");
|
||||
mPorts.append(p);
|
||||
}
|
||||
|
||||
emit portListChanged(mPortGroupId);
|
||||
|
||||
portIdList_->CopyFrom(*portIdList);
|
||||
|
||||
// Request PortConfigList
|
||||
{
|
||||
qDebug("requesting port config list ...");
|
||||
OstProto::PortIdList *portIdList2 = new OstProto::PortIdList();
|
||||
OstProto::PortConfigList *portConfigList = new OstProto::PortConfigList();
|
||||
PbRpcController *controller2 = new PbRpcController(portIdList2,
|
||||
portConfigList);
|
||||
|
||||
portIdList2->CopyFrom(*portIdList);
|
||||
|
||||
serviceStub->getPortConfig(controller, portIdList2, portConfigList,
|
||||
NewCallback(this, &PortGroup::processPortConfigList, controller2));
|
||||
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
_error_exit:
|
||||
_exit:
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::processPortConfigList(PbRpcController *controller)
|
||||
{
|
||||
OstProto::PortConfigList *portConfigList
|
||||
= static_cast<OstProto::PortConfigList*>(controller->response());
|
||||
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
if (controller->Failed())
|
||||
{
|
||||
qDebug("%s: rpc failed", __FUNCTION__);
|
||||
goto _error_exit;
|
||||
}
|
||||
|
||||
//emit portListAboutToBeChanged(mPortGroupId);
|
||||
|
||||
for(int i = 0; i < portConfigList->port_size(); i++)
|
||||
{
|
||||
uint id;
|
||||
|
||||
id = portConfigList->port(i).port_id().id();
|
||||
// FIXME: don't mix port id & index into mPorts[]
|
||||
mPorts[id]->updatePortConfig(portConfigList->mutable_port(i));
|
||||
}
|
||||
|
||||
//emit portListChanged(mPortGroupId);
|
||||
|
||||
// FIXME: check if we need new signals since we are not changing the
|
||||
// number of ports, just the port data
|
||||
|
||||
if (numPorts() > 0)
|
||||
getStreamIdList();
|
||||
|
||||
_error_exit:
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::when_configApply(int portIndex)
|
||||
{
|
||||
OstProto::StreamIdList *streamIdList;
|
||||
OstProto::StreamConfigList *streamConfigList;
|
||||
OstProto::Ack *ack;
|
||||
PbRpcController *controller;
|
||||
|
||||
Q_ASSERT(portIndex < mPorts.size());
|
||||
|
||||
if (state() != QAbstractSocket::ConnectedState)
|
||||
return;
|
||||
|
||||
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||
mainWindow->setDisabled(true);
|
||||
|
||||
qDebug("applying 'deleted streams' ...");
|
||||
streamIdList = new OstProto::StreamIdList;
|
||||
ack = new OstProto::Ack;
|
||||
controller = new PbRpcController(streamIdList, ack);
|
||||
|
||||
streamIdList->mutable_port_id()->set_id(mPorts[portIndex]->id());
|
||||
mPorts[portIndex]->getDeletedStreamsSinceLastSync(*streamIdList);
|
||||
|
||||
serviceStub->deleteStream(controller, streamIdList, ack,
|
||||
NewCallback(this, &PortGroup::processDeleteStreamAck, controller));
|
||||
|
||||
qDebug("applying 'new streams' ...");
|
||||
streamIdList = new OstProto::StreamIdList;
|
||||
ack = new OstProto::Ack;
|
||||
controller = new PbRpcController(streamIdList, ack);
|
||||
|
||||
streamIdList->mutable_port_id()->set_id(mPorts[portIndex]->id());
|
||||
mPorts[portIndex]->getNewStreamsSinceLastSync(*streamIdList);
|
||||
|
||||
serviceStub->addStream(controller, streamIdList, ack,
|
||||
NewCallback(this, &PortGroup::processAddStreamAck, controller));
|
||||
|
||||
qDebug("applying 'modified streams' ...");
|
||||
streamConfigList = new OstProto::StreamConfigList;
|
||||
ack = new OstProto::Ack;
|
||||
controller = new PbRpcController(streamConfigList, ack);
|
||||
|
||||
streamConfigList->mutable_port_id()->set_id(mPorts[portIndex]->id());
|
||||
mPorts[portIndex]->getModifiedStreamsSinceLastSync(*streamConfigList);
|
||||
|
||||
serviceStub->modifyStream(controller, streamConfigList, ack,
|
||||
NewCallback(this, &PortGroup::processModifyStreamAck,
|
||||
portIndex, controller));
|
||||
}
|
||||
|
||||
void PortGroup::processAddStreamAck(PbRpcController *controller)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::processDeleteStreamAck(PbRpcController *controller)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::processModifyStreamAck(int portIndex,
|
||||
PbRpcController *controller)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
qDebug("apply completed");
|
||||
mPorts[portIndex]->when_syncComplete();
|
||||
|
||||
mainWindow->setEnabled(true);
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::modifyPort(int portIndex, OstProto::Port portConfig)
|
||||
{
|
||||
OstProto::PortConfigList *portConfigList = new OstProto::PortConfigList;
|
||||
OstProto::Ack *ack = new OstProto::Ack;
|
||||
|
||||
qDebug("%s: portIndex = %d", __FUNCTION__, portIndex);
|
||||
|
||||
Q_ASSERT(portIndex < mPorts.size());
|
||||
|
||||
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||
mainWindow->setDisabled(true);
|
||||
|
||||
OstProto::Port *port = portConfigList->add_port();
|
||||
port->CopyFrom(portConfig);
|
||||
port->mutable_port_id()->set_id(mPorts[portIndex]->id());
|
||||
|
||||
PbRpcController *controller = new PbRpcController(portConfigList, ack);
|
||||
serviceStub->modifyPort(controller, portConfigList, ack,
|
||||
NewCallback(this, &PortGroup::processModifyPortAck, controller));
|
||||
}
|
||||
|
||||
void PortGroup::processModifyPortAck(PbRpcController *controller)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
if (controller->Failed())
|
||||
{
|
||||
qDebug("%s: rpc failed", __FUNCTION__);
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
{
|
||||
OstProto::PortIdList *portIdList = new OstProto::PortIdList;
|
||||
OstProto::PortConfigList *portConfigList = new OstProto::PortConfigList;
|
||||
PbRpcController *controller2 = new PbRpcController(portIdList,
|
||||
portConfigList);
|
||||
|
||||
OstProto::PortId *portId = portIdList->add_port_id();
|
||||
portId->CopyFrom(static_cast<OstProto::PortConfigList*>
|
||||
(controller->request())->mutable_port(0)->port_id());
|
||||
|
||||
serviceStub->getPortConfig(controller, portIdList, portConfigList,
|
||||
NewCallback(this, &PortGroup::processUpdatedPortConfig,
|
||||
controller2));
|
||||
}
|
||||
_exit:
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::processUpdatedPortConfig(PbRpcController *controller)
|
||||
{
|
||||
OstProto::PortConfigList *portConfigList
|
||||
= static_cast<OstProto::PortConfigList*>(controller->response());
|
||||
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
if (controller->Failed())
|
||||
{
|
||||
qDebug("%s: rpc failed", __FUNCTION__);
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
if (portConfigList->port_size() != 1)
|
||||
qDebug("port size = %d (expected = 1)", portConfigList->port_size());
|
||||
|
||||
for(int i = 0; i < portConfigList->port_size(); i++)
|
||||
{
|
||||
uint id;
|
||||
|
||||
id = portConfigList->port(i).port_id().id();
|
||||
// FIXME: don't mix port id & index into mPorts[]
|
||||
mPorts[id]->updatePortConfig(portConfigList->mutable_port(i));
|
||||
|
||||
emit portGroupDataChanged(mPortGroupId, id);
|
||||
}
|
||||
|
||||
|
||||
_exit:
|
||||
mainWindow->setEnabled(true);
|
||||
QApplication::restoreOverrideCursor();
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::getStreamIdList()
|
||||
{
|
||||
for (int portIndex = 0; portIndex < numPorts(); portIndex++)
|
||||
{
|
||||
OstProto::PortId *portId = new OstProto::PortId;
|
||||
OstProto::StreamIdList *streamIdList = new OstProto::StreamIdList;
|
||||
PbRpcController *controller = new PbRpcController(portId, streamIdList);
|
||||
|
||||
portId->set_id(mPorts[portIndex]->id());
|
||||
|
||||
serviceStub->getStreamIdList(controller, portId, streamIdList,
|
||||
NewCallback(this, &PortGroup::processStreamIdList,
|
||||
portIndex, controller));
|
||||
}
|
||||
}
|
||||
|
||||
void PortGroup::processStreamIdList(int portIndex, PbRpcController *controller)
|
||||
{
|
||||
OstProto::StreamIdList *streamIdList
|
||||
= static_cast<OstProto::StreamIdList*>(controller->response());
|
||||
|
||||
qDebug("In %s (portIndex = %d)", __FUNCTION__, portIndex);
|
||||
|
||||
if (controller->Failed())
|
||||
{
|
||||
qDebug("%s: rpc failed", __FUNCTION__);
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
Q_ASSERT(portIndex < numPorts());
|
||||
|
||||
if (streamIdList->port_id().id() != mPorts[portIndex]->id())
|
||||
{
|
||||
qDebug("Invalid portId %d (expected %d) received for portIndex %d",
|
||||
streamIdList->port_id().id(), mPorts[portIndex]->id(), portIndex);
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
for(int i = 0; i < streamIdList->stream_id_size(); i++)
|
||||
{
|
||||
uint streamId;
|
||||
|
||||
streamId = streamIdList->stream_id(i).id();
|
||||
mPorts[portIndex]->insertStream(streamId);
|
||||
}
|
||||
|
||||
mPorts[portIndex]->when_syncComplete();
|
||||
|
||||
// Are we done for all ports?
|
||||
if (numPorts() && portIndex >= (numPorts()-1))
|
||||
{
|
||||
// FIXME(HI): some way to reset streammodel
|
||||
getStreamConfigList();
|
||||
}
|
||||
|
||||
_exit:
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::getStreamConfigList()
|
||||
{
|
||||
qDebug("requesting stream config list ...");
|
||||
|
||||
for (int portIndex = 0; portIndex < numPorts(); portIndex++)
|
||||
{
|
||||
OstProto::StreamIdList *streamIdList = new OstProto::StreamIdList;
|
||||
OstProto::StreamConfigList *streamConfigList
|
||||
= new OstProto::StreamConfigList;
|
||||
PbRpcController *controller = new PbRpcController(
|
||||
streamIdList, streamConfigList);
|
||||
|
||||
streamIdList->mutable_port_id()->set_id(mPorts[portIndex]->id());
|
||||
for (int j = 0; j < mPorts[portIndex]->numStreams(); j++)
|
||||
{
|
||||
OstProto::StreamId *s = streamIdList->add_stream_id();
|
||||
s->set_id(mPorts[portIndex]->streamByIndex(j)->id());
|
||||
}
|
||||
|
||||
serviceStub->getStreamConfig(controller, streamIdList, streamConfigList,
|
||||
NewCallback(this, &PortGroup::processStreamConfigList,
|
||||
portIndex, controller));
|
||||
}
|
||||
}
|
||||
|
||||
void PortGroup::processStreamConfigList(int portIndex,
|
||||
PbRpcController *controller)
|
||||
{
|
||||
OstProto::StreamConfigList *streamConfigList
|
||||
= static_cast<OstProto::StreamConfigList*>(controller->response());
|
||||
|
||||
qDebug("In %s", __PRETTY_FUNCTION__);
|
||||
|
||||
Q_ASSERT(portIndex < numPorts());
|
||||
|
||||
if (controller->Failed())
|
||||
{
|
||||
qDebug("%s: rpc failed", __FUNCTION__);
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
Q_ASSERT(portIndex < numPorts());
|
||||
|
||||
if (streamConfigList->port_id().id() != mPorts[portIndex]->id())
|
||||
{
|
||||
qDebug("Invalid portId %d (expected %d) received for portIndex %d",
|
||||
streamConfigList->port_id().id(), mPorts[portIndex]->id(), portIndex);
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
for(int i = 0; i < streamConfigList->stream_size(); i++)
|
||||
{
|
||||
uint streamId;
|
||||
|
||||
streamId = streamConfigList->stream(i).stream_id().id();
|
||||
mPorts[portIndex]->updateStream(streamId,
|
||||
streamConfigList->mutable_stream(i));
|
||||
}
|
||||
|
||||
// Are we done for all ports?
|
||||
if (portIndex >= numPorts())
|
||||
{
|
||||
// FIXME(HI): some way to reset streammodel
|
||||
}
|
||||
|
||||
_exit:
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::startTx(QList<uint> *portList)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
if (state() != QAbstractSocket::ConnectedState)
|
||||
goto _exit;
|
||||
|
||||
if (portList == NULL)
|
||||
goto _exit;
|
||||
|
||||
{
|
||||
OstProto::PortIdList *portIdList = new OstProto::PortIdList;
|
||||
OstProto::Ack *ack = new OstProto::Ack;
|
||||
PbRpcController *controller = new PbRpcController(portIdList, ack);
|
||||
|
||||
for (int i = 0; i < portList->size(); i++)
|
||||
{
|
||||
OstProto::PortId *portId = portIdList->add_port_id();
|
||||
portId->set_id(portList->at(i));
|
||||
}
|
||||
|
||||
serviceStub->startTx(controller, portIdList, ack,
|
||||
NewCallback(this, &PortGroup::processStartTxAck, controller));
|
||||
}
|
||||
_exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void PortGroup::processStartTxAck(PbRpcController *controller)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::stopTx(QList<uint> *portList)
|
||||
{
|
||||
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
if (state() != QAbstractSocket::ConnectedState)
|
||||
goto _exit;
|
||||
|
||||
if ((portList == NULL) || (portList->size() == 0))
|
||||
goto _exit;
|
||||
{
|
||||
OstProto::PortIdList *portIdList = new OstProto::PortIdList;
|
||||
OstProto::Ack *ack = new OstProto::Ack;
|
||||
PbRpcController *controller = new PbRpcController(portIdList, ack);
|
||||
|
||||
for (int i = 0; i < portList->size(); i++)
|
||||
{
|
||||
OstProto::PortId *portId = portIdList->add_port_id();
|
||||
portId->set_id(portList->at(i));
|
||||
}
|
||||
|
||||
serviceStub->stopTx(controller, portIdList, ack,
|
||||
NewCallback(this, &PortGroup::processStopTxAck, controller));
|
||||
}
|
||||
_exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void PortGroup::processStopTxAck(PbRpcController *controller)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::startCapture(QList<uint> *portList)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
if (state() != QAbstractSocket::ConnectedState)
|
||||
return;
|
||||
|
||||
if ((portList == NULL) || (portList->size() == 0))
|
||||
goto _exit;
|
||||
|
||||
{
|
||||
OstProto::PortIdList *portIdList = new OstProto::PortIdList;
|
||||
OstProto::Ack *ack = new OstProto::Ack;
|
||||
PbRpcController *controller = new PbRpcController(portIdList, ack);
|
||||
|
||||
for (int i = 0; i < portList->size(); i++)
|
||||
{
|
||||
OstProto::PortId *portId = portIdList->add_port_id();
|
||||
portId->set_id(portList->at(i));
|
||||
}
|
||||
|
||||
serviceStub->startCapture(controller, portIdList, ack,
|
||||
NewCallback(this, &PortGroup::processStartCaptureAck, controller));
|
||||
}
|
||||
_exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void PortGroup::processStartCaptureAck(PbRpcController *controller)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::stopCapture(QList<uint> *portList)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
if (state() != QAbstractSocket::ConnectedState)
|
||||
return;
|
||||
|
||||
if ((portList == NULL) || (portList->size() == 0))
|
||||
goto _exit;
|
||||
|
||||
{
|
||||
OstProto::PortIdList *portIdList = new OstProto::PortIdList;
|
||||
OstProto::Ack *ack = new OstProto::Ack;
|
||||
PbRpcController *controller = new PbRpcController(portIdList, ack);
|
||||
|
||||
for (int i = 0; i < portList->size(); i++)
|
||||
{
|
||||
OstProto::PortId *portId = portIdList->add_port_id();
|
||||
portId->set_id(portList->at(i));
|
||||
}
|
||||
|
||||
serviceStub->stopCapture(controller, portIdList, ack,
|
||||
NewCallback(this, &PortGroup::processStopCaptureAck, controller));
|
||||
}
|
||||
_exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void PortGroup::processStopCaptureAck(PbRpcController *controller)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::viewCapture(QList<uint> *portList)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
if (state() != QAbstractSocket::ConnectedState)
|
||||
goto _exit;
|
||||
|
||||
if ((portList == NULL) || (portList->size() != 1))
|
||||
goto _exit;
|
||||
|
||||
|
||||
for (int i = 0; i < portList->size(); i++)
|
||||
{
|
||||
OstProto::PortId *portId = new OstProto::PortId;
|
||||
OstProto::CaptureBuffer *buf = new OstProto::CaptureBuffer;
|
||||
PbRpcController *controller = new PbRpcController(portId, buf);
|
||||
QFile *capFile = mPorts[portList->at(i)]->getCaptureFile();
|
||||
|
||||
portId->set_id(portList->at(i));
|
||||
|
||||
capFile->open(QIODevice::ReadWrite|QIODevice::Truncate);
|
||||
qDebug("Temp CapFile = %s", capFile->fileName().toAscii().constData());
|
||||
controller->setBinaryBlob(capFile);
|
||||
|
||||
serviceStub->getCaptureBuffer(controller, portId, buf,
|
||||
NewCallback(this, &PortGroup::processViewCaptureAck, controller));
|
||||
}
|
||||
_exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void PortGroup::processViewCaptureAck(PbRpcController *controller)
|
||||
{
|
||||
QFile *capFile = static_cast<QFile*>(controller->binaryBlob());
|
||||
|
||||
QString viewer = appSettings->value(kWiresharkPathKey,
|
||||
kWiresharkPathDefaultValue).toString();
|
||||
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
capFile->flush();
|
||||
capFile->close();
|
||||
|
||||
if (!QFile::exists(viewer))
|
||||
{
|
||||
QMessageBox::warning(NULL, "Can't find Wireshark",
|
||||
viewer + QString(" does not exist!\n\nPlease correct the path"
|
||||
" to Wireshark in the Preferences."));
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
if (!QProcess::startDetached(viewer, QStringList() << capFile->fileName()))
|
||||
qDebug("Failed starting Wireshark");
|
||||
|
||||
_exit:
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void PortGroup::getPortStats()
|
||||
{
|
||||
//qDebug("In %s", __FUNCTION__);
|
||||
|
||||
if (state() != QAbstractSocket::ConnectedState)
|
||||
goto _exit;
|
||||
|
||||
if (numPorts() <= 0)
|
||||
goto _exit;
|
||||
|
||||
if (isGetStatsPending_)
|
||||
goto _exit;
|
||||
|
||||
statsController->Reset();
|
||||
isGetStatsPending_ = true;
|
||||
serviceStub->getStats(statsController,
|
||||
static_cast<OstProto::PortIdList*>(statsController->request()),
|
||||
static_cast<OstProto::PortStatsList*>(statsController->response()),
|
||||
NewCallback(this, &PortGroup::processPortStatsList));
|
||||
|
||||
_exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void PortGroup::processPortStatsList()
|
||||
{
|
||||
//qDebug("In %s", __FUNCTION__);
|
||||
|
||||
if (statsController->Failed())
|
||||
{
|
||||
qDebug("%s: rpc failed", __FUNCTION__);
|
||||
goto _error_exit;
|
||||
}
|
||||
|
||||
for(int i = 0; i < portStatsList_->port_stats_size(); i++)
|
||||
{
|
||||
uint id = portStatsList_->port_stats(i).port_id().id();
|
||||
// FIXME: don't mix port id & index into mPorts[]
|
||||
mPorts[id]->updateStats(portStatsList_->mutable_port_stats(i));
|
||||
}
|
||||
|
||||
emit statsChanged(mPortGroupId);
|
||||
|
||||
_error_exit:
|
||||
isGetStatsPending_ = false;
|
||||
}
|
||||
|
||||
void PortGroup::clearPortStats(QList<uint> *portList)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
if (state() != QAbstractSocket::ConnectedState)
|
||||
goto _exit;
|
||||
|
||||
{
|
||||
OstProto::PortIdList *portIdList = new OstProto::PortIdList;
|
||||
OstProto::Ack *ack = new OstProto::Ack;
|
||||
PbRpcController *controller = new PbRpcController(portIdList, ack);
|
||||
|
||||
if (portList == NULL)
|
||||
portIdList->CopyFrom(*portIdList_);
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < portList->size(); i++)
|
||||
{
|
||||
OstProto::PortId *portId = portIdList->add_port_id();
|
||||
portId->set_id(portList->at(i));
|
||||
}
|
||||
}
|
||||
|
||||
serviceStub->clearStats(controller, portIdList, ack,
|
||||
NewCallback(this, &PortGroup::processClearStatsAck, controller));
|
||||
}
|
||||
_exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void PortGroup::processClearStatsAck(PbRpcController *controller)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
// Refresh stats immediately after a stats clear/reset
|
||||
getPortStats();
|
||||
|
||||
delete controller;
|
||||
}
|
||||
|
145
client/portgroup.h
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
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 _PORT_GROUP_H
|
||||
#define _PORT_GROUP_H
|
||||
|
||||
#include "port.h"
|
||||
#include <QHostAddress>
|
||||
#include <QTcpSocket>
|
||||
|
||||
#include "../common/protocol.pb.h"
|
||||
#include "pbrpcchannel.h"
|
||||
|
||||
/* TODO
|
||||
HIGH
|
||||
MED
|
||||
LOW
|
||||
- Allow hostnames in addition to IP Address as "server address"
|
||||
*/
|
||||
|
||||
#define DEFAULT_SERVER_PORT 7878
|
||||
|
||||
class QFile;
|
||||
class QTimer;
|
||||
|
||||
class PortGroup : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
static quint32 mPortGroupAllocId;
|
||||
quint32 mPortGroupId;
|
||||
QString mUserAlias; // user defined
|
||||
|
||||
bool reconnect;
|
||||
int reconnectAfter; // time in milliseconds
|
||||
static const int kMinReconnectWaitTime = 2000; // ms
|
||||
static const int kMaxReconnectWaitTime = 60000; // ms
|
||||
QTimer *reconnectTimer;
|
||||
PbRpcChannel *rpcChannel;
|
||||
PbRpcController *statsController;
|
||||
bool isGetStatsPending_;
|
||||
|
||||
OstProto::OstService::Stub *serviceStub;
|
||||
|
||||
OstProto::PortIdList *portIdList_;
|
||||
OstProto::PortStatsList *portStatsList_;
|
||||
|
||||
public: // FIXME(HIGH): member access
|
||||
QList<Port*> mPorts;
|
||||
|
||||
public:
|
||||
PortGroup(QHostAddress ip = QHostAddress::LocalHost,
|
||||
quint16 port = DEFAULT_SERVER_PORT);
|
||||
~PortGroup();
|
||||
|
||||
void connectToHost() { reconnect = true; rpcChannel->establish(); }
|
||||
void connectToHost(QHostAddress ip, quint16 port)
|
||||
{ reconnect = true; rpcChannel->establish(ip, port); }
|
||||
void disconnectFromHost() { reconnect = false; rpcChannel->tearDown(); }
|
||||
|
||||
int numPorts() const { return mPorts.size(); }
|
||||
quint32 id() const { return mPortGroupId; }
|
||||
|
||||
const QString& userAlias() const { return mUserAlias; }
|
||||
void setUserAlias(QString alias) { mUserAlias = alias; };
|
||||
|
||||
const QHostAddress& serverAddress() const
|
||||
{ return rpcChannel->serverAddress(); }
|
||||
quint16 serverPort() const
|
||||
{ return rpcChannel->serverPort(); }
|
||||
QAbstractSocket::SocketState state() const
|
||||
{ return rpcChannel->state(); }
|
||||
|
||||
void processPortIdList(PbRpcController *controller);
|
||||
void processPortConfigList(PbRpcController *controller);
|
||||
|
||||
void processAddStreamAck(PbRpcController *controller);
|
||||
void processDeleteStreamAck(PbRpcController *controller);
|
||||
void processModifyStreamAck(int portIndex, PbRpcController *controller);
|
||||
|
||||
void modifyPort(int portId, OstProto::Port portConfig);
|
||||
void processModifyPortAck(PbRpcController *controller);
|
||||
void processUpdatedPortConfig(PbRpcController *controller);
|
||||
|
||||
void getStreamIdList();
|
||||
void processStreamIdList(int portIndex, PbRpcController *controller);
|
||||
void getStreamConfigList();
|
||||
void processStreamConfigList(int portIndex, PbRpcController *controller);
|
||||
|
||||
void processModifyStreamAck(OstProto::Ack *ack);
|
||||
|
||||
void startTx(QList<uint> *portList = NULL);
|
||||
void processStartTxAck(PbRpcController *controller);
|
||||
void stopTx(QList<uint> *portList = NULL);
|
||||
void processStopTxAck(PbRpcController *controller);
|
||||
|
||||
void startCapture(QList<uint> *portList = NULL);
|
||||
void processStartCaptureAck(PbRpcController *controller);
|
||||
void stopCapture(QList<uint> *portList = NULL);
|
||||
void processStopCaptureAck(PbRpcController *controller);
|
||||
void viewCapture(QList<uint> *portList = NULL);
|
||||
void processViewCaptureAck(PbRpcController *controller);
|
||||
|
||||
void getPortStats();
|
||||
void processPortStatsList();
|
||||
void clearPortStats(QList<uint> *portList = NULL);
|
||||
void processClearStatsAck(PbRpcController *controller);
|
||||
|
||||
signals:
|
||||
void portGroupDataChanged(int portGroupId, int portId = 0xFFFF);
|
||||
void portListAboutToBeChanged(quint32 portGroupId);
|
||||
void portListChanged(quint32 portGroupId);
|
||||
void statsChanged(quint32 portGroupId);
|
||||
|
||||
private slots:
|
||||
void on_reconnectTimer_timeout();
|
||||
void on_rpcChannel_stateChanged(QAbstractSocket::SocketState state);
|
||||
void on_rpcChannel_connected();
|
||||
void on_rpcChannel_disconnected();
|
||||
void on_rpcChannel_error(QAbstractSocket::SocketError socketError);
|
||||
|
||||
void when_portListChanged(quint32 portGroupId);
|
||||
|
||||
public slots:
|
||||
void when_configApply(int portIndex);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
133
client/portgrouplist.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
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 "portgrouplist.h"
|
||||
|
||||
// TODO(LOW): Remove
|
||||
#include <modeltest.h>
|
||||
|
||||
PortGroupList::PortGroupList()
|
||||
: mPortGroupListModel(this),
|
||||
mStreamListModel(this),
|
||||
mPortStatsModel(this, this)
|
||||
{
|
||||
PortGroup *pg;
|
||||
|
||||
#ifdef QT_NO_DEBUG
|
||||
streamModelTester_ = NULL;
|
||||
portModelTester_ = NULL;
|
||||
portStatsModelTester_ = NULL;
|
||||
#else
|
||||
streamModelTester_ = new ModelTest(getStreamModel());
|
||||
portModelTester_ = new ModelTest(getPortModel());
|
||||
portStatsModelTester_ = new ModelTest(getPortStatsModel());
|
||||
#endif
|
||||
|
||||
// Add the "Local" Port Group
|
||||
pg = new PortGroup;
|
||||
addPortGroup(*pg);
|
||||
}
|
||||
|
||||
PortGroupList::~PortGroupList()
|
||||
{
|
||||
delete portStatsModelTester_;
|
||||
delete portModelTester_;
|
||||
delete streamModelTester_;
|
||||
|
||||
while (!mPortGroups.isEmpty())
|
||||
delete mPortGroups.takeFirst();
|
||||
|
||||
}
|
||||
|
||||
bool PortGroupList::isPortGroup(const QModelIndex& index)
|
||||
{
|
||||
return mPortGroupListModel.isPortGroup(index);
|
||||
}
|
||||
|
||||
bool PortGroupList::isPort(const QModelIndex& index)
|
||||
{
|
||||
return mPortGroupListModel.isPort(index);
|
||||
}
|
||||
|
||||
PortGroup& PortGroupList::portGroup(const QModelIndex& index)
|
||||
{
|
||||
Q_ASSERT(mPortGroupListModel.isPortGroup(index));
|
||||
|
||||
return *(mPortGroups[index.row()]);
|
||||
}
|
||||
|
||||
Port& PortGroupList::port(const QModelIndex& index)
|
||||
{
|
||||
Q_ASSERT(mPortGroupListModel.isPort(index));
|
||||
return (*mPortGroups.at(index.parent().row())->mPorts[index.row()]);
|
||||
}
|
||||
|
||||
void PortGroupList::addPortGroup(PortGroup &portGroup)
|
||||
{
|
||||
mPortGroupListModel.portGroupAboutToBeAppended();
|
||||
|
||||
connect(&portGroup, SIGNAL(portGroupDataChanged(int, int)),
|
||||
&mPortGroupListModel, SLOT(when_portGroupDataChanged(int, int)));
|
||||
#if 0
|
||||
connect(&portGroup, SIGNAL(portListAboutToBeChanged(quint32)),
|
||||
&mPortGroupListModel, SLOT(triggerLayoutAboutToBeChanged()));
|
||||
connect(&portGroup, SIGNAL(portListChanged(quint32)),
|
||||
&mPortGroupListModel, SLOT(triggerLayoutChanged()));
|
||||
#endif
|
||||
connect(&portGroup, SIGNAL(portListChanged(quint32)),
|
||||
&mPortGroupListModel, SLOT(when_portListChanged()));
|
||||
|
||||
connect(&portGroup, SIGNAL(portListChanged(quint32)),
|
||||
&mPortStatsModel, SLOT(when_portListChanged()));
|
||||
|
||||
connect(&portGroup, SIGNAL(statsChanged(quint32)),
|
||||
&mPortStatsModel, SLOT(when_portGroup_stats_update(quint32)));
|
||||
|
||||
mPortGroups.append(&portGroup);
|
||||
portGroup.connectToHost();
|
||||
|
||||
mPortGroupListModel.portGroupAppended();
|
||||
|
||||
mPortStatsModel.when_portListChanged();
|
||||
}
|
||||
|
||||
void PortGroupList::removePortGroup(PortGroup &portGroup)
|
||||
{
|
||||
mPortGroupListModel.portGroupAboutToBeRemoved(&portGroup);
|
||||
|
||||
PortGroup* pg = mPortGroups.takeAt(mPortGroups.indexOf(&portGroup));
|
||||
qDebug("after takeAt()");
|
||||
mPortGroupListModel.portGroupRemoved();
|
||||
|
||||
delete pg;
|
||||
|
||||
mPortStatsModel.when_portListChanged();
|
||||
}
|
||||
|
||||
//....................
|
||||
// Private Methods
|
||||
//....................
|
||||
int PortGroupList::indexOfPortGroup(quint32 portGroupId)
|
||||
{
|
||||
for (int i = 0; i < mPortGroups.size(); i++) {
|
||||
if (mPortGroups.value(i)->id() == portGroupId)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
75
client/portgrouplist.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
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 _PORT_GROUP_LIST_H
|
||||
#define _PORT_GROUP_LIST_H
|
||||
|
||||
#include "portgroup.h"
|
||||
#include <QAbstractItemModel>
|
||||
#include <QItemSelection>
|
||||
#include "portmodel.h"
|
||||
#include "streammodel.h"
|
||||
#include "portstatsmodel.h"
|
||||
|
||||
class PortModel;
|
||||
class StreamModel;
|
||||
|
||||
class PortGroupList : public QObject {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
friend class PortModel;
|
||||
friend class StreamModel;
|
||||
friend class PortStatsModel;
|
||||
|
||||
QList<PortGroup*> mPortGroups;
|
||||
PortModel mPortGroupListModel;
|
||||
StreamModel mStreamListModel;
|
||||
PortStatsModel mPortStatsModel;
|
||||
|
||||
QObject *streamModelTester_;
|
||||
QObject *portModelTester_;
|
||||
QObject *portStatsModelTester_;
|
||||
|
||||
// Methods
|
||||
public:
|
||||
PortGroupList();
|
||||
~PortGroupList();
|
||||
|
||||
PortModel* getPortModel() { return &mPortGroupListModel; }
|
||||
PortStatsModel* getPortStatsModel() { return &mPortStatsModel; }
|
||||
StreamModel* getStreamModel() { return &mStreamListModel; }
|
||||
|
||||
bool isPortGroup(const QModelIndex& index);
|
||||
bool isPort(const QModelIndex& index);
|
||||
PortGroup& portGroup(const QModelIndex& index);
|
||||
Port& port(const QModelIndex& index);
|
||||
|
||||
int numPortGroups() { return mPortGroups.size(); }
|
||||
PortGroup& portGroupByIndex(int index) { return *(mPortGroups[index]); }
|
||||
|
||||
void addPortGroup(PortGroup &portGroup);
|
||||
void removePortGroup(PortGroup &portGroup);
|
||||
|
||||
private:
|
||||
int indexOfPortGroup(quint32 portGroupId);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
339
client/portmodel.cpp
Normal file
@ -0,0 +1,339 @@
|
||||
/*
|
||||
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 "portmodel.h"
|
||||
#include "portgrouplist.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QPainter>
|
||||
|
||||
#if 0
|
||||
#define DBG0(x) qDebug(x)
|
||||
#define DBG1(x, p1) qDebug(x, (p1))
|
||||
#else
|
||||
#define DBG0(x) {}
|
||||
#define DBG1(x, p1) {}
|
||||
#endif
|
||||
|
||||
PortModel::PortModel(PortGroupList *p, QObject *parent)
|
||||
: QAbstractItemModel(parent)
|
||||
{
|
||||
pgl = p;
|
||||
|
||||
portIconFactory[OstProto::LinkStateUnknown][false] =
|
||||
QIcon(":/icons/bullet_white.png");
|
||||
portIconFactory[OstProto::LinkStateDown][false] =
|
||||
QIcon(":/icons/bullet_red.png");
|
||||
portIconFactory[OstProto::LinkStateUp][false] =
|
||||
QIcon(":/icons/bullet_green.png");
|
||||
|
||||
for (int linkState = 0; linkState < kLinkStatesCount; linkState++)
|
||||
{
|
||||
QPixmap pixmap(":/icons/deco_exclusive.png");
|
||||
QPainter painter(&pixmap);
|
||||
QIcon icon = portIconFactory[linkState][false];
|
||||
|
||||
painter.drawPixmap(0, 0, icon.pixmap(QSize(32,32)));
|
||||
portIconFactory[linkState][true] = QIcon(pixmap);
|
||||
}
|
||||
}
|
||||
|
||||
int PortModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
// qDebug("RowCount Enter\n");
|
||||
if (!parent.isValid())
|
||||
{
|
||||
// Top Level Item
|
||||
//qDebug("RowCount (Top) Exit: %d\n", pgl->mPortGroups.size());
|
||||
return pgl->mPortGroups.size();
|
||||
}
|
||||
// qDebug("RowCount non top %d, %d, %llx\n",
|
||||
// parent.row(), parent.column(), parent.internalId());
|
||||
|
||||
quint16 pg = (parent.internalId() >> 16) & 0xFFFF;
|
||||
quint16 p = parent.internalId() & 0xFFFF;
|
||||
if (p == 0xFFFF)
|
||||
{
|
||||
#if 0 // wrong code?
|
||||
int count = 0;
|
||||
foreach(PortGroup *pg, pgl->mPortGroups)
|
||||
{
|
||||
count += pg->numPorts();
|
||||
}
|
||||
//qDebug("RowCount (Mid) Exit: %d\n", count);
|
||||
return count;
|
||||
#endif
|
||||
if (parent.column() == 0)
|
||||
return pgl->mPortGroups.value(pgl->indexOfPortGroup(pg))->numPorts();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Leaf Item
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int PortModel::columnCount(const QModelIndex &/*parent*/) const
|
||||
{
|
||||
return 1; // FIXME: hardcoding
|
||||
}
|
||||
|
||||
Qt::ItemFlags PortModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
return QAbstractItemModel::flags(index); // FIXME: no need for this func
|
||||
}
|
||||
QVariant PortModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
|
||||
DBG0("Enter PortModel data\n");
|
||||
|
||||
// Check for a valid index
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
DBG1("PortModel::data(index).row = %d", index.row());
|
||||
DBG1("PortModel::data(index).column = %0d", index.column());
|
||||
DBG1("PortModel::data(index).internalId = %08llx", index.internalId());
|
||||
|
||||
QModelIndex parent = index.parent();
|
||||
|
||||
if (!parent.isValid())
|
||||
{
|
||||
// Top Level Item - PortGroup
|
||||
if ((role == Qt::DisplayRole))
|
||||
{
|
||||
DBG0("Exit PortModel data 1\n");
|
||||
return QString("Port Group %1: %2 [%3:%4] (%5)").
|
||||
arg(pgl->mPortGroups.at(index.row())->id()).
|
||||
arg(pgl->mPortGroups.at(index.row())->userAlias()).
|
||||
arg(pgl->mPortGroups.at(index.row())->serverAddress().toString()).
|
||||
arg(pgl->mPortGroups.at(index.row())->serverPort()).
|
||||
arg(pgl->mPortGroups.value(index.row())->numPorts());
|
||||
}
|
||||
else if ((role == Qt::DecorationRole))
|
||||
{
|
||||
DBG0("Exit PortModel data 2\n");
|
||||
switch(pgl->mPortGroups.at(index.row())->state())
|
||||
{
|
||||
case QAbstractSocket::UnconnectedState:
|
||||
return QIcon(":/icons/bullet_red.png");
|
||||
|
||||
case QAbstractSocket::HostLookupState:
|
||||
return QIcon(":/icons/bullet_yellow.png");
|
||||
|
||||
case QAbstractSocket::ConnectingState:
|
||||
case QAbstractSocket::ClosingState:
|
||||
return QIcon(":/icons/bullet_orange.png");
|
||||
|
||||
case QAbstractSocket::ConnectedState:
|
||||
return QIcon(":/icons/bullet_green.png");
|
||||
|
||||
|
||||
case QAbstractSocket::BoundState:
|
||||
case QAbstractSocket::ListeningState:
|
||||
default:
|
||||
return QIcon(":/icons/bullet_error.png");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG0("Exit PortModel data 3\n");
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pgl->mPortGroups.at(parent.row())->numPorts() == 0)
|
||||
{
|
||||
DBG0("Exit PortModel data 4\n");
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
Port *port = pgl->mPortGroups.at(parent.row())->mPorts[index.row()];
|
||||
|
||||
// Non Top Level - Port
|
||||
if ((role == Qt::DisplayRole))
|
||||
{
|
||||
// FIXME(LOW) - IP Address below
|
||||
return QString("Port %1: %2 [%3] (%4)")
|
||||
.arg(port->id())
|
||||
.arg(port->name())
|
||||
.arg(QHostAddress("0.0.0.0").toString())
|
||||
.arg(port->description());
|
||||
}
|
||||
else if ((role == Qt::DecorationRole))
|
||||
{
|
||||
return portIconFactory[port->linkState()][port->hasExclusiveControl()];
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG0("Exit PortModel data 6\n");
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant PortModel::headerData(int /*section*/, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
if (orientation == Qt::Horizontal)
|
||||
return QVariant();
|
||||
else
|
||||
return QString("Name");
|
||||
}
|
||||
|
||||
QModelIndex PortModel::index (int row, int col,
|
||||
const QModelIndex & parent) const
|
||||
{
|
||||
if (!hasIndex(row, col, parent))
|
||||
return QModelIndex();
|
||||
|
||||
//qDebug("index: R=%d, C=%d, PR=%d, PC=%d, PID=%llx\n",
|
||||
// row, col, parent.row(), parent.column(), parent.internalId());
|
||||
|
||||
if (!parent.isValid())
|
||||
{
|
||||
// Top Level Item
|
||||
quint16 pg = pgl->mPortGroups.value(row)->id(), p = 0xFFFF;
|
||||
quint32 id = (pg << 16) | p;
|
||||
//qDebug("index (top) dbg: PG=%d, P=%d, ID=%x\n", pg, p, id);
|
||||
|
||||
return createIndex(row, col, id);
|
||||
}
|
||||
else
|
||||
{
|
||||
quint16 pg = parent.internalId() >> 16;
|
||||
quint16 p = pgl->mPortGroups.value(parent.row())->mPorts.value(row)->id();
|
||||
quint32 id = (pg << 16) | p;
|
||||
//qDebug("index (nontop) dbg: PG=%d, P=%d, ID=%x\n", pg, p, id);
|
||||
|
||||
return createIndex(row, col, id);
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex PortModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QModelIndex();
|
||||
|
||||
//qDebug("parent: R=%d, C=%d ID=%llx\n",
|
||||
// index.row(), index.column(), index.internalId());
|
||||
|
||||
quint16 pg = index.internalId() >> 16;
|
||||
quint16 p = index.internalId() & 0x0000FFFF;
|
||||
|
||||
//qDebug("parent dbg: PG=%d, P=%d\n", pg, p);
|
||||
|
||||
if (p == 0xFFFF)
|
||||
{
|
||||
//qDebug("parent ret: NULL\n");
|
||||
// Top Level Item - PG
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
quint32 id = (pg << 16) | 0xFFFF;
|
||||
//qDebug("parent ret: R=%d, C=%d, ID=%x\n", pg, 0, id);
|
||||
|
||||
return createIndex(pgl->indexOfPortGroup(pg), 0, id);
|
||||
|
||||
}
|
||||
|
||||
bool PortModel::isPortGroup(const QModelIndex& index)
|
||||
{
|
||||
if (index.isValid() && ((index.internalId() & 0xFFFF) == 0xFFFF))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PortModel::isPort(const QModelIndex& index)
|
||||
{
|
||||
if (index.isValid() && ((index.internalId() & 0xFFFF) != 0xFFFF))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
quint32 PortModel::portGroupId(const QModelIndex& index)
|
||||
{
|
||||
return (index.internalId()) >> 16 & 0xFFFF;
|
||||
}
|
||||
|
||||
quint32 PortModel::portId(const QModelIndex& index)
|
||||
{
|
||||
return (index.internalId()) & 0xFFFF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------
|
||||
// Slots
|
||||
// ----------------------------------------------
|
||||
void PortModel::when_portGroupDataChanged(int portGroupId, int portId)
|
||||
{
|
||||
QModelIndex index;
|
||||
int row;
|
||||
|
||||
qDebug("portGroupId = %d, portId = %d", portGroupId, portId);
|
||||
if (portId == 0xFFFF)
|
||||
row = pgl->indexOfPortGroup(portGroupId);
|
||||
else
|
||||
row = portId;
|
||||
|
||||
index = createIndex(row, 0, (portGroupId << 16) | portId);
|
||||
|
||||
emit dataChanged(index, index);
|
||||
}
|
||||
|
||||
void PortModel::portGroupAboutToBeAppended()
|
||||
{
|
||||
int row;
|
||||
|
||||
row = pgl->mPortGroups.size();
|
||||
beginInsertRows(QModelIndex(), row, row);
|
||||
}
|
||||
|
||||
void PortModel::portGroupAppended()
|
||||
{
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
void PortModel::portGroupAboutToBeRemoved(PortGroup *portGroup)
|
||||
{
|
||||
int row;
|
||||
|
||||
row = pgl->mPortGroups.indexOf(portGroup);
|
||||
beginRemoveRows(QModelIndex(), row, row);
|
||||
}
|
||||
|
||||
void PortModel::portGroupRemoved()
|
||||
{
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
void PortModel::when_portListChanged()
|
||||
{
|
||||
reset();
|
||||
}
|
75
client/portmodel.h
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
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 _PORT_MODEL_H
|
||||
#define _PORT_MODEL_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QIcon>
|
||||
|
||||
class PortGroupList;
|
||||
class PortGroup;
|
||||
|
||||
class PortModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
friend class PortGroupList;
|
||||
|
||||
public:
|
||||
PortModel(PortGroupList *p, QObject *parent = 0);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
QModelIndex index (int row, int col,
|
||||
const QModelIndex &parent = QModelIndex()) const;
|
||||
QModelIndex parent(const QModelIndex &index) const;
|
||||
|
||||
bool isPortGroup(const QModelIndex& index);
|
||||
bool isPort(const QModelIndex& index);
|
||||
quint32 portGroupId(const QModelIndex& index);
|
||||
quint32 portId(const QModelIndex& index);
|
||||
|
||||
private:
|
||||
PortGroupList *pgl;
|
||||
static const int kLinkStatesCount = 3;
|
||||
static const int kExclusiveStatesCount = 2;
|
||||
QIcon portIconFactory[kLinkStatesCount][kExclusiveStatesCount];
|
||||
|
||||
private slots:
|
||||
void when_portGroupDataChanged(int portGroupId, int portId);
|
||||
|
||||
void portGroupAboutToBeAppended();
|
||||
void portGroupAppended();
|
||||
void portGroupAboutToBeRemoved(PortGroup *portGroup);
|
||||
void portGroupRemoved();
|
||||
|
||||
void when_portListChanged();
|
||||
|
||||
#if 0
|
||||
void triggerLayoutAboutToBeChanged();
|
||||
void triggerLayoutChanged();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
170
client/portstatsfilter.ui
Normal file
@ -0,0 +1,170 @@
|
||||
<ui version="4.0" >
|
||||
<class>PortStatsFilterDialog</class>
|
||||
<widget class="QDialog" name="PortStatsFilterDialog" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>319</width>
|
||||
<height>193</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Select Ports</string>
|
||||
</property>
|
||||
<property name="windowIcon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/portstats_filter.png</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QListView" name="lvUnselected" >
|
||||
<property name="acceptDrops" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="dragEnabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="dragDropMode" >
|
||||
<enum>QAbstractItemView::NoDragDrop</enum>
|
||||
</property>
|
||||
<property name="selectionMode" >
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="movement" >
|
||||
<enum>QListView::Static</enum>
|
||||
</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>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="tbSelectIn" >
|
||||
<property name="text" >
|
||||
<string>></string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/arrow_right.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="tbSelectOut" >
|
||||
<property name="text" >
|
||||
<string><</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/arrow_left.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="lvSelected" >
|
||||
<property name="acceptDrops" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragEnabled" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="dragDropOverwriteMode" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="dragDropMode" >
|
||||
<enum>QAbstractItemView::InternalMove</enum>
|
||||
</property>
|
||||
<property name="selectionMode" >
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="movement" >
|
||||
<enum>QListView::Free</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</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>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>lvUnselected</tabstop>
|
||||
<tabstop>tbSelectIn</tabstop>
|
||||
<tabstop>tbSelectOut</tabstop>
|
||||
<tabstop>lvSelected</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="ostinato.qrc" />
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>PortStatsFilterDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>PortStatsFilterDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
131
client/portstatsfilterdialog.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
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 "portstatsfilterdialog.h"
|
||||
|
||||
PortStatsFilterDialog::PortStatsFilterDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
mUnselected.setSortRole(PositionRole);
|
||||
|
||||
lvUnselected->setModel(&mUnselected);
|
||||
lvSelected->setModel(&mSelected);
|
||||
}
|
||||
|
||||
QList<uint> PortStatsFilterDialog::getItemList(bool* ok,
|
||||
QAbstractItemModel *model, Qt::Orientation orientation,
|
||||
QList<uint> initial)
|
||||
{
|
||||
QList<uint> ret;
|
||||
|
||||
uint count = (orientation == Qt::Vertical) ?
|
||||
model->rowCount() : model->columnCount();
|
||||
|
||||
*ok = false;
|
||||
|
||||
mUnselected.clear();
|
||||
mSelected.clear();
|
||||
|
||||
for (uint i = 0; i < count; i++)
|
||||
{
|
||||
QStandardItem *item;
|
||||
|
||||
item = new QStandardItem(model->headerData(i, orientation).toString());
|
||||
item->setData(i, PositionRole);
|
||||
item->setFlags(Qt::ItemIsSelectable
|
||||
| Qt::ItemIsDragEnabled
|
||||
//| Qt::ItemIsDropEnabled
|
||||
| Qt::ItemIsEnabled);
|
||||
|
||||
if (initial.contains(i))
|
||||
mSelected.appendRow(item);
|
||||
else
|
||||
mUnselected.appendRow(item);
|
||||
}
|
||||
|
||||
// No need to sort right now 'coz we have inserted items in order
|
||||
|
||||
if (exec() == QDialog::Accepted)
|
||||
{
|
||||
uint count = mSelected.rowCount();
|
||||
for (uint i = 0; i < count; i++)
|
||||
{
|
||||
QModelIndex index = mSelected.index(i, 0, QModelIndex());
|
||||
QStandardItem *item = mSelected.itemFromIndex(index);
|
||||
ret.append(item->data(PositionRole).toInt());
|
||||
}
|
||||
*ok = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void PortStatsFilterDialog::on_tbSelectIn_clicked()
|
||||
{
|
||||
QList<int> rows;
|
||||
|
||||
foreach(QModelIndex idx, lvUnselected->selectionModel()->selectedIndexes())
|
||||
rows.append(idx.row());
|
||||
qSort(rows.begin(), rows.end(), qGreater<int>());
|
||||
|
||||
QModelIndex idx = lvSelected->selectionModel()->currentIndex();
|
||||
int insertAt = idx.isValid() ? idx.row() : mSelected.rowCount();
|
||||
|
||||
foreach(int row, rows)
|
||||
{
|
||||
QList<QStandardItem*> items = mUnselected.takeRow(row);
|
||||
mSelected.insertRow(insertAt, items);
|
||||
}
|
||||
}
|
||||
|
||||
void PortStatsFilterDialog::on_tbSelectOut_clicked()
|
||||
{
|
||||
QList<int> rows;
|
||||
|
||||
foreach(QModelIndex idx, lvSelected->selectionModel()->selectedIndexes())
|
||||
rows.append(idx.row());
|
||||
qSort(rows.begin(), rows.end(), qGreater<int>());
|
||||
|
||||
foreach(int row, rows)
|
||||
{
|
||||
QList<QStandardItem*> items = mSelected.takeRow(row);
|
||||
mUnselected.appendRow(items);
|
||||
}
|
||||
|
||||
mUnselected.sort(0);
|
||||
}
|
||||
|
||||
void PortStatsFilterDialog::on_lvUnselected_doubleClicked(const QModelIndex &index)
|
||||
{
|
||||
QList<QStandardItem*> items = mUnselected.takeRow(index.row());
|
||||
QModelIndex idx = lvSelected->selectionModel()->currentIndex();
|
||||
int insertAt = idx.isValid() ? idx.row() : mSelected.rowCount();
|
||||
|
||||
mSelected.insertRow(insertAt, items);
|
||||
}
|
||||
|
||||
void PortStatsFilterDialog::on_lvSelected_doubleClicked(const QModelIndex &index)
|
||||
{
|
||||
QList<QStandardItem*> items = mSelected.takeRow(index.row());
|
||||
mUnselected.appendRow(items);
|
||||
mUnselected.sort(0);
|
||||
}
|
||||
|
54
client/portstatsfilterdialog.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
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 _PORT_STATS_FILTER_DIALOG_H
|
||||
#define _PORT_STATS_FILTER_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QStandardItemModel>
|
||||
#include "ui_portstatsfilter.h"
|
||||
#include "portgrouplist.h"
|
||||
|
||||
class PortStatsFilterDialog : public QDialog, public Ui::PortStatsFilterDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PortStatsFilterDialog(QWidget *parent = 0);
|
||||
QList<uint> getItemList(bool* ok, QAbstractItemModel *model,
|
||||
Qt::Orientation orientation = Qt::Vertical,
|
||||
QList<uint> initial = QList<uint>());
|
||||
|
||||
private:
|
||||
enum ItemRole {
|
||||
PositionRole = Qt::UserRole + 1
|
||||
};
|
||||
QStandardItemModel mUnselected;
|
||||
QStandardItemModel mSelected;
|
||||
|
||||
private slots:
|
||||
void on_tbSelectIn_clicked();
|
||||
void on_tbSelectOut_clicked();
|
||||
void on_lvUnselected_doubleClicked(const QModelIndex &index);
|
||||
void on_lvSelected_doubleClicked(const QModelIndex &index);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
320
client/portstatsmodel.cpp
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
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 "portstatsmodel.h"
|
||||
#include "portgrouplist.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
PortStatsModel::PortStatsModel(PortGroupList *p, QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
pgl = p;
|
||||
|
||||
timer = new QTimer();
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(updateStats()));
|
||||
timer->start(1000);
|
||||
}
|
||||
|
||||
PortStatsModel::~PortStatsModel()
|
||||
{
|
||||
timer->stop();
|
||||
delete timer;
|
||||
}
|
||||
|
||||
int PortStatsModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
|
||||
if (numPorts.isEmpty())
|
||||
return 0;
|
||||
|
||||
if (numPorts.last() == 0)
|
||||
return 0;
|
||||
|
||||
return (int) e_STAT_MAX;
|
||||
}
|
||||
|
||||
int PortStatsModel::columnCount(const QModelIndex &parent ) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
else
|
||||
if (numPorts.isEmpty())
|
||||
return 0;
|
||||
else
|
||||
return numPorts.last();
|
||||
}
|
||||
|
||||
void PortStatsModel::getDomainIndexes(const QModelIndex &index,
|
||||
uint &portGroupIdx, uint &portIdx) const
|
||||
{
|
||||
int portNum;
|
||||
|
||||
// TODO(LOW): Optimize using binary search: see qLowerBound()
|
||||
portNum = index.column() + 1;
|
||||
for (portGroupIdx = 0; portGroupIdx < (uint) numPorts.size(); portGroupIdx++)
|
||||
if (portNum <= numPorts.at(portGroupIdx))
|
||||
break;
|
||||
|
||||
if (portGroupIdx)
|
||||
{
|
||||
if (numPorts.at(portGroupIdx -1))
|
||||
portIdx = (portNum - 1) % numPorts.at(portGroupIdx - 1);
|
||||
else
|
||||
portIdx = portNum - 1;
|
||||
}
|
||||
else
|
||||
portIdx = portNum - 1;
|
||||
|
||||
//qDebug("PSM: %d - %d, %d", index.column(), portGroupIdx, portIdx);
|
||||
}
|
||||
|
||||
QVariant PortStatsModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
uint pgidx, pidx;
|
||||
int row;
|
||||
|
||||
// Check for a valid index
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
// Check for row/column limits
|
||||
row = index.row();
|
||||
if (row >= e_STAT_MAX)
|
||||
return QVariant();
|
||||
|
||||
if (numPorts.isEmpty())
|
||||
return QVariant();
|
||||
|
||||
if (index.column() >= (numPorts.last()))
|
||||
return QVariant();
|
||||
|
||||
getDomainIndexes(index, pgidx, pidx);
|
||||
|
||||
// Check role
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
OstProto::PortStats stats;
|
||||
|
||||
stats = pgl->mPortGroups.at(pgidx)->mPorts[pidx]->getStats();
|
||||
|
||||
switch(row)
|
||||
{
|
||||
// States
|
||||
case e_LINK_STATE:
|
||||
return LinkStateName.at(stats.state().link_state());
|
||||
|
||||
case e_TRANSMIT_STATE:
|
||||
return BoolStateName.at(stats.state().is_transmit_on());
|
||||
|
||||
case e_CAPTURE_STATE:
|
||||
return BoolStateName.at(stats.state().is_capture_on());
|
||||
|
||||
// Statistics
|
||||
case e_STAT_FRAMES_RCVD:
|
||||
return quint64(stats.rx_pkts());
|
||||
|
||||
case e_STAT_FRAMES_SENT:
|
||||
return quint64(stats.tx_pkts());
|
||||
|
||||
case e_STAT_FRAME_SEND_RATE:
|
||||
return quint64(stats.tx_pps());
|
||||
|
||||
case e_STAT_FRAME_RECV_RATE:
|
||||
return quint64(stats.rx_pps());
|
||||
|
||||
case e_STAT_BYTES_RCVD:
|
||||
return quint64(stats.rx_bytes());
|
||||
|
||||
case e_STAT_BYTES_SENT:
|
||||
return quint64(stats.tx_bytes());
|
||||
|
||||
case e_STAT_BYTE_SEND_RATE:
|
||||
return quint64(stats.tx_bps());
|
||||
|
||||
case e_STAT_BYTE_RECV_RATE:
|
||||
return quint64(stats.rx_bps());
|
||||
|
||||
#if 0
|
||||
case e_STAT_FRAMES_RCVD_NIC:
|
||||
return stats.rx_pkts_nic();
|
||||
|
||||
case e_STAT_FRAMES_SENT_NIC:
|
||||
return stats.tx_pkts_nic();
|
||||
|
||||
case e_STAT_BYTES_RCVD_NIC:
|
||||
return stats.rx_bytes_nic();
|
||||
|
||||
case e_STAT_BYTES_SENT_NIC:
|
||||
return stats.tx_bytes_nic();
|
||||
#endif
|
||||
case e_STAT_RX_DROPS : return quint64(stats.rx_drops());
|
||||
case e_STAT_RX_ERRORS: return quint64(stats.rx_errors());
|
||||
case e_STAT_RX_FIFO_ERRORS: return quint64(stats.rx_fifo_errors());
|
||||
case e_STAT_RX_FRAME_ERRORS: return quint64(stats.rx_frame_errors());
|
||||
|
||||
default:
|
||||
qWarning("%s: Unhandled stats id %d\n", __FUNCTION__,
|
||||
index.row());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (role == Qt::TextAlignmentRole)
|
||||
{
|
||||
if (row >= e_STATE_START && row <= e_STATE_END)
|
||||
return Qt::AlignHCenter;
|
||||
else if (row >= e_STATISTICS_START && row <= e_STATISTICS_END)
|
||||
return Qt::AlignRight;
|
||||
else
|
||||
return QVariant();
|
||||
}
|
||||
else
|
||||
return QVariant();
|
||||
|
||||
}
|
||||
|
||||
QVariant PortStatsModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role == Qt::ToolTipRole)
|
||||
{
|
||||
if (orientation == Qt::Horizontal)
|
||||
{
|
||||
QString notes;
|
||||
uint portGroupIdx, portIdx;
|
||||
|
||||
getDomainIndexes(index(0, section), portGroupIdx, portIdx);
|
||||
notes = pgl->mPortGroups.at(portGroupIdx)->mPorts[portIdx]->notes();
|
||||
if (!notes.isEmpty())
|
||||
return notes;
|
||||
else
|
||||
return QVariant();
|
||||
}
|
||||
else
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
if (orientation == Qt::Horizontal)
|
||||
{
|
||||
uint portGroupIdx, portIdx;
|
||||
QString portName;
|
||||
|
||||
getDomainIndexes(index(0, section), portGroupIdx, portIdx);
|
||||
portName = QString("Port %1-%2").arg(portGroupIdx).arg(portIdx);
|
||||
if (portGroupIdx < (uint) pgl->mPortGroups.size()
|
||||
&& portIdx < (uint) pgl->mPortGroups.at(portGroupIdx)->mPorts.size())
|
||||
{
|
||||
if (!pgl->mPortGroups.at(portGroupIdx)->mPorts[portIdx]->notes()
|
||||
.isEmpty())
|
||||
portName += " *";
|
||||
}
|
||||
return portName;
|
||||
}
|
||||
else
|
||||
return PortStatName.at(section);
|
||||
}
|
||||
|
||||
void PortStatsModel::portListFromIndex(QModelIndexList indices,
|
||||
QList<PortGroupAndPortList> &portList)
|
||||
{
|
||||
int i, j;
|
||||
QModelIndexList selectedCols(indices);
|
||||
|
||||
portList.clear();
|
||||
|
||||
//selectedCols = indices.selectedColumns();
|
||||
for (i = 0; i < selectedCols.size(); i++)
|
||||
{
|
||||
uint portGroupIdx, portIdx;
|
||||
|
||||
getDomainIndexes(selectedCols.at(i), portGroupIdx, portIdx);
|
||||
for (j = 0; j < portList.size(); j++)
|
||||
{
|
||||
if (portList[j].portGroupId == portGroupIdx)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j >= portList.size())
|
||||
{
|
||||
// PortGroup Not found
|
||||
PortGroupAndPortList p;
|
||||
|
||||
p.portGroupId = portGroupIdx;
|
||||
p.portList.append(portIdx);
|
||||
|
||||
portList.append(p);
|
||||
}
|
||||
else
|
||||
{
|
||||
// PortGroup found
|
||||
|
||||
portList[j].portList.append(portIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Slots
|
||||
//
|
||||
void PortStatsModel::when_portListChanged()
|
||||
{
|
||||
int i, count = 0;
|
||||
|
||||
// recalc numPorts
|
||||
while (numPorts.size())
|
||||
numPorts.removeFirst();
|
||||
|
||||
for (i = 0; i < pgl->mPortGroups.size(); i++)
|
||||
{
|
||||
count += pgl->mPortGroups.at(i)->numPorts();
|
||||
numPorts.append(count);
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
void PortStatsModel::on_portStatsUpdate(int port, void* /*stats*/)
|
||||
{
|
||||
QModelIndex topLeft = index(port, 0, QModelIndex());
|
||||
QModelIndex bottomRight = index(port, e_STAT_MAX, QModelIndex());
|
||||
|
||||
emit dataChanged(topLeft, bottomRight);
|
||||
}
|
||||
|
||||
void PortStatsModel::updateStats()
|
||||
{
|
||||
// Request each portgroup to fetch updated stats - the port group
|
||||
// raises a signal once updated stats are available
|
||||
for (int i = 0; i < pgl->mPortGroups.size(); i++)
|
||||
pgl->mPortGroups[i]->getPortStats();
|
||||
}
|
||||
|
||||
void PortStatsModel::when_portGroup_stats_update(quint32 /*portGroupId*/)
|
||||
{
|
||||
// FIXME(MED): update only the changed ports, not all
|
||||
|
||||
QModelIndex topLeft = index(0, 0, QModelIndex());
|
||||
QModelIndex bottomRight = index(rowCount(), columnCount(), QModelIndex());
|
||||
|
||||
emit dataChanged(topLeft, bottomRight);
|
||||
}
|
151
client/portstatsmodel.h
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
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 _PORT_STATS_MODEL_H
|
||||
#define _PORT_STATS_MODEL_H
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QStringList>
|
||||
|
||||
class QTimer;
|
||||
|
||||
typedef enum {
|
||||
// State
|
||||
e_STATE_START = 0,
|
||||
|
||||
e_LINK_STATE = e_STATE_START,
|
||||
e_TRANSMIT_STATE,
|
||||
e_CAPTURE_STATE,
|
||||
|
||||
e_STATE_END = e_CAPTURE_STATE,
|
||||
|
||||
// Statistics
|
||||
e_STATISTICS_START,
|
||||
|
||||
e_STAT_FRAMES_RCVD = e_STATISTICS_START,
|
||||
e_STAT_FRAMES_SENT,
|
||||
e_STAT_FRAME_SEND_RATE,
|
||||
e_STAT_FRAME_RECV_RATE,
|
||||
e_STAT_BYTES_RCVD,
|
||||
e_STAT_BYTES_SENT,
|
||||
e_STAT_BYTE_SEND_RATE,
|
||||
e_STAT_BYTE_RECV_RATE,
|
||||
#if 0
|
||||
e_STAT_FRAMES_RCVD_NIC,
|
||||
e_STAT_FRAMES_SENT_NIC,
|
||||
e_STAT_BYTES_RCVD_NIC,
|
||||
e_STAT_BYTES_SENT_NIC,
|
||||
#endif
|
||||
|
||||
// Rx Errors
|
||||
e_STAT_RX_DROPS,
|
||||
e_STAT_RX_ERRORS,
|
||||
e_STAT_RX_FIFO_ERRORS,
|
||||
e_STAT_RX_FRAME_ERRORS,
|
||||
|
||||
e_STATISTICS_END = e_STAT_RX_FRAME_ERRORS,
|
||||
|
||||
e_STAT_MAX
|
||||
} PortStat;
|
||||
|
||||
static QStringList PortStatName = (QStringList()
|
||||
<< "Link State"
|
||||
<< "Transmit State"
|
||||
<< "Capture State"
|
||||
|
||||
<< "Frames Received"
|
||||
<< "Frames Sent"
|
||||
<< "Frame Send Rate (fps)"
|
||||
<< "Frame Receive Rate (fps)"
|
||||
<< "Bytes Received"
|
||||
<< "Bytes Sent"
|
||||
<< "Byte Send Rate (Bps)"
|
||||
<< "Byte Receive Rate (Bps)"
|
||||
#if 0
|
||||
<< "Frames Received (NIC)"
|
||||
<< "Frames Sent (NIC)"
|
||||
<< "Bytes Received (NIC)"
|
||||
<< "Bytes Sent (NIC)"
|
||||
#endif
|
||||
<< "Receive Drops"
|
||||
<< "Receive Errors"
|
||||
<< "Receive Fifo Errors"
|
||||
<< "Receive Frame Errors"
|
||||
);
|
||||
|
||||
static QStringList LinkStateName = (QStringList()
|
||||
<< "Unknown"
|
||||
<< "Down"
|
||||
<< "Up"
|
||||
);
|
||||
|
||||
static QStringList BoolStateName = (QStringList()
|
||||
<< "Off"
|
||||
<< "On"
|
||||
);
|
||||
|
||||
class PortGroupList;
|
||||
|
||||
class PortStatsModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
PortStatsModel(PortGroupList *p, QObject *parent = 0);
|
||||
~PortStatsModel();
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
|
||||
class PortGroupAndPortList {
|
||||
public:
|
||||
uint portGroupId;
|
||||
QList<uint> portList;
|
||||
};
|
||||
void portListFromIndex(QModelIndexList indices,
|
||||
QList<PortGroupAndPortList> &portList);
|
||||
|
||||
public slots:
|
||||
void when_portListChanged();
|
||||
void on_portStatsUpdate(int port, void*stats);
|
||||
void when_portGroup_stats_update(quint32 portGroupId);
|
||||
|
||||
private slots:
|
||||
void updateStats();
|
||||
|
||||
private:
|
||||
PortGroupList *pgl;
|
||||
|
||||
// numPorts stores the num of ports per portgroup
|
||||
// in the same order as the portgroups are index in the pgl
|
||||
// Also it stores them as cumulative totals
|
||||
QList<quint16> numPorts;
|
||||
|
||||
QTimer *timer;
|
||||
|
||||
void getDomainIndexes(const QModelIndex &index,
|
||||
uint &portGroupIdx, uint &portIdx) const;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
180
client/portstatswindow.cpp
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
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 "portstatswindow.h"
|
||||
#include "portstatsmodel.h"
|
||||
#include "portstatsfilterdialog.h"
|
||||
|
||||
#include "QHeaderView"
|
||||
|
||||
PortStatsWindow::PortStatsWindow(PortGroupList *pgl, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
this->pgl = pgl;
|
||||
model = pgl->getPortStatsModel();
|
||||
tvPortStats->setModel(model);
|
||||
|
||||
tvPortStats->verticalHeader()->setHighlightSections(false);
|
||||
tvPortStats->verticalHeader()->setDefaultSectionSize(
|
||||
tvPortStats->verticalHeader()->minimumSectionSize());
|
||||
|
||||
}
|
||||
|
||||
PortStatsWindow::~PortStatsWindow()
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------- SLOTS -------------- */
|
||||
|
||||
void PortStatsWindow::on_tbStartTransmit_clicked()
|
||||
{
|
||||
QList<PortStatsModel::PortGroupAndPortList> pgpl;
|
||||
|
||||
// Get selected ports
|
||||
model->portListFromIndex(tvPortStats->selectionModel()->selectedColumns(),
|
||||
pgpl);
|
||||
|
||||
// Clear selected ports, portgroup by portgroup
|
||||
for (int i = 0; i < pgpl.size(); i++)
|
||||
{
|
||||
pgl->portGroupByIndex(pgpl.at(i).portGroupId).
|
||||
startTx(&pgpl[i].portList);
|
||||
}
|
||||
}
|
||||
|
||||
void PortStatsWindow::on_tbStopTransmit_clicked()
|
||||
{
|
||||
QList<PortStatsModel::PortGroupAndPortList> pgpl;
|
||||
|
||||
// Get selected ports
|
||||
model->portListFromIndex(tvPortStats->selectionModel()->selectedColumns(),
|
||||
pgpl);
|
||||
|
||||
// Clear selected ports, portgroup by portgroup
|
||||
for (int i = 0; i < pgpl.size(); i++)
|
||||
{
|
||||
pgl->portGroupByIndex(pgpl.at(i).portGroupId).
|
||||
stopTx(&pgpl[i].portList);
|
||||
}
|
||||
}
|
||||
|
||||
void PortStatsWindow::on_tbStartCapture_clicked()
|
||||
{
|
||||
// TODO(MED)
|
||||
QList<PortStatsModel::PortGroupAndPortList> pgpl;
|
||||
|
||||
// Get selected ports
|
||||
model->portListFromIndex(tvPortStats->selectionModel()->selectedColumns(),
|
||||
pgpl);
|
||||
|
||||
// Clear selected ports, portgroup by portgroup
|
||||
for (int i = 0; i < pgpl.size(); i++)
|
||||
{
|
||||
pgl->portGroupByIndex(pgpl.at(i).portGroupId).
|
||||
startCapture(&pgpl[i].portList);
|
||||
}
|
||||
}
|
||||
|
||||
void PortStatsWindow::on_tbStopCapture_clicked()
|
||||
{
|
||||
// TODO(MED)
|
||||
QList<PortStatsModel::PortGroupAndPortList> pgpl;
|
||||
|
||||
// Get selected ports
|
||||
model->portListFromIndex(tvPortStats->selectionModel()->selectedColumns(),
|
||||
pgpl);
|
||||
|
||||
// Clear selected ports, portgroup by portgroup
|
||||
for (int i = 0; i < pgpl.size(); i++)
|
||||
{
|
||||
pgl->portGroupByIndex(pgpl.at(i).portGroupId).
|
||||
stopCapture(&pgpl[i].portList);
|
||||
}
|
||||
}
|
||||
|
||||
void PortStatsWindow::on_tbViewCapture_clicked()
|
||||
{
|
||||
// TODO(MED)
|
||||
QList<PortStatsModel::PortGroupAndPortList> pgpl;
|
||||
|
||||
// Get selected ports
|
||||
model->portListFromIndex(tvPortStats->selectionModel()->selectedColumns(),
|
||||
pgpl);
|
||||
|
||||
// Clear selected ports, portgroup by portgroup
|
||||
for (int i = 0; i < pgpl.size(); i++)
|
||||
{
|
||||
pgl->portGroupByIndex(pgpl.at(i).portGroupId).
|
||||
viewCapture(&pgpl[i].portList);
|
||||
}
|
||||
}
|
||||
|
||||
void PortStatsWindow::on_tbClear_clicked()
|
||||
{
|
||||
QList<PortStatsModel::PortGroupAndPortList> portList;
|
||||
|
||||
// Get selected ports
|
||||
model->portListFromIndex(tvPortStats->selectionModel()->selectedColumns(),
|
||||
portList);
|
||||
|
||||
// Clear selected ports, portgroup by portgroup
|
||||
for (int i = 0; i < portList.size(); i++)
|
||||
{
|
||||
pgl->portGroupByIndex(portList.at(i).portGroupId).
|
||||
clearPortStats(&portList[i].portList);
|
||||
}
|
||||
}
|
||||
|
||||
void PortStatsWindow::on_tbClearAll_clicked()
|
||||
{
|
||||
for (int i = 0; i < pgl->numPortGroups(); i++)
|
||||
{
|
||||
pgl->portGroupByIndex(0).clearPortStats();
|
||||
}
|
||||
}
|
||||
|
||||
void PortStatsWindow::on_tbFilter_clicked()
|
||||
{
|
||||
bool ok;
|
||||
QList<uint> currentColumns, newColumns;
|
||||
PortStatsFilterDialog dialog;
|
||||
|
||||
for(int i = 0; i < model->columnCount(); i++)
|
||||
if (!tvPortStats->isColumnHidden(i))
|
||||
currentColumns.append(i);
|
||||
|
||||
newColumns = dialog.getItemList(&ok, model, Qt::Horizontal, currentColumns);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
// hide/show sections first ...
|
||||
for(int i = 0; i < model->columnCount(); i++)
|
||||
tvPortStats->setColumnHidden(i, !newColumns.contains(i));
|
||||
|
||||
// ... then for the 'shown' columns, set the visual index
|
||||
for(int i = 0; i < newColumns.size(); i++)
|
||||
{
|
||||
tvPortStats->horizontalHeader()->moveSection(tvPortStats->
|
||||
horizontalHeader()->visualIndex(newColumns.at(i)), i);
|
||||
}
|
||||
}
|
||||
}
|
56
client/portstatswindow.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
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 _PORT_STATS_WINDOW_H
|
||||
#define _PORT_STATS_WINDOW_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QAbstractItemModel>
|
||||
#include "ui_portstatswindow.h"
|
||||
#include "portgrouplist.h"
|
||||
#include "portstatsmodel.h"
|
||||
|
||||
class PortStatsWindow : public QWidget, public Ui::PortStatsWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PortStatsWindow(PortGroupList *pgl, QWidget *parent = 0);
|
||||
~PortStatsWindow();
|
||||
|
||||
private:
|
||||
PortGroupList *pgl;
|
||||
PortStatsModel *model;
|
||||
|
||||
private slots:
|
||||
void on_tbStartTransmit_clicked();
|
||||
void on_tbStopTransmit_clicked();
|
||||
|
||||
void on_tbStartCapture_clicked();
|
||||
void on_tbStopCapture_clicked();
|
||||
void on_tbViewCapture_clicked();
|
||||
|
||||
void on_tbClear_clicked();
|
||||
void on_tbClearAll_clicked();
|
||||
|
||||
void on_tbFilter_clicked();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
182
client/portstatswindow.ui
Normal file
@ -0,0 +1,182 @@
|
||||
<ui version="4.0" >
|
||||
<class>PortStatsWindow</class>
|
||||
<widget class="QWidget" name="PortStatsWindow" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>502</width>
|
||||
<height>415</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QFrame" name="frame" >
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::Panel</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QToolButton" name="tbStartTransmit" >
|
||||
<property name="toolTip" >
|
||||
<string>Start Tx</string>
|
||||
</property>
|
||||
<property name="statusTip" >
|
||||
<string>Starts transmit on selected port(s)</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Start Transmit</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/control_play.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="tbStopTransmit" >
|
||||
<property name="toolTip" >
|
||||
<string>Stop Tx</string>
|
||||
</property>
|
||||
<property name="statusTip" >
|
||||
<string>Stops transmit on selected port(s)</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Stop Trasmit</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/control_stop.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="tbClear" >
|
||||
<property name="toolTip" >
|
||||
<string>Clear Selected Port Stats</string>
|
||||
</property>
|
||||
<property name="statusTip" >
|
||||
<string>Clears statistics of the selected port(s)</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Clear</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/portstats_clear.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="tbClearAll" >
|
||||
<property name="toolTip" >
|
||||
<string>Clear All Ports Stats</string>
|
||||
</property>
|
||||
<property name="statusTip" >
|
||||
<string>Clears statistics of all ports</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Clear All</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/portstats_clear_all.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="tbStartCapture" >
|
||||
<property name="toolTip" >
|
||||
<string>Start Capture</string>
|
||||
</property>
|
||||
<property name="statusTip" >
|
||||
<string>Captures packets on the selected port(s)</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Start Capture</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/sound_none.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="tbStopCapture" >
|
||||
<property name="toolTip" >
|
||||
<string>Stop Capture</string>
|
||||
</property>
|
||||
<property name="statusTip" >
|
||||
<string>End capture on selecteed port(s)</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Stop Capture</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/sound_mute.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="tbViewCapture" >
|
||||
<property name="toolTip" >
|
||||
<string>View Capture Buffer</string>
|
||||
</property>
|
||||
<property name="statusTip" >
|
||||
<string>View captured packets on selected port(s)</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>View Capture</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/magnifier.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</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="QToolButton" name="tbFilter" >
|
||||
<property name="statusTip" >
|
||||
<string>Select which ports to view</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Filter</string>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/portstats_filter.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableView" name="tvPortStats" />
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="ostinato.qrc" />
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
663
client/portswindow.cpp
Normal file
@ -0,0 +1,663 @@
|
||||
/*
|
||||
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 "portswindow.h"
|
||||
|
||||
#include "abstractfileformat.h"
|
||||
#include "portconfigdialog.h"
|
||||
#include "streamconfigdialog.h"
|
||||
#include "streamlistdelegate.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QInputDialog>
|
||||
#include <QItemSelectionModel>
|
||||
#include <QMessageBox>
|
||||
|
||||
PortsWindow::PortsWindow(PortGroupList *pgl, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QAction *sep;
|
||||
|
||||
delegate = new StreamListDelegate;
|
||||
//slm = new StreamListModel();
|
||||
//plm = new PortGroupList();
|
||||
plm = pgl;
|
||||
|
||||
setupUi(this);
|
||||
|
||||
tvPortList->header()->hide();
|
||||
|
||||
tvStreamList->setItemDelegate(delegate);
|
||||
|
||||
tvStreamList->verticalHeader()->setDefaultSectionSize(
|
||||
tvStreamList->verticalHeader()->minimumSectionSize());
|
||||
|
||||
// Populate PortList Context Menu Actions
|
||||
tvPortList->addAction(actionNew_Port_Group);
|
||||
tvPortList->addAction(actionDelete_Port_Group);
|
||||
tvPortList->addAction(actionConnect_Port_Group);
|
||||
tvPortList->addAction(actionDisconnect_Port_Group);
|
||||
|
||||
tvPortList->addAction(actionExclusive_Control);
|
||||
tvPortList->addAction(actionPort_Configuration);
|
||||
|
||||
// Populate StramList Context Menu Actions
|
||||
tvStreamList->addAction(actionNew_Stream);
|
||||
tvStreamList->addAction(actionEdit_Stream);
|
||||
tvStreamList->addAction(actionDelete_Stream);
|
||||
|
||||
sep = new QAction(this);
|
||||
sep->setSeparator(true);
|
||||
tvStreamList->addAction(sep);
|
||||
|
||||
tvStreamList->addAction(actionOpen_Streams);
|
||||
tvStreamList->addAction(actionSave_Streams);
|
||||
|
||||
// PortList and StreamList actions combined make this window's actions
|
||||
addActions(tvPortList->actions());
|
||||
sep = new QAction(this);
|
||||
sep->setSeparator(true);
|
||||
addAction(sep);
|
||||
addActions(tvStreamList->actions());
|
||||
|
||||
tvStreamList->setModel(plm->getStreamModel());
|
||||
tvPortList->setModel(plm->getPortModel());
|
||||
|
||||
connect( plm->getPortModel(),
|
||||
SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
||||
this, SLOT(when_portModel_dataChanged(const QModelIndex&,
|
||||
const QModelIndex&)));
|
||||
|
||||
connect(plm->getPortModel(), SIGNAL(modelReset()),
|
||||
SLOT(when_portModel_reset()));
|
||||
|
||||
connect( tvPortList->selectionModel(),
|
||||
SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
|
||||
this, SLOT(when_portView_currentChanged(const QModelIndex&,
|
||||
const QModelIndex&)));
|
||||
|
||||
connect(plm->getStreamModel(), SIGNAL(rowsInserted(QModelIndex, int, int)),
|
||||
SLOT(updateStreamViewActions()));
|
||||
connect(plm->getStreamModel(), SIGNAL(rowsRemoved(QModelIndex, int, int)),
|
||||
SLOT(updateStreamViewActions()));
|
||||
|
||||
connect(tvStreamList->selectionModel(),
|
||||
SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
|
||||
SLOT(updateStreamViewActions()));
|
||||
connect(tvStreamList->selectionModel(),
|
||||
SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
|
||||
SLOT(updateStreamViewActions()));
|
||||
|
||||
tvStreamList->resizeColumnToContents(StreamModel::StreamIcon);
|
||||
tvStreamList->resizeColumnToContents(StreamModel::StreamStatus);
|
||||
|
||||
// Initially we don't have any ports/streams - so send signal triggers
|
||||
when_portView_currentChanged(QModelIndex(), QModelIndex());
|
||||
updateStreamViewActions();
|
||||
|
||||
connect(plm->getStreamModel(),
|
||||
SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)),
|
||||
this, SLOT(streamModelDataChanged()));
|
||||
connect(plm->getStreamModel(),
|
||||
SIGNAL(modelReset()),
|
||||
this, SLOT(streamModelDataChanged()));
|
||||
}
|
||||
|
||||
void PortsWindow::streamModelDataChanged()
|
||||
{
|
||||
if (plm->isPort(tvPortList->currentIndex()))
|
||||
plm->port(tvPortList->currentIndex()).recalculateAverageRates();
|
||||
}
|
||||
|
||||
PortsWindow::~PortsWindow()
|
||||
{
|
||||
delete delegate;
|
||||
}
|
||||
|
||||
void PortsWindow::on_tvStreamList_activated(const QModelIndex & index)
|
||||
{
|
||||
StreamConfigDialog *scd;
|
||||
int ret;
|
||||
|
||||
if (!index.isValid())
|
||||
{
|
||||
qDebug("%s: invalid index", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
scd = new StreamConfigDialog(plm->port(tvPortList->currentIndex()),
|
||||
index.row(), this);
|
||||
qDebug("stream list activated\n");
|
||||
ret = scd->exec();
|
||||
|
||||
if (ret == QDialog::Accepted)
|
||||
plm->port(tvPortList->currentIndex()).recalculateAverageRates();
|
||||
|
||||
delete scd;
|
||||
}
|
||||
|
||||
void PortsWindow::when_portView_currentChanged(const QModelIndex& current,
|
||||
const QModelIndex& previous)
|
||||
{
|
||||
plm->getStreamModel()->setCurrentPortIndex(current);
|
||||
updatePortViewActions(current);
|
||||
updateStreamViewActions();
|
||||
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
|
||||
if (previous.isValid() && plm->isPort(previous))
|
||||
{
|
||||
disconnect(&(plm->port(previous)), SIGNAL(portRateChanged(int, int)),
|
||||
this, SLOT(updatePortRates()));
|
||||
}
|
||||
|
||||
if (!current.isValid())
|
||||
{
|
||||
qDebug("setting stacked widget to blank page");
|
||||
swDetail->setCurrentIndex(2); // blank page
|
||||
}
|
||||
else
|
||||
{
|
||||
if (plm->isPortGroup(current))
|
||||
{
|
||||
swDetail->setCurrentIndex(1); // portGroup detail page
|
||||
}
|
||||
else if (plm->isPort(current))
|
||||
{
|
||||
swDetail->setCurrentIndex(0); // port detail page
|
||||
updatePortRates();
|
||||
connect(&(plm->port(current)), SIGNAL(portRateChanged(int, int)),
|
||||
SLOT(updatePortRates()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PortsWindow::when_portModel_dataChanged(const QModelIndex& topLeft,
|
||||
const QModelIndex& bottomRight)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
#if 0 // not sure why the >= <= operators are not overloaded in QModelIndex
|
||||
if ((tvPortList->currentIndex() >= topLeft) &&
|
||||
(tvPortList->currentIndex() <= bottomRight))
|
||||
#endif
|
||||
if (((topLeft < tvPortList->currentIndex()) ||
|
||||
(topLeft == tvPortList->currentIndex())) &&
|
||||
(((tvPortList->currentIndex() < bottomRight)) ||
|
||||
(tvPortList->currentIndex() == bottomRight)))
|
||||
{
|
||||
// Update UI to reflect potential change in exclusive mode,
|
||||
// transmit mode et al
|
||||
when_portView_currentChanged(tvPortList->currentIndex(),
|
||||
tvPortList->currentIndex());
|
||||
}
|
||||
}
|
||||
|
||||
void PortsWindow::when_portModel_reset()
|
||||
{
|
||||
when_portView_currentChanged(QModelIndex(), tvPortList->currentIndex());
|
||||
}
|
||||
|
||||
void PortsWindow::on_averagePacketsPerSec_editingFinished()
|
||||
{
|
||||
QModelIndex current = tvPortList->currentIndex();
|
||||
|
||||
Q_ASSERT(plm->isPort(current));
|
||||
|
||||
bool isOk;
|
||||
double pps = QLocale().toDouble(averagePacketsPerSec->text(), &isOk);
|
||||
|
||||
plm->port(current).setAveragePacketRate(pps);
|
||||
}
|
||||
|
||||
void PortsWindow::on_averageBitsPerSec_editingFinished()
|
||||
{
|
||||
QModelIndex current = tvPortList->currentIndex();
|
||||
|
||||
Q_ASSERT(plm->isPort(current));
|
||||
|
||||
bool isOk;
|
||||
double bps = QLocale().toDouble(averageBitsPerSec->text(), &isOk);
|
||||
|
||||
plm->port(current).setAverageBitRate(bps);
|
||||
}
|
||||
|
||||
void PortsWindow::updatePortRates()
|
||||
{
|
||||
QModelIndex current = tvPortList->currentIndex();
|
||||
|
||||
if (!current.isValid())
|
||||
return;
|
||||
|
||||
if (!plm->isPort(current))
|
||||
return;
|
||||
|
||||
averagePacketsPerSec->setText(QString("%L1")
|
||||
.arg(plm->port(current).averagePacketRate(), 0, 'f', 4));
|
||||
averageBitsPerSec->setText(QString("%L1")
|
||||
.arg(plm->port(current).averageBitRate(), 0, 'f', 0));
|
||||
}
|
||||
|
||||
void PortsWindow::updateStreamViewActions()
|
||||
{
|
||||
// For some reason hasSelection() returns true even if selection size is 0
|
||||
// so additional check for size introduced
|
||||
if (tvStreamList->selectionModel()->hasSelection() &&
|
||||
(tvStreamList->selectionModel()->selection().size() > 0))
|
||||
{
|
||||
qDebug("Has selection %d",
|
||||
tvStreamList->selectionModel()->selection().size());
|
||||
|
||||
// If more than one non-contiguous ranges selected,
|
||||
// disable "New" and "Edit"
|
||||
if (tvStreamList->selectionModel()->selection().size() > 1)
|
||||
{
|
||||
actionNew_Stream->setDisabled(true);
|
||||
actionEdit_Stream->setDisabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
actionNew_Stream->setEnabled(true);
|
||||
|
||||
// Enable "Edit" only if the single range has a single row
|
||||
if (tvStreamList->selectionModel()->selection().at(0).height() > 1)
|
||||
actionEdit_Stream->setDisabled(true);
|
||||
else
|
||||
actionEdit_Stream->setEnabled(true);
|
||||
}
|
||||
|
||||
// Delete is always enabled as long as we have a selection
|
||||
actionDelete_Stream->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("No selection");
|
||||
if (plm->isPort(tvPortList->currentIndex()))
|
||||
actionNew_Stream->setEnabled(true);
|
||||
else
|
||||
actionNew_Stream->setDisabled(true);
|
||||
actionEdit_Stream->setDisabled(true);
|
||||
actionDelete_Stream->setDisabled(true);
|
||||
}
|
||||
actionOpen_Streams->setEnabled(plm->isPort(
|
||||
tvPortList->selectionModel()->currentIndex()));
|
||||
actionSave_Streams->setEnabled(tvStreamList->model()->rowCount() > 0);
|
||||
}
|
||||
|
||||
void PortsWindow::updatePortViewActions(const QModelIndex& current)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
qDebug("current is now invalid");
|
||||
actionDelete_Port_Group->setDisabled(true);
|
||||
actionConnect_Port_Group->setDisabled(true);
|
||||
actionDisconnect_Port_Group->setDisabled(true);
|
||||
|
||||
actionExclusive_Control->setDisabled(true);
|
||||
actionPort_Configuration->setDisabled(true);
|
||||
|
||||
goto _EXIT;
|
||||
}
|
||||
|
||||
qDebug("currentChanged %llx", current.internalId());
|
||||
|
||||
if (plm->isPortGroup(current))
|
||||
{
|
||||
actionDelete_Port_Group->setEnabled(true);
|
||||
|
||||
actionExclusive_Control->setDisabled(true);
|
||||
actionPort_Configuration->setDisabled(true);
|
||||
|
||||
switch(plm->portGroup(current).state())
|
||||
{
|
||||
case QAbstractSocket::UnconnectedState:
|
||||
case QAbstractSocket::ClosingState:
|
||||
qDebug("state = unconnected|closing");
|
||||
actionConnect_Port_Group->setEnabled(true);
|
||||
actionDisconnect_Port_Group->setDisabled(true);
|
||||
break;
|
||||
|
||||
case QAbstractSocket::HostLookupState:
|
||||
case QAbstractSocket::ConnectingState:
|
||||
case QAbstractSocket::ConnectedState:
|
||||
qDebug("state = lookup|connecting|connected");
|
||||
actionConnect_Port_Group->setDisabled(true);
|
||||
actionDisconnect_Port_Group->setEnabled(true);
|
||||
break;
|
||||
|
||||
|
||||
case QAbstractSocket::BoundState:
|
||||
case QAbstractSocket::ListeningState:
|
||||
default:
|
||||
// FIXME(LOW): indicate error
|
||||
qDebug("unexpected state");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (plm->isPort(current))
|
||||
{
|
||||
actionDelete_Port_Group->setDisabled(true);
|
||||
actionConnect_Port_Group->setDisabled(true);
|
||||
actionDisconnect_Port_Group->setDisabled(true);
|
||||
|
||||
actionExclusive_Control->setEnabled(true);
|
||||
if (plm->port(current).hasExclusiveControl())
|
||||
actionExclusive_Control->setChecked(true);
|
||||
else
|
||||
actionExclusive_Control->setChecked(false);
|
||||
actionPort_Configuration->setEnabled(true);
|
||||
}
|
||||
|
||||
_EXIT:
|
||||
return;
|
||||
}
|
||||
|
||||
void PortsWindow::on_pbApply_clicked()
|
||||
{
|
||||
QModelIndex curPort;
|
||||
QModelIndex curPortGroup;
|
||||
|
||||
curPort = tvPortList->selectionModel()->currentIndex();
|
||||
if (!curPort.isValid())
|
||||
{
|
||||
qDebug("%s: curPort is invalid", __FUNCTION__);
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
if (!plm->isPort(curPort))
|
||||
{
|
||||
qDebug("%s: curPort is not a port", __FUNCTION__);
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
if (plm->port(curPort).getStats().state().is_transmit_on())
|
||||
{
|
||||
QMessageBox::information(0, "Configuration Change",
|
||||
"Please stop transmit on the port before applying any changes");
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
curPortGroup = plm->getPortModel()->parent(curPort);
|
||||
if (!curPortGroup.isValid())
|
||||
{
|
||||
qDebug("%s: curPortGroup is invalid", __FUNCTION__);
|
||||
goto _exit;
|
||||
}
|
||||
if (!plm->isPortGroup(curPortGroup))
|
||||
{
|
||||
qDebug("%s: curPortGroup is not a portGroup", __FUNCTION__);
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
// FIXME(HI): shd this be a signal?
|
||||
//portGroup.when_configApply(port);
|
||||
// FIXME(MED): mixing port id and index!!!
|
||||
plm->portGroup(curPortGroup).when_configApply(plm->port(curPort).id());
|
||||
|
||||
_exit:
|
||||
return;
|
||||
|
||||
#if 0
|
||||
// TODO (LOW): This block is for testing only
|
||||
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||
|
||||
if (current.isValid())
|
||||
qDebug("current = %llx", current.internalId());
|
||||
else
|
||||
qDebug("current is invalid");
|
||||
#endif
|
||||
}
|
||||
|
||||
void PortsWindow::on_actionNew_Port_Group_triggered()
|
||||
{
|
||||
bool ok;
|
||||
QString text = QInputDialog::getText(this,
|
||||
"Add Port Group", "Port Group Address (IP[:Port])",
|
||||
QLineEdit::Normal, lastNewPortGroup, &ok);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
QStringList addr = text.split(":");
|
||||
if (addr.size() == 1) // Port unspecified
|
||||
addr.append(QString().setNum(DEFAULT_SERVER_PORT));
|
||||
PortGroup *pg = new PortGroup(QHostAddress(addr[0]),addr[1].toUShort());
|
||||
plm->addPortGroup(*pg);
|
||||
lastNewPortGroup = text;
|
||||
}
|
||||
}
|
||||
|
||||
void PortsWindow::on_actionDelete_Port_Group_triggered()
|
||||
{
|
||||
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||
|
||||
if (current.isValid())
|
||||
plm->removePortGroup(plm->portGroup(current));
|
||||
}
|
||||
|
||||
void PortsWindow::on_actionConnect_Port_Group_triggered()
|
||||
{
|
||||
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||
|
||||
if (current.isValid())
|
||||
plm->portGroup(current).connectToHost();
|
||||
}
|
||||
|
||||
void PortsWindow::on_actionDisconnect_Port_Group_triggered()
|
||||
{
|
||||
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||
|
||||
if (current.isValid())
|
||||
plm->portGroup(current).disconnectFromHost();
|
||||
}
|
||||
|
||||
void PortsWindow::on_actionExclusive_Control_triggered(bool checked)
|
||||
{
|
||||
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||
|
||||
if (plm->isPort(current))
|
||||
{
|
||||
OstProto::Port config;
|
||||
|
||||
config.set_is_exclusive_control(checked);
|
||||
plm->portGroup(current.parent()).modifyPort(current.row(), config);
|
||||
}
|
||||
}
|
||||
|
||||
void PortsWindow::on_actionPort_Configuration_triggered()
|
||||
{
|
||||
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||
|
||||
if (!plm->isPort(current))
|
||||
return;
|
||||
|
||||
OstProto::Port config;
|
||||
config.set_transmit_mode(plm->port(current).transmitMode());
|
||||
config.set_is_exclusive_control(plm->port(current).hasExclusiveControl());
|
||||
|
||||
PortConfigDialog dialog(config, this);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted)
|
||||
plm->portGroup(current.parent()).modifyPort(current.row(), config);
|
||||
}
|
||||
|
||||
void PortsWindow::on_actionNew_Stream_triggered()
|
||||
{
|
||||
qDebug("New Stream Action");
|
||||
|
||||
// In case nothing is selected, insert 1 row at the top
|
||||
int row = 0, count = 1;
|
||||
|
||||
// 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 (tvStreamList->selectionModel()->selection().size() == 1)
|
||||
{
|
||||
row = tvStreamList->selectionModel()->selection().at(0).top();
|
||||
count = tvStreamList->selectionModel()->selection().at(0).height();
|
||||
}
|
||||
|
||||
plm->getStreamModel()->insertRows(row, count);
|
||||
}
|
||||
|
||||
void PortsWindow::on_actionEdit_Stream_triggered()
|
||||
{
|
||||
qDebug("Edit Stream Action");
|
||||
|
||||
// Ensure we have only one range selected which contains only one row
|
||||
if ((tvStreamList->selectionModel()->selection().size() == 1) &&
|
||||
(tvStreamList->selectionModel()->selection().at(0).height() == 1))
|
||||
{
|
||||
on_tvStreamList_activated(tvStreamList->selectionModel()->
|
||||
selection().at(0).topLeft());
|
||||
}
|
||||
}
|
||||
|
||||
void PortsWindow::on_actionDelete_Stream_triggered()
|
||||
{
|
||||
qDebug("Delete Stream Action");
|
||||
|
||||
QModelIndex index;
|
||||
|
||||
if (tvStreamList->selectionModel()->hasSelection())
|
||||
{
|
||||
qDebug("SelectedIndexes %d",
|
||||
tvStreamList->selectionModel()->selectedRows().size());
|
||||
while(tvStreamList->selectionModel()->selectedRows().size())
|
||||
{
|
||||
index = tvStreamList->selectionModel()->selectedRows().at(0);
|
||||
plm->getStreamModel()->removeRows(index.row(), 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
qDebug("No selection");
|
||||
}
|
||||
|
||||
void PortsWindow::on_actionOpen_Streams_triggered()
|
||||
{
|
||||
qDebug("Open Streams Action");
|
||||
|
||||
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||
static QString dirName;
|
||||
QString fileName;
|
||||
QString errorStr;
|
||||
bool append = true;
|
||||
bool ret;
|
||||
|
||||
Q_ASSERT(plm->isPort(current));
|
||||
|
||||
fileName = QFileDialog::getOpenFileName(this, tr("Open Streams"), dirName);
|
||||
if (fileName.isEmpty())
|
||||
goto _exit;
|
||||
|
||||
if (tvStreamList->model()->rowCount())
|
||||
{
|
||||
QMessageBox msgBox(QMessageBox::Question, qApp->applicationName(),
|
||||
tr("Append to existing streams? Or overwrite?"),
|
||||
QMessageBox::NoButton, this);
|
||||
QPushButton *appendBtn = msgBox.addButton(tr("Append"),
|
||||
QMessageBox::ActionRole);
|
||||
QPushButton *overwriteBtn = msgBox.addButton(tr("Overwrite"),
|
||||
QMessageBox::ActionRole);
|
||||
QPushButton *cancelBtn = msgBox.addButton(QMessageBox::Cancel);
|
||||
|
||||
msgBox.exec();
|
||||
|
||||
if (msgBox.clickedButton() == cancelBtn)
|
||||
goto _exit;
|
||||
else if (msgBox.clickedButton() == appendBtn)
|
||||
append = true;
|
||||
else if (msgBox.clickedButton() == overwriteBtn)
|
||||
append = false;
|
||||
else
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
ret = plm->port(current).openStreams(fileName, append, errorStr);
|
||||
if (!ret || !errorStr.isEmpty())
|
||||
{
|
||||
QMessageBox msgBox(this);
|
||||
QStringList str = errorStr.split("\n\n\n\n");
|
||||
|
||||
msgBox.setIcon(ret ? QMessageBox::Warning : QMessageBox::Critical);
|
||||
msgBox.setWindowTitle(qApp->applicationName());
|
||||
msgBox.setText(str.at(0));
|
||||
if (str.size() > 1)
|
||||
msgBox.setDetailedText(str.at(1));
|
||||
msgBox.setStandardButtons(QMessageBox::Ok);
|
||||
|
||||
msgBox.exec();
|
||||
}
|
||||
dirName = QFileInfo(fileName).absolutePath();
|
||||
|
||||
_exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void PortsWindow::on_actionSave_Streams_triggered()
|
||||
{
|
||||
qDebug("Save Streams Action");
|
||||
|
||||
QModelIndex current = tvPortList->selectionModel()->currentIndex();
|
||||
static QString fileName;
|
||||
QStringList fileTypes = AbstractFileFormat::supportedFileTypes();
|
||||
QString fileType;
|
||||
QString errorStr;
|
||||
QFileDialog::Options options;
|
||||
|
||||
// On Mac OS with Native Dialog, getSaveFileName() ignores fileType
|
||||
// which we need.On some Linux distros the native dialog can't
|
||||
// distinguish between Ostinato(*) and PCAP(*)
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_UNIX)
|
||||
options |= QFileDialog::DontUseNativeDialog;
|
||||
#endif
|
||||
|
||||
if (fileTypes.size())
|
||||
fileType = fileTypes.at(0);
|
||||
|
||||
Q_ASSERT(plm->isPort(current));
|
||||
|
||||
_retry:
|
||||
fileName = QFileDialog::getSaveFileName(this, tr("Save Streams"),
|
||||
fileName, fileTypes.join(";;"), &fileType, options);
|
||||
if (fileName.isEmpty())
|
||||
goto _exit;
|
||||
|
||||
fileType = fileType.remove(QRegExp("\\(.*\\)")).trimmed();
|
||||
if (!fileType.startsWith("Ostinato"))
|
||||
{
|
||||
if (QMessageBox::warning(this, tr("Ostinato"),
|
||||
QString("You have chosen to save in %1 format. All stream "
|
||||
"attributes may not be saved in this format.\n\n"
|
||||
"It is recommended to save in native Ostinato format.\n\n"
|
||||
"Continue to save in %2 format?").arg(fileType).arg(fileType),
|
||||
QMessageBox::Yes|QMessageBox::No,
|
||||
QMessageBox::No) != QMessageBox::Yes)
|
||||
goto _retry;
|
||||
}
|
||||
|
||||
// TODO: all or selected?
|
||||
|
||||
if (!plm->port(current).saveStreams(fileName, fileType, errorStr))
|
||||
QMessageBox::critical(this, qApp->applicationName(), errorStr);
|
||||
else if (!errorStr.isEmpty())
|
||||
QMessageBox::warning(this, qApp->applicationName(), errorStr);
|
||||
|
||||
fileName = QFileInfo(fileName).absolutePath();
|
||||
_exit:
|
||||
return;
|
||||
}
|
||||
|
||||
|
86
client/portswindow.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
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 _PORTS_WINDOW_H
|
||||
#define _PORTS_WINDOW_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QAbstractItemModel>
|
||||
#include "ui_portswindow.h"
|
||||
#include "portgrouplist.h"
|
||||
|
||||
/* TODO
|
||||
HIGH
|
||||
MED
|
||||
LOW
|
||||
*/
|
||||
|
||||
class QAbstractItemDelegate;
|
||||
|
||||
class PortsWindow : public QWidget, private Ui::PortsWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
//QAbstractItemModel *slm; // stream list model
|
||||
PortGroupList *plm;
|
||||
|
||||
public:
|
||||
PortsWindow(PortGroupList *pgl, QWidget *parent = 0);
|
||||
~PortsWindow();
|
||||
|
||||
private:
|
||||
QString lastNewPortGroup;
|
||||
QAbstractItemDelegate *delegate;
|
||||
|
||||
private slots:
|
||||
void updatePortViewActions(const QModelIndex& current);
|
||||
void updateStreamViewActions();
|
||||
|
||||
void on_averagePacketsPerSec_editingFinished();
|
||||
void on_averageBitsPerSec_editingFinished();
|
||||
void updatePortRates();
|
||||
void on_tvStreamList_activated(const QModelIndex & index);
|
||||
void when_portView_currentChanged(const QModelIndex& current,
|
||||
const QModelIndex& previous);
|
||||
void when_portModel_dataChanged(const QModelIndex& topLeft,
|
||||
const QModelIndex& bottomRight);
|
||||
void when_portModel_reset();
|
||||
|
||||
void on_pbApply_clicked();
|
||||
|
||||
void on_actionNew_Port_Group_triggered();
|
||||
void on_actionDelete_Port_Group_triggered();
|
||||
void on_actionConnect_Port_Group_triggered();
|
||||
void on_actionDisconnect_Port_Group_triggered();
|
||||
|
||||
void on_actionExclusive_Control_triggered(bool checked);
|
||||
void on_actionPort_Configuration_triggered();
|
||||
|
||||
void on_actionNew_Stream_triggered();
|
||||
void on_actionEdit_Stream_triggered();
|
||||
void on_actionDelete_Stream_triggered();
|
||||
|
||||
void on_actionOpen_Streams_triggered();
|
||||
void on_actionSave_Streams_triggered();
|
||||
|
||||
void streamModelDataChanged();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
299
client/portswindow.ui
Normal file
@ -0,0 +1,299 @@
|
||||
<ui version="4.0" >
|
||||
<class>PortsWindow</class>
|
||||
<widget class="QWidget" name="PortsWindow" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>710</width>
|
||||
<height>352</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QSplitter" name="splitter" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="childrenCollapsible" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="QTreeView" name="tvPortList" >
|
||||
<property name="contextMenuPolicy" >
|
||||
<enum>Qt::ActionsContextMenu</enum>
|
||||
</property>
|
||||
<property name="selectionMode" >
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QStackedWidget" name="swDetail" >
|
||||
<property name="currentIndex" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="portDetail" >
|
||||
<layout class="QGridLayout" >
|
||||
<property name="leftMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0" >
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QFrame" name="frAggregate" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QRadioButton" name="radioButton" >
|
||||
<property name="text" >
|
||||
<string>Avg pps</string>
|
||||
</property>
|
||||
<property name="checked" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLineEdit" name="averagePacketsPerSec" />
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QRadioButton" name="radioButton_2" >
|
||||
<property name="text" >
|
||||
<string>Avg bps</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLineEdit" name="averageBitsPerSec" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbApply" >
|
||||
<property name="text" >
|
||||
<string>Apply</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QTableView" name="tvStreamList" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="contextMenuPolicy" >
|
||||
<enum>Qt::ActionsContextMenu</enum>
|
||||
</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>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="portGroupDetail" >
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5" >
|
||||
<property name="text" >
|
||||
<string>Select a port to configure streams</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="blankPage" />
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<action name="actionNew_Port_Group" >
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/portgroup_add.png</iconset>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>New Port Group</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDelete_Port_Group" >
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/portgroup_delete.png</iconset>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Delete Port Group</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionConnect_Port_Group" >
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/portgroup_connect.png</iconset>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Connect Port Group</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDisconnect_Port_Group" >
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/portgroup_disconnect.png</iconset>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Disconnect Port Group</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNew_Stream" >
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/stream_add.png</iconset>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>New Stream</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDelete_Stream" >
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/stream_delete.png</iconset>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Delete Stream</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEdit_Stream" >
|
||||
<property name="icon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/stream_edit.png</iconset>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Edit Stream</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExclusive_Control" >
|
||||
<property name="checkable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Exclusive Port Control (EXPERIMENTAL)</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOpen_Streams" >
|
||||
<property name="text" >
|
||||
<string>Open Streams ...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_Streams" >
|
||||
<property name="text" >
|
||||
<string>Save Streams ...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPort_Configuration" >
|
||||
<property name="text" >
|
||||
<string>Port Configuration ...</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="ostinato.qrc" />
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>radioButton</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>averagePacketsPerSec</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>313</x>
|
||||
<y>28</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>380</x>
|
||||
<y>28</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>radioButton_2</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>averageBitsPerSec</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>333</x>
|
||||
<y>55</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>395</x>
|
||||
<y>56</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
119
client/preferences.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
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 "preferences.h"
|
||||
|
||||
#include "../common/ostprotolib.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
|
||||
Preferences::Preferences()
|
||||
{
|
||||
Q_ASSERT(appSettings);
|
||||
|
||||
setupUi(this);
|
||||
|
||||
wiresharkPathEdit->setText(appSettings->value(kWiresharkPathKey,
|
||||
kWiresharkPathDefaultValue).toString());
|
||||
tsharkPathEdit->setText(appSettings->value(kTsharkPathKey,
|
||||
kTsharkPathDefaultValue).toString());
|
||||
gzipPathEdit->setText(appSettings->value(kGzipPathKey,
|
||||
kGzipPathDefaultValue).toString());
|
||||
diffPathEdit->setText(appSettings->value(kDiffPathKey,
|
||||
kDiffPathDefaultValue).toString());
|
||||
awkPathEdit->setText(appSettings->value(kAwkPathKey,
|
||||
kAwkPathDefaultValue).toString());
|
||||
}
|
||||
|
||||
Preferences::~Preferences()
|
||||
{
|
||||
}
|
||||
|
||||
void Preferences::accept()
|
||||
{
|
||||
appSettings->setValue(kWiresharkPathKey, wiresharkPathEdit->text());
|
||||
appSettings->setValue(kTsharkPathKey, tsharkPathEdit->text());
|
||||
appSettings->setValue(kGzipPathKey, gzipPathEdit->text());
|
||||
appSettings->setValue(kDiffPathKey, diffPathEdit->text());
|
||||
appSettings->setValue(kAwkPathKey, awkPathEdit->text());
|
||||
|
||||
OstProtoLib::setExternalApplicationPaths(
|
||||
appSettings->value(kTsharkPathKey, kTsharkPathDefaultValue).toString(),
|
||||
appSettings->value(kGzipPathKey, kGzipPathDefaultValue).toString(),
|
||||
appSettings->value(kDiffPathKey, kDiffPathDefaultValue).toString(),
|
||||
appSettings->value(kAwkPathKey, kAwkPathDefaultValue).toString());
|
||||
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
void Preferences::on_wiresharkPathButton_clicked()
|
||||
{
|
||||
QString path;
|
||||
|
||||
path = QFileDialog::getOpenFileName(0, "Locate Wireshark",
|
||||
wiresharkPathEdit->text());
|
||||
|
||||
if (!path.isEmpty())
|
||||
wiresharkPathEdit->setText(path);
|
||||
}
|
||||
|
||||
void Preferences::on_tsharkPathButton_clicked()
|
||||
{
|
||||
QString path;
|
||||
|
||||
path = QFileDialog::getOpenFileName(0, "Locate tshark",
|
||||
tsharkPathEdit->text());
|
||||
|
||||
if (!path.isEmpty())
|
||||
tsharkPathEdit->setText(path);
|
||||
}
|
||||
|
||||
void Preferences::on_gzipPathButton_clicked()
|
||||
{
|
||||
QString path;
|
||||
|
||||
path = QFileDialog::getOpenFileName(0, "Locate gzip",
|
||||
gzipPathEdit->text());
|
||||
|
||||
if (!path.isEmpty())
|
||||
gzipPathEdit->setText(path);
|
||||
}
|
||||
|
||||
void Preferences::on_diffPathButton_clicked()
|
||||
{
|
||||
QString path;
|
||||
|
||||
path = QFileDialog::getOpenFileName(0, "Locate diff",
|
||||
diffPathEdit->text());
|
||||
|
||||
if (!path.isEmpty())
|
||||
diffPathEdit->setText(path);
|
||||
}
|
||||
|
||||
void Preferences::on_awkPathButton_clicked()
|
||||
{
|
||||
QString path;
|
||||
|
||||
path = QFileDialog::getOpenFileName(0, "Locate awk",
|
||||
awkPathEdit->text());
|
||||
|
||||
if (!path.isEmpty())
|
||||
awkPathEdit->setText(path);
|
||||
}
|
45
client/preferences.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
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 _PREFERENCES_H
|
||||
#define _PREFERENCES_H
|
||||
|
||||
#include "ui_preferences.h"
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class Preferences : public QDialog, private Ui::Preferences
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Preferences();
|
||||
~Preferences();
|
||||
|
||||
public slots:
|
||||
void accept();
|
||||
|
||||
private slots:
|
||||
void on_wiresharkPathButton_clicked();
|
||||
void on_tsharkPathButton_clicked();
|
||||
void on_gzipPathButton_clicked();
|
||||
void on_diffPathButton_clicked();
|
||||
void on_awkPathButton_clicked();
|
||||
};
|
||||
|
||||
#endif
|
226
client/preferences.ui
Normal file
@ -0,0 +1,226 @@
|
||||
<ui version="4.0" >
|
||||
<class>Preferences</class>
|
||||
<widget class="QDialog" name="Preferences" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>220</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Preferences</string>
|
||||
</property>
|
||||
<property name="windowIcon" >
|
||||
<iconset resource="ostinato.qrc" >:/icons/preferences.png</iconset>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QFrame" name="frame" >
|
||||
<property name="frameShape" >
|
||||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
<property name="frameShadow" >
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<string>'wireshark' Path</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>wiresharkPathEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLineEdit" name="wiresharkPathEdit" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<widget class="QToolButton" name="wiresharkPathButton" >
|
||||
<property name="text" >
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<string>'tshark' Path</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>tsharkPathEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLineEdit" name="tsharkPathEdit" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" >
|
||||
<widget class="QToolButton" name="tsharkPathButton" >
|
||||
<property name="text" >
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QLabel" name="label_5" >
|
||||
<property name="text" >
|
||||
<string>'gzip' Path</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>diffPathEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" >
|
||||
<widget class="QLineEdit" name="gzipPathEdit" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2" >
|
||||
<widget class="QToolButton" name="gzipPathButton" >
|
||||
<property name="text" >
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" >
|
||||
<widget class="QLabel" name="label_3" >
|
||||
<property name="text" >
|
||||
<string>'diff' Path</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>diffPathEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" >
|
||||
<widget class="QLineEdit" name="diffPathEdit" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2" >
|
||||
<widget class="QToolButton" name="diffPathButton" >
|
||||
<property name="text" >
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" >
|
||||
<widget class="QLabel" name="label_4" >
|
||||
<property name="text" >
|
||||
<string>'awk' Path</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>awkPathEdit</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" >
|
||||
<widget class="QLineEdit" name="awkPathEdit" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2" >
|
||||
<widget class="QToolButton" name="awkPathButton" >
|
||||
<property name="text" >
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>21</width>
|
||||
<height>61</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</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>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>wiresharkPathEdit</tabstop>
|
||||
<tabstop>wiresharkPathButton</tabstop>
|
||||
<tabstop>tsharkPathEdit</tabstop>
|
||||
<tabstop>tsharkPathButton</tabstop>
|
||||
<tabstop>gzipPathEdit</tabstop>
|
||||
<tabstop>gzipPathButton</tabstop>
|
||||
<tabstop>diffPathEdit</tabstop>
|
||||
<tabstop>diffPathButton</tabstop>
|
||||
<tabstop>awkPathEdit</tabstop>
|
||||
<tabstop>awkPathButton</tabstop>
|
||||
<tabstop>buttonBox</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="ostinato.qrc" />
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>Preferences</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>Preferences</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel" >
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel" >
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
86
client/settings.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
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 _SETTINGS_H
|
||||
#define _SETTINGS_H
|
||||
|
||||
#include <QSettings>
|
||||
#include <QString>
|
||||
|
||||
extern QSettings *appSettings;
|
||||
|
||||
const QString kWiresharkPathKey("WiresharkPath");
|
||||
#if defined(Q_OS_WIN32)
|
||||
const QString kWiresharkPathDefaultValue(
|
||||
"C:/Program Files/Wireshark/wireshark.exe");
|
||||
#elif defined(Q_OS_MAC)
|
||||
const QString kWiresharkPathDefaultValue(
|
||||
"/Applications/Wireshark.app/Contents/Resources/bin/wireshark");
|
||||
#else
|
||||
const QString kWiresharkPathDefaultValue("/usr/bin/wireshark");
|
||||
#endif
|
||||
|
||||
const QString kTsharkPathKey("TsharkPath");
|
||||
#if defined(Q_OS_WIN32)
|
||||
const QString kTsharkPathDefaultValue(
|
||||
"C:/Program Files/Wireshark/tshark.exe");
|
||||
#elif defined(Q_OS_MAC)
|
||||
const QString kTsharkPathDefaultValue(
|
||||
"/Applications/Wireshark.app/Contents/Resources/bin/tshark");
|
||||
#else
|
||||
const QString kTsharkPathDefaultValue("/usr/bin/tshark");
|
||||
#endif
|
||||
|
||||
const QString kGzipPathKey("GzipPath");
|
||||
#if defined(Q_OS_WIN32)
|
||||
extern QString kGzipPathDefaultValue;
|
||||
#elif defined(Q_OS_MAC)
|
||||
const QString kGzipPathDefaultValue("/usr/bin/gzip");
|
||||
#else
|
||||
const QString kGzipPathDefaultValue("/usr/bin/gzip");
|
||||
#endif
|
||||
|
||||
const QString kDiffPathKey("DiffPath");
|
||||
#if defined(Q_OS_WIN32)
|
||||
extern QString kDiffPathDefaultValue;
|
||||
#elif defined(Q_OS_MAC)
|
||||
const QString kDiffPathDefaultValue("/usr/bin/diff");
|
||||
#else
|
||||
const QString kDiffPathDefaultValue("/usr/bin/diff");
|
||||
#endif
|
||||
|
||||
const QString kAwkPathKey("AwkPath");
|
||||
#if defined(Q_OS_WIN32)
|
||||
extern QString kAwkPathDefaultValue;
|
||||
#elif defined(Q_OS_MAC)
|
||||
const QString kAwkPathDefaultValue("/usr/bin/awk");
|
||||
#else
|
||||
const QString kAwkPathDefaultValue("/usr/bin/awk");
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// LastUse Section Keys
|
||||
//
|
||||
const QString kApplicationWindowGeometryKey("LastUse/ApplicationWindowGeometry");
|
||||
const QString kApplicationWindowLayout("LastUse/ApplicationWindowLayout");
|
||||
|
||||
#endif
|
||||
|
||||
|
79
client/stream.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
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 <qendian.h>
|
||||
#include <QHostAddress>
|
||||
|
||||
#include "stream.h"
|
||||
//#include "../common/protocollist.h"
|
||||
#include "../common/protocollistiterator.h"
|
||||
#include "../common/abstractprotocol.h"
|
||||
|
||||
Stream::Stream()
|
||||
{
|
||||
//mId = 0xFFFFFFFF;
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
Stream::~Stream()
|
||||
{
|
||||
}
|
||||
|
||||
void Stream::loadProtocolWidgets()
|
||||
{
|
||||
#if 0
|
||||
//protocols.loadConfigWidgets();
|
||||
foreach(AbstractProtocol* proto, *currentFrameProtocols)
|
||||
{
|
||||
proto->loadConfigWidget();
|
||||
}
|
||||
#else
|
||||
ProtocolListIterator *iter;
|
||||
|
||||
iter = createProtocolListIterator();
|
||||
while (iter->hasNext())
|
||||
{
|
||||
AbstractProtocol* p = iter->next();
|
||||
p->loadConfigWidget();
|
||||
}
|
||||
delete iter;
|
||||
#endif
|
||||
}
|
||||
|
||||
void Stream::storeProtocolWidgets()
|
||||
{
|
||||
#if 0
|
||||
//protocols.storeConfigWidgets();
|
||||
foreach(const AbstractProtocol* proto, frameProtocol())
|
||||
{
|
||||
proto->storeConfigWidget();
|
||||
_iter->toFront();
|
||||
}
|
||||
#else
|
||||
ProtocolListIterator *iter;
|
||||
|
||||
iter = createProtocolListIterator();
|
||||
while (iter->hasNext())
|
||||
{
|
||||
AbstractProtocol* p = iter->next();
|
||||
p->storeConfigWidget();
|
||||
}
|
||||
delete iter;
|
||||
#endif
|
||||
}
|
42
client/stream.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
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 _STREAM_H
|
||||
#define _STREAM_H
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
|
||||
#include "../common/protocol.pb.h"
|
||||
#include "../common/streambase.h"
|
||||
|
||||
class Stream : public StreamBase {
|
||||
|
||||
//quint32 mId;
|
||||
|
||||
public:
|
||||
Stream();
|
||||
~Stream();
|
||||
|
||||
void loadProtocolWidgets();
|
||||
void storeProtocolWidgets();
|
||||
};
|
||||
|
||||
#endif
|
1143
client/streamconfigdialog.cpp
Normal file
146
client/streamconfigdialog.h
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
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 _STREAM_CONFIG_DIALOG_H
|
||||
#define _STREAM_CONFIG_DIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include "ui_streamconfigdialog.h"
|
||||
#include "port.h"
|
||||
#include "stream.h"
|
||||
#include "packetmodel.h"
|
||||
#include "modeltest.h"
|
||||
|
||||
#define MAX_MAC_ITER_COUNT 256
|
||||
#define MIN_PKT_LEN 64
|
||||
#define MAX_PKT_LEN 16384
|
||||
|
||||
/*
|
||||
** TODO
|
||||
** \todo Improve HexStr handling
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
class StreamConfigDialog : public QDialog, public Ui::StreamConfigDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
StreamConfigDialog(Port &port, uint streamIndex, QWidget *parent = 0);
|
||||
~StreamConfigDialog();
|
||||
|
||||
private:
|
||||
|
||||
enum ButtonId
|
||||
{
|
||||
ButtonIdNone = 0,
|
||||
ButtonIdOther = -2
|
||||
};
|
||||
|
||||
enum ProtoButtonGroup
|
||||
{
|
||||
ProtoMin,
|
||||
ProtoL1 = 0,
|
||||
ProtoVlan = 1,
|
||||
ProtoL2 = 2,
|
||||
ProtoL3 = 3,
|
||||
ProtoL4 = 4,
|
||||
ProtoL5 = 5,
|
||||
ProtoPayload = 6,
|
||||
ProtoMax
|
||||
};
|
||||
|
||||
QButtonGroup *bgProto[ProtoMax];
|
||||
|
||||
QStringListModel *mpAvailableProtocolsModel;
|
||||
QStringListModel *mpSelectedProtocolsModel;
|
||||
|
||||
Port& mPort;
|
||||
uint mCurrentStreamIndex;
|
||||
|
||||
Stream *mpStream;
|
||||
ProtocolListIterator *_iter;
|
||||
|
||||
bool isUpdateInProgress;
|
||||
|
||||
PacketModel *mpPacketModel;
|
||||
ModelTest *mpPacketModelTester;
|
||||
|
||||
// The following static variables are used to track the "selected" tab
|
||||
// for the various tab widgets so that it can be restored when the dialog
|
||||
// is opened the next time. We also track the last Dialog geometry.
|
||||
static QRect lastGeometry;
|
||||
static int lastTopLevelTabIndex;
|
||||
static int lastProtocolDataIndex;
|
||||
|
||||
void setupUiExtra();
|
||||
void LoadCurrentStream();
|
||||
void StoreCurrentStream();
|
||||
|
||||
private slots:
|
||||
void on_cmbPktLenMode_currentIndexChanged(QString mode);
|
||||
void update_NumPacketsAndNumBursts();
|
||||
|
||||
void on_twTopLevel_currentChanged(int index);
|
||||
void on_tbSelectProtocols_currentChanged(int index);
|
||||
|
||||
// "Simple" Protocol Selection related
|
||||
bool skipProtocols(int layer);
|
||||
|
||||
void disableProtocols(QButtonGroup *protocolGroup, bool checked);
|
||||
void forceProtocolNone(bool checked);
|
||||
|
||||
void updateProtocol(int newId);
|
||||
void __updateProtocol(int level, int newId);
|
||||
|
||||
void updateSelectProtocolsSimpleWidget();
|
||||
|
||||
// "Advanced" Protocol Selection related
|
||||
void when_lvAllProtocols_selectionChanged(
|
||||
const QItemSelection &selected, const QItemSelection &deselected);
|
||||
void when_lvSelectedProtocols_currentChanged(
|
||||
const QModelIndex ¤t, const QModelIndex &previous);
|
||||
|
||||
void on_tbAdd_clicked();
|
||||
void on_tbDelete_clicked();
|
||||
void on_tbUp_clicked();
|
||||
void on_tbDown_clicked();
|
||||
|
||||
void updateSelectProtocolsAdvancedWidget();
|
||||
|
||||
// "Protocol Data" related
|
||||
void on_tbProtocolData_currentChanged(int index);
|
||||
|
||||
// "Stream Control" related
|
||||
void on_rbPacketsPerSec_toggled(bool checked);
|
||||
void on_rbBurstsPerSec_toggled(bool checked);
|
||||
|
||||
void on_lePacketsPerBurst_textChanged(const QString &text);
|
||||
void on_lePacketsPerSec_textChanged(const QString &text);
|
||||
void on_leBurstsPerSec_textChanged(const QString &text);
|
||||
void on_leBitsPerSec_textEdited(const QString &text);
|
||||
|
||||
void on_pbPrev_clicked();
|
||||
void on_pbNext_clicked();
|
||||
|
||||
void on_pbOk_clicked();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
1462
client/streamconfigdialog.ui
Normal file
194
client/streamlistdelegate.cpp
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
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 <QComboBox>
|
||||
#include <QCheckBox>
|
||||
#include <QApplication>
|
||||
#include <QMouseEvent>
|
||||
|
||||
#include "streammodel.h"
|
||||
#include "streamlistdelegate.h"
|
||||
|
||||
StreamListDelegate::StreamListDelegate(QObject *parent)
|
||||
: QItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QWidget *StreamListDelegate::createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
QWidget *editor = NULL;
|
||||
|
||||
switch ((StreamModel::StreamFields) index.column())
|
||||
{
|
||||
case StreamModel::StreamStatus:
|
||||
{
|
||||
editor = new QCheckBox(parent);
|
||||
goto _handled;
|
||||
}
|
||||
case StreamModel::StreamNextWhat:
|
||||
{
|
||||
editor = new QComboBox(parent);
|
||||
static_cast<QComboBox*>(editor)->insertItems(0,
|
||||
StreamModel::nextWhatOptionList());
|
||||
goto _handled;
|
||||
}
|
||||
|
||||
case StreamModel::StreamIcon:
|
||||
case StreamModel::StreamName:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
editor = QItemDelegate::createEditor(parent, option, index);
|
||||
|
||||
_handled:
|
||||
return editor;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void StreamListDelegate::setEditorData(QWidget *editor,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
switch ((StreamModel::StreamFields) index.column())
|
||||
{
|
||||
case StreamModel::StreamStatus:
|
||||
{
|
||||
QCheckBox *cb = static_cast<QCheckBox*>(editor);
|
||||
cb->setChecked(
|
||||
index.model()->data(index, Qt::EditRole).toBool());
|
||||
goto _handled;
|
||||
}
|
||||
case StreamModel::StreamNextWhat:
|
||||
{
|
||||
QComboBox *cb = static_cast<QComboBox*>(editor);
|
||||
cb->setCurrentIndex(
|
||||
index.model()->data(index, Qt::EditRole).toInt());
|
||||
goto _handled;
|
||||
}
|
||||
|
||||
case StreamModel::StreamIcon:
|
||||
case StreamModel::StreamName:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
QItemDelegate::setEditorData(editor, index);
|
||||
|
||||
_handled:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void StreamListDelegate::setModelData(QWidget *editor,
|
||||
QAbstractItemModel *model, const QModelIndex &index) const
|
||||
{
|
||||
switch ((StreamModel::StreamFields) index.column())
|
||||
{
|
||||
case StreamModel::StreamStatus:
|
||||
{
|
||||
QCheckBox *cb = static_cast<QCheckBox*>(editor);
|
||||
model->setData(index, cb->isChecked(), Qt::EditRole);
|
||||
goto _handled;
|
||||
}
|
||||
|
||||
case StreamModel::StreamNextWhat:
|
||||
{
|
||||
QComboBox *cb = static_cast<QComboBox*>(editor);
|
||||
model->setData(index, cb->currentIndex(), Qt::EditRole);
|
||||
goto _handled;
|
||||
}
|
||||
|
||||
case StreamModel::StreamIcon:
|
||||
case StreamModel::StreamName:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
QItemDelegate::setModelData(editor, model, index);
|
||||
|
||||
_handled:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void StreamListDelegate::updateEditorGeometry(QWidget *editor,
|
||||
const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
switch ((StreamModel::StreamFields) index.column())
|
||||
{
|
||||
case StreamModel::StreamStatus:
|
||||
{
|
||||
/*
|
||||
* extra 'coz QItemDelegate does it - otherwise the editor
|
||||
* placement is incorrect
|
||||
*/
|
||||
int extra = 2 * (qApp->style()->pixelMetric(
|
||||
QStyle::PM_FocusFrameHMargin, 0) + 1);
|
||||
|
||||
editor->setGeometry(option.rect.translated(extra, 0));
|
||||
goto _handled;
|
||||
}
|
||||
case StreamModel::StreamIcon:
|
||||
case StreamModel::StreamName:
|
||||
case StreamModel::StreamNextWhat:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
QItemDelegate::updateEditorGeometry(editor, option, index);
|
||||
|
||||
_handled:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool StreamListDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||
const QStyleOptionViewItem &option, const QModelIndex &index)
|
||||
{
|
||||
/*
|
||||
* Special Handling so that user can use the "Stream status" checkbox
|
||||
* without double clicking first. Copied from QItemDelegate::editorEvent()
|
||||
* and modified suitably
|
||||
*/
|
||||
if ((StreamModel::StreamFields)index.column() ==
|
||||
StreamModel::StreamStatus)
|
||||
{
|
||||
// make sure that we have the right event type
|
||||
if ((event->type() == QEvent::MouseButtonRelease)
|
||||
|| (event->type() == QEvent::MouseButtonDblClick))
|
||||
{
|
||||
QRect checkRect = check(option, option.rect, Qt::Checked);
|
||||
QRect emptyRect;
|
||||
doLayout(option, &checkRect, &emptyRect, &emptyRect, false);
|
||||
if (!checkRect.contains(static_cast<QMouseEvent*>(event)->pos()))
|
||||
return false;
|
||||
|
||||
Qt::CheckState state = (static_cast<Qt::CheckState>(index.data(
|
||||
Qt::CheckStateRole).toInt()) == Qt::Checked ? Qt::Unchecked : Qt::Checked);
|
||||
return model->setData(index, state, Qt::CheckStateRole);
|
||||
}
|
||||
}
|
||||
|
||||
return QItemDelegate::editorEvent(event, model, option, index);
|
||||
}
|
||||
|
48
client/streamlistdelegate.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
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 STREAM_LIST_DELEGATE_H
|
||||
#define STREAM_LIST_DELEGATE_H
|
||||
|
||||
#include <QItemDelegate>
|
||||
#include <QModelIndex>
|
||||
|
||||
class StreamListDelegate : public QItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
StreamListDelegate(QObject *parent = 0);
|
||||
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const;
|
||||
|
||||
void setEditorData(QWidget *editor, const QModelIndex &index) const;
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const;
|
||||
|
||||
void updateEditorGeometry(QWidget *editor,
|
||||
const QStyleOptionViewItem &option, const QModelIndex &index) const;
|
||||
|
||||
bool editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||
const QStyleOptionViewItem &option, const QModelIndex &index);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
288
client/streammodel.cpp
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
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 "stream.h"
|
||||
#include "streammodel.h"
|
||||
#include "portgrouplist.h"
|
||||
#include "qicon.h"
|
||||
|
||||
StreamModel::StreamModel(PortGroupList *p, QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
pgl = p;
|
||||
mCurrentPort = NULL;
|
||||
}
|
||||
|
||||
int StreamModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if (parent.isValid())
|
||||
return 0;
|
||||
|
||||
if (mCurrentPort)
|
||||
return mCurrentPort->numStreams();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int StreamModel::columnCount(const QModelIndex &/*parent*/) const
|
||||
{
|
||||
int count = StreamMaxFields;
|
||||
if (mCurrentPort &&
|
||||
(mCurrentPort->transmitMode() == OstProto::kInterleavedTransmit))
|
||||
count--;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
Qt::ItemFlags StreamModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
Qt::ItemFlags flags = QAbstractTableModel::flags(index);
|
||||
|
||||
|
||||
switch (index.column())
|
||||
{
|
||||
case StreamIcon:
|
||||
break;
|
||||
case StreamName:
|
||||
flags |= Qt::ItemIsEditable;
|
||||
break;
|
||||
case StreamStatus:
|
||||
flags |= Qt::ItemIsUserCheckable;
|
||||
break;
|
||||
case StreamNextWhat:
|
||||
flags |= Qt::ItemIsEditable;
|
||||
break;
|
||||
default:
|
||||
//qFatal("Missed case in switch!");
|
||||
break;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
QVariant StreamModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
// Check for a valid index
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
// Check for row/column limits
|
||||
if (index.row() >= mCurrentPort->numStreams())
|
||||
return QVariant();
|
||||
|
||||
if (index.column() >= StreamMaxFields)
|
||||
return QVariant();
|
||||
|
||||
if (mCurrentPort == NULL)
|
||||
return QVariant();
|
||||
|
||||
// Return data based on field and role
|
||||
switch(index.column())
|
||||
{
|
||||
case StreamIcon:
|
||||
{
|
||||
if (role == Qt::DecorationRole)
|
||||
return QIcon(":/icons/stream_edit.png");
|
||||
else
|
||||
return QVariant();
|
||||
break;
|
||||
}
|
||||
case StreamName:
|
||||
{
|
||||
if ((role == Qt::DisplayRole) || (role == Qt::EditRole))
|
||||
return mCurrentPort->streamByIndex(index.row())->name();
|
||||
else
|
||||
return QVariant();
|
||||
break;
|
||||
}
|
||||
case StreamStatus:
|
||||
{
|
||||
if ((role == Qt::CheckStateRole))
|
||||
{
|
||||
if (mCurrentPort->streamByIndex(index.row())->isEnabled())
|
||||
return Qt::Checked;
|
||||
else
|
||||
return Qt::Unchecked;
|
||||
}
|
||||
else
|
||||
return QVariant();
|
||||
break;
|
||||
}
|
||||
case StreamNextWhat:
|
||||
{
|
||||
int val = mCurrentPort->streamByIndex(index.row())->nextWhat();
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
return nextWhatOptionList().at(val);
|
||||
else if (role == Qt::EditRole)
|
||||
return val;
|
||||
else
|
||||
return QVariant();
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qFatal("-------------UNHANDLED STREAM FIELD----------------");
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool StreamModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
if (mCurrentPort == NULL)
|
||||
return false;
|
||||
|
||||
if (index.isValid())
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
// Edit Supported Fields
|
||||
case StreamName:
|
||||
mCurrentPort->streamByIndex(index.row())->setName(value.toString());
|
||||
emit(dataChanged(index, index));
|
||||
return true;
|
||||
|
||||
case StreamStatus:
|
||||
mCurrentPort->streamByIndex(index.row())->setEnabled(value.toBool());
|
||||
emit(dataChanged(index, index));
|
||||
return true;
|
||||
|
||||
case StreamNextWhat:
|
||||
if (role == Qt::EditRole)
|
||||
{
|
||||
mCurrentPort->streamByIndex(index.row())->setNextWhat(
|
||||
(Stream::NextWhat)value.toInt());
|
||||
emit(dataChanged(index, index));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
// Edit Not Supported Fields
|
||||
case StreamIcon:
|
||||
return false;
|
||||
|
||||
// Unhandled Stream Field
|
||||
default:
|
||||
qDebug("-------------UNHANDLED STREAM FIELD----------------");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant StreamModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
if (orientation == Qt::Horizontal)
|
||||
{
|
||||
switch(section)
|
||||
{
|
||||
case StreamIcon:
|
||||
return QString("");
|
||||
break;
|
||||
case StreamName:
|
||||
return QString("Name");
|
||||
break;
|
||||
case StreamStatus:
|
||||
return QString("");
|
||||
break;
|
||||
case StreamNextWhat:
|
||||
return QString("Goto");
|
||||
break;
|
||||
default:
|
||||
qDebug("-------------UNHANDLED STREAM FIELD----------------");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
return QString("%1").arg(section+1);
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool StreamModel::insertRows(int row, int count, const QModelIndex &/*parent*/)
|
||||
{
|
||||
qDebug("insertRows() row = %d", row);
|
||||
qDebug("insertRows() count = %d", count);
|
||||
beginInsertRows(QModelIndex(), row, row+count-1);
|
||||
for (int i = 0; i < count; i++)
|
||||
mCurrentPort->newStreamAt(row);
|
||||
endInsertRows();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StreamModel::removeRows(int row, int count, const QModelIndex &/*parent*/)
|
||||
{
|
||||
qDebug("removeRows() row = %d", row);
|
||||
qDebug("removeRows() count = %d", count);
|
||||
beginRemoveRows(QModelIndex(), row, row+count-1);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
mCurrentPort->deleteStreamAt(row);
|
||||
}
|
||||
endRemoveRows();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------- SLOTS ------------------------
|
||||
|
||||
void StreamModel::setCurrentPortIndex(const QModelIndex ¤t)
|
||||
{
|
||||
if (!current.isValid() || !pgl->isPort(current))
|
||||
{
|
||||
qDebug("current is either invalid or not a port");
|
||||
mCurrentPort = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("change to valid port");
|
||||
// Disconnect any existing connection to avoid duplication
|
||||
// Qt 4.6 has Qt::UniqueConnection, but we want to remain compatible
|
||||
// with earlier Qt versions
|
||||
if (mCurrentPort)
|
||||
{
|
||||
disconnect(mCurrentPort, SIGNAL(streamListChanged(int, int)),
|
||||
this, SLOT(when_mCurrentPort_streamListChanged(int, int)));
|
||||
}
|
||||
quint16 pg = current.internalId() >> 16;
|
||||
mCurrentPort = pgl->mPortGroups[pgl->indexOfPortGroup(pg)]->mPorts[current.row()];
|
||||
connect(mCurrentPort, SIGNAL(streamListChanged(int, int)),
|
||||
this, SLOT(when_mCurrentPort_streamListChanged(int, int)));
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
void StreamModel::when_mCurrentPort_streamListChanged(int portGroupId,
|
||||
int portId)
|
||||
{
|
||||
qDebug("In %s", __FUNCTION__);
|
||||
if (mCurrentPort)
|
||||
{
|
||||
if ((quint32(portGroupId) == mCurrentPort->portGroupId())
|
||||
&& (quint32(portId) == mCurrentPort->id()))
|
||||
reset();
|
||||
}
|
||||
}
|
78
client/streammodel.h
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
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 _STREAM_MODEL_H
|
||||
#define _STREAM_MODEL_H
|
||||
|
||||
#include <QStringList>
|
||||
#include <QAbstractTableModel>
|
||||
#include "port.h"
|
||||
|
||||
class PortGroupList;
|
||||
|
||||
class StreamModel : public QAbstractTableModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Port *mCurrentPort;
|
||||
PortGroupList *pgl;
|
||||
|
||||
public:
|
||||
StreamModel(PortGroupList *p, QObject *parent = 0);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
bool setData(const QModelIndex &index, const QVariant &value,
|
||||
int role = Qt::EditRole);
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
bool insertRows (int row, int count,
|
||||
const QModelIndex & parent = QModelIndex());
|
||||
bool removeRows (int row, int count,
|
||||
const QModelIndex & parent = QModelIndex());
|
||||
|
||||
#if 0 // CleanedUp!
|
||||
// FIXME(HIGH): This *is* like a kludge
|
||||
QList<Stream>* currentPortStreamList()
|
||||
{ return &mCurrentPort->mStreams; }
|
||||
#endif
|
||||
|
||||
public:
|
||||
enum StreamFields {
|
||||
StreamIcon = 0,
|
||||
StreamStatus,
|
||||
StreamName,
|
||||
StreamNextWhat,
|
||||
|
||||
StreamMaxFields
|
||||
};
|
||||
|
||||
static QStringList nextWhatOptionList()
|
||||
{ return QStringList() << "Stop" << "Next" << "Goto first"; }
|
||||
|
||||
public slots:
|
||||
void setCurrentPortIndex(const QModelIndex ¤t);
|
||||
|
||||
private slots:
|
||||
void when_mCurrentPort_streamListChanged(int portGroupId, int portId);
|
||||
};
|
||||
|
||||
#endif
|
127
common/abstractfileformat.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
Copyright (C) 2011 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 "abstractfileformat.h"
|
||||
|
||||
#include "fileformat.h"
|
||||
#include "pcapfileformat.h"
|
||||
#include "pdmlfileformat.h"
|
||||
|
||||
#include <QStringList>
|
||||
|
||||
AbstractFileFormat::AbstractFileFormat()
|
||||
{
|
||||
stop_ = false;
|
||||
}
|
||||
|
||||
AbstractFileFormat::~AbstractFileFormat()
|
||||
{
|
||||
}
|
||||
|
||||
QDialog* AbstractFileFormat::openOptionsDialog()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QDialog* AbstractFileFormat::saveOptionsDialog()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
QStringList AbstractFileFormat::supportedFileTypes()
|
||||
{
|
||||
return QStringList()
|
||||
<< "Ostinato (*)"
|
||||
<< "PCAP (*)"
|
||||
<< "PDML (*.pdml)";
|
||||
}
|
||||
|
||||
void AbstractFileFormat::openStreamsOffline(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error)
|
||||
{
|
||||
fileName_ = fileName;
|
||||
openStreams_ = &streams;
|
||||
error_ = &error;
|
||||
op_ = kOpen;
|
||||
stop_ = false;
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
void AbstractFileFormat::saveStreamsOffline(
|
||||
const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error)
|
||||
{
|
||||
saveStreams_ = streams;
|
||||
fileName_ = fileName;
|
||||
error_ = &error;
|
||||
op_ = kSave;
|
||||
stop_ = false;
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
bool AbstractFileFormat::result()
|
||||
{
|
||||
return result_;
|
||||
}
|
||||
|
||||
AbstractFileFormat* AbstractFileFormat::fileFormatFromFile(
|
||||
const QString fileName)
|
||||
{
|
||||
if (fileFormat.isMyFileFormat(fileName))
|
||||
return &fileFormat;
|
||||
|
||||
if (pdmlFileFormat.isMyFileFormat(fileName))
|
||||
return &pdmlFileFormat;
|
||||
|
||||
if (pcapFileFormat.isMyFileFormat(fileName))
|
||||
return &pcapFileFormat;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
AbstractFileFormat* AbstractFileFormat::fileFormatFromType(
|
||||
const QString fileType)
|
||||
{
|
||||
|
||||
if (fileFormat.isMyFileType(fileType))
|
||||
return &fileFormat;
|
||||
|
||||
if (pdmlFileFormat.isMyFileType(fileType))
|
||||
return &pdmlFileFormat;
|
||||
|
||||
if (pcapFileFormat.isMyFileType(fileType))
|
||||
return &pcapFileFormat;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void AbstractFileFormat::cancel()
|
||||
{
|
||||
stop_ = true;
|
||||
}
|
||||
|
||||
void AbstractFileFormat::run()
|
||||
{
|
||||
if (op_ == kOpen)
|
||||
result_ = openStreams(fileName_, *openStreams_, *error_);
|
||||
else if (op_ == kSave)
|
||||
result_ = saveStreams(saveStreams_, fileName_, *error_);
|
||||
}
|
91
common/abstractfileformat.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright (C) 2011 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 _ABSTRACT_FILE_FORMAT_H
|
||||
#define _ABSTRACT_FILE_FORMAT_H
|
||||
|
||||
#include "protocol.pb.h"
|
||||
|
||||
#include <QThread>
|
||||
#include <QString>
|
||||
|
||||
class QDialog;
|
||||
|
||||
class AbstractFileFormat : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
AbstractFileFormat();
|
||||
virtual ~AbstractFileFormat();
|
||||
|
||||
virtual bool openStreams(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error) = 0;
|
||||
virtual bool saveStreams(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error) = 0;
|
||||
|
||||
virtual QDialog* openOptionsDialog();
|
||||
virtual QDialog* saveOptionsDialog();
|
||||
|
||||
void openStreamsOffline(const QString fileName,
|
||||
OstProto::StreamConfigList &streams, QString &error);
|
||||
void saveStreamsOffline(const OstProto::StreamConfigList streams,
|
||||
const QString fileName, QString &error);
|
||||
|
||||
bool result();
|
||||
|
||||
static QStringList supportedFileTypes();
|
||||
|
||||
static AbstractFileFormat* fileFormatFromFile(const QString fileName);
|
||||
static AbstractFileFormat* fileFormatFromType(const QString fileType);
|
||||
|
||||
#if 0
|
||||
bool isMyFileFormat(const QString fileName) = 0;
|
||||
bool isMyFileType(const QString fileType) = 0;
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void status(QString text);
|
||||
void target(int value);
|
||||
void progress(int value);
|
||||
|
||||
public slots:
|
||||
void cancel();
|
||||
|
||||
protected:
|
||||
void run();
|
||||
|
||||
bool stop_;
|
||||
|
||||
private:
|
||||
enum kOp
|
||||
{
|
||||
kOpen,
|
||||
kSave
|
||||
};
|
||||
QString fileName_;
|
||||
OstProto::StreamConfigList *openStreams_;
|
||||
OstProto::StreamConfigList saveStreams_;
|
||||
QString *error_;
|
||||
kOp op_;
|
||||
bool result_;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
928
common/abstractprotocol.cpp
Normal file
@ -0,0 +1,928 @@
|
||||
/*
|
||||
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 <qendian.h>
|
||||
|
||||
#include "abstractprotocol.h"
|
||||
#include "streambase.h"
|
||||
#include "protocollistiterator.h"
|
||||
|
||||
/*!
|
||||
\class AbstractProtocol
|
||||
|
||||
AbstractProtocol is the base abstract class which provides the interface
|
||||
for all protocols.
|
||||
|
||||
All protocols supported by Ostinato are derived from AbstractProtocol. Apart
|
||||
from defining the interface for a protocol, it also provides sensible default
|
||||
implementations for methods so that the subclasses need not re-implement. It
|
||||
also provides convenience functions for subclasses to use such as methods to
|
||||
retrieve payload size, checksum etc.
|
||||
|
||||
A subclass typically needs to reimplement the following methods -
|
||||
- name()
|
||||
- shortName()
|
||||
- createInstance()
|
||||
- protocolNumber()
|
||||
- protoDataCopyInto() [pure virtual]
|
||||
- protoDataCopyFrom() [pure virtual]
|
||||
- fieldCount()
|
||||
- fieldFlags()
|
||||
- fieldData()
|
||||
- setFieldData()
|
||||
- configWidget() [pure virtual]
|
||||
- loadConfigWidget() [pure virtual]
|
||||
- storeConfigWidget() [pure virtual]
|
||||
|
||||
Depending on certain conditions, subclasses may need to reimplement the
|
||||
following additional methods -
|
||||
- protocolIdType()
|
||||
- protocolId()
|
||||
- protocolFrameSize()
|
||||
- isProtocolFrameValueVariable()
|
||||
- isProtocolFrameSizeVariable()
|
||||
- protocolFrameVariableCount()
|
||||
|
||||
See the description of the methods for more information.
|
||||
|
||||
Most of the above methods just need some standard boilerplate code -
|
||||
the SampleProtocol implementation includes the boilerplate
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs an abstract protocol for the given stream and parent
|
||||
|
||||
parent is typically NULL except for protocols which are part of a
|
||||
ComboProtocol
|
||||
*/
|
||||
AbstractProtocol::AbstractProtocol(StreamBase *stream, AbstractProtocol *parent)
|
||||
{
|
||||
//qDebug("%s: &prev = %p &next = %p", __FUNCTION__, &prev, &next);
|
||||
mpStream = stream;
|
||||
this->parent = parent;
|
||||
prev = next = NULL;
|
||||
_metaFieldCount = -1;
|
||||
_frameFieldCount = -1;
|
||||
protoSize = -1;
|
||||
_hasPayload = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys the abstract protocol
|
||||
*/
|
||||
AbstractProtocol::~AbstractProtocol()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Allocates and returns a new instance of the class.
|
||||
|
||||
Caller is responsible for freeing up after use. Subclasses MUST implement
|
||||
this function
|
||||
*/
|
||||
AbstractProtocol* AbstractProtocol::createInstance(StreamBase* /* stream */,
|
||||
AbstractProtocol* /* parent */)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the protocol's field number as defined in message 'Protocol', enum 'k'
|
||||
(file: protocol.proto)
|
||||
|
||||
Subclasses MUST implement this function
|
||||
*/
|
||||
quint32 AbstractProtocol::protocolNumber() const
|
||||
{
|
||||
qFatal("Something wrong!!!");
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn virtual void AbstractProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const = 0
|
||||
|
||||
Copy the protocol's protobuf as an extension into the passed in protocol
|
||||
|
||||
In the base class this is a pure virtual function. Subclasses MUST implement
|
||||
this function. See the SampleProtocol for an example
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
\fn virtual void AbstractProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol) = 0
|
||||
|
||||
Copy and update the protocol's protobuf member data variable from the
|
||||
passed in protocol
|
||||
|
||||
In the base class this is a pure virtual function. Subclasses MUST implement
|
||||
this function. See the SampleProtocol for an example
|
||||
*/
|
||||
|
||||
|
||||
/*!
|
||||
Returns the full name of the protocol
|
||||
|
||||
The default implementation returns a null string
|
||||
*/
|
||||
QString AbstractProtocol::name() const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the short name or abbreviation of the protocol
|
||||
|
||||
The default implementation forms and returns an abbreviation composed
|
||||
of all the upper case chars in name() \n
|
||||
The default implementation caches the abbreviation on its first invocation
|
||||
and subsequently returns the cached abbreviation
|
||||
*/
|
||||
QString AbstractProtocol::shortName() const
|
||||
{
|
||||
if (protoAbbr.isNull())
|
||||
{
|
||||
QString abbr;
|
||||
|
||||
for (int i = 0; i < name().size(); i++)
|
||||
if (name().at(i).isUpper()) abbr.append(name().at(i));
|
||||
|
||||
if (abbr.size())
|
||||
protoAbbr = abbr;
|
||||
else
|
||||
protoAbbr = QString("");
|
||||
}
|
||||
|
||||
return protoAbbr;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the number of fields in the protocol (both Frame fields and
|
||||
Meta fields)
|
||||
|
||||
The default implementation returns zero. Subclasses MUST implement this
|
||||
function.
|
||||
*/
|
||||
int AbstractProtocol::fieldCount() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the number of meta fields
|
||||
|
||||
The default implementation counts and returns the number of fields for which
|
||||
the MetaField flag is set\n
|
||||
The default implementation caches the count on its first invocation
|
||||
and subsequently returns the cached count
|
||||
*/
|
||||
int AbstractProtocol::metaFieldCount() const
|
||||
{
|
||||
if (_metaFieldCount < 0)
|
||||
{
|
||||
int c = 0;
|
||||
for (int i = 0; i < fieldCount() ; i++)
|
||||
if (fieldFlags(i).testFlag(MetaField))
|
||||
c++;
|
||||
_metaFieldCount = c;
|
||||
}
|
||||
|
||||
return _metaFieldCount;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the number of frame fields
|
||||
|
||||
The default implementation counts and returns the number of fields for which
|
||||
the FrameField flag is set\n
|
||||
The default implementation caches the count on its first invocation
|
||||
and subsequently returns the cached count
|
||||
|
||||
Subclasses which export different sets of fields based on a opcode/type
|
||||
(e.g. icmp) should re-implement this function
|
||||
*/
|
||||
int AbstractProtocol::frameFieldCount() const
|
||||
{
|
||||
if (_frameFieldCount < 0)
|
||||
{
|
||||
int c = 0;
|
||||
for (int i = 0; i < fieldCount() ; i++)
|
||||
if (fieldFlags(i).testFlag(FrameField))
|
||||
c++;
|
||||
_frameFieldCount = c;
|
||||
}
|
||||
|
||||
return _frameFieldCount;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the field flags for the passed in field index
|
||||
|
||||
The default implementation assumes all fields to be frame fields and returns
|
||||
'FrameField'. Subclasses must reimplement this method if they have any
|
||||
meta fields or checksum fields. See the SampleProtocol for an example.
|
||||
*/
|
||||
AbstractProtocol::FieldFlags AbstractProtocol::fieldFlags(int /*index*/) const
|
||||
{
|
||||
return FrameField;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the requested field attribute data
|
||||
|
||||
Protocols which have meta fields that vary a frame field across
|
||||
streams may use the streamIndex to return the appropriate field value \n
|
||||
Some field attributes e.g. FieldName may be invariant across streams\n
|
||||
The FieldTextValue attribute may include additional information about
|
||||
the field's value e.g. a checksum field may include "(correct)" or
|
||||
"(incorrect)" alongwith the actual checksum value. \n
|
||||
|
||||
The default implementation returns a empty string for FieldName and
|
||||
FieldTextValue; empty byte array of size 0 for FieldFrameValue; 0 for
|
||||
FieldValue; subclasses are expected to return meaning values for all
|
||||
these attributes. The only exception is the 'FieldBitSize' attribute -
|
||||
the default implementation takes the (byte) size of FieldFrameValue,
|
||||
multiplies it with 8 and returns the result - this can be used by
|
||||
subclasses for fields which are an integral multiple of bytes; for
|
||||
fields whose size are a non-integral multiple of bytes or smaller than
|
||||
a byte, subclasses should return the correct value. Also for fields
|
||||
which represent checksums, subclasses should return a value for
|
||||
FieldBitSize - even if it is an integral multiple of bytes.
|
||||
|
||||
\note If a subclass uses any of the below functions to derive
|
||||
FieldFrameValue, the subclass should handle and return a value for
|
||||
FieldBitSize to prevent endless recursion -
|
||||
- protocolFrameCksum()
|
||||
- protocolFramePayloadSize()
|
||||
*/
|
||||
QVariant AbstractProtocol::fieldData(int index, FieldAttrib attrib,
|
||||
int streamIndex) const
|
||||
{
|
||||
switch (attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString();
|
||||
case FieldBitSize:
|
||||
Q_ASSERT_X(!fieldFlags(index).testFlag(CksumField),
|
||||
"AbstractProtocol::fieldData()",
|
||||
"FieldBitSize for checksum fields need to be handled by the subclass");
|
||||
return fieldData(index, FieldFrameValue, streamIndex).
|
||||
toByteArray().size() * 8;
|
||||
case FieldValue:
|
||||
return 0;
|
||||
case FieldFrameValue:
|
||||
return QByteArray();
|
||||
case FieldTextValue:
|
||||
return QString();
|
||||
|
||||
default:
|
||||
qFatal("%s:%d: unhandled case %d\n", __FUNCTION__, __LINE__,
|
||||
attrib);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the value of a field corresponding to index
|
||||
|
||||
This method is called by the GUI code to store a user specified value into
|
||||
the protocol's protoBuf. Currently this method is called with
|
||||
FieldAttrib = FieldValue only.
|
||||
|
||||
Returns true if field is successfully set, false otherwise.
|
||||
The default implementation always returns false. Subclasses should
|
||||
reimplement this method. See SampleProtocol for an example.
|
||||
|
||||
*/
|
||||
bool AbstractProtocol::setFieldData(int /*index*/, const QVariant& /*value*/,
|
||||
FieldAttrib /*attrib*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the protocolIdType for the protocol
|
||||
|
||||
The default implementation returns ProtocolIdNone. If a subclass has a
|
||||
protocolId field it should return the appropriate value e.g. IP protocol
|
||||
will return ProtocolIdIp, Ethernet will return ProtocolIdEth etc.
|
||||
*/
|
||||
AbstractProtocol::ProtocolIdType AbstractProtocol::protocolIdType() const
|
||||
{
|
||||
return ProtocolIdNone;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the protocol id of the protocol for the given type
|
||||
|
||||
The default implementation returns 0. If a subclass represents a protocol
|
||||
which has a particular protocol id, it should return the appropriate value.
|
||||
If a protocol does not have an id for the given type, it should defer to
|
||||
the base class. e.g. IGMP will return 2 for ProtocolIdIp, and defer to the
|
||||
base class for the remaining ProtocolIdTypes; IP will return 0x800 for
|
||||
ProtocolIdEth type, 0x060603 for ProtocolIdLlc and 0x04 for ProtocolIdIp etc.
|
||||
*/
|
||||
quint32 AbstractProtocol::protocolId(ProtocolIdType /*type*/) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the protocol id of the payload protocol (the protocol that
|
||||
immediately follows the current one)
|
||||
|
||||
A subclass which has a protocol id field, can use this to retrieve the
|
||||
appropriate value
|
||||
*/
|
||||
quint32 AbstractProtocol::payloadProtocolId(ProtocolIdType type) const
|
||||
{
|
||||
quint32 id;
|
||||
|
||||
if (next)
|
||||
id = next->protocolId(type);
|
||||
else if (parent)
|
||||
id = parent->payloadProtocolId(type);
|
||||
else
|
||||
id = 0xFFFFFFFF;
|
||||
|
||||
qDebug("%s: payloadProtocolId = 0x%x", __FUNCTION__, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the protocol's size in bytes
|
||||
|
||||
The default implementation sums up the individual field bit sizes and
|
||||
returns it. The default implementation calculates the caches the size on
|
||||
the first invocation and subsequently returns the cached size.
|
||||
|
||||
If the subclass protocol has a varying protocol size, it MUST reimplement
|
||||
this method, otherwise the default implementation is sufficient.
|
||||
*/
|
||||
int AbstractProtocol::protocolFrameSize(int streamIndex) const
|
||||
{
|
||||
if (protoSize < 0)
|
||||
{
|
||||
int bitsize = 0;
|
||||
|
||||
for (int i = 0; i < fieldCount(); i++)
|
||||
{
|
||||
if (fieldFlags(i).testFlag(FrameField))
|
||||
bitsize += fieldData(i, FieldBitSize, streamIndex).toUInt();
|
||||
}
|
||||
protoSize = (bitsize+7)/8;
|
||||
}
|
||||
|
||||
qDebug("%s: protoSize = %d", __FUNCTION__, protoSize);
|
||||
return protoSize;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the byte offset in the packet where the protocol starts
|
||||
|
||||
This method is useful only for "padding" protocols i.e. protocols which
|
||||
fill up the remaining space for the user defined packet size e.g. the
|
||||
PatternPayload protocol
|
||||
*/
|
||||
int AbstractProtocol::protocolFrameOffset(int streamIndex) const
|
||||
{
|
||||
int size = 0;
|
||||
AbstractProtocol *p = prev;
|
||||
while (p)
|
||||
{
|
||||
size += p->protocolFrameSize(streamIndex);
|
||||
p = p->prev;
|
||||
}
|
||||
|
||||
if (parent)
|
||||
size += parent->protocolFrameOffset(streamIndex);
|
||||
|
||||
qDebug("%s: ofs = %d", __FUNCTION__, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the size of the payload in bytes. The payload includes all protocols
|
||||
subsequent to the current
|
||||
|
||||
This method is useful for protocols which need to fill in a payload size field
|
||||
*/
|
||||
int AbstractProtocol::protocolFramePayloadSize(int streamIndex) const
|
||||
{
|
||||
int size = 0;
|
||||
AbstractProtocol *p = next;
|
||||
while (p)
|
||||
{
|
||||
size += p->protocolFrameSize(streamIndex);
|
||||
p = p->next;
|
||||
}
|
||||
if (parent)
|
||||
size += parent->protocolFramePayloadSize(streamIndex);
|
||||
|
||||
qDebug("%s: payloadSize = %d", __FUNCTION__, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Returns a byte array encoding the protocol (and its fields) which can be
|
||||
inserted into the stream's frame
|
||||
|
||||
The default implementation forms and returns an ordered concatenation of
|
||||
the FrameValue of all the 'frame' fields of the protocol also taking care of
|
||||
fields which are not an integral number of bytes\n
|
||||
*/
|
||||
QByteArray AbstractProtocol::protocolFrameValue(int streamIndex, bool forCksum) const
|
||||
{
|
||||
QByteArray proto, field;
|
||||
uint bits, lastbitpos = 0;
|
||||
FieldFlags flags;
|
||||
|
||||
for (int i=0; i < fieldCount() ; i++)
|
||||
{
|
||||
flags = fieldFlags(i);
|
||||
if (flags.testFlag(FrameField))
|
||||
{
|
||||
bits = fieldData(i, FieldBitSize, streamIndex).toUInt();
|
||||
if (bits == 0)
|
||||
continue;
|
||||
Q_ASSERT(bits > 0);
|
||||
|
||||
if (forCksum && flags.testFlag(CksumField))
|
||||
{
|
||||
field.resize((bits+7)/8);
|
||||
field.fill('\0');
|
||||
}
|
||||
else
|
||||
field = fieldData(i, FieldFrameValue, streamIndex).toByteArray();
|
||||
qDebug("<<< (%d, %db) %s >>>", proto.size(), lastbitpos,
|
||||
QString(proto.toHex()).toAscii().constData());
|
||||
qDebug(" < %d: (%db/%dB) %s >", i, bits, field.size(),
|
||||
QString(field.toHex()).toAscii().constData());
|
||||
|
||||
if (bits == (uint) field.size() * 8)
|
||||
{
|
||||
if (lastbitpos == 0)
|
||||
proto.append(field);
|
||||
else
|
||||
{
|
||||
Q_ASSERT(field.size() > 0);
|
||||
|
||||
char c = proto[proto.size() - 1];
|
||||
proto[proto.size() - 1] =
|
||||
c | ((uchar)field.at(0) >> lastbitpos);
|
||||
for (int j = 0; j < field.size() - 1; j++)
|
||||
proto.append(field.at(j) << lastbitpos |
|
||||
(uchar)field.at(j+1) >> lastbitpos);
|
||||
proto.append(field.at(field.size() - 1) << lastbitpos);
|
||||
}
|
||||
}
|
||||
else if (bits < (uint) field.size() * 8)
|
||||
{
|
||||
uchar c;
|
||||
uint v;
|
||||
|
||||
v = (field.size()*8) - bits;
|
||||
|
||||
Q_ASSERT(v < 8);
|
||||
|
||||
if (lastbitpos == 0)
|
||||
{
|
||||
for (int j = 0; j < field.size(); j++)
|
||||
{
|
||||
c = field.at(j) << v;
|
||||
if ((j+1) < field.size())
|
||||
c |= ((uchar)field.at(j+1) >> (8-v));
|
||||
proto.append(c);
|
||||
}
|
||||
|
||||
lastbitpos = (lastbitpos + bits) % 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
Q_ASSERT(proto.size() > 0);
|
||||
|
||||
for (int j = 0; j < field.size(); j++)
|
||||
{
|
||||
uchar d;
|
||||
|
||||
c = field.at(j) << v;
|
||||
if ((j+1) < field.size())
|
||||
c |= ((uchar) field.at(j+1) >> (8-v));
|
||||
d = proto[proto.size() - 1];
|
||||
proto[proto.size() - 1] = d | ((uchar) c >> lastbitpos);
|
||||
if (bits > (8*j + (8 - v)))
|
||||
proto.append(c << (8-lastbitpos));
|
||||
}
|
||||
|
||||
lastbitpos = (lastbitpos + bits) % 8;
|
||||
}
|
||||
}
|
||||
else // if (bits > field.size() * 8)
|
||||
{
|
||||
qFatal("bitsize more than FrameValue size. skipping...");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if the protocol varies one or more of its fields at run-time,
|
||||
false otherwise
|
||||
|
||||
The default implementation returns false. A subclass should reimplement
|
||||
if it has varying fields e.g. an IP protocol that increments/decrements
|
||||
the IP address with every packet
|
||||
*/
|
||||
bool AbstractProtocol::isProtocolFrameValueVariable() const
|
||||
{
|
||||
return (protocolFrameVariableCount() > 1);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if the protocol varies its size at run-time, false otherwise
|
||||
|
||||
The default implmentation returns false. A subclass should reimplement
|
||||
if it varies its size at run-time e.g. a Payload protocol for a stream with
|
||||
incrementing/decrementing frame lengths
|
||||
*/
|
||||
bool AbstractProtocol::isProtocolFrameSizeVariable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the minimum number of frames required for the protocol to
|
||||
vary its fields
|
||||
|
||||
This is the lowest common multiple (LCM) of the counts of all the varying
|
||||
fields in the protocol. Use the AbstractProtocol::lcm() static utility
|
||||
function to calculate the LCM.
|
||||
|
||||
The default implementation returns 1 implying that the protocol has no
|
||||
varying fields. A subclass should reimplement if it has varying fields
|
||||
e.g. an IP protocol that increments/decrements the IP address with
|
||||
every packet
|
||||
*/
|
||||
int AbstractProtocol::protocolFrameVariableCount() const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if the payload content for a protocol varies at run-time,
|
||||
false otherwise
|
||||
|
||||
This is useful for subclasses which have fields dependent on payload content
|
||||
(e.g. UDP has a checksum field that varies if the payload varies)
|
||||
*/
|
||||
bool AbstractProtocol::isProtocolFramePayloadValueVariable() const
|
||||
{
|
||||
AbstractProtocol *p = next;
|
||||
|
||||
while (p)
|
||||
{
|
||||
if (p->isProtocolFrameValueVariable())
|
||||
return true;
|
||||
p = p->next;
|
||||
}
|
||||
if (parent && parent->isProtocolFramePayloadValueVariable())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if the payload size for a protocol varies at run-time,
|
||||
false otherwise
|
||||
|
||||
This is useful for subclasses which have fields dependent on payload size
|
||||
(e.g. UDP has a checksum field that varies if the payload varies)
|
||||
*/
|
||||
bool AbstractProtocol::isProtocolFramePayloadSizeVariable() const
|
||||
{
|
||||
AbstractProtocol *p = next;
|
||||
|
||||
while (p)
|
||||
{
|
||||
if (p->isProtocolFrameSizeVariable())
|
||||
return true;
|
||||
p = p->next;
|
||||
}
|
||||
if (parent && parent->isProtocolFramePayloadSizeVariable())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if the payload size for a protocol varies at run-time,
|
||||
false otherwise
|
||||
|
||||
This is useful for subclasses which have fields dependent on payload size
|
||||
(e.g. UDP has a checksum field that varies if the payload varies)
|
||||
*/
|
||||
int AbstractProtocol::protocolFramePayloadVariableCount() const
|
||||
{
|
||||
int count = 1;
|
||||
AbstractProtocol *p = next;
|
||||
|
||||
while (p)
|
||||
{
|
||||
if (p->isProtocolFrameValueVariable()
|
||||
|| p->isProtocolFrameSizeVariable())
|
||||
count = lcm(count, p->protocolFrameVariableCount());
|
||||
p = p->next;
|
||||
}
|
||||
if (parent && (parent->isProtocolFramePayloadValueVariable()
|
||||
|| parent->isProtocolFramePayloadSizeVariable()))
|
||||
count = lcm(count, parent->protocolFramePayloadVariableCount());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if the protocol typically contains a payload or other protocols
|
||||
following it e.g. TCP, UDP have payloads, while ARP, IGMP do not
|
||||
|
||||
The default implementation returns true. If a subclass does not have a
|
||||
payload, it should set the _hasPayload data member to false
|
||||
*/
|
||||
bool AbstractProtocol::protocolHasPayload() const
|
||||
{
|
||||
return _hasPayload;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the checksum (of the requested type) of the protocol's contents
|
||||
|
||||
Useful for protocols which have a checksum field
|
||||
|
||||
\note If a subclass uses protocolFrameCksum() from within fieldData() to
|
||||
derive a cksum field, it MUST handle and return the 'FieldBitSize'
|
||||
attribute also for that particular field instead of using the default
|
||||
AbstractProtocol implementation for 'FieldBitSize' - this is required
|
||||
to prevent infinite recursion
|
||||
*/
|
||||
quint32 AbstractProtocol::protocolFrameCksum(int streamIndex,
|
||||
CksumType cksumType) const
|
||||
{
|
||||
static int recursionCount = 0;
|
||||
quint32 cksum = 0xFFFFFFFF;
|
||||
|
||||
recursionCount++;
|
||||
Q_ASSERT_X(recursionCount < 10, "protocolFrameCksum", "potential infinite recursion - does a protocol checksum field not implement FieldBitSize?");
|
||||
|
||||
switch(cksumType)
|
||||
{
|
||||
case CksumIp:
|
||||
{
|
||||
QByteArray fv;
|
||||
quint16 *ip;
|
||||
quint32 len, sum = 0;
|
||||
|
||||
fv = protocolFrameValue(streamIndex, true);
|
||||
ip = (quint16*) fv.constData();
|
||||
len = fv.size();
|
||||
|
||||
while(len > 1)
|
||||
{
|
||||
sum += *ip;
|
||||
if(sum & 0x80000000)
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
ip++;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
if (len)
|
||||
sum += (unsigned short) *(unsigned char *)ip;
|
||||
|
||||
while(sum>>16)
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
|
||||
cksum = qFromBigEndian((quint16) ~sum);
|
||||
break;
|
||||
}
|
||||
|
||||
case CksumTcpUdp:
|
||||
{
|
||||
quint16 cks;
|
||||
quint32 sum = 0;
|
||||
|
||||
cks = protocolFrameCksum(streamIndex, CksumIp);
|
||||
sum += (quint16) ~cks;
|
||||
cks = protocolFramePayloadCksum(streamIndex, CksumIp);
|
||||
sum += (quint16) ~cks;
|
||||
cks = protocolFrameHeaderCksum(streamIndex, CksumIpPseudo);
|
||||
sum += (quint16) ~cks;
|
||||
|
||||
while(sum>>16)
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
|
||||
cksum = (~sum) & 0xFFFF;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
recursionCount--;
|
||||
return cksum;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the checksum of the requested type for the protocol's header
|
||||
|
||||
This is useful for subclasses which needs the header's checksum e.g. TCP/UDP
|
||||
require a "Pseudo-IP" checksum. The checksum is limited to the specified
|
||||
scope.
|
||||
|
||||
Currently the default implementation supports only type CksumIpPseudo
|
||||
|
||||
\note The default value for cksumScope is different for
|
||||
protocolFrameHeaderCksum() and protocolFramePayloadCksum()
|
||||
*/
|
||||
quint32 AbstractProtocol::protocolFrameHeaderCksum(int streamIndex,
|
||||
CksumType cksumType, CksumScope cksumScope) const
|
||||
{
|
||||
quint32 sum = 0;
|
||||
quint16 cksum;
|
||||
AbstractProtocol *p = prev;
|
||||
|
||||
Q_ASSERT(cksumType == CksumIpPseudo);
|
||||
|
||||
while (p)
|
||||
{
|
||||
cksum = p->protocolFrameCksum(streamIndex, cksumType);
|
||||
sum += (quint16) ~cksum;
|
||||
qDebug("%s: sum = %u, cksum = %u", __FUNCTION__, sum, cksum);
|
||||
if (cksumScope == CksumScopeAdjacentProtocol)
|
||||
goto out;
|
||||
p = p->prev;
|
||||
}
|
||||
if (parent)
|
||||
{
|
||||
cksum = parent->protocolFrameHeaderCksum(streamIndex, cksumType,
|
||||
cksumScope);
|
||||
sum += (quint16) ~cksum;
|
||||
}
|
||||
|
||||
out:
|
||||
while(sum>>16)
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
|
||||
return (quint16) ~sum;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the checksum of the requested type for the protocol's payload
|
||||
|
||||
This is useful for subclasses which needs the payload's checksum e.g. TCP/UDP
|
||||
require a IP checksum of the payload (to be combined with other checksums to
|
||||
derive the final checksum). The checksum is limited to the specified
|
||||
scope.
|
||||
|
||||
Currently the default implementation supports only type CksumIp
|
||||
|
||||
\note The default value for cksumScope is different for
|
||||
protocolFrameHeaderCksum() and protocolFramePayloadCksum()
|
||||
*/
|
||||
quint32 AbstractProtocol::protocolFramePayloadCksum(int streamIndex,
|
||||
CksumType cksumType, CksumScope cksumScope) const
|
||||
{
|
||||
quint32 sum = 0;
|
||||
quint16 cksum;
|
||||
AbstractProtocol *p = next;
|
||||
|
||||
Q_ASSERT(cksumType == CksumIp);
|
||||
|
||||
while (p)
|
||||
{
|
||||
cksum = p->protocolFrameCksum(streamIndex, cksumType);
|
||||
sum += (quint16) ~cksum;
|
||||
if (cksumScope == CksumScopeAdjacentProtocol)
|
||||
goto out;
|
||||
p = p->next;
|
||||
}
|
||||
|
||||
if (parent)
|
||||
{
|
||||
cksum = parent->protocolFramePayloadCksum(streamIndex, cksumType,
|
||||
cksumScope);
|
||||
sum += (quint16) ~cksum;
|
||||
}
|
||||
|
||||
out:
|
||||
while(sum>>16)
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
|
||||
return (quint16) ~sum;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn virtual QWidget* AbstractProtocol::configWidget() = 0;
|
||||
|
||||
Returns the configuration widget for the protocol. The protocol retains
|
||||
ownership of the configuration widget - the caller should not free it.
|
||||
|
||||
In the base class this is a pure virtual function. Subclasses MUST implement
|
||||
this function. See the SampleProtocol for an example
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn virtual void AbstractProtocol::loadConfigWidget() = 0;
|
||||
|
||||
Loads data from the protocol's protobuf into the configuration widget of
|
||||
the protocol
|
||||
|
||||
In the base class this is a pure virtual function. Subclasses MUST implement
|
||||
this function. See the SampleProtocol for an example
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn virtual void AbstractProtocol::storeConfigWidget() = 0;
|
||||
|
||||
Stores data from the configuration widget of the protocol into the protocol's
|
||||
protobuf
|
||||
|
||||
In the base class this is a pure virtual function. Subclasses MUST implement
|
||||
this function. See the SampleProtocol for an example
|
||||
*/
|
||||
|
||||
// Stein's binary GCD algo - from wikipedia
|
||||
quint64 AbstractProtocol::gcd(quint64 u, quint64 v)
|
||||
{
|
||||
int shift;
|
||||
|
||||
/* GCD(0,x) := x */
|
||||
if (u == 0 || v == 0)
|
||||
return u | v;
|
||||
|
||||
/* Let shift := lg K, where K is the greatest power of 2
|
||||
dividing both u and v. */
|
||||
for (shift = 0; ((u | v) & 1) == 0; ++shift) {
|
||||
u >>= 1;
|
||||
v >>= 1;
|
||||
}
|
||||
|
||||
while ((u & 1) == 0)
|
||||
u >>= 1;
|
||||
|
||||
/* From here on, u is always odd. */
|
||||
do {
|
||||
while ((v & 1) == 0) /* Loop X */
|
||||
v >>= 1;
|
||||
|
||||
/* Now u and v are both odd, so diff(u, v) is even.
|
||||
Let u = min(u, v), v = diff(u, v)/2. */
|
||||
if (u < v) {
|
||||
v -= u;
|
||||
} else {
|
||||
quint64 diff = u - v;
|
||||
u = v;
|
||||
v = diff;
|
||||
}
|
||||
v >>= 1;
|
||||
} while (v != 0);
|
||||
|
||||
return u << shift;
|
||||
}
|
||||
|
||||
quint64 AbstractProtocol::lcm(quint64 u, quint64 v)
|
||||
{
|
||||
#if 0
|
||||
/* LCM(0,x) := x */
|
||||
if (u == 0 || v == 0)
|
||||
return u | v;
|
||||
#else
|
||||
/* For our use case, neither u nor v can ever be 0, the minimum
|
||||
value is 1; we do this correction silently here */
|
||||
if (u == 0) u = 1;
|
||||
if (v == 0) v = 1;
|
||||
|
||||
if (u == 1 || v == 1)
|
||||
return (u * v);
|
||||
#endif
|
||||
|
||||
return (u * v)/gcd(u, v);
|
||||
}
|
||||
|
167
common/abstractprotocol.h
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
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 _ABSTRACT_PROTOCOL_H
|
||||
#define _ABSTRACT_PROTOCOL_H
|
||||
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QByteArray>
|
||||
#include <QWidget>
|
||||
#include <QLinkedList>
|
||||
#include <QFlags>
|
||||
|
||||
//#include "../rpc/pbhelper.h"
|
||||
#include "protocol.pb.h"
|
||||
|
||||
#define BASE_BIN (2)
|
||||
#define BASE_OCT (8)
|
||||
#define BASE_DEC (10)
|
||||
#define BASE_HEX (16)
|
||||
|
||||
#define uintToHexStr(num, bytes) \
|
||||
QString("%1").arg(num, bytes*2, BASE_HEX, QChar('0'))
|
||||
|
||||
class StreamBase;
|
||||
class ProtocolListIterator;
|
||||
|
||||
class AbstractProtocol
|
||||
{
|
||||
template <int protoNumber, class ProtoA, class ProtoB>
|
||||
friend class ComboProtocol;
|
||||
friend class ProtocolListIterator;
|
||||
|
||||
private:
|
||||
mutable int _metaFieldCount;
|
||||
mutable int _frameFieldCount;
|
||||
mutable int protoSize;
|
||||
mutable QString protoAbbr;
|
||||
|
||||
protected:
|
||||
StreamBase *mpStream; //!< Stream that this protocol belongs to
|
||||
AbstractProtocol *parent; //!< Parent protocol, if any
|
||||
AbstractProtocol *prev; //!< Protocol preceding this protocol
|
||||
AbstractProtocol *next; //!< Protocol succeeding this protocol
|
||||
|
||||
//! Is protocol typically followed by payload or another protocol
|
||||
bool _hasPayload;
|
||||
|
||||
public:
|
||||
//! Properties of a field, can be OR'd
|
||||
enum FieldFlag {
|
||||
FrameField = 0x1, //!< field appears in frame content
|
||||
MetaField = 0x2, //!< field does not appear in frame, is meta data
|
||||
CksumField = 0x4 //!< field is a checksum and appears in frame content
|
||||
};
|
||||
Q_DECLARE_FLAGS(FieldFlags, FieldFlag); //!< \private abcd
|
||||
|
||||
//! Various attributes of a field
|
||||
enum FieldAttrib {
|
||||
FieldName, //!< name
|
||||
FieldValue, //!< value in host byte order (user editable)
|
||||
FieldTextValue, //!< value as text
|
||||
FieldFrameValue, //!< frame encoded value in network byte order
|
||||
FieldBitSize, //!< size in bits
|
||||
};
|
||||
|
||||
//! Supported Protocol Id types
|
||||
enum ProtocolIdType {
|
||||
ProtocolIdNone, //!< Marker representing non-existent protocol id
|
||||
ProtocolIdLlc, //!< LLC (802.2)
|
||||
ProtocolIdEth, //!< Ethernet II
|
||||
ProtocolIdIp, //!< IP
|
||||
ProtocolIdTcpUdp, //!< TCP/UDP Port Number
|
||||
};
|
||||
|
||||
//! Supported checksum types
|
||||
enum CksumType {
|
||||
CksumIp, //!< Standard IP Checksum
|
||||
CksumIpPseudo, //!< Standard checksum for Pseudo-IP header
|
||||
CksumTcpUdp, //!< Standard TCP/UDP checksum including pseudo-IP
|
||||
|
||||
CksumMax //!< Marker for number of cksum types
|
||||
};
|
||||
|
||||
//! Supported checksum scopes
|
||||
enum CksumScope {
|
||||
CksumScopeAdjacentProtocol, //!< Cksum only the adjacent protocol
|
||||
CksumScopeAllProtocols, //!< Cksum over all the protocols
|
||||
};
|
||||
|
||||
AbstractProtocol(StreamBase *stream, AbstractProtocol *parent = 0);
|
||||
virtual ~AbstractProtocol();
|
||||
|
||||
static AbstractProtocol* createInstance(StreamBase *stream,
|
||||
AbstractProtocol *parent = 0);
|
||||
virtual quint32 protocolNumber() const;
|
||||
|
||||
virtual void protoDataCopyInto(OstProto::Protocol &protocol) const = 0;
|
||||
virtual void protoDataCopyFrom(const OstProto::Protocol &protocol) = 0;
|
||||
|
||||
virtual QString name() const;
|
||||
virtual QString shortName() const;
|
||||
|
||||
virtual ProtocolIdType protocolIdType() const;
|
||||
virtual quint32 protocolId(ProtocolIdType type) const;
|
||||
quint32 payloadProtocolId(ProtocolIdType type) const;
|
||||
|
||||
virtual int fieldCount() const;
|
||||
int metaFieldCount() const;
|
||||
virtual int frameFieldCount() const;
|
||||
|
||||
virtual FieldFlags fieldFlags(int index) const;
|
||||
virtual QVariant fieldData(int index, FieldAttrib attrib,
|
||||
int streamIndex = 0) const;
|
||||
virtual bool setFieldData(int index, const QVariant &value,
|
||||
FieldAttrib attrib = FieldValue);
|
||||
|
||||
QByteArray protocolFrameValue(int streamIndex = 0,
|
||||
bool forCksum = false) const;
|
||||
virtual int protocolFrameSize(int streamIndex = 0) const;
|
||||
int protocolFrameOffset(int streamIndex = 0) const;
|
||||
int protocolFramePayloadSize(int streamIndex = 0) const;
|
||||
|
||||
virtual bool isProtocolFrameValueVariable() const;
|
||||
virtual bool isProtocolFrameSizeVariable() const;
|
||||
virtual int protocolFrameVariableCount() const;
|
||||
bool isProtocolFramePayloadValueVariable() const;
|
||||
bool isProtocolFramePayloadSizeVariable() const;
|
||||
int protocolFramePayloadVariableCount() const;
|
||||
|
||||
bool protocolHasPayload() const;
|
||||
|
||||
virtual quint32 protocolFrameCksum(int streamIndex = 0,
|
||||
CksumType cksumType = CksumIp) const;
|
||||
quint32 protocolFrameHeaderCksum(int streamIndex = 0,
|
||||
CksumType cksumType = CksumIp,
|
||||
CksumScope cksumScope = CksumScopeAdjacentProtocol) const;
|
||||
quint32 protocolFramePayloadCksum(int streamIndex = 0,
|
||||
CksumType cksumType = CksumIp,
|
||||
CksumScope cksumScope = CksumScopeAllProtocols) const;
|
||||
|
||||
virtual QWidget* configWidget() = 0;
|
||||
virtual void loadConfigWidget() = 0;
|
||||
virtual void storeConfigWidget() = 0;
|
||||
|
||||
static quint64 lcm(quint64 u, quint64 v);
|
||||
static quint64 gcd(quint64 u, quint64 v);
|
||||
};
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractProtocol::FieldFlags);
|
||||
|
||||
#endif
|
993
common/arp.cpp
Normal file
@ -0,0 +1,993 @@
|
||||
/*
|
||||
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 <qendian.h>
|
||||
#include <QHostAddress>
|
||||
|
||||
#include "arp.h"
|
||||
|
||||
ArpConfigForm::ArpConfigForm(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
opCodeCombo->setValidator(new QIntValidator(0, 0xFFFF, this));
|
||||
opCodeCombo->addItem(1, "ARP Request");
|
||||
opCodeCombo->addItem(2, "ARP Reply");
|
||||
|
||||
connect(senderHwAddrMode, SIGNAL(currentIndexChanged(int)),
|
||||
SLOT(on_senderHwAddrMode_currentIndexChanged(int)));
|
||||
connect(senderProtoAddrMode, SIGNAL(currentIndexChanged(int)),
|
||||
SLOT(on_senderProtoAddrMode_currentIndexChanged(int)));
|
||||
connect(targetHwAddrMode, SIGNAL(currentIndexChanged(int)),
|
||||
SLOT(on_targetHwAddrMode_currentIndexChanged(int)));
|
||||
connect(targetProtoAddrMode, SIGNAL(currentIndexChanged(int)),
|
||||
SLOT(on_targetProtoAddrMode_currentIndexChanged(int)));
|
||||
}
|
||||
|
||||
void ArpConfigForm::on_senderHwAddrMode_currentIndexChanged(int index)
|
||||
{
|
||||
if (index == OstProto::Arp::kFixed)
|
||||
senderHwAddrCount->setDisabled(true);
|
||||
else
|
||||
senderHwAddrCount->setEnabled(true);
|
||||
}
|
||||
|
||||
void ArpConfigForm::on_targetHwAddrMode_currentIndexChanged(int index)
|
||||
{
|
||||
if (index == OstProto::Arp::kFixed)
|
||||
targetHwAddrCount->setDisabled(true);
|
||||
else
|
||||
targetHwAddrCount->setEnabled(true);
|
||||
}
|
||||
|
||||
void ArpConfigForm::on_senderProtoAddrMode_currentIndexChanged(int index)
|
||||
{
|
||||
if (index == OstProto::Arp::kFixedHost)
|
||||
{
|
||||
senderProtoAddrCount->setDisabled(true);
|
||||
senderProtoAddrMask->setDisabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
senderProtoAddrCount->setEnabled(true);
|
||||
senderProtoAddrMask->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
void ArpConfigForm::on_targetProtoAddrMode_currentIndexChanged(int index)
|
||||
{
|
||||
if (index == OstProto::Arp::kFixedHost)
|
||||
{
|
||||
targetProtoAddrCount->setDisabled(true);
|
||||
targetProtoAddrMask->setDisabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
targetProtoAddrCount->setEnabled(true);
|
||||
targetProtoAddrMask->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
ArpProtocol::ArpProtocol(StreamBase *stream, AbstractProtocol *parent)
|
||||
: AbstractProtocol(stream, parent)
|
||||
{
|
||||
_hasPayload = false;
|
||||
configForm = NULL;
|
||||
}
|
||||
|
||||
ArpProtocol::~ArpProtocol()
|
||||
{
|
||||
delete configForm;
|
||||
}
|
||||
|
||||
AbstractProtocol* ArpProtocol::createInstance(StreamBase *stream,
|
||||
AbstractProtocol *parent)
|
||||
{
|
||||
return new ArpProtocol(stream, parent);
|
||||
}
|
||||
|
||||
quint32 ArpProtocol::protocolNumber() const
|
||||
{
|
||||
return OstProto::Protocol::kArpFieldNumber;
|
||||
}
|
||||
|
||||
void ArpProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const
|
||||
{
|
||||
protocol.MutableExtension(OstProto::arp)->CopyFrom(data);
|
||||
protocol.mutable_protocol_id()->set_id(protocolNumber());
|
||||
}
|
||||
|
||||
void ArpProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol)
|
||||
{
|
||||
if (protocol.protocol_id().id() == protocolNumber() &&
|
||||
protocol.HasExtension(OstProto::arp))
|
||||
data.MergeFrom(protocol.GetExtension(OstProto::arp));
|
||||
}
|
||||
|
||||
QString ArpProtocol::name() const
|
||||
{
|
||||
return QString("Address Resolution Protocol");
|
||||
}
|
||||
|
||||
QString ArpProtocol::shortName() const
|
||||
{
|
||||
return QString("ARP");
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the ProtocolIdType for your protocol \n
|
||||
|
||||
If your protocol doesn't have a protocolId field, you don't need to
|
||||
reimplement this method - the base class implementation will do the
|
||||
right thing
|
||||
*/
|
||||
#if 0
|
||||
AbstractProtocol::ProtocolIdType ArpProtocol::protocolIdType() const
|
||||
{
|
||||
return ProtocolIdIp;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Return the protocolId for your protocol based on the 'type' requested \n
|
||||
|
||||
If not all types are valid for your protocol, handle the valid type(s)
|
||||
and for the remaining fallback to the base class implementation; if your
|
||||
protocol doesn't have a protocolId at all, you don't need to reimplement
|
||||
this method - the base class will do the right thing
|
||||
*/
|
||||
quint32 ArpProtocol::protocolId(ProtocolIdType type) const
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case ProtocolIdEth: return 0x0806;
|
||||
default:break;
|
||||
}
|
||||
|
||||
return AbstractProtocol::protocolId(type);
|
||||
}
|
||||
|
||||
int ArpProtocol::fieldCount() const
|
||||
{
|
||||
return arp_fieldCount;
|
||||
}
|
||||
|
||||
AbstractProtocol::FieldFlags ArpProtocol::fieldFlags(int index) const
|
||||
{
|
||||
AbstractProtocol::FieldFlags flags;
|
||||
|
||||
flags = AbstractProtocol::fieldFlags(index);
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case arp_hwType:
|
||||
case arp_protoType:
|
||||
|
||||
case arp_hwAddrLen:
|
||||
case arp_protoAddrLen:
|
||||
|
||||
case arp_opCode:
|
||||
|
||||
case arp_senderHwAddr:
|
||||
case arp_senderProtoAddr:
|
||||
case arp_targetHwAddr:
|
||||
case arp_targetProtoAddr:
|
||||
break;
|
||||
|
||||
case arp_senderHwAddrMode:
|
||||
case arp_senderHwAddrCount:
|
||||
|
||||
case arp_senderProtoAddrMode:
|
||||
case arp_senderProtoAddrCount:
|
||||
case arp_senderProtoAddrMask:
|
||||
|
||||
case arp_targetHwAddrMode:
|
||||
case arp_targetHwAddrCount:
|
||||
|
||||
case arp_targetProtoAddrMode:
|
||||
case arp_targetProtoAddrCount:
|
||||
case arp_targetProtoAddrMask:
|
||||
flags &= ~FrameField;
|
||||
flags |= MetaField;
|
||||
break;
|
||||
|
||||
default:
|
||||
qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__,
|
||||
index);
|
||||
break;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
QVariant ArpProtocol::fieldData(int index, FieldAttrib attrib,
|
||||
int streamIndex) const
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case arp_hwType:
|
||||
{
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Hardware Type");
|
||||
case FieldValue:
|
||||
return data.hw_type();
|
||||
case FieldTextValue:
|
||||
return QString("%1").arg(data.hw_type());
|
||||
case FieldFrameValue:
|
||||
{
|
||||
QByteArray fv;
|
||||
fv.resize(2);
|
||||
qToBigEndian((quint16) data.hw_type(), (uchar*) fv.data());
|
||||
return fv;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case arp_protoType:
|
||||
{
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Protocol Type");
|
||||
case FieldValue:
|
||||
return data.proto_type();
|
||||
case FieldTextValue:
|
||||
return QString("%1").arg(data.proto_type(), 4, BASE_HEX,
|
||||
QChar('0'));
|
||||
case FieldFrameValue:
|
||||
{
|
||||
QByteArray fv;
|
||||
fv.resize(2);
|
||||
qToBigEndian((quint16) data.proto_type(), (uchar*) fv.data());
|
||||
return fv;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case arp_hwAddrLen:
|
||||
{
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Hardware Address Length");
|
||||
case FieldValue:
|
||||
return data.hw_addr_len();
|
||||
case FieldTextValue:
|
||||
return QString("%1").arg(data.hw_addr_len());
|
||||
case FieldFrameValue:
|
||||
return QByteArray(1, (char) data.hw_addr_len());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case arp_protoAddrLen:
|
||||
{
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Protocol Address Length");
|
||||
case FieldValue:
|
||||
return data.proto_addr_len();
|
||||
case FieldTextValue:
|
||||
return QString("%1").arg(data.proto_addr_len());
|
||||
case FieldFrameValue:
|
||||
return QByteArray(1, (char) data.proto_addr_len());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case arp_opCode:
|
||||
{
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Operation Code");
|
||||
case FieldValue:
|
||||
return data.op_code();
|
||||
case FieldTextValue:
|
||||
return QString("%1").arg(data.op_code());
|
||||
case FieldFrameValue:
|
||||
{
|
||||
QByteArray fv;
|
||||
fv.resize(2);
|
||||
qToBigEndian((quint16) data.op_code(), (uchar*) fv.data());
|
||||
return fv;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case arp_senderHwAddr:
|
||||
{
|
||||
int u;
|
||||
const int hwAddrStep = 1;
|
||||
quint64 hwAddr = 0;
|
||||
|
||||
switch (data.sender_hw_addr_mode())
|
||||
{
|
||||
case OstProto::Arp::kFixed:
|
||||
hwAddr = data.sender_hw_addr();
|
||||
break;
|
||||
case OstProto::Arp::kIncrement:
|
||||
u = (streamIndex % data.sender_hw_addr_count()) *
|
||||
hwAddrStep;
|
||||
hwAddr = data.sender_hw_addr() + u;
|
||||
break;
|
||||
case OstProto::Arp::kDecrement:
|
||||
u = (streamIndex % data.sender_hw_addr_count()) *
|
||||
hwAddrStep;
|
||||
hwAddr = data.sender_hw_addr() - u;
|
||||
break;
|
||||
default:
|
||||
qWarning("Unhandled hw_addr_mode %d",
|
||||
data.sender_hw_addr_mode());
|
||||
}
|
||||
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Sender Hardware Address");
|
||||
case FieldValue:
|
||||
return hwAddr;
|
||||
case FieldTextValue:
|
||||
return uintToHexStr(hwAddr, 6);
|
||||
case FieldFrameValue:
|
||||
{
|
||||
QByteArray fv;
|
||||
fv.resize(8);
|
||||
qToBigEndian((quint64) hwAddr, (uchar*) fv.data());
|
||||
fv.remove(0, 2);
|
||||
return fv;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case arp_senderProtoAddr:
|
||||
{
|
||||
int u;
|
||||
quint32 subnet, host, protoAddr = 0;
|
||||
|
||||
switch(data.sender_proto_addr_mode())
|
||||
{
|
||||
case OstProto::Arp::kFixedHost:
|
||||
protoAddr = data.sender_proto_addr();
|
||||
break;
|
||||
case OstProto::Arp::kIncrementHost:
|
||||
u = streamIndex % data.sender_proto_addr_count();
|
||||
subnet = data.sender_proto_addr()
|
||||
& data.sender_proto_addr_mask();
|
||||
host = (((data.sender_proto_addr()
|
||||
& ~data.sender_proto_addr_mask()) + u)
|
||||
& ~data.sender_proto_addr_mask());
|
||||
protoAddr = subnet | host;
|
||||
break;
|
||||
case OstProto::Arp::kDecrementHost:
|
||||
u = streamIndex % data.sender_proto_addr_count();
|
||||
subnet = data.sender_proto_addr()
|
||||
& data.sender_proto_addr_mask();
|
||||
host = (((data.sender_proto_addr()
|
||||
& ~data.sender_proto_addr_mask()) - u)
|
||||
& ~data.sender_proto_addr_mask());
|
||||
protoAddr = subnet | host;
|
||||
break;
|
||||
case OstProto::Arp::kRandomHost:
|
||||
subnet = data.sender_proto_addr()
|
||||
& data.sender_proto_addr_mask();
|
||||
host = (qrand() & ~data.sender_proto_addr_mask());
|
||||
protoAddr = subnet | host;
|
||||
break;
|
||||
default:
|
||||
qWarning("Unhandled sender_proto_addr_mode = %d",
|
||||
data.sender_proto_addr_mode());
|
||||
}
|
||||
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Sender Protocol Address");
|
||||
case FieldValue:
|
||||
return protoAddr;
|
||||
case FieldFrameValue:
|
||||
{
|
||||
QByteArray fv;
|
||||
fv.resize(4);
|
||||
qToBigEndian((quint32) protoAddr, (uchar*) fv.data());
|
||||
return fv;
|
||||
}
|
||||
case FieldTextValue:
|
||||
return QHostAddress(protoAddr).toString();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case arp_targetHwAddr:
|
||||
{
|
||||
int u;
|
||||
const int hwAddrStep = 1;
|
||||
quint64 hwAddr = 0;
|
||||
|
||||
switch (data.target_hw_addr_mode())
|
||||
{
|
||||
case OstProto::Arp::kFixed:
|
||||
hwAddr = data.target_hw_addr();
|
||||
break;
|
||||
case OstProto::Arp::kIncrement:
|
||||
u = (streamIndex % data.target_hw_addr_count()) *
|
||||
hwAddrStep;
|
||||
hwAddr = data.target_hw_addr() + u;
|
||||
break;
|
||||
case OstProto::Arp::kDecrement:
|
||||
u = (streamIndex % data.target_hw_addr_count()) *
|
||||
hwAddrStep;
|
||||
hwAddr = data.target_hw_addr() - u;
|
||||
break;
|
||||
default:
|
||||
qWarning("Unhandled hw_addr_mode %d",
|
||||
data.target_hw_addr_mode());
|
||||
}
|
||||
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Target Hardware Address");
|
||||
case FieldValue:
|
||||
return hwAddr;
|
||||
case FieldTextValue:
|
||||
return uintToHexStr(hwAddr, 6);
|
||||
case FieldFrameValue:
|
||||
{
|
||||
QByteArray fv;
|
||||
fv.resize(8);
|
||||
qToBigEndian((quint64) hwAddr, (uchar*) fv.data());
|
||||
fv.remove(0, 2);
|
||||
return fv;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case arp_targetProtoAddr:
|
||||
{
|
||||
int u;
|
||||
quint32 subnet, host, protoAddr = 0;
|
||||
|
||||
switch(data.target_proto_addr_mode())
|
||||
{
|
||||
case OstProto::Arp::kFixed:
|
||||
protoAddr = data.target_proto_addr();
|
||||
break;
|
||||
case OstProto::Arp::kIncrementHost:
|
||||
u = streamIndex % data.target_proto_addr_count();
|
||||
subnet = data.target_proto_addr()
|
||||
& data.target_proto_addr_mask();
|
||||
host = (((data.target_proto_addr()
|
||||
& ~data.target_proto_addr_mask()) + u)
|
||||
& ~data.target_proto_addr_mask());
|
||||
protoAddr = subnet | host;
|
||||
break;
|
||||
case OstProto::Arp::kDecrementHost:
|
||||
u = streamIndex % data.target_proto_addr_count();
|
||||
subnet = data.target_proto_addr()
|
||||
& data.target_proto_addr_mask();
|
||||
host = (((data.target_proto_addr()
|
||||
& ~data.target_proto_addr_mask()) - u)
|
||||
& ~data.target_proto_addr_mask());
|
||||
protoAddr = subnet | host;
|
||||
break;
|
||||
case OstProto::Arp::kRandomHost:
|
||||
subnet = data.target_proto_addr()
|
||||
& data.target_proto_addr_mask();
|
||||
host = (qrand() & ~data.target_proto_addr_mask());
|
||||
protoAddr = subnet | host;
|
||||
break;
|
||||
default:
|
||||
qWarning("Unhandled target_proto_addr_mode = %d",
|
||||
data.target_proto_addr_mode());
|
||||
}
|
||||
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Target Protocol Address");
|
||||
case FieldValue:
|
||||
return protoAddr;
|
||||
case FieldFrameValue:
|
||||
{
|
||||
QByteArray fv;
|
||||
fv.resize(4);
|
||||
qToBigEndian((quint32) protoAddr, (uchar*) fv.data());
|
||||
return fv;
|
||||
}
|
||||
case FieldTextValue:
|
||||
return QHostAddress(protoAddr).toString();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Meta fields
|
||||
case arp_senderHwAddrMode:
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Sender Hardware Address Mode");
|
||||
case FieldValue:
|
||||
return data.sender_hw_addr_mode();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case arp_senderHwAddrCount:
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Sender Hardware Address Count");
|
||||
case FieldValue:
|
||||
return data.sender_hw_addr_count();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case arp_senderProtoAddrMode:
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Sender Protocol Address Mode");
|
||||
case FieldValue:
|
||||
return data.sender_proto_addr_mode();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case arp_senderProtoAddrCount:
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Sender Protocol Address Count");
|
||||
case FieldValue:
|
||||
return data.sender_proto_addr_count();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case arp_senderProtoAddrMask:
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Sender Protocol Address Mask");
|
||||
case FieldValue:
|
||||
return data.sender_proto_addr_mask();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case arp_targetHwAddrMode:
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Target Hardware Address Mode");
|
||||
case FieldValue:
|
||||
return data.target_hw_addr_mode();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case arp_targetHwAddrCount:
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Target Hardware Address Count");
|
||||
case FieldValue:
|
||||
return data.target_hw_addr_count();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case arp_targetProtoAddrMode:
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Target Protocol Address Mode");
|
||||
case FieldValue:
|
||||
return data.target_proto_addr_mode();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case arp_targetProtoAddrCount:
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Target Protocol Address Count");
|
||||
case FieldValue:
|
||||
return data.target_proto_addr_count();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case arp_targetProtoAddrMask:
|
||||
switch(attrib)
|
||||
{
|
||||
case FieldName:
|
||||
return QString("Target Protocol Address Mask");
|
||||
case FieldValue:
|
||||
return data.target_proto_addr_mask();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__,
|
||||
index);
|
||||
break;
|
||||
}
|
||||
|
||||
return AbstractProtocol::fieldData(index, attrib, streamIndex);
|
||||
}
|
||||
|
||||
bool ArpProtocol::setFieldData(int index, const QVariant &value,
|
||||
FieldAttrib attrib)
|
||||
{
|
||||
bool isOk = false;
|
||||
|
||||
if (attrib != FieldValue)
|
||||
goto _exit;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case arp_hwType:
|
||||
{
|
||||
uint hwType = value.toUInt(&isOk);
|
||||
if (isOk)
|
||||
data.set_hw_type(hwType);
|
||||
break;
|
||||
}
|
||||
case arp_protoType:
|
||||
{
|
||||
uint protoType = value.toUInt(&isOk);
|
||||
if (isOk)
|
||||
data.set_proto_type(protoType);
|
||||
break;
|
||||
}
|
||||
case arp_hwAddrLen:
|
||||
{
|
||||
uint hwAddrLen = value.toUInt(&isOk);
|
||||
if (isOk)
|
||||
data.set_hw_addr_len(hwAddrLen);
|
||||
break;
|
||||
}
|
||||
case arp_protoAddrLen:
|
||||
{
|
||||
uint protoAddrLen = value.toUInt(&isOk);
|
||||
if (isOk)
|
||||
data.set_proto_addr_len(protoAddrLen);
|
||||
break;
|
||||
}
|
||||
case arp_opCode:
|
||||
{
|
||||
uint opCode = value.toUInt(&isOk);
|
||||
if (isOk)
|
||||
data.set_op_code(opCode);
|
||||
break;
|
||||
}
|
||||
|
||||
case arp_senderHwAddr:
|
||||
{
|
||||
quint64 hwAddr = value.toULongLong(&isOk);
|
||||
if (isOk)
|
||||
data.set_sender_hw_addr(hwAddr);
|
||||
break;
|
||||
}
|
||||
case arp_senderHwAddrMode:
|
||||
{
|
||||
uint mode = value.toUInt(&isOk);
|
||||
if (isOk && data.HwAddrMode_IsValid(mode))
|
||||
data.set_sender_hw_addr_mode((OstProto::Arp::HwAddrMode) mode);
|
||||
else
|
||||
isOk = false;
|
||||
break;
|
||||
}
|
||||
case arp_senderHwAddrCount:
|
||||
{
|
||||
uint count = value.toUInt(&isOk);
|
||||
if (isOk)
|
||||
data.set_sender_hw_addr_count(count);
|
||||
break;
|
||||
}
|
||||
|
||||
case arp_senderProtoAddr:
|
||||
{
|
||||
uint protoAddr = value.toUInt(&isOk);
|
||||
if (isOk)
|
||||
data.set_sender_proto_addr(protoAddr);
|
||||
break;
|
||||
}
|
||||
case arp_senderProtoAddrMode:
|
||||
{
|
||||
uint mode = value.toUInt(&isOk);
|
||||
if (isOk && data.ProtoAddrMode_IsValid(mode))
|
||||
data.set_sender_proto_addr_mode(
|
||||
(OstProto::Arp::ProtoAddrMode)mode);
|
||||
else
|
||||
isOk = false;
|
||||
break;
|
||||
}
|
||||
case arp_senderProtoAddrCount:
|
||||
{
|
||||
uint count = value.toUInt(&isOk);
|
||||
if (isOk)
|
||||
data.set_sender_proto_addr_count(count);
|
||||
break;
|
||||
}
|
||||
case arp_senderProtoAddrMask:
|
||||
{
|
||||
uint mask = value.toUInt(&isOk);
|
||||
if (isOk)
|
||||
data.set_sender_proto_addr_mask(mask);
|
||||
break;
|
||||
}
|
||||
|
||||
case arp_targetHwAddr:
|
||||
{
|
||||
quint64 hwAddr = value.toULongLong(&isOk);
|
||||
if (isOk)
|
||||
data.set_target_hw_addr(hwAddr);
|
||||
break;
|
||||
}
|
||||
case arp_targetHwAddrMode:
|
||||
{
|
||||
uint mode = value.toUInt(&isOk);
|
||||
if (isOk && data.HwAddrMode_IsValid(mode))
|
||||
data.set_target_hw_addr_mode((OstProto::Arp::HwAddrMode)mode);
|
||||
else
|
||||
isOk = false;
|
||||
break;
|
||||
}
|
||||
case arp_targetHwAddrCount:
|
||||
{
|
||||
uint count = value.toUInt(&isOk);
|
||||
if (isOk)
|
||||
data.set_target_hw_addr_count(count);
|
||||
break;
|
||||
}
|
||||
|
||||
case arp_targetProtoAddr:
|
||||
{
|
||||
uint protoAddr = value.toUInt(&isOk);
|
||||
if (isOk)
|
||||
data.set_target_proto_addr(protoAddr);
|
||||
break;
|
||||
}
|
||||
case arp_targetProtoAddrMode:
|
||||
{
|
||||
uint mode = value.toUInt(&isOk);
|
||||
if (isOk && data.ProtoAddrMode_IsValid(mode))
|
||||
data.set_target_proto_addr_mode(
|
||||
(OstProto::Arp::ProtoAddrMode)mode);
|
||||
else
|
||||
isOk = false;
|
||||
break;
|
||||
}
|
||||
case arp_targetProtoAddrCount:
|
||||
{
|
||||
uint count = value.toUInt(&isOk);
|
||||
if (isOk)
|
||||
data.set_target_proto_addr_count(count);
|
||||
break;
|
||||
}
|
||||
case arp_targetProtoAddrMask:
|
||||
{
|
||||
uint mask = value.toUInt(&isOk);
|
||||
if (isOk)
|
||||
data.set_target_proto_addr_mask(mask);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default:
|
||||
qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__,
|
||||
index);
|
||||
break;
|
||||
}
|
||||
|
||||
_exit:
|
||||
return isOk;
|
||||
}
|
||||
|
||||
bool ArpProtocol::isProtocolFrameValueVariable() const
|
||||
{
|
||||
if (fieldData(arp_senderHwAddrMode, FieldValue).toUInt()
|
||||
!= uint(OstProto::Arp::kFixed)
|
||||
|| fieldData(arp_senderProtoAddrMode, FieldValue).toUInt()
|
||||
!= uint(OstProto::Arp::kFixed)
|
||||
|| fieldData(arp_targetHwAddrMode, FieldValue).toUInt()
|
||||
!= uint(OstProto::Arp::kFixed)
|
||||
|| fieldData(arp_targetProtoAddrMode, FieldValue).toUInt()
|
||||
!= uint(OstProto::Arp::kFixed))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ArpProtocol::protocolFrameVariableCount() const
|
||||
{
|
||||
int count = 1;
|
||||
|
||||
if (fieldData(arp_senderHwAddrMode, FieldValue).toUInt()
|
||||
!= uint(OstProto::Arp::kFixed))
|
||||
{
|
||||
count = AbstractProtocol::lcm(count,
|
||||
fieldData(arp_senderHwAddrCount, FieldValue).toUInt());
|
||||
}
|
||||
|
||||
if (fieldData(arp_senderProtoAddrMode, FieldValue).toUInt()
|
||||
!= uint(OstProto::Arp::kFixed))
|
||||
{
|
||||
count = AbstractProtocol::lcm(count,
|
||||
fieldData(arp_senderProtoAddrCount, FieldValue).toUInt());
|
||||
}
|
||||
|
||||
if (fieldData(arp_targetHwAddrMode, FieldValue).toUInt()
|
||||
!= uint(OstProto::Arp::kFixed))
|
||||
{
|
||||
count = AbstractProtocol::lcm(count,
|
||||
fieldData(arp_targetHwAddrCount, FieldValue).toUInt());
|
||||
}
|
||||
|
||||
if (fieldData(arp_targetProtoAddrMode, FieldValue).toUInt()
|
||||
!= uint(OstProto::Arp::kFixed))
|
||||
{
|
||||
count = AbstractProtocol::lcm(count,
|
||||
fieldData(arp_targetProtoAddrCount, FieldValue).toUInt());
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
QWidget* ArpProtocol::configWidget()
|
||||
{
|
||||
if (configForm == NULL)
|
||||
{
|
||||
configForm = new ArpConfigForm;
|
||||
loadConfigWidget();
|
||||
}
|
||||
|
||||
return configForm;
|
||||
}
|
||||
|
||||
void ArpProtocol::loadConfigWidget()
|
||||
{
|
||||
configWidget();
|
||||
|
||||
configForm->hwType->setText(
|
||||
fieldData(arp_hwType, FieldValue).toString());
|
||||
configForm->protoType->setText(uintToHexStr(
|
||||
fieldData(arp_protoType, FieldValue).toUInt(), 2));
|
||||
configForm->hwAddrLen->setText(
|
||||
fieldData(arp_hwAddrLen, FieldValue).toString());
|
||||
configForm->protoAddrLen->setText(
|
||||
fieldData(arp_protoAddrLen, FieldValue).toString());
|
||||
|
||||
configForm->opCodeCombo->setValue(
|
||||
fieldData(arp_opCode, FieldValue).toUInt());
|
||||
|
||||
configForm->senderHwAddr->setText(uintToHexStr(
|
||||
fieldData(arp_senderHwAddr, FieldValue).toULongLong(), 6));
|
||||
configForm->senderHwAddrMode->setCurrentIndex(
|
||||
fieldData(arp_senderHwAddrMode, FieldValue).toUInt());
|
||||
configForm->senderHwAddrCount->setText(
|
||||
fieldData(arp_senderHwAddrCount, FieldValue).toString());
|
||||
|
||||
configForm->senderProtoAddr->setText(QHostAddress(
|
||||
fieldData(arp_senderProtoAddr, FieldValue).toUInt()).toString());
|
||||
configForm->senderProtoAddrMode->setCurrentIndex(
|
||||
fieldData(arp_senderProtoAddrMode, FieldValue).toUInt());
|
||||
configForm->senderProtoAddrCount->setText(
|
||||
fieldData(arp_senderProtoAddrCount, FieldValue).toString());
|
||||
configForm->senderProtoAddrMask->setText(QHostAddress(
|
||||
fieldData(arp_senderProtoAddrMask, FieldValue).toUInt()).toString());
|
||||
|
||||
configForm->targetHwAddr->setText(uintToHexStr(
|
||||
fieldData(arp_targetHwAddr, FieldValue).toULongLong(), 6));
|
||||
configForm->targetHwAddrMode->setCurrentIndex(
|
||||
fieldData(arp_targetHwAddrMode, FieldValue).toUInt());
|
||||
configForm->targetHwAddrCount->setText(
|
||||
fieldData(arp_targetHwAddrCount, FieldValue).toString());
|
||||
|
||||
configForm->targetProtoAddr->setText(QHostAddress(
|
||||
fieldData(arp_targetProtoAddr, FieldValue).toUInt()).toString());
|
||||
configForm->targetProtoAddrMode->setCurrentIndex(
|
||||
fieldData(arp_targetProtoAddrMode, FieldValue).toUInt());
|
||||
configForm->targetProtoAddrCount->setText(
|
||||
fieldData(arp_targetProtoAddrCount, FieldValue).toString());
|
||||
configForm->targetProtoAddrMask->setText(QHostAddress(
|
||||
fieldData(arp_targetProtoAddrMask, FieldValue).toUInt()).toString());
|
||||
|
||||
}
|
||||
|
||||
void ArpProtocol::storeConfigWidget()
|
||||
{
|
||||
bool isOk;
|
||||
|
||||
configWidget();
|
||||
|
||||
setFieldData(arp_hwType, configForm->hwType->text());
|
||||
setFieldData(arp_protoType, configForm->protoType->text().toUInt(
|
||||
&isOk, BASE_HEX));
|
||||
setFieldData(arp_hwAddrLen, configForm->hwAddrLen->text());
|
||||
setFieldData(arp_protoAddrLen, configForm->protoAddrLen->text());
|
||||
|
||||
setFieldData(arp_opCode, configForm->opCodeCombo->currentValue());
|
||||
|
||||
setFieldData(arp_senderHwAddr, configForm->senderHwAddr->text()
|
||||
.remove(QChar(' ')).toULongLong(&isOk, BASE_HEX));
|
||||
setFieldData(arp_senderHwAddrMode,
|
||||
configForm->senderHwAddrMode->currentIndex());
|
||||
setFieldData(arp_senderHwAddrCount, configForm->senderHwAddrCount->text());
|
||||
|
||||
setFieldData(arp_senderProtoAddr, QHostAddress(
|
||||
configForm->senderProtoAddr->text()).toIPv4Address());
|
||||
setFieldData(arp_senderProtoAddrMode,
|
||||
configForm->senderProtoAddrMode->currentIndex());
|
||||
setFieldData(arp_senderProtoAddrCount,
|
||||
configForm->senderProtoAddrCount->text());
|
||||
setFieldData(arp_senderProtoAddrMask, QHostAddress(
|
||||
configForm->senderProtoAddrMask->text()).toIPv4Address());
|
||||
|
||||
setFieldData(arp_targetHwAddr, configForm->targetHwAddr->text()
|
||||
.remove(QChar(' ')).toULongLong(&isOk, BASE_HEX));
|
||||
setFieldData(arp_targetHwAddrMode,
|
||||
configForm->targetHwAddrMode->currentIndex());
|
||||
setFieldData(arp_targetHwAddrCount, configForm->targetHwAddrCount->text());
|
||||
|
||||
setFieldData(arp_targetProtoAddr, QHostAddress(
|
||||
configForm->targetProtoAddr->text()).toIPv4Address());
|
||||
setFieldData(arp_targetProtoAddrMode,
|
||||
configForm->targetProtoAddrMode->currentIndex());
|
||||
setFieldData(arp_targetProtoAddrCount,
|
||||
configForm->targetProtoAddrCount->text());
|
||||
setFieldData(arp_targetProtoAddrMask, QHostAddress(
|
||||
configForm->targetProtoAddrMask->text()).toIPv4Address());
|
||||
}
|
||||
|
121
common/arp.h
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
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 _ARP_H
|
||||
#define _ARP_H
|
||||
|
||||
#include "arp.pb.h"
|
||||
#include "ui_arp.h"
|
||||
|
||||
#include "abstractprotocol.h"
|
||||
|
||||
/*
|
||||
Arp Protocol Frame Format -
|
||||
+------+------+------+------+------+---------+-------+---------+-------+
|
||||
| HTYP | PTYP | HLEN | PLEN | OPER | SHA | SPA | THA | TPA |
|
||||
| (2) | (2) | (1) | (1) | (2) | (6) | (4) | (6) | (4) |
|
||||
+------+------+------+------+------+---------+-------+---------+-------+
|
||||
Figures in brackets represent field width in bytes
|
||||
*/
|
||||
|
||||
class ArpConfigForm : public QWidget, public Ui::Arp
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ArpConfigForm(QWidget *parent = 0);
|
||||
private slots:
|
||||
void on_senderHwAddrMode_currentIndexChanged(int index);
|
||||
void on_senderProtoAddrMode_currentIndexChanged(int index);
|
||||
void on_targetHwAddrMode_currentIndexChanged(int index);
|
||||
void on_targetProtoAddrMode_currentIndexChanged(int index);
|
||||
};
|
||||
|
||||
class ArpProtocol : public AbstractProtocol
|
||||
{
|
||||
private:
|
||||
OstProto::Arp data;
|
||||
ArpConfigForm *configForm;
|
||||
enum arpfield
|
||||
{
|
||||
// Frame Fields
|
||||
arp_hwType,
|
||||
arp_protoType,
|
||||
|
||||
arp_hwAddrLen,
|
||||
arp_protoAddrLen,
|
||||
|
||||
arp_opCode,
|
||||
|
||||
arp_senderHwAddr,
|
||||
arp_senderProtoAddr,
|
||||
arp_targetHwAddr,
|
||||
arp_targetProtoAddr,
|
||||
|
||||
// Meta Fields
|
||||
arp_senderHwAddrMode,
|
||||
arp_senderHwAddrCount,
|
||||
|
||||
arp_senderProtoAddrMode,
|
||||
arp_senderProtoAddrCount,
|
||||
arp_senderProtoAddrMask,
|
||||
|
||||
arp_targetHwAddrMode,
|
||||
arp_targetHwAddrCount,
|
||||
|
||||
arp_targetProtoAddrMode,
|
||||
arp_targetProtoAddrCount,
|
||||
arp_targetProtoAddrMask,
|
||||
|
||||
|
||||
arp_fieldCount
|
||||
};
|
||||
|
||||
public:
|
||||
ArpProtocol(StreamBase *stream, AbstractProtocol *parent = 0);
|
||||
virtual ~ArpProtocol();
|
||||
|
||||
static AbstractProtocol* createInstance(StreamBase *stream,
|
||||
AbstractProtocol *parent = 0);
|
||||
virtual quint32 protocolNumber() const;
|
||||
|
||||
virtual void protoDataCopyInto(OstProto::Protocol &protocol) const;
|
||||
virtual void protoDataCopyFrom(const OstProto::Protocol &protocol);
|
||||
|
||||
virtual quint32 protocolId(ProtocolIdType type) const;
|
||||
|
||||
virtual QString name() const;
|
||||
virtual QString shortName() const;
|
||||
|
||||
virtual int fieldCount() const;
|
||||
|
||||
virtual AbstractProtocol::FieldFlags fieldFlags(int index) const;
|
||||
virtual QVariant fieldData(int index, FieldAttrib attrib,
|
||||
int streamIndex = 0) const;
|
||||
virtual bool setFieldData(int index, const QVariant &value,
|
||||
FieldAttrib attrib = FieldValue);
|
||||
|
||||
virtual bool isProtocolFrameValueVariable() const;
|
||||
virtual int protocolFrameVariableCount() const;
|
||||
|
||||
virtual QWidget* configWidget();
|
||||
virtual void loadConfigWidget();
|
||||
virtual void storeConfigWidget();
|
||||
};
|
||||
|
||||
#endif
|
67
common/arp.proto
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
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/>
|
||||
*/
|
||||
|
||||
import "protocol.proto";
|
||||
|
||||
package OstProto;
|
||||
|
||||
// ARP Protocol
|
||||
message Arp {
|
||||
|
||||
enum HwAddrMode {
|
||||
kFixed = 0;
|
||||
kIncrement = 1;
|
||||
kDecrement = 2;
|
||||
}
|
||||
|
||||
enum ProtoAddrMode {
|
||||
kFixedHost = 0;
|
||||
kIncrementHost = 1;
|
||||
kDecrementHost = 2;
|
||||
kRandomHost = 3;
|
||||
}
|
||||
|
||||
optional uint32 hw_type = 1 [default = 1];
|
||||
optional uint32 proto_type = 2 [default = 0x800];
|
||||
optional uint32 hw_addr_len = 3 [default = 6];
|
||||
optional uint32 proto_addr_len = 4 [default = 4];
|
||||
optional uint32 op_code = 5 [default = 1]; // 1 => ARP Request
|
||||
|
||||
optional uint64 sender_hw_addr = 6;
|
||||
optional HwAddrMode sender_hw_addr_mode = 7 [default = kFixed];
|
||||
optional uint32 sender_hw_addr_count = 8 [default = 16];
|
||||
|
||||
optional uint32 sender_proto_addr = 9;
|
||||
optional ProtoAddrMode sender_proto_addr_mode = 10 [default = kFixedHost];
|
||||
optional uint32 sender_proto_addr_count = 11 [default = 16];
|
||||
optional fixed32 sender_proto_addr_mask = 12 [default = 0xFFFFFF00];
|
||||
|
||||
optional uint64 target_hw_addr = 13;
|
||||
optional HwAddrMode target_hw_addr_mode = 14 [default = kFixed];
|
||||
optional uint32 target_hw_addr_count = 15 [default = 16];
|
||||
|
||||
optional uint32 target_proto_addr = 16;
|
||||
optional ProtoAddrMode target_proto_addr_mode = 17 [default = kFixedHost];
|
||||
optional uint32 target_proto_addr_count = 18 [default = 16];
|
||||
optional fixed32 target_proto_addr_mask = 19 [default = 0xFFFFFF00];
|
||||
}
|
||||
|
||||
extend Protocol {
|
||||
optional Arp arp = 300;
|
||||
}
|
518
common/arp.ui
Normal file
@ -0,0 +1,518 @@
|
||||
<ui version="4.0" >
|
||||
<class>Arp</class>
|
||||
<widget class="QWidget" name="Arp" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>528</width>
|
||||
<height>286</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle" >
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" >
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox" >
|
||||
<property name="title" >
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="label" >
|
||||
<property name="text" >
|
||||
<string>Hardware Type</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>hwType</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLineEdit" name="hwType" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<widget class="QLabel" name="label_3" >
|
||||
<property name="text" >
|
||||
<string>Hardware Address Length</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>hwAddrLen</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" >
|
||||
<widget class="QLineEdit" name="hwAddrLen" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_2" >
|
||||
<property name="text" >
|
||||
<string>Protocol Type</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>protoType</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLineEdit" name="protoType" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" >
|
||||
<widget class="QLabel" name="label_4" >
|
||||
<property name="text" >
|
||||
<string>Protocol Address Length</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>protoAddrLen</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3" >
|
||||
<widget class="QLineEdit" name="protoAddrLen" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2" >
|
||||
<property name="title" >
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6" >
|
||||
<property name="text" >
|
||||
<string>Operation Code</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="IntComboBox" name="opCodeCombo" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="editable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="insertPolicy" >
|
||||
<enum>QComboBox::NoInsert</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>161</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_7" >
|
||||
<property name="title" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="flat" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>101</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QLabel" name="label_32" >
|
||||
<property name="text" >
|
||||
<string>Address</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2" >
|
||||
<widget class="QLabel" name="label_31" >
|
||||
<property name="text" >
|
||||
<string>Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" >
|
||||
<widget class="QLabel" name="label_23" >
|
||||
<property name="text" >
|
||||
<string>Count</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4" >
|
||||
<widget class="QLabel" name="label_30" >
|
||||
<property name="text" >
|
||||
<string>Mask</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="label_7" >
|
||||
<property name="text" >
|
||||
<string>Sender Hardware</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>senderHwAddr</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QLineEdit" name="senderHwAddr" >
|
||||
<property name="inputMask" >
|
||||
<string>>HH HH HH HH HH HH; </string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string> </string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2" >
|
||||
<widget class="QComboBox" name="senderHwAddrMode" >
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Fixed</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Increment</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Decrement</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3" >
|
||||
<widget class="QLineEdit" name="senderHwAddrCount" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
|
||||
<horstretch>255</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QLabel" name="label_20" >
|
||||
<property name="text" >
|
||||
<string>Sender Protocol</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>senderProtoAddr</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" >
|
||||
<widget class="QLineEdit" name="senderProtoAddr" >
|
||||
<property name="inputMask" >
|
||||
<string>009.009.009.009; </string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2" >
|
||||
<widget class="QComboBox" name="senderProtoAddrMode" >
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Fixed</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Increment Host</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Decrement Host</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Random Host</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3" >
|
||||
<widget class="QLineEdit" name="senderProtoAddrCount" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
|
||||
<horstretch>255</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="4" >
|
||||
<widget class="QLineEdit" name="senderProtoAddrMask" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="inputMask" >
|
||||
<string>009.009.009.009; </string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" >
|
||||
<widget class="QLabel" name="label_5" >
|
||||
<property name="text" >
|
||||
<string>Target Hardware</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>targetHwAddr</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" >
|
||||
<widget class="QLineEdit" name="targetHwAddr" >
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="inputMask" >
|
||||
<string>>HH HH HH HH HH HH; </string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string> </string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2" >
|
||||
<widget class="QComboBox" name="targetHwAddrMode" >
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Fixed</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Increment</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Decrement</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3" >
|
||||
<widget class="QLineEdit" name="targetHwAddrCount" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
|
||||
<horstretch>255</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="cursorPosition" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" >
|
||||
<widget class="QLabel" name="label_21" >
|
||||
<property name="text" >
|
||||
<string>Target Protocol</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>targetProtoAddr</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" >
|
||||
<widget class="QLineEdit" name="targetProtoAddr" >
|
||||
<property name="inputMask" >
|
||||
<string>000.000.000.000; </string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2" >
|
||||
<widget class="QComboBox" name="targetProtoAddrMode" >
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Fixed</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Increment Host</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Decrement Host</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text" >
|
||||
<string>Random Host</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3" >
|
||||
<widget class="QLineEdit" name="targetProtoAddrCount" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Expanding" >
|
||||
<horstretch>255</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="4" >
|
||||
<widget class="QLineEdit" name="targetProtoAddrMask" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="inputMask" >
|
||||
<string>009.009.009.009; </string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="alignment" >
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>61</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>IntComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>intcombobox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>hwType</tabstop>
|
||||
<tabstop>protoType</tabstop>
|
||||
<tabstop>hwAddrLen</tabstop>
|
||||
<tabstop>protoAddrLen</tabstop>
|
||||
<tabstop>senderHwAddr</tabstop>
|
||||
<tabstop>senderHwAddrMode</tabstop>
|
||||
<tabstop>senderHwAddrCount</tabstop>
|
||||
<tabstop>senderProtoAddr</tabstop>
|
||||
<tabstop>senderProtoAddrMode</tabstop>
|
||||
<tabstop>senderProtoAddrCount</tabstop>
|
||||
<tabstop>senderProtoAddrMask</tabstop>
|
||||
<tabstop>targetHwAddr</tabstop>
|
||||
<tabstop>targetHwAddrMode</tabstop>
|
||||
<tabstop>targetHwAddrCount</tabstop>
|
||||
<tabstop>targetProtoAddr</tabstop>
|
||||
<tabstop>targetProtoAddrMode</tabstop>
|
||||
<tabstop>targetProtoAddrCount</tabstop>
|
||||
<tabstop>targetProtoAddrMask</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
223
common/comboprotocol.h
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
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 _COMBO_PROTOCOL_H
|
||||
#define _COMBO_PROTOCOL_H
|
||||
|
||||
#include "abstractprotocol.h"
|
||||
|
||||
template <int protoNumber, class ProtoA, class ProtoB>
|
||||
class ComboProtocol : public AbstractProtocol
|
||||
{
|
||||
protected:
|
||||
ProtoA *protoA;
|
||||
ProtoB *protoB;
|
||||
QWidget *configForm;
|
||||
|
||||
public:
|
||||
ComboProtocol(StreamBase *stream, AbstractProtocol *parent = 0)
|
||||
: AbstractProtocol(stream, parent)
|
||||
{
|
||||
protoA = new ProtoA(stream, this);
|
||||
protoB = new ProtoB(stream, this);
|
||||
protoA->next = protoB;
|
||||
protoB->prev = protoA;
|
||||
configForm = NULL;
|
||||
|
||||
qDebug("%s: protoNumber = %d, %p <--> %p", __FUNCTION__,
|
||||
protoNumber, protoA, protoB);
|
||||
}
|
||||
|
||||
virtual ~ComboProtocol()
|
||||
{
|
||||
if (configForm)
|
||||
{
|
||||
protoA->configWidget()->setParent(0);
|
||||
protoB->configWidget()->setParent(0);
|
||||
delete configForm;
|
||||
}
|
||||
delete protoA;
|
||||
delete protoB;
|
||||
}
|
||||
|
||||
static ComboProtocol* createInstance(StreamBase *stream,
|
||||
AbstractProtocol *parent)
|
||||
{
|
||||
return new ComboProtocol<protoNumber, ProtoA, ProtoB>(stream, parent);
|
||||
}
|
||||
|
||||
virtual quint32 protocolNumber() const
|
||||
{
|
||||
return protoNumber;
|
||||
}
|
||||
|
||||
virtual void protoDataCopyInto(OstProto::Protocol &protocol) const
|
||||
{
|
||||
protoA->protoDataCopyInto(protocol);
|
||||
protoB->protoDataCopyInto(protocol);
|
||||
protocol.mutable_protocol_id()->set_id(protocolNumber());
|
||||
}
|
||||
|
||||
virtual void protoDataCopyFrom(const OstProto::Protocol &protocol)
|
||||
{
|
||||
if (protocol.protocol_id().id() == protocolNumber())
|
||||
{
|
||||
OstProto::Protocol proto;
|
||||
|
||||
// NOTE: To use protoX->protoDataCopyFrom() we need to arrange
|
||||
// so that it sees its own protocolNumber() - but since the
|
||||
// input param 'protocol' is 'const', we work on a copy
|
||||
proto.CopyFrom(protocol);
|
||||
|
||||
proto.mutable_protocol_id()->set_id(protoA->protocolNumber());
|
||||
protoA->protoDataCopyFrom(proto);
|
||||
|
||||
proto.mutable_protocol_id()->set_id(protoB->protocolNumber());
|
||||
protoB->protoDataCopyFrom(proto);
|
||||
}
|
||||
}
|
||||
|
||||
virtual QString name() const
|
||||
{
|
||||
return protoA->name() + "/" + protoB->name();
|
||||
}
|
||||
virtual QString shortName() const
|
||||
{
|
||||
return protoA->shortName() + "/" + protoB->shortName();
|
||||
}
|
||||
|
||||
virtual ProtocolIdType protocolIdType() const
|
||||
{
|
||||
return protoB->protocolIdType();
|
||||
}
|
||||
|
||||
virtual quint32 protocolId(ProtocolIdType type) const
|
||||
{
|
||||
return protoA->protocolId(type);
|
||||
}
|
||||
//quint32 payloadProtocolId(ProtocolIdType type) const;
|
||||
|
||||
virtual int fieldCount() const
|
||||
{
|
||||
return protoA->fieldCount() + protoB->fieldCount();
|
||||
}
|
||||
//virtual int metaFieldCount() const;
|
||||
//int frameFieldCount() const;
|
||||
|
||||
virtual FieldFlags fieldFlags(int index) const
|
||||
{
|
||||
int cnt = protoA->fieldCount();
|
||||
|
||||
if (index < cnt)
|
||||
return protoA->fieldFlags(index);
|
||||
else
|
||||
return protoB->fieldFlags(index - cnt);
|
||||
}
|
||||
virtual QVariant fieldData(int index, FieldAttrib attrib,
|
||||
int streamIndex = 0) const
|
||||
{
|
||||
int cnt = protoA->fieldCount();
|
||||
|
||||
if (index < cnt)
|
||||
return protoA->fieldData(index, attrib, streamIndex);
|
||||
else
|
||||
return protoB->fieldData(index - cnt, attrib, streamIndex);
|
||||
}
|
||||
virtual bool setFieldData(int index, const QVariant &value,
|
||||
FieldAttrib attrib = FieldValue)
|
||||
{
|
||||
int cnt = protoA->fieldCount();
|
||||
|
||||
if (index < cnt)
|
||||
return protoA->setFieldData(index, value, attrib);
|
||||
else
|
||||
return protoB->setFieldData(index - cnt, value, attrib);
|
||||
}
|
||||
|
||||
#if 0
|
||||
QByteArray protocolFrameValue(int streamIndex = 0,
|
||||
bool forCksum = false) const;
|
||||
virtual int protocolFrameSize() const;
|
||||
int protocolFrameOffset() const;
|
||||
int protocolFramePayloadSize() const;
|
||||
#endif
|
||||
|
||||
virtual bool isProtocolFrameValueVariable() const
|
||||
{
|
||||
return (protoA->isProtocolFrameValueVariable()
|
||||
|| protoB->isProtocolFrameValueVariable());
|
||||
}
|
||||
|
||||
virtual bool isProtocolFrameSizeVariable() const
|
||||
{
|
||||
return (protoA->isProtocolFrameSizeVariable()
|
||||
|| protoB->isProtocolFrameSizeVariable());
|
||||
}
|
||||
virtual int protocolFrameVariableCount() const
|
||||
{
|
||||
return AbstractProtocol::lcm(
|
||||
protoA->protocolFrameVariableCount(),
|
||||
protoB->protocolFrameVariableCount());
|
||||
}
|
||||
|
||||
virtual quint32 protocolFrameCksum(int streamIndex = 0,
|
||||
CksumType cksumType = CksumIp) const
|
||||
{
|
||||
// For a Pseudo IP cksum, we assume it is the succeeding protocol
|
||||
// that is requesting it and hence return protoB's cksum;
|
||||
if (cksumType == CksumIpPseudo)
|
||||
return protoB->protocolFrameCksum(streamIndex, cksumType);
|
||||
|
||||
return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType);
|
||||
}
|
||||
#if 0
|
||||
quint32 protocolFrameHeaderCksum(int streamIndex = 0,
|
||||
CksumType cksumType = CksumIp) const;
|
||||
quint32 protocolFramePayloadCksum(int streamIndex = 0,
|
||||
CksumType cksumType = CksumIp) const;
|
||||
#endif
|
||||
|
||||
virtual QWidget* configWidget()
|
||||
{
|
||||
if (configForm == NULL)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
|
||||
configForm = new QWidget;
|
||||
layout->addWidget(protoA->configWidget());
|
||||
layout->addWidget(protoB->configWidget());
|
||||
layout->setSpacing(0);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
configForm->setLayout(layout);
|
||||
}
|
||||
return configForm;
|
||||
}
|
||||
virtual void loadConfigWidget()
|
||||
{
|
||||
protoA->loadConfigWidget();
|
||||
protoB->loadConfigWidget();
|
||||
}
|
||||
virtual void storeConfigWidget()
|
||||
{
|
||||
protoA->storeConfigWidget();
|
||||
protoB->storeConfigWidget();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|