mirror of
https://github.com/olivierkes/manuskript.git
synced 2024-06-14 08:54:34 +12:00
Adds: unit tests and starts refactoring models
This commit is contained in:
commit
64994cde3a
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -11,4 +11,5 @@ icons/Numix
|
||||||
.idea
|
.idea
|
||||||
dist
|
dist
|
||||||
build
|
build
|
||||||
test-projects
|
test-projects
|
||||||
|
.cache
|
||||||
|
|
|
@ -1,339 +0,0 @@
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 2, June 1991
|
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
License is intended to guarantee your freedom to share and change free
|
|
||||||
software--to make sure the software is free for all its users. This
|
|
||||||
General Public License applies to most of the Free Software
|
|
||||||
Foundation's software and to any other program whose authors commit to
|
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
|
||||||
the GNU Lesser General Public License instead.) You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
this service if you wish), that you receive source code or can get it
|
|
||||||
if you want it, that you can change the software or use pieces of it
|
|
||||||
in new free programs; and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
|
||||||
These restrictions translate to certain responsibilities for you if you
|
|
||||||
distribute copies of the software, or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
|
||||||
you have. You must make sure that they, too, receive or can get the
|
|
||||||
source code. And you must show them these terms so they know their
|
|
||||||
rights.
|
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
|
||||||
distribute and/or modify the software.
|
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
|
||||||
that everyone understands that there is no warranty for this free
|
|
||||||
software. If the software is modified by someone else and passed on, we
|
|
||||||
want its recipients to know that what they have is not the original, so
|
|
||||||
that any problems introduced by others will not reflect on the original
|
|
||||||
authors' reputations.
|
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
|
||||||
program will individually obtain patent licenses, in effect making the
|
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
|
||||||
under the terms of this General Public License. The "Program", below,
|
|
||||||
refers to any such program or work, and a "work based on the Program"
|
|
||||||
means either the Program or any derivative work under copyright law:
|
|
||||||
that is to say, a work containing the Program or a portion of it,
|
|
||||||
either verbatim or with modifications and/or translated into another
|
|
||||||
language. (Hereinafter, translation is included without limitation in
|
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running the Program is not restricted, and the output from the Program
|
|
||||||
is covered only if its contents constitute a work based on the
|
|
||||||
Program (independent of having been made by running the Program).
|
|
||||||
Whether that is true depends on what the Program does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
|
||||||
source code as you receive it, in any medium, provided that you
|
|
||||||
conspicuously and appropriately publish on each copy an appropriate
|
|
||||||
copyright notice and disclaimer of warranty; keep intact all the
|
|
||||||
notices that refer to this License and to the absence of any warranty;
|
|
||||||
and give any other recipients of the Program a copy of this License
|
|
||||||
along with the Program.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
|
||||||
of it, thus forming a work based on the Program, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
|
||||||
whole or in part contains or is derived from the Program or any
|
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
|
||||||
parties under the terms of this License.
|
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
|
||||||
when run, you must cause it, when started running for such
|
|
||||||
interactive use in the most ordinary way, to print or display an
|
|
||||||
announcement including an appropriate copyright notice and a
|
|
||||||
notice that there is no warranty (or else, saying that you provide
|
|
||||||
a warranty) and that users may redistribute the program under
|
|
||||||
these conditions, and telling the user how to view a copy of this
|
|
||||||
License. (Exception: if the Program itself is interactive but
|
|
||||||
does not normally print such an announcement, your work based on
|
|
||||||
the Program is not required to print an announcement.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Program,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Program, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Program.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
|
||||||
under Section 2) in object code or executable form under the terms of
|
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
|
||||||
source code, which must be distributed under the terms of Sections
|
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
|
||||||
years, to give any third party, for a charge no more than your
|
|
||||||
cost of physically performing source distribution, a complete
|
|
||||||
machine-readable copy of the corresponding source code, to be
|
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
|
||||||
customarily used for software interchange; or,
|
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
|
||||||
to distribute corresponding source code. (This alternative is
|
|
||||||
allowed only for noncommercial distribution and only if you
|
|
||||||
received the program in object code or executable form with such
|
|
||||||
an offer, in accord with Subsection b above.)
|
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For an executable work, complete source
|
|
||||||
code means all the source code for all modules it contains, plus any
|
|
||||||
associated interface definition files, plus the scripts used to
|
|
||||||
control compilation and installation of the executable. However, as a
|
|
||||||
special exception, the source code distributed need not include
|
|
||||||
anything that is normally distributed (in either source or binary
|
|
||||||
form) with the major components (compiler, kernel, and so on) of the
|
|
||||||
operating system on which the executable runs, unless that component
|
|
||||||
itself accompanies the executable.
|
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
|
||||||
access to copy from a designated place, then offering equivalent
|
|
||||||
access to copy the source code from the same place counts as
|
|
||||||
distribution of the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
|
||||||
except as expressly provided under this License. Any attempt
|
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
|
||||||
void, and will automatically terminate your rights under this License.
|
|
||||||
However, parties who have received copies, or rights, from you under
|
|
||||||
this License will not have their licenses terminated so long as such
|
|
||||||
parties remain in full compliance.
|
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Program or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Program (or any work based on the
|
|
||||||
Program), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Program or works based on it.
|
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
|
||||||
Program), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute or modify the Program subject to
|
|
||||||
these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties to
|
|
||||||
this License.
|
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Program at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Program by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Program.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
|
||||||
any particular circumstance, the balance of the section is intended to
|
|
||||||
apply and the section as a whole is intended to apply in other
|
|
||||||
circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system, which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Program under this License
|
|
||||||
may add an explicit geographical distribution limitation excluding
|
|
||||||
those countries, so that distribution is permitted only in or among
|
|
||||||
countries not thus excluded. In such case, this License incorporates
|
|
||||||
the limitation as if written in the body of this License.
|
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
|
||||||
specifies a version number of this License which applies to it and "any
|
|
||||||
later version", you have the option of following the terms and conditions
|
|
||||||
either of that version or of any later version published by the Free
|
|
||||||
Software Foundation. If the Program does not specify a version number of
|
|
||||||
this License, you may choose any version ever published by the Free Software
|
|
||||||
Foundation.
|
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
|
||||||
programs whose distribution conditions are different, write to the author
|
|
||||||
to ask for permission. For software which is copyrighted by the Free
|
|
||||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
|
||||||
make exceptions for this. Our decision will be guided by the two goals
|
|
||||||
of preserving the free status of all derivatives of our free software and
|
|
||||||
of promoting the sharing and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
|
||||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
|
||||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
|
||||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
|
||||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
|
||||||
REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
|
||||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
|
||||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
|
||||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
|
||||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
|
||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
convey the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program is interactive, make it output a short notice like this
|
|
||||||
when it starts in an interactive mode:
|
|
||||||
|
|
||||||
Gnomovision version 69, Copyright (C) year name of author
|
|
||||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, the commands you use may
|
|
||||||
be called something other than `show w' and `show c'; they could even be
|
|
||||||
mouse-clicks or menu items--whatever suits your program.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
|
||||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1989
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
|
||||||
consider it more useful to permit linking proprietary applications with the
|
|
||||||
library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License.
|
|
|
@ -1,19 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This is free software. You may redistribute it under the terms
|
|
||||||
# of the Apache license and the GNU General Public License Version
|
|
||||||
# 2 or at your option any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public
|
|
||||||
# License along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import ANIMNS
|
|
||||||
from element import Element
|
|
||||||
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def Animate(**args):
|
|
||||||
return Element(qname = (ANIMNS,'animate'), **args)
|
|
||||||
|
|
||||||
def Animatecolor(**args):
|
|
||||||
return Element(qname = (ANIMNS,'animateColor'), **args)
|
|
||||||
|
|
||||||
def Animatemotion(**args):
|
|
||||||
return Element(qname = (ANIMNS,'animateMotion'), **args)
|
|
||||||
|
|
||||||
def Animatetransform(**args):
|
|
||||||
return Element(qname = (ANIMNS,'animateTransform'), **args)
|
|
||||||
|
|
||||||
def Audio(**args):
|
|
||||||
return Element(qname = (ANIMNS,'audio'), **args)
|
|
||||||
|
|
||||||
def Command(**args):
|
|
||||||
return Element(qname = (ANIMNS,'command'), **args)
|
|
||||||
|
|
||||||
def Iterate(**args):
|
|
||||||
return Element(qname = (ANIMNS,'iterate'), **args)
|
|
||||||
|
|
||||||
def Par(**args):
|
|
||||||
return Element(qname = (ANIMNS,'par'), **args)
|
|
||||||
|
|
||||||
def Param(**args):
|
|
||||||
return Element(qname = (ANIMNS,'param'), **args)
|
|
||||||
|
|
||||||
def Seq(**args):
|
|
||||||
return Element(qname = (ANIMNS,'seq'), **args)
|
|
||||||
|
|
||||||
def Set(**args):
|
|
||||||
return Element(qname = (ANIMNS,'set'), **args)
|
|
||||||
|
|
||||||
def Transitionfilter(**args):
|
|
||||||
return Element(qname = (ANIMNS,'transitionFilter'), **args)
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,96 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2013 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from .namespaces import CHARTNS
|
|
||||||
from .element import Element
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def Axis(**args):
|
|
||||||
return Element(qname = (CHARTNS,'axis'), **args)
|
|
||||||
|
|
||||||
def Categories(**args):
|
|
||||||
return Element(qname = (CHARTNS,'categories'), **args)
|
|
||||||
|
|
||||||
def Chart(**args):
|
|
||||||
return Element(qname = (CHARTNS,'chart'), **args)
|
|
||||||
|
|
||||||
def DataLabel(**args):
|
|
||||||
return Element(qname = (CHARTNS,'data-label'), **args)
|
|
||||||
|
|
||||||
def DataPoint(**args):
|
|
||||||
return Element(qname = (CHARTNS,'data-point'), **args)
|
|
||||||
|
|
||||||
def Domain(**args):
|
|
||||||
return Element(qname = (CHARTNS,'domain'), **args)
|
|
||||||
|
|
||||||
def Equation(**args):
|
|
||||||
return Element(qname = (CHARTNS,'equation'), **args)
|
|
||||||
|
|
||||||
def ErrorIndicator(**args):
|
|
||||||
return Element(qname = (CHARTNS,'error-indicator'), **args)
|
|
||||||
|
|
||||||
def Floor(**args):
|
|
||||||
return Element(qname = (CHARTNS,'floor'), **args)
|
|
||||||
|
|
||||||
def Footer(**args):
|
|
||||||
return Element(qname = (CHARTNS,'footer'), **args)
|
|
||||||
|
|
||||||
def Grid(**args):
|
|
||||||
return Element(qname = (CHARTNS,'grid'), **args)
|
|
||||||
|
|
||||||
def LabelSeparator(**args):
|
|
||||||
return Element(qname = (CHARTNS,'label-separator'), **args)
|
|
||||||
|
|
||||||
def Legend(**args):
|
|
||||||
return Element(qname = (CHARTNS,'legend'), **args)
|
|
||||||
|
|
||||||
def MeanValue(**args):
|
|
||||||
return Element(qname = (CHARTNS,'mean-value'), **args)
|
|
||||||
|
|
||||||
def PlotArea(**args):
|
|
||||||
return Element(qname = (CHARTNS,'plot-area'), **args)
|
|
||||||
|
|
||||||
def RegressionCurve(**args):
|
|
||||||
return Element(qname = (CHARTNS,'regression-curve'), **args)
|
|
||||||
|
|
||||||
def Series(**args):
|
|
||||||
return Element(qname = (CHARTNS,'series'), **args)
|
|
||||||
|
|
||||||
def StockGainMarker(**args):
|
|
||||||
return Element(qname = (CHARTNS,'stock-gain-marker'), **args)
|
|
||||||
|
|
||||||
def StockLossMarker(**args):
|
|
||||||
return Element(qname = (CHARTNS,'stock-loss-marker'), **args)
|
|
||||||
|
|
||||||
def StockRangeLine(**args):
|
|
||||||
return Element(qname = (CHARTNS,'stock-range-line'), **args)
|
|
||||||
|
|
||||||
def Subtitle(**args):
|
|
||||||
return Element(qname = (CHARTNS,'subtitle'), **args)
|
|
||||||
|
|
||||||
def SymbolImage(**args):
|
|
||||||
return Element(qname = (CHARTNS,'symbol-image'), **args)
|
|
||||||
|
|
||||||
def Title(**args):
|
|
||||||
return Element(qname = (CHARTNS,'title'), **args)
|
|
||||||
|
|
||||||
def Wall(**args):
|
|
||||||
return Element(qname = (CHARTNS,'wall'), **args)
|
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import CONFIGNS
|
|
||||||
from element import Element
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def ConfigItem(**args):
|
|
||||||
return Element(qname = (CONFIGNS, 'config-item'), **args)
|
|
||||||
|
|
||||||
def ConfigItemMapEntry(**args):
|
|
||||||
return Element(qname = (CONFIGNS,'config-item-map-entry'), **args)
|
|
||||||
|
|
||||||
def ConfigItemMapIndexed(**args):
|
|
||||||
return Element(qname = (CONFIGNS,'config-item-map-indexed'), **args)
|
|
||||||
|
|
||||||
def ConfigItemMapNamed(**args):
|
|
||||||
return Element(qname = (CONFIGNS,'config-item-map-named'), **args)
|
|
||||||
|
|
||||||
def ConfigItemSet(**args):
|
|
||||||
return Element(qname = (CONFIGNS, 'config-item-set'), **args)
|
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import DCNS
|
|
||||||
from element import Element
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def Creator(**args):
|
|
||||||
return Element(qname = (DCNS,'creator'), **args)
|
|
||||||
|
|
||||||
def Date(**args):
|
|
||||||
return Element(qname = (DCNS,'date'), **args)
|
|
||||||
|
|
||||||
def Description(**args):
|
|
||||||
return Element(qname = (DCNS,'description'), **args)
|
|
||||||
|
|
||||||
def Language(**args):
|
|
||||||
return Element(qname = (DCNS,'language'), **args)
|
|
||||||
|
|
||||||
def Subject(**args):
|
|
||||||
return Element(qname = (DCNS,'subject'), **args)
|
|
||||||
|
|
||||||
def Title(**args):
|
|
||||||
return Element(qname = (DCNS,'title'), **args)
|
|
||||||
|
|
||||||
# The following complete the Dublin Core elements, but there is no
|
|
||||||
# guarantee a compliant implementation of OpenDocument will preserve
|
|
||||||
# these elements
|
|
||||||
|
|
||||||
#def Contributor(**args):
|
|
||||||
# return Element(qname = (DCNS,'contributor'), **args)
|
|
||||||
|
|
||||||
#def Coverage(**args):
|
|
||||||
# return Element(qname = (DCNS,'coverage'), **args)
|
|
||||||
|
|
||||||
#def Format(**args):
|
|
||||||
# return Element(qname = (DCNS,'format'), **args)
|
|
||||||
|
|
||||||
#def Identifier(**args):
|
|
||||||
# return Element(qname = (DCNS,'identifier'), **args)
|
|
||||||
|
|
||||||
#def Publisher(**args):
|
|
||||||
# return Element(qname = (DCNS,'publisher'), **args)
|
|
||||||
|
|
||||||
#def Relation(**args):
|
|
||||||
# return Element(qname = (DCNS,'relation'), **args)
|
|
||||||
|
|
||||||
#def Rights(**args):
|
|
||||||
# return Element(qname = (DCNS,'rights'), **args)
|
|
||||||
|
|
||||||
#def Source(**args):
|
|
||||||
# return Element(qname = (DCNS,'source'), **args)
|
|
||||||
|
|
||||||
#def Type(**args):
|
|
||||||
# return Element(qname = (DCNS,'type'), **args)
|
|
|
@ -1,45 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
import sys, os.path
|
|
||||||
sys.path.append(os.path.dirname(__file__))
|
|
||||||
|
|
||||||
from namespaces import DR3DNS
|
|
||||||
from element import Element
|
|
||||||
from draw import StyleRefElement
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def Cube(**args):
|
|
||||||
return StyleRefElement(qname = (DR3DNS,'cube'), **args)
|
|
||||||
|
|
||||||
def Extrude(**args):
|
|
||||||
return StyleRefElement(qname = (DR3DNS,'extrude'), **args)
|
|
||||||
|
|
||||||
def Light(Element):
|
|
||||||
return StyleRefElement(qname = (DR3DNS,'light'), **args)
|
|
||||||
|
|
||||||
def Rotate(**args):
|
|
||||||
return StyleRefElement(qname = (DR3DNS,'rotate'), **args)
|
|
||||||
|
|
||||||
def Scene(**args):
|
|
||||||
return StyleRefElement(qname = (DR3DNS,'scene'), **args)
|
|
||||||
|
|
||||||
def Sphere(**args):
|
|
||||||
return StyleRefElement(qname = (DR3DNS,'sphere'), **args)
|
|
||||||
|
|
188
libs/odf/draw.py
188
libs/odf/draw.py
|
@ -1,188 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
import sys, os.path
|
|
||||||
sys.path.append(os.path.dirname(__file__))
|
|
||||||
from namespaces import DRAWNS, STYLENS, PRESENTATIONNS
|
|
||||||
from element import Element
|
|
||||||
|
|
||||||
def StyleRefElement(stylename=None, classnames=None, **args):
|
|
||||||
qattrs = {}
|
|
||||||
if stylename is not None:
|
|
||||||
f = stylename.getAttrNS(STYLENS, 'family')
|
|
||||||
if f == 'graphic':
|
|
||||||
qattrs[(DRAWNS,u'style-name')]= stylename
|
|
||||||
elif f == 'presentation':
|
|
||||||
qattrs[(PRESENTATIONNS,u'style-name')]= stylename
|
|
||||||
else:
|
|
||||||
raise ValueError( "Style's family must be either 'graphic' or 'presentation'")
|
|
||||||
if classnames is not None:
|
|
||||||
f = classnames[0].getAttrNS(STYLENS, 'family')
|
|
||||||
if f == 'graphic':
|
|
||||||
qattrs[(DRAWNS,u'class-names')]= classnames
|
|
||||||
elif f == 'presentation':
|
|
||||||
qattrs[(PRESENTATIONNS,u'class-names')]= classnames
|
|
||||||
else:
|
|
||||||
raise ValueError( "Style's family must be either 'graphic' or 'presentation'")
|
|
||||||
return Element(qattributes=qattrs, **args)
|
|
||||||
|
|
||||||
def DrawElement(name=None, **args):
|
|
||||||
e = Element(name=name, **args)
|
|
||||||
if 'displayname' not in args:
|
|
||||||
e.setAttrNS(DRAWNS,'display-name', name)
|
|
||||||
return e
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def A(**args):
|
|
||||||
args.setdefault('type', 'simple')
|
|
||||||
return Element(qname = (DRAWNS,'a'), **args)
|
|
||||||
|
|
||||||
def Applet(**args):
|
|
||||||
return Element(qname = (DRAWNS,'applet'), **args)
|
|
||||||
|
|
||||||
def AreaCircle(**args):
|
|
||||||
return Element(qname = (DRAWNS,'area-circle'), **args)
|
|
||||||
|
|
||||||
def AreaPolygon(**args):
|
|
||||||
return Element(qname = (DRAWNS,'area-polygon'), **args)
|
|
||||||
|
|
||||||
def AreaRectangle(**args):
|
|
||||||
return Element(qname = (DRAWNS,'area-rectangle'), **args)
|
|
||||||
|
|
||||||
def Caption(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'caption'), **args)
|
|
||||||
|
|
||||||
def Circle(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'circle'), **args)
|
|
||||||
|
|
||||||
def Connector(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'connector'), **args)
|
|
||||||
|
|
||||||
def ContourPath(**args):
|
|
||||||
return Element(qname = (DRAWNS,'contour-path'), **args)
|
|
||||||
|
|
||||||
def ContourPolygon(**args):
|
|
||||||
return Element(qname = (DRAWNS,'contour-polygon'), **args)
|
|
||||||
|
|
||||||
def Control(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'control'), **args)
|
|
||||||
|
|
||||||
def CustomShape(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'custom-shape'), **args)
|
|
||||||
|
|
||||||
def Ellipse(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'ellipse'), **args)
|
|
||||||
|
|
||||||
def EnhancedGeometry(**args):
|
|
||||||
return Element(qname = (DRAWNS,'enhanced-geometry'), **args)
|
|
||||||
|
|
||||||
def Equation(**args):
|
|
||||||
return Element(qname = (DRAWNS,'equation'), **args)
|
|
||||||
|
|
||||||
def FillImage(**args):
|
|
||||||
args.setdefault('type', 'simple')
|
|
||||||
return DrawElement(qname = (DRAWNS,'fill-image'), **args)
|
|
||||||
|
|
||||||
def FloatingFrame(**args):
|
|
||||||
args.setdefault('type', 'simple')
|
|
||||||
return Element(qname = (DRAWNS,'floating-frame'), **args)
|
|
||||||
|
|
||||||
def Frame(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'frame'), **args)
|
|
||||||
|
|
||||||
def G(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'g'), **args)
|
|
||||||
|
|
||||||
def GluePoint(**args):
|
|
||||||
return Element(qname = (DRAWNS,'glue-point'), **args)
|
|
||||||
|
|
||||||
def Gradient(**args):
|
|
||||||
return DrawElement(qname = (DRAWNS,'gradient'), **args)
|
|
||||||
|
|
||||||
def Handle(**args):
|
|
||||||
return Element(qname = (DRAWNS,'handle'), **args)
|
|
||||||
|
|
||||||
def Hatch(**args):
|
|
||||||
return DrawElement(qname = (DRAWNS,'hatch'), **args)
|
|
||||||
|
|
||||||
def Image(**args):
|
|
||||||
return Element(qname = (DRAWNS,'image'), **args)
|
|
||||||
|
|
||||||
def ImageMap(**args):
|
|
||||||
return Element(qname = (DRAWNS,'image-map'), **args)
|
|
||||||
|
|
||||||
def Layer(**args):
|
|
||||||
return Element(qname = (DRAWNS,'layer'), **args)
|
|
||||||
|
|
||||||
def LayerSet(**args):
|
|
||||||
return Element(qname = (DRAWNS,'layer-set'), **args)
|
|
||||||
|
|
||||||
def Line(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'line'), **args)
|
|
||||||
|
|
||||||
def Marker(**args):
|
|
||||||
return DrawElement(qname = (DRAWNS,'marker'), **args)
|
|
||||||
|
|
||||||
def Measure(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'measure'), **args)
|
|
||||||
|
|
||||||
def Object(**args):
|
|
||||||
return Element(qname = (DRAWNS,'object'), **args)
|
|
||||||
|
|
||||||
def ObjectOle(**args):
|
|
||||||
return Element(qname = (DRAWNS,'object-ole'), **args)
|
|
||||||
|
|
||||||
def Opacity(**args):
|
|
||||||
return DrawElement(qname = (DRAWNS,'opacity'), **args)
|
|
||||||
|
|
||||||
def Page(**args):
|
|
||||||
return Element(qname = (DRAWNS,'page'), **args)
|
|
||||||
|
|
||||||
def PageThumbnail(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'page-thumbnail'), **args)
|
|
||||||
|
|
||||||
def Param(**args):
|
|
||||||
return Element(qname = (DRAWNS,'param'), **args)
|
|
||||||
|
|
||||||
def Path(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'path'), **args)
|
|
||||||
|
|
||||||
def Plugin(**args):
|
|
||||||
args.setdefault('type', 'simple')
|
|
||||||
return Element(qname = (DRAWNS,'plugin'), **args)
|
|
||||||
|
|
||||||
def Polygon(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'polygon'), **args)
|
|
||||||
|
|
||||||
def Polyline(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'polyline'), **args)
|
|
||||||
|
|
||||||
def Rect(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'rect'), **args)
|
|
||||||
|
|
||||||
def RegularPolygon(**args):
|
|
||||||
return StyleRefElement(qname = (DRAWNS,'regular-polygon'), **args)
|
|
||||||
|
|
||||||
def StrokeDash(**args):
|
|
||||||
return DrawElement(qname = (DRAWNS,'stroke-dash'), **args)
|
|
||||||
|
|
||||||
def TextBox(**args):
|
|
||||||
return Element(qname = (DRAWNS,'text-box'), **args)
|
|
||||||
|
|
|
@ -1,104 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Create a <text:list-style> element from a text string.
|
|
||||||
# Copyright (C) 2008 J. David Eisenberg
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along
|
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
import re, sys, os.path
|
|
||||||
sys.path.append(os.path.dirname(__file__))
|
|
||||||
from style import Style, TextProperties, ListLevelProperties
|
|
||||||
from text import ListStyle,ListLevelStyleNumber,ListLevelStyleBullet
|
|
||||||
|
|
||||||
"""
|
|
||||||
Create a <text:list-style> element from a string or array.
|
|
||||||
|
|
||||||
List styles require a lot of code to create one level at a time.
|
|
||||||
These routines take a string and delimiter, or a list of
|
|
||||||
strings, and creates a <text:list-style> element for you.
|
|
||||||
Each item in the string (or array) represents a list level
|
|
||||||
* style for levels 1-10.</p>
|
|
||||||
*
|
|
||||||
* <p>If an item contains <code>1</code>, <code>I</code>,
|
|
||||||
* <code>i</code>, <code>A</code>, or <code>a</code>, then it is presumed
|
|
||||||
* to be a numbering style; otherwise it is a bulleted style.</p>
|
|
||||||
"""
|
|
||||||
|
|
||||||
_MAX_LIST_LEVEL = 10
|
|
||||||
SHOW_ALL_LEVELS = True
|
|
||||||
SHOW_ONE_LEVEL = False
|
|
||||||
|
|
||||||
def styleFromString(name, specifiers, delim, spacing, showAllLevels):
|
|
||||||
specArray = specifiers.split(delim)
|
|
||||||
return styleFromList( name, specArray, spacing, showAllLevels )
|
|
||||||
|
|
||||||
def styleFromList( styleName, specArray, spacing, showAllLevels):
|
|
||||||
bullet = ""
|
|
||||||
numPrefix = ""
|
|
||||||
numSuffix = ""
|
|
||||||
numberFormat = ""
|
|
||||||
cssLengthNum = 0
|
|
||||||
cssLengthUnits = ""
|
|
||||||
numbered = False
|
|
||||||
displayLevels = 0
|
|
||||||
listStyle = ListStyle(name=styleName)
|
|
||||||
numFormatPattern = re.compile("([1IiAa])")
|
|
||||||
cssLengthPattern = re.compile("([^a-z]+)\\s*([a-z]+)?")
|
|
||||||
m = cssLengthPattern.search( spacing )
|
|
||||||
if (m != None):
|
|
||||||
cssLengthNum = float(m.group(1))
|
|
||||||
if (m.lastindex == 2):
|
|
||||||
cssLengthUnits = m.group(2)
|
|
||||||
i = 0
|
|
||||||
while i < len(specArray):
|
|
||||||
specification = specArray[i]
|
|
||||||
m = numFormatPattern.search(specification)
|
|
||||||
if (m != None):
|
|
||||||
numberFormat = m.group(1)
|
|
||||||
numPrefix = specification[0:m.start(1)]
|
|
||||||
numSuffix = specification[m.end(1):]
|
|
||||||
bullet = ""
|
|
||||||
numbered = True
|
|
||||||
if (showAllLevels):
|
|
||||||
displayLevels = i + 1
|
|
||||||
else:
|
|
||||||
displayLevels = 1
|
|
||||||
else: # it's a bullet style
|
|
||||||
bullet = specification
|
|
||||||
numPrefix = ""
|
|
||||||
numSuffix = ""
|
|
||||||
numberFormat = ""
|
|
||||||
displayLevels = 1
|
|
||||||
numbered = False
|
|
||||||
if (numbered):
|
|
||||||
lls = ListLevelStyleNumber(level=(i+1))
|
|
||||||
if (numPrefix != ''):
|
|
||||||
lls.setAttribute('numprefix', numPrefix)
|
|
||||||
if (numSuffix != ''):
|
|
||||||
lls.setAttribute('numsuffix', numSuffix)
|
|
||||||
lls.setAttribute('displaylevels', displayLevels)
|
|
||||||
else:
|
|
||||||
lls = ListLevelStyleBullet(level=(i+1),bulletchar=bullet[0])
|
|
||||||
llp = ListLevelProperties()
|
|
||||||
llp.setAttribute('spacebefore', str(cssLengthNum * (i+1)) + cssLengthUnits)
|
|
||||||
llp.setAttribute('minlabelwidth', str(cssLengthNum) + cssLengthUnits)
|
|
||||||
lls.addElement( llp )
|
|
||||||
listStyle.addElement(lls)
|
|
||||||
i += 1
|
|
||||||
return listStyle
|
|
||||||
|
|
||||||
# vim: set expandtab sw=4 :
|
|
|
@ -1,541 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2007-2010 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
# Note: This script has copied a lot of text from xml.dom.minidom.
|
|
||||||
# Whatever license applies to that file also applies to this file.
|
|
||||||
#
|
|
||||||
import sys, os.path
|
|
||||||
sys.path.append(os.path.dirname(__file__))
|
|
||||||
import xml.dom
|
|
||||||
from xml.dom.minicompat import *
|
|
||||||
from namespaces import nsdict
|
|
||||||
import grammar
|
|
||||||
from attrconverters import AttrConverters
|
|
||||||
|
|
||||||
if sys.version_info[0] == 3:
|
|
||||||
unicode=str # unicode function does not exist
|
|
||||||
|
|
||||||
# The following code is pasted form xml.sax.saxutils
|
|
||||||
# Tt makes it possible to run the code without the xml sax package installed
|
|
||||||
# To make it possible to have <rubbish> in your text elements, it is necessary to escape the texts
|
|
||||||
def _escape(data, entities={}):
|
|
||||||
""" Escape &, <, and > in a string of data.
|
|
||||||
|
|
||||||
You can escape other strings of data by passing a dictionary as
|
|
||||||
the optional entities parameter. The keys and values must all be
|
|
||||||
strings; each key will be replaced with its corresponding value.
|
|
||||||
"""
|
|
||||||
data = data.replace("&", "&")
|
|
||||||
data = data.replace("<", "<")
|
|
||||||
data = data.replace(">", ">")
|
|
||||||
for chars, entity in entities.items():
|
|
||||||
data = data.replace(chars, entity)
|
|
||||||
return data
|
|
||||||
|
|
||||||
def _quoteattr(data, entities={}):
|
|
||||||
""" Escape and quote an attribute value.
|
|
||||||
|
|
||||||
Escape &, <, and > in a string of data, then quote it for use as
|
|
||||||
an attribute value. The \" character will be escaped as well, if
|
|
||||||
necessary.
|
|
||||||
|
|
||||||
You can escape other strings of data by passing a dictionary as
|
|
||||||
the optional entities parameter. The keys and values must all be
|
|
||||||
strings; each key will be replaced with its corresponding value.
|
|
||||||
"""
|
|
||||||
entities['\n']=' '
|
|
||||||
entities['\r']=''
|
|
||||||
data = _escape(data, entities)
|
|
||||||
if '"' in data:
|
|
||||||
if "'" in data:
|
|
||||||
data = '"%s"' % data.replace('"', """)
|
|
||||||
else:
|
|
||||||
data = "'%s'" % data
|
|
||||||
else:
|
|
||||||
data = '"%s"' % data
|
|
||||||
return data
|
|
||||||
|
|
||||||
def _nssplit(qualifiedName):
|
|
||||||
""" Split a qualified name into namespace part and local part. """
|
|
||||||
fields = qualifiedName.split(':', 1)
|
|
||||||
if len(fields) == 2:
|
|
||||||
return fields
|
|
||||||
else:
|
|
||||||
return (None, fields[0])
|
|
||||||
|
|
||||||
def _nsassign(namespace):
|
|
||||||
return nsdict.setdefault(namespace,"ns" + str(len(nsdict)))
|
|
||||||
|
|
||||||
|
|
||||||
# Exceptions
|
|
||||||
class IllegalChild(Exception):
|
|
||||||
""" Complains if you add an element to a parent where it is not allowed """
|
|
||||||
class IllegalText(Exception):
|
|
||||||
""" Complains if you add text or cdata to an element where it is not allowed """
|
|
||||||
|
|
||||||
class Node(xml.dom.Node):
|
|
||||||
""" super class for more specific nodes """
|
|
||||||
parentNode = None
|
|
||||||
nextSibling = None
|
|
||||||
previousSibling = None
|
|
||||||
|
|
||||||
def hasChildNodes(self):
|
|
||||||
""" Tells whether this element has any children; text nodes,
|
|
||||||
subelements, whatever.
|
|
||||||
"""
|
|
||||||
if self.childNodes:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _get_childNodes(self):
|
|
||||||
return self.childNodes
|
|
||||||
|
|
||||||
def _get_firstChild(self):
|
|
||||||
if self.childNodes:
|
|
||||||
return self.childNodes[0]
|
|
||||||
|
|
||||||
def _get_lastChild(self):
|
|
||||||
if self.childNodes:
|
|
||||||
return self.childNodes[-1]
|
|
||||||
|
|
||||||
def insertBefore(self, newChild, refChild):
|
|
||||||
""" Inserts the node newChild before the existing child node refChild.
|
|
||||||
If refChild is null, insert newChild at the end of the list of children.
|
|
||||||
"""
|
|
||||||
if newChild.nodeType not in self._child_node_types:
|
|
||||||
raise IllegalChild( "%s cannot be child of %s" % (newChild.tagName, self.tagName))
|
|
||||||
if newChild.parentNode is not None:
|
|
||||||
newChild.parentNode.removeChild(newChild)
|
|
||||||
if refChild is None:
|
|
||||||
self.appendChild(newChild)
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
index = self.childNodes.index(refChild)
|
|
||||||
except ValueError:
|
|
||||||
raise xml.dom.NotFoundErr()
|
|
||||||
self.childNodes.insert(index, newChild)
|
|
||||||
newChild.nextSibling = refChild
|
|
||||||
refChild.previousSibling = newChild
|
|
||||||
if index:
|
|
||||||
node = self.childNodes[index-1]
|
|
||||||
node.nextSibling = newChild
|
|
||||||
newChild.previousSibling = node
|
|
||||||
else:
|
|
||||||
newChild.previousSibling = None
|
|
||||||
newChild.parentNode = self
|
|
||||||
return newChild
|
|
||||||
|
|
||||||
def appendChild(self, newChild):
|
|
||||||
""" Adds the node newChild to the end of the list of children of this node.
|
|
||||||
If the newChild is already in the tree, it is first removed.
|
|
||||||
"""
|
|
||||||
if newChild.nodeType == self.DOCUMENT_FRAGMENT_NODE:
|
|
||||||
for c in tuple(newChild.childNodes):
|
|
||||||
self.appendChild(c)
|
|
||||||
### The DOM does not clearly specify what to return in this case
|
|
||||||
return newChild
|
|
||||||
if newChild.nodeType not in self._child_node_types:
|
|
||||||
raise IllegalChild( "<%s> is not allowed in %s" % ( newChild.tagName, self.tagName))
|
|
||||||
if newChild.parentNode is not None:
|
|
||||||
newChild.parentNode.removeChild(newChild)
|
|
||||||
_append_child(self, newChild)
|
|
||||||
newChild.nextSibling = None
|
|
||||||
return newChild
|
|
||||||
|
|
||||||
def removeChild(self, oldChild):
|
|
||||||
""" Removes the child node indicated by oldChild from the list of children, and returns it.
|
|
||||||
"""
|
|
||||||
#FIXME: update ownerDocument.element_dict or find other solution
|
|
||||||
try:
|
|
||||||
self.childNodes.remove(oldChild)
|
|
||||||
except ValueError:
|
|
||||||
raise xml.dom.NotFoundErr()
|
|
||||||
if oldChild.nextSibling is not None:
|
|
||||||
oldChild.nextSibling.previousSibling = oldChild.previousSibling
|
|
||||||
if oldChild.previousSibling is not None:
|
|
||||||
oldChild.previousSibling.nextSibling = oldChild.nextSibling
|
|
||||||
oldChild.nextSibling = oldChild.previousSibling = None
|
|
||||||
if self.ownerDocument:
|
|
||||||
self.ownerDocument.clear_caches()
|
|
||||||
oldChild.parentNode = None
|
|
||||||
return oldChild
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
val = []
|
|
||||||
for c in self.childNodes:
|
|
||||||
val.append(str(c))
|
|
||||||
return ''.join(val)
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
val = []
|
|
||||||
for c in self.childNodes:
|
|
||||||
val.append(unicode(c))
|
|
||||||
return u''.join(val)
|
|
||||||
|
|
||||||
defproperty(Node, "firstChild", doc="First child node, or None.")
|
|
||||||
defproperty(Node, "lastChild", doc="Last child node, or None.")
|
|
||||||
|
|
||||||
def _append_child(self, node):
|
|
||||||
# fast path with less checks; usable by DOM builders if careful
|
|
||||||
childNodes = self.childNodes
|
|
||||||
if childNodes:
|
|
||||||
last = childNodes[-1]
|
|
||||||
node.__dict__["previousSibling"] = last
|
|
||||||
last.__dict__["nextSibling"] = node
|
|
||||||
childNodes.append(node)
|
|
||||||
node.__dict__["parentNode"] = self
|
|
||||||
|
|
||||||
class Childless:
|
|
||||||
""" Mixin that makes childless-ness easy to implement and avoids
|
|
||||||
the complexity of the Node methods that deal with children.
|
|
||||||
"""
|
|
||||||
|
|
||||||
attributes = None
|
|
||||||
childNodes = EmptyNodeList()
|
|
||||||
firstChild = None
|
|
||||||
lastChild = None
|
|
||||||
|
|
||||||
def _get_firstChild(self):
|
|
||||||
return None
|
|
||||||
|
|
||||||
def _get_lastChild(self):
|
|
||||||
return None
|
|
||||||
|
|
||||||
def appendChild(self, node):
|
|
||||||
""" Raises an error """
|
|
||||||
raise xml.dom.HierarchyRequestErr(
|
|
||||||
self.tagName + " nodes cannot have children")
|
|
||||||
|
|
||||||
def hasChildNodes(self):
|
|
||||||
return False
|
|
||||||
|
|
||||||
def insertBefore(self, newChild, refChild):
|
|
||||||
""" Raises an error """
|
|
||||||
raise xml.dom.HierarchyRequestErr(
|
|
||||||
self.tagName + " nodes do not have children")
|
|
||||||
|
|
||||||
def removeChild(self, oldChild):
|
|
||||||
""" Raises an error """
|
|
||||||
raise xml.dom.NotFoundErr(
|
|
||||||
self.tagName + " nodes do not have children")
|
|
||||||
|
|
||||||
def replaceChild(self, newChild, oldChild):
|
|
||||||
""" Raises an error """
|
|
||||||
raise xml.dom.HierarchyRequestErr(
|
|
||||||
self.tagName + " nodes do not have children")
|
|
||||||
|
|
||||||
class Text(Childless, Node):
|
|
||||||
nodeType = Node.TEXT_NODE
|
|
||||||
tagName = "Text"
|
|
||||||
|
|
||||||
def __init__(self, data):
|
|
||||||
self.data = data
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.data
|
|
||||||
|
|
||||||
def __unicode__(self):
|
|
||||||
return self.data
|
|
||||||
|
|
||||||
def toXml(self,level,f):
|
|
||||||
""" Write XML in UTF-8 """
|
|
||||||
if self.data:
|
|
||||||
f.write(_escape(unicode(self.data)))
|
|
||||||
|
|
||||||
class CDATASection(Text, Childless):
|
|
||||||
nodeType = Node.CDATA_SECTION_NODE
|
|
||||||
|
|
||||||
def toXml(self,level,f):
|
|
||||||
""" Generate XML output of the node. If the text contains "]]>", then
|
|
||||||
escape it by going out of CDATA mode (]]>), then write the string
|
|
||||||
and then go into CDATA mode again. (<![CDATA[)
|
|
||||||
"""
|
|
||||||
if self.data:
|
|
||||||
f.write('<![CDATA[%s]]>' % self.data.replace(']]>',']]>]]><![CDATA['))
|
|
||||||
|
|
||||||
class Element(Node):
|
|
||||||
""" Creates a arbitrary element and is intended to be subclassed not used on its own.
|
|
||||||
This element is the base of every element it defines a class which resembles
|
|
||||||
a xml-element. The main advantage of this kind of implementation is that you don't
|
|
||||||
have to create a toXML method for every different object. Every element
|
|
||||||
consists of an attribute, optional subelements, optional text and optional cdata.
|
|
||||||
"""
|
|
||||||
|
|
||||||
nodeType = Node.ELEMENT_NODE
|
|
||||||
namespaces = {} # Due to shallow copy this is a static variable
|
|
||||||
|
|
||||||
_child_node_types = (Node.ELEMENT_NODE,
|
|
||||||
Node.PROCESSING_INSTRUCTION_NODE,
|
|
||||||
Node.COMMENT_NODE,
|
|
||||||
Node.TEXT_NODE,
|
|
||||||
Node.CDATA_SECTION_NODE,
|
|
||||||
Node.ENTITY_REFERENCE_NODE)
|
|
||||||
|
|
||||||
def __init__(self, attributes=None, text=None, cdata=None, qname=None, qattributes=None, check_grammar=True, **args):
|
|
||||||
if qname is not None:
|
|
||||||
self.qname = qname
|
|
||||||
assert(hasattr(self, 'qname'))
|
|
||||||
self.ownerDocument = None
|
|
||||||
self.childNodes=[]
|
|
||||||
self.allowed_children = grammar.allowed_children.get(self.qname)
|
|
||||||
prefix = self.get_nsprefix(self.qname[0])
|
|
||||||
self.tagName = prefix + ":" + self.qname[1]
|
|
||||||
if text is not None:
|
|
||||||
self.addText(text)
|
|
||||||
if cdata is not None:
|
|
||||||
self.addCDATA(cdata)
|
|
||||||
|
|
||||||
allowed_attrs = self.allowed_attributes()
|
|
||||||
if allowed_attrs is not None:
|
|
||||||
allowed_args = [ a[1].lower().replace('-','') for a in allowed_attrs]
|
|
||||||
self.attributes={}
|
|
||||||
# Load the attributes from the 'attributes' argument
|
|
||||||
if attributes:
|
|
||||||
for attr, value in attributes.items():
|
|
||||||
self.setAttribute(attr, value)
|
|
||||||
# Load the qualified attributes
|
|
||||||
if qattributes:
|
|
||||||
for attr, value in qattributes.items():
|
|
||||||
self.setAttrNS(attr[0], attr[1], value)
|
|
||||||
if allowed_attrs is not None:
|
|
||||||
# Load the attributes from the 'args' argument
|
|
||||||
for arg in args.keys():
|
|
||||||
self.setAttribute(arg, args[arg])
|
|
||||||
else:
|
|
||||||
for arg in args.keys(): # If any attribute is allowed
|
|
||||||
self.attributes[arg]=args[arg]
|
|
||||||
if not check_grammar:
|
|
||||||
return
|
|
||||||
# Test that all mandatory attributes have been added.
|
|
||||||
required = grammar.required_attributes.get(self.qname)
|
|
||||||
if required:
|
|
||||||
for r in required:
|
|
||||||
if self.getAttrNS(r[0],r[1]) is None:
|
|
||||||
raise AttributeError( "Required attribute missing: %s in <%s>" % (r[1].lower().replace('-',''), self.tagName))
|
|
||||||
|
|
||||||
def get_knownns(self, prefix):
|
|
||||||
""" Odfpy maintains a list of known namespaces. In some cases a prefix is used, and
|
|
||||||
we need to know which namespace it resolves to.
|
|
||||||
"""
|
|
||||||
global nsdict
|
|
||||||
for ns,p in nsdict.items():
|
|
||||||
if p == prefix: return ns
|
|
||||||
return None
|
|
||||||
|
|
||||||
def get_nsprefix(self, namespace):
|
|
||||||
""" Odfpy maintains a list of known namespaces. In some cases we have a namespace URL,
|
|
||||||
and needs to look up or assign the prefix for it.
|
|
||||||
"""
|
|
||||||
if namespace is None: namespace = ""
|
|
||||||
prefix = _nsassign(namespace)
|
|
||||||
if not namespace in self.namespaces:
|
|
||||||
self.namespaces[namespace] = prefix
|
|
||||||
return prefix
|
|
||||||
|
|
||||||
def allowed_attributes(self):
|
|
||||||
return grammar.allowed_attributes.get(self.qname)
|
|
||||||
|
|
||||||
def _setOwnerDoc(self, element):
|
|
||||||
element.ownerDocument = self.ownerDocument
|
|
||||||
for child in element.childNodes:
|
|
||||||
self._setOwnerDoc(child)
|
|
||||||
|
|
||||||
def addElement(self, element, check_grammar=True):
|
|
||||||
""" adds an element to an Element
|
|
||||||
|
|
||||||
Element.addElement(Element)
|
|
||||||
"""
|
|
||||||
if check_grammar and self.allowed_children is not None:
|
|
||||||
if element.qname not in self.allowed_children:
|
|
||||||
raise IllegalChild( "<%s> is not allowed in <%s>" % ( element.tagName, self.tagName))
|
|
||||||
self.appendChild(element)
|
|
||||||
self._setOwnerDoc(element)
|
|
||||||
if self.ownerDocument:
|
|
||||||
self.ownerDocument.rebuild_caches(element)
|
|
||||||
|
|
||||||
def addText(self, text, check_grammar=True):
|
|
||||||
""" Adds text to an element
|
|
||||||
Setting check_grammar=False turns off grammar checking
|
|
||||||
"""
|
|
||||||
if check_grammar and self.qname not in grammar.allows_text:
|
|
||||||
raise IllegalText( "The <%s> element does not allow text" % self.tagName)
|
|
||||||
else:
|
|
||||||
if text != '':
|
|
||||||
self.appendChild(Text(text))
|
|
||||||
|
|
||||||
def addCDATA(self, cdata, check_grammar=True):
|
|
||||||
""" Adds CDATA to an element
|
|
||||||
Setting check_grammar=False turns off grammar checking
|
|
||||||
"""
|
|
||||||
if check_grammar and self.qname not in grammar.allows_text:
|
|
||||||
raise IllegalText( "The <%s> element does not allow text" % self.tagName)
|
|
||||||
else:
|
|
||||||
self.appendChild(CDATASection(cdata))
|
|
||||||
|
|
||||||
def removeAttribute(self, attr, check_grammar=True):
|
|
||||||
""" Removes an attribute by name. """
|
|
||||||
allowed_attrs = self.allowed_attributes()
|
|
||||||
if allowed_attrs is None:
|
|
||||||
if type(attr) == type(()):
|
|
||||||
prefix, localname = attr
|
|
||||||
self.removeAttrNS(prefix, localname)
|
|
||||||
else:
|
|
||||||
raise AttributeError( "Unable to add simple attribute - use (namespace, localpart)")
|
|
||||||
else:
|
|
||||||
# Construct a list of allowed arguments
|
|
||||||
allowed_args = [ a[1].lower().replace('-','') for a in allowed_attrs]
|
|
||||||
if check_grammar and attr not in allowed_args:
|
|
||||||
raise AttributeError( "Attribute %s is not allowed in <%s>" % ( attr, self.tagName))
|
|
||||||
i = allowed_args.index(attr)
|
|
||||||
self.removeAttrNS(allowed_attrs[i][0], allowed_attrs[i][1])
|
|
||||||
|
|
||||||
def setAttribute(self, attr, value, check_grammar=True):
|
|
||||||
""" Add an attribute to the element
|
|
||||||
This is sort of a convenience method. All attributes in ODF have
|
|
||||||
namespaces. The library knows what attributes are legal and then allows
|
|
||||||
the user to provide the attribute as a keyword argument and the
|
|
||||||
library will add the correct namespace.
|
|
||||||
Must overwrite, If attribute already exists.
|
|
||||||
"""
|
|
||||||
allowed_attrs = self.allowed_attributes()
|
|
||||||
if allowed_attrs is None:
|
|
||||||
if type(attr) == type(()):
|
|
||||||
prefix, localname = attr
|
|
||||||
self.setAttrNS(prefix, localname, value)
|
|
||||||
else:
|
|
||||||
raise AttributeError( "Unable to add simple attribute - use (namespace, localpart)")
|
|
||||||
else:
|
|
||||||
# Construct a list of allowed arguments
|
|
||||||
allowed_args = [ a[1].lower().replace('-','') for a in allowed_attrs]
|
|
||||||
if check_grammar and attr not in allowed_args:
|
|
||||||
raise AttributeError( "Attribute %s is not allowed in <%s>" % ( attr, self.tagName))
|
|
||||||
i = allowed_args.index(attr)
|
|
||||||
self.setAttrNS(allowed_attrs[i][0], allowed_attrs[i][1], value)
|
|
||||||
|
|
||||||
def setAttrNS(self, namespace, localpart, value):
|
|
||||||
""" Add an attribute to the element
|
|
||||||
In case you need to add an attribute the library doesn't know about
|
|
||||||
then you must provide the full qualified name
|
|
||||||
It will not check that the attribute is legal according to the schema.
|
|
||||||
Must overwrite, If attribute already exists.
|
|
||||||
"""
|
|
||||||
allowed_attrs = self.allowed_attributes()
|
|
||||||
prefix = self.get_nsprefix(namespace)
|
|
||||||
# if allowed_attrs and (namespace, localpart) not in allowed_attrs:
|
|
||||||
# raise AttributeError( "Attribute %s:%s is not allowed in element <%s>" % ( prefix, localpart, self.tagName))
|
|
||||||
c = AttrConverters()
|
|
||||||
self.attributes[(namespace, localpart)] = c.convert((namespace, localpart), value, self)
|
|
||||||
|
|
||||||
def getAttrNS(self, namespace, localpart):
|
|
||||||
"""
|
|
||||||
gets an attribute, given a namespace and a key
|
|
||||||
@param namespace a unicode string or a bytes: the namespace
|
|
||||||
@param localpart a unicode string or a bytes:
|
|
||||||
the key to get the attribute
|
|
||||||
@return an attribute as a unicode string or a bytes: if both paramters
|
|
||||||
are byte strings, it will be a bytes; if both attributes are
|
|
||||||
unicode strings, it will be a unicode string
|
|
||||||
"""
|
|
||||||
prefix = self.get_nsprefix(namespace)
|
|
||||||
result = self.attributes.get((namespace, localpart))
|
|
||||||
|
|
||||||
assert(
|
|
||||||
(type(namespace), type(namespace), type(namespace) == \
|
|
||||||
type(b""), type(b""), type(b"")) or
|
|
||||||
(type(namespace), type(namespace), type(namespace) == \
|
|
||||||
type(u""), type(u""), type(u""))
|
|
||||||
)
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
def removeAttrNS(self, namespace, localpart):
|
|
||||||
del self.attributes[(namespace, localpart)]
|
|
||||||
|
|
||||||
def getAttribute(self, attr):
|
|
||||||
""" Get an attribute value. The method knows which namespace the attribute is in
|
|
||||||
"""
|
|
||||||
allowed_attrs = self.allowed_attributes()
|
|
||||||
if allowed_attrs is None:
|
|
||||||
if type(attr) == type(()):
|
|
||||||
prefix, localname = attr
|
|
||||||
return self.getAttrNS(prefix, localname)
|
|
||||||
else:
|
|
||||||
raise AttributeError( "Unable to get simple attribute - use (namespace, localpart)")
|
|
||||||
else:
|
|
||||||
# Construct a list of allowed arguments
|
|
||||||
allowed_args = [ a[1].lower().replace('-','') for a in allowed_attrs]
|
|
||||||
i = allowed_args.index(attr)
|
|
||||||
return self.getAttrNS(allowed_attrs[i][0], allowed_attrs[i][1])
|
|
||||||
|
|
||||||
def write_open_tag(self, level, f):
|
|
||||||
f.write(('<'+self.tagName))
|
|
||||||
if level == 0:
|
|
||||||
for namespace, prefix in self.namespaces.items():
|
|
||||||
f.write(u' xmlns:' + prefix + u'="'+ _escape(str(namespace))+'"')
|
|
||||||
for qname in self.attributes.keys():
|
|
||||||
prefix = self.get_nsprefix(qname[0])
|
|
||||||
f.write(u' '+_escape(str(prefix+u':'+qname[1]))+u'='+_quoteattr(unicode(self.attributes[qname])))
|
|
||||||
f.write(u'>')
|
|
||||||
|
|
||||||
def write_close_tag(self, level, f):
|
|
||||||
f.write('</'+self.tagName+'>')
|
|
||||||
|
|
||||||
def toXml(self, level, f):
|
|
||||||
"""
|
|
||||||
Generate an XML stream out of the tree structure
|
|
||||||
@param level integer: level in the XML tree; zero at root of the tree
|
|
||||||
@param f an open writable file able to accept unicode strings
|
|
||||||
"""
|
|
||||||
f.write(u'<'+self.tagName)
|
|
||||||
if level == 0:
|
|
||||||
for namespace, prefix in self.namespaces.items():
|
|
||||||
f.write(u' xmlns:' + prefix + u'="'+ _escape(str(namespace))+u'"')
|
|
||||||
for qname in self.attributes.keys():
|
|
||||||
prefix = self.get_nsprefix(qname[0])
|
|
||||||
f.write(u' '+_escape(unicode(prefix+':'+qname[1]))+u'='+_quoteattr(unicode(self.attributes[qname])))
|
|
||||||
if self.childNodes:
|
|
||||||
f.write(u'>')
|
|
||||||
for element in self.childNodes:
|
|
||||||
element.toXml(level+1,f)
|
|
||||||
f.write(u'</'+self.tagName+'>')
|
|
||||||
else:
|
|
||||||
f.write(u'/>')
|
|
||||||
|
|
||||||
def _getElementsByObj(self, obj, accumulator):
|
|
||||||
if self.qname == obj.qname:
|
|
||||||
accumulator.append(self)
|
|
||||||
for e in self.childNodes:
|
|
||||||
if e.nodeType == Node.ELEMENT_NODE:
|
|
||||||
accumulator = e._getElementsByObj(obj, accumulator)
|
|
||||||
return accumulator
|
|
||||||
|
|
||||||
def getElementsByType(self, element):
|
|
||||||
""" Gets elements based on the type, which is function from text.py, draw.py etc. """
|
|
||||||
obj = element(check_grammar=False)
|
|
||||||
return self._getElementsByObj(obj,[])
|
|
||||||
|
|
||||||
def isInstanceOf(self, element):
|
|
||||||
""" This is a check to see if the object is an instance of a type """
|
|
||||||
obj = element(check_grammar=False)
|
|
||||||
return self.qname == obj.qname
|
|
||||||
|
|
||||||
|
|
|
@ -1,325 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2008 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import *
|
|
||||||
|
|
||||||
# Inline element don't cause a box
|
|
||||||
# They are analogous to the HTML elements SPAN, B, I etc.
|
|
||||||
inline_elements = (
|
|
||||||
(TEXTNS,u'a'),
|
|
||||||
(TEXTNS,u'author-initials'),
|
|
||||||
(TEXTNS,u'author-name'),
|
|
||||||
(TEXTNS,u'bibliography-mark'),
|
|
||||||
(TEXTNS,u'bookmark-ref'),
|
|
||||||
(TEXTNS,u'chapter'),
|
|
||||||
(TEXTNS,u'character-count'),
|
|
||||||
(TEXTNS,u'conditional-text'),
|
|
||||||
(TEXTNS,u'creation-date'),
|
|
||||||
(TEXTNS,u'creation-time'),
|
|
||||||
(TEXTNS,u'creator'),
|
|
||||||
(TEXTNS,u'database-display'),
|
|
||||||
(TEXTNS,u'database-name'),
|
|
||||||
(TEXTNS,u'database-next'),
|
|
||||||
(TEXTNS,u'database-row-number'),
|
|
||||||
(TEXTNS,u'database-row-select'),
|
|
||||||
(TEXTNS,u'date'),
|
|
||||||
(TEXTNS,u'dde-connection'),
|
|
||||||
(TEXTNS,u'description'),
|
|
||||||
(TEXTNS,u'editing-cycles'),
|
|
||||||
(TEXTNS,u'editing-duration'),
|
|
||||||
(TEXTNS,u'execute-macro'),
|
|
||||||
(TEXTNS,u'expression'),
|
|
||||||
(TEXTNS,u'file-name'),
|
|
||||||
(TEXTNS,u'hidden-paragraph'),
|
|
||||||
(TEXTNS,u'hidden-text'),
|
|
||||||
(TEXTNS,u'image-count'),
|
|
||||||
(TEXTNS,u'initial-creator'),
|
|
||||||
(TEXTNS,u'keywords'),
|
|
||||||
(TEXTNS,u'measure'),
|
|
||||||
(TEXTNS,u'modification-date'),
|
|
||||||
(TEXTNS,u'modification-time'),
|
|
||||||
(TEXTNS,u'note-ref'),
|
|
||||||
(TEXTNS,u'object-count'),
|
|
||||||
(TEXTNS,u'page-continuation'),
|
|
||||||
(TEXTNS,u'page-count'),
|
|
||||||
(TEXTNS,u'page-number'),
|
|
||||||
(TEXTNS,u'page-variable-get'),
|
|
||||||
(TEXTNS,u'page-variable-set'),
|
|
||||||
(TEXTNS,u'paragraph-count'),
|
|
||||||
(TEXTNS,u'placeholder'),
|
|
||||||
(TEXTNS,u'print-date'),
|
|
||||||
(TEXTNS,u'printed-by'),
|
|
||||||
(TEXTNS,u'print-time'),
|
|
||||||
(TEXTNS,u'reference-ref'),
|
|
||||||
(TEXTNS,u'ruby'),
|
|
||||||
(TEXTNS,u'ruby-base'),
|
|
||||||
(TEXTNS,u'ruby-text'),
|
|
||||||
(TEXTNS,u'script'),
|
|
||||||
(TEXTNS,u'sender-city'),
|
|
||||||
(TEXTNS,u'sender-company'),
|
|
||||||
(TEXTNS,u'sender-country'),
|
|
||||||
(TEXTNS,u'sender-email'),
|
|
||||||
(TEXTNS,u'sender-fax'),
|
|
||||||
(TEXTNS,u'sender-firstname'),
|
|
||||||
(TEXTNS,u'sender-initials'),
|
|
||||||
(TEXTNS,u'sender-lastname'),
|
|
||||||
(TEXTNS,u'sender-phone-private'),
|
|
||||||
(TEXTNS,u'sender-phone-work'),
|
|
||||||
(TEXTNS,u'sender-position'),
|
|
||||||
(TEXTNS,u'sender-postal-code'),
|
|
||||||
(TEXTNS,u'sender-state-or-province'),
|
|
||||||
(TEXTNS,u'sender-street'),
|
|
||||||
(TEXTNS,u'sender-title'),
|
|
||||||
(TEXTNS,u'sequence'),
|
|
||||||
(TEXTNS,u'sequence-ref'),
|
|
||||||
(TEXTNS,u'sheet-name'),
|
|
||||||
(TEXTNS,u'span'),
|
|
||||||
(TEXTNS,u'subject'),
|
|
||||||
(TEXTNS,u'table-count'),
|
|
||||||
(TEXTNS,u'table-formula'),
|
|
||||||
(TEXTNS,u'template-name'),
|
|
||||||
(TEXTNS,u'text-input'),
|
|
||||||
(TEXTNS,u'time'),
|
|
||||||
(TEXTNS,u'title'),
|
|
||||||
(TEXTNS,u'user-defined'),
|
|
||||||
(TEXTNS,u'user-field-get'),
|
|
||||||
(TEXTNS,u'user-field-input'),
|
|
||||||
(TEXTNS,u'variable-get'),
|
|
||||||
(TEXTNS,u'variable-input'),
|
|
||||||
(TEXTNS,u'variable-set'),
|
|
||||||
(TEXTNS,u'word-count'),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# It is almost impossible to determine what elements are block elements.
|
|
||||||
# There are so many that don't fit the form
|
|
||||||
block_elements = (
|
|
||||||
(TEXTNS,u'h'),
|
|
||||||
(TEXTNS,u'p'),
|
|
||||||
(TEXTNS,u'list'),
|
|
||||||
(TEXTNS,u'list-item'),
|
|
||||||
(TEXTNS,u'section'),
|
|
||||||
)
|
|
||||||
|
|
||||||
declarative_elements = (
|
|
||||||
(OFFICENS,u'font-face-decls'),
|
|
||||||
(PRESENTATIONNS,u'date-time-decl'),
|
|
||||||
(PRESENTATIONNS,u'footer-decl'),
|
|
||||||
(PRESENTATIONNS,u'header-decl'),
|
|
||||||
(TABLENS,u'table-template'),
|
|
||||||
(TEXTNS,u'alphabetical-index-entry-template'),
|
|
||||||
(TEXTNS,u'alphabetical-index-source'),
|
|
||||||
(TEXTNS,u'bibliography-entry-template'),
|
|
||||||
(TEXTNS,u'bibliography-source'),
|
|
||||||
(TEXTNS,u'dde-connection-decls'),
|
|
||||||
(TEXTNS,u'illustration-index-entry-template'),
|
|
||||||
(TEXTNS,u'illustration-index-source'),
|
|
||||||
(TEXTNS,u'index-source-styles'),
|
|
||||||
(TEXTNS,u'index-title-template'),
|
|
||||||
(TEXTNS,u'note-continuation-notice-backward'),
|
|
||||||
(TEXTNS,u'note-continuation-notice-forward'),
|
|
||||||
(TEXTNS,u'notes-configuration'),
|
|
||||||
(TEXTNS,u'object-index-entry-template'),
|
|
||||||
(TEXTNS,u'object-index-source'),
|
|
||||||
(TEXTNS,u'sequence-decls'),
|
|
||||||
(TEXTNS,u'table-index-entry-template'),
|
|
||||||
(TEXTNS,u'table-index-source'),
|
|
||||||
(TEXTNS,u'table-of-content-entry-template'),
|
|
||||||
(TEXTNS,u'table-of-content-source'),
|
|
||||||
(TEXTNS,u'user-field-decls'),
|
|
||||||
(TEXTNS,u'user-index-entry-template'),
|
|
||||||
(TEXTNS,u'user-index-source'),
|
|
||||||
(TEXTNS,u'variable-decls'),
|
|
||||||
)
|
|
||||||
|
|
||||||
empty_elements = (
|
|
||||||
(ANIMNS,u'animate'),
|
|
||||||
(ANIMNS,u'animateColor'),
|
|
||||||
(ANIMNS,u'animateMotion'),
|
|
||||||
(ANIMNS,u'animateTransform'),
|
|
||||||
(ANIMNS,u'audio'),
|
|
||||||
(ANIMNS,u'param'),
|
|
||||||
(ANIMNS,u'set'),
|
|
||||||
(ANIMNS,u'transitionFilter'),
|
|
||||||
(CHARTNS,u'categories'),
|
|
||||||
(CHARTNS,u'data-point'),
|
|
||||||
(CHARTNS,u'domain'),
|
|
||||||
(CHARTNS,u'error-indicator'),
|
|
||||||
(CHARTNS,u'floor'),
|
|
||||||
(CHARTNS,u'grid'),
|
|
||||||
(CHARTNS,u'legend'),
|
|
||||||
(CHARTNS,u'mean-value'),
|
|
||||||
(CHARTNS,u'regression-curve'),
|
|
||||||
(CHARTNS,u'stock-gain-marker'),
|
|
||||||
(CHARTNS,u'stock-loss-marker'),
|
|
||||||
(CHARTNS,u'stock-range-line'),
|
|
||||||
(CHARTNS,u'symbol-image'),
|
|
||||||
(CHARTNS,u'wall'),
|
|
||||||
(DR3DNS,u'cube'),
|
|
||||||
(DR3DNS,u'extrude'),
|
|
||||||
(DR3DNS,u'light'),
|
|
||||||
(DR3DNS,u'rotate'),
|
|
||||||
(DR3DNS,u'sphere'),
|
|
||||||
(DRAWNS,u'contour-path'),
|
|
||||||
(DRAWNS,u'contour-polygon'),
|
|
||||||
(DRAWNS,u'equation'),
|
|
||||||
(DRAWNS,u'fill-image'),
|
|
||||||
(DRAWNS,u'floating-frame'),
|
|
||||||
(DRAWNS,u'glue-point'),
|
|
||||||
(DRAWNS,u'gradient'),
|
|
||||||
(DRAWNS,u'handle'),
|
|
||||||
(DRAWNS,u'hatch'),
|
|
||||||
(DRAWNS,u'layer'),
|
|
||||||
(DRAWNS,u'marker'),
|
|
||||||
(DRAWNS,u'opacity'),
|
|
||||||
(DRAWNS,u'page-thumbnail'),
|
|
||||||
(DRAWNS,u'param'),
|
|
||||||
(DRAWNS,u'stroke-dash'),
|
|
||||||
(FORMNS,u'connection-resource'),
|
|
||||||
(FORMNS,u'list-value'),
|
|
||||||
(FORMNS,u'property'),
|
|
||||||
(MANIFESTNS,u'algorithm'),
|
|
||||||
(MANIFESTNS,u'key-derivation'),
|
|
||||||
(METANS,u'auto-reload'),
|
|
||||||
(METANS,u'document-statistic'),
|
|
||||||
(METANS,u'hyperlink-behaviour'),
|
|
||||||
(METANS,u'template'),
|
|
||||||
(NUMBERNS,u'am-pm'),
|
|
||||||
(NUMBERNS,u'boolean'),
|
|
||||||
(NUMBERNS,u'day'),
|
|
||||||
(NUMBERNS,u'day-of-week'),
|
|
||||||
(NUMBERNS,u'era'),
|
|
||||||
(NUMBERNS,u'fraction'),
|
|
||||||
(NUMBERNS,u'hours'),
|
|
||||||
(NUMBERNS,u'minutes'),
|
|
||||||
(NUMBERNS,u'month'),
|
|
||||||
(NUMBERNS,u'quarter'),
|
|
||||||
(NUMBERNS,u'scientific-number'),
|
|
||||||
(NUMBERNS,u'seconds'),
|
|
||||||
(NUMBERNS,u'text-content'),
|
|
||||||
(NUMBERNS,u'week-of-year'),
|
|
||||||
(NUMBERNS,u'year'),
|
|
||||||
(OFFICENS,u'dde-source'),
|
|
||||||
(PRESENTATIONNS,u'date-time'),
|
|
||||||
(PRESENTATIONNS,u'footer'),
|
|
||||||
(PRESENTATIONNS,u'header'),
|
|
||||||
(PRESENTATIONNS,u'placeholder'),
|
|
||||||
(PRESENTATIONNS,u'play'),
|
|
||||||
(PRESENTATIONNS,u'show'),
|
|
||||||
(PRESENTATIONNS,u'sound'),
|
|
||||||
(SCRIPTNS,u'event-listener'),
|
|
||||||
(STYLENS,u'column'),
|
|
||||||
(STYLENS,u'column-sep'),
|
|
||||||
(STYLENS,u'drop-cap'),
|
|
||||||
(STYLENS,u'footnote-sep'),
|
|
||||||
(STYLENS,u'list-level-properties'),
|
|
||||||
(STYLENS,u'map'),
|
|
||||||
(STYLENS,u'ruby-properties'),
|
|
||||||
(STYLENS,u'table-column-properties'),
|
|
||||||
(STYLENS,u'tab-stop'),
|
|
||||||
(STYLENS,u'text-properties'),
|
|
||||||
(SVGNS,u'definition-src'),
|
|
||||||
(SVGNS,u'font-face-format'),
|
|
||||||
(SVGNS,u'font-face-name'),
|
|
||||||
(SVGNS,u'stop'),
|
|
||||||
(TABLENS,u'body'),
|
|
||||||
(TABLENS,u'cell-address'),
|
|
||||||
(TABLENS,u'cell-range-source'),
|
|
||||||
(TABLENS,u'change-deletion'),
|
|
||||||
(TABLENS,u'consolidation'),
|
|
||||||
(TABLENS,u'database-source-query'),
|
|
||||||
(TABLENS,u'database-source-sql'),
|
|
||||||
(TABLENS,u'database-source-table'),
|
|
||||||
(TABLENS,u'data-pilot-display-info'),
|
|
||||||
(TABLENS,u'data-pilot-field-reference'),
|
|
||||||
(TABLENS,u'data-pilot-group-member'),
|
|
||||||
(TABLENS,u'data-pilot-layout-info'),
|
|
||||||
(TABLENS,u'data-pilot-member'),
|
|
||||||
(TABLENS,u'data-pilot-sort-info'),
|
|
||||||
(TABLENS,u'data-pilot-subtotal'),
|
|
||||||
(TABLENS,u'dependency'),
|
|
||||||
(TABLENS,u'error-macro'),
|
|
||||||
(TABLENS,u'even-columns'),
|
|
||||||
(TABLENS,u'even-rows'),
|
|
||||||
(TABLENS,u'filter-condition'),
|
|
||||||
(TABLENS,u'first-column'),
|
|
||||||
(TABLENS,u'first-row'),
|
|
||||||
(TABLENS,u'highlighted-range'),
|
|
||||||
(TABLENS,u'insertion-cut-off'),
|
|
||||||
(TABLENS,u'iteration'),
|
|
||||||
(TABLENS,u'label-range'),
|
|
||||||
(TABLENS,u'last-column'),
|
|
||||||
(TABLENS,u'last-row'),
|
|
||||||
(TABLENS,u'movement-cut-off'),
|
|
||||||
(TABLENS,u'named-expression'),
|
|
||||||
(TABLENS,u'named-range'),
|
|
||||||
(TABLENS,u'null-date'),
|
|
||||||
(TABLENS,u'odd-columns'),
|
|
||||||
(TABLENS,u'odd-rows'),
|
|
||||||
(TABLENS,u'operation'),
|
|
||||||
(TABLENS,u'scenario'),
|
|
||||||
(TABLENS,u'sort-by'),
|
|
||||||
(TABLENS,u'sort-groups'),
|
|
||||||
(TABLENS,u'source-range-address'),
|
|
||||||
(TABLENS,u'source-service'),
|
|
||||||
(TABLENS,u'subtotal-field'),
|
|
||||||
(TABLENS,u'table-column'),
|
|
||||||
(TABLENS,u'table-source'),
|
|
||||||
(TABLENS,u'target-range-address'),
|
|
||||||
(TEXTNS,u'alphabetical-index-auto-mark-file'),
|
|
||||||
(TEXTNS,u'alphabetical-index-mark'),
|
|
||||||
(TEXTNS,u'alphabetical-index-mark-end'),
|
|
||||||
(TEXTNS,u'alphabetical-index-mark-start'),
|
|
||||||
(TEXTNS,u'bookmark'),
|
|
||||||
(TEXTNS,u'bookmark-end'),
|
|
||||||
(TEXTNS,u'bookmark-start'),
|
|
||||||
(TEXTNS,u'change'),
|
|
||||||
(TEXTNS,u'change-end'),
|
|
||||||
(TEXTNS,u'change-start'),
|
|
||||||
(TEXTNS,u'dde-connection-decl'),
|
|
||||||
(TEXTNS,u'index-entry-bibliography'),
|
|
||||||
(TEXTNS,u'index-entry-chapter'),
|
|
||||||
(TEXTNS,u'index-entry-link-end'),
|
|
||||||
(TEXTNS,u'index-entry-link-start'),
|
|
||||||
(TEXTNS,u'index-entry-page-number'),
|
|
||||||
(TEXTNS,u'index-entry-tab-stop'),
|
|
||||||
(TEXTNS,u'index-entry-text'),
|
|
||||||
(TEXTNS,u'index-source-style'),
|
|
||||||
(TEXTNS,u'line-break'),
|
|
||||||
(TEXTNS,u'page'),
|
|
||||||
(TEXTNS,u'reference-mark'),
|
|
||||||
(TEXTNS,u'reference-mark-end'),
|
|
||||||
(TEXTNS,u'reference-mark-start'),
|
|
||||||
(TEXTNS,u's'),
|
|
||||||
(TEXTNS,u'section-source'),
|
|
||||||
(TEXTNS,u'sequence-decl'),
|
|
||||||
(TEXTNS,u'soft-page-break'),
|
|
||||||
(TEXTNS,u'sort-key'),
|
|
||||||
(TEXTNS,u'tab'),
|
|
||||||
(TEXTNS,u'toc-mark'),
|
|
||||||
(TEXTNS,u'toc-mark-end'),
|
|
||||||
(TEXTNS,u'toc-mark-start'),
|
|
||||||
(TEXTNS,u'user-field-decl'),
|
|
||||||
(TEXTNS,u'user-index-mark'),
|
|
||||||
(TEXTNS,u'user-index-mark-end'),
|
|
||||||
(TEXTNS,u'user-index-mark-start'),
|
|
||||||
(TEXTNS,u'variable-decl')
|
|
||||||
)
|
|
115
libs/odf/form.py
115
libs/odf/form.py
|
@ -1,115 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import FORMNS
|
|
||||||
from element import Element
|
|
||||||
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def Button(**args):
|
|
||||||
return Element(qname = (FORMNS,'button'), **args)
|
|
||||||
|
|
||||||
def Checkbox(**args):
|
|
||||||
return Element(qname = (FORMNS,'checkbox'), **args)
|
|
||||||
|
|
||||||
def Column(**args):
|
|
||||||
return Element(qname = (FORMNS,'column'), **args)
|
|
||||||
|
|
||||||
def Combobox(**args):
|
|
||||||
return Element(qname = (FORMNS,'combobox'), **args)
|
|
||||||
|
|
||||||
def ConnectionResource(**args):
|
|
||||||
return Element(qname = (FORMNS,'connection-resource'), **args)
|
|
||||||
|
|
||||||
def Date(**args):
|
|
||||||
return Element(qname = (FORMNS,'date'), **args)
|
|
||||||
|
|
||||||
def File(**args):
|
|
||||||
return Element(qname = (FORMNS,'file'), **args)
|
|
||||||
|
|
||||||
def FixedText(**args):
|
|
||||||
return Element(qname = (FORMNS,'fixed-text'), **args)
|
|
||||||
|
|
||||||
def Form(**args):
|
|
||||||
return Element(qname = (FORMNS,'form'), **args)
|
|
||||||
|
|
||||||
def FormattedText(**args):
|
|
||||||
return Element(qname = (FORMNS,'formatted-text'), **args)
|
|
||||||
|
|
||||||
def Frame(**args):
|
|
||||||
return Element(qname = (FORMNS,'frame'), **args)
|
|
||||||
|
|
||||||
def GenericControl(**args):
|
|
||||||
return Element(qname = (FORMNS,'generic-control'), **args)
|
|
||||||
|
|
||||||
def Grid(**args):
|
|
||||||
return Element(qname = (FORMNS,'grid'), **args)
|
|
||||||
|
|
||||||
def Hidden(**args):
|
|
||||||
return Element(qname = (FORMNS,'hidden'), **args)
|
|
||||||
|
|
||||||
def Image(**args):
|
|
||||||
return Element(qname = (FORMNS,'image'), **args)
|
|
||||||
|
|
||||||
def ImageFrame(**args):
|
|
||||||
return Element(qname = (FORMNS,'image-frame'), **args)
|
|
||||||
|
|
||||||
def Item(**args):
|
|
||||||
return Element(qname = (FORMNS,'item'), **args)
|
|
||||||
|
|
||||||
def ListProperty(**args):
|
|
||||||
return Element(qname = (FORMNS,'list-property'), **args)
|
|
||||||
|
|
||||||
def ListValue(**args):
|
|
||||||
return Element(qname = (FORMNS,'list-value'), **args)
|
|
||||||
|
|
||||||
def Listbox(**args):
|
|
||||||
return Element(qname = (FORMNS,'listbox'), **args)
|
|
||||||
|
|
||||||
def Number(**args):
|
|
||||||
return Element(qname = (FORMNS,'number'), **args)
|
|
||||||
|
|
||||||
def Option(**args):
|
|
||||||
return Element(qname = (FORMNS,'option'), **args)
|
|
||||||
|
|
||||||
def Password(**args):
|
|
||||||
return Element(qname = (FORMNS,'password'), **args)
|
|
||||||
|
|
||||||
def Properties(**args):
|
|
||||||
return Element(qname = (FORMNS,'properties'), **args)
|
|
||||||
|
|
||||||
def Property(**args):
|
|
||||||
return Element(qname = (FORMNS,'property'), **args)
|
|
||||||
|
|
||||||
def Radio(**args):
|
|
||||||
return Element(qname = (FORMNS,'radio'), **args)
|
|
||||||
|
|
||||||
def Text(**args):
|
|
||||||
return Element(qname = (FORMNS,'text'), **args)
|
|
||||||
|
|
||||||
def Textarea(**args):
|
|
||||||
return Element(qname = (FORMNS,'textarea'), **args)
|
|
||||||
|
|
||||||
def Time(**args):
|
|
||||||
return Element(qname = (FORMNS,'time'), **args)
|
|
||||||
|
|
||||||
def ValueRange(**args):
|
|
||||||
return Element(qname = (FORMNS,'value-range'), **args)
|
|
||||||
|
|
9194
libs/odf/grammar.py
9194
libs/odf/grammar.py
File diff suppressed because it is too large
Load diff
115
libs/odf/load.py
115
libs/odf/load.py
|
@ -1,115 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2007-2008 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
# This script is to be embedded in opendocument.py later
|
|
||||||
# The purpose is to read an ODT/ODP/ODS file and create the datastructure
|
|
||||||
# in memory. The user should then be able to make operations and then save
|
|
||||||
# the structure again.
|
|
||||||
|
|
||||||
from xml.sax import make_parser,handler
|
|
||||||
from xml.sax.xmlreader import InputSource
|
|
||||||
import xml.sax.saxutils
|
|
||||||
from element import Element
|
|
||||||
from namespaces import OFFICENS
|
|
||||||
try:
|
|
||||||
from cStringIO import StringIO
|
|
||||||
except ImportError:
|
|
||||||
from io import StringIO
|
|
||||||
|
|
||||||
#
|
|
||||||
# Parse the XML files
|
|
||||||
#
|
|
||||||
class LoadParser(handler.ContentHandler):
|
|
||||||
""" Extract headings from content.xml of an ODT file """
|
|
||||||
triggers = (
|
|
||||||
(OFFICENS, 'automatic-styles'), (OFFICENS, 'body'),
|
|
||||||
(OFFICENS, 'font-face-decls'), (OFFICENS, 'master-styles'),
|
|
||||||
(OFFICENS, 'meta'), (OFFICENS, 'scripts'),
|
|
||||||
(OFFICENS, 'settings'), (OFFICENS, 'styles') )
|
|
||||||
|
|
||||||
def __init__(self, document):
|
|
||||||
self.doc = document
|
|
||||||
self.data = []
|
|
||||||
self.level = 0
|
|
||||||
self.parse = False
|
|
||||||
|
|
||||||
def characters(self, data):
|
|
||||||
if self.parse == False:
|
|
||||||
return
|
|
||||||
self.data.append(data)
|
|
||||||
|
|
||||||
def startElementNS(self, tag, qname, attrs):
|
|
||||||
if tag in self.triggers:
|
|
||||||
self.parse = True
|
|
||||||
if self.doc._parsing != "styles.xml" and tag == (OFFICENS, 'font-face-decls'):
|
|
||||||
self.parse = False
|
|
||||||
if self.parse == False:
|
|
||||||
return
|
|
||||||
|
|
||||||
self.level = self.level + 1
|
|
||||||
# Add any accumulated text content
|
|
||||||
content = ''.join(self.data)
|
|
||||||
if len(content.strip()) > 0:
|
|
||||||
self.parent.addText(content, check_grammar=False)
|
|
||||||
self.data = []
|
|
||||||
# Create the element
|
|
||||||
attrdict = {}
|
|
||||||
for (att,value) in attrs.items():
|
|
||||||
attrdict[att] = value
|
|
||||||
try:
|
|
||||||
e = Element(qname = tag, qattributes=attrdict, check_grammar=False)
|
|
||||||
self.curr = e
|
|
||||||
except AttributeError as v:
|
|
||||||
print ("Error: %s" % v)
|
|
||||||
|
|
||||||
if tag == (OFFICENS, 'automatic-styles'):
|
|
||||||
e = self.doc.automaticstyles
|
|
||||||
elif tag == (OFFICENS, 'body'):
|
|
||||||
e = self.doc.body
|
|
||||||
elif tag == (OFFICENS, 'master-styles'):
|
|
||||||
e = self.doc.masterstyles
|
|
||||||
elif tag == (OFFICENS, 'meta'):
|
|
||||||
e = self.doc.meta
|
|
||||||
elif tag == (OFFICENS,'scripts'):
|
|
||||||
e = self.doc.scripts
|
|
||||||
elif tag == (OFFICENS,'settings'):
|
|
||||||
e = self.doc.settings
|
|
||||||
elif tag == (OFFICENS,'styles'):
|
|
||||||
e = self.doc.styles
|
|
||||||
elif self.doc._parsing == "styles.xml" and tag == (OFFICENS, 'font-face-decls'):
|
|
||||||
e = self.doc.fontfacedecls
|
|
||||||
elif hasattr(self,'parent'):
|
|
||||||
self.parent.addElement(e, check_grammar=False)
|
|
||||||
self.parent = e
|
|
||||||
|
|
||||||
|
|
||||||
def endElementNS(self, tag, qname):
|
|
||||||
if self.parse == False:
|
|
||||||
return
|
|
||||||
self.level = self.level - 1
|
|
||||||
str = ''.join(self.data)
|
|
||||||
if len(str.strip()) > 0:
|
|
||||||
self.curr.addText(str, check_grammar=False)
|
|
||||||
self.data = []
|
|
||||||
self.curr = self.curr.parentNode
|
|
||||||
self.parent = self.curr
|
|
||||||
if tag in self.triggers:
|
|
||||||
self.parse = False
|
|
|
@ -1,44 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
#
|
|
||||||
|
|
||||||
import sys, os.path
|
|
||||||
sys.path.append(os.path.dirname(__file__))
|
|
||||||
|
|
||||||
from namespaces import MANIFESTNS
|
|
||||||
from element import Element
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def Manifest(**args):
|
|
||||||
return Element(qname = (MANIFESTNS,'manifest'), **args)
|
|
||||||
|
|
||||||
def FileEntry(**args):
|
|
||||||
return Element(qname = (MANIFESTNS,'file-entry'), **args)
|
|
||||||
|
|
||||||
def EncryptionData(**args):
|
|
||||||
return Element(qname = (MANIFESTNS,'encryption-data'), **args)
|
|
||||||
|
|
||||||
def Algorithm(**args):
|
|
||||||
return Element(qname = (MANIFESTNS,'algorithm'), **args)
|
|
||||||
|
|
||||||
def KeyDerivation(**args):
|
|
||||||
return Element(qname = (MANIFESTNS,'key-derivation'), **args)
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import MATHNS
|
|
||||||
from element import Element
|
|
||||||
|
|
||||||
# ODF 1.0 section 12.5
|
|
||||||
# Mathematical content is represented by MathML 2.0
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def Math(**args):
|
|
||||||
return Element(qname = (MATHNS,'math'), **args)
|
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import METANS
|
|
||||||
from element import Element
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def AutoReload(**args):
|
|
||||||
return Element(qname = (METANS,'auto-reload'), **args)
|
|
||||||
|
|
||||||
def CreationDate(**args):
|
|
||||||
return Element(qname = (METANS,'creation-date'), **args)
|
|
||||||
|
|
||||||
def DateString(**args):
|
|
||||||
return Element(qname = (METANS,'date-string'), **args)
|
|
||||||
|
|
||||||
def DocumentStatistic(**args):
|
|
||||||
return Element(qname = (METANS,'document-statistic'), **args)
|
|
||||||
|
|
||||||
def EditingCycles(**args):
|
|
||||||
return Element(qname = (METANS,'editing-cycles'), **args)
|
|
||||||
|
|
||||||
def EditingDuration(**args):
|
|
||||||
return Element(qname = (METANS,'editing-duration'), **args)
|
|
||||||
|
|
||||||
def Generator(**args):
|
|
||||||
return Element(qname = (METANS,'generator'), **args)
|
|
||||||
|
|
||||||
def HyperlinkBehaviour(**args):
|
|
||||||
return Element(qname = (METANS,'hyperlink-behaviour'), **args)
|
|
||||||
|
|
||||||
def InitialCreator(**args):
|
|
||||||
return Element(qname = (METANS,'initial-creator'), **args)
|
|
||||||
|
|
||||||
def Keyword(**args):
|
|
||||||
return Element(qname = (METANS,'keyword'), **args)
|
|
||||||
|
|
||||||
def PrintDate(**args):
|
|
||||||
return Element(qname = (METANS,'print-date'), **args)
|
|
||||||
|
|
||||||
def PrintedBy(**args):
|
|
||||||
return Element(qname = (METANS,'printed-by'), **args)
|
|
||||||
|
|
||||||
def Template(**args):
|
|
||||||
args.setdefault('type', 'simple')
|
|
||||||
return Element(qname = (METANS,'template'), **args)
|
|
||||||
|
|
||||||
def UserDefined(**args):
|
|
||||||
return Element(qname = (METANS,'user-defined'), **args)
|
|
||||||
|
|
|
@ -1,107 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2013 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
TOOLSVERSION = u"ODFPY/1.3.1dev"
|
|
||||||
|
|
||||||
ANIMNS = u"urn:oasis:names:tc:opendocument:xmlns:animation:1.0"
|
|
||||||
CHARTNS = u"urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
|
|
||||||
CHARTOOONS = u"http://openoffice.org/2010/chart"
|
|
||||||
CONFIGNS = u"urn:oasis:names:tc:opendocument:xmlns:config:1.0"
|
|
||||||
CSS3TNS = u"http://www.w3.org/TR/css3-text/"
|
|
||||||
#DBNS = u"http://openoffice.org/2004/database"
|
|
||||||
DBNS = u"urn:oasis:names:tc:opendocument:xmlns:database:1.0"
|
|
||||||
DCNS = u"http://purl.org/dc/elements/1.1/"
|
|
||||||
DOMNS = u"http://www.w3.org/2001/xml-events"
|
|
||||||
DR3DNS = u"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
|
|
||||||
DRAWNS = u"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
|
|
||||||
FIELDNS = u"urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0"
|
|
||||||
FONS = u"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
|
|
||||||
FORMNS = u"urn:oasis:names:tc:opendocument:xmlns:form:1.0"
|
|
||||||
FORMXNS = u"urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0"
|
|
||||||
GRDDLNS = u"http://www.w3.org/2003/g/data-view#"
|
|
||||||
KOFFICENS = u"http://www.koffice.org/2005/"
|
|
||||||
MANIFESTNS = u"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"
|
|
||||||
MATHNS = u"http://www.w3.org/1998/Math/MathML"
|
|
||||||
METANS = u"urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
|
|
||||||
NUMBERNS = u"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
|
|
||||||
OFFICENS = u"urn:oasis:names:tc:opendocument:xmlns:office:1.0"
|
|
||||||
OFNS = u"urn:oasis:names:tc:opendocument:xmlns:of:1.2"
|
|
||||||
OOOCNS = u"http://openoffice.org/2004/calc"
|
|
||||||
OOONS = u"http://openoffice.org/2004/office"
|
|
||||||
OOOWNS = u"http://openoffice.org/2004/writer"
|
|
||||||
PRESENTATIONNS = u"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
|
|
||||||
RDFANS = u"http://docs.oasis-open.org/opendocument/meta/rdfa#"
|
|
||||||
RPTNS = u"http://openoffice.org/2005/report"
|
|
||||||
SCRIPTNS = u"urn:oasis:names:tc:opendocument:xmlns:script:1.0"
|
|
||||||
SMILNS = u"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0"
|
|
||||||
STYLENS = u"urn:oasis:names:tc:opendocument:xmlns:style:1.0"
|
|
||||||
SVGNS = u"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
|
|
||||||
TABLENS = u"urn:oasis:names:tc:opendocument:xmlns:table:1.0"
|
|
||||||
TABLEOOONS = u"http://openoffice.org/2009/table"
|
|
||||||
TEXTNS = u"urn:oasis:names:tc:opendocument:xmlns:text:1.0"
|
|
||||||
XFORMSNS = u"http://www.w3.org/2002/xforms"
|
|
||||||
XHTMLNS = u"http://www.w3.org/1999/xhtml"
|
|
||||||
XLINKNS = u"http://www.w3.org/1999/xlink"
|
|
||||||
XMLNS = u"http://www.w3.org/XML/1998/namespace"
|
|
||||||
XSDNS = u"http://www.w3.org/2001/XMLSchema"
|
|
||||||
XSINS = u"http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
|
|
||||||
nsdict = {
|
|
||||||
ANIMNS: u'anim',
|
|
||||||
CHARTNS: u'chart',
|
|
||||||
CHARTOOONS: u'chartooo',
|
|
||||||
CONFIGNS: u'config',
|
|
||||||
CSS3TNS: u'css3t',
|
|
||||||
DBNS: u'db',
|
|
||||||
DCNS: u'dc',
|
|
||||||
DOMNS: u'dom',
|
|
||||||
DR3DNS: u'dr3d',
|
|
||||||
DRAWNS: u'draw',
|
|
||||||
FIELDNS: u'field',
|
|
||||||
FONS: u'fo',
|
|
||||||
FORMNS: u'form',
|
|
||||||
FORMXNS: u'formx',
|
|
||||||
GRDDLNS: u'grddl',
|
|
||||||
KOFFICENS: u'koffice',
|
|
||||||
MANIFESTNS: u'manifest',
|
|
||||||
MATHNS: u'math',
|
|
||||||
METANS: u'meta',
|
|
||||||
NUMBERNS: u'number',
|
|
||||||
OFFICENS: u'office',
|
|
||||||
OFNS: u'of',
|
|
||||||
OOONS: u'ooo',
|
|
||||||
OOOWNS: u'ooow',
|
|
||||||
OOOCNS: u'oooc',
|
|
||||||
PRESENTATIONNS: u'presentation',
|
|
||||||
RDFANS: u'rdfa',
|
|
||||||
RPTNS: u'rpt',
|
|
||||||
SCRIPTNS: u'script',
|
|
||||||
SMILNS: u'smil',
|
|
||||||
STYLENS: u'style',
|
|
||||||
SVGNS: u'svg',
|
|
||||||
TABLENS: u'table',
|
|
||||||
TABLEOOONS: u'tableooo',
|
|
||||||
TEXTNS: u'text',
|
|
||||||
XFORMSNS: u'xforms',
|
|
||||||
XLINKNS: u'xlink',
|
|
||||||
XHTMLNS: u'xhtml',
|
|
||||||
XMLNS: u'xml',
|
|
||||||
XSDNS: u'xsd',
|
|
||||||
XSINS: u'xsi',
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import NUMBERNS
|
|
||||||
from element import Element
|
|
||||||
from style import StyleElement
|
|
||||||
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def AmPm(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'am-pm'), **args)
|
|
||||||
|
|
||||||
def Boolean(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'boolean'), **args)
|
|
||||||
|
|
||||||
def BooleanStyle(**args):
|
|
||||||
return StyleElement(qname = (NUMBERNS,'boolean-style'), **args)
|
|
||||||
|
|
||||||
def CurrencyStyle(**args):
|
|
||||||
return StyleElement(qname = (NUMBERNS,'currency-style'), **args)
|
|
||||||
|
|
||||||
def CurrencySymbol(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'currency-symbol'), **args)
|
|
||||||
|
|
||||||
def DateStyle(**args):
|
|
||||||
return StyleElement(qname = (NUMBERNS,'date-style'), **args)
|
|
||||||
|
|
||||||
def Day(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'day'), **args)
|
|
||||||
|
|
||||||
def DayOfWeek(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'day-of-week'), **args)
|
|
||||||
|
|
||||||
def EmbeddedText(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'embedded-text'), **args)
|
|
||||||
|
|
||||||
def Era(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'era'), **args)
|
|
||||||
|
|
||||||
def Fraction(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'fraction'), **args)
|
|
||||||
|
|
||||||
def Hours(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'hours'), **args)
|
|
||||||
|
|
||||||
def Minutes(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'minutes'), **args)
|
|
||||||
|
|
||||||
def Month(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'month'), **args)
|
|
||||||
|
|
||||||
def Number(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'number'), **args)
|
|
||||||
|
|
||||||
def NumberStyle(**args):
|
|
||||||
return StyleElement(qname = (NUMBERNS,'number-style'), **args)
|
|
||||||
|
|
||||||
def PercentageStyle(**args):
|
|
||||||
return StyleElement(qname = (NUMBERNS,'percentage-style'), **args)
|
|
||||||
|
|
||||||
def Quarter(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'quarter'), **args)
|
|
||||||
|
|
||||||
def ScientificNumber(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'scientific-number'), **args)
|
|
||||||
|
|
||||||
def Seconds(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'seconds'), **args)
|
|
||||||
|
|
||||||
def Text(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'text'), **args)
|
|
||||||
|
|
||||||
def TextContent(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'text-content'), **args)
|
|
||||||
|
|
||||||
def TextStyle(**args):
|
|
||||||
return StyleElement(qname = (NUMBERNS,'text-style'), **args)
|
|
||||||
|
|
||||||
def TimeStyle(**args):
|
|
||||||
return StyleElement(qname = (NUMBERNS,'time-style'), **args)
|
|
||||||
|
|
||||||
def WeekOfYear(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'week-of-year'), **args)
|
|
||||||
|
|
||||||
def Year(**args):
|
|
||||||
return Element(qname = (NUMBERNS,'year'), **args)
|
|
||||||
|
|
|
@ -1,579 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2008 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# See http://trac.edgewall.org/wiki/WikiFormatting
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
import sys, zipfile, xml.dom.minidom
|
|
||||||
from namespaces import nsdict
|
|
||||||
from elementtypes import *
|
|
||||||
|
|
||||||
IGNORED_TAGS = [
|
|
||||||
'draw:a'
|
|
||||||
'draw:g',
|
|
||||||
'draw:line',
|
|
||||||
'draw:object-ole',
|
|
||||||
'office:annotation',
|
|
||||||
'presentation:notes',
|
|
||||||
'svg:desc',
|
|
||||||
] + [ nsdict[item[0]]+":"+item[1] for item in empty_elements]
|
|
||||||
|
|
||||||
INLINE_TAGS = [ nsdict[item[0]]+":"+item[1] for item in inline_elements]
|
|
||||||
|
|
||||||
|
|
||||||
class TextProps:
|
|
||||||
""" Holds properties for a text style. """
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
|
|
||||||
self.italic = False
|
|
||||||
self.bold = False
|
|
||||||
self.fixed = False
|
|
||||||
self.underlined = False
|
|
||||||
self.strikethrough = False
|
|
||||||
self.superscript = False
|
|
||||||
self.subscript = False
|
|
||||||
|
|
||||||
def setItalic(self, value):
|
|
||||||
if value == "italic":
|
|
||||||
self.italic = True
|
|
||||||
elif value == "normal":
|
|
||||||
self.italic = False
|
|
||||||
|
|
||||||
def setBold(self, value):
|
|
||||||
if value == "bold":
|
|
||||||
self.bold = True
|
|
||||||
elif value == "normal":
|
|
||||||
self.bold = False
|
|
||||||
|
|
||||||
def setFixed(self, value):
|
|
||||||
self.fixed = value
|
|
||||||
|
|
||||||
def setUnderlined(self, value):
|
|
||||||
if value and value != "none":
|
|
||||||
self.underlined = True
|
|
||||||
|
|
||||||
def setStrikethrough(self, value):
|
|
||||||
if value and value != "none":
|
|
||||||
self.strikethrough = True
|
|
||||||
|
|
||||||
def setPosition(self, value):
|
|
||||||
if value is None or value == '':
|
|
||||||
return
|
|
||||||
posisize = value.split(' ')
|
|
||||||
textpos = posisize[0]
|
|
||||||
if textpos.find('%') == -1:
|
|
||||||
if textpos == "sub":
|
|
||||||
self.superscript = False
|
|
||||||
self.subscript = True
|
|
||||||
elif textpos == "super":
|
|
||||||
self.superscript = True
|
|
||||||
self.subscript = False
|
|
||||||
else:
|
|
||||||
itextpos = int(textpos[:textpos.find('%')])
|
|
||||||
if itextpos > 10:
|
|
||||||
self.superscript = False
|
|
||||||
self.subscript = True
|
|
||||||
elif itextpos < -10:
|
|
||||||
self.superscript = True
|
|
||||||
self.subscript = False
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
|
|
||||||
return "[italic=%s, bold=i%s, fixed=%s]" % (str(self.italic),
|
|
||||||
str(self.bold),
|
|
||||||
str(self.fixed))
|
|
||||||
|
|
||||||
class ParagraphProps:
|
|
||||||
""" Holds properties of a paragraph style. """
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
|
|
||||||
self.blockquote = False
|
|
||||||
self.headingLevel = 0
|
|
||||||
self.code = False
|
|
||||||
self.title = False
|
|
||||||
self.indented = 0
|
|
||||||
|
|
||||||
def setIndented(self, value):
|
|
||||||
self.indented = value
|
|
||||||
|
|
||||||
def setHeading(self, level):
|
|
||||||
self.headingLevel = level
|
|
||||||
|
|
||||||
def setTitle(self, value):
|
|
||||||
self.title = value
|
|
||||||
|
|
||||||
def setCode(self, value):
|
|
||||||
self.code = value
|
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
|
|
||||||
return "[bq=%s, h=%d, code=%s]" % (str(self.blockquote),
|
|
||||||
self.headingLevel,
|
|
||||||
str(self.code))
|
|
||||||
|
|
||||||
|
|
||||||
class ListProperties:
|
|
||||||
""" Holds properties for a list style. """
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.ordered = False
|
|
||||||
|
|
||||||
def setOrdered(self, value):
|
|
||||||
self.ordered = value
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ODF2MoinMoin(object):
|
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, filepath):
|
|
||||||
self.footnotes = []
|
|
||||||
self.footnoteCounter = 0
|
|
||||||
self.textStyles = {"Standard": TextProps()}
|
|
||||||
self.paragraphStyles = {"Standard": ParagraphProps()}
|
|
||||||
self.listStyles = {}
|
|
||||||
self.fixedFonts = []
|
|
||||||
self.hasTitle = 0
|
|
||||||
self.lastsegment = None
|
|
||||||
|
|
||||||
# Tags
|
|
||||||
self.elements = {
|
|
||||||
'draw:page': self.textToString,
|
|
||||||
'draw:frame': self.textToString,
|
|
||||||
'draw:image': self.draw_image,
|
|
||||||
'draw:text-box': self.textToString,
|
|
||||||
'text:a': self.text_a,
|
|
||||||
'text:note': self.text_note,
|
|
||||||
}
|
|
||||||
for tag in IGNORED_TAGS:
|
|
||||||
self.elements[tag] = self.do_nothing
|
|
||||||
|
|
||||||
for tag in INLINE_TAGS:
|
|
||||||
self.elements[tag] = self.inline_markup
|
|
||||||
self.elements['text:line-break'] = self.text_line_break
|
|
||||||
self.elements['text:s'] = self.text_s
|
|
||||||
self.elements['text:tab'] = self.text_tab
|
|
||||||
|
|
||||||
self.load(filepath)
|
|
||||||
|
|
||||||
def processFontDeclarations(self, fontDecl):
|
|
||||||
""" Extracts necessary font information from a font-declaration
|
|
||||||
element.
|
|
||||||
"""
|
|
||||||
for fontFace in fontDecl.getElementsByTagName("style:font-face"):
|
|
||||||
if fontFace.getAttribute("style:font-pitch") == "fixed":
|
|
||||||
self.fixedFonts.append(fontFace.getAttribute("style:name"))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def extractTextProperties(self, style, parent=None):
|
|
||||||
""" Extracts text properties from a style element. """
|
|
||||||
|
|
||||||
textProps = TextProps()
|
|
||||||
|
|
||||||
if parent:
|
|
||||||
parentProp = self.textStyles.get(parent, None)
|
|
||||||
if parentProp:
|
|
||||||
textProp = parentProp
|
|
||||||
|
|
||||||
textPropEl = style.getElementsByTagName("style:text-properties")
|
|
||||||
if not textPropEl: return textProps
|
|
||||||
|
|
||||||
textPropEl = textPropEl[0]
|
|
||||||
|
|
||||||
textProps.setItalic(textPropEl.getAttribute("fo:font-style"))
|
|
||||||
textProps.setBold(textPropEl.getAttribute("fo:font-weight"))
|
|
||||||
textProps.setUnderlined(textPropEl.getAttribute("style:text-underline-style"))
|
|
||||||
textProps.setStrikethrough(textPropEl.getAttribute("style:text-line-through-style"))
|
|
||||||
textProps.setPosition(textPropEl.getAttribute("style:text-position"))
|
|
||||||
|
|
||||||
if textPropEl.getAttribute("style:font-name") in self.fixedFonts:
|
|
||||||
textProps.setFixed(True)
|
|
||||||
|
|
||||||
return textProps
|
|
||||||
|
|
||||||
def extractParagraphProperties(self, style, parent=None):
|
|
||||||
""" Extracts paragraph properties from a style element. """
|
|
||||||
|
|
||||||
paraProps = ParagraphProps()
|
|
||||||
|
|
||||||
name = style.getAttribute("style:name")
|
|
||||||
|
|
||||||
if name.startswith("Heading_20_"):
|
|
||||||
level = name[11:]
|
|
||||||
try:
|
|
||||||
level = int(level)
|
|
||||||
paraProps.setHeading(level)
|
|
||||||
except:
|
|
||||||
level = 0
|
|
||||||
|
|
||||||
if name == "Title":
|
|
||||||
paraProps.setTitle(True)
|
|
||||||
|
|
||||||
paraPropEl = style.getElementsByTagName("style:paragraph-properties")
|
|
||||||
if paraPropEl:
|
|
||||||
paraPropEl = paraPropEl[0]
|
|
||||||
leftMargin = paraPropEl.getAttribute("fo:margin-left")
|
|
||||||
if leftMargin:
|
|
||||||
try:
|
|
||||||
leftMargin = float(leftMargin[:-2])
|
|
||||||
if leftMargin > 0.01:
|
|
||||||
paraProps.setIndented(True)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
textProps = self.extractTextProperties(style)
|
|
||||||
if textProps.fixed:
|
|
||||||
paraProps.setCode(True)
|
|
||||||
|
|
||||||
return paraProps
|
|
||||||
|
|
||||||
|
|
||||||
def processStyles(self, styleElements):
|
|
||||||
""" Runs through "style" elements extracting necessary information.
|
|
||||||
"""
|
|
||||||
|
|
||||||
for style in styleElements:
|
|
||||||
|
|
||||||
name = style.getAttribute("style:name")
|
|
||||||
|
|
||||||
if name == "Standard": continue
|
|
||||||
|
|
||||||
family = style.getAttribute("style:family")
|
|
||||||
parent = style.getAttribute("style:parent-style-name")
|
|
||||||
|
|
||||||
if family == "text":
|
|
||||||
self.textStyles[name] = self.extractTextProperties(style, parent)
|
|
||||||
|
|
||||||
elif family == "paragraph":
|
|
||||||
self.paragraphStyles[name] = \
|
|
||||||
self.extractParagraphProperties(style, parent)
|
|
||||||
self.textStyles[name] = self.extractTextProperties(style, parent)
|
|
||||||
|
|
||||||
def processListStyles(self, listStyleElements):
|
|
||||||
|
|
||||||
for style in listStyleElements:
|
|
||||||
name = style.getAttribute("style:name")
|
|
||||||
|
|
||||||
prop = ListProperties()
|
|
||||||
if style.hasChildNodes():
|
|
||||||
subitems = [el for el in style.childNodes
|
|
||||||
if el.nodeType == xml.dom.Node.ELEMENT_NODE
|
|
||||||
and el.tagName == "text:list-level-style-number"]
|
|
||||||
if len(subitems) > 0:
|
|
||||||
prop.setOrdered(True)
|
|
||||||
|
|
||||||
self.listStyles[name] = prop
|
|
||||||
|
|
||||||
|
|
||||||
def load(self, filepath):
|
|
||||||
""" Loads an ODT file. """
|
|
||||||
|
|
||||||
zip = zipfile.ZipFile(filepath)
|
|
||||||
|
|
||||||
styles_doc = xml.dom.minidom.parseString(zip.read("styles.xml"))
|
|
||||||
fontfacedecls = styles_doc.getElementsByTagName("office:font-face-decls")
|
|
||||||
if fontfacedecls:
|
|
||||||
self.processFontDeclarations(fontfacedecls[0])
|
|
||||||
self.processStyles(styles_doc.getElementsByTagName("style:style"))
|
|
||||||
self.processListStyles(styles_doc.getElementsByTagName("text:list-style"))
|
|
||||||
|
|
||||||
self.content = xml.dom.minidom.parseString(zip.read("content.xml"))
|
|
||||||
fontfacedecls = self.content.getElementsByTagName("office:font-face-decls")
|
|
||||||
if fontfacedecls:
|
|
||||||
self.processFontDeclarations(fontfacedecls[0])
|
|
||||||
|
|
||||||
self.processStyles(self.content.getElementsByTagName("style:style"))
|
|
||||||
self.processListStyles(self.content.getElementsByTagName("text:list-style"))
|
|
||||||
|
|
||||||
def compressCodeBlocks(self, text):
|
|
||||||
""" Removes extra blank lines from code blocks. """
|
|
||||||
|
|
||||||
return text
|
|
||||||
lines = text.split("\n")
|
|
||||||
buffer = []
|
|
||||||
numLines = len(lines)
|
|
||||||
for i in range(numLines):
|
|
||||||
|
|
||||||
if (lines[i].strip() or i == numLines-1 or i == 0 or
|
|
||||||
not ( lines[i-1].startswith(" ")
|
|
||||||
and lines[i+1].startswith(" ") ) ):
|
|
||||||
buffer.append("\n" + lines[i])
|
|
||||||
|
|
||||||
return ''.join(buffer)
|
|
||||||
|
|
||||||
#-----------------------------------
|
|
||||||
def do_nothing(self, node):
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def draw_image(self, node):
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
|
|
||||||
link = node.getAttribute("xlink:href")
|
|
||||||
if link and link[:2] == './': # Indicates a sub-object, which isn't supported
|
|
||||||
return "%s\n" % link
|
|
||||||
if link and link[:9] == 'Pictures/':
|
|
||||||
link = link[9:]
|
|
||||||
return "[[Image(%s)]]\n" % link
|
|
||||||
|
|
||||||
def text_a(self, node):
|
|
||||||
text = self.textToString(node)
|
|
||||||
link = node.getAttribute("xlink:href")
|
|
||||||
if link.strip() == text.strip():
|
|
||||||
return "[%s] " % link.strip()
|
|
||||||
else:
|
|
||||||
return "[%s %s] " % (link.strip(), text.strip())
|
|
||||||
|
|
||||||
|
|
||||||
def text_line_break(self, node):
|
|
||||||
return "[[BR]]"
|
|
||||||
|
|
||||||
def text_note(self, node):
|
|
||||||
cite = (node.getElementsByTagName("text:note-citation")[0]
|
|
||||||
.childNodes[0].nodeValue)
|
|
||||||
body = (node.getElementsByTagName("text:note-body")[0]
|
|
||||||
.childNodes[0])
|
|
||||||
self.footnotes.append((cite, self.textToString(body)))
|
|
||||||
return "^%s^" % cite
|
|
||||||
|
|
||||||
def text_s(self, node):
|
|
||||||
try:
|
|
||||||
num = int(node.getAttribute("text:c"))
|
|
||||||
return " "*num
|
|
||||||
except:
|
|
||||||
return " "
|
|
||||||
|
|
||||||
def text_tab(self, node):
|
|
||||||
return " "
|
|
||||||
|
|
||||||
def inline_markup(self, node):
|
|
||||||
text = self.textToString(node)
|
|
||||||
|
|
||||||
if not text.strip():
|
|
||||||
return '' # don't apply styles to white space
|
|
||||||
|
|
||||||
styleName = node.getAttribute("text:style-name")
|
|
||||||
style = self.textStyles.get(styleName, TextProps())
|
|
||||||
|
|
||||||
if style.fixed:
|
|
||||||
return "`" + text + "`"
|
|
||||||
|
|
||||||
mark = []
|
|
||||||
if style:
|
|
||||||
if style.italic:
|
|
||||||
mark.append("''")
|
|
||||||
if style.bold:
|
|
||||||
mark.append("'''")
|
|
||||||
if style.underlined:
|
|
||||||
mark.append("__")
|
|
||||||
if style.strikethrough:
|
|
||||||
mark.append("~~")
|
|
||||||
if style.superscript:
|
|
||||||
mark.append("^")
|
|
||||||
if style.subscript:
|
|
||||||
mark.append(",,")
|
|
||||||
revmark = mark[:]
|
|
||||||
revmark.reverse()
|
|
||||||
return "%s%s%s" % (''.join(mark), text, ''.join(revmark))
|
|
||||||
|
|
||||||
#-----------------------------------
|
|
||||||
def listToString(self, listElement, indent = 0):
|
|
||||||
|
|
||||||
self.lastsegment = listElement.tagName
|
|
||||||
buffer = []
|
|
||||||
|
|
||||||
styleName = listElement.getAttribute("text:style-name")
|
|
||||||
props = self.listStyles.get(styleName, ListProperties())
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
for item in listElement.childNodes:
|
|
||||||
buffer.append(" "*indent)
|
|
||||||
i += 1
|
|
||||||
if props.ordered:
|
|
||||||
number = str(i)
|
|
||||||
number = " " + number + ". "
|
|
||||||
buffer.append(" 1. ")
|
|
||||||
else:
|
|
||||||
buffer.append(" * ")
|
|
||||||
subitems = [el for el in item.childNodes
|
|
||||||
if el.tagName in ["text:p", "text:h", "text:list"]]
|
|
||||||
for subitem in subitems:
|
|
||||||
if subitem.tagName == "text:list":
|
|
||||||
buffer.append("\n")
|
|
||||||
buffer.append(self.listToString(subitem, indent+3))
|
|
||||||
else:
|
|
||||||
buffer.append(self.paragraphToString(subitem, indent+3))
|
|
||||||
self.lastsegment = subitem.tagName
|
|
||||||
self.lastsegment = item.tagName
|
|
||||||
buffer.append("\n")
|
|
||||||
|
|
||||||
return ''.join(buffer)
|
|
||||||
|
|
||||||
def tableToString(self, tableElement):
|
|
||||||
""" MoinMoin uses || to delimit table cells
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.lastsegment = tableElement.tagName
|
|
||||||
buffer = []
|
|
||||||
|
|
||||||
for item in tableElement.childNodes:
|
|
||||||
self.lastsegment = item.tagName
|
|
||||||
if item.tagName == "table:table-header-rows":
|
|
||||||
buffer.append(self.tableToString(item))
|
|
||||||
if item.tagName == "table:table-row":
|
|
||||||
buffer.append("\n||")
|
|
||||||
for cell in item.childNodes:
|
|
||||||
buffer.append(self.inline_markup(cell))
|
|
||||||
buffer.append("||")
|
|
||||||
self.lastsegment = cell.tagName
|
|
||||||
return ''.join(buffer)
|
|
||||||
|
|
||||||
|
|
||||||
def toString(self):
|
|
||||||
""" Converts the document to a string.
|
|
||||||
FIXME: Result from second call differs from first call
|
|
||||||
"""
|
|
||||||
body = self.content.getElementsByTagName("office:body")[0]
|
|
||||||
text = body.childNodes[0]
|
|
||||||
|
|
||||||
buffer = []
|
|
||||||
|
|
||||||
paragraphs = [el for el in text.childNodes
|
|
||||||
if el.tagName in ["draw:page", "text:p", "text:h","text:section",
|
|
||||||
"text:list", "table:table"]]
|
|
||||||
|
|
||||||
for paragraph in paragraphs:
|
|
||||||
if paragraph.tagName == "text:list":
|
|
||||||
text = self.listToString(paragraph)
|
|
||||||
elif paragraph.tagName == "text:section":
|
|
||||||
text = self.textToString(paragraph)
|
|
||||||
elif paragraph.tagName == "table:table":
|
|
||||||
text = self.tableToString(paragraph)
|
|
||||||
else:
|
|
||||||
text = self.paragraphToString(paragraph)
|
|
||||||
if text:
|
|
||||||
buffer.append(text)
|
|
||||||
|
|
||||||
if self.footnotes:
|
|
||||||
|
|
||||||
buffer.append("----")
|
|
||||||
for cite, body in self.footnotes:
|
|
||||||
buffer.append("%s: %s" % (cite, body))
|
|
||||||
|
|
||||||
|
|
||||||
buffer.append("")
|
|
||||||
return self.compressCodeBlocks('\n'.join(buffer))
|
|
||||||
|
|
||||||
|
|
||||||
def textToString(self, element):
|
|
||||||
|
|
||||||
buffer = []
|
|
||||||
|
|
||||||
for node in element.childNodes:
|
|
||||||
|
|
||||||
if node.nodeType == xml.dom.Node.TEXT_NODE:
|
|
||||||
buffer.append(node.nodeValue)
|
|
||||||
|
|
||||||
elif node.nodeType == xml.dom.Node.ELEMENT_NODE:
|
|
||||||
tag = node.tagName
|
|
||||||
|
|
||||||
if tag in ("draw:text-box", "draw:frame"):
|
|
||||||
buffer.append(self.textToString(node))
|
|
||||||
|
|
||||||
elif tag in ("text:p", "text:h"):
|
|
||||||
text = self.paragraphToString(node)
|
|
||||||
if text:
|
|
||||||
buffer.append(text)
|
|
||||||
elif tag == "text:list":
|
|
||||||
buffer.append(self.listToString(node))
|
|
||||||
else:
|
|
||||||
method = self.elements.get(tag)
|
|
||||||
if method:
|
|
||||||
buffer.append(method(node))
|
|
||||||
else:
|
|
||||||
buffer.append(" {" + tag + "} ")
|
|
||||||
|
|
||||||
return ''.join(buffer)
|
|
||||||
|
|
||||||
def paragraphToString(self, paragraph, indent = 0):
|
|
||||||
|
|
||||||
dummyParaProps = ParagraphProps()
|
|
||||||
|
|
||||||
style_name = paragraph.getAttribute("text:style-name")
|
|
||||||
paraProps = self.paragraphStyles.get(style_name, dummyParaProps)
|
|
||||||
text = self.inline_markup(paragraph)
|
|
||||||
|
|
||||||
if paraProps and not paraProps.code:
|
|
||||||
text = text.strip()
|
|
||||||
|
|
||||||
if paragraph.tagName == "text:p" and self.lastsegment == "text:p":
|
|
||||||
text = "\n" + text
|
|
||||||
|
|
||||||
self.lastsegment = paragraph.tagName
|
|
||||||
|
|
||||||
if paraProps.title:
|
|
||||||
self.hasTitle = 1
|
|
||||||
return "= " + text + " =\n"
|
|
||||||
|
|
||||||
outlinelevel = paragraph.getAttribute("text:outline-level")
|
|
||||||
if outlinelevel:
|
|
||||||
|
|
||||||
level = int(outlinelevel)
|
|
||||||
if self.hasTitle: level += 1
|
|
||||||
|
|
||||||
if level >= 1:
|
|
||||||
return "=" * level + " " + text + " " + "=" * level + "\n"
|
|
||||||
|
|
||||||
elif paraProps.code:
|
|
||||||
return "{{{\n" + text + "\n}}}\n"
|
|
||||||
|
|
||||||
if paraProps.indented:
|
|
||||||
return self.wrapParagraph(text, indent = indent, blockquote = True)
|
|
||||||
|
|
||||||
else:
|
|
||||||
return self.wrapParagraph(text, indent = indent)
|
|
||||||
|
|
||||||
|
|
||||||
def wrapParagraph(self, text, indent = 0, blockquote=False):
|
|
||||||
|
|
||||||
counter = 0
|
|
||||||
buffer = []
|
|
||||||
LIMIT = 50
|
|
||||||
|
|
||||||
if blockquote:
|
|
||||||
buffer.append(" ")
|
|
||||||
|
|
||||||
return ''.join(buffer) + text
|
|
||||||
# Unused from here
|
|
||||||
for token in text.split():
|
|
||||||
|
|
||||||
if counter > LIMIT - indent:
|
|
||||||
buffer.append("\n" + " "*indent)
|
|
||||||
if blockquote:
|
|
||||||
buffer.append(" ")
|
|
||||||
counter = 0
|
|
||||||
|
|
||||||
buffer.append(token + " ")
|
|
||||||
counter += len(token)
|
|
||||||
|
|
||||||
return ''.join(buffer)
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,120 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
from __future__ import print_function
|
|
||||||
# This script lists the content of the manifest.xml file
|
|
||||||
import zipfile
|
|
||||||
from xml.sax import make_parser,handler
|
|
||||||
from xml.sax.xmlreader import InputSource
|
|
||||||
import xml.sax.saxutils
|
|
||||||
try:
|
|
||||||
from cStringIO import StringIO
|
|
||||||
except ImportError:
|
|
||||||
from io import StringIO
|
|
||||||
|
|
||||||
MANIFESTNS="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"
|
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# ODFMANIFESTHANDLER
|
|
||||||
#
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
class ODFManifestHandler(handler.ContentHandler):
|
|
||||||
""" The ODFManifestHandler parses a manifest file and produces a list of
|
|
||||||
content """
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.manifest = {}
|
|
||||||
|
|
||||||
# Tags
|
|
||||||
# FIXME: Also handle encryption data
|
|
||||||
self.elements = {
|
|
||||||
(MANIFESTNS, 'file-entry'): (self.s_file_entry, self.donothing),
|
|
||||||
}
|
|
||||||
|
|
||||||
def handle_starttag(self, tag, method, attrs):
|
|
||||||
method(tag,attrs)
|
|
||||||
|
|
||||||
def handle_endtag(self, tag, method):
|
|
||||||
method(tag)
|
|
||||||
|
|
||||||
def startElementNS(self, tag, qname, attrs):
|
|
||||||
method = self.elements.get(tag, (None, None))[0]
|
|
||||||
if method:
|
|
||||||
self.handle_starttag(tag, method, attrs)
|
|
||||||
else:
|
|
||||||
self.unknown_starttag(tag,attrs)
|
|
||||||
|
|
||||||
def endElementNS(self, tag, qname):
|
|
||||||
method = self.elements.get(tag, (None, None))[1]
|
|
||||||
if method:
|
|
||||||
self.handle_endtag(tag, method)
|
|
||||||
else:
|
|
||||||
self.unknown_endtag(tag)
|
|
||||||
|
|
||||||
def unknown_starttag(self, tag, attrs):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def unknown_endtag(self, tag):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def donothing(self, tag, attrs=None):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def s_file_entry(self, tag, attrs):
|
|
||||||
m = attrs.get((MANIFESTNS, 'media-type'),"application/octet-stream")
|
|
||||||
p = attrs.get((MANIFESTNS, 'full-path'))
|
|
||||||
self.manifest[p] = { 'media-type':m, 'full-path':p }
|
|
||||||
|
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
#
|
|
||||||
# Reading the file
|
|
||||||
#
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
def manifestlist(manifestxml):
|
|
||||||
odhandler = ODFManifestHandler()
|
|
||||||
parser = make_parser()
|
|
||||||
parser.setFeature(handler.feature_namespaces, 1)
|
|
||||||
parser.setContentHandler(odhandler)
|
|
||||||
parser.setErrorHandler(handler.ErrorHandler())
|
|
||||||
|
|
||||||
inpsrc = InputSource()
|
|
||||||
if not isinstance(manifestxml, str):
|
|
||||||
manifestxml=manifestxml.decode("utf-8")
|
|
||||||
inpsrc.setByteStream(StringIO(manifestxml))
|
|
||||||
parser.parse(inpsrc)
|
|
||||||
|
|
||||||
return odhandler.manifest
|
|
||||||
|
|
||||||
def odfmanifest(odtfile):
|
|
||||||
z = zipfile.ZipFile(odtfile)
|
|
||||||
manifest = z.read('META-INF/manifest.xml')
|
|
||||||
z.close()
|
|
||||||
return manifestlist(manifest)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
import sys
|
|
||||||
result = odfmanifest(sys.argv[1])
|
|
||||||
for file in result.values():
|
|
||||||
print ("%-40s %-40s" % (file['media-type'], file['full-path']))
|
|
||||||
|
|
|
@ -1,107 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2013 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import OFFICENS
|
|
||||||
from element import Element
|
|
||||||
from draw import StyleRefElement
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def Annotation(**args):
|
|
||||||
return StyleRefElement(qname = (OFFICENS,'annotation'), **args)
|
|
||||||
|
|
||||||
def AnnotationEnd(**args):
|
|
||||||
return StyleRefElement(qname = (OFFICENS,'annotation-end'), **args)
|
|
||||||
|
|
||||||
def AutomaticStyles(**args):
|
|
||||||
return Element(qname = (OFFICENS, 'automatic-styles'), **args)
|
|
||||||
|
|
||||||
def BinaryData(**args):
|
|
||||||
return Element(qname = (OFFICENS,'binary-data'), **args)
|
|
||||||
|
|
||||||
def Body(**args):
|
|
||||||
return Element(qname = (OFFICENS, 'body'), **args)
|
|
||||||
|
|
||||||
def ChangeInfo(**args):
|
|
||||||
return Element(qname = (OFFICENS,'change-info'), **args)
|
|
||||||
|
|
||||||
def Chart(**args):
|
|
||||||
return Element(qname = (OFFICENS,'chart'), **args)
|
|
||||||
|
|
||||||
def DdeSource(**args):
|
|
||||||
return Element(qname = (OFFICENS,'dde-source'), **args)
|
|
||||||
|
|
||||||
def Document(version="1.2", **args):
|
|
||||||
return Element(qname = (OFFICENS,'document'), version=version, **args)
|
|
||||||
|
|
||||||
def DocumentContent(version="1.2", **args):
|
|
||||||
return Element(qname = (OFFICENS, 'document-content'), version=version, **args)
|
|
||||||
|
|
||||||
def DocumentMeta(version="1.2", **args):
|
|
||||||
return Element(qname = (OFFICENS, 'document-meta'), version=version, **args)
|
|
||||||
|
|
||||||
def DocumentSettings(version="1.2", **args):
|
|
||||||
return Element(qname = (OFFICENS, 'document-settings'), version=version, **args)
|
|
||||||
|
|
||||||
def DocumentStyles(version="1.2", **args):
|
|
||||||
return Element(qname = (OFFICENS, 'document-styles'), version=version, **args)
|
|
||||||
|
|
||||||
def Drawing(**args):
|
|
||||||
return Element(qname = (OFFICENS,'drawing'), **args)
|
|
||||||
|
|
||||||
def EventListeners(**args):
|
|
||||||
return Element(qname = (OFFICENS,'event-listeners'), **args)
|
|
||||||
|
|
||||||
def FontFaceDecls(**args):
|
|
||||||
return Element(qname = (OFFICENS, 'font-face-decls'), **args)
|
|
||||||
|
|
||||||
def Forms(**args):
|
|
||||||
return Element(qname = (OFFICENS,'forms'), **args)
|
|
||||||
|
|
||||||
def Image(**args):
|
|
||||||
return Element(qname = (OFFICENS,'image'), **args)
|
|
||||||
|
|
||||||
def MasterStyles(**args):
|
|
||||||
return Element(qname = (OFFICENS, 'master-styles'), **args)
|
|
||||||
|
|
||||||
def Meta(**args):
|
|
||||||
return Element(qname = (OFFICENS, 'meta'), **args)
|
|
||||||
|
|
||||||
def Presentation(**args):
|
|
||||||
return Element(qname = (OFFICENS,'presentation'), **args)
|
|
||||||
|
|
||||||
def Script(**args):
|
|
||||||
return Element(qname = (OFFICENS, 'script'), **args)
|
|
||||||
|
|
||||||
def Scripts(**args):
|
|
||||||
return Element(qname = (OFFICENS, 'scripts'), **args)
|
|
||||||
|
|
||||||
def Settings(**args):
|
|
||||||
return Element(qname = (OFFICENS, 'settings'), **args)
|
|
||||||
|
|
||||||
def Spreadsheet(**args):
|
|
||||||
return Element(qname = (OFFICENS, 'spreadsheet'), **args)
|
|
||||||
|
|
||||||
def Styles(**args):
|
|
||||||
return Element(qname = (OFFICENS, 'styles'), **args)
|
|
||||||
|
|
||||||
def Text(**args):
|
|
||||||
return Element(qname = (OFFICENS, 'text'), **args)
|
|
||||||
|
|
||||||
# Autogenerated end
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,86 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import PRESENTATIONNS
|
|
||||||
from element import Element
|
|
||||||
|
|
||||||
# ODF 1.0 section 9.6 and 9.7
|
|
||||||
# Autogenerated
|
|
||||||
def AnimationGroup(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'animation-group'), **args)
|
|
||||||
|
|
||||||
def Animations(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'animations'), **args)
|
|
||||||
|
|
||||||
def DateTime(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'date-time'), **args)
|
|
||||||
|
|
||||||
def DateTimeDecl(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'date-time-decl'), **args)
|
|
||||||
|
|
||||||
def Dim(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'dim'), **args)
|
|
||||||
|
|
||||||
def EventListener(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'event-listener'), **args)
|
|
||||||
|
|
||||||
def Footer(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'footer'), **args)
|
|
||||||
|
|
||||||
def FooterDecl(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'footer-decl'), **args)
|
|
||||||
|
|
||||||
def Header(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'header'), **args)
|
|
||||||
|
|
||||||
def HeaderDecl(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'header-decl'), **args)
|
|
||||||
|
|
||||||
def HideShape(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'hide-shape'), **args)
|
|
||||||
|
|
||||||
def HideText(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'hide-text'), **args)
|
|
||||||
|
|
||||||
def Notes(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'notes'), **args)
|
|
||||||
|
|
||||||
def Placeholder(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'placeholder'), **args)
|
|
||||||
|
|
||||||
def Play(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'play'), **args)
|
|
||||||
|
|
||||||
def Settings(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'settings'), **args)
|
|
||||||
|
|
||||||
def Show(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'show'), **args)
|
|
||||||
|
|
||||||
def ShowShape(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'show-shape'), **args)
|
|
||||||
|
|
||||||
def ShowText(**args):
|
|
||||||
return Element(qname = (PRESENTATIONNS,'show-text'), **args)
|
|
||||||
|
|
||||||
def Sound(**args):
|
|
||||||
args.setdefault('type', 'simple')
|
|
||||||
return Element(qname = (PRESENTATIONNS,'sound'), **args)
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import SCRIPTNS
|
|
||||||
from element import Element
|
|
||||||
|
|
||||||
# ODF 1.0 section 12.4.1
|
|
||||||
# The <script:event-listener> element binds an event to a macro.
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def EventListener(**args):
|
|
||||||
return Element(qname = (SCRIPTNS,'event-listener'), **args)
|
|
||||||
|
|
|
@ -1,154 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2013 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import STYLENS
|
|
||||||
from element import Element
|
|
||||||
|
|
||||||
def StyleElement(**args):
|
|
||||||
e = Element(**args)
|
|
||||||
if args.get('check_grammar', True) == True:
|
|
||||||
if 'displayname' not in args:
|
|
||||||
e.setAttrNS(STYLENS,'display-name', args.get('name'))
|
|
||||||
return e
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def BackgroundImage(**args):
|
|
||||||
return Element(qname = (STYLENS,'background-image'), **args)
|
|
||||||
|
|
||||||
def ChartProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'chart-properties'), **args)
|
|
||||||
|
|
||||||
def Column(**args):
|
|
||||||
return Element(qname = (STYLENS,'column'), **args)
|
|
||||||
|
|
||||||
def ColumnSep(**args):
|
|
||||||
return Element(qname = (STYLENS,'column-sep'), **args)
|
|
||||||
|
|
||||||
def Columns(**args):
|
|
||||||
return Element(qname = (STYLENS,'columns'), **args)
|
|
||||||
|
|
||||||
def DefaultPageLayout(**args):
|
|
||||||
return Element(qname = (STYLENS,'default-page-layout'), **args)
|
|
||||||
|
|
||||||
def DefaultStyle(**args):
|
|
||||||
return Element(qname = (STYLENS,'default-style'), **args)
|
|
||||||
|
|
||||||
def DrawingPageProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'drawing-page-properties'), **args)
|
|
||||||
|
|
||||||
def DropCap(**args):
|
|
||||||
return Element(qname = (STYLENS,'drop-cap'), **args)
|
|
||||||
|
|
||||||
def FontFace(**args):
|
|
||||||
return Element(qname = (STYLENS,'font-face'), **args)
|
|
||||||
|
|
||||||
def Footer(**args):
|
|
||||||
return Element(qname = (STYLENS,'footer'), **args)
|
|
||||||
|
|
||||||
def FooterLeft(**args):
|
|
||||||
return Element(qname = (STYLENS,'footer-left'), **args)
|
|
||||||
|
|
||||||
def FooterStyle(**args):
|
|
||||||
return Element(qname = (STYLENS,'footer-style'), **args)
|
|
||||||
|
|
||||||
def FootnoteSep(**args):
|
|
||||||
return Element(qname = (STYLENS,'footnote-sep'), **args)
|
|
||||||
|
|
||||||
def GraphicProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'graphic-properties'), **args)
|
|
||||||
|
|
||||||
def HandoutMaster(**args):
|
|
||||||
return Element(qname = (STYLENS,'handout-master'), **args)
|
|
||||||
|
|
||||||
def Header(**args):
|
|
||||||
return Element(qname = (STYLENS,'header'), **args)
|
|
||||||
|
|
||||||
def HeaderFooterProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'header-footer-properties'), **args)
|
|
||||||
|
|
||||||
def HeaderLeft(**args):
|
|
||||||
return Element(qname = (STYLENS,'header-left'), **args)
|
|
||||||
|
|
||||||
def HeaderStyle(**args):
|
|
||||||
return Element(qname = (STYLENS,'header-style'), **args)
|
|
||||||
|
|
||||||
def ListLevelLabelAlignment(**args):
|
|
||||||
return Element(qname = (STYLENS,'list-level-label-alignment'), **args)
|
|
||||||
|
|
||||||
def ListLevelProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'list-level-properties'), **args)
|
|
||||||
|
|
||||||
def Map(**args):
|
|
||||||
return Element(qname = (STYLENS,'map'), **args)
|
|
||||||
|
|
||||||
def MasterPage(**args):
|
|
||||||
return StyleElement(qname = (STYLENS,'master-page'), **args)
|
|
||||||
|
|
||||||
def PageLayout(**args):
|
|
||||||
return Element(qname = (STYLENS,'page-layout'), **args)
|
|
||||||
|
|
||||||
def PageLayoutProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'page-layout-properties'), **args)
|
|
||||||
|
|
||||||
def ParagraphProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'paragraph-properties'), **args)
|
|
||||||
|
|
||||||
def PresentationPageLayout(**args):
|
|
||||||
return StyleElement(qname = (STYLENS,'presentation-page-layout'), **args)
|
|
||||||
|
|
||||||
def RegionCenter(**args):
|
|
||||||
return Element(qname = (STYLENS,'region-center'), **args)
|
|
||||||
|
|
||||||
def RegionLeft(**args):
|
|
||||||
return Element(qname = (STYLENS,'region-left'), **args)
|
|
||||||
|
|
||||||
def RegionRight(**args):
|
|
||||||
return Element(qname = (STYLENS,'region-right'), **args)
|
|
||||||
|
|
||||||
def RubyProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'ruby-properties'), **args)
|
|
||||||
|
|
||||||
def SectionProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'section-properties'), **args)
|
|
||||||
|
|
||||||
def Style(**args):
|
|
||||||
return StyleElement(qname = (STYLENS,'style'), **args)
|
|
||||||
|
|
||||||
def TabStop(**args):
|
|
||||||
return Element(qname = (STYLENS,'tab-stop'), **args)
|
|
||||||
|
|
||||||
def TabStops(**args):
|
|
||||||
return Element(qname = (STYLENS,'tab-stops'), **args)
|
|
||||||
|
|
||||||
def TableCellProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'table-cell-properties'), **args)
|
|
||||||
|
|
||||||
def TableColumnProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'table-column-properties'), **args)
|
|
||||||
|
|
||||||
def TableProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'table-properties'), **args)
|
|
||||||
|
|
||||||
def TableRowProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'table-row-properties'), **args)
|
|
||||||
|
|
||||||
def TextProperties(**args):
|
|
||||||
return Element(qname = (STYLENS,'text-properties'), **args)
|
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import SVGNS
|
|
||||||
from element import Element
|
|
||||||
from draw import DrawElement
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def DefinitionSrc(**args):
|
|
||||||
args.setdefault('type', 'simple')
|
|
||||||
return Element(qname = (SVGNS,'definition-src'), **args)
|
|
||||||
|
|
||||||
def Desc(**args):
|
|
||||||
return Element(qname = (SVGNS,'desc'), **args)
|
|
||||||
|
|
||||||
def FontFaceFormat(**args):
|
|
||||||
return Element(qname = (SVGNS,'font-face-format'), **args)
|
|
||||||
|
|
||||||
def FontFaceName(**args):
|
|
||||||
return Element(qname = (SVGNS,'font-face-name'), **args)
|
|
||||||
|
|
||||||
def FontFaceSrc(**args):
|
|
||||||
return Element(qname = (SVGNS,'font-face-src'), **args)
|
|
||||||
|
|
||||||
def FontFaceUri(**args):
|
|
||||||
args.setdefault('type', 'simple')
|
|
||||||
return Element(qname = (SVGNS,'font-face-uri'), **args)
|
|
||||||
|
|
||||||
def Lineargradient(**args):
|
|
||||||
return DrawElement(qname = (SVGNS,'linearGradient'), **args)
|
|
||||||
|
|
||||||
def Radialgradient(**args):
|
|
||||||
return DrawElement(qname = (SVGNS,'radialGradient'), **args)
|
|
||||||
|
|
||||||
def Stop(**args):
|
|
||||||
return Element(qname = (SVGNS,'stop'), **args)
|
|
||||||
|
|
||||||
def Title(**args):
|
|
||||||
return Element(qname = (SVGNS,'title'), **args)
|
|
|
@ -1,321 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2013 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import TABLENS
|
|
||||||
from element import Element
|
|
||||||
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def Background(**args):
|
|
||||||
return Element(qname = (TABLENS,'background'), **args)
|
|
||||||
|
|
||||||
def Body(**args):
|
|
||||||
return Element(qname = (TABLENS,'body'), **args)
|
|
||||||
|
|
||||||
def CalculationSettings(**args):
|
|
||||||
return Element(qname = (TABLENS,'calculation-settings'), **args)
|
|
||||||
|
|
||||||
def CellAddress(**args):
|
|
||||||
return Element(qname = (TABLENS,'cell-address'), **args)
|
|
||||||
|
|
||||||
def CellContentChange(**args):
|
|
||||||
return Element(qname = (TABLENS,'cell-content-change'), **args)
|
|
||||||
|
|
||||||
def CellContentDeletion(**args):
|
|
||||||
return Element(qname = (TABLENS,'cell-content-deletion'), **args)
|
|
||||||
|
|
||||||
def CellRangeSource(**args):
|
|
||||||
args.setdefault('type', 'simple')
|
|
||||||
return Element(qname = (TABLENS,'cell-range-source'), **args)
|
|
||||||
|
|
||||||
def ChangeDeletion(**args):
|
|
||||||
return Element(qname = (TABLENS,'change-deletion'), **args)
|
|
||||||
|
|
||||||
def ChangeTrackTableCell(**args):
|
|
||||||
return Element(qname = (TABLENS,'change-track-table-cell'), **args)
|
|
||||||
|
|
||||||
def Consolidation(**args):
|
|
||||||
return Element(qname = (TABLENS,'consolidation'), **args)
|
|
||||||
|
|
||||||
def ContentValidation(**args):
|
|
||||||
return Element(qname = (TABLENS,'content-validation'), **args)
|
|
||||||
|
|
||||||
def ContentValidations(**args):
|
|
||||||
return Element(qname = (TABLENS,'content-validations'), **args)
|
|
||||||
|
|
||||||
def CoveredTableCell(**args):
|
|
||||||
return Element(qname = (TABLENS,'covered-table-cell'), **args)
|
|
||||||
|
|
||||||
def CutOffs(**args):
|
|
||||||
return Element(qname = (TABLENS,'cut-offs'), **args)
|
|
||||||
|
|
||||||
def DataPilotDisplayInfo(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-display-info'), **args)
|
|
||||||
|
|
||||||
def DataPilotField(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-field'), **args)
|
|
||||||
|
|
||||||
def DataPilotFieldReference(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-field-reference'), **args)
|
|
||||||
|
|
||||||
def DataPilotGroup(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-group'), **args)
|
|
||||||
|
|
||||||
def DataPilotGroupMember(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-group-member'), **args)
|
|
||||||
|
|
||||||
def DataPilotGroups(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-groups'), **args)
|
|
||||||
|
|
||||||
def DataPilotLayoutInfo(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-layout-info'), **args)
|
|
||||||
|
|
||||||
def DataPilotLevel(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-level'), **args)
|
|
||||||
|
|
||||||
def DataPilotMember(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-member'), **args)
|
|
||||||
|
|
||||||
def DataPilotMembers(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-members'), **args)
|
|
||||||
|
|
||||||
def DataPilotSortInfo(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-sort-info'), **args)
|
|
||||||
|
|
||||||
def DataPilotSubtotal(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-subtotal'), **args)
|
|
||||||
|
|
||||||
def DataPilotSubtotals(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-subtotals'), **args)
|
|
||||||
|
|
||||||
def DataPilotTable(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-table'), **args)
|
|
||||||
|
|
||||||
def DataPilotTables(**args):
|
|
||||||
return Element(qname = (TABLENS,'data-pilot-tables'), **args)
|
|
||||||
|
|
||||||
def DatabaseRange(**args):
|
|
||||||
return Element(qname = (TABLENS,'database-range'), **args)
|
|
||||||
|
|
||||||
def DatabaseRanges(**args):
|
|
||||||
return Element(qname = (TABLENS,'database-ranges'), **args)
|
|
||||||
|
|
||||||
def DatabaseSourceQuery(**args):
|
|
||||||
return Element(qname = (TABLENS,'database-source-query'), **args)
|
|
||||||
|
|
||||||
def DatabaseSourceSql(**args):
|
|
||||||
return Element(qname = (TABLENS,'database-source-sql'), **args)
|
|
||||||
|
|
||||||
def DatabaseSourceTable(**args):
|
|
||||||
return Element(qname = (TABLENS,'database-source-table'), **args)
|
|
||||||
|
|
||||||
def DdeLink(**args):
|
|
||||||
return Element(qname = (TABLENS,'dde-link'), **args)
|
|
||||||
|
|
||||||
def DdeLinks(**args):
|
|
||||||
return Element(qname = (TABLENS,'dde-links'), **args)
|
|
||||||
|
|
||||||
def Deletion(**args):
|
|
||||||
return Element(qname = (TABLENS,'deletion'), **args)
|
|
||||||
|
|
||||||
def Deletions(**args):
|
|
||||||
return Element(qname = (TABLENS,'deletions'), **args)
|
|
||||||
|
|
||||||
def Dependencies(**args):
|
|
||||||
return Element(qname = (TABLENS,'dependencies'), **args)
|
|
||||||
|
|
||||||
def Dependency(**args):
|
|
||||||
return Element(qname = (TABLENS,'dependency'), **args)
|
|
||||||
|
|
||||||
def Desc(**args):
|
|
||||||
return Element(qname = (TABLENS,'desc'), **args)
|
|
||||||
|
|
||||||
def Detective(**args):
|
|
||||||
return Element(qname = (TABLENS,'detective'), **args)
|
|
||||||
|
|
||||||
def ErrorMacro(**args):
|
|
||||||
return Element(qname = (TABLENS,'error-macro'), **args)
|
|
||||||
|
|
||||||
def ErrorMessage(**args):
|
|
||||||
return Element(qname = (TABLENS,'error-message'), **args)
|
|
||||||
|
|
||||||
def EvenColumns(**args):
|
|
||||||
return Element(qname = (TABLENS,'even-columns'), **args)
|
|
||||||
|
|
||||||
def EvenRows(**args):
|
|
||||||
return Element(qname = (TABLENS,'even-rows'), **args)
|
|
||||||
|
|
||||||
def Filter(**args):
|
|
||||||
return Element(qname = (TABLENS,'filter'), **args)
|
|
||||||
|
|
||||||
def FilterAnd(**args):
|
|
||||||
return Element(qname = (TABLENS,'filter-and'), **args)
|
|
||||||
|
|
||||||
def FilterCondition(**args):
|
|
||||||
return Element(qname = (TABLENS,'filter-condition'), **args)
|
|
||||||
|
|
||||||
def FilterOr(**args):
|
|
||||||
return Element(qname = (TABLENS,'filter-or'), **args)
|
|
||||||
|
|
||||||
def FilterSetItem(**args):
|
|
||||||
return Element(qname = (TABLENS,'filter-set-item'), **args)
|
|
||||||
|
|
||||||
def FirstColumn(**args):
|
|
||||||
return Element(qname = (TABLENS,'first-column'), **args)
|
|
||||||
|
|
||||||
def FirstRow(**args):
|
|
||||||
return Element(qname = (TABLENS,'first-row'), **args)
|
|
||||||
|
|
||||||
def HelpMessage(**args):
|
|
||||||
return Element(qname = (TABLENS,'help-message'), **args)
|
|
||||||
|
|
||||||
def HighlightedRange(**args):
|
|
||||||
return Element(qname = (TABLENS,'highlighted-range'), **args)
|
|
||||||
|
|
||||||
def Insertion(**args):
|
|
||||||
return Element(qname = (TABLENS,'insertion'), **args)
|
|
||||||
|
|
||||||
def InsertionCutOff(**args):
|
|
||||||
return Element(qname = (TABLENS,'insertion-cut-off'), **args)
|
|
||||||
|
|
||||||
def Iteration(**args):
|
|
||||||
return Element(qname = (TABLENS,'iteration'), **args)
|
|
||||||
|
|
||||||
def LabelRange(**args):
|
|
||||||
return Element(qname = (TABLENS,'label-range'), **args)
|
|
||||||
|
|
||||||
def LabelRanges(**args):
|
|
||||||
return Element(qname = (TABLENS,'label-ranges'), **args)
|
|
||||||
|
|
||||||
def LastColumn(**args):
|
|
||||||
return Element(qname = (TABLENS,'last-column'), **args)
|
|
||||||
|
|
||||||
def LastRow(**args):
|
|
||||||
return Element(qname = (TABLENS,'last-row'), **args)
|
|
||||||
|
|
||||||
def Movement(**args):
|
|
||||||
return Element(qname = (TABLENS,'movement'), **args)
|
|
||||||
|
|
||||||
def MovementCutOff(**args):
|
|
||||||
return Element(qname = (TABLENS,'movement-cut-off'), **args)
|
|
||||||
|
|
||||||
def NamedExpression(**args):
|
|
||||||
return Element(qname = (TABLENS,'named-expression'), **args)
|
|
||||||
|
|
||||||
def NamedExpressions(**args):
|
|
||||||
return Element(qname = (TABLENS,'named-expressions'), **args)
|
|
||||||
|
|
||||||
def NamedRange(**args):
|
|
||||||
return Element(qname = (TABLENS,'named-range'), **args)
|
|
||||||
|
|
||||||
def NullDate(**args):
|
|
||||||
return Element(qname = (TABLENS,'null-date'), **args)
|
|
||||||
|
|
||||||
def OddColumns(**args):
|
|
||||||
return Element(qname = (TABLENS,'odd-columns'), **args)
|
|
||||||
|
|
||||||
def OddRows(**args):
|
|
||||||
return Element(qname = (TABLENS,'odd-rows'), **args)
|
|
||||||
|
|
||||||
def Operation(**args):
|
|
||||||
return Element(qname = (TABLENS,'operation'), **args)
|
|
||||||
|
|
||||||
def Previous(**args):
|
|
||||||
return Element(qname = (TABLENS,'previous'), **args)
|
|
||||||
|
|
||||||
def Scenario(**args):
|
|
||||||
return Element(qname = (TABLENS,'scenario'), **args)
|
|
||||||
|
|
||||||
def Shapes(**args):
|
|
||||||
return Element(qname = (TABLENS,'shapes'), **args)
|
|
||||||
|
|
||||||
def Sort(**args):
|
|
||||||
return Element(qname = (TABLENS,'sort'), **args)
|
|
||||||
|
|
||||||
def SortBy(**args):
|
|
||||||
return Element(qname = (TABLENS,'sort-by'), **args)
|
|
||||||
|
|
||||||
def SortGroups(**args):
|
|
||||||
return Element(qname = (TABLENS,'sort-groups'), **args)
|
|
||||||
|
|
||||||
def SourceCellRange(**args):
|
|
||||||
return Element(qname = (TABLENS,'source-cell-range'), **args)
|
|
||||||
|
|
||||||
def SourceRangeAddress(**args):
|
|
||||||
return Element(qname = (TABLENS,'source-range-address'), **args)
|
|
||||||
|
|
||||||
def SourceService(**args):
|
|
||||||
return Element(qname = (TABLENS,'source-service'), **args)
|
|
||||||
|
|
||||||
def SubtotalField(**args):
|
|
||||||
return Element(qname = (TABLENS,'subtotal-field'), **args)
|
|
||||||
|
|
||||||
def SubtotalRule(**args):
|
|
||||||
return Element(qname = (TABLENS,'subtotal-rule'), **args)
|
|
||||||
|
|
||||||
def SubtotalRules(**args):
|
|
||||||
return Element(qname = (TABLENS,'subtotal-rules'), **args)
|
|
||||||
|
|
||||||
def Table(**args):
|
|
||||||
return Element(qname = (TABLENS,'table'), **args)
|
|
||||||
|
|
||||||
def TableCell(**args):
|
|
||||||
return Element(qname = (TABLENS,'table-cell'), **args)
|
|
||||||
|
|
||||||
def TableColumn(**args):
|
|
||||||
return Element(qname = (TABLENS,'table-column'), **args)
|
|
||||||
|
|
||||||
def TableColumnGroup(**args):
|
|
||||||
return Element(qname = (TABLENS,'table-column-group'), **args)
|
|
||||||
|
|
||||||
def TableColumns(**args):
|
|
||||||
return Element(qname = (TABLENS,'table-columns'), **args)
|
|
||||||
|
|
||||||
def TableHeaderColumns(**args):
|
|
||||||
return Element(qname = (TABLENS,'table-header-columns'), **args)
|
|
||||||
|
|
||||||
def TableHeaderRows(**args):
|
|
||||||
return Element(qname = (TABLENS,'table-header-rows'), **args)
|
|
||||||
|
|
||||||
def TableRow(**args):
|
|
||||||
return Element(qname = (TABLENS,'table-row'), **args)
|
|
||||||
|
|
||||||
def TableRowGroup(**args):
|
|
||||||
return Element(qname = (TABLENS,'table-row-group'), **args)
|
|
||||||
|
|
||||||
def TableRows(**args):
|
|
||||||
return Element(qname = (TABLENS,'table-rows'), **args)
|
|
||||||
|
|
||||||
def TableSource(**args):
|
|
||||||
args.setdefault('type', 'simple')
|
|
||||||
return Element(qname = (TABLENS,'table-source'), **args)
|
|
||||||
|
|
||||||
def TableTemplate(**args):
|
|
||||||
return Element(qname = (TABLENS,'table-template'), **args)
|
|
||||||
|
|
||||||
def TargetRangeAddress(**args):
|
|
||||||
return Element(qname = (TABLENS,'target-range-address'), **args)
|
|
||||||
|
|
||||||
def Title(**args):
|
|
||||||
return Element(qname = (TABLENS,'title'), **args)
|
|
||||||
|
|
||||||
def TrackedChanges(**args):
|
|
||||||
return Element(qname = (TABLENS,'tracked-changes'), **args)
|
|
||||||
|
|
|
@ -1,137 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
# Create and extract text from ODF, handling whitespace correctly.
|
|
||||||
# Copyright (C) 2008 J. David Eisenberg
|
|
||||||
#
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License along
|
|
||||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
Class for handling whitespace properly in OpenDocument.
|
|
||||||
|
|
||||||
While it is possible to use getTextContent() and setTextContent()
|
|
||||||
to extract or create ODF content, these won't extract or create
|
|
||||||
the appropriate <text:s>, <text:tab>, or <text:line-break>
|
|
||||||
elements. This module takes care of that problem.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from odf.element import Node
|
|
||||||
import odf.opendocument
|
|
||||||
from odf.text import S,LineBreak,Tab
|
|
||||||
|
|
||||||
class WhitespaceText(object):
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.textBuffer = []
|
|
||||||
self.spaceCount = 0
|
|
||||||
|
|
||||||
def addTextToElement(self, odfElement, s):
|
|
||||||
""" Process an input string, inserting
|
|
||||||
<text:tab> elements for '\t',
|
|
||||||
<text:line-break> elements for '\n', and
|
|
||||||
<text:s> elements for runs of more than one blank.
|
|
||||||
These will be added to the given element.
|
|
||||||
"""
|
|
||||||
i = 0
|
|
||||||
ch = ' '
|
|
||||||
|
|
||||||
# When we encounter a tab or newline, we can immediately
|
|
||||||
# dump any accumulated text and then emit the appropriate
|
|
||||||
# ODF element.
|
|
||||||
#
|
|
||||||
# When we encounter a space, we add it to the text buffer,
|
|
||||||
# and then collect more spaces. If there are more spaces
|
|
||||||
# after the first one, we dump the text buffer and then
|
|
||||||
# then emit the appropriate <text:s> element.
|
|
||||||
|
|
||||||
while i < len(s):
|
|
||||||
ch = s[i]
|
|
||||||
if ch == '\t':
|
|
||||||
self._emitTextBuffer(odfElement)
|
|
||||||
odfElement.addElement(Tab())
|
|
||||||
i += 1
|
|
||||||
elif ch == '\n':
|
|
||||||
self._emitTextBuffer(odfElement);
|
|
||||||
odfElement.addElement(LineBreak())
|
|
||||||
i += 1
|
|
||||||
elif ch == ' ':
|
|
||||||
self.textBuffer.append(' ')
|
|
||||||
i += 1
|
|
||||||
self.spaceCount = 0
|
|
||||||
while i < len(s) and (s[i] == ' '):
|
|
||||||
self.spaceCount += 1
|
|
||||||
i += 1
|
|
||||||
if self.spaceCount > 0:
|
|
||||||
self._emitTextBuffer(odfElement)
|
|
||||||
self._emitSpaces(odfElement)
|
|
||||||
else:
|
|
||||||
self.textBuffer.append(ch)
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
self._emitTextBuffer(odfElement)
|
|
||||||
|
|
||||||
def _emitTextBuffer(self, odfElement):
|
|
||||||
""" Creates a Text Node whose contents are the current textBuffer.
|
|
||||||
Side effect: clears the text buffer.
|
|
||||||
"""
|
|
||||||
if len(self.textBuffer) > 0:
|
|
||||||
odfElement.addText(''.join(self.textBuffer))
|
|
||||||
self.textBuffer = []
|
|
||||||
|
|
||||||
|
|
||||||
def _emitSpaces(self, odfElement):
|
|
||||||
""" Creates a <text:s> element for the current spaceCount.
|
|
||||||
Side effect: sets spaceCount back to zero
|
|
||||||
"""
|
|
||||||
if self.spaceCount > 0:
|
|
||||||
spaceElement = S(c=self.spaceCount)
|
|
||||||
odfElement.addElement(spaceElement)
|
|
||||||
self.spaceCount = 0
|
|
||||||
|
|
||||||
def addTextToElement(odfElement, s):
|
|
||||||
wst = WhitespaceText()
|
|
||||||
wst.addTextToElement(odfElement, s)
|
|
||||||
|
|
||||||
def extractText(odfElement):
|
|
||||||
""" Extract text content from an Element, with whitespace represented
|
|
||||||
properly. Returns the text, with tabs, spaces, and newlines
|
|
||||||
correctly evaluated. This method recursively descends through the
|
|
||||||
children of the given element, accumulating text and "unwrapping"
|
|
||||||
<text:s>, <text:tab>, and <text:line-break> elements along the way.
|
|
||||||
"""
|
|
||||||
result = [];
|
|
||||||
|
|
||||||
if len(odfElement.childNodes) != 0:
|
|
||||||
for child in odfElement.childNodes:
|
|
||||||
if child.nodeType == Node.TEXT_NODE:
|
|
||||||
result.append(child.data)
|
|
||||||
elif child.nodeType == Node.ELEMENT_NODE:
|
|
||||||
subElement = child
|
|
||||||
tagName = subElement.qname;
|
|
||||||
if tagName == (u"urn:oasis:names:tc:opendocument:xmlns:text:1.0", u"line-break"):
|
|
||||||
result.append("\n")
|
|
||||||
elif tagName == (u"urn:oasis:names:tc:opendocument:xmlns:text:1.0", u"tab"):
|
|
||||||
result.append("\t")
|
|
||||||
elif tagName == (u"urn:oasis:names:tc:opendocument:xmlns:text:1.0", u"s"):
|
|
||||||
c = subElement.getAttribute('c')
|
|
||||||
if c:
|
|
||||||
spaceCount = int(c)
|
|
||||||
else:
|
|
||||||
spaceCount = 1
|
|
||||||
|
|
||||||
result.append(" " * spaceCount)
|
|
||||||
else:
|
|
||||||
result.append(extractText(subElement))
|
|
||||||
return ''.join(result)
|
|
573
libs/odf/text.py
573
libs/odf/text.py
|
@ -1,573 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2013 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
import re, sys, os.path
|
|
||||||
sys.path.append(os.path.dirname(__file__))
|
|
||||||
|
|
||||||
|
|
||||||
from namespaces import TEXTNS
|
|
||||||
from element import Element
|
|
||||||
from style import StyleElement
|
|
||||||
|
|
||||||
# Autogenerated
|
|
||||||
def A(**args):
|
|
||||||
args.setdefault('type', 'simple')
|
|
||||||
return Element(qname = (TEXTNS,'a'), **args)
|
|
||||||
|
|
||||||
def AlphabeticalIndex(**args):
|
|
||||||
return Element(qname = (TEXTNS,'alphabetical-index'), **args)
|
|
||||||
|
|
||||||
def AlphabeticalIndexAutoMarkFile(**args):
|
|
||||||
args.setdefault('type', 'simple')
|
|
||||||
return Element(qname = (TEXTNS,'alphabetical-index-auto-mark-file'), **args)
|
|
||||||
|
|
||||||
def AlphabeticalIndexEntryTemplate(**args):
|
|
||||||
return Element(qname = (TEXTNS,'alphabetical-index-entry-template'), **args)
|
|
||||||
|
|
||||||
def AlphabeticalIndexMark(**args):
|
|
||||||
return Element(qname = (TEXTNS,'alphabetical-index-mark'), **args)
|
|
||||||
|
|
||||||
def AlphabeticalIndexMarkEnd(**args):
|
|
||||||
return Element(qname = (TEXTNS,'alphabetical-index-mark-end'), **args)
|
|
||||||
|
|
||||||
def AlphabeticalIndexMarkStart(**args):
|
|
||||||
return Element(qname = (TEXTNS,'alphabetical-index-mark-start'), **args)
|
|
||||||
|
|
||||||
def AlphabeticalIndexSource(**args):
|
|
||||||
return Element(qname = (TEXTNS,'alphabetical-index-source'), **args)
|
|
||||||
|
|
||||||
def AuthorInitials(**args):
|
|
||||||
return Element(qname = (TEXTNS,'author-initials'), **args)
|
|
||||||
|
|
||||||
def AuthorName(**args):
|
|
||||||
return Element(qname = (TEXTNS,'author-name'), **args)
|
|
||||||
|
|
||||||
def Bibliography(**args):
|
|
||||||
return Element(qname = (TEXTNS,'bibliography'), **args)
|
|
||||||
|
|
||||||
def BibliographyConfiguration(**args):
|
|
||||||
return Element(qname = (TEXTNS,'bibliography-configuration'), **args)
|
|
||||||
|
|
||||||
def BibliographyEntryTemplate(**args):
|
|
||||||
return Element(qname = (TEXTNS,'bibliography-entry-template'), **args)
|
|
||||||
|
|
||||||
def BibliographyMark(**args):
|
|
||||||
return Element(qname = (TEXTNS,'bibliography-mark'), **args)
|
|
||||||
|
|
||||||
def BibliographySource(**args):
|
|
||||||
return Element(qname = (TEXTNS,'bibliography-source'), **args)
|
|
||||||
|
|
||||||
def Bookmark(**args):
|
|
||||||
return Element(qname = (TEXTNS,'bookmark'), **args)
|
|
||||||
|
|
||||||
def BookmarkEnd(**args):
|
|
||||||
return Element(qname = (TEXTNS,'bookmark-end'), **args)
|
|
||||||
|
|
||||||
def BookmarkRef(**args):
|
|
||||||
return Element(qname = (TEXTNS,'bookmark-ref'), **args)
|
|
||||||
|
|
||||||
def BookmarkStart(**args):
|
|
||||||
return Element(qname = (TEXTNS,'bookmark-start'), **args)
|
|
||||||
|
|
||||||
def Change(**args):
|
|
||||||
return Element(qname = (TEXTNS,'change'), **args)
|
|
||||||
|
|
||||||
def ChangeEnd(**args):
|
|
||||||
return Element(qname = (TEXTNS,'change-end'), **args)
|
|
||||||
|
|
||||||
def ChangeStart(**args):
|
|
||||||
return Element(qname = (TEXTNS,'change-start'), **args)
|
|
||||||
|
|
||||||
def ChangedRegion(**args):
|
|
||||||
return Element(qname = (TEXTNS,'changed-region'), **args)
|
|
||||||
|
|
||||||
def Chapter(**args):
|
|
||||||
return Element(qname = (TEXTNS,'chapter'), **args)
|
|
||||||
|
|
||||||
def CharacterCount(**args):
|
|
||||||
return Element(qname = (TEXTNS,'character-count'), **args)
|
|
||||||
|
|
||||||
def ConditionalText(**args):
|
|
||||||
return Element(qname = (TEXTNS,'conditional-text'), **args)
|
|
||||||
|
|
||||||
def CreationDate(**args):
|
|
||||||
return Element(qname = (TEXTNS,'creation-date'), **args)
|
|
||||||
|
|
||||||
def CreationTime(**args):
|
|
||||||
return Element(qname = (TEXTNS,'creation-time'), **args)
|
|
||||||
|
|
||||||
def Creator(**args):
|
|
||||||
return Element(qname = (TEXTNS,'creator'), **args)
|
|
||||||
|
|
||||||
def DatabaseDisplay(**args):
|
|
||||||
return Element(qname = (TEXTNS,'database-display'), **args)
|
|
||||||
|
|
||||||
def DatabaseName(**args):
|
|
||||||
return Element(qname = (TEXTNS,'database-name'), **args)
|
|
||||||
|
|
||||||
def DatabaseNext(**args):
|
|
||||||
return Element(qname = (TEXTNS,'database-next'), **args)
|
|
||||||
|
|
||||||
def DatabaseRowNumber(**args):
|
|
||||||
return Element(qname = (TEXTNS,'database-row-number'), **args)
|
|
||||||
|
|
||||||
def DatabaseRowSelect(**args):
|
|
||||||
return Element(qname = (TEXTNS,'database-row-select'), **args)
|
|
||||||
|
|
||||||
def Date(**args):
|
|
||||||
return Element(qname = (TEXTNS,'date'), **args)
|
|
||||||
|
|
||||||
def DdeConnection(**args):
|
|
||||||
return Element(qname = (TEXTNS,'dde-connection'), **args)
|
|
||||||
|
|
||||||
def DdeConnectionDecl(**args):
|
|
||||||
return Element(qname = (TEXTNS,'dde-connection-decl'), **args)
|
|
||||||
|
|
||||||
def DdeConnectionDecls(**args):
|
|
||||||
return Element(qname = (TEXTNS,'dde-connection-decls'), **args)
|
|
||||||
|
|
||||||
def Deletion(**args):
|
|
||||||
return Element(qname = (TEXTNS,'deletion'), **args)
|
|
||||||
|
|
||||||
def Description(**args):
|
|
||||||
return Element(qname = (TEXTNS,'description'), **args)
|
|
||||||
|
|
||||||
def EditingCycles(**args):
|
|
||||||
return Element(qname = (TEXTNS,'editing-cycles'), **args)
|
|
||||||
|
|
||||||
def EditingDuration(**args):
|
|
||||||
return Element(qname = (TEXTNS,'editing-duration'), **args)
|
|
||||||
|
|
||||||
def ExecuteMacro(**args):
|
|
||||||
return Element(qname = (TEXTNS,'execute-macro'), **args)
|
|
||||||
|
|
||||||
def Expression(**args):
|
|
||||||
return Element(qname = (TEXTNS,'expression'), **args)
|
|
||||||
|
|
||||||
def FileName(**args):
|
|
||||||
return Element(qname = (TEXTNS,'file-name'), **args)
|
|
||||||
|
|
||||||
def FormatChange(**args):
|
|
||||||
return Element(qname = (TEXTNS,'format-change'), **args)
|
|
||||||
|
|
||||||
def H(**args):
|
|
||||||
return Element(qname = (TEXTNS, 'h'), **args)
|
|
||||||
|
|
||||||
def HiddenParagraph(**args):
|
|
||||||
return Element(qname = (TEXTNS,'hidden-paragraph'), **args)
|
|
||||||
|
|
||||||
def HiddenText(**args):
|
|
||||||
return Element(qname = (TEXTNS,'hidden-text'), **args)
|
|
||||||
|
|
||||||
def IllustrationIndex(**args):
|
|
||||||
return Element(qname = (TEXTNS,'illustration-index'), **args)
|
|
||||||
|
|
||||||
def IllustrationIndexEntryTemplate(**args):
|
|
||||||
return Element(qname = (TEXTNS,'illustration-index-entry-template'), **args)
|
|
||||||
|
|
||||||
def IllustrationIndexSource(**args):
|
|
||||||
return Element(qname = (TEXTNS,'illustration-index-source'), **args)
|
|
||||||
|
|
||||||
def ImageCount(**args):
|
|
||||||
return Element(qname = (TEXTNS,'image-count'), **args)
|
|
||||||
|
|
||||||
def IndexBody(**args):
|
|
||||||
return Element(qname = (TEXTNS,'index-body'), **args)
|
|
||||||
|
|
||||||
def IndexEntryBibliography(**args):
|
|
||||||
return Element(qname = (TEXTNS,'index-entry-bibliography'), **args)
|
|
||||||
|
|
||||||
def IndexEntryChapter(**args):
|
|
||||||
return Element(qname = (TEXTNS,'index-entry-chapter'), **args)
|
|
||||||
|
|
||||||
def IndexEntryLinkEnd(**args):
|
|
||||||
return Element(qname = (TEXTNS,'index-entry-link-end'), **args)
|
|
||||||
|
|
||||||
def IndexEntryLinkStart(**args):
|
|
||||||
return Element(qname = (TEXTNS,'index-entry-link-start'), **args)
|
|
||||||
|
|
||||||
def IndexEntryPageNumber(**args):
|
|
||||||
return Element(qname = (TEXTNS,'index-entry-page-number'), **args)
|
|
||||||
|
|
||||||
def IndexEntrySpan(**args):
|
|
||||||
return Element(qname = (TEXTNS,'index-entry-span'), **args)
|
|
||||||
|
|
||||||
def IndexEntryTabStop(**args):
|
|
||||||
return Element(qname = (TEXTNS,'index-entry-tab-stop'), **args)
|
|
||||||
|
|
||||||
def IndexEntryText(**args):
|
|
||||||
return Element(qname = (TEXTNS,'index-entry-text'), **args)
|
|
||||||
|
|
||||||
def IndexSourceStyle(**args):
|
|
||||||
return Element(qname = (TEXTNS,'index-source-style'), **args)
|
|
||||||
|
|
||||||
def IndexSourceStyles(**args):
|
|
||||||
return Element(qname = (TEXTNS,'index-source-styles'), **args)
|
|
||||||
|
|
||||||
def IndexTitle(**args):
|
|
||||||
return Element(qname = (TEXTNS,'index-title'), **args)
|
|
||||||
|
|
||||||
def IndexTitleTemplate(**args):
|
|
||||||
return Element(qname = (TEXTNS,'index-title-template'), **args)
|
|
||||||
|
|
||||||
def InitialCreator(**args):
|
|
||||||
return Element(qname = (TEXTNS,'initial-creator'), **args)
|
|
||||||
|
|
||||||
def Insertion(**args):
|
|
||||||
return Element(qname = (TEXTNS,'insertion'), **args)
|
|
||||||
|
|
||||||
def Keywords(**args):
|
|
||||||
return Element(qname = (TEXTNS,'keywords'), **args)
|
|
||||||
|
|
||||||
def LineBreak(**args):
|
|
||||||
return Element(qname = (TEXTNS,'line-break'), **args)
|
|
||||||
|
|
||||||
def LinenumberingConfiguration(**args):
|
|
||||||
return Element(qname = (TEXTNS,'linenumbering-configuration'), **args)
|
|
||||||
|
|
||||||
def LinenumberingSeparator(**args):
|
|
||||||
return Element(qname = (TEXTNS,'linenumbering-separator'), **args)
|
|
||||||
|
|
||||||
def List(**args):
|
|
||||||
return Element(qname = (TEXTNS,'list'), **args)
|
|
||||||
|
|
||||||
def ListHeader(**args):
|
|
||||||
return Element(qname = (TEXTNS,'list-header'), **args)
|
|
||||||
|
|
||||||
def ListItem(**args):
|
|
||||||
return Element(qname = (TEXTNS,'list-item'), **args)
|
|
||||||
|
|
||||||
def ListLevelStyleBullet(**args):
|
|
||||||
return Element(qname = (TEXTNS,'list-level-style-bullet'), **args)
|
|
||||||
|
|
||||||
def ListLevelStyleImage(**args):
|
|
||||||
return Element(qname = (TEXTNS,'list-level-style-image'), **args)
|
|
||||||
|
|
||||||
def ListLevelStyleNumber(**args):
|
|
||||||
return Element(qname = (TEXTNS,'list-level-style-number'), **args)
|
|
||||||
|
|
||||||
def ListStyle(**args):
|
|
||||||
return StyleElement(qname = (TEXTNS,'list-style'), **args)
|
|
||||||
|
|
||||||
def Measure(**args):
|
|
||||||
return Element(qname = (TEXTNS,'measure'), **args)
|
|
||||||
|
|
||||||
def Meta(**args):
|
|
||||||
return Element(qname = (TEXTNS,'meta'), **args)
|
|
||||||
|
|
||||||
def MetaField(**args):
|
|
||||||
return Element(qname = (TEXTNS,'meta-field'), **args)
|
|
||||||
|
|
||||||
def ModificationDate(**args):
|
|
||||||
return Element(qname = (TEXTNS,'modification-date'), **args)
|
|
||||||
|
|
||||||
def ModificationTime(**args):
|
|
||||||
return Element(qname = (TEXTNS,'modification-time'), **args)
|
|
||||||
|
|
||||||
def Note(**args):
|
|
||||||
return Element(qname = (TEXTNS,'note'), **args)
|
|
||||||
|
|
||||||
def NoteBody(**args):
|
|
||||||
return Element(qname = (TEXTNS,'note-body'), **args)
|
|
||||||
|
|
||||||
def NoteCitation(**args):
|
|
||||||
return Element(qname = (TEXTNS,'note-citation'), **args)
|
|
||||||
|
|
||||||
def NoteContinuationNoticeBackward(**args):
|
|
||||||
return Element(qname = (TEXTNS,'note-continuation-notice-backward'), **args)
|
|
||||||
|
|
||||||
def NoteContinuationNoticeForward(**args):
|
|
||||||
return Element(qname = (TEXTNS,'note-continuation-notice-forward'), **args)
|
|
||||||
|
|
||||||
def NoteRef(**args):
|
|
||||||
return Element(qname = (TEXTNS,'note-ref'), **args)
|
|
||||||
|
|
||||||
def NotesConfiguration(**args):
|
|
||||||
return Element(qname = (TEXTNS,'notes-configuration'), **args)
|
|
||||||
|
|
||||||
def Number(**args):
|
|
||||||
return Element(qname = (TEXTNS,'number'), **args)
|
|
||||||
|
|
||||||
def NumberedParagraph(**args):
|
|
||||||
return Element(qname = (TEXTNS,'numbered-paragraph'), **args)
|
|
||||||
|
|
||||||
def ObjectCount(**args):
|
|
||||||
return Element(qname = (TEXTNS,'object-count'), **args)
|
|
||||||
|
|
||||||
def ObjectIndex(**args):
|
|
||||||
return Element(qname = (TEXTNS,'object-index'), **args)
|
|
||||||
|
|
||||||
def ObjectIndexEntryTemplate(**args):
|
|
||||||
return Element(qname = (TEXTNS,'object-index-entry-template'), **args)
|
|
||||||
|
|
||||||
def ObjectIndexSource(**args):
|
|
||||||
return Element(qname = (TEXTNS,'object-index-source'), **args)
|
|
||||||
|
|
||||||
def OutlineLevelStyle(**args):
|
|
||||||
return Element(qname = (TEXTNS,'outline-level-style'), **args)
|
|
||||||
|
|
||||||
def OutlineStyle(**args):
|
|
||||||
return Element(qname = (TEXTNS,'outline-style'), **args)
|
|
||||||
|
|
||||||
def P(**args):
|
|
||||||
return Element(qname = (TEXTNS, 'p'), **args)
|
|
||||||
|
|
||||||
def Page(**args):
|
|
||||||
return Element(qname = (TEXTNS,'page'), **args)
|
|
||||||
|
|
||||||
def PageContinuation(**args):
|
|
||||||
return Element(qname = (TEXTNS,'page-continuation'), **args)
|
|
||||||
|
|
||||||
def PageCount(**args):
|
|
||||||
return Element(qname = (TEXTNS,'page-count'), **args)
|
|
||||||
|
|
||||||
def PageNumber(**args):
|
|
||||||
return Element(qname = (TEXTNS,'page-number'), **args)
|
|
||||||
|
|
||||||
def PageSequence(**args):
|
|
||||||
return Element(qname = (TEXTNS,'page-sequence'), **args)
|
|
||||||
|
|
||||||
def PageVariableGet(**args):
|
|
||||||
return Element(qname = (TEXTNS,'page-variable-get'), **args)
|
|
||||||
|
|
||||||
def PageVariableSet(**args):
|
|
||||||
return Element(qname = (TEXTNS,'page-variable-set'), **args)
|
|
||||||
|
|
||||||
def ParagraphCount(**args):
|
|
||||||
return Element(qname = (TEXTNS,'paragraph-count'), **args)
|
|
||||||
|
|
||||||
def Placeholder(**args):
|
|
||||||
return Element(qname = (TEXTNS,'placeholder'), **args)
|
|
||||||
|
|
||||||
def PrintDate(**args):
|
|
||||||
return Element(qname = (TEXTNS,'print-date'), **args)
|
|
||||||
|
|
||||||
def PrintTime(**args):
|
|
||||||
return Element(qname = (TEXTNS,'print-time'), **args)
|
|
||||||
|
|
||||||
def PrintedBy(**args):
|
|
||||||
return Element(qname = (TEXTNS,'printed-by'), **args)
|
|
||||||
|
|
||||||
def ReferenceMark(**args):
|
|
||||||
return Element(qname = (TEXTNS,'reference-mark'), **args)
|
|
||||||
|
|
||||||
def ReferenceMarkEnd(**args):
|
|
||||||
return Element(qname = (TEXTNS,'reference-mark-end'), **args)
|
|
||||||
|
|
||||||
def ReferenceMarkStart(**args):
|
|
||||||
return Element(qname = (TEXTNS,'reference-mark-start'), **args)
|
|
||||||
|
|
||||||
def ReferenceRef(**args):
|
|
||||||
return Element(qname = (TEXTNS,'reference-ref'), **args)
|
|
||||||
|
|
||||||
def Ruby(**args):
|
|
||||||
return Element(qname = (TEXTNS,'ruby'), **args)
|
|
||||||
|
|
||||||
def RubyBase(**args):
|
|
||||||
return Element(qname = (TEXTNS,'ruby-base'), **args)
|
|
||||||
|
|
||||||
def RubyText(**args):
|
|
||||||
return Element(qname = (TEXTNS,'ruby-text'), **args)
|
|
||||||
|
|
||||||
def S(**args):
|
|
||||||
return Element(qname = (TEXTNS,'s'), **args)
|
|
||||||
|
|
||||||
def Script(**args):
|
|
||||||
return Element(qname = (TEXTNS,'script'), **args)
|
|
||||||
|
|
||||||
def Section(**args):
|
|
||||||
return Element(qname = (TEXTNS,'section'), **args)
|
|
||||||
|
|
||||||
def SectionSource(**args):
|
|
||||||
return Element(qname = (TEXTNS,'section-source'), **args)
|
|
||||||
|
|
||||||
def SenderCity(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-city'), **args)
|
|
||||||
|
|
||||||
def SenderCompany(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-company'), **args)
|
|
||||||
|
|
||||||
def SenderCountry(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-country'), **args)
|
|
||||||
|
|
||||||
def SenderEmail(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-email'), **args)
|
|
||||||
|
|
||||||
def SenderFax(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-fax'), **args)
|
|
||||||
|
|
||||||
def SenderFirstname(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-firstname'), **args)
|
|
||||||
|
|
||||||
def SenderInitials(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-initials'), **args)
|
|
||||||
|
|
||||||
def SenderLastname(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-lastname'), **args)
|
|
||||||
|
|
||||||
def SenderPhonePrivate(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-phone-private'), **args)
|
|
||||||
|
|
||||||
def SenderPhoneWork(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-phone-work'), **args)
|
|
||||||
|
|
||||||
def SenderPosition(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-position'), **args)
|
|
||||||
|
|
||||||
def SenderPostalCode(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-postal-code'), **args)
|
|
||||||
|
|
||||||
def SenderStateOrProvince(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-state-or-province'), **args)
|
|
||||||
|
|
||||||
def SenderStreet(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-street'), **args)
|
|
||||||
|
|
||||||
def SenderTitle(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sender-title'), **args)
|
|
||||||
|
|
||||||
def Sequence(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sequence'), **args)
|
|
||||||
|
|
||||||
def SequenceDecl(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sequence-decl'), **args)
|
|
||||||
|
|
||||||
def SequenceDecls(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sequence-decls'), **args)
|
|
||||||
|
|
||||||
def SequenceRef(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sequence-ref'), **args)
|
|
||||||
|
|
||||||
def SheetName(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sheet-name'), **args)
|
|
||||||
|
|
||||||
def SoftPageBreak(**args):
|
|
||||||
return Element(qname = (TEXTNS,'soft-page-break'), **args)
|
|
||||||
|
|
||||||
def SortKey(**args):
|
|
||||||
return Element(qname = (TEXTNS,'sort-key'), **args)
|
|
||||||
|
|
||||||
def Span(**args):
|
|
||||||
return Element(qname = (TEXTNS,'span'), **args)
|
|
||||||
|
|
||||||
def Subject(**args):
|
|
||||||
return Element(qname = (TEXTNS,'subject'), **args)
|
|
||||||
|
|
||||||
def Tab(**args):
|
|
||||||
return Element(qname = (TEXTNS,'tab'), **args)
|
|
||||||
|
|
||||||
def TableCount(**args):
|
|
||||||
return Element(qname = (TEXTNS,'table-count'), **args)
|
|
||||||
|
|
||||||
def TableFormula(**args):
|
|
||||||
return Element(qname = (TEXTNS,'table-formula'), **args)
|
|
||||||
|
|
||||||
def TableIndex(**args):
|
|
||||||
return Element(qname = (TEXTNS,'table-index'), **args)
|
|
||||||
|
|
||||||
def TableIndexEntryTemplate(**args):
|
|
||||||
return Element(qname = (TEXTNS,'table-index-entry-template'), **args)
|
|
||||||
|
|
||||||
def TableIndexSource(**args):
|
|
||||||
return Element(qname = (TEXTNS,'table-index-source'), **args)
|
|
||||||
|
|
||||||
def TableOfContent(**args):
|
|
||||||
return Element(qname = (TEXTNS,'table-of-content'), **args)
|
|
||||||
|
|
||||||
def TableOfContentEntryTemplate(**args):
|
|
||||||
return Element(qname = (TEXTNS,'table-of-content-entry-template'), **args)
|
|
||||||
|
|
||||||
def TableOfContentSource(**args):
|
|
||||||
return Element(qname = (TEXTNS,'table-of-content-source'), **args)
|
|
||||||
|
|
||||||
def TemplateName(**args):
|
|
||||||
return Element(qname = (TEXTNS,'template-name'), **args)
|
|
||||||
|
|
||||||
def TextInput(**args):
|
|
||||||
return Element(qname = (TEXTNS,'text-input'), **args)
|
|
||||||
|
|
||||||
def Time(**args):
|
|
||||||
return Element(qname = (TEXTNS,'time'), **args)
|
|
||||||
|
|
||||||
def Title(**args):
|
|
||||||
return Element(qname = (TEXTNS,'title'), **args)
|
|
||||||
|
|
||||||
def TocMark(**args):
|
|
||||||
return Element(qname = (TEXTNS,'toc-mark'), **args)
|
|
||||||
|
|
||||||
def TocMarkEnd(**args):
|
|
||||||
return Element(qname = (TEXTNS,'toc-mark-end'), **args)
|
|
||||||
|
|
||||||
def TocMarkStart(**args):
|
|
||||||
return Element(qname = (TEXTNS,'toc-mark-start'), **args)
|
|
||||||
|
|
||||||
def TrackedChanges(**args):
|
|
||||||
return Element(qname = (TEXTNS,'tracked-changes'), **args)
|
|
||||||
|
|
||||||
def UserDefined(**args):
|
|
||||||
return Element(qname = (TEXTNS,'user-defined'), **args)
|
|
||||||
|
|
||||||
def UserFieldDecl(**args):
|
|
||||||
return Element(qname = (TEXTNS,'user-field-decl'), **args)
|
|
||||||
|
|
||||||
def UserFieldDecls(**args):
|
|
||||||
return Element(qname = (TEXTNS,'user-field-decls'), **args)
|
|
||||||
|
|
||||||
def UserFieldGet(**args):
|
|
||||||
return Element(qname = (TEXTNS,'user-field-get'), **args)
|
|
||||||
|
|
||||||
def UserFieldInput(**args):
|
|
||||||
return Element(qname = (TEXTNS,'user-field-input'), **args)
|
|
||||||
|
|
||||||
def UserIndex(**args):
|
|
||||||
return Element(qname = (TEXTNS,'user-index'), **args)
|
|
||||||
|
|
||||||
def UserIndexEntryTemplate(**args):
|
|
||||||
return Element(qname = (TEXTNS,'user-index-entry-template'), **args)
|
|
||||||
|
|
||||||
def UserIndexMark(**args):
|
|
||||||
return Element(qname = (TEXTNS,'user-index-mark'), **args)
|
|
||||||
|
|
||||||
def UserIndexMarkEnd(**args):
|
|
||||||
return Element(qname = (TEXTNS,'user-index-mark-end'), **args)
|
|
||||||
|
|
||||||
def UserIndexMarkStart(**args):
|
|
||||||
return Element(qname = (TEXTNS,'user-index-mark-start'), **args)
|
|
||||||
|
|
||||||
def UserIndexSource(**args):
|
|
||||||
return Element(qname = (TEXTNS,'user-index-source'), **args)
|
|
||||||
|
|
||||||
def VariableDecl(**args):
|
|
||||||
return Element(qname = (TEXTNS,'variable-decl'), **args)
|
|
||||||
|
|
||||||
def VariableDecls(**args):
|
|
||||||
return Element(qname = (TEXTNS,'variable-decls'), **args)
|
|
||||||
|
|
||||||
def VariableGet(**args):
|
|
||||||
return Element(qname = (TEXTNS,'variable-get'), **args)
|
|
||||||
|
|
||||||
def VariableInput(**args):
|
|
||||||
return Element(qname = (TEXTNS,'variable-input'), **args)
|
|
||||||
|
|
||||||
def VariableSet(**args):
|
|
||||||
return Element(qname = (TEXTNS,'variable-set'), **args)
|
|
||||||
|
|
||||||
def WordCount(**args):
|
|
||||||
return Element(qname = (TEXTNS,'word-count'), **args)
|
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# This contains a 104x128 px thumbnail in PNG format
|
|
||||||
# Downloaded from http://da.libreoffice.org/assets/Uploads/Da-Projekt_Billeder/IconLibreOffice.png
|
|
||||||
# Copyright information: Unless otherwise specified, all text and images on the
|
|
||||||
# http://da.libreoffice.org website are licensed under the Creative Commons
|
|
||||||
# Attribution-Share Alike 3.0 License. (As of 2013-01-09)
|
|
||||||
|
|
||||||
# Alternative download: http://commons.wikimedia.org/wiki/File:LibreOffice_icon_3.3.1_48_px.svg
|
|
||||||
import base64
|
|
||||||
|
|
||||||
iconstr = """\
|
|
||||||
iVBORw0KGgoAAAANSUhEUgAAAGgAAACACAYAAADnCyxOAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz
|
|
||||||
AAAG7AAABuwBHnU4NQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAwBSURB
|
|
||||||
VHic7Z1bbFTHHca/2UsxYDs4IRiv7Y0xUNRUCCmAFBXiCwaiRhFIxjdsjG18g8YvlfoQqepDH/yA
|
|
||||||
hKI+EUIIKqVxwiVAuapUlh+qqi+8VH2hfUgDUpuHVnhjs17vnsv0oZ3lnNkzs2fXu2eX3flJR7ue
|
|
||||||
nbN7znz7/ec/M+esCaUUk5OTtQDOAOgAUAdnqKBc9lqm5bl8Lwrg7wD+BODWJ5988lDymY6cPHmy
|
|
||||||
F8AIpfRHAL6X6f5ZQAE8JYQ80DTtF5999tkiGR8fXw/gLwBCHhxAITkD4MPz588bbipPTEx8H8Bf
|
|
||||||
4Y0wKRBC/qbr+m4fgGmUvjgA8DMADyYmJta4qUwI6UCBxAEASuk2v9//Sx+Adwt1EAXgAIC7bkSi
|
|
||||||
lM5TSlHg7VCAUvqG9cCmp6dBqayLeLmYm5vD7OystagdwN3x8fH3P/300yXRfpWVlb9bWFh4Qgh5
|
|
||||||
Q1THAzb7+BJKKUzTLJmtra0N+/bt40+TiSR00kcffRQzTXPCNE0tx42eET7eVgxN0xCNRrG0tISl
|
|
||||||
pSXEYjHEYjEsLy9jeXkZ8Xgc8XgciUQCiUQCmqbZNl3Xoes6DMOAYRjJBuM/J99QStHe3o729nY+
|
|
||||||
fLRTSu+OjY0JRbp48eJD0zR7NU3TChXmyOjoqK21pqenYZomotEompqa8t6A+cAwDEQiEZimmSwj
|
|
||||||
hGB2dhZzc3N89TkA71+4cEEY7oaGhjoBfBkMBoN5OWAJthDHf7MJIS/lFggEUFNTA5/PZzu3jo4O
|
|
||||||
tLW18W3QDkDqpEuXLt0wTbM/Ho977qSUEOcU7l5G/H4/ampqQAhJno9pmujo6EBLS4tjuBsdHRWK
|
|
||||||
dPny5euGYRyLx+Oe9kkpDioVgYAXIvFOOnDgAFpbW/nq7QCkIs3MzFyllB6PxWJ6fo44FWGSUCqw
|
|
||||||
cMc7af/+/di7d6+Tk+6dOHFCKNLnn3/+pWEYQ9FoVPckxPEHUIpiBQIBvPrqqykiHTx4EHv27OHP
|
|
||||||
tQ2AVKQrV67MGIYxEo1G8+6kkg5xVmQivf322xmLdO3atd/quj76/PlzV3N72SJMEkqRYDCI1157
|
|
||||||
DYQQW/l7772HXbt22cZplNI2Sum9kZERoUhfffXVbzRNG1tYWDA8C3GMUhZp/fr1AOwR49ChQ9i5
|
|
||||||
c6dt7IT/O0km0s2bN39tGMbEwsJCXpxkc1AhRvqFgDmJP/fDhw9jx44dMAwjxUnDw8MykS4ahnEy
|
|
||||||
Eonk3EllkSQ4sWrVKrz++uu286SUoqurC9u3b3d0kkykW7duXdB1/Sfz8/OmqE42CGcS+DhdijCR
|
|
||||||
rI4xTRM9PT148803YRi2qNUG4P7w8PBa0fvduXPnPKX0g2fPnuVMJGGSwH2DSpaKigps2LAhRaTe
|
|
||||||
3l5s27YNuq5b26WVUnpvaGhIKNLt27fPUUqnnj17ZuY8xDEHWR/LYauoqEBtbS3f96C/vx9bt27l
|
|
||||||
ndQKQCrSnTt3PqaUTkUikRV/y8veQQyrSFYGBwfR3NwMTdNSnHT8+PF0In3w3XffrchJwjS7HPog
|
|
||||||
ntWrV2Pjxo28GBgaGsKmTZug67aJg1YAUpFu3759zjTNqcXFxay/7cKZhHJzEGP16tWoq6tDIpGw
|
|
||||||
tcfIyAjC4XA2In0MYOr58+dZNWhZzSS4Zc2aNQiFQkgkErbysbGxZDkf7gYHB4Ui3bx5MylSTpIE
|
|
||||||
BbB27VqEQiHE43Fbg01OTqKurg6aZlsWagUgFenGjRsfA/ggFotl1MgqSZBQWVmJUCiE5eVlW9uc
|
|
||||||
OnUKtbW1Tk66f+zYMZlI50zTnIrFYjTrJEGFOTtVVVWor69HLBZLESkUCvFOagGQTqSzAKbi8bir
|
|
||||||
BhYmCYoXVFdXo7GxEbFYLFlGCMHk5CTq6+v5xCGtSNevXz8LYCqRSKRt6JJfUc0V1dXVCIfDNicB
|
|
||||||
wPj4OOrr6/nUvIVSen9gYEAo0rVr185SSqcSiYQ03EkX7NRm36qqqtDY2Gjrk4D/ZXcNDQ2OTkon
|
|
||||||
EoApXddFzoiU7FU9+YKFu3g8bisfGxtDY2MjP3fXQim939/fLxTp6tWrZymlU4ZhODnpYdkt2OUC
|
|
||||||
Fu747O7EiRMIh8P8dFELADciHTJN84ml+F8AfqWyuCypqqpCOBxOGScNDw+jqamJH6akFenKlSt3
|
|
||||||
5+fnf0gp3U8pfd/n8/1gZmbmz6Svry+pRDQaxenTp2EYBqLRKN566608nmJpsLi4iCdPnoC/Kvjy
|
|
||||||
5cv45ptvbNfkAfgjgB9/8cUXUbfvrxy0QpiTuAQBg4OD2LRpE++kdwA8OHr0qNBJPMI+SOEeljjw
|
|
||||||
s+ADAwNobm7mv+xMpEo37y28aEQ5KDNY4sBlcTh69Ciam5v5tn2HUnq/r68vrUiODlICZQcTiZ/H
|
|
||||||
7Ovrw5YtW5yclFYk4UyCEig7qqur0dDQkBKNuru7kyLxTurt7RWKVDaX/nrJK6+8gsbGxpTrDLu6
|
|
||||||
urB161a++jsAhCIJszj+G6C2zGZcWLizvk4IwZEjR0QiPXASSU315ABR+7G5O75Njxw54hTu9lJK
|
|
||||||
H/T09NhEEq6oKoFyA0vBAbuQnZ2d2LJlC199LwCbSMpBHuAkEgB0dnYmx0m8k7q7uysBNZPgGUwk
|
|
||||||
6+VshBB0dXVh8+bNfPW9AM4Bae7yVuQWlt0BSOmTmpub+eoD3d3dPSrEeYxMpKamJl6DU9I0W5Ef
|
|
||||||
1q1bh3A4nBLuuru7+apNAT5zUw7yhnXr1oFSiqdPn8I0zeQPcHDt3qDS7AJSU1PjOE6yEAjwJcpF
|
|
||||||
3lJTU4Ovv/4aPp8v2ebW0KdCXJHBt7tKs4sAmTGEDlJZnHewJMFJJDWTUATIkjO1HlQEyH6fIiXE
|
|
||||||
OT1X5Be+a7FeqiW8JkHhHVb3ZJQklLJQxXSTtJMGjICoYqlTTOcq6/vVZGkRkFGSoLI477G2Nd+1
|
|
||||||
qHFQESBr84ASovDIkjPloCJA1gcJBVJ4h2yCQIW4IkB2PYhwwY49V+SfrJYblDjeYU0MpMsN1jUJ
|
|
||||||
hXeIxAHULZBFQUbjIOUg71HjoCJH1tYqzS4CnG6WY6iBahEgTbPT7aBYOZksDqadSVDC5J507el6
|
|
||||||
HKQoDK7TbDWTUBhcp9miqxsV+UXW1upfAxQBst9IEiYJykHekdVygxLJO1wv2ClhCoermQTV7xQG
|
|
||||||
mTHUVE+RwNqdN4kaBxUZrkOcCnfeYTWFclCRIrpYR6XZecZNJJLVsQmkpnpyj5t2zCjE8Tuqvii/
|
|
||||||
8MsMGa+oKiflDydxpA6y7mjdQTkp91jFsbat6wU7/iJG5aTcIQtrvBGkl13xOyuRVo6TONa/eaTL
|
|
||||||
Dfw9+yrcrQwncZzuBXY1DgKQ/E9ShBDbpkTKHFFYY23sykF8Bd5BDCVSZojEYQ6SdSVpB6qifkeJ
|
|
||||||
5A6ZOE7TbDzSJIHFR5U4ZIcbcfg+yPVMAiEkaT/mFieUk5xxI47MBAzpZKn1g5RI7nErjlO9tDMJ
|
|
||||||
TvZTIrknU3H4EJeRg6yqKpHSk61zrM9THCT7QOtlqEokOdmKw/dBPGlnEtgPnvKDVP55OQ9mV9Ln
|
|
||||||
ZDQO4ne2jnIZykl2ViIOAP7/fqcgDHGsgdlsghIplZWK43RfUEYXjRiGoUQSkCtx+Lk4aRbHrwGx
|
|
||||||
Psjn8ymRLORKHNa+MqQO0nU96SImDnu0JgRs30wTh5dRsFyLw9rXdZJgxTAMm8IiJwF2l7h1kqhe
|
|
||||||
seJWHKc6QKo4pmlC13VbfZ60d3nzFsy1SC8L+RDHKcXOeKpHiZRfcdg40/pZrkOcNQ0sV5Hy7RzZ
|
|
||||||
7Y9AmhVV1gexVdVyE8kLcZwGqhk5iIlSbiJ5IY51Kk1EyjjICp+nl4tIXoqT0YoqXzEYDCISicDn
|
|
||||||
88Hn88Hv9yefE0Lg9/uTZX6/P1lGCEnWYY/sOYDkexTjJV1ODc83plMfYp0ZYI8shFlnZFgZex4M
|
|
||||||
BlOSBCvSEPf48eO8nby1EZyeW8tkr1nLGOyErQNpUVk2r3uJ9PfiNE3z8FAK1wg8IuG9/GxGioP8
|
|
||||||
fj8qKio8OyDFC/x+f0oZ2b179z8BhLw6CFG4Svfotq4oJGXzWOjwBuDfAUrp7wGMePmpxRLKMqUA
|
|
||||||
IW/WB+BDAN96/cmKtHwL4KeEUopdu3bVAjgD4CCADYU9rrLnHwD+AODnjx49+s9/AexyD6bH7vMJ
|
|
||||||
AAAAAElFTkSuQmCC\
|
|
||||||
"""
|
|
||||||
|
|
||||||
def thumbnail():
|
|
||||||
icon = base64.decodestring(iconstr)
|
|
||||||
return icon
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
icon = thumbnail()
|
|
||||||
f = file("thumbnail.png","wb")
|
|
||||||
f.write(icon)
|
|
||||||
f.close()
|
|
|
@ -1,180 +0,0 @@
|
||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2009 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This is free software. You may redistribute it under the terms
|
|
||||||
# of the Apache license and the GNU General Public License Version
|
|
||||||
# 2 or at your option any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public
|
|
||||||
# License along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s): Michael Howitz, gocept gmbh & co. kg
|
|
||||||
#
|
|
||||||
# $Id: userfield.py 447 2008-07-10 20:01:30Z roug $
|
|
||||||
|
|
||||||
"""Class to show and manipulate user fields in odf documents."""
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import zipfile
|
|
||||||
|
|
||||||
from odf.text import UserFieldDecl
|
|
||||||
from odf.namespaces import OFFICENS
|
|
||||||
from odf.opendocument import load
|
|
||||||
import io, sys
|
|
||||||
|
|
||||||
if sys.version_info[0]==3:
|
|
||||||
unicode=str
|
|
||||||
|
|
||||||
OUTENCODING = "utf-8"
|
|
||||||
|
|
||||||
|
|
||||||
# OpenDocument v.1.0 section 6.7.1
|
|
||||||
VALUE_TYPES = {
|
|
||||||
u'float': (OFFICENS, u'value'),
|
|
||||||
u'percentage': (OFFICENS, u'value'),
|
|
||||||
u'currency': (OFFICENS, u'value'),
|
|
||||||
u'date': (OFFICENS, u'date-value'),
|
|
||||||
u'time': (OFFICENS, u'time-value'),
|
|
||||||
u'boolean': (OFFICENS, u'boolean-value'),
|
|
||||||
u'string': (OFFICENS, u'string-value'),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class UserFields(object):
|
|
||||||
"""List, view and manipulate user fields."""
|
|
||||||
|
|
||||||
# these attributes can be a filename or a file like object
|
|
||||||
src_file = None
|
|
||||||
dest_file = None
|
|
||||||
|
|
||||||
def __init__(self, src=None, dest=None):
|
|
||||||
"""Constructor
|
|
||||||
|
|
||||||
@param src open file in binary mode: source document,
|
|
||||||
or filename as a unicode string, or None for stdin.
|
|
||||||
@param dest opendile in binary mode: destination document,
|
|
||||||
or filename as a unicode string, or None for stdout.
|
|
||||||
"""
|
|
||||||
assert(src==None or 'rb' in repr(src) or 'BufferedReader' in repr(src) or 'BytesIO' in repr(src) or type(src)==type(u""))
|
|
||||||
assert(dest==None or 'wb' in repr(dest) or 'BufferedWriter' in repr(dest) or 'BytesIO' in repr(dest) or type(dest)==type(u""))
|
|
||||||
self.src_file = src
|
|
||||||
self.dest_file = dest
|
|
||||||
self.document = None
|
|
||||||
|
|
||||||
def loaddoc(self):
|
|
||||||
if (sys.version_info[0]==3 and (isinstance(self.src_file, str) or (isinstance(self.src_file, io.IOBase)))) or (sys.version_info[0]==2 and isinstance(self.src_file, basestring)):
|
|
||||||
# src_file is a filename, check if it is a zip-file
|
|
||||||
if not zipfile.is_zipfile(self.src_file):
|
|
||||||
raise TypeError(u"%s is no odt file." % self.src_file)
|
|
||||||
elif self.src_file is None:
|
|
||||||
# use stdin if no file given
|
|
||||||
self.src_file = sys.stdin
|
|
||||||
|
|
||||||
self.document = load(self.src_file)
|
|
||||||
|
|
||||||
def savedoc(self):
|
|
||||||
# write output
|
|
||||||
if self.dest_file is None:
|
|
||||||
# use stdout if no filename given
|
|
||||||
self.document.save(u'-')
|
|
||||||
else:
|
|
||||||
self.document.save(self.dest_file)
|
|
||||||
|
|
||||||
def list_fields(self):
|
|
||||||
"""List (extract) all known user-fields.
|
|
||||||
|
|
||||||
@return list of user-field names as unicode strings.
|
|
||||||
"""
|
|
||||||
return [x[0] for x in self.list_fields_and_values()]
|
|
||||||
|
|
||||||
def list_fields_and_values(self, field_names=None):
|
|
||||||
"""List (extract) user-fields with type and value.
|
|
||||||
|
|
||||||
@param field_names list of field names as unicode strings
|
|
||||||
to show, or None for all.
|
|
||||||
|
|
||||||
@return list of tuples (<field name>, <field type>, <value>)
|
|
||||||
as type (unicode string, stringified type, unicode string).
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.loaddoc()
|
|
||||||
found_fields = []
|
|
||||||
all_fields = self.document.getElementsByType(UserFieldDecl)
|
|
||||||
for f in all_fields:
|
|
||||||
value_type = f.getAttribute(u'valuetype')
|
|
||||||
if value_type == u'string':
|
|
||||||
value = f.getAttribute(u'stringvalue')
|
|
||||||
else:
|
|
||||||
value = f.getAttribute(u'value')
|
|
||||||
field_name = f.getAttribute(u'name')
|
|
||||||
|
|
||||||
if field_names is None or field_name in field_names:
|
|
||||||
found_fields.append((field_name,
|
|
||||||
value_type,
|
|
||||||
value))
|
|
||||||
return found_fields
|
|
||||||
|
|
||||||
def list_values(self, field_names):
|
|
||||||
"""Extract the contents of given field names from the file.
|
|
||||||
|
|
||||||
@param field_names list of field names as unicode strings
|
|
||||||
|
|
||||||
@return list of field values as unicode strings.
|
|
||||||
|
|
||||||
"""
|
|
||||||
return [x[2] for x in self.list_fields_and_values(field_names)]
|
|
||||||
|
|
||||||
def get(self, field_name):
|
|
||||||
"""Extract the contents of this field from the file.
|
|
||||||
@param field_name unicode string: name of a field
|
|
||||||
@return field value as a unicode string or None if field does not exist.
|
|
||||||
|
|
||||||
"""
|
|
||||||
assert(type(field_name)==type(u""))
|
|
||||||
values = self.list_values([field_name])
|
|
||||||
if not values:
|
|
||||||
return None
|
|
||||||
return values[0]
|
|
||||||
|
|
||||||
def get_type_and_value(self, field_name):
|
|
||||||
"""Extract the type and contents of this field from the file.
|
|
||||||
@param field_name unicode string: name of a field
|
|
||||||
@return tuple (<type>, <field-value>) as a pair of unicode strings
|
|
||||||
or None if field does not exist.
|
|
||||||
|
|
||||||
"""
|
|
||||||
assert(type(field_name)==type(u""))
|
|
||||||
fields = self.list_fields_and_values([field_name])
|
|
||||||
if not fields:
|
|
||||||
return None
|
|
||||||
field_name, value_type, value = fields[0]
|
|
||||||
return value_type, value
|
|
||||||
|
|
||||||
def update(self, data):
|
|
||||||
"""Set the value of user fields. The field types will be the same.
|
|
||||||
|
|
||||||
data ... dict, with field name as key, field value as value
|
|
||||||
|
|
||||||
Returns None
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.loaddoc()
|
|
||||||
all_fields = self.document.getElementsByType(UserFieldDecl)
|
|
||||||
for f in all_fields:
|
|
||||||
field_name = f.getAttribute(u'name')
|
|
||||||
if field_name in data:
|
|
||||||
value_type = f.getAttribute(u'valuetype')
|
|
||||||
value = data.get(field_name)
|
|
||||||
if value_type == u'string':
|
|
||||||
f.setAttribute(u'stringvalue', value)
|
|
||||||
else:
|
|
||||||
f.setAttribute(u'value', value)
|
|
||||||
self.savedoc()
|
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
|
||||||
#
|
|
||||||
# This library is free software; you can redistribute it and/or
|
|
||||||
# modify it under the terms of the GNU Lesser General Public
|
|
||||||
# License as published by the Free Software Foundation; either
|
|
||||||
# version 2.1 of the License, or (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This library 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
|
|
||||||
# Lesser General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU Lesser General Public
|
|
||||||
# License along with this library; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
#
|
|
||||||
# Contributor(s):
|
|
||||||
#
|
|
||||||
|
|
||||||
from namespaces import XFORMSNS
|
|
||||||
from element import Element
|
|
||||||
|
|
||||||
# ODF 1.0 section 11.2
|
|
||||||
# XForms is designed to be embedded in another XML format.
|
|
||||||
# Autogenerated
|
|
||||||
def Model(**args):
|
|
||||||
return Element(qname = (XFORMSNS,'model'), **args)
|
|
||||||
|
|
||||||
def Instance(**args):
|
|
||||||
return Element(qname = (XFORMSNS,'instance'), **args)
|
|
||||||
|
|
||||||
def Bind(**args):
|
|
||||||
return Element(qname = (XFORMSNS,'bind'), **args)
|
|
5987
libs/txt2tags
5987
libs/txt2tags
File diff suppressed because it is too large
Load diff
|
@ -2,14 +2,9 @@
|
||||||
#--!-- coding: utf8 --!--
|
#--!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
|
||||||
# As seen on http://stackoverflow.com/questions/36932/how-can-i-represent-an-enum-in-python
|
from enum import IntEnum
|
||||||
|
|
||||||
from enum import Enum
|
class Character(IntEnum):
|
||||||
|
|
||||||
#def enum(**enums):
|
|
||||||
#return type(str('Enum'), (), enums)
|
|
||||||
|
|
||||||
class Character(Enum):
|
|
||||||
name = 0
|
name = 0
|
||||||
ID = 1
|
ID = 1
|
||||||
importance = 2
|
importance = 2
|
||||||
|
@ -22,7 +17,7 @@ class Character(Enum):
|
||||||
summaryFull = 9
|
summaryFull = 9
|
||||||
notes = 10
|
notes = 10
|
||||||
|
|
||||||
class Plot(Enum):
|
class Plot(IntEnum):
|
||||||
name = 0
|
name = 0
|
||||||
ID = 1
|
ID = 1
|
||||||
importance = 2
|
importance = 2
|
||||||
|
@ -32,20 +27,20 @@ class Plot(Enum):
|
||||||
steps = 6
|
steps = 6
|
||||||
summary = 7
|
summary = 7
|
||||||
|
|
||||||
class PlotStep(Enum):
|
class PlotStep(IntEnum):
|
||||||
name = 0
|
name = 0
|
||||||
ID = 1
|
ID = 1
|
||||||
meta = 2
|
meta = 2
|
||||||
summary = 3
|
summary = 3
|
||||||
|
|
||||||
class World(Enum):
|
class World(IntEnum):
|
||||||
name = 0
|
name = 0
|
||||||
ID = 1
|
ID = 1
|
||||||
description = 2
|
description = 2
|
||||||
passion = 3
|
passion = 3
|
||||||
conflict = 4
|
conflict = 4
|
||||||
|
|
||||||
class Outline(Enum):
|
class Outline(IntEnum):
|
||||||
title = 0
|
title = 0
|
||||||
ID = 1
|
ID = 1
|
||||||
type = 2
|
type = 2
|
||||||
|
@ -65,3 +60,8 @@ class Outline(Enum):
|
||||||
textFormat = 15
|
textFormat = 15
|
||||||
revisions = 16
|
revisions = 16
|
||||||
customIcon = 17
|
customIcon = 17
|
||||||
|
|
||||||
|
class Abstract(IntEnum):
|
||||||
|
title = 0
|
||||||
|
ID = 1
|
||||||
|
type = 2
|
||||||
|
|
|
@ -7,7 +7,7 @@ import subprocess
|
||||||
from PyQt5.QtCore import QSettings
|
from PyQt5.QtCore import QSettings
|
||||||
from PyQt5.QtWidgets import QWidget
|
from PyQt5.QtWidgets import QWidget
|
||||||
|
|
||||||
from manuskript.models.outlineModel import outlineItem
|
from manuskript.models import outlineItem
|
||||||
from manuskript.functions import mainWindow
|
from manuskript.functions import mainWindow
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ from PyQt5.QtWidgets import QPlainTextEdit, qApp, QFrame, QFileDialog
|
||||||
|
|
||||||
from manuskript.exporter.basic import basicFormat
|
from manuskript.exporter.basic import basicFormat
|
||||||
from manuskript.functions import mainWindow
|
from manuskript.functions import mainWindow
|
||||||
from manuskript.models.outlineModel import outlineItem
|
from manuskript.models import outlineItem
|
||||||
from manuskript.ui.exporters.manuskript.plainTextSettings import exporterSettings
|
from manuskript.ui.exporters.manuskript.plainTextSettings import exporterSettings
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -172,7 +172,7 @@ def outlineItemColors(item):
|
||||||
|
|
||||||
# POV
|
# POV
|
||||||
colors["POV"] = QColor(Qt.transparent)
|
colors["POV"] = QColor(Qt.transparent)
|
||||||
POV = item.data(Outline.POV.value)
|
POV = item.data(Outline.POV)
|
||||||
if POV == "":
|
if POV == "":
|
||||||
col = QColor(Qt.transparent)
|
col = QColor(Qt.transparent)
|
||||||
else:
|
else:
|
||||||
|
@ -181,7 +181,7 @@ def outlineItemColors(item):
|
||||||
colors["POV"] = iconColor(mw.mdlCharacter.icon(i))
|
colors["POV"] = iconColor(mw.mdlCharacter.icon(i))
|
||||||
|
|
||||||
# Label
|
# Label
|
||||||
lbl = item.data(Outline.label.value)
|
lbl = item.data(Outline.label)
|
||||||
if lbl == "":
|
if lbl == "":
|
||||||
col = QColor(Qt.transparent)
|
col = QColor(Qt.transparent)
|
||||||
else:
|
else:
|
||||||
|
@ -192,7 +192,7 @@ def outlineItemColors(item):
|
||||||
colors["Label"] = col
|
colors["Label"] = col
|
||||||
|
|
||||||
# Progress
|
# Progress
|
||||||
pg = item.data(Outline.goalPercentage.value)
|
pg = item.data(Outline.goalPercentage)
|
||||||
colors["Progress"] = colorFromProgress(pg)
|
colors["Progress"] = colorFromProgress(pg)
|
||||||
|
|
||||||
# Compile
|
# Compile
|
||||||
|
@ -353,10 +353,27 @@ def customIcons():
|
||||||
|
|
||||||
return sorted(r)
|
return sorted(r)
|
||||||
|
|
||||||
|
|
||||||
def statusMessage(message, duration=5000):
|
def statusMessage(message, duration=5000):
|
||||||
|
"""
|
||||||
|
Shows a message in MainWindow's status bar.
|
||||||
|
"""
|
||||||
mainWindow().statusBar().showMessage(message, duration)
|
mainWindow().statusBar().showMessage(message, duration)
|
||||||
|
|
||||||
|
|
||||||
def openURL(url):
|
def openURL(url):
|
||||||
|
"""
|
||||||
|
Opens url (string) in browser using desktop default application.
|
||||||
|
"""
|
||||||
QDesktopServices.openUrl(QUrl(url))
|
QDesktopServices.openUrl(QUrl(url))
|
||||||
|
|
||||||
|
def inspect():
|
||||||
|
"""
|
||||||
|
Debugging tool. Call it to see a stack of calls up to that point.
|
||||||
|
"""
|
||||||
|
import inspect, os
|
||||||
|
print("-----------------------")
|
||||||
|
for s in inspect.stack()[1:]:
|
||||||
|
print(" * {}:{} // {}".format(
|
||||||
|
os.path.basename(s.filename),
|
||||||
|
s.lineno,
|
||||||
|
s.function))
|
||||||
|
print(" " + "".join(s.code_context))
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from manuskript.importer.abstractImporter import abstractImporter
|
from manuskript.importer.abstractImporter import abstractImporter
|
||||||
from manuskript.models.outlineModel import outlineItem
|
from manuskript.models import outlineItem
|
||||||
from manuskript.enums import Outline
|
from manuskript.enums import Outline
|
||||||
from PyQt5.QtWidgets import qApp
|
from PyQt5.QtWidgets import qApp
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# --!-- coding: utf8 --!--
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
from manuskript.importer.abstractImporter import abstractImporter
|
from manuskript.importer.abstractImporter import abstractImporter
|
||||||
from manuskript.models.outlineModel import outlineItem
|
from manuskript.models import outlineItem
|
||||||
from manuskript.enums import Outline
|
from manuskript.enums import Outline
|
||||||
from PyQt5.QtWidgets import qApp
|
from PyQt5.QtWidgets import qApp
|
||||||
import re, os
|
import re, os
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# --!-- coding: utf8 --!--
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
from PyQt5.QtWidgets import qApp, QMessageBox
|
from PyQt5.QtWidgets import qApp, QMessageBox
|
||||||
from manuskript.models.outlineModel import outlineItem
|
from manuskript.models import outlineItem
|
||||||
from manuskript.enums import Outline
|
from manuskript.enums import Outline
|
||||||
from lxml import etree as ET
|
from lxml import etree as ET
|
||||||
from manuskript.functions import mainWindow
|
from manuskript.functions import mainWindow
|
||||||
|
@ -114,18 +114,18 @@ class mindMapImporter(abstractImporter):
|
||||||
# If there is one line, we use it as title.
|
# If there is one line, we use it as title.
|
||||||
# Otherwise we leave it to be inserted as a note.
|
# Otherwise we leave it to be inserted as a note.
|
||||||
if len(lines) == 1:
|
if len(lines) == 1:
|
||||||
item.setData(Outline.title.value, "".join(lines))
|
item.setData(Outline.title, "".join(lines))
|
||||||
content = ""
|
content = ""
|
||||||
|
|
||||||
if content:
|
if content:
|
||||||
# Set the note content as text value
|
# Set the note content as text value
|
||||||
content = HTML2MD(content)
|
content = HTML2MD(content)
|
||||||
item.setData(Outline.notes.value, content)
|
item.setData(Outline.notes, content)
|
||||||
|
|
||||||
if url:
|
if url:
|
||||||
# Set the url in notes
|
# Set the url in notes
|
||||||
item.setData(Outline.notes.value,
|
item.setData(Outline.notes,
|
||||||
item.data(Outline.notes.value) + "\n\n" + url)
|
item.data(Outline.notes) + "\n\n" + url)
|
||||||
|
|
||||||
children = underElement.findall('node')
|
children = underElement.findall('node')
|
||||||
|
|
||||||
|
@ -137,10 +137,10 @@ class mindMapImporter(abstractImporter):
|
||||||
# Process if no children
|
# Process if no children
|
||||||
elif self.getSetting("importTipAs").value() == "Text":
|
elif self.getSetting("importTipAs").value() == "Text":
|
||||||
# Transform item to text
|
# Transform item to text
|
||||||
item.setData(Outline.type.value, 'md')
|
item.setData(Outline.type, 'md')
|
||||||
# Move notes to text
|
# Move notes to text
|
||||||
if item.data(Outline.notes.value):
|
if item.data(Outline.notes):
|
||||||
item.setData(Outline.text.value, item.data(Outline.notes.value))
|
item.setData(Outline.text, item.data(Outline.notes))
|
||||||
item.setData(Outline.notes.value, "")
|
item.setData(Outline.notes, "")
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# --!-- coding: utf8 --!--
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
from PyQt5.QtWidgets import qApp, QMessageBox
|
from PyQt5.QtWidgets import qApp, QMessageBox
|
||||||
from manuskript.models.outlineModel import outlineItem
|
from manuskript.models import outlineItem
|
||||||
from manuskript.enums import Outline
|
from manuskript.enums import Outline
|
||||||
from lxml import etree as ET
|
from lxml import etree as ET
|
||||||
from manuskript.functions import mainWindow
|
from manuskript.functions import mainWindow
|
||||||
|
@ -90,8 +90,8 @@ class opmlImporter(abstractImporter):
|
||||||
for el in children:
|
for el in children:
|
||||||
items.extend(cls.parseItems(el, card))
|
items.extend(cls.parseItems(el, card))
|
||||||
else:
|
else:
|
||||||
card.setData(Outline.type.value, 'md')
|
card.setData(Outline.type, 'md')
|
||||||
card.setData(Outline.text.value, body)
|
card.setData(Outline.text, body)
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ from lxml import etree as ET
|
||||||
|
|
||||||
from manuskript.load_save.version_0 import loadFilesFromZip
|
from manuskript.load_save.version_0 import loadFilesFromZip
|
||||||
from manuskript.models.characterModel import CharacterInfo
|
from manuskript.models.characterModel import CharacterInfo
|
||||||
from manuskript.models.outlineModel import outlineItem
|
from manuskript.models import outlineItem
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import zlib # Used with zipfile for compression
|
import zlib # Used with zipfile for compression
|
||||||
|
@ -473,7 +473,7 @@ def addPlotItem(root, mdl, parent=QModelIndex()):
|
||||||
outline.attrib[w.name] = val
|
outline.attrib[w.name] = val
|
||||||
|
|
||||||
# List characters as attrib
|
# List characters as attrib
|
||||||
if y == Plot.characters.value:
|
if y == Plot.characters:
|
||||||
if mdl.hasChildren(index):
|
if mdl.hasChildren(index):
|
||||||
characters = []
|
characters = []
|
||||||
for cX in range(mdl.rowCount(index)):
|
for cX in range(mdl.rowCount(index)):
|
||||||
|
@ -486,7 +486,7 @@ def addPlotItem(root, mdl, parent=QModelIndex()):
|
||||||
outline.attrib.pop(Plot.characters.name)
|
outline.attrib.pop(Plot.characters.name)
|
||||||
|
|
||||||
# List resolution steps as sub items
|
# List resolution steps as sub items
|
||||||
elif y == Plot.steps.value:
|
elif y == Plot.steps:
|
||||||
if mdl.hasChildren(index):
|
if mdl.hasChildren(index):
|
||||||
for cX in range(mdl.rowCount(index)):
|
for cX in range(mdl.rowCount(index)):
|
||||||
step = ET.SubElement(outline, "step")
|
step = ET.SubElement(outline, "step")
|
||||||
|
@ -603,7 +603,7 @@ def outlineToMMD(item):
|
||||||
content += formatMetaData(attrib.name, str(val), 15)
|
content += formatMetaData(attrib.name, str(val), 15)
|
||||||
|
|
||||||
content += "\n\n"
|
content += "\n\n"
|
||||||
content += item.data(Outline.text.value)
|
content += item.data(Outline.text)
|
||||||
|
|
||||||
return content
|
return content
|
||||||
|
|
||||||
|
@ -762,16 +762,16 @@ def loadProject(project, zip=None):
|
||||||
log("* Add plot: ", row[0].text())
|
log("* Add plot: ", row[0].text())
|
||||||
|
|
||||||
# Characters
|
# Characters
|
||||||
if row[Plot.characters.value].text():
|
if row[Plot.characters].text():
|
||||||
IDs = row[Plot.characters.value].text().split(",")
|
IDs = row[Plot.characters].text().split(",")
|
||||||
item = QStandardItem()
|
item = QStandardItem()
|
||||||
for ID in IDs:
|
for ID in IDs:
|
||||||
item.appendRow(QStandardItem(ID.strip()))
|
item.appendRow(QStandardItem(ID.strip()))
|
||||||
row[Plot.characters.value] = item
|
row[Plot.characters] = item
|
||||||
|
|
||||||
# Subplots
|
# Subplots
|
||||||
for step in plot:
|
for step in plot:
|
||||||
row[Plot.steps.value].appendRow(
|
row[Plot.steps].appendRow(
|
||||||
getStandardItemRowFromXMLEnum(step, PlotStep)
|
getStandardItemRowFromXMLEnum(step, PlotStep)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -929,18 +929,18 @@ def outlineFromMMD(text, parent):
|
||||||
# Store metadata
|
# Store metadata
|
||||||
for k in md:
|
for k in md:
|
||||||
if k in Outline.__members__:
|
if k in Outline.__members__:
|
||||||
item.setData(Outline.__members__[k].value, str(md[k]))
|
item.setData(Outline.__members__[k], str(md[k]))
|
||||||
|
|
||||||
# Store body
|
# Store body
|
||||||
item.setData(Outline.text.value, str(body))
|
item.setData(Outline.text, str(body))
|
||||||
|
|
||||||
# Set file format to "md"
|
# Set file format to "md"
|
||||||
# (Old version of manuskript had different file formats: text, t2t, html and md)
|
# (Old version of manuskript had different file formats: text, t2t, html and md)
|
||||||
# If file format is html, convert to plain text:
|
# If file format is html, convert to plain text:
|
||||||
if item.type() == "html":
|
if item.type() == "html":
|
||||||
item.setData(Outline.text.value, HTML2PlainText(body))
|
item.setData(Outline.text, HTML2PlainText(body))
|
||||||
if item.type() in ["txt", "t2t", "html"]:
|
if item.type() in ["txt", "t2t", "html"]:
|
||||||
item.setData(Outline.type.value, "md")
|
item.setData(Outline.type, "md")
|
||||||
|
|
||||||
return item
|
return item
|
||||||
|
|
||||||
|
|
|
@ -14,14 +14,13 @@ from manuskript.version import getVersion
|
||||||
|
|
||||||
faulthandler.enable()
|
faulthandler.enable()
|
||||||
|
|
||||||
|
def prepare(tests=False):
|
||||||
def run():
|
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
app.setOrganizationName("manuskript")
|
app.setOrganizationName("manuskript"+("_tests" if tests else ""))
|
||||||
app.setOrganizationDomain("www.theologeek.ch")
|
app.setOrganizationDomain("www.theologeek.ch")
|
||||||
app.setApplicationName("manuskript")
|
app.setApplicationName("manuskript"+("_tests" if tests else ""))
|
||||||
app.setApplicationVersion(getVersion())
|
app.setApplicationVersion(getVersion())
|
||||||
|
|
||||||
print("Running manuskript version {}.".format(getVersion()))
|
print("Running manuskript version {}.".format(getVersion()))
|
||||||
icon = QIcon()
|
icon = QIcon()
|
||||||
for i in [16, 32, 64, 128, 256, 512]:
|
for i in [16, 32, 64, 128, 256, 512]:
|
||||||
|
@ -57,25 +56,38 @@ def run():
|
||||||
|
|
||||||
QIcon.setThemeSearchPaths(QIcon.themeSearchPaths() + [appPath("icons")])
|
QIcon.setThemeSearchPaths(QIcon.themeSearchPaths() + [appPath("icons")])
|
||||||
QIcon.setThemeName("NumixMsk")
|
QIcon.setThemeName("NumixMsk")
|
||||||
# qApp.setWindowIcon(QIcon.fromTheme("im-aim"))
|
|
||||||
|
|
||||||
# Seperating launch to avoid segfault, so it seem.
|
# Main window
|
||||||
# Cf. http://stackoverflow.com/questions/12433491/is-this-pyqt-4-python-bug-or-wrongly-behaving-code
|
from manuskript.mainWindow import MainWindow
|
||||||
launch()
|
|
||||||
|
|
||||||
|
MW = MainWindow()
|
||||||
def launch():
|
|
||||||
from .mainWindow import MainWindow
|
|
||||||
|
|
||||||
main = MainWindow()
|
|
||||||
# We store the system default cursor flash time to be able to restore it
|
# We store the system default cursor flash time to be able to restore it
|
||||||
# later if necessary
|
# later if necessary
|
||||||
main._defaultCursorFlashTime = qApp.cursorFlashTime()
|
MW._defaultCursorFlashTime = qApp.cursorFlashTime()
|
||||||
main.show()
|
|
||||||
|
return app, MW
|
||||||
|
|
||||||
|
def launch(MW = None):
|
||||||
|
if MW is None:
|
||||||
|
from manuskript.functions import mainWindow
|
||||||
|
MW = mainWindow()
|
||||||
|
|
||||||
|
MW.show()
|
||||||
|
|
||||||
qApp.exec_()
|
qApp.exec_()
|
||||||
qApp.deleteLater()
|
qApp.deleteLater()
|
||||||
|
|
||||||
|
def run():
|
||||||
|
"""
|
||||||
|
Run separates prepare and launch for two reasons:
|
||||||
|
1. I've read somewhere it helps with potential segfault (see comment below)
|
||||||
|
2. So that prepare can be used in tests, without running the whole thing
|
||||||
|
"""
|
||||||
|
# Need to return and keep `app` otherwise it gets deleted.
|
||||||
|
app, MW = prepare()
|
||||||
|
# Seperating launch to avoid segfault, so it seem.
|
||||||
|
# Cf. http://stackoverflow.com/questions/12433491/is-this-pyqt-4-python-bug-or-wrongly-behaving-code
|
||||||
|
launch(MW)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run()
|
run()
|
||||||
|
|
|
@ -10,11 +10,11 @@ from PyQt5.QtWidgets import QMainWindow, QHeaderView, qApp, QMenu, QActionGroup,
|
||||||
|
|
||||||
from manuskript import settings
|
from manuskript import settings
|
||||||
from manuskript.enums import Character, PlotStep, Plot, World, Outline
|
from manuskript.enums import Character, PlotStep, Plot, World, Outline
|
||||||
from manuskript.functions import AUC, wordCount, appPath, findWidgetsOfClass
|
from manuskript.functions import wordCount, appPath, findWidgetsOfClass
|
||||||
import manuskript.functions as F
|
import manuskript.functions as F
|
||||||
from manuskript import loadSave
|
from manuskript import loadSave
|
||||||
from manuskript.models.characterModel import characterModel
|
from manuskript.models.characterModel import characterModel
|
||||||
from manuskript.models.outlineModel import outlineModel
|
from manuskript.models import outlineModel
|
||||||
from manuskript.models.plotModel import plotModel
|
from manuskript.models.plotModel import plotModel
|
||||||
from manuskript.models.worldModel import worldModel
|
from manuskript.models.worldModel import worldModel
|
||||||
from manuskript.settingsWindow import settingsWindow
|
from manuskript.settingsWindow import settingsWindow
|
||||||
|
@ -57,6 +57,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
# Var
|
# Var
|
||||||
self.currentProject = None
|
self.currentProject = None
|
||||||
self._lastFocus = None
|
self._lastFocus = None
|
||||||
|
self._defaultCursorFlashTime = 1000 # Overriden at startup with system
|
||||||
|
# value. In manuskript.main.
|
||||||
|
|
||||||
self.readSettings()
|
self.readSettings()
|
||||||
|
|
||||||
|
@ -326,12 +328,12 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
self.txtPlotResult.setCurrentModelIndex(index)
|
self.txtPlotResult.setCurrentModelIndex(index)
|
||||||
self.sldPlotImportance.setCurrentModelIndex(index)
|
self.sldPlotImportance.setCurrentModelIndex(index)
|
||||||
self.lstPlotPerso.setRootIndex(index.sibling(index.row(),
|
self.lstPlotPerso.setRootIndex(index.sibling(index.row(),
|
||||||
Plot.characters.value))
|
Plot.characters))
|
||||||
|
|
||||||
# Slider importance
|
# Slider importance
|
||||||
self.updatePlotImportance(index.row())
|
self.updatePlotImportance(index.row())
|
||||||
|
|
||||||
subplotindex = index.sibling(index.row(), Plot.steps.value)
|
subplotindex = index.sibling(index.row(), Plot.steps)
|
||||||
self.lstSubPlots.setRootIndex(subplotindex)
|
self.lstSubPlots.setRootIndex(subplotindex)
|
||||||
if self.mdlPlots.rowCount(subplotindex):
|
if self.mdlPlots.rowCount(subplotindex):
|
||||||
self.updateSubPlotView()
|
self.updateSubPlotView()
|
||||||
|
@ -351,22 +353,22 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
# So instead we set their width to 0.
|
# So instead we set their width to 0.
|
||||||
#for i in range(self.mdlPlots.columnCount()):
|
#for i in range(self.mdlPlots.columnCount()):
|
||||||
#self.lstSubPlots.hideColumn(i)
|
#self.lstSubPlots.hideColumn(i)
|
||||||
#self.lstSubPlots.showColumn(PlotStep.name.value)
|
#self.lstSubPlots.showColumn(PlotStep.name)
|
||||||
#self.lstSubPlots.showColumn(PlotStep.meta.value)
|
#self.lstSubPlots.showColumn(PlotStep.meta)
|
||||||
|
|
||||||
self.lstSubPlots.horizontalHeader().setSectionResizeMode(
|
self.lstSubPlots.horizontalHeader().setSectionResizeMode(
|
||||||
PlotStep.ID.value, QHeaderView.Fixed)
|
PlotStep.ID, QHeaderView.Fixed)
|
||||||
self.lstSubPlots.horizontalHeader().setSectionResizeMode(
|
self.lstSubPlots.horizontalHeader().setSectionResizeMode(
|
||||||
PlotStep.summary.value, QHeaderView.Fixed)
|
PlotStep.summary, QHeaderView.Fixed)
|
||||||
self.lstSubPlots.horizontalHeader().resizeSection(
|
self.lstSubPlots.horizontalHeader().resizeSection(
|
||||||
PlotStep.ID.value, 0)
|
PlotStep.ID, 0)
|
||||||
self.lstSubPlots.horizontalHeader().resizeSection(
|
self.lstSubPlots.horizontalHeader().resizeSection(
|
||||||
PlotStep.summary.value, 0)
|
PlotStep.summary, 0)
|
||||||
|
|
||||||
self.lstSubPlots.horizontalHeader().setSectionResizeMode(
|
self.lstSubPlots.horizontalHeader().setSectionResizeMode(
|
||||||
PlotStep.name.value, QHeaderView.Stretch)
|
PlotStep.name, QHeaderView.Stretch)
|
||||||
self.lstSubPlots.horizontalHeader().setSectionResizeMode(
|
self.lstSubPlots.horizontalHeader().setSectionResizeMode(
|
||||||
PlotStep.meta.value, QHeaderView.ResizeToContents)
|
PlotStep.meta, QHeaderView.ResizeToContents)
|
||||||
self.lstSubPlots.verticalHeader().hide()
|
self.lstSubPlots.verticalHeader().hide()
|
||||||
|
|
||||||
def updatePlotImportance(self, ID):
|
def updatePlotImportance(self, ID):
|
||||||
|
@ -375,7 +377,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
|
|
||||||
def changeCurrentSubPlot(self, index):
|
def changeCurrentSubPlot(self, index):
|
||||||
# Got segfaults when using textEditView model system, so ad hoc stuff.
|
# Got segfaults when using textEditView model system, so ad hoc stuff.
|
||||||
index = index.sibling(index.row(), PlotStep.summary.value)
|
index = index.sibling(index.row(), PlotStep.summary)
|
||||||
item = self.mdlPlots.itemFromIndex(index)
|
item = self.mdlPlots.itemFromIndex(index)
|
||||||
if not item:
|
if not item:
|
||||||
self.txtSubPlotSummary.setEnabled(False)
|
self.txtSubPlotSummary.setEnabled(False)
|
||||||
|
@ -393,7 +395,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
index = self.lstSubPlots.currentIndex()
|
index = self.lstSubPlots.currentIndex()
|
||||||
if not index.isValid():
|
if not index.isValid():
|
||||||
return
|
return
|
||||||
index = index.sibling(index.row(), PlotStep.summary.value)
|
index = index.sibling(index.row(), PlotStep.summary)
|
||||||
item = self.mdlPlots.itemFromIndex(index)
|
item = self.mdlPlots.itemFromIndex(index)
|
||||||
|
|
||||||
self._updatingSubPlot = True
|
self._updatingSubPlot = True
|
||||||
|
@ -745,20 +747,20 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
|
|
||||||
def makeUIConnections(self):
|
def makeUIConnections(self):
|
||||||
"Connections that have to be made once only, even when a new project is loaded."
|
"Connections that have to be made once only, even when a new project is loaded."
|
||||||
self.lstCharacters.currentItemChanged.connect(self.changeCurrentCharacter, AUC)
|
self.lstCharacters.currentItemChanged.connect(self.changeCurrentCharacter, F.AUC)
|
||||||
|
|
||||||
self.txtPlotFilter.textChanged.connect(self.lstPlots.setFilter, AUC)
|
self.txtPlotFilter.textChanged.connect(self.lstPlots.setFilter, F.AUC)
|
||||||
self.lstPlots.currentItemChanged.connect(self.changeCurrentPlot, AUC)
|
self.lstPlots.currentItemChanged.connect(self.changeCurrentPlot, F.AUC)
|
||||||
self.txtSubPlotSummary.document().contentsChanged.connect(
|
self.txtSubPlotSummary.document().contentsChanged.connect(
|
||||||
self.updateSubPlotSummary, AUC)
|
self.updateSubPlotSummary, F.AUC)
|
||||||
self.lstSubPlots.clicked.connect(self.changeCurrentSubPlot, AUC)
|
self.lstSubPlots.clicked.connect(self.changeCurrentSubPlot, F.AUC)
|
||||||
|
|
||||||
self.btnRedacAddFolder.clicked.connect(self.treeRedacOutline.addFolder, AUC)
|
self.btnRedacAddFolder.clicked.connect(self.treeRedacOutline.addFolder, F.AUC)
|
||||||
self.btnOutlineAddFolder.clicked.connect(self.treeOutlineOutline.addFolder, AUC)
|
self.btnOutlineAddFolder.clicked.connect(self.treeOutlineOutline.addFolder, F.AUC)
|
||||||
self.btnRedacAddText.clicked.connect(self.treeRedacOutline.addText, AUC)
|
self.btnRedacAddText.clicked.connect(self.treeRedacOutline.addText, F.AUC)
|
||||||
self.btnOutlineAddText.clicked.connect(self.treeOutlineOutline.addText, AUC)
|
self.btnOutlineAddText.clicked.connect(self.treeOutlineOutline.addText, F.AUC)
|
||||||
self.btnRedacRemoveItem.clicked.connect(self.outlineRemoveItemsRedac, AUC)
|
self.btnRedacRemoveItem.clicked.connect(self.outlineRemoveItemsRedac, F.AUC)
|
||||||
self.btnOutlineRemoveItem.clicked.connect(self.outlineRemoveItemsOutline, AUC)
|
self.btnOutlineRemoveItem.clicked.connect(self.outlineRemoveItemsOutline, F.AUC)
|
||||||
|
|
||||||
self.tabMain.currentChanged.connect(self.toolbar.setCurrentGroup)
|
self.tabMain.currentChanged.connect(self.toolbar.setCurrentGroup)
|
||||||
self.tabMain.currentChanged.connect(self.tabMainChanged)
|
self.tabMain.currentChanged.connect(self.tabMainChanged)
|
||||||
|
@ -803,27 +805,27 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
self.lstCharacters.setCharactersModel(self.mdlCharacter)
|
self.lstCharacters.setCharactersModel(self.mdlCharacter)
|
||||||
self.tblPersoInfos.setModel(self.mdlCharacter)
|
self.tblPersoInfos.setModel(self.mdlCharacter)
|
||||||
|
|
||||||
self.btnAddPerso.clicked.connect(self.mdlCharacter.addCharacter, AUC)
|
self.btnAddPerso.clicked.connect(self.mdlCharacter.addCharacter, F.AUC)
|
||||||
try:
|
try:
|
||||||
self.btnRmPerso.clicked.connect(self.lstCharacters.removeCharacter, AUC)
|
self.btnRmPerso.clicked.connect(self.lstCharacters.removeCharacter, F.AUC)
|
||||||
self.btnPersoColor.clicked.connect(self.lstCharacters.choseCharacterColor, AUC)
|
self.btnPersoColor.clicked.connect(self.lstCharacters.choseCharacterColor, F.AUC)
|
||||||
self.btnPersoAddInfo.clicked.connect(self.lstCharacters.addCharacterInfo, AUC)
|
self.btnPersoAddInfo.clicked.connect(self.lstCharacters.addCharacterInfo, F.AUC)
|
||||||
self.btnPersoRmInfo.clicked.connect(self.lstCharacters.removeCharacterInfo, AUC)
|
self.btnPersoRmInfo.clicked.connect(self.lstCharacters.removeCharacterInfo, F.AUC)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
# Connection has already been made
|
# Connection has already been made
|
||||||
pass
|
pass
|
||||||
|
|
||||||
for w, c in [
|
for w, c in [
|
||||||
(self.txtPersoName, Character.name.value),
|
(self.txtPersoName, Character.name),
|
||||||
(self.sldPersoImportance, Character.importance.value),
|
(self.sldPersoImportance, Character.importance),
|
||||||
(self.txtPersoMotivation, Character.motivation.value),
|
(self.txtPersoMotivation, Character.motivation),
|
||||||
(self.txtPersoGoal, Character.goal.value),
|
(self.txtPersoGoal, Character.goal),
|
||||||
(self.txtPersoConflict, Character.conflict.value),
|
(self.txtPersoConflict, Character.conflict),
|
||||||
(self.txtPersoEpiphany, Character.epiphany.value),
|
(self.txtPersoEpiphany, Character.epiphany),
|
||||||
(self.txtPersoSummarySentence, Character.summarySentence.value),
|
(self.txtPersoSummarySentence, Character.summarySentence),
|
||||||
(self.txtPersoSummaryPara, Character.summaryPara.value),
|
(self.txtPersoSummaryPara, Character.summaryPara),
|
||||||
(self.txtPersoSummaryFull, Character.summaryFull.value),
|
(self.txtPersoSummaryFull, Character.summaryFull),
|
||||||
(self.txtPersoNotes, Character.notes.value)
|
(self.txtPersoNotes, Character.notes)
|
||||||
]:
|
]:
|
||||||
w.setModel(self.mdlCharacter)
|
w.setModel(self.mdlCharacter)
|
||||||
w.setColumn(c)
|
w.setColumn(c)
|
||||||
|
@ -834,21 +836,21 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
self.lstPlotPerso.setModel(self.mdlPlots)
|
self.lstPlotPerso.setModel(self.mdlPlots)
|
||||||
self.lstPlots.setPlotModel(self.mdlPlots)
|
self.lstPlots.setPlotModel(self.mdlPlots)
|
||||||
self._updatingSubPlot = False
|
self._updatingSubPlot = False
|
||||||
self.btnAddPlot.clicked.connect(self.mdlPlots.addPlot, AUC)
|
self.btnAddPlot.clicked.connect(self.mdlPlots.addPlot, F.AUC)
|
||||||
self.btnRmPlot.clicked.connect(lambda:
|
self.btnRmPlot.clicked.connect(lambda:
|
||||||
self.mdlPlots.removePlot(self.lstPlots.currentPlotIndex()), AUC)
|
self.mdlPlots.removePlot(self.lstPlots.currentPlotIndex()), F.AUC)
|
||||||
self.btnAddSubPlot.clicked.connect(self.mdlPlots.addSubPlot, AUC)
|
self.btnAddSubPlot.clicked.connect(self.mdlPlots.addSubPlot, F.AUC)
|
||||||
self.btnAddSubPlot.clicked.connect(self.updateSubPlotView, AUC)
|
self.btnAddSubPlot.clicked.connect(self.updateSubPlotView, F.AUC)
|
||||||
self.btnRmSubPlot.clicked.connect(self.mdlPlots.removeSubPlot, AUC)
|
self.btnRmSubPlot.clicked.connect(self.mdlPlots.removeSubPlot, F.AUC)
|
||||||
self.lstPlotPerso.selectionModel().selectionChanged.connect(self.plotPersoSelectionChanged)
|
self.lstPlotPerso.selectionModel().selectionChanged.connect(self.plotPersoSelectionChanged)
|
||||||
self.btnRmPlotPerso.clicked.connect(self.mdlPlots.removePlotPerso, AUC)
|
self.btnRmPlotPerso.clicked.connect(self.mdlPlots.removePlotPerso, F.AUC)
|
||||||
self.lstSubPlots.selectionModel().currentRowChanged.connect(self.changeCurrentSubPlot, AUC)
|
self.lstSubPlots.selectionModel().currentRowChanged.connect(self.changeCurrentSubPlot, F.AUC)
|
||||||
|
|
||||||
for w, c in [
|
for w, c in [
|
||||||
(self.txtPlotName, Plot.name.value),
|
(self.txtPlotName, Plot.name),
|
||||||
(self.txtPlotDescription, Plot.description.value),
|
(self.txtPlotDescription, Plot.description),
|
||||||
(self.txtPlotResult, Plot.result.value),
|
(self.txtPlotResult, Plot.result),
|
||||||
(self.sldPlotImportance, Plot.importance.value),
|
(self.sldPlotImportance, Plot.importance),
|
||||||
]:
|
]:
|
||||||
w.setModel(self.mdlPlots)
|
w.setModel(self.mdlPlots)
|
||||||
w.setColumn(c)
|
w.setColumn(c)
|
||||||
|
@ -861,7 +863,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
self.plotCharacterDelegate = outlineCharacterDelegate(self.mdlCharacter, self)
|
self.plotCharacterDelegate = outlineCharacterDelegate(self.mdlCharacter, self)
|
||||||
self.lstPlotPerso.setItemDelegate(self.plotCharacterDelegate)
|
self.lstPlotPerso.setItemDelegate(self.plotCharacterDelegate)
|
||||||
self.plotDelegate = plotDelegate(self)
|
self.plotDelegate = plotDelegate(self)
|
||||||
self.lstSubPlots.setItemDelegateForColumn(PlotStep.meta.value, self.plotDelegate)
|
self.lstSubPlots.setItemDelegateForColumn(PlotStep.meta, self.plotDelegate)
|
||||||
|
|
||||||
# World
|
# World
|
||||||
self.treeWorld.setModel(self.mdlWorld)
|
self.treeWorld.setModel(self.mdlWorld)
|
||||||
|
@ -869,14 +871,14 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
self.treeWorld.hideColumn(i)
|
self.treeWorld.hideColumn(i)
|
||||||
self.treeWorld.showColumn(0)
|
self.treeWorld.showColumn(0)
|
||||||
self.btnWorldEmptyData.setMenu(self.mdlWorld.emptyDataMenu())
|
self.btnWorldEmptyData.setMenu(self.mdlWorld.emptyDataMenu())
|
||||||
self.treeWorld.selectionModel().selectionChanged.connect(self.changeCurrentWorld, AUC)
|
self.treeWorld.selectionModel().selectionChanged.connect(self.changeCurrentWorld, F.AUC)
|
||||||
self.btnAddWorld.clicked.connect(self.mdlWorld.addItem, AUC)
|
self.btnAddWorld.clicked.connect(self.mdlWorld.addItem, F.AUC)
|
||||||
self.btnRmWorld.clicked.connect(self.mdlWorld.removeItem, AUC)
|
self.btnRmWorld.clicked.connect(self.mdlWorld.removeItem, F.AUC)
|
||||||
for w, c in [
|
for w, c in [
|
||||||
(self.txtWorldName, World.name.value),
|
(self.txtWorldName, World.name),
|
||||||
(self.txtWorldDescription, World.description.value),
|
(self.txtWorldDescription, World.description),
|
||||||
(self.txtWorldPassion, World.passion.value),
|
(self.txtWorldPassion, World.passion),
|
||||||
(self.txtWorldConflict, World.conflict.value),
|
(self.txtWorldConflict, World.conflict),
|
||||||
]:
|
]:
|
||||||
w.setModel(self.mdlWorld)
|
w.setModel(self.mdlWorld)
|
||||||
w.setColumn(c)
|
w.setColumn(c)
|
||||||
|
@ -898,14 +900,14 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
# self.redacEditor.setModel(self.mdlOutline)
|
# self.redacEditor.setModel(self.mdlOutline)
|
||||||
self.storylineView.setModels(self.mdlOutline, self.mdlCharacter, self.mdlPlots)
|
self.storylineView.setModels(self.mdlOutline, self.mdlCharacter, self.mdlPlots)
|
||||||
|
|
||||||
self.treeOutlineOutline.selectionModel().selectionChanged.connect(self.outlineItemEditor.selectionChanged, AUC)
|
self.treeOutlineOutline.selectionModel().selectionChanged.connect(self.outlineItemEditor.selectionChanged, F.AUC)
|
||||||
self.treeOutlineOutline.clicked.connect(self.outlineItemEditor.selectionChanged, AUC)
|
self.treeOutlineOutline.clicked.connect(self.outlineItemEditor.selectionChanged, F.AUC)
|
||||||
|
|
||||||
# Sync selection
|
# Sync selection
|
||||||
self.treeRedacOutline.selectionModel().selectionChanged.connect(self.redacMetadata.selectionChanged, AUC)
|
self.treeRedacOutline.selectionModel().selectionChanged.connect(self.redacMetadata.selectionChanged, F.AUC)
|
||||||
self.treeRedacOutline.clicked.connect(self.redacMetadata.selectionChanged, AUC)
|
self.treeRedacOutline.clicked.connect(self.redacMetadata.selectionChanged, F.AUC)
|
||||||
|
|
||||||
self.treeRedacOutline.selectionModel().selectionChanged.connect(self.mainEditor.selectionChanged, AUC)
|
self.treeRedacOutline.selectionModel().selectionChanged.connect(self.mainEditor.selectionChanged, F.AUC)
|
||||||
|
|
||||||
# Cheat Sheet
|
# Cheat Sheet
|
||||||
self.cheatSheet.setModels()
|
self.cheatSheet.setModels()
|
||||||
|
@ -918,7 +920,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
self.tblDebugPersos.selectionModel().currentChanged.connect(
|
self.tblDebugPersos.selectionModel().currentChanged.connect(
|
||||||
lambda: self.tblDebugPersosInfos.setRootIndex(self.mdlCharacter.index(
|
lambda: self.tblDebugPersosInfos.setRootIndex(self.mdlCharacter.index(
|
||||||
self.tblDebugPersos.selectionModel().currentIndex().row(),
|
self.tblDebugPersos.selectionModel().currentIndex().row(),
|
||||||
Character.name.value)), AUC)
|
Character.name)), F.AUC)
|
||||||
|
|
||||||
self.tblDebugPlots.setModel(self.mdlPlots)
|
self.tblDebugPlots.setModel(self.mdlPlots)
|
||||||
self.tblDebugPlotsPersos.setModel(self.mdlPlots)
|
self.tblDebugPlotsPersos.setModel(self.mdlPlots)
|
||||||
|
@ -926,11 +928,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
self.tblDebugPlots.selectionModel().currentChanged.connect(
|
self.tblDebugPlots.selectionModel().currentChanged.connect(
|
||||||
lambda: self.tblDebugPlotsPersos.setRootIndex(self.mdlPlots.index(
|
lambda: self.tblDebugPlotsPersos.setRootIndex(self.mdlPlots.index(
|
||||||
self.tblDebugPlots.selectionModel().currentIndex().row(),
|
self.tblDebugPlots.selectionModel().currentIndex().row(),
|
||||||
Plot.characters.value)), AUC)
|
Plot.characters)), F.AUC)
|
||||||
self.tblDebugPlots.selectionModel().currentChanged.connect(
|
self.tblDebugPlots.selectionModel().currentChanged.connect(
|
||||||
lambda: self.tblDebugSubPlots.setRootIndex(self.mdlPlots.index(
|
lambda: self.tblDebugSubPlots.setRootIndex(self.mdlPlots.index(
|
||||||
self.tblDebugPlots.selectionModel().currentIndex().row(),
|
self.tblDebugPlots.selectionModel().currentIndex().row(),
|
||||||
Plot.steps.value)), AUC)
|
Plot.steps)), F.AUC)
|
||||||
self.treeDebugWorld.setModel(self.mdlWorld)
|
self.treeDebugWorld.setModel(self.mdlWorld)
|
||||||
self.treeDebugOutline.setModel(self.mdlOutline)
|
self.treeDebugOutline.setModel(self.mdlOutline)
|
||||||
self.lstDebugLabels.setModel(self.mdlLabels)
|
self.lstDebugLabels.setModel(self.mdlLabels)
|
||||||
|
@ -997,15 +999,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
self.disconnectAll(self.tblDebugPersos.selectionModel().currentChanged,
|
self.disconnectAll(self.tblDebugPersos.selectionModel().currentChanged,
|
||||||
lambda: self.tblDebugPersosInfos.setRootIndex(self.mdlCharacter.index(
|
lambda: self.tblDebugPersosInfos.setRootIndex(self.mdlCharacter.index(
|
||||||
self.tblDebugPersos.selectionModel().currentIndex().row(),
|
self.tblDebugPersos.selectionModel().currentIndex().row(),
|
||||||
Character.name.value)))
|
Character.name)))
|
||||||
self.disconnectAll(self.tblDebugPlots.selectionModel().currentChanged,
|
self.disconnectAll(self.tblDebugPlots.selectionModel().currentChanged,
|
||||||
lambda: self.tblDebugPlotsPersos.setRootIndex(self.mdlPlots.index(
|
lambda: self.tblDebugPlotsPersos.setRootIndex(self.mdlPlots.index(
|
||||||
self.tblDebugPlots.selectionModel().currentIndex().row(),
|
self.tblDebugPlots.selectionModel().currentIndex().row(),
|
||||||
Plot.characters.value)))
|
Plot.characters)))
|
||||||
self.disconnectAll(self.tblDebugPlots.selectionModel().currentChanged,
|
self.disconnectAll(self.tblDebugPlots.selectionModel().currentChanged,
|
||||||
lambda: self.tblDebugSubPlots.setRootIndex(self.mdlPlots.index(
|
lambda: self.tblDebugSubPlots.setRootIndex(self.mdlPlots.index(
|
||||||
self.tblDebugPlots.selectionModel().currentIndex().row(),
|
self.tblDebugPlots.selectionModel().currentIndex().row(),
|
||||||
Plot.steps.value)))
|
Plot.steps)))
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# HELP
|
# HELP
|
||||||
|
@ -1173,7 +1175,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
|
|
||||||
for widget, text, pos in references:
|
for widget, text, pos in references:
|
||||||
label = helpLabel(text, self)
|
label = helpLabel(text, self)
|
||||||
self.actShowHelp.toggled.connect(label.setVisible, AUC)
|
self.actShowHelp.toggled.connect(label.setVisible, F.AUC)
|
||||||
widget.layout().insertWidget(pos, label)
|
widget.layout().insertWidget(pos, label)
|
||||||
|
|
||||||
self.actShowHelp.setChecked(False)
|
self.actShowHelp.setChecked(False)
|
||||||
|
@ -1185,17 +1187,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
self.updateMenuDict()
|
self.updateMenuDict()
|
||||||
self.menuTools.addMenu(self.menuDict)
|
self.menuTools.addMenu(self.menuDict)
|
||||||
|
|
||||||
self.actSpellcheck.toggled.connect(self.toggleSpellcheck, AUC)
|
self.actSpellcheck.toggled.connect(self.toggleSpellcheck, F.AUC)
|
||||||
self.dictChanged.connect(self.mainEditor.setDict, AUC)
|
self.dictChanged.connect(self.mainEditor.setDict, F.AUC)
|
||||||
self.dictChanged.connect(self.redacMetadata.setDict, AUC)
|
self.dictChanged.connect(self.redacMetadata.setDict, F.AUC)
|
||||||
self.dictChanged.connect(self.outlineItemEditor.setDict, AUC)
|
self.dictChanged.connect(self.outlineItemEditor.setDict, F.AUC)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# No Spell check support
|
# No Spell check support
|
||||||
self.actSpellcheck.setVisible(False)
|
self.actSpellcheck.setVisible(False)
|
||||||
a = QAction(self.tr("Install PyEnchant to use spellcheck"), self)
|
a = QAction(self.tr("Install PyEnchant to use spellcheck"), self)
|
||||||
a.setIcon(self.style().standardIcon(QStyle.SP_MessageBoxWarning))
|
a.setIcon(self.style().standardIcon(QStyle.SP_MessageBoxWarning))
|
||||||
a.triggered.connect(self.openPyEnchantWebPage, AUC)
|
a.triggered.connect(self.openPyEnchantWebPage, F.AUC)
|
||||||
self.menuTools.addAction(a)
|
self.menuTools.addAction(a)
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
@ -1215,7 +1217,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
settings.dict = enchant.get_default_language()
|
settings.dict = enchant.get_default_language()
|
||||||
if str(i[0]) == settings.dict:
|
if str(i[0]) == settings.dict:
|
||||||
a.setChecked(True)
|
a.setChecked(True)
|
||||||
a.triggered.connect(self.setDictionary, AUC)
|
a.triggered.connect(self.setDictionary, F.AUC)
|
||||||
self.menuDictGroup.addAction(a)
|
self.menuDictGroup.addAction(a)
|
||||||
self.menuDict.addAction(a)
|
self.menuDict.addAction(a)
|
||||||
|
|
||||||
|
@ -1333,7 +1335,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
a.setData("{},{},{}".format(mnud, sd, vd))
|
a.setData("{},{},{}".format(mnud, sd, vd))
|
||||||
if settings.viewSettings[mnud][sd] == vd:
|
if settings.viewSettings[mnud][sd] == vd:
|
||||||
a.setChecked(True)
|
a.setChecked(True)
|
||||||
a.triggered.connect(self.setViewSettingsAction, AUC)
|
a.triggered.connect(self.setViewSettingsAction, F.AUC)
|
||||||
agp.addAction(a)
|
agp.addAction(a)
|
||||||
m2.addAction(a)
|
m2.addAction(a)
|
||||||
m.addMenu(m2)
|
m.addMenu(m2)
|
||||||
|
@ -1385,8 +1387,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
w.cmbPOV.setVisible(val)
|
w.cmbPOV.setVisible(val)
|
||||||
|
|
||||||
# POV in outline view
|
# POV in outline view
|
||||||
if Outline.POV.value in settings.outlineViewColumns:
|
if val is None and Outline.POV in settings.outlineViewColumns:
|
||||||
settings.outlineViewColumns.remove(Outline.POV.value)
|
settings.outlineViewColumns.remove(Outline.POV)
|
||||||
|
|
||||||
from manuskript.ui.views.outlineView import outlineView
|
from manuskript.ui.views.outlineView import outlineView
|
||||||
for w in findWidgetsOfClass(outlineView):
|
for w in findWidgetsOfClass(outlineView):
|
||||||
|
@ -1415,4 +1417,3 @@ class MainWindow(QMainWindow, Ui_MainWindow):
|
||||||
r = self.dialog.geometry()
|
r = self.dialog.geometry()
|
||||||
r2 = self.geometry()
|
r2 = self.geometry()
|
||||||
self.dialog.move(r2.center() - r.center())
|
self.dialog.move(r2.center() - r.center())
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
from manuskript.models.outlineItem import outlineItem
|
||||||
|
from manuskript.models.outlineModel import outlineModel
|
306
manuskript/models/abstractItem.py
Normal file
306
manuskript/models/abstractItem.py
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QAbstractItemModel, QMimeData
|
||||||
|
from PyQt5.QtCore import QModelIndex
|
||||||
|
from PyQt5.QtCore import QSize
|
||||||
|
from PyQt5.QtCore import QVariant
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
from PyQt5.QtGui import QIcon, QFont
|
||||||
|
from PyQt5.QtWidgets import QTextEdit, qApp
|
||||||
|
from lxml import etree as ET
|
||||||
|
|
||||||
|
from manuskript import enums
|
||||||
|
|
||||||
|
|
||||||
|
class abstractItem():
|
||||||
|
|
||||||
|
# Enum kept on the class for easier acces
|
||||||
|
enum = enums.Abstract
|
||||||
|
|
||||||
|
# Used for XML export
|
||||||
|
name = "abstractItem"
|
||||||
|
|
||||||
|
def __init__(self, model=None, title="", _type="abstract", xml=None, parent=None, ID=None):
|
||||||
|
|
||||||
|
self._data = {}
|
||||||
|
self.childItems = []
|
||||||
|
self._parent = None
|
||||||
|
self._model = model
|
||||||
|
|
||||||
|
self.IDs = ["0"] # used by root item to store unique IDs
|
||||||
|
self._lastPath = "" # used by loadSave version_1 to remember which files the items comes from,
|
||||||
|
# in case it is renamed / removed
|
||||||
|
|
||||||
|
self._data[self.enum.title] = title
|
||||||
|
self._data[self.enum.type] = _type
|
||||||
|
|
||||||
|
if xml is not None:
|
||||||
|
self.setFromXML(xml)
|
||||||
|
|
||||||
|
if ID:
|
||||||
|
self._data[self.enum.ID] = ID
|
||||||
|
|
||||||
|
if parent:
|
||||||
|
parent.appendChild(self)
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Model
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def setModel(self, model):
|
||||||
|
self._model = model
|
||||||
|
for c in self.children():
|
||||||
|
c.setModel(model)
|
||||||
|
|
||||||
|
def index(self, column=0):
|
||||||
|
if self._model:
|
||||||
|
return self._model.indexFromItem(self, column)
|
||||||
|
else:
|
||||||
|
return QModelIndex()
|
||||||
|
|
||||||
|
def emitDataChanged(self, cols=None, recursive=False):
|
||||||
|
"""
|
||||||
|
Emits the dataChanged signal of the model, to signal views that data
|
||||||
|
have changed.
|
||||||
|
|
||||||
|
@param cols: an array of int (or None). The columns of the index that
|
||||||
|
have been changed.
|
||||||
|
@param recursive: boolean. If true, all children will also emit the
|
||||||
|
dataChanged signal.
|
||||||
|
"""
|
||||||
|
idx = self.index()
|
||||||
|
if idx and self._model:
|
||||||
|
if not cols:
|
||||||
|
# Emit data changed for the whole item (all columns)
|
||||||
|
self._model.dataChanged.emit(idx, self.index(len(self.enum)))
|
||||||
|
|
||||||
|
else:
|
||||||
|
# Emit only for the specified columns
|
||||||
|
for c in cols:
|
||||||
|
self._model.dataChanged.emit(self.index(c), self.index(c))
|
||||||
|
|
||||||
|
if recursive:
|
||||||
|
for c in self.children():
|
||||||
|
c.emitDataChanged(cols, recursive=True)
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Properties
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def title(self):
|
||||||
|
return self._data.get(self.enum.title, "")
|
||||||
|
|
||||||
|
def ID(self):
|
||||||
|
return self._data.get(self.enum.ID)
|
||||||
|
|
||||||
|
def columnCount(self):
|
||||||
|
return len(self.enum)
|
||||||
|
|
||||||
|
def type(self):
|
||||||
|
return self._data[self.enum.type]
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Parent / Children managment
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def child(self, row):
|
||||||
|
return self.childItems[row]
|
||||||
|
|
||||||
|
def childCount(self):
|
||||||
|
return len(self.childItems)
|
||||||
|
|
||||||
|
def childCountRecursive(self):
|
||||||
|
n = self.childCount()
|
||||||
|
for c in self.children():
|
||||||
|
n += c.childCountRecursive()
|
||||||
|
return n
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
return self.childItems
|
||||||
|
|
||||||
|
def row(self):
|
||||||
|
if self.parent():
|
||||||
|
return self.parent().childItems.index(self)
|
||||||
|
|
||||||
|
def appendChild(self, child):
|
||||||
|
self.insertChild(self.childCount(), child)
|
||||||
|
|
||||||
|
def insertChild(self, row, child):
|
||||||
|
self.childItems.insert(row, child)
|
||||||
|
child._parent = self
|
||||||
|
child.setModel(self._model)
|
||||||
|
if not child.ID():
|
||||||
|
child.getUniqueID()
|
||||||
|
|
||||||
|
def removeChild(self, row):
|
||||||
|
"""
|
||||||
|
Removes child at position `row` and returns it.
|
||||||
|
@param row: index (int) of the child to remove.
|
||||||
|
@return: the removed abstractItem
|
||||||
|
"""
|
||||||
|
r = self.childItems.pop(row)
|
||||||
|
return r
|
||||||
|
|
||||||
|
def parent(self):
|
||||||
|
return self._parent
|
||||||
|
|
||||||
|
def path(self, sep=" > "):
|
||||||
|
"Returns path to item as string."
|
||||||
|
if self.parent().parent():
|
||||||
|
return "{parent}{sep}{title}".format(
|
||||||
|
parent=self.parent().path(),
|
||||||
|
sep=sep,
|
||||||
|
title=self.title())
|
||||||
|
else:
|
||||||
|
return self.title()
|
||||||
|
|
||||||
|
def pathID(self):
|
||||||
|
"Returns path to item as list of (ID, title)."
|
||||||
|
if self.parent() and self.parent().parent():
|
||||||
|
return self.parent().pathID() + [(self.ID(), self.title())]
|
||||||
|
else:
|
||||||
|
return [(self.ID(), self.title())]
|
||||||
|
|
||||||
|
def level(self):
|
||||||
|
"""Returns the level of the current item. Root item returns -1."""
|
||||||
|
if self.parent():
|
||||||
|
return self.parent().level() + 1
|
||||||
|
else:
|
||||||
|
return -1
|
||||||
|
|
||||||
|
def copy(self):
|
||||||
|
"""
|
||||||
|
Returns a copy of item, with no parent, and no ID.
|
||||||
|
"""
|
||||||
|
item = self.__class__(xml=self.toXML())
|
||||||
|
item.setData(self.enum.ID, None)
|
||||||
|
return item
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# IDS
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
def getUniqueID(self, recursive=False):
|
||||||
|
self.setData(self.enum.ID, self._model.rootItem.findUniqueID())
|
||||||
|
|
||||||
|
if recursive:
|
||||||
|
for c in self.children():
|
||||||
|
c.getUniqueID(recursive)
|
||||||
|
|
||||||
|
def checkIDs(self):
|
||||||
|
"""This is called when a model is loaded.
|
||||||
|
|
||||||
|
Makes a list of all sub-items IDs, that is used to generate unique IDs afterwards.
|
||||||
|
"""
|
||||||
|
self.IDs = self.listAllIDs()
|
||||||
|
|
||||||
|
if max([self.IDs.count(i) for i in self.IDs if i]) != 1:
|
||||||
|
print("WARNING ! There are some items with same IDs:", [i for i in self.IDs if i and self.IDs.count(i) != 1])
|
||||||
|
|
||||||
|
def checkChildren(item):
|
||||||
|
for c in item.children():
|
||||||
|
_id = c.ID()
|
||||||
|
if not _id or _id == "0":
|
||||||
|
c.getUniqueID()
|
||||||
|
checkChildren(c)
|
||||||
|
|
||||||
|
checkChildren(self)
|
||||||
|
|
||||||
|
def listAllIDs(self):
|
||||||
|
IDs = [self.ID()]
|
||||||
|
for c in self.children():
|
||||||
|
IDs.extend(c.listAllIDs())
|
||||||
|
return IDs
|
||||||
|
|
||||||
|
def findUniqueID(self):
|
||||||
|
IDs = [int(i) for i in self.IDs]
|
||||||
|
k = 1
|
||||||
|
while k in IDs:
|
||||||
|
k += 1
|
||||||
|
self.IDs.append(str(k))
|
||||||
|
return str(k)
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Data
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def data(self, column, role=Qt.DisplayRole):
|
||||||
|
# Return value in self._data
|
||||||
|
if role == Qt.DisplayRole or role == Qt.EditRole:
|
||||||
|
return self._data.get(column, "")
|
||||||
|
|
||||||
|
# Or return QVariant
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
def setData(self, column, data, role=Qt.DisplayRole):
|
||||||
|
# Setting data
|
||||||
|
self._data[column] = data
|
||||||
|
|
||||||
|
# Emit signal
|
||||||
|
self.emitDataChanged(cols=[column]) # new in 0.5.0
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# XML
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
# We don't want to write some datas (computed)
|
||||||
|
XMLExclude = []
|
||||||
|
# We want to force some data even if they're empty
|
||||||
|
XMLForce = []
|
||||||
|
|
||||||
|
def toXML(self):
|
||||||
|
"""
|
||||||
|
Returns a string containing the item (and children) in XML.
|
||||||
|
By default, saves all attributes from self.enum and lastPath.
|
||||||
|
You can define in XMLExclude and XMLForce what you want to be
|
||||||
|
excluded or forcibly included.
|
||||||
|
"""
|
||||||
|
item = ET.Element(self.name)
|
||||||
|
|
||||||
|
for attrib in self.enum:
|
||||||
|
if attrib in self.XMLExclude:
|
||||||
|
continue
|
||||||
|
val = self.data(attrib)
|
||||||
|
if val or attrib in self.XMLForce:
|
||||||
|
item.set(attrib.name, str(val))
|
||||||
|
|
||||||
|
# Saving lastPath
|
||||||
|
item.set("lastPath", self._lastPath)
|
||||||
|
|
||||||
|
# Additional stuff for subclasses
|
||||||
|
item = self.toXMLProcessItem(item)
|
||||||
|
|
||||||
|
for i in self.childItems:
|
||||||
|
item.append(ET.XML(i.toXML()))
|
||||||
|
|
||||||
|
return ET.tostring(item)
|
||||||
|
|
||||||
|
def toXMLProcessItem(self, item):
|
||||||
|
"""
|
||||||
|
Subclass this to change the behavior of `toXML`.
|
||||||
|
"""
|
||||||
|
return item
|
||||||
|
|
||||||
|
def setFromXML(self, xml):
|
||||||
|
root = ET.XML(xml)
|
||||||
|
|
||||||
|
for k in self.enum:
|
||||||
|
if k.name in root.attrib:
|
||||||
|
self.setData(k, str(root.attrib[k.name]))
|
||||||
|
|
||||||
|
if "lastPath" in root.attrib:
|
||||||
|
self._lastPath = root.attrib["lastPath"]
|
||||||
|
|
||||||
|
self.setFromXMLProcessMore(root)
|
||||||
|
|
||||||
|
for child in root:
|
||||||
|
if child.tag == self.name:
|
||||||
|
item = self.__class__(self._model, xml=ET.tostring(child), parent=self)
|
||||||
|
|
||||||
|
def setFromXMLProcessMore(self, root):
|
||||||
|
"""
|
||||||
|
Additional stuff that subclasses must do with the XML to restore
|
||||||
|
item.
|
||||||
|
"""
|
||||||
|
return
|
547
manuskript/models/abstractModel.py
Normal file
547
manuskript/models/abstractModel.py
Normal file
|
@ -0,0 +1,547 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
import locale
|
||||||
|
|
||||||
|
from PyQt5.QtCore import QAbstractItemModel, QMimeData
|
||||||
|
from PyQt5.QtCore import QModelIndex
|
||||||
|
from PyQt5.QtCore import QSize
|
||||||
|
from PyQt5.QtCore import QVariant
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
from PyQt5.QtGui import QIcon, QFont
|
||||||
|
from PyQt5.QtWidgets import QTextEdit, qApp
|
||||||
|
|
||||||
|
from manuskript import settings
|
||||||
|
from lxml import etree as ET
|
||||||
|
|
||||||
|
from manuskript.enums import Outline
|
||||||
|
from manuskript.functions import mainWindow, toInt, wordCount
|
||||||
|
from manuskript.models import outlineItem
|
||||||
|
|
||||||
|
try:
|
||||||
|
locale.setlocale(locale.LC_ALL, '')
|
||||||
|
except:
|
||||||
|
# Invalid locale, but not really a big deal because it's used only for
|
||||||
|
# number formating
|
||||||
|
pass
|
||||||
|
import time, os
|
||||||
|
|
||||||
|
|
||||||
|
class abstractModel(QAbstractItemModel):
|
||||||
|
"""
|
||||||
|
Abstract model is the base class for all others models we use.
|
||||||
|
|
||||||
|
It's main responsibilities are:
|
||||||
|
|
||||||
|
- Interface with QModelIndex and stuff
|
||||||
|
- XML Import / Export
|
||||||
|
- Drag'n'drop
|
||||||
|
|
||||||
|
"""
|
||||||
|
def __init__(self, parent):
|
||||||
|
QAbstractItemModel.__init__(self, parent)
|
||||||
|
|
||||||
|
self.rootItem = outlineItem(self, title="Root", ID="0")
|
||||||
|
|
||||||
|
# Stores removed item, in order to remove them on disk when saving, depending on the file format.
|
||||||
|
self.removed = []
|
||||||
|
self._removingRows = False
|
||||||
|
|
||||||
|
def index(self, row, column, parent):
|
||||||
|
|
||||||
|
if not self.hasIndex(row, column, parent):
|
||||||
|
return QModelIndex()
|
||||||
|
|
||||||
|
if not parent.isValid():
|
||||||
|
parentItem = self.rootItem
|
||||||
|
else:
|
||||||
|
parentItem = parent.internalPointer()
|
||||||
|
|
||||||
|
childItem = parentItem.child(row)
|
||||||
|
if childItem:
|
||||||
|
return self.createIndex(row, column, childItem)
|
||||||
|
else:
|
||||||
|
return QModelIndex()
|
||||||
|
|
||||||
|
def indexFromItem(self, item, column=0):
|
||||||
|
if item == self.rootItem:
|
||||||
|
return QModelIndex()
|
||||||
|
|
||||||
|
parent = item.parent()
|
||||||
|
if not parent:
|
||||||
|
parent = self.rootItem
|
||||||
|
|
||||||
|
if len(parent.children()) == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# print(item.title(), [i.title() for i in parent.children()])
|
||||||
|
|
||||||
|
row = parent.children().index(item)
|
||||||
|
col = column
|
||||||
|
return self.createIndex(row, col, item)
|
||||||
|
|
||||||
|
def ID(self, index):
|
||||||
|
if index.isValid():
|
||||||
|
item = index.internalPointer()
|
||||||
|
return item.ID()
|
||||||
|
|
||||||
|
def findItemsContaining(self, text, columns, caseSensitive=False):
|
||||||
|
"""
|
||||||
|
Returns a list of IDs of all items containing `text`
|
||||||
|
in columns `columns` (being a list of int).
|
||||||
|
"""
|
||||||
|
return self.rootItem.findItemsContaining(text, columns, mainWindow(), caseSensitive)
|
||||||
|
|
||||||
|
def getItemByID(self, ID):
|
||||||
|
def search(item):
|
||||||
|
if item.ID() == ID:
|
||||||
|
return item
|
||||||
|
for c in item.children():
|
||||||
|
r = search(c)
|
||||||
|
if r:
|
||||||
|
return r
|
||||||
|
|
||||||
|
item = search(self.rootItem)
|
||||||
|
return item
|
||||||
|
|
||||||
|
def getIndexByID(self, ID, column=0):
|
||||||
|
"Returns the index of item whose ID is `ID`. If none, returns QModelIndex()."
|
||||||
|
item = self.getItemByID(ID)
|
||||||
|
if not item:
|
||||||
|
return QModelIndex()
|
||||||
|
else:
|
||||||
|
return self.indexFromItem(item, column)
|
||||||
|
|
||||||
|
def parent(self, index=QModelIndex()):
|
||||||
|
if not index.isValid():
|
||||||
|
return QModelIndex()
|
||||||
|
|
||||||
|
childItem = index.internalPointer()
|
||||||
|
parentItem = childItem.parent()
|
||||||
|
|
||||||
|
if parentItem == self.rootItem:
|
||||||
|
return QModelIndex()
|
||||||
|
|
||||||
|
return self.createIndex(parentItem.row(), 0, parentItem)
|
||||||
|
|
||||||
|
def rowCount(self, parent=QModelIndex()):
|
||||||
|
if parent.column() > 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
if not parent.isValid():
|
||||||
|
parentItem = self.rootItem
|
||||||
|
else:
|
||||||
|
parentItem = parent.internalPointer()
|
||||||
|
|
||||||
|
return parentItem.childCount()
|
||||||
|
|
||||||
|
def columnCount(self, parent=QModelIndex()):
|
||||||
|
if parent.isValid():
|
||||||
|
return parent.internalPointer().columnCount()
|
||||||
|
else:
|
||||||
|
return self.rootItem.columnCount()
|
||||||
|
|
||||||
|
def data(self, index, role=Qt.DisplayRole):
|
||||||
|
if not index.isValid():
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
item = index.internalPointer()
|
||||||
|
return item.data(index.column(), role)
|
||||||
|
|
||||||
|
def setData(self, index, value, role=Qt.EditRole):
|
||||||
|
item = index.internalPointer()
|
||||||
|
if item.data(index.column(), role) != value:
|
||||||
|
|
||||||
|
item.setData(index.column(), value, role)
|
||||||
|
|
||||||
|
# self.dataChanged.emit(index.sibling(index.row(), 0),
|
||||||
|
# index.sibling(index.row(), max([i.value for i in Outline])))
|
||||||
|
# print("Model emit", index.row(), index.column())
|
||||||
|
self.dataChanged.emit(index, index)
|
||||||
|
|
||||||
|
if index.column() == Outline.type:
|
||||||
|
# If type changed, then the icon of title changed.
|
||||||
|
# Some views might be glad to know it.
|
||||||
|
self.dataChanged.emit(index.sibling(index.row(), Outline.title),
|
||||||
|
index.sibling(index.row(), Outline.title))
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def headerData(self, section, orientation, role=Qt.DisplayRole):
|
||||||
|
if orientation == Qt.Horizontal and role in [Qt.DisplayRole, Qt.ToolTipRole]:
|
||||||
|
if section == Outline.title:
|
||||||
|
return self.tr("Title")
|
||||||
|
elif section == Outline.POV:
|
||||||
|
return self.tr("POV")
|
||||||
|
elif section == Outline.label:
|
||||||
|
return self.tr("Label")
|
||||||
|
elif section == Outline.status:
|
||||||
|
return self.tr("Status")
|
||||||
|
elif section == Outline.compile:
|
||||||
|
return self.tr("Compile")
|
||||||
|
elif section == Outline.wordCount:
|
||||||
|
return self.tr("Word count")
|
||||||
|
elif section == Outline.goal:
|
||||||
|
return self.tr("Goal")
|
||||||
|
elif section == Outline.goalPercentage:
|
||||||
|
return "%"
|
||||||
|
else:
|
||||||
|
return [i.name for i in Outline][section]
|
||||||
|
|
||||||
|
elif role == Qt.SizeHintRole:
|
||||||
|
if section == Outline.compile:
|
||||||
|
return QSize(40, 30)
|
||||||
|
elif section == Outline.goalPercentage:
|
||||||
|
return QSize(100, 30)
|
||||||
|
else:
|
||||||
|
return QVariant()
|
||||||
|
else:
|
||||||
|
return QVariant()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def maxLevel(self):
|
||||||
|
"""Returns the max depth of the model."""
|
||||||
|
def depth(item, d=-1):
|
||||||
|
d += 1
|
||||||
|
r = d
|
||||||
|
for c in item.children():
|
||||||
|
r = max(r, depth(c, d))
|
||||||
|
return r
|
||||||
|
|
||||||
|
d = depth(self.rootItem)
|
||||||
|
return d
|
||||||
|
|
||||||
|
#################### DRAG AND DROP ########################
|
||||||
|
# http://doc.qt.io/qt-5/model-view-programming.html#using-drag-and-drop-with-item-views
|
||||||
|
|
||||||
|
def flags(self, index):
|
||||||
|
# FIXME when dragging folders, sometimes flags is not called
|
||||||
|
|
||||||
|
flags = QAbstractItemModel.flags(self, index) | Qt.ItemIsEditable
|
||||||
|
|
||||||
|
if index.isValid() and index.internalPointer().isFolder() and index.column() == 0:
|
||||||
|
flags |= Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled
|
||||||
|
|
||||||
|
elif index.isValid() and index.column() == 0:
|
||||||
|
flags |= Qt.ItemIsDragEnabled
|
||||||
|
|
||||||
|
elif not index.isValid():
|
||||||
|
flags |= Qt.ItemIsDropEnabled
|
||||||
|
|
||||||
|
if index.isValid() and index.column() == Outline.compile:
|
||||||
|
flags |= Qt.ItemIsUserCheckable
|
||||||
|
|
||||||
|
if index.column() in [i.value for i in [Outline.wordCount, Outline.goalPercentage]]:
|
||||||
|
flags &= ~ Qt.ItemIsEditable
|
||||||
|
|
||||||
|
return flags
|
||||||
|
|
||||||
|
def mimeTypes(self):
|
||||||
|
return ["application/xml"]
|
||||||
|
|
||||||
|
def mimeData(self, indexes):
|
||||||
|
mimeData = QMimeData()
|
||||||
|
encodedData = ""
|
||||||
|
|
||||||
|
root = ET.Element("outlineItems")
|
||||||
|
|
||||||
|
for index in indexes:
|
||||||
|
if index.isValid() and index.column() == 0:
|
||||||
|
item = ET.XML(index.internalPointer().toXML())
|
||||||
|
root.append(item)
|
||||||
|
|
||||||
|
encodedData = ET.tostring(root)
|
||||||
|
|
||||||
|
mimeData.setData("application/xml", encodedData)
|
||||||
|
return mimeData
|
||||||
|
|
||||||
|
def supportedDropActions(self):
|
||||||
|
|
||||||
|
return Qt.CopyAction | Qt.MoveAction
|
||||||
|
|
||||||
|
def canDropMimeData(self, data, action, row, column, parent):
|
||||||
|
"""Ensures that we are not droping an item into itself."""
|
||||||
|
|
||||||
|
if not data.hasFormat("application/xml"):
|
||||||
|
return False
|
||||||
|
|
||||||
|
if column > 0:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# # Gets encoded mime data to retrieve the item
|
||||||
|
items = self.decodeMimeData(data)
|
||||||
|
if items is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# We check if parent is not a child of one of the items
|
||||||
|
if self.isParentAChildOfItems(parent, items):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def isParentAChildOfItems(self, parent, items):
|
||||||
|
"""
|
||||||
|
Takes a parent index, and a list of outlineItems items. Check whether
|
||||||
|
parent is in a child of one of the items.
|
||||||
|
Return True in that case, False if not.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Get the parent item
|
||||||
|
if not parent.isValid():
|
||||||
|
parentItem = self.rootItem
|
||||||
|
else:
|
||||||
|
parentItem = parent.internalPointer()
|
||||||
|
|
||||||
|
for item in items:
|
||||||
|
# Get parentItem's parents IDs in a list
|
||||||
|
path = parentItem.pathID() # path to item in the form [(ID, title), ...]
|
||||||
|
path = [ID for ID, title in path]
|
||||||
|
# Is item in the path? It would mean that it tries to get dropped
|
||||||
|
# as a children of himself.
|
||||||
|
if item.ID() in path:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def decodeMimeData(self, data):
|
||||||
|
if not data.hasFormat("application/xml"):
|
||||||
|
return None
|
||||||
|
encodedData = bytes(data.data("application/xml")).decode()
|
||||||
|
root = ET.XML(encodedData)
|
||||||
|
if root is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if root.tag != "outlineItems":
|
||||||
|
return None
|
||||||
|
|
||||||
|
items = []
|
||||||
|
for child in root:
|
||||||
|
if child.tag == "outlineItem":
|
||||||
|
item = outlineItem(xml=ET.tostring(child))
|
||||||
|
items.append(item)
|
||||||
|
|
||||||
|
# We remove every item whose parent is also in items, otherwise it gets
|
||||||
|
# duplicated. (https://github.com/olivierkes/manuskript/issues/169)
|
||||||
|
# For example if selecting:
|
||||||
|
# - Parent
|
||||||
|
# - Child
|
||||||
|
# And draging them, items encoded in mime data are: [Parent, Child],
|
||||||
|
# but Child is already contained in Parent, so if we do nothing we end
|
||||||
|
# up with:
|
||||||
|
# - Parent
|
||||||
|
# - Child
|
||||||
|
# - Child
|
||||||
|
|
||||||
|
newItems = items[:]
|
||||||
|
IDs = [i.ID() for i in items]
|
||||||
|
|
||||||
|
def checkIfChildIsPresent(item):
|
||||||
|
# Recursively check every children of item, to see if any is in
|
||||||
|
# the list of items to copy. If so, we remove it from the list.
|
||||||
|
for c in item.children():
|
||||||
|
# We check if children is in the selection
|
||||||
|
# and if it hasn't been removed yet
|
||||||
|
if c.ID() in IDs and c.ID() in [i.ID() for i in newItems]:
|
||||||
|
# Remove item by ID
|
||||||
|
newItems.remove([i for i in newItems if i.ID() == c.ID()][0])
|
||||||
|
checkIfChildIsPresent(c)
|
||||||
|
|
||||||
|
for i in items:
|
||||||
|
checkIfChildIsPresent(i)
|
||||||
|
|
||||||
|
items = newItems
|
||||||
|
|
||||||
|
return items
|
||||||
|
|
||||||
|
def dropMimeData(self, data, action, row, column, parent):
|
||||||
|
|
||||||
|
if action == Qt.IgnoreAction:
|
||||||
|
return True # What is that?
|
||||||
|
|
||||||
|
if action == Qt.MoveAction:
|
||||||
|
# Strangely, on some cases, we get a call to dropMimeData though
|
||||||
|
# self.canDropMimeData returned False.
|
||||||
|
# See https://github.com/olivierkes/manuskript/issues/169 to reproduce.
|
||||||
|
# So we double check for safety.
|
||||||
|
if not self.canDropMimeData(data, action, row, column, parent):
|
||||||
|
return False
|
||||||
|
|
||||||
|
items = self.decodeMimeData(data)
|
||||||
|
|
||||||
|
if items is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if column > 0:
|
||||||
|
column = 0
|
||||||
|
|
||||||
|
if row != -1:
|
||||||
|
beginRow = row
|
||||||
|
elif parent.isValid():
|
||||||
|
beginRow = self.rowCount(parent) + 1
|
||||||
|
else:
|
||||||
|
beginRow = self.rowCount() + 1
|
||||||
|
|
||||||
|
if action == Qt.CopyAction:
|
||||||
|
# Behavior if parent is a text item
|
||||||
|
# For example, we select a text and do: CTRL+C CTRL+V
|
||||||
|
if parent.isValid() and not parent.internalPointer().isFolder():
|
||||||
|
# We insert copy in parent folder, just below
|
||||||
|
beginRow = parent.row() + 1
|
||||||
|
parent = parent.parent()
|
||||||
|
|
||||||
|
if parent.isValid() and parent.internalPointer().isFolder():
|
||||||
|
while self.isParentAChildOfItems(parent, items):
|
||||||
|
# We are copying a folder on itself. Assume duplicates.
|
||||||
|
# Copy not in, but next to
|
||||||
|
beginRow = parent.row() + 1
|
||||||
|
parent = parent.parent()
|
||||||
|
|
||||||
|
if not items:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# In case of copy actions, items might be duplicates, so we need new IDs.
|
||||||
|
# But they might not be, if we cut, then paste. Paste is a Copy Action.
|
||||||
|
# The first paste would not need new IDs. But subsequent ones will.
|
||||||
|
if action == Qt.CopyAction:
|
||||||
|
IDs = self.rootItem.listAllIDs()
|
||||||
|
|
||||||
|
for item in items:
|
||||||
|
if item.ID() in IDs:
|
||||||
|
# Recursively remove ID. So will get a new one when inserted.
|
||||||
|
def stripID(item):
|
||||||
|
item.setData(Outline.ID, None)
|
||||||
|
for c in item.children():
|
||||||
|
stripID(c)
|
||||||
|
|
||||||
|
stripID(item)
|
||||||
|
|
||||||
|
r = self.insertItems(items, beginRow, parent)
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
|
################# ADDING AND REMOVING #################
|
||||||
|
|
||||||
|
def insertItem(self, item, row, parent=QModelIndex()):
|
||||||
|
return self.insertItems([item], row, parent)
|
||||||
|
|
||||||
|
def insertItems(self, items, row, parent=QModelIndex()):
|
||||||
|
if not parent.isValid():
|
||||||
|
parentItem = self.rootItem
|
||||||
|
else:
|
||||||
|
parentItem = parent.internalPointer()
|
||||||
|
|
||||||
|
if parent.isValid() and parent.column() != 0:
|
||||||
|
parent = parentItem.index()
|
||||||
|
|
||||||
|
# Insert only if parent is folder
|
||||||
|
if parentItem.isFolder():
|
||||||
|
self.beginInsertRows(parent, row, row + len(items) - 1)
|
||||||
|
|
||||||
|
for i in items:
|
||||||
|
parentItem.insertChild(row + items.index(i), i)
|
||||||
|
|
||||||
|
self.endInsertRows()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def appendItem(self, item, parent=QModelIndex()):
|
||||||
|
if not parent.isValid():
|
||||||
|
parentItem = self.rootItem
|
||||||
|
else:
|
||||||
|
parentItem = parent.internalPointer()
|
||||||
|
|
||||||
|
if parent.isValid() and parent.column() != 0:
|
||||||
|
parent = parentItem.index()
|
||||||
|
|
||||||
|
# If parent is folder, write into
|
||||||
|
if parentItem.isFolder():
|
||||||
|
self.insertItem(item, self.rowCount(parent), parent)
|
||||||
|
|
||||||
|
# If parent is not folder, write next to
|
||||||
|
else:
|
||||||
|
self.insertItem(item, parent.row() + 1, parent.parent())
|
||||||
|
|
||||||
|
def removeIndex(self, index):
|
||||||
|
item = index.internalPointer()
|
||||||
|
self.removeRow(item.row(), index.parent())
|
||||||
|
|
||||||
|
def removeIndexes(self, indexes):
|
||||||
|
levels = {}
|
||||||
|
for i in indexes:
|
||||||
|
item = i.internalPointer()
|
||||||
|
level = item.level()
|
||||||
|
if not level in levels:
|
||||||
|
levels[level] = []
|
||||||
|
levels[level].append([i.row(), i])
|
||||||
|
|
||||||
|
# Sort by level then by row
|
||||||
|
for l in reversed(sorted(levels.keys())):
|
||||||
|
rows = levels[l]
|
||||||
|
|
||||||
|
rows = list(reversed(sorted(rows, key=lambda x: x[0])))
|
||||||
|
for r in rows:
|
||||||
|
self.removeIndex(r[1])
|
||||||
|
|
||||||
|
def removeRow(self, row, parent=QModelIndex()):
|
||||||
|
return self.removeRows(row, 1, parent)
|
||||||
|
|
||||||
|
def removeRows(self, row, count, parent=QModelIndex()):
|
||||||
|
if not parent.isValid():
|
||||||
|
parentItem = self.rootItem
|
||||||
|
else:
|
||||||
|
parentItem = parent.internalPointer()
|
||||||
|
|
||||||
|
self._removingRows = True # Views that are updating can easily know
|
||||||
|
# if this is due to row removal.
|
||||||
|
self.beginRemoveRows(parent, row, row + count - 1)
|
||||||
|
for i in range(count):
|
||||||
|
item = parentItem.removeChild(row)
|
||||||
|
self.removed.append(item)
|
||||||
|
|
||||||
|
self._removingRows = False
|
||||||
|
self.endRemoveRows()
|
||||||
|
return True
|
||||||
|
|
||||||
|
# def insertRow(self, row, item, parent=QModelIndex()):
|
||||||
|
# self.beginInsertRows(parent, row, row)
|
||||||
|
|
||||||
|
# if not parent.isValid():
|
||||||
|
# parentItem = self.rootItem
|
||||||
|
# else:
|
||||||
|
# parentItem = parent.internalPointer()
|
||||||
|
|
||||||
|
# parentItem.insertChild(row, item)
|
||||||
|
|
||||||
|
# self.endInsertRows()
|
||||||
|
|
||||||
|
################# XML / saving / loading #################
|
||||||
|
|
||||||
|
def saveToXML(self, xml=None):
|
||||||
|
"If xml (filename) is given, saves the items to xml. Otherwise returns as string."
|
||||||
|
root = ET.XML(self.rootItem.toXML())
|
||||||
|
if xml:
|
||||||
|
ET.ElementTree(root).write(xml, encoding="UTF-8", xml_declaration=True, pretty_print=True)
|
||||||
|
else:
|
||||||
|
return ET.tostring(root, encoding="UTF-8", xml_declaration=True, pretty_print=True)
|
||||||
|
|
||||||
|
def loadFromXML(self, xml, fromString=False):
|
||||||
|
"Load from xml. Assume that xml is a filename. If fromString=True, xml is the content."
|
||||||
|
if not fromString:
|
||||||
|
root = ET.parse(xml)
|
||||||
|
else:
|
||||||
|
root = ET.fromstring(xml)
|
||||||
|
|
||||||
|
self.rootItem = outlineItem(model=self, xml=ET.tostring(root), ID="0")
|
||||||
|
self.rootItem.checkIDs()
|
||||||
|
|
||||||
|
def indexFromPath(self, path):
|
||||||
|
path = path.split(",")
|
||||||
|
item = self.rootItem
|
||||||
|
for p in path:
|
||||||
|
if p != "" and int(p) < item.childCount():
|
||||||
|
item = item.child(int(p))
|
||||||
|
return self.indexFromItem(item)
|
|
@ -296,4 +296,4 @@ class CharacterInfo():
|
||||||
def __init__(self, character, description="", value=""):
|
def __init__(self, character, description="", value=""):
|
||||||
self.description = description
|
self.description = description
|
||||||
self.value = value
|
self.value = value
|
||||||
self.character = character
|
self.character = character
|
||||||
|
|
497
manuskript/models/outlineItem.py
Normal file
497
manuskript/models/outlineItem.py
Normal file
|
@ -0,0 +1,497 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
import time
|
||||||
|
import locale
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
from PyQt5.QtGui import QFont, QIcon
|
||||||
|
from PyQt5.QtWidgets import qApp
|
||||||
|
from lxml import etree as ET
|
||||||
|
from manuskript.models.abstractItem import abstractItem
|
||||||
|
from manuskript import enums
|
||||||
|
from manuskript import functions as F
|
||||||
|
from manuskript import settings
|
||||||
|
from manuskript.converters import HTML2PlainText
|
||||||
|
|
||||||
|
try:
|
||||||
|
locale.setlocale(locale.LC_ALL, '')
|
||||||
|
except:
|
||||||
|
# Invalid locale, but not really a big deal because it's used only for
|
||||||
|
# number formating
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class outlineItem(abstractItem):
|
||||||
|
|
||||||
|
enum = enums.Outline
|
||||||
|
|
||||||
|
# Used for XML export
|
||||||
|
name = "outlineItem"
|
||||||
|
|
||||||
|
def __init__(self, model=None, title="", _type="folder", xml=None, parent=None, ID=None):
|
||||||
|
abstractItem.__init__(self, model, title, _type, xml, parent, ID)
|
||||||
|
|
||||||
|
self.defaultTextType = None
|
||||||
|
if not self._data.get(self.enum.compile):
|
||||||
|
self._data[self.enum.compile] = 2
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Properties
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def isFolder(self):
|
||||||
|
return self._data[self.enum.type] == "folder"
|
||||||
|
|
||||||
|
def isText(self):
|
||||||
|
return self._data[self.enum.type] == "md"
|
||||||
|
|
||||||
|
def isMD(self):
|
||||||
|
return self._data[self.enum.type] == "md"
|
||||||
|
|
||||||
|
def isMMD(self):
|
||||||
|
return self._data[self.enum.type] == "md"
|
||||||
|
|
||||||
|
def text(self):
|
||||||
|
return self.data(self.enum.text)
|
||||||
|
|
||||||
|
def compile(self):
|
||||||
|
if self._data.get(self.enum.compile, 1) in ["0", 0]:
|
||||||
|
return False
|
||||||
|
elif self.parent():
|
||||||
|
return self.parent().compile()
|
||||||
|
else:
|
||||||
|
return True # rootItem always compile
|
||||||
|
|
||||||
|
def POV(self):
|
||||||
|
return self.data(self.enum.POV)
|
||||||
|
|
||||||
|
def status(self):
|
||||||
|
return self.data(self.enum.status)
|
||||||
|
|
||||||
|
def label(self):
|
||||||
|
return self.data(self.enum.label)
|
||||||
|
|
||||||
|
def customIcon(self):
|
||||||
|
return self.data(self.enum.customIcon)
|
||||||
|
|
||||||
|
def setCustomIcon(self, customIcon):
|
||||||
|
self.setData(self.enum.customIcon, customIcon)
|
||||||
|
|
||||||
|
def wordCount(self):
|
||||||
|
return self._data.get(self.enum.wordCount, 0)
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Data
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def data(self, column, role=Qt.DisplayRole):
|
||||||
|
|
||||||
|
data = abstractItem.data(self, column, role)
|
||||||
|
E = self.enum
|
||||||
|
|
||||||
|
if role == Qt.DisplayRole or role == Qt.EditRole:
|
||||||
|
if data == "" and column == E.revisions:
|
||||||
|
return []
|
||||||
|
|
||||||
|
else:
|
||||||
|
return data
|
||||||
|
|
||||||
|
elif role == Qt.DecorationRole and column == E.title:
|
||||||
|
if self.customIcon():
|
||||||
|
return QIcon.fromTheme(self.data(E.customIcon))
|
||||||
|
if self.isFolder():
|
||||||
|
return QIcon.fromTheme("folder")
|
||||||
|
elif self.isText():
|
||||||
|
return QIcon.fromTheme("text-x-generic")
|
||||||
|
|
||||||
|
elif role == Qt.CheckStateRole and column == E.compile:
|
||||||
|
return Qt.Checked if self.compile() else Qt.Unchecked
|
||||||
|
|
||||||
|
elif role == Qt.FontRole:
|
||||||
|
f = QFont()
|
||||||
|
if column == E.wordCount and self.isFolder():
|
||||||
|
f.setItalic(True)
|
||||||
|
elif column == E.goal and self.isFolder() and not self.data(E.setGoal):
|
||||||
|
f.setItalic(True)
|
||||||
|
if self.isFolder():
|
||||||
|
f.setBold(True)
|
||||||
|
return f
|
||||||
|
|
||||||
|
def setData(self, column, data, role=Qt.DisplayRole):
|
||||||
|
|
||||||
|
E = self.enum
|
||||||
|
|
||||||
|
if column == E.text and self.isFolder():
|
||||||
|
# Folder have no text
|
||||||
|
return
|
||||||
|
|
||||||
|
if column == E.goal:
|
||||||
|
self._data[E.setGoal] = F.toInt(data) if F.toInt(data) > 0 else ""
|
||||||
|
|
||||||
|
# Checking if we will have to recount words
|
||||||
|
updateWordCount = False
|
||||||
|
if column in [E.wordCount, E.goal, E.setGoal]:
|
||||||
|
updateWordCount = not column in self._data or self._data[column] != data
|
||||||
|
|
||||||
|
# Stuff to do before
|
||||||
|
if column == E.text:
|
||||||
|
self.addRevision()
|
||||||
|
|
||||||
|
# Calling base class implementation
|
||||||
|
abstractItem.setData(self, column, data, role)
|
||||||
|
|
||||||
|
# Stuff to do afterwards
|
||||||
|
if column == E.text:
|
||||||
|
wc = F.wordCount(data)
|
||||||
|
self.setData(E.wordCount, wc)
|
||||||
|
|
||||||
|
if column == E.compile:
|
||||||
|
# Title changes when compile changes
|
||||||
|
self.emitDataChanged(cols=[E.title, E.compile],
|
||||||
|
recursive=True)
|
||||||
|
|
||||||
|
if column == E.customIcon:
|
||||||
|
# If custom icon changed, we tell views to update title (so that
|
||||||
|
# icons will be updated as well)
|
||||||
|
self.emitDataChanged(cols=[E.title])
|
||||||
|
|
||||||
|
if updateWordCount:
|
||||||
|
self.updateWordCount()
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Wordcount
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def insertChild(self, row, child):
|
||||||
|
abstractItem.insertChild(self, row, child)
|
||||||
|
self.updateWordCount()
|
||||||
|
|
||||||
|
def removeChild(self, row):
|
||||||
|
r = abstractItem.removeChild(self, row)
|
||||||
|
# Might be causing segfault when updateWordCount emits dataChanged
|
||||||
|
self.updateWordCount(emit=False)
|
||||||
|
return r
|
||||||
|
|
||||||
|
def updateWordCount(self, emit=True):
|
||||||
|
"""Update word count for item and parents.
|
||||||
|
If emit is False, no signal is emitted (sometimes cause segfault)"""
|
||||||
|
if not self.isFolder():
|
||||||
|
setGoal = F.toInt(self.data(self.enum.setGoal))
|
||||||
|
goal = F.toInt(self.data(self.enum.goal))
|
||||||
|
|
||||||
|
if goal != setGoal:
|
||||||
|
self._data[self.enum.goal] = setGoal
|
||||||
|
if setGoal:
|
||||||
|
wc = F.toInt(self.data(self.enum.wordCount))
|
||||||
|
self.setData(self.enum.goalPercentage, wc / float(setGoal))
|
||||||
|
|
||||||
|
else:
|
||||||
|
wc = 0
|
||||||
|
for c in self.children():
|
||||||
|
wc += F.toInt(c.data(self.enum.wordCount))
|
||||||
|
self._data[self.enum.wordCount] = wc
|
||||||
|
|
||||||
|
setGoal = F.toInt(self.data(self.enum.setGoal))
|
||||||
|
goal = F.toInt(self.data(self.enum.goal))
|
||||||
|
|
||||||
|
if setGoal:
|
||||||
|
if goal != setGoal:
|
||||||
|
self._data[self.enum.goal] = setGoal
|
||||||
|
goal = setGoal
|
||||||
|
else:
|
||||||
|
goal = 0
|
||||||
|
for c in self.children():
|
||||||
|
goal += F.toInt(c.data(self.enum.goal))
|
||||||
|
self._data[self.enum.goal] = goal
|
||||||
|
|
||||||
|
if goal:
|
||||||
|
self.setData(self.enum.goalPercentage, wc / float(goal))
|
||||||
|
else:
|
||||||
|
self.setData(self.enum.goalPercentage, "")
|
||||||
|
|
||||||
|
if emit:
|
||||||
|
self.emitDataChanged([self.enum.goal, self.enum.setGoal,
|
||||||
|
self.enum.wordCount, self.enum.goalPercentage])
|
||||||
|
|
||||||
|
if self.parent():
|
||||||
|
self.parent().updateWordCount(emit)
|
||||||
|
|
||||||
|
def stats(self):
|
||||||
|
wc = self.data(enums.Outline.wordCount)
|
||||||
|
goal = self.data(enums.Outline.goal)
|
||||||
|
progress = self.data(enums.Outline.goalPercentage)
|
||||||
|
if not wc:
|
||||||
|
wc = 0
|
||||||
|
if goal:
|
||||||
|
return qApp.translate("outlineItem", "{} words / {} ({})").format(
|
||||||
|
locale.format("%d", wc, grouping=True),
|
||||||
|
locale.format("%d", goal, grouping=True),
|
||||||
|
"{}%".format(str(int(progress * 100))))
|
||||||
|
else:
|
||||||
|
return qApp.translate("outlineItem", "{} words").format(
|
||||||
|
locale.format("%d", wc, grouping=True))
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Tools: split and merge
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def split(self, splitMark, recursive=True):
|
||||||
|
"""
|
||||||
|
Split scene at splitMark. If multiple splitMark, multiple splits.
|
||||||
|
|
||||||
|
If called on a folder and recursive is True, then it is recursively
|
||||||
|
applied to every children.
|
||||||
|
"""
|
||||||
|
if self.isFolder() and recursive:
|
||||||
|
for c in self.children():
|
||||||
|
c.split(splitMark)
|
||||||
|
|
||||||
|
else:
|
||||||
|
txt = self.text().split(splitMark)
|
||||||
|
|
||||||
|
if len(txt) == 1:
|
||||||
|
# Mark not found
|
||||||
|
return False
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
# Stores the new text
|
||||||
|
self.setData(self.enum.text, txt[0])
|
||||||
|
|
||||||
|
k = 1
|
||||||
|
for subTxt in txt[1:]:
|
||||||
|
# Create a copy
|
||||||
|
item = self.copy()
|
||||||
|
|
||||||
|
# Change title adding _k
|
||||||
|
item.setData(self.enum.title,
|
||||||
|
"{}_{}".format(item.title(), k+1))
|
||||||
|
|
||||||
|
# Set text
|
||||||
|
item.setData(self.enum.text, subTxt)
|
||||||
|
|
||||||
|
# Inserting item
|
||||||
|
#self.parent().insertChild(self.row()+k, item)
|
||||||
|
self._model.insertItem(item, self.row()+k, self.parent().index())
|
||||||
|
k += 1
|
||||||
|
|
||||||
|
def splitAt(self, position, length=0):
|
||||||
|
"""
|
||||||
|
Splits note at position p.
|
||||||
|
|
||||||
|
If length is bigger than 0, it describes the length of the title, made
|
||||||
|
from the character following position.
|
||||||
|
"""
|
||||||
|
|
||||||
|
txt = self.text()
|
||||||
|
|
||||||
|
# Stores the new text
|
||||||
|
self.setData(self.enum.text, txt[:position])
|
||||||
|
|
||||||
|
# Create a copy
|
||||||
|
item = self.copy()
|
||||||
|
|
||||||
|
# Update title
|
||||||
|
if length > 0:
|
||||||
|
title = txt[position:position+length].replace("\n", "")
|
||||||
|
else:
|
||||||
|
title = "{}_{}".format(item.title(), 2)
|
||||||
|
item.setData(self.enum.title, title)
|
||||||
|
|
||||||
|
# Set text
|
||||||
|
item.setData(self.enum.text, txt[position+length:])
|
||||||
|
|
||||||
|
# Inserting item using the model to signal views
|
||||||
|
self._model.insertItem(item, self.row()+1, self.parent().index())
|
||||||
|
|
||||||
|
def mergeWith(self, items, sep="\n\n"):
|
||||||
|
"""
|
||||||
|
Merges item with several other items. Merge is basic, it merges only
|
||||||
|
the text.
|
||||||
|
|
||||||
|
@param items: list of `outlineItem`s.
|
||||||
|
@param sep: a text added between each item's text.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Merges the texts
|
||||||
|
text = [self.text()]
|
||||||
|
text.extend([i.text() for i in items])
|
||||||
|
self.setData(self.enum.text, sep.join(text))
|
||||||
|
|
||||||
|
# Removes other items
|
||||||
|
self._model.removeIndexes([i.index() for i in items])
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# Search
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
def findItemsByPOV(self, POV):
|
||||||
|
"Returns a list of IDs of all subitems whose POV is ``POV``."
|
||||||
|
lst = []
|
||||||
|
if self.POV() == POV:
|
||||||
|
lst.append(self.ID())
|
||||||
|
|
||||||
|
for c in self.children():
|
||||||
|
lst.extend(c.findItemsByPOV(POV))
|
||||||
|
|
||||||
|
return lst
|
||||||
|
|
||||||
|
def findItemsContaining(self, text, columns, mainWindow=F.mainWindow(),
|
||||||
|
caseSensitive=False, recursive=True):
|
||||||
|
"""Returns a list if IDs of all subitems
|
||||||
|
containing ``text`` in columns ``columns``
|
||||||
|
(being a list of int).
|
||||||
|
"""
|
||||||
|
lst = self.itemContains(text, columns, mainWindow, caseSensitive)
|
||||||
|
|
||||||
|
if recursive:
|
||||||
|
for c in self.children():
|
||||||
|
lst.extend(c.findItemsContaining(text, columns, mainWindow, caseSensitive))
|
||||||
|
|
||||||
|
return lst
|
||||||
|
|
||||||
|
def itemContains(self, text, columns, mainWindow=F.mainWindow(),
|
||||||
|
caseSensitive=False):
|
||||||
|
lst = []
|
||||||
|
text = text.lower() if not caseSensitive else text
|
||||||
|
for c in columns:
|
||||||
|
|
||||||
|
if c == self.enum.POV and self.POV():
|
||||||
|
c = mainWindow.mdlCharacter.getCharacterByID(self.POV())
|
||||||
|
if c:
|
||||||
|
searchIn = c.name()
|
||||||
|
else:
|
||||||
|
searchIn = ""
|
||||||
|
print("Character POV not found:", self.POV())
|
||||||
|
|
||||||
|
elif c == self.enum.status:
|
||||||
|
searchIn = mainWindow.mdlStatus.item(F.toInt(self.status()), 0).text()
|
||||||
|
|
||||||
|
elif c == self.enum.label:
|
||||||
|
searchIn = mainWindow.mdlLabels.item(F.toInt(self.label()), 0).text()
|
||||||
|
|
||||||
|
else:
|
||||||
|
searchIn = self.data(c)
|
||||||
|
|
||||||
|
searchIn = searchIn.lower() if not caseSensitive else searchIn
|
||||||
|
|
||||||
|
if text in searchIn:
|
||||||
|
if not self.ID() in lst:
|
||||||
|
lst.append(self.ID())
|
||||||
|
|
||||||
|
return lst
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# REVISIONS
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
def revisions(self):
|
||||||
|
return self.data(self.enum.revisions)
|
||||||
|
|
||||||
|
def appendRevision(self, ts, text):
|
||||||
|
if not self.enum.revisions in self._data:
|
||||||
|
self._data[self.enum.revisions] = []
|
||||||
|
|
||||||
|
self._data[self.enum.revisions].append((
|
||||||
|
int(ts),
|
||||||
|
text))
|
||||||
|
|
||||||
|
def addRevision(self):
|
||||||
|
if not settings.revisions["keep"]:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.enum.text in self._data:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.appendRevision(
|
||||||
|
time.time(),
|
||||||
|
self.text())
|
||||||
|
|
||||||
|
if settings.revisions["smartremove"]:
|
||||||
|
self.cleanRevisions()
|
||||||
|
|
||||||
|
self.emitDataChanged([self.enum.revisions])
|
||||||
|
|
||||||
|
def deleteRevision(self, ts):
|
||||||
|
self._data[self.enum.revisions] = [r for r in self._data[self.enum.revisions] if r[0] != ts]
|
||||||
|
self.emitDataChanged([self.enum.revisions])
|
||||||
|
|
||||||
|
def clearAllRevisions(self):
|
||||||
|
self._data[self.enum.revisions] = []
|
||||||
|
self.emitDataChanged([self.enum.revisions])
|
||||||
|
|
||||||
|
def cleanRevisions(self):
|
||||||
|
"Keep only one some the revisions."
|
||||||
|
rev = self.revisions()
|
||||||
|
rev2 = []
|
||||||
|
now = time.time()
|
||||||
|
|
||||||
|
rule = settings.revisions["rules"]
|
||||||
|
|
||||||
|
revs = {}
|
||||||
|
for i in rule:
|
||||||
|
revs[i] = []
|
||||||
|
|
||||||
|
for r in rev:
|
||||||
|
# Have to put the lambda key otherwise cannot order when one element is None
|
||||||
|
for span in sorted(rule, key=lambda x: x if x else 60 * 60 * 24 * 30 * 365):
|
||||||
|
if not span or now - r[0] < span:
|
||||||
|
revs[span].append(r)
|
||||||
|
break
|
||||||
|
|
||||||
|
for span in revs:
|
||||||
|
sortedRev = sorted(revs[span], key=lambda x: x[0])
|
||||||
|
last = None
|
||||||
|
for r in sortedRev:
|
||||||
|
if not last:
|
||||||
|
rev2.append(r)
|
||||||
|
last = r[0]
|
||||||
|
elif r[0] - last >= rule[span]:
|
||||||
|
rev2.append(r)
|
||||||
|
last = r[0]
|
||||||
|
|
||||||
|
if rev2 != rev:
|
||||||
|
self._data[self.enum.revisions] = rev2
|
||||||
|
self.emitDataChanged([self.enum.revisions])
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
# XML
|
||||||
|
#######################################################################
|
||||||
|
|
||||||
|
# We don't want to write some datas (computed)
|
||||||
|
XMLExclude = [enums.Outline.wordCount,
|
||||||
|
enums.Outline.goal,
|
||||||
|
enums.Outline.goalPercentage,
|
||||||
|
enums.Outline.revisions]
|
||||||
|
# We want to force some data even if they're empty
|
||||||
|
XMLForce = [enums.Outline.compile]
|
||||||
|
|
||||||
|
def toXMLProcessItem(self, item):
|
||||||
|
|
||||||
|
# Saving revisions
|
||||||
|
rev = self.revisions()
|
||||||
|
for r in rev:
|
||||||
|
revItem = ET.Element("revision")
|
||||||
|
revItem.set("timestamp", str(r[0]))
|
||||||
|
revItem.set("text", r[1])
|
||||||
|
item.append(revItem)
|
||||||
|
|
||||||
|
return item
|
||||||
|
|
||||||
|
|
||||||
|
def setFromXMLProcessMore(self, root):
|
||||||
|
|
||||||
|
# If loading from an old file format, convert to md and
|
||||||
|
# remove html markup
|
||||||
|
if self.type() in ["txt", "t2t"]:
|
||||||
|
self.setData(Outline.type, "md")
|
||||||
|
|
||||||
|
elif self.type() == "html":
|
||||||
|
self.setData(Outline.type, "md")
|
||||||
|
self.setData(Outline.text, HTML2PlainText(self.data(Outline.text)))
|
||||||
|
self.setData(Outline.notes, HTML2PlainText(self.data(Outline.notes)))
|
||||||
|
|
||||||
|
# Revisions
|
||||||
|
for child in root:
|
||||||
|
if child.tag == "revision":
|
||||||
|
self.appendRevision(child.attrib["timestamp"], child.attrib["text"])
|
File diff suppressed because it is too large
Load diff
|
@ -28,8 +28,8 @@ class plotModel(QStandardItemModel):
|
||||||
def getPlotsByImportance(self):
|
def getPlotsByImportance(self):
|
||||||
plots = [[], [], []]
|
plots = [[], [], []]
|
||||||
for i in range(self.rowCount()):
|
for i in range(self.rowCount()):
|
||||||
importance = self.item(i, Plot.importance.value).text()
|
importance = self.item(i, Plot.importance).text()
|
||||||
ID = self.item(i, Plot.ID.value).text()
|
ID = self.item(i, Plot.ID).text()
|
||||||
plots[2 - toInt(importance)].append(ID)
|
plots[2 - toInt(importance)].append(ID)
|
||||||
return plots
|
return plots
|
||||||
|
|
||||||
|
@ -37,23 +37,23 @@ class plotModel(QStandardItemModel):
|
||||||
index = self.getIndexFromID(ID)
|
index = self.getIndexFromID(ID)
|
||||||
if not index.isValid():
|
if not index.isValid():
|
||||||
return
|
return
|
||||||
index = index.sibling(index.row(), Plot.steps.value)
|
index = index.sibling(index.row(), Plot.steps)
|
||||||
item = self.itemFromIndex(index)
|
item = self.itemFromIndex(index)
|
||||||
lst = []
|
lst = []
|
||||||
for i in range(item.rowCount()):
|
for i in range(item.rowCount()):
|
||||||
if item.child(i, PlotStep.ID.value):
|
if item.child(i, PlotStep.ID):
|
||||||
_ID = item.child(i, PlotStep.ID.value).text()
|
_ID = item.child(i, PlotStep.ID).text()
|
||||||
|
|
||||||
# Don't know why sometimes name is None (while drag'n'droping
|
# Don't know why sometimes name is None (while drag'n'droping
|
||||||
# several items)
|
# several items)
|
||||||
if item.child(i, PlotStep.name.value):
|
if item.child(i, PlotStep.name):
|
||||||
name = item.child(i, PlotStep.name.value).text()
|
name = item.child(i, PlotStep.name).text()
|
||||||
else:
|
else:
|
||||||
name = ""
|
name = ""
|
||||||
|
|
||||||
# Don't know why sometimes summary is None
|
# Don't know why sometimes summary is None
|
||||||
if item.child(i, PlotStep.summary.value):
|
if item.child(i, PlotStep.summary):
|
||||||
summary = item.child(i, PlotStep.summary.value).text()
|
summary = item.child(i, PlotStep.summary).text()
|
||||||
else:
|
else:
|
||||||
summary = ""
|
summary = ""
|
||||||
|
|
||||||
|
@ -62,17 +62,17 @@ class plotModel(QStandardItemModel):
|
||||||
|
|
||||||
def getPlotNameByID(self, ID):
|
def getPlotNameByID(self, ID):
|
||||||
for i in range(self.rowCount()):
|
for i in range(self.rowCount()):
|
||||||
_ID = self.item(i, Plot.ID.value).text()
|
_ID = self.item(i, Plot.ID).text()
|
||||||
if _ID == ID or toInt(_ID) == ID:
|
if _ID == ID or toInt(_ID) == ID:
|
||||||
name = self.item(i, Plot.name.value).text()
|
name = self.item(i, Plot.name).text()
|
||||||
return name
|
return name
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getPlotImportanceByID(self, ID):
|
def getPlotImportanceByID(self, ID):
|
||||||
for i in range(self.rowCount()):
|
for i in range(self.rowCount()):
|
||||||
_ID = self.item(i, Plot.ID.value).text()
|
_ID = self.item(i, Plot.ID).text()
|
||||||
if _ID == ID or toInt(_ID) == ID:
|
if _ID == ID or toInt(_ID) == ID:
|
||||||
importance = self.item(i, Plot.importance.value).text()
|
importance = self.item(i, Plot.importance).text()
|
||||||
return importance
|
return importance
|
||||||
return "0" # Default to "Minor"
|
return "0" # Default to "Minor"
|
||||||
|
|
||||||
|
@ -81,13 +81,13 @@ class plotModel(QStandardItemModel):
|
||||||
is ``subplotRaw``, of plot whose ID is ``plotID``.
|
is ``subplotRaw``, of plot whose ID is ``plotID``.
|
||||||
"""
|
"""
|
||||||
plotIndex = self.getIndexFromID(plotID)
|
plotIndex = self.getIndexFromID(plotID)
|
||||||
name = plotIndex.child(subplotRaw, PlotStep.name.value).data()
|
name = plotIndex.child(subplotRaw, PlotStep.name).data()
|
||||||
summary = plotIndex.child(subplotRaw, PlotStep.summary.value).data()
|
summary = plotIndex.child(subplotRaw, PlotStep.summary).data()
|
||||||
return name, summary
|
return name, summary
|
||||||
|
|
||||||
def getIndexFromID(self, ID):
|
def getIndexFromID(self, ID):
|
||||||
for i in range(self.rowCount()):
|
for i in range(self.rowCount()):
|
||||||
_ID = self.item(i, Plot.ID.value).text()
|
_ID = self.item(i, Plot.ID).text()
|
||||||
if _ID == ID or toInt(_ID) == ID:
|
if _ID == ID or toInt(_ID) == ID:
|
||||||
return self.index(i, 0)
|
return self.index(i, 0)
|
||||||
return QModelIndex()
|
return QModelIndex()
|
||||||
|
@ -115,8 +115,8 @@ class plotModel(QStandardItemModel):
|
||||||
parentItem = self.itemFromIndex(parent)
|
parentItem = self.itemFromIndex(parent)
|
||||||
vals = []
|
vals = []
|
||||||
for i in range(self.rowCount(parent)):
|
for i in range(self.rowCount(parent)):
|
||||||
index = self.index(i, Plot.ID.value, parent)
|
index = self.index(i, Plot.ID, parent)
|
||||||
# item = self.item(i, Plot.ID.value)
|
# item = self.item(i, Plot.ID)
|
||||||
if index.isValid() and index.data():
|
if index.isValid() and index.data():
|
||||||
vals.append(int(index.data()))
|
vals.append(int(index.data()))
|
||||||
|
|
||||||
|
@ -135,9 +135,9 @@ class plotModel(QStandardItemModel):
|
||||||
def headerData(self, section, orientation, role=Qt.DisplayRole):
|
def headerData(self, section, orientation, role=Qt.DisplayRole):
|
||||||
if role == Qt.DisplayRole:
|
if role == Qt.DisplayRole:
|
||||||
if orientation == Qt.Horizontal:
|
if orientation == Qt.Horizontal:
|
||||||
if section == PlotStep.name.value:
|
if section == PlotStep.name:
|
||||||
return self.tr("Name")
|
return self.tr("Name")
|
||||||
elif section == PlotStep.meta.value:
|
elif section == PlotStep.meta:
|
||||||
return self.tr("Meta")
|
return self.tr("Meta")
|
||||||
else:
|
else:
|
||||||
return ""
|
return ""
|
||||||
|
@ -148,8 +148,8 @@ class plotModel(QStandardItemModel):
|
||||||
|
|
||||||
def data(self, index, role=Qt.DisplayRole):
|
def data(self, index, role=Qt.DisplayRole):
|
||||||
if index.parent().isValid() and \
|
if index.parent().isValid() and \
|
||||||
index.parent().column() == Plot.steps.value and \
|
index.parent().column() == Plot.steps and \
|
||||||
index.column() == PlotStep.meta.value:
|
index.column() == PlotStep.meta:
|
||||||
if role == Qt.TextAlignmentRole:
|
if role == Qt.TextAlignmentRole:
|
||||||
return Qt.AlignRight | Qt.AlignVCenter
|
return Qt.AlignRight | Qt.AlignVCenter
|
||||||
elif role == Qt.ForegroundRole:
|
elif role == Qt.ForegroundRole:
|
||||||
|
@ -165,8 +165,8 @@ class plotModel(QStandardItemModel):
|
||||||
if not index.isValid():
|
if not index.isValid():
|
||||||
return
|
return
|
||||||
|
|
||||||
parent = index.sibling(index.row(), Plot.steps.value)
|
parent = index.sibling(index.row(), Plot.steps)
|
||||||
parentItem = self.item(index.row(), Plot.steps.value)
|
parentItem = self.item(index.row(), Plot.steps)
|
||||||
|
|
||||||
if not parentItem:
|
if not parentItem:
|
||||||
return
|
return
|
||||||
|
@ -216,10 +216,10 @@ class plotModel(QStandardItemModel):
|
||||||
def addPlotPerso(self, v):
|
def addPlotPerso(self, v):
|
||||||
index = self.mw.lstPlots.currentPlotIndex()
|
index = self.mw.lstPlots.currentPlotIndex()
|
||||||
if index.isValid():
|
if index.isValid():
|
||||||
if not self.item(index.row(), Plot.characters.value):
|
if not self.item(index.row(), Plot.characters):
|
||||||
self.setItem(index.row(), Plot.characters.value, QStandardItem())
|
self.setItem(index.row(), Plot.characters, QStandardItem())
|
||||||
|
|
||||||
item = self.item(index.row(), Plot.characters.value)
|
item = self.item(index.row(), Plot.characters)
|
||||||
|
|
||||||
# We check that the PersoID is not in the list yet
|
# We check that the PersoID is not in the list yet
|
||||||
for i in range(item.rowCount()):
|
for i in range(item.rowCount()):
|
||||||
|
|
|
@ -72,7 +72,7 @@ class plotsProxyModel(QSortFilterProxyModel):
|
||||||
self.mapModel()
|
self.mapModel()
|
||||||
|
|
||||||
def mapModelMaybe(self, topLeft, bottomRight):
|
def mapModelMaybe(self, topLeft, bottomRight):
|
||||||
if topLeft.column() <= Plot.importance.value <= bottomRight.column():
|
if topLeft.column() <= Plot.importance <= bottomRight.column():
|
||||||
self.mapModel()
|
self.mapModel()
|
||||||
|
|
||||||
def mapModel(self):
|
def mapModel(self):
|
||||||
|
@ -85,7 +85,7 @@ class plotsProxyModel(QSortFilterProxyModel):
|
||||||
self._map.append(self._cats[i])
|
self._map.append(self._cats[i])
|
||||||
|
|
||||||
for p in range(src.rowCount()):
|
for p in range(src.rowCount()):
|
||||||
item = src.item(p, Plot.importance.value)
|
item = src.item(p, Plot.importance)
|
||||||
|
|
||||||
if item:
|
if item:
|
||||||
imp = int(item.text())
|
imp = int(item.text())
|
||||||
|
|
|
@ -140,9 +140,9 @@ def infos(ref):
|
||||||
path = " > ".join(pathStr)
|
path = " > ".join(pathStr)
|
||||||
|
|
||||||
# Summaries and notes
|
# Summaries and notes
|
||||||
ss = item.data(Outline.summarySentence.value)
|
ss = item.data(Outline.summarySentence)
|
||||||
ls = item.data(Outline.summaryFull.value)
|
ls = item.data(Outline.summaryFull)
|
||||||
notes = item.data(Outline.notes.value)
|
notes = item.data(Outline.notes)
|
||||||
|
|
||||||
text = """<h1>{title}</h1>
|
text = """<h1>{title}</h1>
|
||||||
<p><b>{pathTitle}</b> {path}</p>
|
<p><b>{pathTitle}</b> {path}</p>
|
||||||
|
@ -187,6 +187,9 @@ def infos(ref):
|
||||||
elif _type == CharacterLetter:
|
elif _type == CharacterLetter:
|
||||||
m = mainWindow().mdlCharacter
|
m = mainWindow().mdlCharacter
|
||||||
c = m.getCharacterByID(int(_ref))
|
c = m.getCharacterByID(int(_ref))
|
||||||
|
if c is None:
|
||||||
|
return qApp.translate("references", "Unknown reference: {}.").format(ref)
|
||||||
|
|
||||||
index = c.index()
|
index = c.index()
|
||||||
|
|
||||||
name = c.name()
|
name = c.name()
|
||||||
|
@ -237,7 +240,7 @@ def infos(ref):
|
||||||
idx = oM.getIndexByID(t)
|
idx = oM.getIndexByID(t)
|
||||||
listPOV += "<li><a href='{link}'>{text}</a></li>".format(
|
listPOV += "<li><a href='{link}'>{text}</a></li>".format(
|
||||||
link=textReference(t),
|
link=textReference(t),
|
||||||
text=oM.data(idx, Outline.title.value))
|
text=oM.data(idx, Outline.title))
|
||||||
|
|
||||||
text = """<h1>{name}</h1>
|
text = """<h1>{name}</h1>
|
||||||
{goto}
|
{goto}
|
||||||
|
@ -267,6 +270,9 @@ def infos(ref):
|
||||||
index = m.getIndexFromID(_ref)
|
index = m.getIndexFromID(_ref)
|
||||||
name = m.getPlotNameByID(_ref)
|
name = m.getPlotNameByID(_ref)
|
||||||
|
|
||||||
|
if not index.isValid():
|
||||||
|
return qApp.translate("references", "Unknown reference: {}.").format(ref)
|
||||||
|
|
||||||
# Titles
|
# Titles
|
||||||
descriptionTitle = qApp.translate("references", "Description")
|
descriptionTitle = qApp.translate("references", "Description")
|
||||||
resultTitle = qApp.translate("references", "Result")
|
resultTitle = qApp.translate("references", "Result")
|
||||||
|
@ -279,15 +285,15 @@ def infos(ref):
|
||||||
|
|
||||||
# Description
|
# Description
|
||||||
description = m.data(index.sibling(index.row(),
|
description = m.data(index.sibling(index.row(),
|
||||||
Plot.description.value))
|
Plot.description))
|
||||||
|
|
||||||
# Result
|
# Result
|
||||||
result = m.data(index.sibling(index.row(),
|
result = m.data(index.sibling(index.row(),
|
||||||
Plot.result.value))
|
Plot.result))
|
||||||
|
|
||||||
# Characters
|
# Characters
|
||||||
pM = mainWindow().mdlCharacter
|
pM = mainWindow().mdlCharacter
|
||||||
item = m.item(index.row(), Plot.characters.value)
|
item = m.item(index.row(), Plot.characters)
|
||||||
characters = ""
|
characters = ""
|
||||||
if item:
|
if item:
|
||||||
for r in range(item.rowCount()):
|
for r in range(item.rowCount()):
|
||||||
|
@ -298,12 +304,12 @@ def infos(ref):
|
||||||
|
|
||||||
# Resolution steps
|
# Resolution steps
|
||||||
steps = ""
|
steps = ""
|
||||||
item = m.item(index.row(), Plot.steps.value)
|
item = m.item(index.row(), Plot.steps)
|
||||||
if item:
|
if item:
|
||||||
for r in range(item.rowCount()):
|
for r in range(item.rowCount()):
|
||||||
title = item.child(r, PlotStep.name.value).text()
|
title = item.child(r, PlotStep.name).text()
|
||||||
summary = item.child(r, PlotStep.summary.value).text()
|
summary = item.child(r, PlotStep.summary).text()
|
||||||
meta = item.child(r, PlotStep.meta.value).text()
|
meta = item.child(r, PlotStep.meta).text()
|
||||||
if meta:
|
if meta:
|
||||||
meta = " <span style='color:gray;'>({})</span>".format(meta)
|
meta = " <span style='color:gray;'>({})</span>".format(meta)
|
||||||
steps += "<li><b>{title}</b>{summary}{meta}</li>".format(
|
steps += "<li><b>{title}</b>{summary}{meta}</li>".format(
|
||||||
|
@ -343,6 +349,9 @@ def infos(ref):
|
||||||
index = m.indexByID(_ref)
|
index = m.indexByID(_ref)
|
||||||
name = m.name(index)
|
name = m.name(index)
|
||||||
|
|
||||||
|
if not index.isValid():
|
||||||
|
return qApp.translate("references", "Unknown reference: {}.").format(ref)
|
||||||
|
|
||||||
# Titles
|
# Titles
|
||||||
descriptionTitle = qApp.translate("references", "Description")
|
descriptionTitle = qApp.translate("references", "Description")
|
||||||
passionTitle = qApp.translate("references", "Passion")
|
passionTitle = qApp.translate("references", "Passion")
|
||||||
|
@ -532,7 +541,9 @@ def refToLink(ref):
|
||||||
|
|
||||||
elif _type == CharacterLetter:
|
elif _type == CharacterLetter:
|
||||||
m = mainWindow().mdlCharacter
|
m = mainWindow().mdlCharacter
|
||||||
text = m.getCharacterByID(int(_ref)).name()
|
c = m.getCharacterByID(int(_ref))
|
||||||
|
if c:
|
||||||
|
text = c.name()
|
||||||
|
|
||||||
elif _type == PlotLetter:
|
elif _type == PlotLetter:
|
||||||
m = mainWindow().mdlPlots
|
m = mainWindow().mdlPlots
|
||||||
|
@ -540,7 +551,9 @@ def refToLink(ref):
|
||||||
|
|
||||||
elif _type == WorldLetter:
|
elif _type == WorldLetter:
|
||||||
m = mainWindow().mdlWorld
|
m = mainWindow().mdlWorld
|
||||||
text = m.itemByID(_ref).text()
|
item = m.itemByID(_ref)
|
||||||
|
if item:
|
||||||
|
text = item.text()
|
||||||
|
|
||||||
if text:
|
if text:
|
||||||
return "<a href='{ref}'>{text}</a>".format(
|
return "<a href='{ref}'>{text}</a>".format(
|
||||||
|
@ -549,12 +562,10 @@ def refToLink(ref):
|
||||||
else:
|
else:
|
||||||
return ref
|
return ref
|
||||||
|
|
||||||
|
|
||||||
def linkifyAllRefs(text):
|
def linkifyAllRefs(text):
|
||||||
"""Takes all the references in ``text`` and transform them into HMTL links."""
|
"""Takes all the references in ``text`` and transform them into HMTL links."""
|
||||||
return re.sub(RegEx, lambda m: refToLink(m.group(0)), text)
|
return re.sub(RegEx, lambda m: refToLink(m.group(0)), text)
|
||||||
|
|
||||||
|
|
||||||
def findReferencesTo(ref, parent=None, recursive=True):
|
def findReferencesTo(ref, parent=None, recursive=True):
|
||||||
"""List of text items containing references ref, and returns IDs.
|
"""List of text items containing references ref, and returns IDs.
|
||||||
Starts from item parent. If None, starts from root."""
|
Starts from item parent. If None, starts from root."""
|
||||||
|
@ -570,8 +581,8 @@ def findReferencesTo(ref, parent=None, recursive=True):
|
||||||
ref2 = ref[:-1] + "}"
|
ref2 = ref[:-1] + "}"
|
||||||
|
|
||||||
# Since it's a simple search (no regex), we search for both.
|
# Since it's a simple search (no regex), we search for both.
|
||||||
lst = parent.findItemsContaining(ref, [Outline.notes.value], recursive=recursive)
|
lst = parent.findItemsContaining(ref, [Outline.notes], recursive=recursive)
|
||||||
lst += parent.findItemsContaining(ref2, [Outline.notes.value], recursive=recursive)
|
lst += parent.findItemsContaining(ref2, [Outline.notes], recursive=recursive)
|
||||||
|
|
||||||
return lst
|
return lst
|
||||||
|
|
||||||
|
@ -585,13 +596,12 @@ def listReferences(ref, title=qApp.translate("references", "Referenced in:")):
|
||||||
idx = oM.getIndexByID(t)
|
idx = oM.getIndexByID(t)
|
||||||
listRefs += "<li><a href='{link}'>{text}</a></li>".format(
|
listRefs += "<li><a href='{link}'>{text}</a></li>".format(
|
||||||
link=textReference(t),
|
link=textReference(t),
|
||||||
text=oM.data(idx, Outline.title.value))
|
text=oM.data(idx, Outline.title))
|
||||||
|
|
||||||
return "<h2>{title}</h2><ul>{ref}</ul>".format(
|
return "<h2>{title}</h2><ul>{ref}</ul>".format(
|
||||||
title=title,
|
title=title,
|
||||||
ref=listRefs) if listRefs else ""
|
ref=listRefs) if listRefs else ""
|
||||||
|
|
||||||
|
|
||||||
def basicFormat(text):
|
def basicFormat(text):
|
||||||
if not text:
|
if not text:
|
||||||
return ""
|
return ""
|
||||||
|
@ -599,7 +609,6 @@ def basicFormat(text):
|
||||||
text = linkifyAllRefs(text)
|
text = linkifyAllRefs(text)
|
||||||
return text
|
return text
|
||||||
|
|
||||||
|
|
||||||
def open(ref):
|
def open(ref):
|
||||||
"""Identify ``ref`` and open it."""
|
"""Identify ``ref`` and open it."""
|
||||||
match = re.fullmatch(RegEx, ref)
|
match = re.fullmatch(RegEx, ref)
|
||||||
|
|
|
@ -46,24 +46,24 @@ class worldModel(QStandardItemModel):
|
||||||
|
|
||||||
def ID(self, index):
|
def ID(self, index):
|
||||||
"""Returns the ID of the given index."""
|
"""Returns the ID of the given index."""
|
||||||
index = index.sibling(index.row(), World.ID.value)
|
index = index.sibling(index.row(), World.ID)
|
||||||
return self.data(index)
|
return self.data(index)
|
||||||
|
|
||||||
def name(self, index):
|
def name(self, index):
|
||||||
"""Returns the name of the given index."""
|
"""Returns the name of the given index."""
|
||||||
index = index.sibling(index.row(), World.name.value)
|
index = index.sibling(index.row(), World.name)
|
||||||
return self.data(index)
|
return self.data(index)
|
||||||
|
|
||||||
def description(self, index):
|
def description(self, index):
|
||||||
index = index.sibling(index.row(), World.description.value)
|
index = index.sibling(index.row(), World.description)
|
||||||
return self.data(index)
|
return self.data(index)
|
||||||
|
|
||||||
def conflict(self, index):
|
def conflict(self, index):
|
||||||
index = index.sibling(index.row(), World.conflict.value)
|
index = index.sibling(index.row(), World.conflict)
|
||||||
return self.data(index)
|
return self.data(index)
|
||||||
|
|
||||||
def passion(self, index):
|
def passion(self, index):
|
||||||
index = index.sibling(index.row(), World.passion.value)
|
index = index.sibling(index.row(), World.passion)
|
||||||
return self.data(index)
|
return self.data(index)
|
||||||
|
|
||||||
def itemID(self, item):
|
def itemID(self, item):
|
||||||
|
|
|
@ -46,9 +46,9 @@ autoSaveDelay = 5
|
||||||
autoSaveNoChanges = True
|
autoSaveNoChanges = True
|
||||||
autoSaveNoChangesDelay = 5
|
autoSaveNoChangesDelay = 5
|
||||||
saveOnQuit = True
|
saveOnQuit = True
|
||||||
outlineViewColumns = [Outline.title.value, Outline.POV.value, Outline.status.value,
|
outlineViewColumns = [Outline.title, Outline.POV, Outline.status,
|
||||||
Outline.compile.value, Outline.wordCount.value, Outline.goal.value,
|
Outline.compile, Outline.wordCount, Outline.goal,
|
||||||
Outline.goalPercentage.value, Outline.label.value]
|
Outline.goalPercentage, Outline.label]
|
||||||
corkBackground = {
|
corkBackground = {
|
||||||
"color": "#926239",
|
"color": "#926239",
|
||||||
"image": "writingdesk"
|
"image": "writingdesk"
|
||||||
|
|
|
@ -65,7 +65,9 @@ class settingsWindow(QWidget, Ui_Settings):
|
||||||
|
|
||||||
# General
|
# General
|
||||||
self.cmbStyle.addItems(list(QStyleFactory.keys()))
|
self.cmbStyle.addItems(list(QStyleFactory.keys()))
|
||||||
self.cmbStyle.setCurrentIndex([i.lower() for i in list(QStyleFactory.keys())].index(qApp.style().objectName()))
|
self.cmbStyle.setCurrentIndex(
|
||||||
|
[i.lower() for i in list(QStyleFactory.keys())]
|
||||||
|
.index(qApp.style().objectName()))
|
||||||
self.cmbStyle.currentIndexChanged[str].connect(self.setStyle)
|
self.cmbStyle.currentIndexChanged[str].connect(self.setStyle)
|
||||||
|
|
||||||
self.cmbTranslation.clear()
|
self.cmbTranslation.clear()
|
||||||
|
@ -75,13 +77,18 @@ class settingsWindow(QWidget, Ui_Settings):
|
||||||
tr["Español"] = "manuskript_es.qm"
|
tr["Español"] = "manuskript_es.qm"
|
||||||
tr["Deutsch"] = "manuskript_de.qm"
|
tr["Deutsch"] = "manuskript_de.qm"
|
||||||
tr["Svenska"] = "manuskript_sv.qm"
|
tr["Svenska"] = "manuskript_sv.qm"
|
||||||
|
self.translations = tr
|
||||||
|
|
||||||
for name in tr:
|
for name in tr:
|
||||||
self.cmbTranslation.addItem(name, tr[name])
|
self.cmbTranslation.addItem(name, tr[name])
|
||||||
|
|
||||||
sttgs = QSettings(qApp.organizationName(), qApp.applicationName())
|
sttgs = QSettings(qApp.organizationName(), qApp.applicationName())
|
||||||
if sttgs.contains("applicationTranslation") and sttgs.value("applicationTranslation") in tr.values():
|
if (sttgs.contains("applicationTranslation")
|
||||||
self.cmbTranslation.setCurrentText([i for i in tr if tr[i] == sttgs.value("applicationTranslation")][0])
|
and sttgs.value("applicationTranslation") in tr.values()):
|
||||||
|
# Sets the correct translation
|
||||||
|
self.cmbTranslation.setCurrentText(
|
||||||
|
[i for i in tr
|
||||||
|
if tr[i] == sttgs.value("applicationTranslation")][0])
|
||||||
|
|
||||||
self.cmbTranslation.currentIndexChanged.connect(self.setTranslation)
|
self.cmbTranslation.currentIndexChanged.connect(self.setTranslation)
|
||||||
|
|
||||||
|
@ -355,14 +362,14 @@ class settingsWindow(QWidget, Ui_Settings):
|
||||||
|
|
||||||
def outlineColumnsData(self):
|
def outlineColumnsData(self):
|
||||||
return {
|
return {
|
||||||
self.chkOutlineTitle: Outline.title.value,
|
self.chkOutlineTitle: Outline.title,
|
||||||
self.chkOutlinePOV: Outline.POV.value,
|
self.chkOutlinePOV: Outline.POV,
|
||||||
self.chkOutlineLabel: Outline.label.value,
|
self.chkOutlineLabel: Outline.label,
|
||||||
self.chkOutlineStatus: Outline.status.value,
|
self.chkOutlineStatus: Outline.status,
|
||||||
self.chkOutlineCompile: Outline.compile.value,
|
self.chkOutlineCompile: Outline.compile,
|
||||||
self.chkOutlineWordCount: Outline.wordCount.value,
|
self.chkOutlineWordCount: Outline.wordCount,
|
||||||
self.chkOutlineGoal: Outline.goal.value,
|
self.chkOutlineGoal: Outline.goal,
|
||||||
self.chkOutlinePercentage: Outline.goalPercentage.value,
|
self.chkOutlinePercentage: Outline.goalPercentage,
|
||||||
}
|
}
|
||||||
|
|
||||||
def outlineColumnsChanged(self):
|
def outlineColumnsChanged(self):
|
||||||
|
@ -571,8 +578,8 @@ class settingsWindow(QWidget, Ui_Settings):
|
||||||
# px = QPixmap(64, 64)
|
# px = QPixmap(64, 64)
|
||||||
# px.fill(iconColor(self.mw.mdlLabels.item(index.row()).icon()))
|
# px.fill(iconColor(self.mw.mdlLabels.item(index.row()).icon()))
|
||||||
# self.btnLabelColor.setIcon(QIcon(px))
|
# self.btnLabelColor.setIcon(QIcon(px))
|
||||||
self.btnLabelColor.setStyleSheet(
|
self.btnLabelColor.setStyleSheet("background:{};".format(
|
||||||
"background:{};".format(iconColor(self.mw.mdlLabels.item(index.row()).icon()).name()))
|
iconColor(self.mw.mdlLabels.item(index.row()).icon()).name()))
|
||||||
self.btnLabelColor.setEnabled(True)
|
self.btnLabelColor.setEnabled(True)
|
||||||
|
|
||||||
def addLabel(self):
|
def addLabel(self):
|
||||||
|
|
41
manuskript/tests/__init__.py
Normal file
41
manuskript/tests/__init__.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Tests."""
|
||||||
|
|
||||||
|
# METHOD 1
|
||||||
|
# ========
|
||||||
|
# Don't know why, this causes seg fault on SemaphoreCI
|
||||||
|
# Seg fault in app = QApplication(...)
|
||||||
|
# Workaround: create and discard an app first...
|
||||||
|
from PyQt5.QtWidgets import QApplication
|
||||||
|
QApplication([])
|
||||||
|
|
||||||
|
# Create app and mainWindow
|
||||||
|
from manuskript import main
|
||||||
|
app, MW = main.prepare(tests=True)
|
||||||
|
|
||||||
|
# FIXME: Again, don't know why, but when closing a project and then reopening
|
||||||
|
# one, we get a `TypeError: connection is not unique` in MainWindow:
|
||||||
|
# self.btnAddSubPlot.clicked.connect(self.updateSubPlotView, F.AUC)
|
||||||
|
# Yet the disconnectAll() function has been called.
|
||||||
|
# Workaround: we remove the necessity for connection to be unique. This
|
||||||
|
# works for now, but could create issues later one when we want to tests
|
||||||
|
# those specific functionnality. Maybe it will be called several times.
|
||||||
|
# At that moment, we will need to catch the exception in the MainWindow,
|
||||||
|
# or better: understand why it happens at all, and only on some signals.
|
||||||
|
from manuskript import functions as F
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
F.AUC = Qt.AutoConnection
|
||||||
|
|
||||||
|
# METHOD 2
|
||||||
|
# ========
|
||||||
|
# We need a qApplication to be running, or all the calls to qApp
|
||||||
|
# will throw a seg fault.
|
||||||
|
# from PyQt5.QtWidgets import QApplication
|
||||||
|
# app = QApplication([])
|
||||||
|
# app.setOrganizationName("manuskript_tests")
|
||||||
|
# app.setApplicationName("manuskript_tests")
|
||||||
|
|
||||||
|
# from manuskript.mainWindow import MainWindow
|
||||||
|
# MW = MainWindow()
|
73
manuskript/tests/conftest.py
Normal file
73
manuskript/tests/conftest.py
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Fixtures."""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def MW():
|
||||||
|
"""
|
||||||
|
Returns the mainWindow
|
||||||
|
"""
|
||||||
|
from manuskript import functions as F
|
||||||
|
MW = F.mainWindow()
|
||||||
|
assert MW is not None
|
||||||
|
assert MW == F.MW
|
||||||
|
|
||||||
|
return MW
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def MWNoProject(MW):
|
||||||
|
"""
|
||||||
|
Take the MainWindow and close andy possibly open project.
|
||||||
|
"""
|
||||||
|
MW.closeProject()
|
||||||
|
assert MW.currentProject is None
|
||||||
|
return MW
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def MWEmptyProject(MW):
|
||||||
|
"""
|
||||||
|
Creates a MainWindow and load an empty project.
|
||||||
|
"""
|
||||||
|
import tempfile
|
||||||
|
tf = tempfile.NamedTemporaryFile(suffix=".msk")
|
||||||
|
|
||||||
|
MW.closeProject()
|
||||||
|
assert MW.currentProject is None
|
||||||
|
MW.welcome.createFile(tf.name, overwrite=True)
|
||||||
|
assert MW.currentProject is not None
|
||||||
|
return MW
|
||||||
|
|
||||||
|
# If using with: @pytest.fixture(scope='session', autouse=True)
|
||||||
|
# yield MW
|
||||||
|
# # Properly destructed after. Otherwise: seg fault.
|
||||||
|
# MW.deleteLater()
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def MWSampleProject(MW):
|
||||||
|
"""
|
||||||
|
Creates a MainWindow and load a copy of the Acts sample project.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from manuskript import functions as F
|
||||||
|
import os
|
||||||
|
# Get the path of the first sample project. We assume it is here.
|
||||||
|
spDir = F.appPath("sample-projects")
|
||||||
|
lst = os.listdir(spDir)
|
||||||
|
# We assume it's saved in folder, so there is a `name.msk` file and a
|
||||||
|
# `name` folder.
|
||||||
|
src = [f for f in lst if f[-4:] == ".msk" and f[:-4] in lst][0]
|
||||||
|
src = os.path.join(spDir, src)
|
||||||
|
# Copy to a temp file
|
||||||
|
import tempfile
|
||||||
|
tf = tempfile.NamedTemporaryFile(suffix=".msk")
|
||||||
|
import shutil
|
||||||
|
shutil.copyfile(src, tf.name)
|
||||||
|
shutil.copytree(src[:-4], tf.name[:-4])
|
||||||
|
MW.closeProject()
|
||||||
|
MW.loadProject(tf.name)
|
||||||
|
assert MW.currentProject is not None
|
||||||
|
|
||||||
|
return MW
|
4
manuskript/tests/models/__init__.py
Normal file
4
manuskript/tests/models/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Tests for models."""
|
23
manuskript/tests/models/conftest.py
Normal file
23
manuskript/tests/models/conftest.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Conf for models."""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def outlineModelBasic(MWEmptyProject):
|
||||||
|
"""Returns an outlineModel with a few items:
|
||||||
|
* Folder
|
||||||
|
* Text
|
||||||
|
* Text
|
||||||
|
"""
|
||||||
|
from manuskript.models import outlineItem
|
||||||
|
mdl = MWEmptyProject.mdlOutline
|
||||||
|
|
||||||
|
root = mdl.rootItem
|
||||||
|
f = outlineItem(title="Folder", parent=root)
|
||||||
|
t1 = outlineItem(title="Text", _type="md", parent=f)
|
||||||
|
t2 = outlineItem(title="Text", _type="md", parent=root)
|
||||||
|
|
||||||
|
return mdl
|
161
manuskript/tests/models/test_outlineItem.py
Normal file
161
manuskript/tests/models/test_outlineItem.py
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Tests for outlineItem"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def outlineItemFolder():
|
||||||
|
'''Returns a folder outlineItem title "Folder".'''
|
||||||
|
from manuskript.models import outlineItem
|
||||||
|
return outlineItem(title="Folder")
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def outlineItemText():
|
||||||
|
'''Returns a text outlineItem title "Text".'''
|
||||||
|
from manuskript.models import outlineItem
|
||||||
|
return outlineItem(title="Text", _type="md")
|
||||||
|
|
||||||
|
def test_outlineItemsProperties(outlineItemFolder, outlineItemText):
|
||||||
|
"""
|
||||||
|
Tests with simple items, without parent or models.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
|
# Simplification
|
||||||
|
folder = outlineItemFolder
|
||||||
|
text = outlineItemText
|
||||||
|
|
||||||
|
# getters
|
||||||
|
assert folder.isFolder() == True
|
||||||
|
assert text.isFolder() == False
|
||||||
|
assert text.isText() == True
|
||||||
|
assert text.isMD() == text.isMMD() == True
|
||||||
|
assert text.title() == "Text"
|
||||||
|
assert text.compile() == True
|
||||||
|
assert folder.POV() == ""
|
||||||
|
assert folder.status() == ""
|
||||||
|
assert folder.label() == ""
|
||||||
|
assert folder.customIcon() == ""
|
||||||
|
assert folder.data(42) == ""
|
||||||
|
assert folder.data(folder.enum.title, role=Qt.CheckStateRole) == None
|
||||||
|
|
||||||
|
# setData and other setters
|
||||||
|
assert text.data(text.enum.compile, role=Qt.CheckStateRole) == Qt.Checked
|
||||||
|
text.setData(text.enum.compile, 0)
|
||||||
|
assert text.compile() == False
|
||||||
|
assert text.data(text.enum.compile, role=Qt.CheckStateRole) == Qt.Unchecked
|
||||||
|
folder.setCustomIcon("custom")
|
||||||
|
assert folder.customIcon() == "custom"
|
||||||
|
folder.setData(folder.enum.text, "Some text")
|
||||||
|
assert folder.text() == "" # folders have no text
|
||||||
|
|
||||||
|
# wordCount
|
||||||
|
text.setData(text.enum.text, "Sample **text**.")
|
||||||
|
assert text.wordCount() == 2
|
||||||
|
text.setData(text.enum.goal, 4)
|
||||||
|
assert text.data(text.enum.goalPercentage) == .5
|
||||||
|
|
||||||
|
# revisions
|
||||||
|
assert text.data(text.enum.revisions) == []
|
||||||
|
|
||||||
|
def test_modelStuff(outlineModelBasic):
|
||||||
|
"""
|
||||||
|
Tests with children items.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Simplification
|
||||||
|
model = outlineModelBasic
|
||||||
|
|
||||||
|
# Child count
|
||||||
|
root = model.rootItem
|
||||||
|
assert len(root.children()) == 2
|
||||||
|
folder = root.child(0)
|
||||||
|
text1 = folder.child(0)
|
||||||
|
text2 = root.child(1)
|
||||||
|
|
||||||
|
# Compile
|
||||||
|
assert text1.compile() == True
|
||||||
|
folder.setData(folder.enum.compile, 0)
|
||||||
|
assert text1.compile() == False
|
||||||
|
|
||||||
|
# Word count
|
||||||
|
text1.setData(text1.enum.text, "Sample text.")
|
||||||
|
assert text1.wordCount() == 2
|
||||||
|
assert folder.wordCount() == 2
|
||||||
|
statsWithGoal = folder.stats()
|
||||||
|
assert statsWithGoal != ""
|
||||||
|
text1.setData(text1.enum.setGoal, 4)
|
||||||
|
assert folder.data(folder.enum.goal) == 4
|
||||||
|
folder.setData(folder.enum.setGoal, 3)
|
||||||
|
assert folder.data(folder.enum.goal) == 3
|
||||||
|
assert folder.stats() != statsWithGoal
|
||||||
|
|
||||||
|
# Split and merge
|
||||||
|
text1.setData(text1.enum.text, "Sample\n---\ntext.")
|
||||||
|
folder.split("invalid mark")
|
||||||
|
assert folder.childCount() == 1
|
||||||
|
folder.split("\n---\n")
|
||||||
|
assert folder.childCount() == 2
|
||||||
|
text1.mergeWith([folder.child(1)])
|
||||||
|
assert text1.text() == "Sample\n\ntext."
|
||||||
|
text1.setData(text1.enum.text, "Sample\nNewTitle\ntext.")
|
||||||
|
text1.splitAt(7, 8)
|
||||||
|
assert folder.child(1).title() == "NewTitle"
|
||||||
|
folder.child(1).splitAt(3)
|
||||||
|
assert folder.child(2).title() == "NewTitle_2"
|
||||||
|
folder.removeChild(2)
|
||||||
|
folder.removeChild(1)
|
||||||
|
folder.removeChild(0)
|
||||||
|
assert folder.childCount() == 0
|
||||||
|
|
||||||
|
# Search
|
||||||
|
folder.appendChild(text2)
|
||||||
|
text2.setData(text2.enum.POV, 1)
|
||||||
|
folder.setData(folder.enum.POV, 1)
|
||||||
|
assert len(folder.findItemsByPOV(1)) == 2
|
||||||
|
folder.setData(folder.enum.label, 1) # Idea
|
||||||
|
folder.setData(folder.enum.status, 4) # Final
|
||||||
|
text2.setData(text2.enum.text, "Some final value.")
|
||||||
|
from manuskript.functions import MW
|
||||||
|
cols = [folder.enum.text, folder.enum.POV,
|
||||||
|
folder.enum.label, folder.enum.status]
|
||||||
|
assert folder.findItemsContaining("VALUE", cols, MW, True) == []
|
||||||
|
assert folder.findItemsContaining("VALUE", cols, MW, False) == [text2.ID()]
|
||||||
|
|
||||||
|
# Revisions
|
||||||
|
text2.clearAllRevisions()
|
||||||
|
assert text2.revisions() == []
|
||||||
|
text2.setData(text2.enum.text, "Some value.")
|
||||||
|
assert len(text2.revisions()) == 1
|
||||||
|
text2.setData(text2.enum.text, "Some new value.")
|
||||||
|
assert len(text2.revisions()) == 1 # Auto clean
|
||||||
|
text2.deleteRevision(text2.revisions()[0][0])
|
||||||
|
assert len(text2.revisions()) == 0
|
||||||
|
|
||||||
|
# Model, count and copy
|
||||||
|
k = folder._model
|
||||||
|
folder.setModel(14)
|
||||||
|
assert text2._model == 14
|
||||||
|
folder.setModel(k)
|
||||||
|
assert folder.columnCount() == len(folder.enum)
|
||||||
|
text1 = text2.copy()
|
||||||
|
assert text1.ID() is None
|
||||||
|
folder.appendChild(text1)
|
||||||
|
assert text1.ID() is not None
|
||||||
|
assert folder.childCountRecursive() == 2
|
||||||
|
assert text1.path() == "Folder > Text"
|
||||||
|
assert len(text1.pathID()) == 2
|
||||||
|
|
||||||
|
# IDs
|
||||||
|
folder2 = folder.copy()
|
||||||
|
text3 = text1.copy()
|
||||||
|
text3.setData(text3.enum.ID, "0")
|
||||||
|
folder2.appendChild(text3)
|
||||||
|
folder.appendChild(folder2)
|
||||||
|
assert text3.ID() == "0"
|
||||||
|
root.checkIDs()
|
||||||
|
assert text3.ID() != "0"
|
116
manuskript/tests/models/test_references.py
Normal file
116
manuskript/tests/models/test_references.py
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Tests for references.py"""
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
def test_references(MWSampleProject):
|
||||||
|
"""
|
||||||
|
Tests references using sample project.
|
||||||
|
"""
|
||||||
|
from manuskript.models import references as Ref
|
||||||
|
MW = MWSampleProject
|
||||||
|
|
||||||
|
# References
|
||||||
|
ref1 = Ref.plotReference("42", searchable=True)
|
||||||
|
ref2 = Ref.plotReference("42")
|
||||||
|
assert ref1 in ref2
|
||||||
|
|
||||||
|
ref1 = Ref.characterReference("42", searchable=True)
|
||||||
|
ref2 = Ref.characterReference("42")
|
||||||
|
assert ref1 in ref2
|
||||||
|
|
||||||
|
ref1 = Ref.textReference("42", searchable=True)
|
||||||
|
ref2 = Ref.textReference("42")
|
||||||
|
assert ref1 in ref2
|
||||||
|
|
||||||
|
ref1 = Ref.worldReference("42", searchable=True)
|
||||||
|
ref2 = Ref.worldReference("42")
|
||||||
|
assert ref1 in ref2
|
||||||
|
|
||||||
|
# Plots
|
||||||
|
mdlPlots = MW.mdlPlots
|
||||||
|
plotsImp = mdlPlots.getPlotsByImportance()
|
||||||
|
plots = []
|
||||||
|
[plots.extend(i) for i in plotsImp]
|
||||||
|
assert len(plots) == 3
|
||||||
|
plotID = plots[0]
|
||||||
|
assert "\n" in Ref.infos(Ref.plotReference(plotID))
|
||||||
|
assert "Not a ref" in Ref.infos("<invalid>")
|
||||||
|
assert "Unknown" in Ref.infos(Ref.plotReference("999"))
|
||||||
|
assert Ref.shortInfos(Ref.plotReference(plotID)) is not None
|
||||||
|
assert Ref.shortInfos(Ref.plotReference("999")) == None
|
||||||
|
assert Ref.shortInfos("<invalidref>") == -1
|
||||||
|
|
||||||
|
# Character
|
||||||
|
mdlChar = MW.mdlCharacter
|
||||||
|
IDs = [mdlChar.ID(r) for r in range(mdlChar.rowCount())]
|
||||||
|
assert len(IDs) == 6 # Peter, Paul, Philip, Stephen, Barnabas, Herod
|
||||||
|
charID = IDs[0]
|
||||||
|
assert "\n" in Ref.infos(Ref.characterReference(charID))
|
||||||
|
assert "Unknown" in Ref.infos(Ref.characterReference("999"))
|
||||||
|
assert Ref.shortInfos(Ref.characterReference(charID)) is not None
|
||||||
|
assert Ref.shortInfos(Ref.characterReference("999")) == None
|
||||||
|
assert Ref.shortInfos("<invalidref>") == -1
|
||||||
|
|
||||||
|
# Texts
|
||||||
|
mdlOutline = MW.mdlOutline
|
||||||
|
assert mdlOutline.rowCount() == 3 # Jerusalem, Samaria, Extremities
|
||||||
|
root = mdlOutline.rootItem
|
||||||
|
textID = root.child(0).ID()
|
||||||
|
|
||||||
|
assert "\n" in Ref.infos(Ref.textReference(textID))
|
||||||
|
assert "Unknown" in Ref.infos(Ref.textReference("999"))
|
||||||
|
assert Ref.shortInfos(Ref.textReference(textID)) is not None
|
||||||
|
assert Ref.shortInfos(Ref.textReference("999")) == None
|
||||||
|
assert Ref.shortInfos("<invalidref>") == -1
|
||||||
|
|
||||||
|
# World
|
||||||
|
mdlWorld = MW.mdlWorld
|
||||||
|
assert mdlWorld.rowCount() == 3 # Places, Culture, Travel
|
||||||
|
worldID = mdlWorld.itemID(mdlWorld.item(2).child(1))
|
||||||
|
|
||||||
|
assert "\n" in Ref.infos(Ref.worldReference(worldID))
|
||||||
|
assert "Unknown" in Ref.infos(Ref.worldReference("999"))
|
||||||
|
assert Ref.shortInfos(Ref.worldReference(worldID)) is not None
|
||||||
|
assert Ref.shortInfos(Ref.worldReference("999")) == None
|
||||||
|
assert Ref.shortInfos("<invalidref>") == -1
|
||||||
|
|
||||||
|
refs = [Ref.plotReference(plotID),
|
||||||
|
Ref.characterReference(charID),
|
||||||
|
Ref.textReference(textID),
|
||||||
|
Ref.worldReference(worldID),]
|
||||||
|
|
||||||
|
# Titles
|
||||||
|
for ref in refs:
|
||||||
|
assert Ref.title(ref) is not None
|
||||||
|
assert Ref.title("<invalid>") is None
|
||||||
|
assert Ref.title(Ref.plotReference("999")) is None
|
||||||
|
|
||||||
|
# Other stuff
|
||||||
|
assert Ref.type(Ref.plotReference(plotID)) == Ref.PlotLetter
|
||||||
|
assert Ref.ID(Ref.textReference(textID)) == textID
|
||||||
|
assert "Unknown" in Ref.tooltip(Ref.worldReference("999"))
|
||||||
|
assert "Not a ref" in Ref.tooltip("<invalid>")
|
||||||
|
for ref in refs:
|
||||||
|
assert Ref.tooltip(ref) is not None
|
||||||
|
|
||||||
|
# Links
|
||||||
|
assert Ref.refToLink("<invalid>") is None
|
||||||
|
assert Ref.refToLink(Ref.plotReference("999")) == Ref.plotReference("999")
|
||||||
|
assert Ref.refToLink(Ref.characterReference("999")) == Ref.characterReference("999")
|
||||||
|
assert Ref.refToLink(Ref.textReference("999")) == Ref.textReference("999")
|
||||||
|
assert Ref.refToLink(Ref.worldReference("999")) == Ref.worldReference("999")
|
||||||
|
for ref in refs:
|
||||||
|
assert "<a href" in Ref.refToLink(ref)
|
||||||
|
|
||||||
|
# Open
|
||||||
|
assert Ref.open("<invalid>") is None
|
||||||
|
assert Ref.open(Ref.plotReference("999")) == False
|
||||||
|
assert Ref.open(Ref.characterReference("999")) == False
|
||||||
|
assert Ref.open(Ref.textReference("999")) == False
|
||||||
|
assert Ref.open(Ref.worldReference("999")) == False
|
||||||
|
for ref in refs:
|
||||||
|
assert Ref.open(ref) == True
|
||||||
|
assert Ref.open(Ref.EmptyRef.format("Z", 14, "")) == False
|
96
manuskript/tests/test_functions.py
Normal file
96
manuskript/tests/test_functions.py
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Tests for functions"""
|
||||||
|
|
||||||
|
from manuskript import functions as F
|
||||||
|
|
||||||
|
def test_wordCount():
|
||||||
|
assert F.wordCount("In the beginning was the word.") == 6
|
||||||
|
assert F.wordCount("") == 0
|
||||||
|
|
||||||
|
def test_convert():
|
||||||
|
|
||||||
|
# toInt
|
||||||
|
assert F.toInt("9") == 9
|
||||||
|
assert F.toInt("a") == 0
|
||||||
|
assert F.toInt("") == 0
|
||||||
|
|
||||||
|
# toFloat
|
||||||
|
assert F.toFloat("9.4") == 9.4
|
||||||
|
assert F.toFloat("") == 0.
|
||||||
|
|
||||||
|
# toString
|
||||||
|
assert F.toString(None) == ""
|
||||||
|
assert F.toString("None") == ""
|
||||||
|
assert F.toString("Joy") == "Joy"
|
||||||
|
|
||||||
|
def test_several():
|
||||||
|
|
||||||
|
from PyQt5.QtGui import QPainter, QPixmap, QIcon, QColor
|
||||||
|
from PyQt5.QtCore import QRect
|
||||||
|
|
||||||
|
# drawProgress
|
||||||
|
px = QPixmap(10, 10)
|
||||||
|
F.drawProgress(QPainter(px), QRect(0, 0, 100, 100), 0.5)
|
||||||
|
|
||||||
|
# colorFromProgress
|
||||||
|
a = F.colorFromProgress(0.1)
|
||||||
|
b = F.colorFromProgress(0.5)
|
||||||
|
c = F.colorFromProgress(1.0)
|
||||||
|
d = F.colorFromProgress(1.5)
|
||||||
|
assert a != b != c != d
|
||||||
|
|
||||||
|
# iconColor & iconFromColor & iconFromColorString
|
||||||
|
icon = F.iconFromColorString("#ff0000")
|
||||||
|
assert F.iconColor(icon).name().lower() == "#ff0000"
|
||||||
|
|
||||||
|
# themeIcon
|
||||||
|
assert F.themeIcon("text") is not None
|
||||||
|
assert F.themeIcon("nonexistingname") is not None
|
||||||
|
|
||||||
|
# randomColor
|
||||||
|
c1 = F.randomColor()
|
||||||
|
c2 = F.randomColor(c1)
|
||||||
|
assert c1.name() != c2.name()
|
||||||
|
|
||||||
|
# mixColors
|
||||||
|
c1 = QColor("#FFF")
|
||||||
|
c2 = QColor("#000")
|
||||||
|
assert F.mixColors(c1, c2).name() == "#7f7f7f"
|
||||||
|
|
||||||
|
# colorifyPixmap
|
||||||
|
assert F.colorifyPixmap(px, c1) != None
|
||||||
|
|
||||||
|
def test_outlineItemColors():
|
||||||
|
|
||||||
|
from manuskript.models import outlineItem
|
||||||
|
item = outlineItem(title="Test")
|
||||||
|
|
||||||
|
r = F.outlineItemColors(item)
|
||||||
|
for i in ["POV", "Label", "Progress", "Compile"]:
|
||||||
|
assert i in r
|
||||||
|
from PyQt5.QtGui import QColor
|
||||||
|
assert r["Compile"].name(QColor.HexArgb) == "#00000000"
|
||||||
|
|
||||||
|
def test_paths():
|
||||||
|
|
||||||
|
assert F.appPath() is not None
|
||||||
|
assert F.writablePath is not None
|
||||||
|
assert len(F.allPaths("suffix")) == 2
|
||||||
|
assert F.tempFile("yop") is not None
|
||||||
|
f = F.findBackground("spacedreams.jpg")
|
||||||
|
assert "resources/backgrounds/spacedreams.jpg" in f
|
||||||
|
assert len(F.customIcons()) > 1
|
||||||
|
|
||||||
|
def test_mainWindow():
|
||||||
|
|
||||||
|
from PyQt5.QtWidgets import QWidget, QLCDNumber
|
||||||
|
|
||||||
|
assert F.mainWindow() is not None
|
||||||
|
assert F.MW is not None
|
||||||
|
|
||||||
|
F.statusMessage("Test")
|
||||||
|
F.printObjects()
|
||||||
|
assert len(F.findWidgetsOfClass(QWidget)) > 0
|
||||||
|
assert len(F.findWidgetsOfClass(QLCDNumber)) == 0
|
164
manuskript/tests/test_settingsWindow.py
Normal file
164
manuskript/tests/test_settingsWindow.py
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Tests for settingsWindow"""
|
||||||
|
|
||||||
|
from manuskript import functions as F
|
||||||
|
|
||||||
|
def test_general(MWSampleProject):
|
||||||
|
MW = MWSampleProject
|
||||||
|
|
||||||
|
# Loading from mainWindow
|
||||||
|
MW.actSettings.triggered.emit()
|
||||||
|
assert MW.sw.isVisible()
|
||||||
|
MW.sw.close()
|
||||||
|
MW.actLabels.triggered.emit()
|
||||||
|
assert MW.sw.isVisible()
|
||||||
|
MW.sw.close()
|
||||||
|
MW.actStatus.triggered.emit()
|
||||||
|
assert MW.sw.isVisible()
|
||||||
|
MW.sw.hide()
|
||||||
|
MW.sw.setTab("General")
|
||||||
|
|
||||||
|
SW = MW.sw
|
||||||
|
|
||||||
|
# Imports
|
||||||
|
from PyQt5.QtWidgets import qApp, QStyleFactory
|
||||||
|
from PyQt5.QtCore import QSettings, Qt
|
||||||
|
qS = QSettings(qApp.organizationName(), qApp.applicationName())
|
||||||
|
from manuskript import settings as S
|
||||||
|
|
||||||
|
# Style
|
||||||
|
assert SW.cmbStyle.count() == len(list(QStyleFactory.keys()))
|
||||||
|
if qS.value("applicationStyle"):
|
||||||
|
assert SW.cmbStyle.currentText() == qS.value("applicationStyle")
|
||||||
|
## Seg fault when trying to set the style in tests:
|
||||||
|
# for s in styles:
|
||||||
|
# SW.cmbStyle.setCurrentText(s)
|
||||||
|
# assert S.value("applicationStyle") == s
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
if qS.value("applicationTranslation"):
|
||||||
|
assert (SW.cmbTranslation.currentData()
|
||||||
|
== qS.value("applicationTranslation"))
|
||||||
|
for name in SW.translations:
|
||||||
|
SW.cmbTranslation.setCurrentText(name)
|
||||||
|
if qS.value("applicationTranslation"):
|
||||||
|
assert qS.value("applicationTranslation") == SW.translations[name]
|
||||||
|
|
||||||
|
def switchCheckBoxAndAssert(chk, settings):
|
||||||
|
"""
|
||||||
|
Asserts that the check state is that of settings, change checkstate
|
||||||
|
and asserts settings has been changed.
|
||||||
|
Settings is a function that returns the value.
|
||||||
|
"""
|
||||||
|
state = settings()
|
||||||
|
assert chk.isChecked() == state
|
||||||
|
chk.setChecked(not state)
|
||||||
|
assert chk.isChecked() is not state
|
||||||
|
|
||||||
|
# Loading and Saving
|
||||||
|
SW.txtAutoSave.setText("0")
|
||||||
|
SW.txtAutoSaveNoChanges.setText("0")
|
||||||
|
switchCheckBoxAndAssert(SW.chkAutoLoad,
|
||||||
|
lambda: qS.value("autoLoad", type=bool))
|
||||||
|
switchCheckBoxAndAssert(SW.chkAutoSave,
|
||||||
|
lambda: S.autoSave)
|
||||||
|
switchCheckBoxAndAssert(SW.chkAutoSaveNoChanges,
|
||||||
|
lambda: S.autoSaveNoChanges)
|
||||||
|
switchCheckBoxAndAssert(SW.chkSaveOnQuit,
|
||||||
|
lambda: S.saveOnQuit)
|
||||||
|
switchCheckBoxAndAssert(SW.chkSaveToZip,
|
||||||
|
lambda: S.saveToZip)
|
||||||
|
|
||||||
|
# Revisions
|
||||||
|
switchCheckBoxAndAssert(SW.chkRevisionsKeep,
|
||||||
|
lambda: S.revisions["keep"])
|
||||||
|
switchCheckBoxAndAssert(SW.chkRevisionRemove,
|
||||||
|
lambda: S.revisions["smartremove"])
|
||||||
|
|
||||||
|
# Views
|
||||||
|
# Simple way here, we just call the functions.
|
||||||
|
SW.cmbTreeIcon.currentIndexChanged.emit(0)
|
||||||
|
SW.cmbOutlineIcon.currentIndexChanged.emit(0)
|
||||||
|
SW.cmbCorkIcon.currentIndexChanged.emit(0)
|
||||||
|
SW.chkOutlineTitle.setChecked(Qt.Checked) #outlineColumnsChanged
|
||||||
|
SW.chkOutlineTitle.setChecked(Qt.Unchecked)
|
||||||
|
SW.chkOutlineTitle.setChecked(Qt.Checked)
|
||||||
|
# Can't test because of the dialog
|
||||||
|
# assert SW.setCorkColor() is None
|
||||||
|
SW.sldTreeIconSize.setValue(SW.sldTreeIconSize.value() + 1)
|
||||||
|
SW.rdoCorkNewStyle.toggled.emit(True)
|
||||||
|
SW.cmbCorkImage.currentIndexChanged.emit(0)
|
||||||
|
SW.cmbCorkImage.currentIndexChanged.emit(1)
|
||||||
|
# Test editor: same problem as above
|
||||||
|
# choseEditorFontColor
|
||||||
|
# choseEditorMisspelledColor
|
||||||
|
# choseEditorBackgroundColor
|
||||||
|
# Test editor
|
||||||
|
switchCheckBoxAndAssert(SW.chkEditorBackgroundTransparent,
|
||||||
|
lambda: S.textEditor["backgroundTransparent"])
|
||||||
|
assert SW.restoreEditorColors() is None
|
||||||
|
switchCheckBoxAndAssert(SW.chkEditorNoBlinking,
|
||||||
|
lambda: S.textEditor["cursorNotBlinking"])
|
||||||
|
# Twice on purpose: set and restore
|
||||||
|
switchCheckBoxAndAssert(SW.chkEditorNoBlinking,
|
||||||
|
lambda: S.textEditor["cursorNotBlinking"])
|
||||||
|
# Manually call updateAllWidgets, because other wise timer of 250ms
|
||||||
|
SW.updateAllWidgets()
|
||||||
|
|
||||||
|
# Labels
|
||||||
|
assert SW.updateLabelColor(MW.mdlLabels.item(1).index()) is None
|
||||||
|
rc = MW.mdlLabels.rowCount()
|
||||||
|
SW.addLabel()
|
||||||
|
SW.lstLabels.setCurrentIndex(
|
||||||
|
MW.mdlLabels.item(MW.mdlLabels.rowCount() - 1).index())
|
||||||
|
SW.removeLabel()
|
||||||
|
assert MW.mdlLabels.rowCount() == rc
|
||||||
|
# setLabelColor # Same problem as above
|
||||||
|
|
||||||
|
# Status
|
||||||
|
rc = MW.mdlStatus.rowCount()
|
||||||
|
SW.addStatus()
|
||||||
|
SW.lstStatus.setCurrentIndex(
|
||||||
|
MW.mdlStatus.item(MW.mdlStatus.rowCount() - 1).index())
|
||||||
|
SW.removeStatus()
|
||||||
|
assert MW.mdlStatus.rowCount() == rc
|
||||||
|
|
||||||
|
# Fullscreen
|
||||||
|
# self.lstThemes.currentItemChanged.connect(self.themeSelected)
|
||||||
|
item = SW.lstThemes.item(0)
|
||||||
|
SW.lstThemes.currentItemChanged.emit(item, None)
|
||||||
|
assert S.fullScreenTheme in item.data(Qt.UserRole)
|
||||||
|
SW.lstThemes.currentItemChanged.emit(None, None)
|
||||||
|
count = SW.lstThemes.count()
|
||||||
|
SW.newTheme()
|
||||||
|
assert SW.lstThemes.count() == count + 1
|
||||||
|
SW.newTheme() # theme with same name
|
||||||
|
item = SW.lstThemes.item(SW.lstThemes.count() - 1)
|
||||||
|
SW.lstThemes.setCurrentItem(item)
|
||||||
|
SW.removeTheme()
|
||||||
|
item = SW.lstThemes.item(count)
|
||||||
|
SW.lstThemes.setCurrentItem(item)
|
||||||
|
SW.editTheme()
|
||||||
|
switchCheckBoxAndAssert(SW.chkThemeIndent,
|
||||||
|
lambda: SW._themeData["Spacings/IndentFirstLine"])
|
||||||
|
SW.updateThemeFont(None)
|
||||||
|
SW.updateThemeBackground(0)
|
||||||
|
SW.updateThemeBackground(1)
|
||||||
|
SW.spnThemeLineSpacing.setValue(123)
|
||||||
|
for i in range(4):
|
||||||
|
SW.updateLineSpacing(i)
|
||||||
|
SW.updateUIFromTheme() # No time to wait on timer
|
||||||
|
assert SW._editingTheme is not None
|
||||||
|
SW.resize(SW.geometry().size()) # resizeEvent
|
||||||
|
#TODO: other edit test (see SW.loadTheme
|
||||||
|
SW.saveTheme()
|
||||||
|
item = SW.lstThemes.item(count)
|
||||||
|
SW.lstThemes.setCurrentItem(item)
|
||||||
|
SW.editTheme()
|
||||||
|
SW.cancelEdit()
|
||||||
|
item = SW.lstThemes.item(count)
|
||||||
|
SW.lstThemes.setCurrentItem(item)
|
||||||
|
SW.removeTheme()
|
||||||
|
assert SW.lstThemes.count() == count
|
4
manuskript/tests/ui/__init__.py
Normal file
4
manuskript/tests/ui/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Tests for stuff in ui."""
|
4
manuskript/tests/ui/exporters/__init__.py
Normal file
4
manuskript/tests/ui/exporters/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Tests for exporters, ui part."""
|
27
manuskript/tests/ui/exporters/test_exporters.py
Normal file
27
manuskript/tests/ui/exporters/test_exporters.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Tests for settingsWindow"""
|
||||||
|
|
||||||
|
def test_loadExportWiget(MWSampleProject):
|
||||||
|
"""
|
||||||
|
Simply tests that export widget loads properly.
|
||||||
|
"""
|
||||||
|
MW = MWSampleProject
|
||||||
|
|
||||||
|
# Loading from mainWindow
|
||||||
|
MW.doCompile()
|
||||||
|
E = MW.dialog
|
||||||
|
assert E.isVisible()
|
||||||
|
E.hide()
|
||||||
|
|
||||||
|
# Load exporter manager
|
||||||
|
E.openManager()
|
||||||
|
EM = E.dialog
|
||||||
|
assert EM.isVisible()
|
||||||
|
EM.hide()
|
||||||
|
|
||||||
|
EM.close()
|
||||||
|
E.close()
|
||||||
|
|
||||||
|
#FIXME: test significant stuff
|
4
manuskript/tests/ui/importers/__init__.py
Normal file
4
manuskript/tests/ui/importers/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Tests for importers, ui part."""
|
19
manuskript/tests/ui/importers/test_importers.py
Normal file
19
manuskript/tests/ui/importers/test_importers.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Tests for settingsWindow"""
|
||||||
|
|
||||||
|
def test_loadImportWiget(MWSampleProject):
|
||||||
|
"""
|
||||||
|
Simply tests that import widget loads properly.
|
||||||
|
"""
|
||||||
|
MW = MWSampleProject
|
||||||
|
|
||||||
|
# Loading from mainWindow
|
||||||
|
MW.doImport()
|
||||||
|
I = MW.dialog
|
||||||
|
assert I.isVisible()
|
||||||
|
I.hide()
|
||||||
|
I.close()
|
||||||
|
|
||||||
|
#FIXME: test significant stuff
|
22
manuskript/tests/ui/test_welcome.py
Normal file
22
manuskript/tests/ui/test_welcome.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# --!-- coding: utf8 --!--
|
||||||
|
|
||||||
|
"""Tests for the welcome widget."""
|
||||||
|
|
||||||
|
def test_autoLoad(MWNoProject):
|
||||||
|
"""
|
||||||
|
Tests for the welcome widget using MainWindow with no open project.
|
||||||
|
"""
|
||||||
|
MW = MWNoProject
|
||||||
|
from PyQt5.QtCore import QSettings
|
||||||
|
|
||||||
|
# Testing when no autoLoad
|
||||||
|
QSettings().remove("autoLoad")
|
||||||
|
autoLoad, path = MW.welcome.getAutoLoadValues()
|
||||||
|
assert type(autoLoad) == bool
|
||||||
|
assert autoLoad == False
|
||||||
|
|
||||||
|
for v in [True, False, 42, "42", None, True]:
|
||||||
|
MW.welcome.setAutoLoad(v)
|
||||||
|
autoLoad, path = MW.welcome.getAutoLoadValues()
|
||||||
|
assert type(autoLoad) == bool
|
|
@ -105,9 +105,9 @@ class cheatSheet(QWidget, Ui_cheatSheet):
|
||||||
d = []
|
d = []
|
||||||
|
|
||||||
for r in range(self.plotModel.rowCount()):
|
for r in range(self.plotModel.rowCount()):
|
||||||
name = self.plotModel.item(r, Plot.name.value).text()
|
name = self.plotModel.item(r, Plot.name).text()
|
||||||
ID = self.plotModel.item(r, Plot.ID.value).text()
|
ID = self.plotModel.item(r, Plot.ID).text()
|
||||||
imp = self.plotModel.item(r, Plot.importance.value).text()
|
imp = self.plotModel.item(r, Plot.importance).text()
|
||||||
imp = [self.tr("Minor"), self.tr("Secondary"), self.tr("Main")][int(imp)]
|
imp = [self.tr("Minor"), self.tr("Secondary"), self.tr("Main")][int(imp)]
|
||||||
d.append((name, ID, imp))
|
d.append((name, ID, imp))
|
||||||
|
|
||||||
|
|
|
@ -273,9 +273,9 @@ class fullScreenEditor(QWidget):
|
||||||
if self._index:
|
if self._index:
|
||||||
item = self._index.internalPointer()
|
item = self._index.internalPointer()
|
||||||
|
|
||||||
wc = item.data(Outline.wordCount.value)
|
wc = item.data(Outline.wordCount)
|
||||||
goal = item.data(Outline.goal.value)
|
goal = item.data(Outline.goal)
|
||||||
pg = item.data(Outline.goalPercentage.value)
|
pg = item.data(Outline.goalPercentage)
|
||||||
|
|
||||||
if goal:
|
if goal:
|
||||||
rect = self.lblProgress.geometry()
|
rect = self.lblProgress.geometry()
|
||||||
|
|
|
@ -301,9 +301,9 @@ class mainEditor(QWidget, Ui_mainEditor):
|
||||||
if not item:
|
if not item:
|
||||||
item = self.mw.mdlOutline.rootItem
|
item = self.mw.mdlOutline.rootItem
|
||||||
|
|
||||||
wc = item.data(Outline.wordCount.value)
|
wc = item.data(Outline.wordCount)
|
||||||
goal = item.data(Outline.goal.value)
|
goal = item.data(Outline.goal)
|
||||||
progress = item.data(Outline.goalPercentage.value)
|
progress = item.data(Outline.goalPercentage)
|
||||||
# mw = qApp.activeWindow()
|
# mw = qApp.activeWindow()
|
||||||
|
|
||||||
if not wc:
|
if not wc:
|
||||||
|
|
|
@ -4,7 +4,7 @@ from PyQt5.QtGui import QIcon
|
||||||
from PyQt5.QtWidgets import QWidget, QAction
|
from PyQt5.QtWidgets import QWidget, QAction
|
||||||
|
|
||||||
from manuskript.enums import Outline
|
from manuskript.enums import Outline
|
||||||
from manuskript.models.outlineModel import outlineModel
|
from manuskript.models import outlineModel
|
||||||
from manuskript.ui.editors.textFormat_ui import Ui_textFormat
|
from manuskript.ui.editors.textFormat_ui import Ui_textFormat
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ class textFormat(QWidget, Ui_textFormat):
|
||||||
self.setVisible(False)
|
self.setVisible(False)
|
||||||
return
|
return
|
||||||
|
|
||||||
if index.column() not in [Outline.text.value, Outline.notes.value]:
|
if index.column() not in [Outline.text, Outline.notes]:
|
||||||
self.setVisible(False)
|
self.setVisible(False)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ class generalSettings(QWidget, Ui_generalSettings):
|
||||||
# TreeView to select parent
|
# TreeView to select parent
|
||||||
# We use a proxy to display only folders
|
# We use a proxy to display only folders
|
||||||
proxy = QSortFilterProxyModel()
|
proxy = QSortFilterProxyModel()
|
||||||
proxy.setFilterKeyColumn(Outline.type.value)
|
proxy.setFilterKeyColumn(Outline.type)
|
||||||
proxy.setFilterFixedString("folder")
|
proxy.setFilterFixedString("folder")
|
||||||
proxy.setSourceModel(self.mw.mdlOutline)
|
proxy.setSourceModel(self.mw.mdlOutline)
|
||||||
self.treeGeneralParent.setModel(proxy)
|
self.treeGeneralParent.setModel(proxy)
|
||||||
|
|
|
@ -12,7 +12,7 @@ from manuskript.ui.importers.importer_ui import Ui_importer
|
||||||
from manuskript.ui.importers.generalSettings import generalSettings
|
from manuskript.ui.importers.generalSettings import generalSettings
|
||||||
from manuskript.ui import style
|
from manuskript.ui import style
|
||||||
from manuskript import importer
|
from manuskript import importer
|
||||||
from manuskript.models.outlineModel import outlineModel, outlineItem
|
from manuskript.models import outlineModel, outlineItem
|
||||||
from manuskript.enums import Outline
|
from manuskript.enums import Outline
|
||||||
from manuskript.exporter.pandoc import pandocExporter
|
from manuskript.exporter.pandoc import pandocExporter
|
||||||
|
|
||||||
|
@ -312,7 +312,7 @@ class importerDialog(QWidget, Ui_importer):
|
||||||
if self.settingsWidget.trimLongTitles():
|
if self.settingsWidget.trimLongTitles():
|
||||||
for item in items:
|
for item in items:
|
||||||
if len(item.title()) > 32:
|
if len(item.title()) > 32:
|
||||||
item.setData(Outline.title.value, item.title()[:32])
|
item.setData(Outline.title, item.title()[:32])
|
||||||
|
|
||||||
# Split at
|
# Split at
|
||||||
if self.settingsWidget.splitScenes():
|
if self.settingsWidget.splitScenes():
|
||||||
|
|
|
@ -84,7 +84,7 @@ class revisions(QWidget, Ui_revisions):
|
||||||
|
|
||||||
def updateMaybe(self, topLeft, bottomRight):
|
def updateMaybe(self, topLeft, bottomRight):
|
||||||
if self._index and \
|
if self._index and \
|
||||||
topLeft.column() <= Outline.revisions.value <= bottomRight.column() and \
|
topLeft.column() <= Outline.revisions <= bottomRight.column() and \
|
||||||
topLeft.row() <= self._index.row() <= bottomRight.row():
|
topLeft.row() <= self._index.row() <= bottomRight.row():
|
||||||
# self.update()
|
# self.update()
|
||||||
self.updateTimer.start()
|
self.updateTimer.start()
|
||||||
|
@ -228,9 +228,9 @@ class revisions(QWidget, Ui_revisions):
|
||||||
ts = i.data(Qt.UserRole)
|
ts = i.data(Qt.UserRole)
|
||||||
item = self._index.internalPointer()
|
item = self._index.internalPointer()
|
||||||
textBefore = [r[1] for r in item.revisions() if r[0] == ts][0]
|
textBefore = [r[1] for r in item.revisions() if r[0] == ts][0]
|
||||||
index = self._index.sibling(self._index.row(), Outline.text.value)
|
index = self._index.sibling(self._index.row(), Outline.text)
|
||||||
self._index.model().setData(index, textBefore)
|
self._index.model().setData(index, textBefore)
|
||||||
# item.setData(Outline.text.value, textBefore)
|
# item.setData(Outline.text, textBefore)
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
i = self.list.currentItem()
|
i = self.list.currentItem()
|
||||||
|
|
|
@ -86,14 +86,14 @@ class search(QWidget, Ui_search):
|
||||||
|
|
||||||
# Chosing the right columns
|
# Chosing the right columns
|
||||||
lstColumns = [
|
lstColumns = [
|
||||||
("Title", Outline.title.value),
|
("Title", Outline.title),
|
||||||
("Text", Outline.text.value),
|
("Text", Outline.text),
|
||||||
("Summary", Outline.summarySentence.value),
|
("Summary", Outline.summarySentence),
|
||||||
("Summary", Outline.summaryFull.value),
|
("Summary", Outline.summaryFull),
|
||||||
("Notes", Outline.notes.value),
|
("Notes", Outline.notes),
|
||||||
("POV", Outline.POV.value),
|
("POV", Outline.POV),
|
||||||
("Status", Outline.status.value),
|
("Status", Outline.status),
|
||||||
("Label", Outline.label.value),
|
("Label", Outline.label),
|
||||||
]
|
]
|
||||||
columns = [c[1] for c in lstColumns if self.options[c[0]] or self.options["All"]]
|
columns = [c[1] for c in lstColumns if self.options[c[0]] or self.options["All"]]
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,9 @@ class basicItemView(QWidget, Ui_basicItemView):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QWidget.__init__(self)
|
QWidget.__init__(self)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.txtSummarySentence.setColumn(Outline.summarySentence.value)
|
self.txtSummarySentence.setColumn(Outline.summarySentence)
|
||||||
self.txtSummaryFull.setColumn(Outline.summaryFull.value)
|
self.txtSummaryFull.setColumn(Outline.summaryFull)
|
||||||
self.txtGoal.setColumn(Outline.setGoal.value)
|
self.txtGoal.setColumn(Outline.setGoal)
|
||||||
|
|
||||||
def setModels(self, mdlOutline, mdlCharacter, mdlLabels, mdlStatus):
|
def setModels(self, mdlOutline, mdlCharacter, mdlLabels, mdlStatus):
|
||||||
self.cmbPOV.setModels(mdlCharacter, mdlOutline)
|
self.cmbPOV.setModels(mdlCharacter, mdlOutline)
|
||||||
|
|
|
@ -44,11 +44,11 @@ class characterTreeView(QTreeWidget):
|
||||||
if topLeft.parent() != QModelIndex():
|
if topLeft.parent() != QModelIndex():
|
||||||
return
|
return
|
||||||
|
|
||||||
if topLeft.column() <= Character.name.value <= bottomRight.column():
|
if topLeft.column() <= Character.name <= bottomRight.column():
|
||||||
# Update name
|
# Update name
|
||||||
self.updateNames()
|
self.updateNames()
|
||||||
|
|
||||||
elif topLeft.column() <= Character.importance.value <= bottomRight.column():
|
elif topLeft.column() <= Character.importance <= bottomRight.column():
|
||||||
# Importance changed
|
# Importance changed
|
||||||
self.updateItems()
|
self.updateItems()
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ class chkOutlineCompile(QCheckBox):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QCheckBox.__init__(self, parent)
|
QCheckBox.__init__(self, parent)
|
||||||
self.stateChanged.connect(self.submit)
|
self.stateChanged.connect(self.submit)
|
||||||
self._column = Outline.compile.value
|
self._column = Outline.compile
|
||||||
self._index = None
|
self._index = None
|
||||||
self._indexes = None
|
self._indexes = None
|
||||||
self._model = None
|
self._model = None
|
||||||
|
@ -43,13 +43,7 @@ class chkOutlineCompile(QCheckBox):
|
||||||
|
|
||||||
def getCheckedValue(self, index):
|
def getCheckedValue(self, index):
|
||||||
item = index.internalPointer()
|
item = index.internalPointer()
|
||||||
c = item.data(Outline.compile)
|
return Qt.Checked if item.compile() else Qt.Unchecked
|
||||||
if c:
|
|
||||||
c = int(c)
|
|
||||||
else:
|
|
||||||
c = Qt.Unchecked
|
|
||||||
|
|
||||||
return c
|
|
||||||
|
|
||||||
def update(self, topLeft, bottomRight):
|
def update(self, topLeft, bottomRight):
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ class cmbOutlineCharacterChoser(QComboBox):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QComboBox.__init__(self, parent)
|
QComboBox.__init__(self, parent)
|
||||||
self.activated[int].connect(self.submit)
|
self.activated[int].connect(self.submit)
|
||||||
self._column = Outline.POV.value
|
self._column = Outline.POV
|
||||||
self._index = None
|
self._index = None
|
||||||
self._indexes = None
|
self._indexes = None
|
||||||
self._updating = False
|
self._updating = False
|
||||||
|
|
|
@ -11,7 +11,7 @@ class cmbOutlineLabelChoser(QComboBox):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QComboBox.__init__(self, parent)
|
QComboBox.__init__(self, parent)
|
||||||
self.activated[int].connect(self.submit)
|
self.activated[int].connect(self.submit)
|
||||||
self._column = Outline.label.value
|
self._column = Outline.label
|
||||||
self._index = None
|
self._index = None
|
||||||
self._indexes = None
|
self._indexes = None
|
||||||
self._updating = False
|
self._updating = False
|
||||||
|
|
|
@ -11,7 +11,7 @@ class cmbOutlineStatusChoser(QComboBox):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QComboBox.__init__(self, parent)
|
QComboBox.__init__(self, parent)
|
||||||
self.activated[int].connect(self.submit)
|
self.activated[int].connect(self.submit)
|
||||||
self._column = Outline.status.value
|
self._column = Outline.status
|
||||||
self._index = None
|
self._index = None
|
||||||
self._indexes = None
|
self._indexes = None
|
||||||
self._updating = False
|
self._updating = False
|
||||||
|
|
|
@ -114,7 +114,7 @@ class corkDelegate(QStyledItemDelegate):
|
||||||
|
|
||||||
if self.editing == Outline.summarySentence:
|
if self.editing == Outline.summarySentence:
|
||||||
# One line summary
|
# One line summary
|
||||||
editor.setText(item.data(Outline.summarySentence.value))
|
editor.setText(item.data(Outline.summarySentence))
|
||||||
|
|
||||||
elif self.editing == Outline.title:
|
elif self.editing == Outline.title:
|
||||||
# Title
|
# Title
|
||||||
|
@ -122,21 +122,21 @@ class corkDelegate(QStyledItemDelegate):
|
||||||
|
|
||||||
elif self.editing == Outline.summaryFull:
|
elif self.editing == Outline.summaryFull:
|
||||||
# Summary
|
# Summary
|
||||||
editor.setPlainText(item.data(Outline.summaryFull.value))
|
editor.setPlainText(item.data(Outline.summaryFull))
|
||||||
|
|
||||||
def setModelData(self, editor, model, index):
|
def setModelData(self, editor, model, index):
|
||||||
|
|
||||||
if self.editing == Outline.summarySentence:
|
if self.editing == Outline.summarySentence:
|
||||||
# One line summary
|
# One line summary
|
||||||
model.setData(index.sibling(index.row(), Outline.summarySentence.value), editor.text())
|
model.setData(index.sibling(index.row(), Outline.summarySentence), editor.text())
|
||||||
|
|
||||||
elif self.editing == Outline.title:
|
elif self.editing == Outline.title:
|
||||||
# Title
|
# Title
|
||||||
model.setData(index, editor.text(), Outline.title.value)
|
model.setData(index, editor.text(), Outline.title)
|
||||||
|
|
||||||
elif self.editing == Outline.summaryFull:
|
elif self.editing == Outline.summaryFull:
|
||||||
# Summary
|
# Summary
|
||||||
model.setData(index.sibling(index.row(), Outline.summaryFull.value), editor.toPlainText())
|
model.setData(index.sibling(index.row(), Outline.summaryFull), editor.toPlainText())
|
||||||
|
|
||||||
def updateRects(self, option, index):
|
def updateRects(self, option, index):
|
||||||
if self.newStyle():
|
if self.newStyle():
|
||||||
|
@ -173,7 +173,7 @@ class corkDelegate(QStyledItemDelegate):
|
||||||
self.mainRect.topRight() + QPoint(0, h))
|
self.mainRect.topRight() + QPoint(0, h))
|
||||||
self.mainTextRect = QRect(self.mainLineRect.bottomLeft() + QPoint(0, margin),
|
self.mainTextRect = QRect(self.mainLineRect.bottomLeft() + QPoint(0, margin),
|
||||||
self.mainRect.bottomRight())
|
self.mainRect.bottomRight())
|
||||||
if not item.data(Outline.summarySentence.value):
|
if not item.data(Outline.summarySentence):
|
||||||
self.mainTextRect.setTopLeft(self.mainLineRect.topLeft())
|
self.mainTextRect.setTopLeft(self.mainLineRect.topLeft())
|
||||||
|
|
||||||
def updateRects_v1(self, option, index):
|
def updateRects_v1(self, option, index):
|
||||||
|
@ -194,9 +194,9 @@ class corkDelegate(QStyledItemDelegate):
|
||||||
self.mainRect.topRight() + QPoint(0, iconSize))
|
self.mainRect.topRight() + QPoint(0, iconSize))
|
||||||
self.mainTextRect = QRect(self.mainLineRect.bottomLeft() + QPoint(0, margin),
|
self.mainTextRect = QRect(self.mainLineRect.bottomLeft() + QPoint(0, margin),
|
||||||
self.mainRect.bottomRight())
|
self.mainRect.bottomRight())
|
||||||
if not item.data(Outline.summarySentence.value):
|
if not item.data(Outline.summarySentence):
|
||||||
self.mainTextRect.setTopLeft(self.mainLineRect.topLeft())
|
self.mainTextRect.setTopLeft(self.mainLineRect.topLeft())
|
||||||
if item.data(Outline.label.value) in ["", "0", 0]:
|
if item.data(Outline.label) in ["", "0", 0]:
|
||||||
self.titleRect.setBottomRight(self.labelRect.bottomRight() - QPoint(self.margin, self.margin))
|
self.titleRect.setBottomRight(self.labelRect.bottomRight() - QPoint(self.margin, self.margin))
|
||||||
|
|
||||||
def paint(self, p, option, index):
|
def paint(self, p, option, index):
|
||||||
|
@ -340,8 +340,8 @@ class corkDelegate(QStyledItemDelegate):
|
||||||
p.restore()
|
p.restore()
|
||||||
|
|
||||||
# One line summary background
|
# One line summary background
|
||||||
lineSummary = item.data(Outline.summarySentence.value)
|
lineSummary = item.data(Outline.summarySentence)
|
||||||
fullSummary = item.data(Outline.summaryFull.value)
|
fullSummary = item.data(Outline.summaryFull)
|
||||||
|
|
||||||
# Border
|
# Border
|
||||||
if settings.viewSettings["Cork"]["Border"] != "Nothing":
|
if settings.viewSettings["Cork"]["Border"] != "Nothing":
|
||||||
|
@ -359,7 +359,7 @@ class corkDelegate(QStyledItemDelegate):
|
||||||
p.restore()
|
p.restore()
|
||||||
|
|
||||||
# Draw status
|
# Draw status
|
||||||
status = item.data(Outline.status.value)
|
status = item.data(Outline.status)
|
||||||
if status:
|
if status:
|
||||||
it = mainWindow().mdlStatus.item(int(status), 0)
|
it = mainWindow().mdlStatus.item(int(status), 0)
|
||||||
if it != None:
|
if it != None:
|
||||||
|
@ -476,8 +476,8 @@ class corkDelegate(QStyledItemDelegate):
|
||||||
p.drawLine(self.labelRect.topLeft(), self.labelRect.bottomLeft())
|
p.drawLine(self.labelRect.topLeft(), self.labelRect.bottomLeft())
|
||||||
|
|
||||||
# One line summary background
|
# One line summary background
|
||||||
lineSummary = item.data(Outline.summarySentence.value)
|
lineSummary = item.data(Outline.summarySentence)
|
||||||
fullSummary = item.data(Outline.summaryFull.value)
|
fullSummary = item.data(Outline.summaryFull)
|
||||||
if lineSummary or not fullSummary:
|
if lineSummary or not fullSummary:
|
||||||
m = self.margin
|
m = self.margin
|
||||||
r = self.mainLineRect.adjusted(-m, -m, m, m / 2)
|
r = self.mainLineRect.adjusted(-m, -m, m, m / 2)
|
||||||
|
@ -556,7 +556,7 @@ class corkDelegate(QStyledItemDelegate):
|
||||||
|
|
||||||
# Draw status
|
# Draw status
|
||||||
mainRect = self.mainRect
|
mainRect = self.mainRect
|
||||||
status = item.data(Outline.status.value)
|
status = item.data(Outline.status)
|
||||||
if status:
|
if status:
|
||||||
it = mainWindow().mdlStatus.item(int(status), 0)
|
it = mainWindow().mdlStatus.item(int(status), 0)
|
||||||
if it != None:
|
if it != None:
|
||||||
|
|
|
@ -9,7 +9,7 @@ from manuskript.functions import toString
|
||||||
class lineEditView(QLineEdit):
|
class lineEditView(QLineEdit):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QLineEdit.__init__(self, parent)
|
QLineEdit.__init__(self, parent)
|
||||||
self._column = Outline.title.value
|
self._column = Outline.title
|
||||||
self._indexes = None
|
self._indexes = None
|
||||||
self._index = None
|
self._index = None
|
||||||
self._placeholderText = None
|
self._placeholderText = None
|
||||||
|
|
|
@ -12,9 +12,9 @@ class metadataView(QWidget, Ui_metadataView):
|
||||||
QWidget.__init__(self, parent)
|
QWidget.__init__(self, parent)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self._lastIndexes = None
|
self._lastIndexes = None
|
||||||
self.txtSummarySentence.setColumn(Outline.summarySentence.value)
|
self.txtSummarySentence.setColumn(Outline.summarySentence)
|
||||||
self.txtSummaryFull.setColumn(Outline.summaryFull.value)
|
self.txtSummaryFull.setColumn(Outline.summaryFull)
|
||||||
self.txtNotes.setColumn(Outline.notes.value)
|
self.txtNotes.setColumn(Outline.notes)
|
||||||
self.revisions.setEnabled(False)
|
self.revisions.setEnabled(False)
|
||||||
|
|
||||||
self.txtSummarySentence.setStyleSheet(style.lineEditSS())
|
self.txtSummarySentence.setStyleSheet(style.lineEditSS())
|
||||||
|
|
|
@ -10,7 +10,7 @@ from manuskript import settings
|
||||||
from manuskript.enums import Outline
|
from manuskript.enums import Outline
|
||||||
from manuskript.functions import mainWindow, statusMessage
|
from manuskript.functions import mainWindow, statusMessage
|
||||||
from manuskript.functions import toInt, customIcons
|
from manuskript.functions import toInt, customIcons
|
||||||
from manuskript.models.outlineModel import outlineItem
|
from manuskript.models import outlineItem
|
||||||
from manuskript.ui.tools.splitDialog import splitDialog
|
from manuskript.ui.tools.splitDialog import splitDialog
|
||||||
|
|
||||||
|
|
||||||
|
@ -31,8 +31,10 @@ class outlineBasics(QAbstractItemView):
|
||||||
if event.button() == Qt.RightButton:
|
if event.button() == Qt.RightButton:
|
||||||
self.menu = self.makePopupMenu()
|
self.menu = self.makePopupMenu()
|
||||||
self.menu.popup(event.globalPos())
|
self.menu.popup(event.globalPos())
|
||||||
else:
|
# We don't call QAbstractItemView.mouseReleaseEvent because
|
||||||
QAbstractItemView.mouseReleaseEvent(self, event)
|
# outlineBasics is never subclassed alone. So the others views
|
||||||
|
# (outlineView, corkView, treeView) that subclass outlineBasics
|
||||||
|
# call their respective mother class.
|
||||||
|
|
||||||
def makePopupMenu(self):
|
def makePopupMenu(self):
|
||||||
index = self.currentIndex()
|
index = self.currentIndex()
|
||||||
|
@ -414,15 +416,15 @@ class outlineBasics(QAbstractItemView):
|
||||||
|
|
||||||
def setPOV(self, POV):
|
def setPOV(self, POV):
|
||||||
for i in self.getSelection():
|
for i in self.getSelection():
|
||||||
self.model().setData(i.sibling(i.row(), Outline.POV.value), str(POV))
|
self.model().setData(i.sibling(i.row(), Outline.POV), str(POV))
|
||||||
|
|
||||||
def setStatus(self, status):
|
def setStatus(self, status):
|
||||||
for i in self.getSelection():
|
for i in self.getSelection():
|
||||||
self.model().setData(i.sibling(i.row(), Outline.status.value), str(status))
|
self.model().setData(i.sibling(i.row(), Outline.status), str(status))
|
||||||
|
|
||||||
def setLabel(self, label):
|
def setLabel(self, label):
|
||||||
for i in self.getSelection():
|
for i in self.getSelection():
|
||||||
self.model().setData(i.sibling(i.row(), Outline.label.value), str(label))
|
self.model().setData(i.sibling(i.row(), Outline.label), str(label))
|
||||||
|
|
||||||
def setCustomIcon(self, customIcon):
|
def setCustomIcon(self, customIcon):
|
||||||
for i in self.getSelection():
|
for i in self.getSelection():
|
||||||
|
|
|
@ -114,7 +114,7 @@ class outlineCharacterDelegate(QStyledItemDelegate):
|
||||||
item = QModelIndex()
|
item = QModelIndex()
|
||||||
character = self.mdlCharacter.getCharacterByID(index.data())
|
character = self.mdlCharacter.getCharacterByID(index.data())
|
||||||
if character:
|
if character:
|
||||||
item = character.index(Character.name.value)
|
item = character.index(Character.name)
|
||||||
|
|
||||||
opt = QStyleOptionViewItem(option)
|
opt = QStyleOptionViewItem(option)
|
||||||
self.initStyleOption(opt, item)
|
self.initStyleOption(opt, item)
|
||||||
|
@ -172,14 +172,14 @@ class outlineCharacterDelegate(QStyledItemDelegate):
|
||||||
itemIndex = QModelIndex()
|
itemIndex = QModelIndex()
|
||||||
character = self.mdlCharacter.getCharacterByID(index.data())
|
character = self.mdlCharacter.getCharacterByID(index.data())
|
||||||
if character:
|
if character:
|
||||||
itemIndex = character.index(Character.name.value)
|
itemIndex = character.index(Character.name)
|
||||||
|
|
||||||
opt = QStyleOptionViewItem(option)
|
opt = QStyleOptionViewItem(option)
|
||||||
self.initStyleOption(opt, itemIndex)
|
self.initStyleOption(opt, itemIndex)
|
||||||
|
|
||||||
qApp.style().drawControl(QStyle.CE_ItemViewItem, opt, painter)
|
qApp.style().drawControl(QStyle.CE_ItemViewItem, opt, painter)
|
||||||
|
|
||||||
# if index.isValid() and index.internalPointer().data(Outline.POV.value) not in ["", None]:
|
# if index.isValid() and index.internalPointer().data(Outline.POV) not in ["", None]:
|
||||||
if itemIndex.isValid() and self.mdlCharacter.data(itemIndex) not in ["", None]:
|
if itemIndex.isValid() and self.mdlCharacter.data(itemIndex) not in ["", None]:
|
||||||
opt = QStyleOptionComboBox()
|
opt = QStyleOptionComboBox()
|
||||||
opt.rect = option.rect
|
opt.rect = option.rect
|
||||||
|
@ -195,6 +195,9 @@ class outlineCompileDelegate(QStyledItemDelegate):
|
||||||
def displayText(self, value, locale):
|
def displayText(self, value, locale):
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
#def createEditor(self, parent, option, index):
|
||||||
|
#return None
|
||||||
|
|
||||||
|
|
||||||
class outlineGoalPercentageDelegate(QStyledItemDelegate):
|
class outlineGoalPercentageDelegate(QStyledItemDelegate):
|
||||||
def __init__(self, rootIndex=None, parent=None):
|
def __init__(self, rootIndex=None, parent=None):
|
||||||
|
@ -215,12 +218,12 @@ class outlineGoalPercentageDelegate(QStyledItemDelegate):
|
||||||
|
|
||||||
item = index.internalPointer()
|
item = index.internalPointer()
|
||||||
|
|
||||||
if not item.data(Outline.goal.value):
|
if not item.data(Outline.goal):
|
||||||
return
|
return
|
||||||
|
|
||||||
p = toFloat(item.data(Outline.goalPercentage.value))
|
p = toFloat(item.data(Outline.goalPercentage))
|
||||||
|
|
||||||
typ = item.data(Outline.type.value)
|
typ = item.data(Outline.type)
|
||||||
|
|
||||||
level = item.level()
|
level = item.level()
|
||||||
if self.rootIndex and self.rootIndex.isValid():
|
if self.rootIndex and self.rootIndex.isValid():
|
||||||
|
@ -271,7 +274,7 @@ class outlineStatusDelegate(QStyledItemDelegate):
|
||||||
for i in range(self.mdlStatus.rowCount()):
|
for i in range(self.mdlStatus.rowCount()):
|
||||||
editor.addItem(self.mdlStatus.item(i, 0).text())
|
editor.addItem(self.mdlStatus.item(i, 0).text())
|
||||||
|
|
||||||
val = index.internalPointer().data(Outline.status.value)
|
val = index.internalPointer().data(Outline.status)
|
||||||
if not val: val = 0
|
if not val: val = 0
|
||||||
editor.setCurrentIndex(int(val))
|
editor.setCurrentIndex(int(val))
|
||||||
editor.showPopup()
|
editor.showPopup()
|
||||||
|
@ -289,7 +292,7 @@ class outlineStatusDelegate(QStyledItemDelegate):
|
||||||
def paint(self, painter, option, index):
|
def paint(self, painter, option, index):
|
||||||
QStyledItemDelegate.paint(self, painter, option, index)
|
QStyledItemDelegate.paint(self, painter, option, index)
|
||||||
|
|
||||||
if index.isValid() and index.internalPointer().data(Outline.status.value) not in ["", None, "0", 0]:
|
if index.isValid() and index.internalPointer().data(Outline.status) not in ["", None, "0", 0]:
|
||||||
opt = QStyleOptionComboBox()
|
opt = QStyleOptionComboBox()
|
||||||
opt.rect = option.rect
|
opt.rect = option.rect
|
||||||
r = qApp.style().subControlRect(QStyle.CC_ComboBox, opt, QStyle.SC_ComboBoxArrow)
|
r = qApp.style().subControlRect(QStyle.CC_ComboBox, opt, QStyle.SC_ComboBoxArrow)
|
||||||
|
@ -329,7 +332,7 @@ class outlineLabelDelegate(QStyledItemDelegate):
|
||||||
editor.addItem(self.mdlLabels.item(i, 0).icon(),
|
editor.addItem(self.mdlLabels.item(i, 0).icon(),
|
||||||
self.mdlLabels.item(i, 0).text())
|
self.mdlLabels.item(i, 0).text())
|
||||||
|
|
||||||
val = index.internalPointer().data(Outline.label.value)
|
val = index.internalPointer().data(Outline.label)
|
||||||
if not val: val = 0
|
if not val: val = 0
|
||||||
editor.setCurrentIndex(int(val))
|
editor.setCurrentIndex(int(val))
|
||||||
editor.showPopup()
|
editor.showPopup()
|
||||||
|
@ -355,7 +358,7 @@ class outlineLabelDelegate(QStyledItemDelegate):
|
||||||
qApp.style().drawControl(QStyle.CE_ItemViewItem, opt, painter)
|
qApp.style().drawControl(QStyle.CE_ItemViewItem, opt, painter)
|
||||||
|
|
||||||
# Drop down indicator
|
# Drop down indicator
|
||||||
if index.isValid() and index.internalPointer().data(Outline.label.value) not in ["", None, "0", 0]:
|
if index.isValid() and index.internalPointer().data(Outline.label) not in ["", None, "0", 0]:
|
||||||
opt = QStyleOptionComboBox()
|
opt = QStyleOptionComboBox()
|
||||||
opt.rect = option.rect
|
opt.rect = option.rect
|
||||||
r = qApp.style().subControlRect(QStyle.CC_ComboBox, opt, QStyle.SC_ComboBoxArrow)
|
r = qApp.style().subControlRect(QStyle.CC_ComboBox, opt, QStyle.SC_ComboBoxArrow)
|
||||||
|
|
|
@ -40,29 +40,29 @@ class outlineView(QTreeView, dndView, outlineBasics):
|
||||||
# Setting delegates
|
# Setting delegates
|
||||||
self.outlineTitleDelegate = outlineTitleDelegate(self)
|
self.outlineTitleDelegate = outlineTitleDelegate(self)
|
||||||
# self.outlineTitleDelegate.setView(self)
|
# self.outlineTitleDelegate.setView(self)
|
||||||
self.setItemDelegateForColumn(Outline.title.value, self.outlineTitleDelegate)
|
self.setItemDelegateForColumn(Outline.title, self.outlineTitleDelegate)
|
||||||
self.outlineCharacterDelegate = outlineCharacterDelegate(self.modelCharacters)
|
self.outlineCharacterDelegate = outlineCharacterDelegate(self.modelCharacters)
|
||||||
self.setItemDelegateForColumn(Outline.POV.value, self.outlineCharacterDelegate)
|
self.setItemDelegateForColumn(Outline.POV, self.outlineCharacterDelegate)
|
||||||
self.outlineCompileDelegate = outlineCompileDelegate()
|
self.outlineCompileDelegate = outlineCompileDelegate()
|
||||||
self.setItemDelegateForColumn(Outline.compile.value, self.outlineCompileDelegate)
|
self.setItemDelegateForColumn(Outline.compile, self.outlineCompileDelegate)
|
||||||
self.outlineStatusDelegate = outlineStatusDelegate(self.modelStatus)
|
self.outlineStatusDelegate = outlineStatusDelegate(self.modelStatus)
|
||||||
self.setItemDelegateForColumn(Outline.status.value, self.outlineStatusDelegate)
|
self.setItemDelegateForColumn(Outline.status, self.outlineStatusDelegate)
|
||||||
self.outlineGoalPercentageDelegate = outlineGoalPercentageDelegate()
|
self.outlineGoalPercentageDelegate = outlineGoalPercentageDelegate()
|
||||||
self.setItemDelegateForColumn(Outline.goalPercentage.value, self.outlineGoalPercentageDelegate)
|
self.setItemDelegateForColumn(Outline.goalPercentage, self.outlineGoalPercentageDelegate)
|
||||||
self.outlineLabelDelegate = outlineLabelDelegate(self.modelLabels)
|
self.outlineLabelDelegate = outlineLabelDelegate(self.modelLabels)
|
||||||
self.setItemDelegateForColumn(Outline.label.value, self.outlineLabelDelegate)
|
self.setItemDelegateForColumn(Outline.label, self.outlineLabelDelegate)
|
||||||
|
|
||||||
# Hiding columns
|
# Hiding columns
|
||||||
self.hideColumns()
|
self.hideColumns()
|
||||||
|
|
||||||
self.header().setSectionResizeMode(Outline.title.value, QHeaderView.Stretch)
|
self.header().setSectionResizeMode(Outline.title, QHeaderView.Stretch)
|
||||||
self.header().setSectionResizeMode(Outline.POV.value, QHeaderView.ResizeToContents)
|
self.header().setSectionResizeMode(Outline.POV, QHeaderView.ResizeToContents)
|
||||||
self.header().setSectionResizeMode(Outline.status.value, QHeaderView.ResizeToContents)
|
self.header().setSectionResizeMode(Outline.status, QHeaderView.ResizeToContents)
|
||||||
self.header().setSectionResizeMode(Outline.label.value, QHeaderView.ResizeToContents)
|
self.header().setSectionResizeMode(Outline.label, QHeaderView.ResizeToContents)
|
||||||
self.header().setSectionResizeMode(Outline.compile.value, QHeaderView.ResizeToContents)
|
self.header().setSectionResizeMode(Outline.compile, QHeaderView.ResizeToContents)
|
||||||
self.header().setSectionResizeMode(Outline.wordCount.value, QHeaderView.ResizeToContents)
|
self.header().setSectionResizeMode(Outline.wordCount, QHeaderView.ResizeToContents)
|
||||||
self.header().setSectionResizeMode(Outline.goal.value, QHeaderView.ResizeToContents)
|
self.header().setSectionResizeMode(Outline.goal, QHeaderView.ResizeToContents)
|
||||||
self.header().setSectionResizeMode(Outline.goalPercentage.value, QHeaderView.ResizeToContents)
|
self.header().setSectionResizeMode(Outline.goalPercentage, QHeaderView.ResizeToContents)
|
||||||
|
|
||||||
def hideColumns(self):
|
def hideColumns(self):
|
||||||
if not self.model():
|
if not self.model():
|
||||||
|
@ -77,7 +77,7 @@ class outlineView(QTreeView, dndView, outlineBasics):
|
||||||
def setRootIndex(self, index):
|
def setRootIndex(self, index):
|
||||||
QTreeView.setRootIndex(self, index)
|
QTreeView.setRootIndex(self, index)
|
||||||
self.outlineGoalPercentageDelegate = outlineGoalPercentageDelegate(index)
|
self.outlineGoalPercentageDelegate = outlineGoalPercentageDelegate(index)
|
||||||
self.setItemDelegateForColumn(Outline.goalPercentage.value, self.outlineGoalPercentageDelegate)
|
self.setItemDelegateForColumn(Outline.goalPercentage, self.outlineGoalPercentageDelegate)
|
||||||
|
|
||||||
def dragMoveEvent(self, event):
|
def dragMoveEvent(self, event):
|
||||||
dndView.dragMoveEvent(self, event)
|
dndView.dragMoveEvent(self, event)
|
||||||
|
|
|
@ -78,7 +78,7 @@ class plotTreeView(QTreeWidget):
|
||||||
|
|
||||||
def updateMaybe(self, topLeft, bottomRight):
|
def updateMaybe(self, topLeft, bottomRight):
|
||||||
if topLeft.parent() != QModelIndex() and \
|
if topLeft.parent() != QModelIndex() and \
|
||||||
topLeft.column() <= PlotStep.name.value <= bottomRight.column() and \
|
topLeft.column() <= PlotStep.name <= bottomRight.column() and \
|
||||||
self._showSubPlot:
|
self._showSubPlot:
|
||||||
# Name's of Step has been updated, we update Items if showing
|
# Name's of Step has been updated, we update Items if showing
|
||||||
# subplots.
|
# subplots.
|
||||||
|
@ -86,11 +86,11 @@ class plotTreeView(QTreeWidget):
|
||||||
elif topLeft.parent() != QModelIndex():
|
elif topLeft.parent() != QModelIndex():
|
||||||
return
|
return
|
||||||
|
|
||||||
if topLeft.column() <= Plot.name.value <= bottomRight.column():
|
if topLeft.column() <= Plot.name <= bottomRight.column():
|
||||||
# Update name
|
# Update name
|
||||||
self.updateNames()
|
self.updateNames()
|
||||||
|
|
||||||
elif topLeft.column() <= Plot.importance.value <= bottomRight.column():
|
elif topLeft.column() <= Plot.importance <= bottomRight.column():
|
||||||
# Importance changed
|
# Importance changed
|
||||||
self.updateItems()
|
self.updateItems()
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ class propertiesView(QWidget, Ui_propertiesView):
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QWidget.__init__(self)
|
QWidget.__init__(self)
|
||||||
self.setupUi(self)
|
self.setupUi(self)
|
||||||
self.txtGoal.setColumn(Outline.setGoal.value)
|
self.txtGoal.setColumn(Outline.setGoal)
|
||||||
|
|
||||||
def setModels(self, mdlOutline, mdlCharacter, mdlLabels, mdlStatus):
|
def setModels(self, mdlOutline, mdlCharacter, mdlLabels, mdlStatus):
|
||||||
self.cmbPOV.setModels(mdlCharacter, mdlOutline)
|
self.cmbPOV.setModels(mdlCharacter, mdlOutline)
|
||||||
|
|
|
@ -61,7 +61,7 @@ class storylineView(QWidget, Ui_storylineView):
|
||||||
self._mdlCharacter.dataChanged.connect(self.reloadTimer.start)
|
self._mdlCharacter.dataChanged.connect(self.reloadTimer.start)
|
||||||
|
|
||||||
def updateMaybe(self, topLeft, bottomRight):
|
def updateMaybe(self, topLeft, bottomRight):
|
||||||
if topLeft.column() <= Outline.notes.value <= bottomRight.column():
|
if topLeft.column() <= Outline.notes <= bottomRight.column():
|
||||||
self.reloadTimer.start
|
self.reloadTimer.start
|
||||||
|
|
||||||
def plotReferences(self):
|
def plotReferences(self):
|
||||||
|
|
|
@ -26,7 +26,7 @@ class textEditView(QTextEdit):
|
||||||
def __init__(self, parent=None, index=None, html=None, spellcheck=True, highlighting=False, dict="",
|
def __init__(self, parent=None, index=None, html=None, spellcheck=True, highlighting=False, dict="",
|
||||||
autoResize=False):
|
autoResize=False):
|
||||||
QTextEdit.__init__(self, parent)
|
QTextEdit.__init__(self, parent)
|
||||||
self._column = Outline.text.value
|
self._column = Outline.text
|
||||||
self._index = None
|
self._index = None
|
||||||
self._indexes = None
|
self._indexes = None
|
||||||
self._model = None
|
self._model = None
|
||||||
|
@ -38,6 +38,10 @@ class textEditView(QTextEdit):
|
||||||
self.setAcceptRichText(False)
|
self.setAcceptRichText(False)
|
||||||
# When setting up a theme, this becomes true.
|
# When setting up a theme, this becomes true.
|
||||||
self._fromTheme = False
|
self._fromTheme = False
|
||||||
|
# Sometimes we need to update index because item has changed its
|
||||||
|
# position, so we only have it's ID as reference. We store it to
|
||||||
|
# update at the propper time.
|
||||||
|
self._updateIndexFromID = None
|
||||||
|
|
||||||
self.spellcheck = spellcheck
|
self.spellcheck = spellcheck
|
||||||
self.currentDict = dict if dict else settings.dict
|
self.currentDict = dict if dict else settings.dict
|
||||||
|
@ -179,7 +183,7 @@ class textEditView(QTextEdit):
|
||||||
return
|
return
|
||||||
|
|
||||||
# what type of text are we editing?
|
# what type of text are we editing?
|
||||||
if self._column not in [Outline.text.value, Outline.notes.value]:
|
if self._column not in [Outline.text, Outline.notes]:
|
||||||
self._textFormat = "text"
|
self._textFormat = "text"
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -188,7 +192,7 @@ class textEditView(QTextEdit):
|
||||||
# Setting highlighter
|
# Setting highlighter
|
||||||
if self._highlighting:
|
if self._highlighting:
|
||||||
item = index.internalPointer()
|
item = index.internalPointer()
|
||||||
if self._column in [Outline.text.value, Outline.notes.value]:
|
if self._column in [Outline.text, Outline.notes]:
|
||||||
self.highlighter = MMDHighlighter(self)
|
self.highlighter = MMDHighlighter(self)
|
||||||
else:
|
else:
|
||||||
self.highlighter = basicHighlighter(self)
|
self.highlighter = basicHighlighter(self)
|
||||||
|
@ -199,7 +203,7 @@ class textEditView(QTextEdit):
|
||||||
if self._fromTheme or \
|
if self._fromTheme or \
|
||||||
not self._index or \
|
not self._index or \
|
||||||
type(self._index.model()) != outlineModel or \
|
type(self._index.model()) != outlineModel or \
|
||||||
self._column != Outline.text.value:
|
self._column != Outline.text:
|
||||||
return
|
return
|
||||||
|
|
||||||
opt = settings.textEditor
|
opt = settings.textEditor
|
||||||
|
@ -270,7 +274,15 @@ class textEditView(QTextEdit):
|
||||||
if self._updating:
|
if self._updating:
|
||||||
return
|
return
|
||||||
|
|
||||||
elif self._index and self._index.isValid():
|
if self._updateIndexFromID:
|
||||||
|
# We have to update to a new index
|
||||||
|
self._index = self._index.model().getIndexByID(
|
||||||
|
self._updateIndexFromID,
|
||||||
|
self._column)
|
||||||
|
self._updateIndexFromID = None
|
||||||
|
|
||||||
|
if self._index and self._index.isValid():
|
||||||
|
|
||||||
if topLeft.parent() != self._index.parent():
|
if topLeft.parent() != self._index.parent():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -293,13 +305,34 @@ class textEditView(QTextEdit):
|
||||||
self.updateText()
|
self.updateText()
|
||||||
|
|
||||||
def rowsAboutToBeRemoved(self, parent, first, last):
|
def rowsAboutToBeRemoved(self, parent, first, last):
|
||||||
if self._index:
|
if self._index and self._index.isValid():
|
||||||
|
|
||||||
|
# Has my _index just been removed?
|
||||||
if self._index.parent() == parent and \
|
if self._index.parent() == parent and \
|
||||||
first <= self._index.row() <= last:
|
first <= self._index.row() <= last:
|
||||||
self._index = None
|
self._index = None
|
||||||
self.setEnabled(False)
|
self.setEnabled(False)
|
||||||
|
return
|
||||||
# FIXME: self._indexes
|
# FIXME: self._indexes
|
||||||
|
|
||||||
|
# We check if item is a child of the row about to be removed
|
||||||
|
child = False
|
||||||
|
p = self._index.parent()
|
||||||
|
while p:
|
||||||
|
if p == parent:
|
||||||
|
child = True
|
||||||
|
p = None
|
||||||
|
elif p.isValid():
|
||||||
|
p = p.parent()
|
||||||
|
else:
|
||||||
|
p = None
|
||||||
|
if child:
|
||||||
|
# Item might have moved (so will not be valid any more)
|
||||||
|
ID = self._index.internalPointer().ID()
|
||||||
|
# We store ID, and we update it in self.update (after the
|
||||||
|
# rows have been removed).
|
||||||
|
self._updateIndexFromID = ID
|
||||||
|
|
||||||
def disconnectDocument(self):
|
def disconnectDocument(self):
|
||||||
try:
|
try:
|
||||||
self.document().contentsChanged.disconnect(self.updateTimer.start)
|
self.document().contentsChanged.disconnect(self.updateTimer.start)
|
||||||
|
|
|
@ -94,7 +94,7 @@ class treeTitleDelegate(QStyledItemDelegate):
|
||||||
# If text color is Compile and item is selected, we have
|
# If text color is Compile and item is selected, we have
|
||||||
# to change the color
|
# to change the color
|
||||||
if settings.viewSettings["Outline"]["Text"] == "Compile" and \
|
if settings.viewSettings["Outline"]["Text"] == "Compile" and \
|
||||||
item.compile() in [0, "0"]:
|
not item.compile():
|
||||||
col = mixColors(textColor, QColor(S.window))
|
col = mixColors(textColor, QColor(S.window))
|
||||||
painter.setPen(col)
|
painter.setPen(col)
|
||||||
f = QFont(opt.font)
|
f = QFont(opt.font)
|
||||||
|
@ -109,27 +109,27 @@ class treeTitleDelegate(QStyledItemDelegate):
|
||||||
extraText = item.childCount()
|
extraText = item.childCount()
|
||||||
extraText = " [{}]".format(extraText)
|
extraText = " [{}]".format(extraText)
|
||||||
elif settings.viewSettings["Tree"]["InfoFolder"] == "WC":
|
elif settings.viewSettings["Tree"]["InfoFolder"] == "WC":
|
||||||
extraText = item.data(Outline.wordCount.value)
|
extraText = item.wordCount()
|
||||||
extraText = " ({})".format(extraText)
|
extraText = " ({})".format(extraText)
|
||||||
elif settings.viewSettings["Tree"]["InfoFolder"] == "Progress":
|
elif settings.viewSettings["Tree"]["InfoFolder"] == "Progress":
|
||||||
extraText = int(toFloat(item.data(Outline.goalPercentage.value)) * 100)
|
extraText = int(toFloat(item.data(Outline.goalPercentage)) * 100)
|
||||||
if extraText:
|
if extraText:
|
||||||
extraText = " ({}%)".format(extraText)
|
extraText = " ({}%)".format(extraText)
|
||||||
elif settings.viewSettings["Tree"]["InfoFolder"] == "Summary":
|
elif settings.viewSettings["Tree"]["InfoFolder"] == "Summary":
|
||||||
extraText = item.data(Outline.summarySentence.value)
|
extraText = item.data(Outline.summarySentence)
|
||||||
if extraText:
|
if extraText:
|
||||||
extraText = " - {}".format(extraText)
|
extraText = " - {}".format(extraText)
|
||||||
|
|
||||||
if item.isText() and settings.viewSettings["Tree"]["InfoText"] != "Nothing":
|
if item.isText() and settings.viewSettings["Tree"]["InfoText"] != "Nothing":
|
||||||
if settings.viewSettings["Tree"]["InfoText"] == "WC":
|
if settings.viewSettings["Tree"]["InfoText"] == "WC":
|
||||||
extraText = item.data(Outline.wordCount.value)
|
extraText = item.wordCount()
|
||||||
extraText = " ({})".format(extraText)
|
extraText = " ({})".format(extraText)
|
||||||
elif settings.viewSettings["Tree"]["InfoText"] == "Progress":
|
elif settings.viewSettings["Tree"]["InfoText"] == "Progress":
|
||||||
extraText = int(toFloat(item.data(Outline.goalPercentage.value)) * 100)
|
extraText = int(toFloat(item.data(Outline.goalPercentage)) * 100)
|
||||||
if extraText:
|
if extraText:
|
||||||
extraText = " ({}%)".format(extraText)
|
extraText = " ({}%)".format(extraText)
|
||||||
elif settings.viewSettings["Tree"]["InfoText"] == "Summary":
|
elif settings.viewSettings["Tree"]["InfoText"] == "Summary":
|
||||||
extraText = item.data(Outline.summarySentence.value)
|
extraText = item.data(Outline.summarySentence)
|
||||||
if extraText:
|
if extraText:
|
||||||
extraText = " - {}".format(extraText)
|
extraText = " - {}".format(extraText)
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,14 @@ class treeView(QTreeView, dndView, outlineBasics):
|
||||||
QTreeView.setModel(self, model)
|
QTreeView.setModel(self, model)
|
||||||
|
|
||||||
# Hiding columns
|
# Hiding columns
|
||||||
for c in range(1, self.model().columnCount()):
|
for c in range(self.model().columnCount()):
|
||||||
self.hideColumn(c)
|
self.hideColumn(c)
|
||||||
|
|
||||||
|
self.showColumn(Outline.title)
|
||||||
|
|
||||||
# Setting delegate
|
# Setting delegate
|
||||||
self.titleDelegate = treeTitleDelegate()
|
self.titleDelegate = treeTitleDelegate()
|
||||||
self.setItemDelegateForColumn(Outline.title.value, self.titleDelegate)
|
self.setItemDelegateForColumn(Outline.title, self.titleDelegate)
|
||||||
|
|
||||||
def makePopupMenu(self):
|
def makePopupMenu(self):
|
||||||
menu = outlineBasics.makePopupMenu(self)
|
menu = outlineBasics.makePopupMenu(self)
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue