changeset 13400:4a718f51baa3

Added qcodeedit source.
author Jacob Dawid <jacob.dawid@googlemail.com>
date Mon, 11 Apr 2011 18:44:09 +0200
parents d5566981b3ac
children 8832a2221563
files gui//qcodeedit-2.2.3/GPL.txt gui//qcodeedit-2.2.3/README.txt gui//qcodeedit-2.2.3/document/qdocument.cpp gui//qcodeedit-2.2.3/document/qdocument.h gui//qcodeedit-2.2.3/document/qdocument_p.h gui//qcodeedit-2.2.3/document/qdocumentbuffer.cpp gui//qcodeedit-2.2.3/document/qdocumentbuffer.h gui//qcodeedit-2.2.3/document/qdocumentcommand.cpp gui//qcodeedit-2.2.3/document/qdocumentcommand.h gui//qcodeedit-2.2.3/document/qdocumentcursor.cpp gui//qcodeedit-2.2.3/document/qdocumentcursor.h gui//qcodeedit-2.2.3/document/qdocumentcursor_p.h gui//qcodeedit-2.2.3/document/qdocumentline.cpp gui//qcodeedit-2.2.3/document/qdocumentline.h gui//qcodeedit-2.2.3/document/qdocumentline_p.h gui//qcodeedit-2.2.3/document/qdocumentsearch.cpp gui//qcodeedit-2.2.3/document/qdocumentsearch.h gui//qcodeedit-2.2.3/lib.pri gui//qcodeedit-2.2.3/lib.pro gui//qcodeedit-2.2.3/qce-config.h gui//qcodeedit-2.2.3/qcodecompletionengine.cpp gui//qcodeedit-2.2.3/qcodecompletionengine.h gui//qcodeedit-2.2.3/qcodeedit.cpp gui//qcodeedit-2.2.3/qcodeedit.h gui//qcodeedit-2.2.3/qeditor.cpp gui//qcodeedit-2.2.3/qeditor.h gui//qcodeedit-2.2.3/qeditorfactory.cpp gui//qcodeedit-2.2.3/qeditorfactory.h gui//qcodeedit-2.2.3/qeditorinputbinding.cpp gui//qcodeedit-2.2.3/qeditorinputbinding.h gui//qcodeedit-2.2.3/qeditorinputbindinginterface.h gui//qcodeedit-2.2.3/qeditsession.cpp gui//qcodeedit-2.2.3/qeditsession.h gui//qcodeedit-2.2.3/qformat.h gui//qcodeedit-2.2.3/qformatfactory.h gui//qcodeedit-2.2.3/qformatscheme.cpp gui//qcodeedit-2.2.3/qformatscheme.h gui//qcodeedit-2.2.3/qlanguagedefinition.cpp gui//qcodeedit-2.2.3/qlanguagedefinition.h gui//qcodeedit-2.2.3/qlanguagefactory.cpp gui//qcodeedit-2.2.3/qlanguagefactory.h gui//qcodeedit-2.2.3/qlinemarksinfocenter.cpp gui//qcodeedit-2.2.3/qlinemarksinfocenter.h gui//qcodeedit-2.2.3/qnfa/light_vector.h gui//qcodeedit-2.2.3/qnfa/qnfa.cpp gui//qcodeedit-2.2.3/qnfa/qnfa.h gui//qcodeedit-2.2.3/qnfa/qnfadefinition.cpp gui//qcodeedit-2.2.3/qnfa/qnfadefinition.h gui//qcodeedit-2.2.3/qnfa/xml2qnfa.cpp gui//qcodeedit-2.2.3/qpanellayout.cpp gui//qcodeedit-2.2.3/qpanellayout.h gui//qcodeedit-2.2.3/qreliablefilewatch.cpp gui//qcodeedit-2.2.3/qreliablefilewatch.h gui//qcodeedit-2.2.3/snippets/qsnippet.cpp gui//qcodeedit-2.2.3/snippets/qsnippet.h gui//qcodeedit-2.2.3/snippets/qsnippet_p.h gui//qcodeedit-2.2.3/snippets/qsnippetbinding.cpp gui//qcodeedit-2.2.3/snippets/qsnippetbinding.h gui//qcodeedit-2.2.3/snippets/qsnippetedit.cpp gui//qcodeedit-2.2.3/snippets/qsnippetedit.h gui//qcodeedit-2.2.3/snippets/qsnippetmanager.cpp gui//qcodeedit-2.2.3/snippets/qsnippetmanager.h gui//qcodeedit-2.2.3/snippets/qsnippetpatternloader.h gui//qcodeedit-2.2.3/snippets/snippetedit.ui gui//qcodeedit-2.2.3/widgets/editconfig.ui gui//qcodeedit-2.2.3/widgets/formatconfig.ui gui//qcodeedit-2.2.3/widgets/gotoline.ui gui//qcodeedit-2.2.3/widgets/gotolinedialog.ui gui//qcodeedit-2.2.3/widgets/qcalltip.cpp gui//qcodeedit-2.2.3/widgets/qcalltip.h gui//qcodeedit-2.2.3/widgets/qeditconfig.cpp gui//qcodeedit-2.2.3/widgets/qeditconfig.h gui//qcodeedit-2.2.3/widgets/qfoldpanel.cpp gui//qcodeedit-2.2.3/widgets/qfoldpanel.h gui//qcodeedit-2.2.3/widgets/qformatconfig.cpp gui//qcodeedit-2.2.3/widgets/qformatconfig.h gui//qcodeedit-2.2.3/widgets/qgotolinedialog.cpp gui//qcodeedit-2.2.3/widgets/qgotolinedialog.h gui//qcodeedit-2.2.3/widgets/qgotolinepanel.cpp gui//qcodeedit-2.2.3/widgets/qgotolinepanel.h gui//qcodeedit-2.2.3/widgets/qlinechangepanel.cpp gui//qcodeedit-2.2.3/widgets/qlinechangepanel.h gui//qcodeedit-2.2.3/widgets/qlinemarkpanel.cpp gui//qcodeedit-2.2.3/widgets/qlinemarkpanel.h gui//qcodeedit-2.2.3/widgets/qlinenumberpanel.cpp gui//qcodeedit-2.2.3/widgets/qlinenumberpanel.h gui//qcodeedit-2.2.3/widgets/qpanel.cpp gui//qcodeedit-2.2.3/widgets/qpanel.h gui//qcodeedit-2.2.3/widgets/qsearchreplacepanel.cpp gui//qcodeedit-2.2.3/widgets/qsearchreplacepanel.h gui//qcodeedit-2.2.3/widgets/qsimplecolorpicker.cpp gui//qcodeedit-2.2.3/widgets/qsimplecolorpicker.h gui//qcodeedit-2.2.3/widgets/qstatuspanel.cpp gui//qcodeedit-2.2.3/widgets/qstatuspanel.h gui//qcodeedit-2.2.3/widgets/searchreplace.ui gui//src/QTerminalWidget.cpp gui//src/QTerminalWidget.h
diffstat 97 files changed, 34891 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/GPL.txt	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/README.txt	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,175 @@
+
+----------------------------------------------------------------------------------
+----------------------------------------------------------------------------------
+  
+        QCodeEdit, copyright (c) 2006-2009 Luc Bruant aka fullmetalcoder,
+                  is a free and open source software
+  
+  QCodeEdit sources are part of Edyuk and are thus available under GNU General Public
+  License version 3 (GPL v3), as published by the Free Software Foundation.
+
+----------------------------------------------------------------------------------
+----------------------------------------------------------------------------------
+
+QCodeEdit is a project aiming at the creation of a flexible and powerful text
+editing framework for Qt4. It has started as a sub-project of Edyuk, copyright (c)
+Luc Bruant, a free and open source IDE. As it proved successful it is also
+released as a standalone library to make it easy for everyone to use such
+a framework within other apps without having to reinvent the wheel.
+
+Writing closed source applications with QCodeEdit is possible after buying a
+proper license. For more informations about pricing and licensing conditions
+please contact the author directly <non.deterministic.finite.organism@gmail.com>
+Note that you will still need a Qt commercial license for that or, starting with
+Qt 4.5, a LGPL one.
+
+QCodeEdit depends on Qt 4.3 or newer, copyright (c) Nokia Corporation, which can
+be downloaded at : ftp://ftp.trolltech.com/qt/sources
+
+More information about Qt and Qt Software (formerly Trolltech) :
+http://www.qtsoftware.com
+
+Hoping you'll like it.
+
+
+The author would like to thank all the people who contributed to QCodeEdit in various ways :
+
+ * testing, reporting bugs, making suggestions :
+	Jeremy Sonander, from Saros Inc
+	Phil Martinot
+	Benito van der Zander
+	Ulrich Van Den Hekke
+	Boris Barbulovski
+	
+ * contributing patches :
+	Jerome Vizcaino
+	Benito van der Zander
+	Ulrich Van Den Hekke
+	Boris Barbulovski
+
+ * funding (by buying commercial licenses) :
+	Saros Inc
+	Movimento SE
+
+ * spreading the word :
+	Johan Thelin (posted a blog post that appeared on PlanetKDE)
+
+(If you have been forgotten send an email to the author and the list will be updated)
+
+
+IMPORTANT : If you encounter any sort of troubles trying to build or run QCodeEdit
+please send a bug report with as many details as possible (including but not limited
+to : OS, Qt version, compiler, QCodeEdit version, compile log, backtrace, ...) to the
+team using either of these :
+	* staff@qcodeedit.edyuk.org
+	* Edyuk task tracker on Sf.net : http://sf.net/projects/edyuk
+	* Edyuk webissues server (needs a WebIssues client) : http://edyuk.org/webissues/
+		- login		: anonymous
+		- password	: anonymous
+	* QtCentre dedicated thread in Qt Software section : http://www.qtcentre.org/forum
+
+
+In case you don't understand, blocks of text enclosed between lines of minus signs are
+shell commands. The dollar signs just stand for command prompt.
+
+
+ >>> Building :
+
+------------------------------------------------------------------------------------------
+$ qmake
+$ make
+------------------------------------------------------------------------------------------
+
+This will build the library and the example. You may want to alter the build mode to force
+either debug or release. If so just pass the mode you want to make, e.g. :
+
+------------------------------------------------------------------------------------------
+$ make release
+------------------------------------------------------------------------------------------
+or
+------------------------------------------------------------------------------------------
+$ make debug
+------------------------------------------------------------------------------------------
+
+Finally, with admins rights/root privilegdes, you can install QCodeEdit so as to be able
+to use it simply :
+
+------------------------------------------------------------------------------------------
+$ qmake
+$ make install
+------------------------------------------------------------------------------------------
+
+NB : the extra "qmake" is NEEDED to ensure that binaries will be located and copied properly.
+NB 2 : Only the "make install" command requires root priviledges, "qmake" can and should
+always be run as normal user.
+NB 3 : Apart from libs and headers, QCodeEdit also provides a .prf file which makes it
+easier to use the lib in another project. Under non-Unix platforms it is recommended to
+copy the files manually (and possibly edit them to fit your needs).
+
+
+ >>> Using within an app :
+
+To have one of your app building with QCodeEdit just add the following line to your project
+file (this won't work if you have not installed QCodeEdit as described above....) :
+
+CONFIG += qcodeedit
+
+If you did not install QCodeEdit as described above you will have to either update the file
+qcodeedit.prf or inspect it to determine what project variables need to be adjusted and how.
+
+Then, add proper headers in your sources and start coding. :D
+
+
+ >>> Testing :
+
+A very basic example is provided which open a list of files passed as parameters
+and try to highlight them according to their file extension. Only a few language
+definitions are provided :
+  * C++ (with Doxygen support)
+  * PHP
+  * XML
+  * Doxygen alone (for .dox files)
+  * QMake project files
+  * Python
+  * QtScript/JavaScript
+  * C# (WIP)
+  * Lua (WIP)
+  * LaTex (WIP)
+  * BibTex (WIP)
+
+If you write a new one for your own use (or modify an existing one to suit you needs)
+please consider contributing it back to the project.
+
+------------------------------------------------------------------------------------------
+$ example/example [file]
+------------------------------------------------------------------------------------------
+
+Note : on Unix system it is recommended to use the script due to the need of setting
+the LD_LIBRARY_PATH variable properly :
+
+------------------------------------------------------------------------------------------
+$ ./example.sh [file]
+------------------------------------------------------------------------------------------
+
+NB : [file] stands for a filename. If omitted a minimal string will be loaded and
+considered as C++ source code
+
+
+ >>> Generating documentation [needs Doxygen : http://www.doxygen.org] :
+
+------------------------------------------------------------------------------------------
+$ doxygen
+------------------------------------------------------------------------------------------
+
+NB :
+	* This will create the documentation in the doc folder. Just open doc/html/index.html
+
+
+ >>> Fetching bleeding edge sources [needs Subversion : http://subversion.tigris.org] :
+
+------------------------------------------------------------------------------------------
+$ svn co http://edyuk.svn.sf.net/svnroot/edyuk/trunk/3rdparty/qcodeedit2
+------------------------------------------------------------------------------------------
+
+NB : Using a graphical client this command extends to a "checkout" action using the above
+repository URL.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocument.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,6617 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2008 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+**
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qdocument.h"
+
+/*
+	Document model :
+	
+	Goals :
+		* KISS : Keep It Simple Stupid
+		* FAST : ...
+		* LIGHTWEIGHT : reduce memory usage
+		* FLEXIBLE : allow punctual bidi through QTextLayout
+		
+	Implementation :
+		QDocument
+		QDocumentPrivate
+		
+		QDocumentLine and QDocumentLineHandle => equivalent of QTextBlock
+		QDocumentCursor and QDocumentCursorHandle => equivalent of QTextCursor
+	
+	Note :
+		The KISS principle has been kinda mistreated in the private API due to
+		the addition of some complex features which where not planned to be
+		supported when defining the goals (e.g line wrapping, variable width
+		fonts, ...). Such a compromission is affordable but should be avoided
+		whenever possible in the future. And of course the public API should
+		never suffer from such a thing.
+*/
+
+/*!
+	\ingroup document
+	@{
+*/
+
+/*!
+	\class QDocument
+	
+	\brief A class storing a document
+	
+	QCE uses an architecture very similar to that of QTextEdit/QTextDocument
+	which closely ressembles model/view. The document holds all the textual
+	and formatting data. It offers some (mostly indirect) ways of modifying
+	its content and is usable without any GUI.
+	
+	In QCE, a document is merely a list of QDocumentLine objects on which some
+	extra formatting can be applied and which can be wrapped/hidden in various
+	ways.
+	
+	The document model has been designed with three goals in mind :
+	<ul>
+	<li>performance
+	<li>flexibility
+	<li>low memory usage
+	</ul>
+	
+	QDocument supports Bidi by using QTextLayout on lines that require it and
+	prefers custom rendering in other cases to achieve the above goals.
+	
+	All the actual text editing is done through QDocumentCursor objects.
+	
+	\see QDocumentLine
+	\see QDocumentCursor
+*/
+
+#include "qdocument_p.h"
+#include "qdocumentcommand.h"
+
+#include "qformat.h"
+#include "qformatscheme.h"
+#include "qlanguagedefinition.h"
+#include "qlinemarksinfocenter.h"
+
+#include <QPen>
+#include <QTime>
+#include <QRect>
+#include <QLine>
+#include <QPainter>
+#include <QPrinter>
+#include <QTextStream>
+#include <QTextLayout>
+#include <QApplication>
+#include <QVarLengthArray>
+#include <QMessageBox>
+
+static int m_spaceSignOffset = 2;
+
+static QPoint m_spaceSign[] = {
+	QPoint(2, -1),
+	QPoint(2, 0),
+	QPoint(3, 0)
+};
+
+inline static bool isWord(QChar c)
+{ return c.isLetterOrNumber() || (c == QLatin1Char('_')); }
+
+int QDocument::screenLength(const QChar *d, int l, int tabStop)
+{
+	if ( tabStop == 1 )
+		return l;
+	
+	int idx, column = idx = 0;
+	
+	while ( idx < l )
+	{
+		QChar c = d[idx];
+		
+		if ( c == QLatin1Char('\t') )
+		{
+			int taboffset = tabStop - (column % tabStop);
+			column += taboffset;
+		} else {
+			++column;
+		}
+		
+		++idx;
+	}
+	
+	//qDebug("%s : %i", qPrintable(QString(d, l)), column);
+	
+	return column;
+}
+
+QString QDocument::screenable(const QChar *d, int l, int tabStop)
+{
+	if ( tabStop == 1 )
+		return QString(d, l);
+	
+	QString fragment;
+	int idx, column = idx = 0;
+	
+	while ( idx < l )
+	{
+		QChar c = d[idx];
+		
+		if ( c == QLatin1Char('\t') )
+		{
+			int taboffset = tabStop - (column % tabStop);
+			
+			fragment += QString(taboffset, QLatin1Char(' '));
+			column += taboffset;
+		} else {
+			fragment += c;
+			++column;
+		}
+		
+		++idx;
+	}
+	
+	return fragment;
+}
+
+struct InitStruct
+{
+	InitStruct()
+	{
+		qRegisterMetaType<QDocumentIterator>("QDocumentIterator");
+		qRegisterMetaType<QDocumentConstIterator>("QDocumentConstIterator");
+	}
+};
+
+static InitStruct init_inst;
+
+/*!
+	\brief ctor
+*/
+QDocument::QDocument(QObject *p)
+ : QObject(p), m_impl(new QDocumentPrivate(this))
+{
+	if ( !QDocumentPrivate::m_font )
+	{
+		// must not happen if config dialog plugged in...
+		setFont(QFont("Monospace", 10));
+	}
+	
+	setText(QString());
+	setLineEnding(QDocument::Conservative);
+	
+	connect(&(m_impl->m_commands)	, SIGNAL( cleanChanged(bool) ),
+			this					, SIGNAL( cleanChanged(bool) ) );
+	
+	connect(&(m_impl->m_commands)	, SIGNAL( canUndoChanged(bool) ),
+			this					, SIGNAL( undoAvailable(bool) ) );
+	
+	connect(&(m_impl->m_commands)	, SIGNAL( canRedoChanged(bool) ),
+			this					, SIGNAL( redoAvailable(bool) ) );
+	
+	connect(this							,
+			SIGNAL( lineDeleted(QDocumentLineHandle*) ),
+			QLineMarksInfoCenter::instance(),
+			SLOT  ( lineDeleted(QDocumentLineHandle*) ) );
+			
+}
+
+/*!
+	\brief dtor
+*/
+QDocument::~QDocument()
+{
+	delete m_impl;
+}
+
+/*!
+	\brief Clear the content of the document
+*/
+void QDocument::clear()
+{
+	setText(QString());
+}
+
+/*!
+	\return whether there commands to undo on the command stack
+*/
+bool QDocument::canUndo() const
+{
+	return m_impl ? m_impl->m_commands.canUndo() : false;
+}
+
+/*!
+	\return whether there are commands to redo on the command stack
+*/
+bool QDocument::canRedo() const
+{
+	return m_impl ? m_impl->m_commands.canRedo() : false;
+}
+
+/*!
+	\brief Undo the last editing operation
+*/
+void QDocument::undo()
+{
+	if ( m_impl )
+	{
+		m_impl->m_commands.undo();
+		m_impl->m_lastModified = QDateTime::currentDateTime();
+	}
+}
+
+/*!
+	\brief Redo the last undone editing operation
+*/
+void QDocument::redo()
+{
+	if ( m_impl )
+	{
+		m_impl->m_commands.redo();
+		m_impl->m_lastModified = QDateTime::currentDateTime();
+	}
+	
+}
+
+/*!
+	\return The content of the document
+	\param mode extra processing to perform on text
+*/
+QString QDocument::text(int mode) const
+{
+	QString s;
+	
+	if ( !m_impl || m_impl->m_lines.isEmpty() )
+		return s;
+	
+	int line = 0;
+	int prevIndent = 0, curIndent = 0, nextIndent = m_impl->m_lines.at(0)->nextNonSpaceChar(0);
+	
+	if ( nextIndent < 0 )
+		nextIndent = 0;
+	
+	foreach ( QDocumentLineHandle *l, m_impl->m_lines )
+	{
+		prevIndent = curIndent;
+		curIndent = nextIndent;
+		nextIndent = ++line < m_impl->m_lines.count() ? m_impl->m_lines.at(line)->nextNonSpaceChar(0) : 0;
+		
+		if ( nextIndent < 0 )
+			nextIndent = 0;
+		
+		QString buf = l->text();
+		int avgIndent = qMax(prevIndent, nextIndent);
+		
+		if ( (mode & RestoreTrailingIndent) && buf.isEmpty() && avgIndent )
+		{
+			buf = QString(avgIndent, '\t');
+		} else if ( mode & RemoveTrailingWS ) {
+			
+			int len = 0, idx = buf.length();
+			
+			while ( --idx >= 0 )
+			{
+				if ( !buf.at(idx).isSpace() )
+					break;
+				
+				++len;
+			}
+			
+			++idx;
+			
+			if ( len && (idx || !(mode & PreserveIndent)) )
+				buf.remove(idx, len);
+		}
+		
+		s += buf + m_impl->m_lineEndingString;
+	}
+	
+	//s.chop(m_impl->m_lineEndingString.count());
+	return s;
+}
+
+/*!
+	\return The content of the document
+	\param removeTrailing whether to remove trailing whitespaces
+	\param preserveIndent whether to keep trailing whitespaces when they are indent
+*/
+QString QDocument::text(bool removeTrailing, bool preserveIndent) const
+{
+	int mode = 0;
+	
+	if ( removeTrailing )
+		mode |= RemoveTrailingWS;
+	
+	if ( preserveIndent )
+		mode |= PreserveIndent;
+	
+	return text(mode);
+}
+
+/*!
+	\brief Set the content of the document
+*/
+void QDocument::setText(const QString& s)
+{
+	if ( !m_impl )
+		return;
+	
+	int last = 0, idx = 0;
+	
+	m_impl->m_deleting = true;
+	
+	//qDeleteAll(m_impl->m_lines);
+	foreach ( QDocumentLineHandle *h, m_impl->m_lines )
+	{
+		h->m_doc = 0;
+		h->deref();
+	}
+	
+	QDocumentCommand::discardHandlesFromDocument(this);
+	
+	m_impl->m_lines.clear();
+	m_impl->m_marks.clear();
+	m_impl->m_status.clear();
+	m_impl->m_hidden.clear();
+	m_impl->m_wrapped.clear();
+	m_impl->m_matches.clear();
+	m_impl->m_largest.clear();
+	m_impl->m_commands.clear();
+	
+	m_impl->m_deleting = false;
+	
+	if ( s.isEmpty() )
+		m_impl->m_lines << new QDocumentLineHandle(QString(), this);
+	
+	m_impl->_nix = 0;
+	m_impl->_dos = 0;
+	m_impl->_mac = 0;
+	
+	while ( idx < s.length() )
+	{
+		if ( s.at(idx) == '\n' )
+		{
+			if ( (idx > 0) && (s.at(idx - 1) == '\r') )
+			{
+				++(m_impl->_dos);
+				
+				m_impl->m_lines << new QDocumentLineHandle(
+										s.mid(last, idx - last - 1),
+										this
+									);
+			} else {
+				++(m_impl->_nix);
+				
+				m_impl->m_lines << new QDocumentLineHandle(
+										s.mid(last, idx - last),
+										this
+									);
+			}
+			
+			last = ++idx;
+		} else if ( s.at(idx) == '\r' ) {
+			++idx;
+			if ( idx >= s.length() || (s.at(idx) != '\n') )
+			{
+				++(m_impl->_mac);
+				
+				m_impl->m_lines << new QDocumentLineHandle(
+										s.mid(last, idx - last - 1),
+										this
+									);
+				
+				last = idx;
+			}
+		} else {
+			++idx;
+		}
+	}
+	
+	if ( idx != last )
+	{
+		m_impl->m_lines << new QDocumentLineHandle(
+								s.mid(last, s.length() - last),
+								this
+							);
+	
+	}
+//
+//	if ( (idx > 0) && ((idx - 1) < s.length()) && ((s.at(idx - 1) == '\n') || (s.at(idx - 1) == '\r')) )
+//		m_impl->m_lines << new QDocumentLineHandle(this);
+//
+	
+	//qDebug("[one go] dos : %i; nix : %i", m_impl->_dos, m_impl->_nix);
+	
+	m_impl->m_lastModified = QDateTime::currentDateTime();
+	
+	if ( lineEnding() == Conservative )
+		setLineEnding(Conservative);
+	
+	m_impl->setWidth();
+	m_impl->setHeight();
+	
+	emit lineCountChanged(lineCount());
+	
+	m_impl->emitContentsChange(0, m_impl->m_lines.count());
+}
+
+/*!
+	\brief Start a chunk loading
+	
+	It is possible to load document contents in one piece
+	or by chunks. To achieve the later you have to proceed as follows :
+	
+	\code
+	QDocument doc;
+	doc.startChunkLoading();
+	
+	// fetch data and add it using doc.addChunk();
+	
+	doc.stopChunkLoading();
+	\endcode
+	
+	\see addChunk(const QString&)
+	\see stopChunkLoading()
+*/
+void QDocument::startChunkLoading()
+{
+	if ( !m_impl )
+		return;
+	
+	m_impl->m_deleting = true;
+	
+	//qDeleteAll(m_impl->m_lines);
+	foreach ( QDocumentLineHandle *h, m_impl->m_lines )
+	{
+		h->m_doc = 0;
+		h->deref();
+	}
+	
+	m_impl->m_lines.clear();
+	m_impl->m_marks.clear();
+	m_impl->m_status.clear();
+	m_impl->m_hidden.clear();
+	m_impl->m_wrapped.clear();
+	m_impl->m_matches.clear();
+	m_impl->m_largest.clear();
+	m_impl->m_commands.clear();
+	
+	m_impl->m_deleting = false;
+	
+	m_impl->_nix = 0;
+	m_impl->_dos = 0;
+	m_impl->_mac = 0;
+	
+	m_leftOver.clear();
+}
+
+/*!
+	\brief Stop chunk loading
+	
+	\see startChunkLoading()
+*/
+void QDocument::stopChunkLoading()
+{
+	if ( m_leftOver.count() )
+	{
+		m_impl->m_lines << new QDocumentLineHandle(
+								m_leftOver,
+								this
+							);
+		
+		m_leftOver.clear();
+		
+	} else {
+		//m_impl->m_lines << new QDocumentLineHandle(this);
+	}
+	
+	//qDebug("[chunk] dos : %i; nix : %i", m_impl->_dos, m_impl->_nix);
+	
+	m_impl->m_lastModified = QDateTime::currentDateTime();
+	
+	if ( lineEnding() == Conservative )
+		setLineEnding(Conservative);
+	
+	m_impl->setWidth();
+	m_impl->setHeight();
+	
+	emit lineCountChanged(lineCount());
+	
+	emit m_impl->emitContentsChange(0, m_impl->m_lines.count());
+}
+
+/*!
+	\return The format scheme used by the document
+*/
+QFormatScheme* QDocument::formatScheme() const
+{
+	return m_impl ? m_impl->m_formatScheme : 0;
+}
+
+/*!
+	\brief Set the format scheme used by the document
+*/
+void QDocument::setFormatScheme(QFormatScheme *f)
+{
+	if ( m_impl )
+		m_impl->setFormatScheme(f);
+}
+
+/*!
+	\return the language definition set to the document
+*/
+QLanguageDefinition* QDocument::languageDefinition() const
+{
+	return m_impl ? m_impl->m_language : 0;
+}
+
+/*!
+	\brief Set the language definition
+*/
+void QDocument::setLanguageDefinition(QLanguageDefinition *f)
+{
+	if ( m_impl )
+		m_impl->m_language = f;
+}
+
+/*!
+	\brief Update the formatting of the whole document
+	This function is only useful when changing the language definition
+	of a non-empty document. Make sure you do not call it more often
+	than needed.
+*/
+void QDocument::highlight()
+{
+	if ( m_impl )
+		m_impl->emitContentsChange(0, lines());
+}
+
+/*!
+	\brief Add a chunk of text to the document
+*/
+void QDocument::addChunk(const QString& txt)
+{
+	if ( !m_impl || txt.isEmpty() )
+		return;
+	
+	m_leftOver += txt;
+	int idx = 0, last = 0;
+	
+	while ( idx < m_leftOver.length() )
+	{
+		if ( m_leftOver.at(idx) == '\n' )
+		{
+			if ( (idx > 0) && (m_leftOver.at(idx - 1) == '\r') )
+			{
+				++(m_impl->_dos);
+				
+				m_impl->m_lines << new QDocumentLineHandle(
+										m_leftOver.mid(last, idx - last - 1),
+										this
+									);
+			} else {
+				++(m_impl->_nix);
+				
+				m_impl->m_lines << new QDocumentLineHandle(
+										m_leftOver.mid(last, idx - last),
+										this
+									);
+			}
+			
+			last = ++idx;
+		} else if ( m_leftOver.at(idx) == '\r' ) {
+			++idx;
+			if ( idx >= m_leftOver.length() || (m_leftOver.at(idx) != '\n') )
+			{
+				++(m_impl->_mac);
+				
+				m_impl->m_lines << new QDocumentLineHandle(
+										m_leftOver.mid(last, idx - last - 1),
+										this
+									);
+				
+				last = idx;
+			}
+		} else {
+			++idx;
+		}
+	}
+	
+	if ( idx != last )
+		m_leftOver = m_leftOver.mid(last);
+	else
+		m_leftOver.clear();
+	
+}
+
+/*!
+	\brief Print the content of the document
+	\param pr printer to use
+	
+	\note the printer MUST be initialized (probably using a printing dialog)
+*/
+void QDocument::print(QPrinter *pr)
+{
+	QRect fit = pr->pageRect();
+	
+	if ( pr->printRange() == QPrinter::Selection )
+	{
+		qWarning("printing selection not implemented yet");
+		return;
+	}
+	
+	if ( fit.width() < width() )
+	{
+		// TODO: got to temporarily wrap text to fit page size
+		
+		qWarning("temporary wrapping not implementated yet");
+	}
+	
+	const int lineCount = lines();
+	const int linesPerPage = fit.height() / m_impl->m_lineSpacing;
+	int pageCount = lineCount / linesPerPage;
+	
+	if ( lineCount % linesPerPage )
+		++pageCount;
+	
+	//qDebug("%i lines per page -> %i pages", linesPerPage, pageCount);
+	
+	const int pageWidth = fit.width();
+	const int pageHeight = linesPerPage * m_impl->m_lineSpacing;
+	
+	int firstPage = pr->fromPage(), lastPage = pr->toPage();
+	
+	if ( !lastPage )
+		lastPage = pageCount - 1;
+	
+	QPainter p(pr);
+	PaintContext cxt;
+	cxt.xoffset = 0;
+	cxt.yoffset = firstPage * pageHeight;
+	cxt.width = pageWidth;
+	cxt.height = pageHeight - m_impl->m_lineSpacing;
+	cxt.palette = QApplication::palette();
+	cxt.fillCursorRect = false;
+	cxt.blinkingCursor = false;
+	
+	for ( int i = firstPage; i <= lastPage; ++i )
+	{
+		draw(&p, cxt);
+		
+		cxt.yoffset += pageHeight;
+		
+		if ( i != lastPage )
+		{
+			pr->newPage();
+			p.translate(0, -pageHeight);
+		}
+	}
+}
+
+/*!
+	\return The line ending policy of the document
+	
+	The line ending policy determines how line endings
+	are used when saving the document (which includes
+	fetching the document's text()).
+	
+	It can either be conservative (auto detect upon loading
+	and do not modify when saving later on) or enforce
+	a particular line ending (either local line ending
+	or a specific value).
+*/
+QDocument::LineEnding QDocument::lineEnding() const
+{
+	return m_impl ? m_impl->m_lineEnding : Local;
+}
+
+/*!
+	\return the lin endings detected upon loading
+	
+	This should only ever take the the Window of Linux value
+	if a document has been loaded. If no content has been
+	loaded it will fall back to Local.
+*/
+QDocument::LineEnding QDocument::originalLineEnding() const
+{
+	if ( !m_impl )
+		return Local;
+	
+	bool dosVSnix = m_impl->_dos > m_impl->_nix;
+	bool dosVSmac = m_impl->_dos > m_impl->_mac;
+	bool nixVSmac = m_impl->_nix > m_impl->_mac;
+	
+	// nothing loaded thus far
+	if ( !(dosVSnix || dosVSmac || nixVSmac) )
+		return Local;
+	
+	return dosVSnix ? (dosVSmac ? Windows : OldMac) : (nixVSmac ? Unix : OldMac);
+}
+
+/*!
+	\brief Set the line ending policy of the document
+*/
+void QDocument::setLineEnding(LineEnding le)
+{
+	if ( !m_impl )
+		return;
+	
+	m_impl->m_lineEnding = le;
+	QString& les = m_impl->m_lineEndingString;
+	
+	/*
+		Notes about "local" line endings :
+		 * Dos & co : well defined CRLF
+		 * Unix & co : well defined LF
+		 * Mac : CR up until OS 9 LF afterwards (OSX is Unix-based)
+
+		 Guess about macros (to be confirmed/infirmed) : 
+			Q_OS_UNIX *should* be set under OSX
+			Q_OS_MAC *might* be set under OSX
+
+		=> order #ifdefs to try avoiding troubles
+	*/
+	#ifdef Q_OS_WIN
+	const QString loc_les = "\r\n";
+	#elif defined(Q_OS_UNIX)
+	const QString loc_les = "\n";
+	#elif defined(Q_OS_MAC)
+	const QString loc_les = "\r";
+	#else
+
+	const QString loc_les = "\n";
+	#endif
+	
+	switch ( le )
+	{
+		case Conservative :
+			switch ( originalLineEnding() )
+			{
+				case Windows :
+					les = "\r\n";
+					break;
+				case OldMac :
+					les = "\r";
+					break;
+				case Unix :
+					les = "\n";
+				default:
+					les = loc_les;
+					break;
+			}
+			break;
+			
+		case Unix :
+			les = "\n";
+			break;
+			
+		case OldMac :
+			les = "\r";
+			break;
+			
+		case Windows :
+			les = "\r\n";
+			break;
+			
+		default :
+			les = "\n";
+			break;
+	}
+	
+	emit lineEndingChanged(le);
+}
+
+/*!
+	\return the font used by ALL documents to render their content
+	
+	This font is also used to do calculations (such as converting
+	(line, column) cursor position to (x, y) document position (or
+	the inverse transformation))
+	
+	\note this limitation is historic and may disappear
+	in future versions
+*/
+QFont QDocument::font()
+{
+	return *(QDocumentPrivate::m_font);
+}
+
+/*!
+	\brief Set the font of ALL documents
+	
+	\note this limitation is historic and may disappear
+	in future versions
+*/
+void QDocument::setFont(const QFont& f)
+{
+	QDocumentPrivate::setFont(f);
+	//emit contentsChanged();
+}
+
+/*!
+	\return The font metrics used by ALL documents
+	
+	\note this limitation is historic and may disappear
+	in future versions
+*/
+const QFontMetrics& QDocument::fontMetrics()
+{
+	return *(QDocumentPrivate::m_fontMetrics);
+}
+
+/*!
+	\return The default tab stop common to ALL documents
+	
+	\note this limitation is historic and may disappear
+	in future versions
+*/
+int QDocument::tabStop()
+{
+	return QDocumentPrivate::m_defaultTabStop;
+}
+
+/*!
+	\brief Set the default tab stop common to all documents
+	
+	\note this limitation is historic and may disappear
+	in future versions
+*/
+void QDocument::setTabStop(int n)
+{
+	QDocumentPrivate::m_defaultTabStop = n;
+	
+	foreach ( QDocumentPrivate *d, QDocumentPrivate::m_documents )
+	{
+		d->m_tabStop = n;
+		d->emitFormatsChanged();
+	}
+}
+
+/*!
+	\return the whitesapce display mode
+*/
+QDocument::WhiteSpaceMode QDocument::showSpaces()
+{
+	return QDocumentPrivate::m_showSpaces;
+}
+
+/*!
+	\brief Set the whitespace display mode
+*/
+void QDocument::setShowSpaces(WhiteSpaceMode m)
+{
+	QDocumentPrivate::m_showSpaces = m;
+	
+	foreach ( QDocumentPrivate *d, QDocumentPrivate::m_documents )
+		d->emitFormatsChanged();
+		
+}
+
+/*!
+	\brief Set the edit cursor
+	
+	Archaic concept designed for use in QEditor
+	(is it still used???)
+*/
+QDocumentCursor* QDocument::editCursor() const
+{
+	return m_impl ? m_impl->m_editCursor : 0;
+}
+
+/*!
+	\brief Set the edit cursor
+	
+	\see editCursor()
+*/
+void QDocument::setEditCursor(QDocumentCursor *c)
+{
+	if ( m_impl )
+		m_impl->m_editCursor = c;
+		
+}
+
+/*!
+	\return the width of the document, in pixels
+	
+	The width of the document is that of longest text line.
+*/
+int QDocument::width() const
+{
+	return m_impl ? m_impl->m_width : 0;
+}
+
+/*!
+	\return the height of the document, in pixels
+*/
+int QDocument::height() const
+{
+	return m_impl ? m_impl->m_height : 0;
+}
+
+/*!
+	\return The width constraint imposed on that document
+	
+	Setting a width constraint on a document achieves line
+	wrapping.
+*/
+int QDocument::widthConstraint() const
+{
+	return (m_impl && m_impl->m_constrained) ? m_impl->m_width : 0;
+}
+
+/*!
+	\return the number of text lines in the document
+	
+	The number of visual lines may differ from that of text
+	lines as soon as line wrapping and/or folding are enabled.
+	
+	\deprecated Use lineCount() instead
+*/
+int QDocument::lines() const
+{
+	return m_impl ? m_impl->m_lines.count() : 0;
+}
+
+/*!
+	\return the number of text lines in the document
+	
+	The number of visual lines may differ from that of text
+	lines as soon as line wrapping and/or folding are enabled.
+*/
+int QDocument::lineCount() const
+{
+	return m_impl ? m_impl->m_lines.count() : 0;
+}
+
+/*!
+	\return the number of visual lines in the document
+	\deprecated Use visualLineCount() instead
+*/
+int QDocument::visualLines() const
+{
+	return m_impl ? m_impl->visualLine(m_impl->m_lines.count() - 1) : 0;
+}
+
+/*!
+	\return the number of visual lines in the document
+*/
+int QDocument::visualLineCount() const
+{
+	return m_impl ? m_impl->visualLine(m_impl->m_lines.count() - 1) : 0;
+}
+
+/*!
+	\brief Convert a text (logical) line number int a visual line number
+	
+	\note this is not a 1:1 mapping as logical lines can span over several visual lines
+*/
+int QDocument::visualLineNumber(int textLineNumber) const
+{
+	return m_impl ? m_impl->visualLine(textLineNumber) : -1;
+}
+
+/*!
+	\brief Convert a visual line number int a text (logical) line number
+	
+	\note this is not a 1:1 mapping as logical lines can span over several visual lines
+*/
+int QDocument::textLineNumber(int visualLineNumber) const
+{
+	return m_impl ? m_impl->textLine(visualLineNumber) : -1;
+}
+
+/*!
+	\brief Clear the width constraint, if any
+*/
+void QDocument::clearWidthConstraint()
+{
+	if ( m_impl )
+		m_impl->setWidth(0);
+}
+
+/*!
+	\brief Set a new width constraint
+	\param width maximum width to allow
+	
+	Passing a value inferior (or equal) to zero clear the width constraint, if any.
+*/
+void QDocument::setWidthConstraint(int width)
+{
+	if ( m_impl )
+		m_impl->setWidth(qMax(0, width));
+}
+
+/*!
+	\return the line object at a given line number
+	\param line Text line to acces
+*/
+QDocumentLine QDocument::line(int line) const
+{
+	return QDocumentLine(m_impl->at(line));
+}
+
+/*!
+	\return the line number corresponding to a given document y coordinate
+	\param ypos Y document coordinate of the target
+	\param wrap if not null, will be set to the wrap offset (position of the
+	visual line among the sublines of the wrapped text line).
+	
+*/
+int QDocument::lineNumber(int ypos, int *wrap) const
+{
+	int ln = ypos / m_impl->m_lineSpacing;
+	
+	return m_impl->textLine(ln, wrap);
+}
+
+/*!
+	\return the line object to which an iterator points
+*/
+QDocumentLine QDocument::line(QDocumentConstIterator iterator) const
+{
+	return (m_impl && (m_impl->constEnd() != iterator)) ? QDocumentLine(*iterator) : QDocumentLine();
+}
+
+/*!
+	\return A cursor operating on the document, placed at a given position
+	\param line target line number (text line)
+	\param column target text column
+*/
+QDocumentCursor QDocument::cursor(int line, int column) const
+{
+	return QDocumentCursor(const_cast<QDocument*>(this), line, column);
+}
+
+/*!
+	\return the document line which contains a given (document-wide) text position
+	
+	\note The sole purpose of this method is to have an API close to that of QTextDocument.
+	This method being ridiculously slow it is recommended to avoid it whenever possible.
+*/
+QDocumentLine QDocument::findLine(int& position) const
+{
+	if ( !m_impl )
+		return QDocumentLine();
+	
+	return QDocumentLine(m_impl->lineForPosition(position));
+}
+
+/*!
+	\return The Y document coordinate of a given line
+	\param ln textual line number
+*/
+int QDocument::y(int ln) const
+{
+	if ( !m_impl )
+		return -1;
+	
+	return m_impl->m_lineSpacing * m_impl->visualLine(ln);
+}
+
+/*!
+	\overload
+	
+	\return The Y document coordinate of a given line
+	\param l line object
+	
+	\note Significantly slower than the line number based version.
+*/
+int QDocument::y(const QDocumentLine& l) const
+{
+	qDebug("bad perf...");
+	
+	return y(l.lineNumber());
+}
+
+/*!
+	\return the rectangle (in document position) occupied by the line
+	\param line textual line number
+	
+	\note the width of the returned rectangle is the DOCUMENT's width
+*/
+QRect QDocument::lineRect(int line) const
+{
+	const int yoff = y(line);
+	
+	return (yoff != -1) ? QRect(0, yoff, width(), this->line(line).lineSpan() * m_impl->m_lineSpacing) : QRect();
+}
+
+/*!
+	\overload
+	\return the rectangle (in document position) occupied by the line
+	
+	\note the width of the returned rectangle is the DOCUMENT's width
+	\note Significantly slower than the line number based version.
+*/
+QRect QDocument::lineRect(const QDocumentLine& l) const
+{
+	//return lineRect(l.lineNumber());
+	const int yoff = y(l);
+	
+	return (yoff != -1) ? QRect(0, yoff, width(), m_impl->m_lineSpacing) : QRect();
+}
+
+/*!
+	\return the line at a given document position
+*/
+QDocumentLine QDocument::lineAt(const QPoint& p) const
+{
+	if ( !m_impl )
+		return QDocumentLine();
+	
+	return line(lineNumber(p.y()));
+}
+
+/*!
+	\return a document iterator pointing to the first line
+*/
+QDocumentConstIterator QDocument::begin() const
+{
+	Q_ASSERT(m_impl);
+	
+	return m_impl->m_lines.constBegin();
+}
+
+/*!
+	\return a document iterator pointing past the last line
+*/
+QDocumentConstIterator QDocument::end() const
+{
+	Q_ASSERT(m_impl);
+	
+	return m_impl->m_lines.constEnd();
+}
+
+/*!
+	\return a document iterator pointing to a given line
+*/
+QDocumentConstIterator QDocument::iterator(int ln) const
+{
+	Q_ASSERT(m_impl);
+	
+	return begin() + ln;
+}
+
+/*!
+	\overload
+	\note If you can avoid using this method, do so unless performance really isn't an issue
+*/
+QDocumentConstIterator QDocument::iterator(const QDocumentLine& l) const
+{
+	Q_ASSERT(m_impl);
+	
+	QDocumentConstIterator it = begin(), e = end();
+	
+	while ( (*it != l.handle()) && (it != e) )
+		++it;
+	
+	return it;
+}
+
+/*!
+	\brief Convert a document (or viewport) (x, y) position to a (line, column) cursor position
+	\param p document position
+	\param line where the line number will be stored
+	\param column where the column (text position within line) will be stored
+*/
+void QDocument::cursorForDocumentPosition(const QPoint& p, int& line, int& column) const
+{
+	if ( !m_impl )
+		return;
+	
+	int wrap = 0;
+	line = lineNumber(p.y(), &wrap);
+	QDocumentLine l = this->line(line);
+	
+	if ( !l.isValid() )
+		return;
+	
+	//qDebug("%i %i", line, wrap);
+	column = l.documentOffsetToCursor(p.x(), wrap * QDocumentPrivate::m_lineSpacing);
+	
+	//qDebug("(%i, %i) -> (%i [+%i], %i)", p.x(), p.y(), line, wrap, column);
+}
+
+/*!
+	\return The cursor nearest to a document (x, y) position
+*/
+QDocumentCursor QDocument::cursorAt(const QPoint& p) const
+{
+	int ln = -1, col = -1;
+	
+	cursorForDocumentPosition(p, ln, col);
+	
+	return QDocumentCursor(const_cast<QDocument*>(this), ln, col);
+}
+
+/*!
+	\brief Draw the contents of the document
+	\param p painter to use
+	\param cxt paint context (specifies what part of the document to draw, among other things)
+*/
+void QDocument::draw(QPainter *p, PaintContext& cxt)
+{
+	m_impl->draw(p, cxt);
+}
+
+/*!
+	\brief Execute a document command (editing operation)
+*/
+void QDocument::execute(QDocumentCommand *cmd)
+{
+	if ( m_impl && cmd )
+		m_impl->execute(cmd);
+		
+}
+
+/*!
+	\return The default line ending policy
+*/
+QDocument::LineEnding QDocument::defaultLineEnding()
+{
+	return QDocumentPrivate::m_defaultLineEnding;
+}
+
+/*!
+	\brief Set the default line ending policy
+	
+	\note The line ending policy of existing documents is changed accordingly
+*/
+void QDocument::setDefaultLineEnding(QDocument::LineEnding le)
+{
+	QDocumentPrivate::m_defaultLineEnding = le;
+	
+	foreach ( QDocumentPrivate *d, QDocumentPrivate::m_documents )
+	{
+		d->m_doc->setLineEnding(le);
+	}
+}
+
+/*!
+	\return The default format scheme used to draw document contents
+*/
+QFormatScheme* QDocument::defaultFormatScheme()
+{
+	return QDocumentPrivate::m_defaultFormatScheme;
+}
+
+/*!
+	\brief Set the default format scheme
+	
+	\note Existing documents using the default format scheme will see their format scheme changed
+*/
+void QDocument::setDefaultFormatScheme(QFormatScheme *f)
+{
+	foreach ( QDocumentPrivate *d, QDocumentPrivate::m_documents )
+	{
+		if ( d->m_formatScheme == QDocumentPrivate::m_defaultFormatScheme )
+			d->setFormatScheme(f);
+	}
+	
+	QDocumentPrivate::m_defaultFormatScheme = f;
+}
+
+/*!
+	\deprecated
+	\brief Compatibility alias for defaultFormatScheme()
+*/
+QFormatScheme* QDocument::formatFactory()
+{
+	return defaultFormatScheme();
+}
+
+/*!
+	\deprecated
+	\brief Compatibility alias for setDefaultFormatScheme()
+*/
+void QDocument::setFormatFactory(QFormatScheme *f)
+{
+	setDefaultFormatScheme(f);
+}
+
+/*!
+	\brief Begin a macro
+	
+	Macro in QDocument map directly to macro in the underlying undo stack
+*/
+void QDocument::beginMacro()
+{
+	if ( m_impl )
+		m_impl->beginChangeBlock();
+		
+}
+
+/*!
+	\brief End a macro
+*/
+void QDocument::endMacro()
+{
+	if ( m_impl )
+		m_impl->endChangeBlock();
+		
+}
+
+/*!
+	\brief Get an available group id for matches
+*/
+int QDocument::getNextGroupId()
+{
+	return m_impl ? m_impl->getNextGroupId() : -1;
+}
+
+void QDocument::releaseGroupId(int groupId)
+{
+	if ( m_impl )
+		m_impl->releaseGroupId(groupId);
+}
+
+/*!
+	\brief Clear matches
+*/
+void QDocument::clearMatches(int gid)
+{
+	if ( m_impl )
+	{
+		m_impl->clearMatches(gid);
+	}
+}
+
+/*!
+	\brief Highlight the matched sequences
+	
+	\note Both position are BEFORE the matched characters (cursor position).
+*/
+void QDocument::addMatch(int gid, int line, int pos, int len, int format)
+{
+	if ( m_impl )
+	{
+		m_impl->addMatch(gid, line, pos, len, format);
+	}
+}
+
+/*!
+	\
+*/
+void QDocument::flushMatches(int gid)
+{
+	if ( m_impl )
+	{
+		m_impl->flushMatches(gid);
+	}
+}
+
+/*!
+	\return Whether the document is in a clean state
+	
+	This is undo stak terminology. A clean document is one
+	whose undo stack is at the same index it was upon last
+	save/load. In other words : clean = !modified
+*/
+bool QDocument::isClean() const
+{
+	return m_impl ? m_impl->m_commands.isClean() : true;
+}
+
+/*!
+	\brief Set the document to clean state
+	
+	This method does not go back to clean state but tell
+	the stack that the current state is to be considered
+	as the clean state.
+*/
+void QDocument::setClean()
+{
+	if ( m_impl )
+	{
+		m_impl->m_commands.setClean();
+		//m_impl->m_status.clear();
+		
+		QHash<QDocumentLineHandle*, QPair<int, int> >::iterator it = m_impl->m_status.begin();
+		
+		while ( it != m_impl->m_status.end() )
+		{
+			it->second = it->first;
+			++it;
+		}
+	}
+}
+
+/*!
+	\return Whether a given line has been modified since last save/load
+*/
+bool QDocument::isLineModified(const QDocumentLine& l) const
+{
+	if ( !m_impl )
+		return false;
+	
+	QHash<QDocumentLineHandle*, QPair<int, int> >::const_iterator it = m_impl->m_status.constFind(l.handle());
+	
+	//if ( it != m_impl->m_status.constEnd() )
+	//	qDebug("%i vs %i", it->first, it->second);
+	
+	return it != m_impl->m_status.constEnd() ? it->first != it->second : false;
+}
+
+/*!
+	\return Whether a given line has been modified since last load
+*/
+bool QDocument::hasLineEverBeenModified(const QDocumentLine& l) const
+{
+	return m_impl ? m_impl->m_status.contains(l.handle()) : false;
+}
+
+/*!
+	\return the maximum number of marks on a single line
+	
+	This is meant for the line mark panel to smartly adapt its size.
+*/
+int QDocument::maxMarksPerLine() const
+{
+	return m_impl ? m_impl->maxMarksPerLine() : 0;
+}
+
+/*!
+	\brief Find the next mark of a given type
+	\return the line on which a mark was found
+	\param id mark identifier to find
+	\param from line from which to start search
+	\param until line until which to search
+	
+	\a from and \a until can be negatives, in which case they
+	indicate positions from the end of the document (i.e -1 is
+	last line, -2 the line before last line and so on).
+	
+	If \a until is inferior to \a from and no matching mark
+	is found in the [from, end] range then the [0, until]
+	range will also be searched.
+*/
+int QDocument::findNextMark(int id, int from, int until) const
+{
+	return m_impl ? m_impl->findNextMark(id, from, until) : -1;
+}
+
+/*!
+	\brief Find the previous mark of a given type
+	\return the line on which a mark was found
+	\param id mark identifier to find
+	\param from line from which to start search
+	\param until line until which to search
+	
+	\a from and \a until can be negatives, in which case they
+	indicate positions from the end of the document (i.e -1 is
+	last line, -2 the line before last line and so on).
+	
+	If \a until is superior to \a from and no matching mark
+	is found in the [0, from] range then the [until, end]
+	range will also be searched (both range being searched backward,
+	of course).
+*/
+int QDocument::findPreviousMark(int id, int from, int until) const
+{
+	return m_impl ? m_impl->findPreviousMark(id, from, until) : -1;
+}
+
+/*!
+	\return the date/time of the last modification of the document
+	
+	If the document has not been modified since its load the date/time
+	of last modification (as reported by QFileInfo) will be returned.
+*/
+QDateTime QDocument::lastModified() const
+{
+	return m_impl ? m_impl->m_lastModified : QDateTime();
+}
+
+/*!
+	\brief set the date/time of the last modification of the document
+	
+	You should not need to use that EVER. It is only provided for use
+	in QEditor (and possibly in some panels).
+*/
+void QDocument::setLastModified(const QDateTime& d)
+{
+	if ( m_impl )
+		m_impl->m_lastModified = d;
+}
+
+/////////////////////////
+//	QDocumentLineHandle
+/////////////////////////
+//static quint32 q_line_counter = 0;
+
+/*!
+	\class QDocumentLineHandle
+	\brief Private implementation of a document line
+*/
+
+/*!
+	\
+*/
+QDocumentLineHandle::QDocumentLineHandle(QDocument *d)
+ : m_doc(d)
+#if QT_VERSION >= 0x040400
+ , m_ref(1)
+#endif
+ , m_indent(0)
+ , m_state(QDocumentLine::LayoutDirty)
+ , m_layout(0)
+{
+	#if QT_VERSION < 0x040400
+	m_ref.init(1);
+	#endif
+}
+
+/*!
+	\
+*/
+QDocumentLineHandle::QDocumentLineHandle(const QString& s, QDocument *d)
+ : m_text(s)
+ , m_doc(d)
+#if QT_VERSION >= 0x040400
+ , m_ref(1)
+#endif
+ , m_indent(0)
+ , m_state(QDocumentLine::LayoutDirty)
+ , m_layout(0)
+{
+	#if QT_VERSION < 0x040400
+	m_ref.init(1);
+	#endif
+}
+
+QDocumentLineHandle::~QDocumentLineHandle()
+{
+	Q_ASSERT(!m_ref);
+	
+	if ( m_doc && m_doc->impl() )
+		m_doc->impl()->emitLineDeleted(this);
+}
+
+int QDocumentLineHandle::count() const
+{
+	return m_text.count();
+}
+
+int QDocumentLineHandle::length() const
+{
+	return m_text.length();
+}
+
+int QDocumentLineHandle::line() const
+{
+	return (m_doc && m_doc->impl()) ? m_doc->impl()->indexOf(this) : -1;
+}
+
+int QDocumentLineHandle::position() const
+{
+	return (m_doc && m_doc->impl()) ? m_doc->impl()->position(this) : -1;
+}
+
+QString QDocumentLineHandle::text() const
+{
+	return m_text;
+}
+
+int QDocumentLineHandle::indent() const
+{
+	int l = nextNonSpaceChar(0);
+	return QDocument::screenLength(m_text.constData(), l == -1 ? m_text.length() : l, m_doc->tabStop());
+}
+
+int QDocumentLineHandle::nextNonSpaceChar(uint pos) const
+{
+	const int len = m_text.length();
+	const QChar *unicode = m_text.unicode();
+	
+	for ( int i = pos; i < len; ++i )
+	{
+		if ( !unicode[i].isSpace() )
+			return i;
+	}
+	
+	return -1;
+}
+
+int QDocumentLineHandle::previousNonSpaceChar(int pos) const
+{
+	const int len = m_text.length();
+	const QChar *unicode = m_text.unicode();
+	
+	if ( pos < 0 )
+		pos = 0;
+		
+	if ( pos >= len )
+		pos = len - 1;
+		
+	for ( int i = pos; i >= 0; --i )
+	{
+		if ( !unicode[i].isSpace() )
+			return i;
+	}
+	
+	return -1;
+}
+
+QDocument* QDocumentLineHandle::document() const
+{
+	return m_doc;
+}
+
+bool QDocumentLineHandle::hasFlag(int s) const
+{
+	return m_state & s;
+}
+
+void QDocumentLineHandle::setFlag(int s, bool y) const
+{
+	if ( y )
+		m_state |= s;
+	else
+		m_state &= ~s;
+}
+
+QDocumentLineHandle* QDocumentLineHandle::next() const
+{
+	return (m_doc && m_doc->impl()) ? m_doc->impl()->next(this) : 0;
+}
+
+QDocumentLineHandle* QDocumentLineHandle::previous() const
+{
+	return (m_doc && m_doc->impl()) ? m_doc->impl()->previous(this) : 0;
+}
+
+void QDocumentLineHandle::updateWrap() const
+{
+	m_indent = 0;
+	m_frontiers.clear();
+	
+	if ( !m_doc->impl()->m_constrained )
+	{
+		if ( m_layout )
+			setFlag(QDocumentLine::LayoutDirty, true);
+		
+		return;
+	}
+	
+	const int tabStop = m_doc->impl()->m_tabStop;
+	const int maxWidth = m_doc->widthConstraint();
+	
+	if ( m_layout )
+	{
+		layout();
+	} else if ( QDocumentPrivate::m_fixedPitch ) {
+		
+		int idx = 0, minx = 0, lastBreak = 0, lastWidth = 0, lastX = 0, rx,
+			x = QDocumentPrivate::m_leftMargin, column = 0, cwidth;
+			
+		QChar c;
+		int indent = 0;
+		const int sw = QDocumentPrivate::m_spaceWidth;
+		
+		while ( idx < m_text.length() && m_text.at(idx).isSpace() )
+		{
+			c = m_text.at(idx);
+			
+			if ( c.unicode() == '\t' )
+			{
+				int taboffset = tabStop - (column % tabStop);
+				
+				column += taboffset;
+				cwidth = sw * taboffset;
+			} else {
+				++column;
+				cwidth = sw;
+			}
+			
+			x += cwidth;
+			++idx;
+		}
+		
+		indent = idx;
+		minx = rx = x;
+		
+		if ( (minx + sw) >= maxWidth )
+		{
+			//qWarning("Please stop shrinking so aggressively.\nNo attempt will be made to show something decent");
+			// shrinking too aggresively (or too much spaces...) ungraceful fallback
+			
+			indent = idx = 0;
+			minx = rx = x = QDocumentPrivate::m_leftMargin;
+		}
+		
+		m_indent = minx - QDocumentPrivate::m_leftMargin;
+		
+		while ( idx < m_text.length() )
+		{
+			if ( c.isSpace() )  //!isWord(c) || !isWord(m_text.at(idx)) )
+			{
+				lastX = rx;
+				lastWidth = x;
+				lastBreak = idx;
+			}
+			
+			c = m_text.at(idx);
+			
+			if ( c.unicode() == '\t' )
+			{
+				int taboffset = tabStop - (column % tabStop);
+				
+				column += taboffset;
+				cwidth = sw * taboffset;
+			} else {
+				++column;
+				cwidth = sw;
+			}
+			
+			if ( x + cwidth > maxWidth )
+			{
+				if ( lastBreak == (m_frontiers.count() ? m_frontiers.last().first : indent) )
+				{
+					// perfect cut or fallback to aggressive cut
+					m_frontiers << qMakePair(idx, rx);
+					lastBreak = idx;
+					lastWidth = x;
+					lastX = rx;
+					x = minx;
+				} else if ( lastBreak < idx ) {
+					// word cut at a non-ideal position
+					m_frontiers << qMakePair(lastBreak, lastX);
+					x = minx + (x - lastWidth);
+				} else {
+					m_frontiers << qMakePair(idx, rx);
+					x = minx;
+				}
+			}
+			
+			rx += cwidth;
+			x += cwidth;
+			++idx;
+		}
+	} else {
+		QMediumArray composited = compose();
+		
+		int idx = 0, minx = 0, lastBreak = 0, lastWidth = 0, lastX = 0, rx,
+			x = QDocumentPrivate::m_leftMargin, column = 0, cwidth;
+			
+		QChar c;
+		int indent = 0;
+		int fmt = 0;
+		const QVector<QFont>& fonts = m_doc->impl()->m_fonts;
+		
+		while ( idx < m_text.length() && m_text.at(idx).isSpace() )
+		{
+			c = m_text.at(idx);
+			fmt = idx < composited.count() ? composited[idx] : 0;
+			QFontMetrics fm(fonts.at(fmt));
+			
+			if ( c.unicode() == '\t' )
+			{
+				int taboffset = tabStop - (column % tabStop);
+				
+				column += taboffset;
+				cwidth = fm.width(' ') * taboffset;
+			} else {
+				++column;
+				cwidth = fm.width(c);
+			}
+			
+			x += cwidth;
+			++idx;
+		}
+		
+		indent = idx;
+		minx = rx = x;
+		
+		if ( (minx + QDocumentPrivate::m_spaceWidth) >= maxWidth )
+		{
+			//qWarning("Please stop shrinking so aggressively.\nNo attempt will be made to show something decent");
+			
+			indent = idx = 0;
+			minx = rx = x = QDocumentPrivate::m_leftMargin;
+		}
+		
+		m_indent = minx - QDocumentPrivate::m_leftMargin;
+		
+		while ( idx < m_text.length() )
+		{
+			if ( c.isSpace() )  //!isWord(c) || !isWord(m_text.at(idx)) )
+			{
+				lastX = rx;
+				lastWidth = x;
+				lastBreak = idx;
+			}
+			
+			c = m_text.at(idx);
+			fmt = idx < composited.count() ? composited[idx] : 0;
+			QFontMetrics fm(fonts.at(fmt));
+			
+			if ( c.unicode() == '\t' )
+			{
+				int taboffset = tabStop - (column % tabStop);
+				
+				column += taboffset;
+				cwidth = fm.width(' ') * taboffset;
+			} else {
+				++column;
+				cwidth = fm.width(c);
+			}
+			
+			if ( x + cwidth > maxWidth )
+			{
+				if ( lastBreak == (m_frontiers.count() ? m_frontiers.last().first : indent) )
+				{
+					// perfect cut or fallback to aggressive cut
+					m_frontiers << qMakePair(idx, rx);
+					lastBreak = idx;
+					lastWidth = x;
+					lastX = rx;
+					x = minx;
+				} else if ( lastBreak < idx ) {
+					// word cut at a non-ideal position
+					m_frontiers << qMakePair(lastBreak, lastX);
+					x = minx + (x - lastWidth);
+				} else {
+					m_frontiers << qMakePair(idx, rx);
+					x = minx;
+				}
+			}
+			
+			rx += cwidth;
+			x += cwidth;
+			++idx;
+		}
+	}
+}
+
+int QDocumentLineHandle::cursorToX(int cpos) const
+{
+	cpos = qBound(0, cpos, m_text.length());
+	
+	if ( m_layout )
+	{
+		int xoff = QDocumentPrivate::m_leftMargin, coff = 0, line = m_frontiers.count();
+		
+		for ( int i = 0; i < m_frontiers.count(); ++i )
+		{
+			if ( m_frontiers.at(i).first >= cpos )
+			{
+				line = i;
+				
+				break;
+			}
+		}
+		
+		if ( line )
+		{
+			//coff = m_frontiers.at(line - 1).first;
+			xoff = m_frontiers.at(line - 1).second;
+		}
+		
+		//qDebug("c:%i (wrap:%i) => c2x(x - %i) + %i", cpos, line, coff, xoff);
+		return qRound(m_layout->lineAt(line).cursorToX(cpos - coff)) + xoff;
+	}
+	
+	int tabStop = m_doc->impl()->m_tabStop;
+	
+	if ( QDocumentPrivate::m_fixedPitch )
+	{
+		return QDocument::screenLength(m_text.constData(), cpos, tabStop)
+				* QDocumentPrivate::m_spaceWidth
+				+ QDocumentPrivate::m_leftMargin;
+	}
+	
+	//qDebug("c->x(%i) unsafe computations...", cpos);
+	
+	QMediumArray composited = compose();
+	const QVector<QFont>& fonts = m_doc->impl()->m_fonts;
+	
+	if ( (composited.count() < cpos) || fonts.isEmpty() )
+		return QDocumentPrivate::m_fontMetrics->width(m_text.left(cpos));
+		
+	int idx = 0, column = 0, cwidth;
+	int screenx = QDocumentPrivate::m_leftMargin;
+	
+	while ( idx < cpos )
+	{
+		QChar c = m_text.at(idx);
+		QFontMetrics fm(fonts.at(idx < composited.count() ? composited[idx] : 0));
+		
+		if ( c == '\t' )
+		{
+			int taboffset = tabStop - (column % tabStop);
+			
+			column += taboffset;
+			cwidth = fm.width(' ') * taboffset;
+		} else {
+			++column;
+			cwidth = fm.width(c);
+		}
+		
+		screenx += cwidth;
+		++idx;
+	}
+	
+	//qDebug("cursorToX(%i) = %i", cpos, screenx);
+	
+	return screenx;
+}
+
+int QDocumentLineHandle::xToCursor(int xpos) const
+{
+	//qDebug("x->c(%i) unsafe computations...", xpos);
+	if ( m_layout )
+	{
+		int xoff = QDocumentPrivate::m_leftMargin, coff = 0, line = m_frontiers.count();
+		
+		for ( int i = 0; i < m_frontiers.count(); ++i )
+		{
+			if ( m_frontiers.at(i).second >= xpos )
+			{
+				line = i;
+				
+				break;
+			}
+		}
+		
+		if ( line )
+		{
+			//coff = m_frontiers.at(line - 1).first;
+			xoff = m_frontiers.at(line - 1).second;
+		}
+		
+		//qDebug("x:%i (wrap:%i) => x2c(x - %i) + %i", xpos, line, xoff, coff);
+		return m_layout->lineAt(line).xToCursor(xpos - xoff) + coff;
+	}
+	
+	int screenx = xpos;
+	int tabStop = m_doc->impl()->m_tabStop;
+	const QVector<QFont>& fonts = m_doc->impl()->m_fonts;
+	
+	if ( QDocumentPrivate::m_fixedPitch )
+	{
+		int screenPos =
+					(screenx - QDocumentPrivate::m_leftMargin / 2)
+				/
+					QDocumentPrivate::m_spaceWidth
+				;
+				
+		if ( tabStop == 1 )
+			return screenPos;
+			
+		int idx = 0, column = 0;
+		
+		while ( (column < screenPos) && (idx < m_text.length()) )
+		{
+			QChar c = m_text.at(idx);
+			
+			if ( c == QLatin1Char('\t') )
+			{
+				int taboffset = tabStop - (column % tabStop);
+				column += taboffset;
+			} else {
+				++column;
+			}
+			
+			++idx;
+		}
+		
+		return idx;
+	} else {
+		if ( screenx <= QDocumentPrivate::m_leftMargin )
+			return 0;
+			
+		QMediumArray composited = compose();
+		
+		int idx = 0, x = 0, column = 0, cwidth;
+		screenx -= QDocumentPrivate::m_leftMargin;
+		
+		while ( idx < m_text.length() )
+		{
+			QFontMetrics fm(fonts.at(idx < composited.count() ? composited[idx] : 0));
+			
+			if ( m_text.at(idx) == '\t' )
+			{
+				int taboffset = tabStop - (column % tabStop);
+				
+				column += taboffset;
+				cwidth = fm.width(' ') * taboffset;
+			} else {
+				++column;
+				cwidth = fm.width(m_text.at(idx));
+			}
+			
+			int mid = (x + (cwidth / 2) + 1);
+			
+			if ( screenx <= mid )
+				return idx;
+			else if ( screenx <= (x + cwidth) )
+				return idx + 1;
+				
+			x += cwidth;
+			++idx;
+		}
+		
+		return m_text.length();
+	}
+}
+
+int QDocumentLineHandle::wrappedLineForCursor(int cpos) const
+{
+	int wrap = m_frontiers.count();
+	
+	for ( int i = 0; i < m_frontiers.count(); ++i )
+	{
+		if ( m_frontiers.at(i).first > cpos )
+		{
+			wrap = i;
+			break;
+		}
+	}
+	
+	return wrap;
+}
+
+int QDocumentLineHandle::documentOffsetToCursor(int x, int y) const
+{
+	int wrap = y / QDocumentPrivate::m_lineSpacing;
+	
+	if ( wrap > m_frontiers.count() )
+	{
+		// return an invalid value instead?
+		//qDebug("a bit too far : (%i, %i)", x, y);
+		//wrap = m_frontiers.count();
+		
+		return m_text.length();
+	}
+	
+	if ( m_frontiers.count() )
+	{
+		//qDebug("(%i, %i) : %i", x, y, wrap);
+		x = qMin(x, m_doc->widthConstraint());
+	}
+	
+	int cpos = 0;
+	int max = m_text.length();
+	
+	if ( wrap < m_frontiers.count() )
+		max = m_frontiers.at(wrap).first - 1;
+	
+	if ( wrap > 0 )
+		cpos = m_frontiers.at(wrap - 1).first;
+	
+	x -= QDocumentPrivate::m_leftMargin;
+	
+	int idx = cpos, column = 0;
+	const int ts = m_doc->tabStop();
+	
+	if ( m_layout )
+	{
+		cpos = m_layout->lineAt(wrap).xToCursor(x);
+	} else if ( QDocumentPrivate::m_fixedPitch ) {
+		if ( wrap )
+			x -= m_indent;
+			
+		while ( (idx < max) && (x > 0) )
+		{
+			bool tab = m_text.at(idx).unicode() == '\t';
+			int cwidth = QDocumentPrivate::m_spaceWidth;
+			
+			if ( tab )
+			{
+				int coff = ts - (column % ts);
+				column += coff;
+				cwidth *= coff;
+			} else {
+				++column;
+			}
+			
+			int thresold = (2 * cwidth) / 3;
+			
+			if ( x <= thresold )
+				break;
+				
+			x -= cwidth;
+			++idx;
+		}
+		
+		cpos = idx;
+	} else {
+		if ( !hasFlag(QDocumentLine::FormatsApplied) )
+			compose();
+			
+		if ( wrap )
+			x -= m_indent;
+			
+		const QVector<QFont>& fonts = m_doc->impl()->m_fonts;
+		
+		while ( (idx < max) && (x > 0) )
+		{
+			int fid = idx < m_cache.count() ? m_cache[idx] : 0;
+			
+			if ( fid < 0 )
+				fid = 0;
+			
+			QFontMetrics fm = (fid < fonts.count()) ? QFontMetrics(fonts.at(fid)) : m_doc->fontMetrics();
+			
+			QChar c = m_text.at(idx);
+			bool tab = c.unicode() == '\t';
+			int cwidth = 0;
+			
+			if ( tab )
+			{
+				int coff = ts - (column % ts);
+				column += coff;
+				cwidth = fm.width(' ');
+				cwidth *= coff;
+			} else {
+				++column;
+				cwidth = fm.width(c);
+			}
+			
+			int thresold = (2 * cwidth) / 3;
+			
+			if ( x <= thresold )
+				break;
+				
+			x -= cwidth;
+			++idx;
+		}
+		
+		cpos = idx;
+	}
+	
+	return cpos;
+}
+
+void QDocumentLineHandle::cursorToDocumentOffset(int cpos, int& x, int& y) const
+{
+	if ( cpos > m_text.length() )
+		cpos = m_text.length();
+	else if ( cpos < 0 )
+		cpos = 0;
+		
+	int idx = 0;
+	int wrap = wrappedLineForCursor(cpos);
+	
+	x = QDocumentPrivate::m_leftMargin;
+	y = wrap * QDocumentPrivate::m_lineSpacing;
+	
+	if ( wrap )
+	{
+		idx = m_frontiers.at(wrap - 1).first;
+	}
+	
+	int column = 0;
+	const int ts = m_doc->tabStop();
+	
+	if ( m_layout )
+	{
+		x += m_layout->lineAt(wrap).cursorToX(cpos);
+	} else if ( QDocumentPrivate::m_fixedPitch ) {
+		if ( wrap )
+			x += m_indent;
+			
+		while ( idx < cpos )
+		{
+			bool tab = m_text.at(idx).unicode() == '\t';
+			int cwidth = QDocumentPrivate::m_spaceWidth;
+			
+			if ( tab )
+			{
+				int coff = ts - (column % ts);
+				column += coff;
+				cwidth *= coff;
+			} else {
+				++column;
+			}
+			
+			x += cwidth;
+			++idx;
+		}
+	} else {
+		if ( !hasFlag(QDocumentLine::FormatsApplied) )
+			compose();
+			
+		if ( wrap )
+			x += m_indent;
+			
+		const QVector<QFont>& fonts = m_doc->impl()->m_fonts;
+		
+		while ( idx < cpos )
+		{
+			int fid = idx < m_cache.count() ? m_cache[idx] : 0;
+			
+			if ( fid < 0 )
+				fid = 0;
+			
+			QFontMetrics fm = (fid < fonts.count()) ? QFontMetrics(fonts.at(fid)) : m_doc->fontMetrics();
+			
+			QChar c = m_text.at(idx);
+			bool tab = c.unicode() == '\t';
+			int cwidth = 0;
+			
+			if ( tab )
+			{
+				int coff = ts - (column % ts);
+				column += coff;
+				cwidth = fm.width(' ');
+				cwidth *= coff;
+			} else {
+				++column;
+				cwidth = fm.width(c);
+			}
+			
+			x += cwidth;
+			++idx;
+		}
+	}
+}
+
+QPoint QDocumentLineHandle::cursorToDocumentOffset(int cpos) const
+{
+	QPoint p;
+	cursorToDocumentOffset(cpos, p.rx(), p.ry());
+	return p;
+	#if 0
+	int y = 0;
+	int x = cursorToX(cpos);
+	
+	if ( m_frontiers.isEmpty() )
+		return QPoint(x, y);
+		
+	int first = m_frontiers.at(0).first;
+	
+	if ( cpos < first )
+		return QPoint(x, y);
+		
+	int wrappedX = 0;
+	int fns = nextNonSpaceChar(0), off = 0;
+	
+	if ( fns != -1 && fns < first )
+		off = cursorToX(fns);
+	else
+		off = QDocumentPrivate::m_leftMargin;
+		
+	for ( int j = 0; j < m_frontiers.count(); ++j )
+	{
+		if ( m_frontiers[j].first <= cpos )
+		{
+			wrappedX = m_frontiers[j].second;
+			y += QDocumentPrivate::m_lineSpacing;
+		} else {
+			break;
+		}
+	}
+	
+	return QPoint(x - wrappedX + off, y);
+	#endif
+}
+
+void QDocumentLineHandle::clearOverlays()
+{
+	m_overlays.clear();
+	
+	//setFlag(QDocumentLine::LayoutDirty, true);
+	setFlag(QDocumentLine::FormatsApplied, false);
+	//applyOverlays();
+}
+
+void QDocumentLineHandle::addOverlay(const QFormatRange& over)
+{
+	m_overlays << over;
+	
+	//setFlag(QDocumentLine::LayoutDirty, true);
+	setFlag(QDocumentLine::FormatsApplied, false);
+	//applyOverlays();
+}
+
+void QDocumentLineHandle::removeOverlay(const QFormatRange& over)
+{
+	int i = m_overlays.removeAll(over);
+	
+	//setFlag(QDocumentLine::LayoutDirty, true);
+	if ( i )
+		setFlag(QDocumentLine::FormatsApplied, false);
+	//applyOverlays();
+}
+
+void QDocumentLineHandle::shiftOverlays(int position, int offset)
+{
+	if ( offset > 0 )
+	{
+		for ( int i = 0; i < m_overlays.count(); ++i )
+		{
+			QFormatRange& r = m_overlays[i];
+			
+			if ( r.offset >= position )
+			{
+				r.offset += offset;
+			} else if ( r.offset + r.length > position ) {
+				m_overlays.removeAt(i);
+				--i;
+			}
+		}
+	} else if ( offset < 0 ) {
+		const int max = position - offset;
+		
+		for ( int i = 0; i < m_overlays.count(); ++i )
+		{
+			QFormatRange& r = m_overlays[i];
+			
+			if ( r.offset >= max )
+			{
+				r.offset += offset;
+			} else if ( r.offset + r.length >= position ) {
+				m_overlays.removeAt(i);
+				--i;
+			}
+		}
+	}
+	
+	setFlag(QDocumentLine::FormatsApplied, false);
+}
+
+void QDocumentLineHandle::setFormats(const QVector<int>& fmts)
+{
+	m_formats = fmts;
+	
+	while ( m_formats.count() > m_text.length() )
+		m_formats.pop_back();
+		
+	while ( m_formats.count() < m_text.length() )
+		m_formats.append(0);
+		
+	//setFlag(QDocumentLine::LayoutDirty, true);
+	setFlag(QDocumentLine::FormatsApplied, false);
+	//applyOverlays();
+}
+
+QMediumArray QDocumentLineHandle::compose() const
+{
+	//QMediumArray m_composited(m_text.length());
+	if ( hasFlag(QDocumentLine::FormatsApplied) )
+		return m_cache;
+		
+	m_cache.resize(m_text.length());
+	
+	for ( int i = 0; i < qMin(m_formats.count(), m_text.length()); ++i )
+		m_cache[i] = m_formats.at(i);
+		
+	for ( int i = m_formats.count(); i < m_text.length(); ++i )
+		m_cache[i] = 0;
+		
+	// compositing formats and overlays
+	foreach ( const QFormatRange& r, m_overlays )
+	{
+		int beg = qMax(0, r.offset);
+		int end = qMin(r.offset + r.length, m_cache.count());
+		
+		for ( int i = beg; i < end; ++i )
+		{
+			m_cache[i] = r.format;
+		}
+	}
+	
+	setFlag(QDocumentLine::FormatsApplied, true);
+	
+	return m_cache;
+}
+
+QList<QTextLayout::FormatRange> QDocumentLineHandle::decorations() const
+{
+	if ( !hasFlag(QDocumentLine::FormatsApplied) )
+		compose();
+		
+	// turning format "map" into ranges that QTextLayout can understand...
+	QList<QTextLayout::FormatRange> m_ranges;
+	
+	int fid = 0;
+	QTextLayout::FormatRange r;
+	r.start = r.length = -1;
+	
+	int i = 0;
+	
+	//if ( m_cache.isEmpty() )
+	//	qWarning("empty cache...");
+	
+	while ( i < m_cache.count() )
+	{
+		while ( (i < m_cache.count()) && !m_cache[i] )
+			++i;
+			
+		if ( i >= m_cache.count() )
+			break;
+			
+		fid = m_cache[i];
+		
+		r.start = i;
+		r.format = m_doc->formatScheme()->format(fid).toTextCharFormat();
+		
+		while ( (i < m_cache.count()) && (m_cache[i] == fid) )
+			++i;
+			
+		if ( i >= m_cache.count() )
+			break;
+			
+		r.length = i - r.start;
+		m_ranges << r;
+		
+		r.start = r.length = -1;
+	}
+	
+	if ( r.start != -1 )
+	{
+		r.length = m_cache.count() - r.start;
+		m_ranges << r;
+	}
+	
+	return m_ranges;
+}
+
+void QDocumentLineHandle::applyOverlays() const
+{
+	if ( !m_layout )
+		return;
+		
+	//m_layout->setAdditionalFormats(decorations());
+	
+	//setFlag(QDocumentLine::FormatsApplied, true);
+}
+
+void QDocumentLineHandle::layout() const
+{
+	bool needLayout = false;
+	static QList<QChar::Direction> m_layoutRequirements = QList<QChar::Direction>()
+		<< QChar::DirR
+		<< QChar::DirAL
+		<< QChar::DirRLE
+		<< QChar::DirRLO
+		<< QChar::DirPDF
+		<< QChar::DirAN;
+		
+	for ( int i = 0; (i < m_text.length()) && !needLayout; ++i )
+	{
+		QChar c = m_text.at(i);
+		
+		needLayout = m_layoutRequirements.contains(c.direction());
+	}
+	
+	if ( needLayout )
+	{
+		//qDebug("layout needed at line %i", this->line());
+		
+		if ( !m_layout )
+		{
+			m_layout = new QTextLayout(m_text, QDocument::font());
+		} else {
+			m_layout->setText(m_text);
+			//m_layout->setFont(config()->font());
+		}
+		
+		m_layout->setCacheEnabled(false);
+		// Initial setup of the QTextLayout.
+		
+		// Tab width
+		QTextOption opt;
+		opt.setFlags(QTextOption::IncludeTrailingSpaces);
+		opt.setTabStop(m_doc->tabStop() * QDocumentPrivate::m_spaceWidth);
+		
+		//opt.setWrapMode(QTextOption::NoWrap);
+		opt.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+		
+		// Find the first strong character in the string.
+		// If it is an RTL character, set the base layout direction of the string to RTL.
+		//
+		// See http://www.unicode.org/reports/tr9/#The_Paragraph_Level (Sections P2 & P3).
+		// Qt's text renderer ("scribe") version 4.2 assumes a "higher-level protocol"
+		// (such as KatePart) will specify the paragraph level, so it does not apply P2 & P3
+		// by itself. If this ever change in Qt, the next code block could be removed.
+		if ( m_text.isRightToLeft() )
+			opt.setTextDirection(Qt::RightToLeft);
+		
+		m_layout->setTextOption(opt);
+		
+		// Syntax highlighting, inbuilt and arbitrary
+		//m_layout->setAdditionalFormats(m_ranges);
+		
+		// Begin layouting
+		m_layout->beginLayout();
+		
+		m_frontiers.clear();
+		
+		int i = 0, rx = 0, height = 0, minwidth = 0;
+		
+		forever
+		{
+			QTextLine line = m_layout->createLine();
+			
+			if ( !line.isValid() )
+			{
+				//if ( m_layout->lineCount() > 1 )
+				//	qWarning("Troubles expected on line %i", this->line());
+				
+				break;
+			}
+			
+			if ( m_doc->widthConstraint() )
+				line.setLineWidth(m_doc->widthConstraint() - QDocumentPrivate::m_leftMargin);
+			else
+				line.setNumColumns(m_text.length());
+				
+			rx += qRound(line.naturalTextWidth()); //qRound(line.cursorToX(line.textLength()));
+			
+			if ( m_doc->impl()->m_constrained && m_layout->textOption().textDirection() == Qt::RightToLeft )
+			{
+				line.setPosition(QPoint(qRound(qreal(m_doc->widthConstraint() - 2 * QDocumentPrivate::m_leftMargin) - line.naturalTextWidth()), height));
+			} else {
+				line.setPosition(QPoint(minwidth, height));
+				
+				if ( !i )
+				{
+					m_indent = minwidth = cursorToX(nextNonSpaceChar(0)) - QDocumentPrivate::m_leftMargin;
+					
+					if ( minwidth < 0 || minwidth >= m_doc->widthConstraint() )
+						minwidth = 0;
+				}
+			}
+			
+			m_frontiers << qMakePair(line.textStart() + line.textLength(), rx);
+			
+			++i;
+			
+			height += QDocumentPrivate::m_lineSpacing;
+			//height += QDocument::fontMetrics().height();
+		}
+		
+		m_frontiers.pop_back();
+		
+		m_layout->endLayout();
+	} else {
+		if ( m_layout )
+			delete m_layout;
+			
+		m_layout = 0;
+		//updateWrap();
+	}
+	
+	setFlag(QDocumentLine::LayoutDirty, false);
+}
+
+struct RenderRange
+{
+	int position;
+	int length;
+	quint16 format;
+	int wrap;
+};
+
+void QDocumentLineHandle::draw(	QPainter *p,
+								int xOffset,
+								int vWidth,
+								const QSmallArray& sel,
+								const QSmallArray& cursor,
+								const QPalette& pal,
+								bool fullSel) const
+{
+	if ( hasFlag(QDocumentLine::LayoutDirty) )
+		layout();
+		
+	if ( m_layout && !hasFlag(QDocumentLine::FormatsApplied) )
+		m_layout->setAdditionalFormats(decorations());
+		
+	QMediumArray m_composited = compose();
+	
+	if ( m_layout )
+	{
+		//if ( !hasFlag(QDocumentLine::FormatsApplied) )
+		//	applyOverlays();
+		
+		const int lh = QDocument::fontMetrics().height();
+		
+		QVector<QTextLayout::FormatRange> selections;
+		
+		QTextCharFormat fmt;
+		fmt.setBackground(pal.highlight());
+		fmt.setForeground(pal.highlightedText());
+		
+		QTextLayout::FormatRange range;
+		if ( fullSel )
+		{
+			range.start = 0;
+			range.format = fmt;
+			range.length = m_text.length();
+			selections << range;
+		} else {
+			for ( int i = 0; i < sel.count(); ++i )
+			{
+				range.start = sel[i];
+				range.format = fmt;
+				
+				if ( (i + 1) < sel.count() )
+				{
+					// regular selection subset
+					range.length = sel[++i] - range.start;
+					
+				} else if ( m_layout->lineCount() ) {
+					// span to end of line, not only text
+					range.length = m_text.length() - range.start;
+					qreal lineWidth = m_layout->lineAt(m_layout->lineCount() - 1).naturalTextWidth();
+					const int endX = QDocumentPrivate::m_leftMargin + qRound(lineWidth) - xOffset;
+					
+					QRect area(endX, lh * i, vWidth - endX, lh);
+					
+					p->fillRect(area, fmt.background());
+				}
+				
+				selections << range;
+			}
+		}
+		
+		QPoint off(QDocumentPrivate::m_leftMargin, 0);
+		
+		m_layout->draw(p, off, selections);
+		
+		for ( int i = 0; i < cursor.count(); ++i )
+			m_layout->drawCursor(p, off, cursor[i]);
+			
+		//m_layout->clearAdditionalFormats();
+	} else if ( m_text.isEmpty() ) {
+		// enforce selection drawing on empty lines
+		if ( sel.count() == 1 )
+			p->fillRect(
+						qMax(xOffset, QDocumentPrivate::m_leftMargin),
+						0,
+						vWidth,
+						QDocumentPrivate::m_lineSpacing,
+						pal.highlight()
+						);
+						
+		// enforce cursor drawing on empty lines
+		if ( cursor.count() && (xOffset < QDocumentPrivate::m_leftMargin) )
+			p->drawLine(
+						QDocumentPrivate::m_leftMargin,
+						0,
+						QDocumentPrivate::m_leftMargin,
+						QDocumentPrivate::m_lineSpacing
+						);
+						
+	} else if ( true ) {
+		
+		QVector<quint16> merged;
+		merged.fill(0, m_text.count());
+		
+		QList<RenderRange> ranges;
+		
+		// find start of trailing whitespaces
+		int last = m_text.length();
+		
+		while ( (last > 0) && m_text.at(last - 1).isSpace() )
+			--last;
+			
+		// TODO : format-level (not format id) merging of formats and opverlays...
+		
+		// merge selection ranges with the rest (formats + overlays)
+		if ( true ) //m_composited.count() || sel.count() )
+		{
+			//int max = qMin(m_text.count(), m_composited.count());
+			
+			for ( int i = 0; i < m_text.count(); ++i )
+			{
+				if ( m_composited.count() > i )
+					merged[i] = m_composited.at(i);
+					
+				// separate spaces to ease rendering loop
+				if ( m_text.at(i).isSpace() )
+					merged[i] |= 0x4000;
+			}
+			
+			for ( int i = 0; i < sel.count(); i += 2 )
+			{
+				int max = m_text.length();
+				
+				if ( (i + 1) < sel.count() )
+					max = qMin(sel[i + 1], max);
+				
+				for ( int j = sel[i]; j < max; ++j )
+					merged[j] |= 0x8000;
+			}
+		}
+		
+		// generate render ranges
+		if ( merged.count() )
+		{
+			int i = 0, wrap = 0, max = m_text.count(),
+				frontier = m_frontiers.count() ? m_frontiers.first().first : max;
+				
+			while ( i < max )
+			{
+				RenderRange r;
+				r.position = i;
+				r.length = 1;
+				r.wrap = wrap;
+				r.format = merged.at(i);
+				
+				while ( ((i + 1) < frontier) && (merged.at(i + 1) == r.format) )
+				{
+					++r.length;
+					++i;
+				}
+				
+				ranges << r;
+				++i;
+				
+				if ( i == frontier )
+				{
+					++wrap;
+					frontier = wrap < m_frontiers.count() ? m_frontiers.at(wrap).first : max;
+				}
+			}
+		} else if ( m_frontiers.count() ) {
+			// no formatting (nor selection) : simpler
+			int i = 0, wrap = 0, max = m_text.count(),
+				frontier = m_frontiers.count() ? m_frontiers.first().first : max;
+				
+			while ( i < max )
+			{
+				RenderRange r;
+				r.position = i;
+				r.length = 1;
+				r.wrap = wrap;
+				r.format = fullSel ? 0x8000 : 0;
+				
+				while ( ((i + 1) < frontier) )
+				{
+					++r.length;
+					++i;
+				}
+				
+				ranges << r;
+				++i;
+				
+				if ( i == frontier )
+				{
+					++wrap;
+					frontier = wrap < m_frontiers.count() ? m_frontiers.at(wrap).first : max;
+				}
+			}
+		} else {
+			// neither formatting nor line wrapping : simple drawText()
+			RenderRange r;
+			r.position = 0;
+			r.length = m_text.length();
+			r.format = fullSel ? 0x8000 : 0;
+			
+			ranges << r;
+		}
+		
+		quint16 fmt = fullSel ? 0x8000 : 0;
+		QDocumentPrivate *d = m_doc->impl();
+		const int ts = d->m_tabStop;
+		const int maxWidth = xOffset + vWidth;
+		const bool unbounded = sel.count() & 1;
+		const QColor ht = pal.highlightedText().color();
+		
+		const bool showTabs = QDocument::showSpaces() & QDocument::ShowTabs,
+				showLeading = QDocument::showSpaces() & QDocument::ShowLeading,
+				showTrailing = QDocument::showSpaces() & QDocument::ShowTrailing;
+				
+		//const int fns = nextNonSpaceChar(0);
+		int indent = qMax(m_indent, QDocumentPrivate::m_leftMargin);
+		
+		int cidx = 0;
+		int rngIdx = 0;
+		int column = 0;
+		bool continuingWave = false, brokenWave = false;
+		int dir = 0; // 0 = down; 1 = up
+		int wrap = 0, xpos = QDocumentPrivate::m_leftMargin, ypos = 0;
+		bool leading = ranges.first().format & 0x4000, pastLead = false;
+		
+		foreach ( const RenderRange& r, ranges )
+		{
+			++rngIdx;
+			
+			if ( wrap != r.wrap )
+			{
+				continuingWave = false;
+				
+				if ( fmt & 0x8000 )
+				{
+					// finish selection
+					p->fillRect(
+									xpos, ypos,
+									maxWidth - xpos, QDocumentPrivate::m_lineSpacing,
+									pal.highlight()
+								);
+								
+				}
+				
+				if ( pastLead && (r.format & 0x4000) )
+				{
+					indent = QDocumentPrivate::m_leftMargin;
+				}
+				
+				++wrap;
+				column = 0;
+				ypos += QDocumentPrivate::m_lineSpacing;
+				xpos = indent;
+				
+				if ( r.format & 0x8000 )
+				{
+					// finish selection
+					p->fillRect(
+									QDocumentPrivate::m_leftMargin, ypos,
+									xpos, QDocumentPrivate::m_lineSpacing,
+									pal.highlight()
+								);
+								
+				}
+			}
+			if ( leading && !(r.format & 0x4000) )
+			{
+				//indent = xpos;
+				leading = false;
+				pastLead = true;
+			}
+			
+			// TODO : clip more accurately (i.e inside ranges)
+			if ( xpos > maxWidth )
+				break;
+			
+			if ( r.format != fmt )
+			{
+				d->tunePainter(p, r.format & 0x0fff);
+				
+				fmt = r.format;
+			}
+			
+			int rwidth = 0;
+			int tcol = column;
+			const QString rng = m_text.mid(r.position, r.length);
+			
+			if ( r.format & 0x4000 )
+			{
+				foreach ( QChar c, rng )
+				{
+					if ( c.unicode() == '\t' )
+					{
+						int toff = ts - (tcol % ts);
+ 						rwidth += toff * QDocumentPrivate::m_spaceWidth;
+						tcol += toff;
+					} else {
+						rwidth += QDocumentPrivate::m_spaceWidth;
+						++tcol;
+					}
+				}
+			} else {
+				column += r.length;
+				
+				if ( QDocumentPrivate::m_fixedPitch )
+					rwidth = QDocumentPrivate::m_spaceWidth * r.length;
+				else
+					rwidth = p->fontMetrics().width(rng);
+			}
+			
+			if ( (xpos + rwidth) <= xOffset )
+			{
+				xpos += rwidth;
+				
+				if ( r.format & 0x4000 )
+					column = tcol;
+				
+				continue;
+			}
+			
+			QFormat format;
+			int xspos = xpos;
+			const QPen oldpen = p->pen();
+			const int baseline = ypos + QDocumentPrivate::m_ascent;
+			
+			if ( d->m_formatScheme )
+				format = d->m_formatScheme->format(fmt & 0x0fff);
+			
+			if ( fullSel || (fmt & 0x8000) )
+			{
+				p->setPen(ht);
+				
+				p->fillRect(xpos, ypos,
+							rwidth, QDocumentPrivate::m_lineSpacing,
+							pal.highlight());
+				
+			} else {
+				if ( format.foreground.isValid() )
+				{
+					p->setPen(format.foreground);
+				} else {
+					p->setBrush(pal.text());
+				}
+				
+				if ( format.background.isValid() )
+				{
+					p->fillRect(xpos, ypos,
+								rwidth, QDocumentPrivate::m_lineSpacing,
+								format.background);
+				}
+			}
+			
+			if ( r.format & 0x4000 )
+			{
+				// spaces
+				int max = r.position + r.length;
+				
+				if ( rngIdx == ranges.count() )
+					++max;
+					
+				for ( int i = r.position; i < max; ++i )
+				{
+					while ( cidx < cursor.count() )
+					{
+						if ( cursor.at(cidx) == i )
+						{
+							p->drawLine(xpos, ypos, xpos, ypos + QDocumentPrivate::m_lineSpacing);
+							
+							++cidx;
+						} else {
+							break;
+						}
+					}
+					
+					if ( i == r.position + r.length )
+						break;
+						
+					bool isTab = m_text.at(i).unicode() == '\t';
+					
+					if ( isTab )
+					{
+						int toff = ts - (column % ts);
+						column += toff;
+						int xoff = toff * QDocumentPrivate::m_spaceWidth;
+						/*
+						if ( r.format & 0x8000 )
+						{
+							p->fillRect(xpos, ypos,
+										xoff, QDocumentPrivate::m_lineSpacing,
+										pal.highlight());
+										
+						}
+						*/
+						if ( showTabs )
+						{
+							p->translate(xpos - m_spaceSignOffset, ypos + QDocumentPrivate::m_ascent);
+							p->drawPoints(m_spaceSign, sizeof(m_spaceSign) / sizeof(QPoint));
+							p->translate(m_spaceSignOffset - xpos,-ypos - QDocumentPrivate::m_ascent);
+						}
+						
+						xpos += xoff;
+					} else {
+						++column;
+						/*
+						if ( r.format & 0x8000 )
+						{
+							p->fillRect(xpos, ypos,
+										QDocumentPrivate::m_spaceWidth, QDocumentPrivate::m_lineSpacing,
+										pal.highlight());
+										
+						}
+						*/
+						if (
+								(
+									leading
+								&&
+									showLeading
+								)
+							||
+								(
+									(r.position >= last)
+								&&
+									showTrailing
+								)
+							)
+						{
+							p->translate(xpos - m_spaceSignOffset, ypos + QDocumentPrivate::m_ascent);
+							p->drawPoints(m_spaceSign, sizeof(m_spaceSign) / sizeof(QPoint));
+							p->translate(m_spaceSignOffset - xpos,-ypos - QDocumentPrivate::m_ascent);
+						}
+						
+						xpos += QDocumentPrivate::m_spaceWidth;
+					}
+				}
+				
+				/*
+				if ( leading )
+				{
+					//indent = xpos;
+					leading = false;
+					pastLead = true;
+				}
+				*/
+				
+			} else {
+				p->drawText(xpos, baseline, rng);
+				
+				while ( cidx < cursor.count() )
+				{
+					const int xcoff = cursor.at(cidx) - r.position;
+					
+					if ( xcoff < 0 )
+					{
+						++cidx;
+						continue;
+					}
+					
+					if ( xcoff < (rngIdx == ranges.count() ? r.length + 1 : r.length) )
+					{
+						int xcpos = xpos;
+						
+						if ( xcoff )
+						{
+							if ( QDocumentPrivate::m_fixedPitch )
+							{
+								xcpos += xcoff * QDocumentPrivate::m_spaceWidth;
+							} else {
+								xcpos += p->fontMetrics().width(rng.left(xcoff));
+							}
+						}
+						
+						//qDebug("drawing cursor %i (col %i, x=%i)", cidx, cursor.at(cidx), xcpos);
+						
+						p->drawLine(xcpos, ypos, xcpos, ypos + QDocumentPrivate::m_lineSpacing);
+						
+						++cidx;
+					} else {
+						break;
+					}
+				}
+				
+				xpos += rwidth;
+			}
+			
+			//qDebug("underline pos : %i", p->fontMetrics().underlinePos());
+			
+			if ( format.linescolor.isValid() )
+				p->setPen(format.linescolor);
+			
+			const int ydo = qMin(baseline + p->fontMetrics().underlinePos(), ypos + QDocumentPrivate::m_lineSpacing - 1);
+			const int yin = baseline - p->fontMetrics().strikeOutPos();
+			const int yup = qMax(baseline - p->fontMetrics().overlinePos() + 1, ypos);
+			
+			if ( format.overline )
+			{
+				p->drawLine(xspos, yup, xpos, yup);
+			}
+			
+			if ( format.strikeout )
+			{
+				p->drawLine(xspos, yin, xpos, yin);
+			}
+			
+			if ( format.underline )
+			{
+				p->drawLine(xspos, ydo, xpos, ydo);
+			}
+			
+			if ( format.waveUnderline )
+ 			{
+				/*
+				those goddamn font makers take liberties with common sense
+				and make it so damn harder to figure proper y offset for wave
+				underline (keeping the regular underline pos make it look
+				weird or even invisible on some fonts... reference rendering
+				with DejaVu Sans Mono)
+				*/
+				
+				// we used fixed wave amplitude of 3 (well strictly speaking
+				// amplitude would be 1.5 but let's forget about waves and
+				// focus on getting that code to work...
+				
+				// gotta center things
+				const int ycenter = ypos + QDocumentPrivate::m_lineSpacing - 3; 
+									/*
+									qMin(
+										ypos + (QDocumentPrivate::m_ascent + QDocumentPrivate::m_lineSpacing) / 2,
+										ypos + QDocumentPrivate::m_lineSpacing - 3
+									);*/
+				
+				//if (format.waveUnderlineForeground.isValid())
+				//	p->setPen(format.waveUnderlineForeground);
+				
+				int cp = 0;
+				brokenWave = false;
+				
+				while ( cp < rwidth )
+ 				{
+					if ( !cp && !continuingWave )
+					{
+						dir = 0;
+						p->drawLine(xspos, ycenter, xspos + 1, ycenter + 1);
+						++cp;
+					} else if ( !cp && brokenWave ) {
+						if ( !dir )
+							p->drawLine(xspos, ycenter, xspos + 1, ycenter + 1);
+						else
+							p->drawLine(xspos, ycenter, xspos + 1, ycenter - 1);
+						
+					} else {
+						if ( cp + 2 > rwidth)
+						{
+							if ( !dir )
+								p->drawLine(xspos + cp, ycenter - 1, xspos + cp + 1, ycenter);
+							else
+								p->drawLine(xspos + cp, ycenter + 1, xspos + cp + 1, ycenter);
+							
+							// trick to keep current direction
+							dir ^= 1;
+							
+							brokenWave = true;
+							++cp;
+						} else {
+							if ( !dir )
+								p->drawLine(xspos + cp, ycenter - 1, xspos + cp + 2, ycenter + 1);
+							else
+								p->drawLine(xspos + cp, ycenter + 1, xspos + cp + 2, ycenter - 1);
+							
+							cp += 2;
+						}
+					}
+					
+					dir ^= 1;
+ 				}
+					
+				continuingWave = true;
+ 			} else {
+				continuingWave = false;
+				dir = 0;
+			}
+			
+			p->setPen(oldpen);
+		}
+		
+		if ( unbounded )
+			p->fillRect(
+							xpos, ypos,
+							maxWidth - xpos, QDocumentPrivate::m_lineSpacing,
+							pal.highlight()
+						);
+		
+	} else {
+		QChar c;
+		
+		int maxWidth = xOffset + vWidth;
+		
+		const bool wrapped = m_frontiers.count();
+		
+		int fmt = 0;
+		
+		bool leading = true, unbounded = false, leftSel = false,
+			showTabs = QDocument::showSpaces() & QDocument::ShowTabs,
+			showLeading = QDocument::showSpaces() & QDocument::ShowLeading,
+			showTrailing = QDocument::showSpaces() & QDocument::ShowTrailing;
+			
+		int cwidth,
+			ypos = 0,
+			indent = 0,
+			idx = 0, column = 0,
+			selidx = 0, sellen = 0, wrap = 0,
+			xpos = QDocumentPrivate::m_leftMargin;
+			
+		const int ts = QDocument::tabStop();
+		
+		// find start of trailing whitespaces
+		int last = m_text.length();
+		
+		while ( (last > 0) && m_text.at(last - 1).isSpace() )
+			--last;
+			
+		//p->save();
+		
+		//qDebug("drawing from %i to %i", xpos, maxWidth);
+		
+		while ( idx < m_text.length() )
+		{
+			if ( (selidx < sel.count()) && (idx == sel[selidx]) )
+			{
+				if ( (selidx + 1) < sel.count() )
+				{
+					sellen = sel[selidx + 1] - sel[selidx];
+					selidx += 2;
+				} else {
+					// unbounded selection
+					unbounded = true;
+					
+					++selidx;
+					sellen = m_text.length() - idx;
+					
+					p->fillRect(
+								xpos, ypos,
+								maxWidth - xpos, QDocumentPrivate::m_lineSpacing,
+								pal.highlight()
+							);
+				}
+			}
+			
+			c = m_text.at(idx);
+			
+			if ( c == '\t' )
+			{
+				int toff = ts - (column % ts);
+				cwidth = toff * QDocumentPrivate::m_spaceWidth;
+				column += toff - 1;
+			} else if ( c == ' ' ) {
+				cwidth = QDocumentPrivate::m_spaceWidth;
+			} else if ( idx < m_composited.count() ) {
+				int nfmt = m_composited[idx];
+				
+				if ( fmt != nfmt )
+				{
+					m_doc->impl()->tunePainter(p, nfmt);
+					fmt = nfmt;
+				}
+				
+				// make sure bold/italicized/.. chars are taken into account...
+				cwidth = p->fontMetrics().width(c);
+			} else {
+				// char uses default font...
+				cwidth = QDocumentPrivate::m_fontMetrics->width(c);
+			}
+			
+			if ( (xpos + cwidth) > xOffset )
+			{
+				// MUST be done after setting the proper chararcter width!
+				if ( wrapped && (wrap < m_frontiers.count()) && (idx >= m_frontiers.at(wrap).first) )
+				{
+					if ( sellen || leftSel )
+					{
+						p->fillRect(
+									xpos, ypos,
+									maxWidth - xpos, QDocumentPrivate::m_lineSpacing,
+									pal.highlight()
+								);
+								
+					}
+					
+					++wrap;
+					xpos = indent;
+					ypos += QDocumentPrivate::m_lineSpacing;
+					
+					if ( sellen || leftSel )
+					{
+						p->fillRect(
+									QDocumentPrivate::m_leftMargin, ypos,
+									xpos - QDocumentPrivate::m_leftMargin + (leftSel ? 0 : cwidth),
+									QDocumentPrivate::m_lineSpacing,
+									pal.highlight()
+								);
+								
+					}
+					
+				} else {
+					if ( sellen )
+					{
+						p->fillRect(
+									xpos, ypos,
+									cwidth, QDocumentPrivate::m_lineSpacing,
+									pal.highlight()
+								);
+								
+					}
+				}
+				
+				const int baseline = ypos + QDocumentPrivate::m_ascent;
+				
+				if ( !c.isSpace() )
+				{
+					if ( leading )
+						indent = xpos;
+						
+					leading = false;
+					
+					if ( fullSel || sellen )
+						p->setPen(pal.highlightedText().color());
+						
+					p->drawText(xpos, baseline, QString(c));
+				} else if (
+						(
+							(c == ' ')
+						&&
+							(
+								(
+									leading
+								&&
+									showLeading
+								)
+							||
+								(
+									(idx > last)
+								&&
+									showTrailing
+								)
+							)
+						)
+					||
+						(
+							(c == '\t')
+						&&
+							showTabs
+						)
+					)
+				{
+					//p->drawText(xpos - m_spaceSignOffset, ypos + QDocumentPrivate::m_ascent, QChar(0x231E));
+					
+					p->translate(xpos - m_spaceSignOffset, ypos + QDocumentPrivate::m_ascent);
+					p->drawPoints(m_spaceSign, sizeof(m_spaceSign) / sizeof(QPoint));
+					p->translate(m_spaceSignOffset - xpos,-ypos - QDocumentPrivate::m_ascent);
+				}
+				
+				for ( int cidx = 0; cidx < cursor.count(); ++cidx )
+				{
+					if ( cursor[cidx] == idx )
+						p->drawLine(xpos, ypos, xpos, ypos + QDocumentPrivate::m_lineSpacing);
+				}
+				
+				if ( idx < m_composited.count() )
+				{
+					QFormat format = m_doc->impl()->m_formatScheme->format(m_composited[idx]);
+					
+					//qDebug("underline pos : %i", p->fontMetrics().underlinePos());
+					
+					const int ydo = baseline + p->fontMetrics().underlinePos();
+					const int yin = baseline - p->fontMetrics().strikeOutPos();
+					const int yup = baseline - p->fontMetrics().overlinePos();
+					
+					if ( format.overline )
+					{
+						p->drawLine(xpos, yup, xpos + cwidth, yup);
+					}
+					
+					if ( format.strikeout )
+					{
+						p->drawLine(xpos, yin, xpos + cwidth, yin);
+					}
+					
+					if ( format.underline )
+					{
+						p->drawLine(xpos, ydo, xpos + cwidth, ydo);
+					}
+					
+					if ( format.waveUnderline )
+					{
+						QPen oldpen = p->pen();
+						p->setPen(QColor(255, 0, 0));
+						
+						p->drawLine(xpos, ydo,
+									xpos + cwidth / 2 , ypos + QDocumentPrivate::m_lineSpacing - 1);
+									
+						p->drawLine(xpos + cwidth / 2, ypos + QDocumentPrivate::m_lineSpacing - 1,
+									xpos + cwidth, ydo);
+									
+						p->setPen(oldpen);
+					}
+				}
+			} else {
+				if ( wrapped && (wrap < m_frontiers.count()) && (idx >= m_frontiers.at(wrap).first) )
+				{
+					++wrap;
+					xpos = indent;
+					ypos += QDocumentPrivate::m_lineSpacing;
+				}
+				
+				if ( !c.isSpace() )
+				{
+					if ( leading )
+						indent = xpos;
+						
+					leading = false;
+				}
+			}
+			
+			if ( sellen )
+				leftSel = !(--sellen);
+			else
+				leftSel = false;
+				
+			if ( leftSel )
+			{
+				p->setPen(pal.text().color());
+				fmt = 0;
+			}
+			
+			xpos += cwidth;
+			++column;
+			++idx;
+			
+			if ( !wrapped && xpos > maxWidth )
+				break;
+		}
+		
+		// ensure drawing of cursor at EOL
+		for ( int cidx = 0; cidx < cursor.count(); ++cidx )
+		{
+			if ( cursor[cidx] == idx )
+				p->drawLine(xpos, ypos, xpos, ypos + QDocumentPrivate::m_lineSpacing);
+		}
+		
+		if ( wrapped && unbounded )
+			p->fillRect(
+							xpos, ypos,
+							maxWidth - xpos, QDocumentPrivate::m_lineSpacing,
+							pal.highlight()
+						);
+						
+	}
+}
+
+//////////////////
+
+
+/////////////////////////
+//	QDocumentCursorHandle
+/////////////////////////
+QDocumentCursorHandle::QDocumentCursorHandle(QDocument *d, int line)
+ :	m_flags(ColumnMemory), m_doc(d),
+	#if QT_VERSION >= 0x040400
+	m_ref(0),
+	#endif
+	m_begOffset(0), m_endOffset(0), m_max(0), m_begLine(line), m_endLine(-1)
+{
+	#if QT_VERSION < 0x040400
+	m_ref.init(0);
+	#endif
+	
+	//m_blocks.push(0);
+	//qDebug("Cursor handle created : 0x%x", this);
+}
+
+QDocumentCursorHandle::~QDocumentCursorHandle()
+{
+	//qDebug("Cursor handle deleted : 0x%x", this);
+	Q_ASSERT(!m_ref);
+	
+	QDocumentCommand::disableAutoUpdate(this);
+}
+
+void QDocumentCursorHandle::copy(const QDocumentCursorHandle *c)
+{
+	if ( !c )
+		return;
+		
+	m_begLine = c->m_begLine;
+	m_begOffset = c->m_begOffset;
+	m_endLine = c->m_endLine;
+	m_endOffset = c->m_endOffset;
+	m_flags = c->m_flags;
+	m_max = c->m_max;
+}
+
+QDocument* QDocumentCursorHandle::document() const
+{
+	return m_doc;
+}
+
+QDocumentCursorHandle* QDocumentCursorHandle::clone() const
+{
+	QDocumentCursorHandle *c = new QDocumentCursorHandle(m_doc);
+	c->copy(this);
+	
+	c->setAutoUpdated(isAutoUpdated());
+	
+	return c;
+}
+
+bool QDocumentCursorHandle::atEnd() const
+{
+	if ( !m_doc )
+		return true;
+		
+	bool atLineEnd;
+	QDocumentLine l = m_doc->line(m_begLine);
+	
+	//qDebug("Cursor handle : 0x%x->atEnd() => 0x%x", this, m_begLine.handle());
+	
+	if ( l.isValid() )
+	{
+		atLineEnd = m_begOffset == l.length();
+		l = m_doc->line(m_begLine + 1);
+	} else {
+		//qWarning("Invalid cursor...");
+		return true;
+	}
+	
+	return l.isNull() && atLineEnd;
+}
+
+bool QDocumentCursorHandle::atStart() const
+{
+	if ( !m_doc )
+		return true;
+		
+	QDocumentLine l = m_doc->line(m_begLine - 1);
+	
+	return l.isNull() && !m_begOffset;
+}
+
+bool QDocumentCursorHandle::atBlockEnd() const
+{
+	return atLineEnd();
+}
+
+bool QDocumentCursorHandle::atBlockStart() const
+{
+	return atLineStart();
+}
+
+bool QDocumentCursorHandle::atLineEnd() const
+{
+	if ( !m_doc )
+		return true;
+		
+	QDocumentLine l = m_doc->line(m_begLine);
+	
+	return l.isValid() ? l.length() == m_begOffset : false;
+}
+
+bool QDocumentCursorHandle::atLineStart() const
+{
+	if ( !m_doc )
+		return true;
+		
+	QDocumentLine l = m_doc->line(m_begLine);
+	
+	return l.isValid() ? !m_begOffset : false;
+}
+
+bool QDocumentCursorHandle::hasSelection() const
+{
+	if ( !m_doc )
+		return false;
+		
+	QDocumentLine l1 = m_doc->line(m_begLine), l2 = m_doc->line(m_endLine);
+	
+	return l1.isValid() && l2.isValid();
+}
+
+bool QDocumentCursorHandle::isSilent() const
+{
+	return hasFlag(Silent);
+}
+
+void QDocumentCursorHandle::setSilent(bool y)
+{
+	if ( y )
+		setFlag(Silent);
+	else
+		clearFlag(Silent);
+}
+
+bool QDocumentCursorHandle::isAutoUpdated() const
+{
+	return QDocumentCommand::isAutoUpdated(this);
+}
+
+void QDocumentCursorHandle::setAutoUpdated(bool y)
+{
+	if ( y )
+		QDocumentCommand::enableAutoUpdate(this);
+	else
+		QDocumentCommand::disableAutoUpdate(this);
+}
+
+QDocumentLine QDocumentCursorHandle::line() const
+{
+	if ( !m_doc )
+		return QDocumentLine();
+		
+	return m_doc->line(m_begLine);
+}
+
+QDocumentLine QDocumentCursorHandle::anchorLine() const
+{
+	if ( !m_doc )
+		return QDocumentLine();
+		
+	return m_endLine != -1 ? m_doc->line(m_endLine) : line();
+}
+
+int QDocumentCursorHandle::lineNumber() const
+{
+	return m_begLine;
+}
+
+int QDocumentCursorHandle::anchorLineNumber() const
+{
+	return m_endLine != -1 ? m_endLine : m_begLine;
+}
+
+int QDocumentCursorHandle::anchorColumnNumber() const
+{
+	if ( !m_doc )
+		return -1;
+		
+	return m_doc->line(m_endLine).isValid() ? m_endOffset : m_begOffset;
+}
+
+int QDocumentCursorHandle::visualColumnNumber() const
+{
+	return QDocument::screenLength(
+						line().text().constData(),
+						m_begOffset,
+						QDocument::tabStop()
+					);
+					
+}
+
+int QDocumentCursorHandle::columnNumber() const
+{
+	return m_begOffset;
+}
+
+void QDocumentCursorHandle::setColumnNumber(int c, int m)
+{
+	if ( !m_doc )
+		return;
+		
+	QDocumentLine l1 = m_doc->line(m_begLine), l2 = m_doc->line(m_endLine);
+	
+	if ( m & QDocumentCursor::KeepAnchor )
+	{
+		if ( l2.isNull() )
+		{
+			m_endLine = m_begLine;
+			m_endOffset = m_begOffset;
+		}
+		
+		m_begOffset = c; //qBound(0, c, l1.length());
+	} else {
+		m_endLine = -1;
+		m_endOffset = 0;
+		m_begOffset = c; //qBound(0, c, l1.length());
+	}
+	
+	refreshColumnMemory();
+}
+
+QPoint QDocumentCursorHandle::documentPosition() const
+{
+	if ( !m_doc )
+		return QPoint();
+	
+	return QPoint(0, m_doc->y(m_begLine)) + m_doc->line(m_begLine).cursorToDocumentOffset(m_begOffset);
+}
+
+QPoint QDocumentCursorHandle::anchorDocumentPosition() const
+{
+	if ( !m_doc )
+		return QPoint();
+	
+	if ( m_endLine < 0 || m_endOffset < 0 )
+		return documentPosition();
+	
+	return QPoint(0, m_doc->y(m_endLine)) + m_doc->line(m_endLine).cursorToDocumentOffset(m_endOffset);
+}
+
+QPolygon QDocumentCursorHandle::documentRegion() const
+{
+	QPolygon poly;
+	QPoint p = documentPosition(), ap = anchorDocumentPosition();
+	
+	int w = m_doc->width();
+	const int lm = m_doc->impl()->m_leftMargin;
+	const int ls = m_doc->impl()->m_lineSpacing - 1;
+	
+	if ( p == ap )
+	{
+		poly
+			<< p
+			<< QPoint(p.x() + 1, p.y())
+			<< QPoint(p.x() + 1, p.y() + ls)
+			<< QPoint(p.x(), p.y() + ls);
+	} else if ( p.y() == ap.y() ) {
+		poly
+			<< p
+			<< ap
+			<< QPoint(ap.x(), ap.y() + ls)
+			<< QPoint(p.x(), p.y() + ls);
+	} else if ( p.y() < ap.y() ) {
+		poly
+			<< p
+			<< QPoint(w, p.y());
+		
+		if ( ap.x() < w )
+			poly << QPoint(w, ap.y()) << ap;
+		
+		poly
+			<< QPoint(ap.x(), ap.y() + ls)
+			<< QPoint(lm, ap.y() + ls)
+			<< QPoint(lm, p.y() + ls);
+		
+		if ( p.x() > lm )
+			poly << QPoint(p.x(), p.y() + ls);
+	} else {
+		poly
+			<< ap
+			<< QPoint(w, ap.y());
+		
+		if ( p.x() < w )
+			poly << QPoint(w, p.y()) << p;
+		
+		poly
+			<< QPoint(p.x(), p.y() + ls)
+			<< QPoint(lm, p.y() + ls)
+			<< QPoint(lm, ap.y() + ls);
+		
+		if ( ap.x() > lm )
+			poly << QPoint(ap.x(), ap.y() + ls);
+	}
+	
+	return poly;
+}
+
+int QDocumentCursorHandle::position() const
+{
+	if ( !m_doc )
+		return -1;
+		
+	int pos = m_doc->line(m_begLine).position();
+	
+	return (pos != -1) ? pos + m_begOffset : pos;
+}
+
+void QDocumentCursorHandle::shift(int offset)
+{
+	if ( !m_doc )
+		return;
+		
+	QDocumentLine l1 = m_doc->line(m_begLine), l2 = m_doc->line(m_endLine);
+	
+	if ( l1.isValid() )
+		m_begOffset = qBound(0, m_begOffset + offset, l1.length());
+		
+	if ( l2.isValid() )
+		m_endOffset = qBound(0, m_endOffset + offset, l2.length());
+}
+
+void QDocumentCursorHandle::refreshColumnMemory()
+{
+	//m_max = m_doc->line(line).cursorToX(offset);
+	m_max = hasFlag(ColumnMemory) ? m_doc->line(m_begLine).cursorToDocumentOffset(m_begOffset).x() : 0;
+}
+
+bool QDocumentCursorHandle::hasColumnMemory() const
+{
+	return hasFlag(ColumnMemory);
+}
+
+void QDocumentCursorHandle::setColumnMemory(bool y)
+{
+	if ( y )
+		setFlag(ColumnMemory);
+	else
+		clearFlag(ColumnMemory);
+}
+
+void QDocumentCursorHandle::setPosition(int pos, int m)
+{
+	Q_UNUSED(pos)
+	Q_UNUSED(m)
+	
+	qWarning("Set position to cursor using character index : forbidden...");
+	/*
+	if ( m == QDocumentCursor::MoveAnchor )
+	{
+		m_begLine = m_doc->findLine(pos);
+		m_begOffset = (m_begLine.isValid() ? pos : 0);
+		
+		m_endLine = QDocumentLine();
+		m_endOffset = 0;
+		
+		m_max = m_begLine.cursorToX(m_begOffset);
+	} else {
+		m_endLine = m_doc->findLine(pos);
+		m_endOffset = (m_begLine.isValid() ? pos : 0);
+		
+		//m_max = 0;
+	}
+	*/
+}
+
+bool QDocumentCursorHandle::movePosition(int count, int op, int m)
+{
+	if ( !m_doc )
+		return false;
+	
+	QDocumentLine l, l1 = m_doc->line(m_begLine), l2 = m_doc->line(m_endLine);
+	
+	int &line = m_begLine;
+	int &offset = m_begOffset;
+	static QRegExp wordStart("\\b\\w+$"), wordEnd("^\\w+\\b");
+	
+	if ( !(m & QDocumentCursor::KeepAnchor) )
+	{
+		m_endLine = -1;
+		m_endOffset = 0;
+	} else if ( !l2.isValid() ) {
+		m_endLine = m_begLine;
+		m_endOffset = m_begOffset;
+	}
+	
+	int beg = 0, end = m_doc->lines();
+	
+	switch ( op )
+	{
+		case QDocumentCursor::Left :
+		{
+			if ( atStart() )
+				return false;
+				
+			int remaining = offset;
+			
+			do
+			{
+				if ( remaining >= count )
+				{
+					offset = remaining - count;
+					break;
+				} else if ( line == beg ) {
+					offset = 0;
+					break;
+				}
+				
+				do
+				{
+					--line;
+				} while ( (line > beg) && m_doc->line(line).hasFlag(QDocumentLine::Hidden) );
+				
+				//*line = *it;
+				
+				count -= remaining + 1; // jumping a line is one char
+				offset = remaining = m_doc->line(line).length();
+			} while ( count && remaining );
+			
+			refreshColumnMemory();
+			
+			break;
+		}
+		
+		case QDocumentCursor::Right :
+		{
+			if ( atEnd() )
+				return false;
+				
+			int remaining = m_doc->line(line).length() - offset;
+			
+			do
+			{
+				if ( remaining >= count )
+				{
+					offset += count;
+					break;
+				} else if ( (line + 1) == end ) {
+					offset = remaining;
+					break;
+				}
+				
+				do
+				{
+					++line;
+				} while ( ((line+1) < end) && m_doc->line(line).hasFlag(QDocumentLine::Hidden) );
+				
+				//*line = *it;
+				
+				offset = 0;
+				count -= remaining + 1;
+				remaining = m_doc->line(line).length();
+			} while ( count && remaining );
+			
+			refreshColumnMemory();
+			
+			break;
+		}
+		
+		case QDocumentCursor::Up :
+		{
+			if ( atStart() )
+				return false;
+			
+			//qDebug("%i, %i  : up", line, offset);
+			
+			if ( m & QDocumentCursor::ThroughWrap )
+			{
+				QPoint p = documentPosition();
+				
+				if ( hasColumnMemory() )
+					p.rx() = qMax(p.x(), m_max);
+				
+				p.ry() -= QDocumentPrivate::m_lineSpacing * count;
+				
+				if ( p.y() >= 0 )
+				{
+					m_doc->cursorForDocumentPosition(p, line, offset);
+				} else {
+					line = 0;
+					offset = 0;
+				}
+				
+				return true;
+			}
+			
+			while ( count && (line > beg) )
+			{
+				--line;
+				
+				if ( !m_doc->line(line).hasFlag(QDocumentLine::Hidden) )
+					--count;
+					
+			}
+			
+			//*line = QDocumentLine(*it);
+			//*offset = line->xToCursor(qMin(line->cursorToX(*offset), m_max), 0);
+			l = m_doc->line(line);
+			
+			if ( count )
+				offset = 0;
+			else if ( m == QDocumentCursor::MoveAnchor )
+				offset = l.xToCursor(
+						qMax(
+							l.cursorToX(
+								qMin(
+									offset,
+									l.length()
+								)
+							),
+							m_max
+						)
+					);
+			else
+				offset = qMin(l.length(), offset);
+				
+			break;
+		}
+		
+		case QDocumentCursor::Down :
+		{
+			if ( atEnd() )
+				return false;
+				
+			if ( m & QDocumentCursor::ThroughWrap )
+			{
+				QPoint p = documentPosition();
+				
+				if ( hasColumnMemory() )
+					p.rx() = qMax(p.x(), m_max);
+					
+				p.ry() += QDocumentPrivate::m_lineSpacing * count;
+				
+				int oldLine = line, oldCol = offset;
+				m_doc->cursorForDocumentPosition(p, line, offset);
+				if ( oldLine == line && oldCol == offset )
+					offset = m_doc->line(line).length();
+				return true;
+			}
+			
+			while ( count && ((line + 1) < end) )
+			{
+				++line;
+				
+				if ( !m_doc->line(line).hasFlag(QDocumentLine::Hidden) )
+					--count;
+					
+			}
+			
+			//*line = QDocumentLine(*it);
+			l = m_doc->line(line);
+			
+			if ( count )
+				offset = l.length();
+			else if ( m == QDocumentCursor::MoveAnchor )
+				offset = l.xToCursor(
+						qMax(
+							l.cursorToX(
+								qMin(
+									offset,
+									l.length()
+								)
+							),
+							m_max
+						)
+					);
+			else
+				offset = qMin(l.length(), offset);
+				
+			break;
+		}
+		
+		case QDocumentCursor::Start :
+			if ( atStart() )
+				return false;
+				
+			m_max = offset = 0;
+			line = 0; //m_doc->line(0);
+			break;
+			
+		case QDocumentCursor::End :
+			if ( atEnd() )
+				return false;
+				
+			line = end - 1; //QDocumentLine(*(m_doc->impl()->end() - 1));
+			offset = m_doc->line(line).length();
+			refreshColumnMemory();
+			break;
+			
+		case QDocumentCursor::StartOfBlock :
+			if ( atBlockStart() )
+				return false;
+				
+			m_max = offset = 0;
+			break;
+			
+		case QDocumentCursor::EndOfBlock :
+			if ( atBlockEnd() )
+				return false;
+				
+			offset = m_doc->line(line).length();
+			refreshColumnMemory();
+			break;
+			
+		case QDocumentCursor::NextBlock :
+			
+			if ( atEnd() )
+				return false;
+				
+			while ( ((line + 1) < end) && count )
+			{
+				++line;
+				
+				if ( !m_doc->line(line).hasFlag(QDocumentLine::Hidden) )
+					--count;
+					
+			}
+			
+			if ( !count )
+			{
+				//*line = *it;
+				offset = 0;
+			} else {
+				//*line = QDocumentLine(*(m_doc->impl()->end() - 1));
+				offset = m_doc->line(line).length();
+			}
+			
+			break;
+			
+		case QDocumentCursor::PreviousBlock :
+			
+			if ( atStart() )
+				return false;
+				
+			offset = 0;
+			
+			while ( (line > beg) && count )
+			{
+				--line;
+				
+				if ( !m_doc->line(line).hasFlag(QDocumentLine::Hidden) )
+					--count;
+					
+			}
+			
+			if ( !count )
+			{
+				//*line = *it;
+				offset = m_doc->line(line).length();
+			} else {
+				offset = 0;
+				//*line = QDocumentLine(*(m_doc->impl()->begin()));
+			}
+			
+			//*line = *it;
+			
+			break;
+			
+		case QDocumentCursor::WordLeft :
+		case QDocumentCursor::PreviousWord :
+		{
+			if ( atStart() )
+				return false;
+				
+			l = m_doc->line(line);
+			
+			//for ( int loop = 0; loop <= 1; ++loop )
+			//{
+			//	while ( l.isValid() )
+			
+			// -- patch --
+			/* eats up white space */
+			while ( (offset > 0) && !isWord(l.text().at(offset - 1)) )
+				--offset;
+				
+			/* start of line */
+			if ( offset == 0 )
+			{
+				/* first line, first char => nothing to do */
+				if( line == beg )
+					return true;
+					
+				do
+			// -- patch --
+				{
+// 					//offset = qMin(offset, l.length() - 1);
+// 					bool next = (l.length() && offset >= 0) ? isWord(l.text().at(offset)) : true;
+//
+// 					if ( loop )
+// 						next = !next;
+//
+// 					if ( !next )
+// 						break;
+//
+// 					if ( offset > 0 )
+// 					{
+// 						--offset;
+// 					} else if ( line != beg ) {
+// 						do
+// 						{
+// 							//*line = *(--it);
+// 							--line;
+// 							l = m_doc->line(line);
+// 							offset = l.length() - 1;
+// 						} while ( l.isValid() && (line != beg) && l.hasFlag(QDocumentLine::Hidden) );
+// 					} else {
+// 						break;
+// 					}
+// 				}
+// 			}
+//
+// 			while ( l.isValid() )
+// 			{
+// 				offset = qMin(offset, l.length());
+// 				bool next = (offset <= 0) ? false : isWord(l.text().at(offset - 1));
+//
+// 				if ( !next )
+// 					break;
+//
+// 				--offset;
+			
+			// -- patch --
+					--line;
+					l = m_doc->line(line);
+					offset = l.length();
+				} while ( (line != beg) && l.isValid() && l.hasFlag(QDocumentLine::Hidden) );
+				return true;
+			// -- patch --
+			}
+			
+			// -- patch --
+			/* eats up whole word */
+			while ( (offset > 0) && isWord(l.text().at(offset - 1)) )
+				--offset;
+			// -- patch --
+			
+			refreshColumnMemory();
+			
+			break;
+		}
+		
+		case QDocumentCursor::WordRight :
+		case QDocumentCursor::NextWord :
+		{
+			if ( atEnd() )
+				return false;
+				
+			l = m_doc->line(line);
+			int lineLength = l.text().length();
+			
+// 			for ( int loop = 0; loop <= 1; ++loop )
+			// -- patch --
+			/* end of line */
+			if ( offset == lineLength )
+ 			{
+// 				while ( l.isValid() )
+				/* last line, last char => nothing to do */
+				if ( line == end )
+					return true;
+			// -- patch --
+				do
+				{
+// 					//offset = qBound(0, offset, l.length() - 1);
+// 					bool next = (offset < l.length()) ? isWord(l.text().at(offset)) : true;
+//
+// 					if ( loop )
+// 						next = !next;
+//
+// 					if ( !next )
+// 						break;
+//
+// 					if ( offset < l.length() )
+// 					{
+// 						++offset;
+// 					} else if ( (line + 1) != end ) {
+// 						offset = 0;
+// 						do
+// 						{
+// 							++line;
+// 							l = m_doc->line(line);
+// 						} while ( l.isValid() && ((line + 1) != end) && (l.hasFlag(QDocumentLine::Hidden) || !l.length()) );
+// 					} else {
+			// -- patch --
+					++line;
+					l = m_doc->line(line);
+					offset = 0;
+				} while ( (line != end) && l.isValid() && l.hasFlag(QDocumentLine::Hidden) );
+				
+				lineLength = l.text().length();
+				/* empty line */
+				if ( lineLength == 0 )
+					return true;
+					
+				/* eats up white space */
+				while ( !isWord(l.text().at(offset)) )
+				{
+					++offset;
+					/* move to end of line */
+					if ( offset == lineLength )
+						break;
+			// -- patch --
+//					}
+				}
+			// -- patch --
+				return true;
+			// -- patch --
+			}
+			
+			// -- patch --
+			/* next char */
+			++offset;
+			/* eats up whole word */
+			while ( (offset < lineLength) && isWord(l.text().at(offset)) )
+				++offset;
+				
+			/* eats up white space */
+			while ( (offset < lineLength) && !isWord(l.text().at(offset)) )
+				++offset;
+			// -- patch --
+			
+			refreshColumnMemory();
+			
+			break;
+		}
+		
+		case QDocumentCursor::StartOfWord :
+		{
+			int x = wordStart.indexIn(m_doc->line(line).text().left(offset));
+			
+			if ( x != -1 )
+			{
+				offset = x;
+			} else {
+				qDebug("failed to find SOW : %i + %i != %i",
+						x, wordStart.matchedLength(), offset);
+						
+				return false;
+			}
+			
+			refreshColumnMemory();
+			
+			break;
+		}
+		
+		case QDocumentCursor::EndOfWord :
+		{
+			int x = wordEnd.indexIn(m_doc->line(line).text(), offset, QRegExp::CaretAtOffset);
+			
+			if ( x == offset )
+			{
+				offset += wordEnd.matchedLength();
+			} else {
+				qDebug("failed to find EOW");
+				return false;
+			}
+			
+			refreshColumnMemory();
+			
+			break;
+		}
+		
+		default:
+			qWarning("Unhandled move operation...");
+			return false;
+	};
+	
+	return true;
+}
+
+void QDocumentCursorHandle::moveTo(const QDocumentCursor &c)
+{
+	if ( !c.isValid() || !m_doc )
+		return;
+		
+	m_begLine = c.handle()->m_begLine;
+	m_begOffset = c.handle()->m_begOffset;
+	
+	m_endLine = -1;
+	m_endOffset = 0;
+	
+	refreshColumnMemory();
+}
+
+void QDocumentCursorHandle::moveTo(int line, int column)
+{
+	m_begLine = line;
+	m_begOffset = column;
+	
+	m_endLine = -1;
+	m_endOffset = 0;
+	
+	refreshColumnMemory();
+}
+
+void QDocumentCursorHandle::insertText(const QString& s, bool keepAnchor)
+{
+	if ( !m_doc || s.isEmpty() || m_doc->line(m_begLine).isNull() )
+		return;
+	
+	bool sel = hasSelection();
+	
+	if ( sel )
+	{
+		beginEditBlock();
+		removeSelectedText(keepAnchor);
+	}
+	
+	QDocumentCommand *command = new QDocumentInsertCommand(
+										m_begLine,
+										m_begOffset,
+										s,
+										m_doc
+									);
+	
+	command->setKeepAnchor(keepAnchor);
+	command->setTargetCursor(this);
+	execute(command);
+	
+	if ( sel )
+		endEditBlock();
+}
+
+void QDocumentCursorHandle::eraseLine()
+{
+	if ( !m_doc )
+		return;
+		
+	QDocumentCommand *command = 0;
+	
+	if ( m_endLine == -1 )
+	{
+		command = new QDocumentEraseCommand(
+										m_begLine,
+										0,
+										m_begLine + 1,
+										0,
+										m_doc
+									);
+	} else {
+		command = new QDocumentEraseCommand(
+										qMin(m_begLine, m_endLine),
+										0,
+										qMax(m_begLine, m_endLine) + 1,
+										0,
+										m_doc
+									);
+	}
+	
+	command->setTargetCursor(this);
+	execute(command);
+}
+
+QChar QDocumentCursorHandle::nextChar() const
+{
+	if ( !m_doc )
+		return QChar();
+	
+	QDocumentLine l = m_doc->line(m_begLine);
+	
+	if ( !l.isValid() )
+		return QChar();
+	
+	return m_begOffset < l.length() ? l.text().at(m_begOffset) : QLatin1Char('\n');
+}
+
+QChar QDocumentCursorHandle::previousChar() const
+{
+	if ( !m_doc || (m_begLine <= 0 && m_begOffset <= 0) )
+		return QChar();
+	
+	QDocumentLine l = m_doc->line(m_begLine);
+	
+	if ( !l.isValid() || m_begOffset > l.length() )
+		return QChar();
+	
+	return m_begOffset ? l.text().at(m_begOffset - 1) : QLatin1Char('\n');
+}
+
+void QDocumentCursorHandle::deleteChar()
+{
+	if ( !m_doc )
+		return;
+		
+	QDocumentLine l = m_doc->line(m_begLine);
+	
+	if ( l.isNull() || atEnd() )
+		return;
+		
+	QDocumentCommand *command = 0;
+	
+	if ( !atLineEnd() )
+	{
+		command = new QDocumentEraseCommand(
+											m_begLine,
+											m_begOffset,
+											m_begLine,
+											m_begOffset + 1,
+											m_doc
+										);
+										
+	} else {
+		// merge two blocks...
+		command = new QDocumentEraseCommand(
+											m_begLine,
+											m_begOffset,
+											m_begLine + 1,
+											0,
+											m_doc
+										);
+										
+	}
+	
+	command->setTargetCursor(this);
+	command->setUndoOffset(-1);
+	execute(command);
+}
+
+void QDocumentCursorHandle::deletePreviousChar()
+{
+	if ( !m_doc )
+		return;
+		
+	QDocumentLine l = m_doc->line(m_begLine);
+	
+	if ( l.isNull() || atStart() )
+		return;
+		
+	QDocumentCommand *command = 0;
+	
+	if ( !atLineStart() )
+	{
+		command = new QDocumentEraseCommand(
+											m_begLine,
+											m_begOffset - 1,
+											m_begLine,
+											m_begOffset,
+											m_doc
+										);
+										
+	} else {
+		// merge two blocks...
+		QDocumentLine prev = m_doc->line(m_begLine - 1);
+		
+		command = new QDocumentEraseCommand(
+											m_begLine - 1,
+											prev.length(),
+											m_begLine,
+											m_begOffset,
+											m_doc
+										);
+										
+	}
+	
+	command->setTargetCursor(this);
+	execute(command);
+}
+
+void QDocumentCursorHandle::execute(QDocumentCommand *c)
+{
+	if ( !m_doc )
+		return;
+		
+	if ( isSilent() && !c->isSilent() )
+		c->setSilent(isSilent());
+	
+	if ( m_blocks.count() )
+	{
+		c->redo();
+		m_blocks.top()->addCommand(c);
+		
+	} else if ( m_doc ) {
+		//qDebug("Cursor handle executing command : 0x%x", this);
+		
+		m_doc->execute(c);
+	}
+}
+
+void QDocumentCursorHandle::beginEditBlock()
+{
+	m_blocks.push(new QDocumentCommandBlock(m_doc));
+}
+
+void QDocumentCursorHandle::endEditBlock()
+{
+	if ( !m_doc || m_blocks.isEmpty() )
+		return;
+		
+	//qDebug("Cursor handle executing command : 0x%x [block]", this);
+	
+	QDocumentCommandBlock *block = m_blocks.pop();
+	
+	// special trick to prevent double redo() while getting rid of
+	// bugs occuring in when inserting/erasing in overlapping lines
+	// inside a command block
+	block->setWeakLock(true);
+	
+	m_doc->execute(block);
+}
+
+QDocumentCursor QDocumentCursorHandle::selectionStart() const
+{
+	if ( !m_doc )
+		return QDocumentCursor();
+		
+	if ( !hasSelection() )
+		return QDocumentCursor(clone());
+		
+	QDocumentCursor pos(m_doc, m_begLine, m_begOffset),
+					anc(m_doc, m_endLine, m_endOffset);
+					
+	return (pos < anc) ? pos : anc;
+}
+
+QDocumentCursor QDocumentCursorHandle::selectionEnd() const
+{
+	if ( !m_doc )
+		return QDocumentCursor();
+		
+	if ( !hasSelection() )
+		return QDocumentCursor(clone());
+		
+	QDocumentCursor pos(m_doc, m_begLine, m_begOffset),
+					anc(m_doc, m_endLine, m_endOffset);
+					
+	return (pos > anc) ? pos : anc;
+}
+
+bool QDocumentCursorHandle::eq(const QDocumentCursorHandle *h)
+{
+	return (m_begLine == h->m_begLine) && (m_begOffset == h->m_begOffset);
+	/*
+	if ( !hasSelection() )
+		return (m_begLine == h->m_begLine) && (m_begOffset == h->m_begOffset);
+		
+	return
+			(m_begLine == h->m_begLine)
+		&&
+			(m_begOffset == h->m_begOffset)
+		&&
+			(m_endLine == h->m_endLine)
+		&&
+			(m_endOffset == h->m_endOffset)
+		;
+	*/
+}
+
+bool QDocumentCursorHandle::lt(const QDocumentCursorHandle *h)
+{
+	return
+				(m_begLine < h->m_begLine)
+			||
+				((m_begLine == h->m_begLine) && (m_begOffset < h->m_begOffset))
+			;
+}
+
+bool QDocumentCursorHandle::gt(const QDocumentCursorHandle *h)
+{
+	return
+				(m_begLine > h->m_begLine)
+			||
+				((m_begLine == h->m_begLine) && (m_begOffset > h->m_begOffset))
+			;
+}
+
+QString QDocumentCursorHandle::selectedText() const
+{
+	if ( !m_doc )
+		return QString();
+		
+	QDocumentLine l1 = m_doc->line(m_begLine), l2 = m_doc->line(m_endLine);
+	
+	if ( l1.isNull() || l2.isNull() )
+		return QString();
+		
+	QString s;
+	
+	if ( m_begLine == m_endLine )
+	{
+		int min = qMin(m_begOffset, m_endOffset),
+			max = qMax(m_begOffset, m_endOffset);
+			
+		s = l1.text().mid(min, max - min);
+	} else if ( m_begLine < m_endLine ) {
+		s = l1.text().mid(m_begOffset);
+		
+		int it = m_begLine;
+		//QDocumentConstIterator it = m_doc->impl()->index(m_begLine.handle());
+		
+		while ( ++it < m_endLine )
+		{
+			s += '\n';
+			s += m_doc->line(it).text();
+		}
+		
+		s += '\n';
+		s += l2.text().left(m_endOffset);
+	} else {
+		s = l2.text().mid(m_endOffset);
+		
+		int it = m_endLine;
+		//QDocumentConstIterator it = m_doc->impl()->index(m_endLine.handle());
+		
+		while ( ++it < m_begLine )
+		{
+			s += '\n';
+			s += m_doc->line(it).text();
+		}
+		
+		s += '\n';
+		s += l1.text().left(m_begOffset);
+	}
+	
+	return s;
+}
+
+void QDocumentCursorHandle::clearSelection()
+{
+	if ( m_doc && m_doc->line(m_endLine).isValid() )
+	{
+		//m_begLine = m_endLine;
+		//m_begOffset = m_endOffset;
+		
+		m_endLine = -1;
+		m_endOffset = -1;
+	}
+}
+
+void QDocumentCursorHandle::replaceSelectedText(const QString& text)
+{
+	int begline, begcol;
+	beginBoundary(begline, begcol);
+	
+	bool atStart = (begline == m_begLine && begcol == m_begOffset);
+	
+	if ( text.isEmpty() )
+	{
+		removeSelectedText();
+	} else {
+		insertText(text, true);
+		
+		/*
+			Adjust selection around the new text and preserve the order
+			of position and anchor
+		*/
+		/*
+		if ( atStart )
+		{
+			m_endLine = m_begLine;
+			m_begLine = begline;
+			m_endOffset = m_begOffset;
+			m_begOffset = begcol;
+		} else {
+			m_endLine = begline;
+			m_endOffset = begcol;
+		}
+		*/
+	}
+	
+	//qDebug("[%i, %i] => ( (%i, %i), (%i, %i) )", begline, begcol, m_begLine, m_begOffset, m_endLine, m_endOffset);
+}
+
+void QDocumentCursorHandle::select(QDocumentCursor::SelectionType t)
+{
+	if ( !m_doc || !m_doc->line(m_begLine).isValid() )
+		return;
+		
+	if ( t == QDocumentCursor::LineUnderCursor )
+	{
+		movePosition(1, QDocumentCursor::StartOfLine, QDocumentCursor::MoveAnchor);
+		movePosition(1, QDocumentCursor::EndOfLine, QDocumentCursor::KeepAnchor);
+		
+	} else if ( t == QDocumentCursor::WordUnderCursor ) {
+		
+		movePosition(1, QDocumentCursor::StartOfWord, QDocumentCursor::MoveAnchor);
+		movePosition(1, QDocumentCursor::EndOfWord, QDocumentCursor::KeepAnchor);
+	}
+}
+
+void QDocumentCursorHandle::setSelectionBoundary(const QDocumentCursor& c)
+{
+	if (
+			!m_doc
+		||
+			(m_begLine == -1)
+		||
+			(
+					(c.lineNumber() == m_begLine)
+				&&
+					(c.columnNumber() == m_begOffset)
+			)
+		)
+		return;
+		
+	//qDebug("setting new selection boundary... ");
+	
+	if ( !hasSelection() )
+	{
+		m_endLine = m_begLine;
+		m_endOffset = m_begOffset;
+	}
+	
+	m_begLine = c.lineNumber();
+	m_begOffset = c.columnNumber();
+}
+
+bool QDocumentCursorHandle::isWithinSelection(const QDocumentCursor& c) const
+{
+	if ( !hasSelection() ) //|| c.hasSelection() )
+		return false;
+		
+	int minOff, maxOff, min, max;
+	
+	if ( m_begLine > m_endLine )
+	{
+		max = m_begLine;
+		maxOff = m_begOffset;
+		
+		min = m_endLine;
+		minOff = m_endOffset;
+	} else {
+		min = m_begLine;
+		minOff = m_begOffset;
+		
+		max = m_endLine;
+		maxOff = m_endOffset;
+	}
+	
+	return (m_begLine == m_endLine)
+		?
+			(
+				(c.lineNumber() == m_begLine)
+			&&
+				(qMin(m_begOffset, m_endOffset) <= c.columnNumber())
+			&&
+				(qMax(m_begOffset, m_endOffset) >= c.columnNumber())
+			)
+		:
+			(
+				(
+					(c.lineNumber() > min)
+				&&
+					(c.lineNumber() < max)
+				)
+			||
+				(
+					(c.lineNumber() == min)
+				&&
+					(minOff <= c.columnNumber())
+				)
+			||
+				(
+					(c.lineNumber() == max)
+				&&
+					(maxOff >= c.columnNumber())
+				)
+			)
+		;
+		
+}
+
+/*
+	beware when modifying these as their current form handle the special
+	case of no selection (m_endLine == -1) and a hasty change may break
+	that behavior : no selection -> both boundary are the cursor pos = (m_begLine, m_begOffset)
+*/
+void QDocumentCursorHandle::beginBoundary(int& begline, int& begcol) const
+{
+	if ( m_begLine < m_endLine )
+	{
+		begline = m_begLine;
+		begcol = m_begOffset;
+	} else {
+		begline = m_endLine;
+		begcol = (m_begLine == m_endLine && m_begOffset < m_endOffset) ? m_begOffset : m_endOffset;
+	}
+}
+
+void QDocumentCursorHandle::endBoundary(int& endline, int& endcol) const
+{
+	if ( m_begLine < m_endLine )
+	{
+		endline = m_endLine;
+		endcol = m_endOffset;
+	} else {
+		endline = m_begLine;
+		endcol = (m_begLine == m_endLine && m_begOffset < m_endOffset) ? m_endOffset : m_begOffset;
+	}
+}
+
+void QDocumentCursorHandle::boundaries(int& begline, int& begcol, int& endline, int& endcol) const
+{
+	beginBoundary(begline, begcol);
+	endBoundary(endline, endcol);
+	
+	/*
+	if ( m_begLine == m_endLine )
+	{
+		begline = m_begLine;
+		endline = m_endLine;
+		if ( m_begOffset < m_endOffset )
+		{
+			begcol = m_begOffset;
+			endcol = m_endOffset;
+		} else {
+			endcol = m_begOffset;
+			begcol = m_endOffset;
+		}
+	} else if ( m_begLine < m_endLine ) {
+		begline = m_begLine;
+		endline = m_endLine;
+		begcol = m_begOffset;
+		endcol = m_endOffset;
+	} else {
+		endline = m_begLine;
+		begline = m_endLine;
+		endcol = m_begOffset;
+		begcol = m_endOffset;
+	}
+	*/
+}
+
+void QDocumentCursorHandle::substractBoundaries(int lbeg, int cbeg, int lend, int cend)
+{
+	int tlmin, tlmax, tcmin, tcmax;
+	
+	boundaries(tlmin, tcmin, tlmax, tcmax);
+
+	bool begFirst = tlmin == m_begLine && tcmin == m_begOffset;
+	
+	if ( tlmax < lbeg || tlmin > lend || (tlmax == lbeg && tcmax < cbeg) || (tlmin == lend && tcmin > cend) )
+	{
+		// no intersection
+		return;
+	}
+	
+	int numLines = lend - lbeg;
+	bool beyondBeg = (tlmin > lbeg || (tlmin == lbeg && tcmin >= cbeg));
+	bool beyondEnd = (tlmax < lend || (tlmax == lend && tcmax <= cend));
+	
+	if ( beyondBeg && beyondEnd )
+	{
+		//qDebug("(%i, %i : %i, %i) erased as in (%i, %i : %i, %i)", tlmin, tcmin, tlmax, tcmax, lbeg, cbeg, lend, cend);
+		// cursor erased...
+		m_begLine = m_endLine = lbeg;
+		m_begOffset = m_endOffset = cbeg;
+	} else if ( beyondEnd ) {
+		//qDebug("beyond end");
+		if ( begFirst )
+		{
+			m_endLine = lbeg;
+			m_endOffset = cbeg;
+		} else {
+			m_begLine = lbeg;
+			m_begOffset = cbeg;
+		}
+	} else if ( beyondBeg ) {
+		//qDebug("beyond beg");
+		if ( begFirst )
+		{
+			m_begLine = lend;
+			m_begOffset = cend;
+			if ( numLines )
+			{
+				m_begLine -= numLines;
+				m_endLine -= numLines;
+			} else {
+				m_begOffset = cbeg;
+			}
+			if ( m_begLine == m_endLine )
+				m_endOffset -= (cend - cbeg);
+		} else {
+			m_endLine = lend;
+			m_endOffset = cend;
+			if ( numLines )
+			{
+				m_endLine -= numLines;
+				m_begLine -= numLines;
+			} else {
+				m_endOffset = cbeg;
+			}
+			if ( m_begLine == m_endLine )
+				m_begOffset -= (cend - cbeg);
+		}
+	} else {
+		int off = cend - cbeg;
+		
+		//qDebug("correcting by %i", off);
+		
+		if ( begFirst )
+		{
+			m_endLine -= numLines;
+			if ( tlmax == lend )
+			{
+				m_endOffset -= off;
+			}
+		} else {
+			m_begLine -= numLines;
+			if ( tlmax == lend )
+			{
+				m_begOffset -= off;
+			}
+		}
+	}
+	
+	//qDebug("(%i, %i : %i, %i) corrected to (%i, %i : %i, %i)", tlmin, tcmin, tlmax, tcmax, m_begLine, m_begOffset, m_endLine, m_endOffset);
+}
+
+void QDocumentCursorHandle::intersectBoundaries(int& lbeg, int& cbeg, int& lend, int& cend) const
+{
+	int tlmin, tlmax, tcmin, tcmax, clmin, clmax, ccmin, ccmax;
+	
+	boundaries(tlmin, tcmin, tlmax, tcmax);
+	clmin = lbeg;
+	clmax = lend;
+	ccmin = cbeg;
+	ccmax = cend;
+	
+	if ( tlmax < clmin || tlmin > clmax || (tlmax == clmin && tcmax < ccmin) || (tlmin == clmax && tcmin > ccmax) )
+	{
+		lbeg = cbeg = lend = cend = -1;
+		return;
+	}
+	
+	if ( tlmin == clmin )
+	{
+		lbeg = tlmin;
+		cbeg = qMax(tcmin, ccmin);
+	} else if ( tlmin < clmin ) {
+		lbeg = clmin;
+		cbeg = ccmin;
+	} else {
+		lbeg = tlmin;
+		cbeg = tcmin;
+	}
+
+	if ( tlmax == clmax )
+	{
+		lend = tlmax;
+		cend = qMin(tcmax, ccmax);
+	} else if ( tlmax < clmax ) {
+		lend = tlmax;
+		cend = tcmax;
+	} else {
+		lend = clmax;
+		cend = ccmax;
+	}
+}
+
+void QDocumentCursorHandle::intersectBoundaries(QDocumentCursorHandle *h, int& lbeg, int& cbeg, int& lend, int& cend) const
+{
+	int tlmin, tlmax, tcmin, tcmax, clmin, clmax, ccmin, ccmax;
+	
+	boundaries(tlmin, tcmin, tlmax, tcmax);
+	h->boundaries(clmin, ccmin, clmax, ccmax);
+	
+	if ( tlmax < clmin || tlmin > clmax || (tlmax == clmin && tcmax < ccmin) || (tlmin == clmax && tcmin > ccmax) )
+	{
+		lbeg = cbeg = lend = cend = -1;
+		return;
+	}
+	
+	if ( tlmin == clmin )
+	{
+		lbeg = tlmin;
+		cbeg = qMax(tcmin, ccmin);
+	} else if ( tlmin < clmin ) {
+		lbeg = clmin;
+		cbeg = ccmin;
+	} else {
+		lbeg = tlmin;
+		cbeg = tcmin;
+	}
+
+	if ( tlmax == clmax )
+	{
+		lend = tlmax;
+		cend = qMin(tcmax, ccmax);
+	} else if ( tlmax < clmax ) {
+		lend = tlmax;
+		cend = tcmax;
+	} else {
+		lend = clmax;
+		cend = ccmax;
+	}
+}
+
+QDocumentCursor QDocumentCursorHandle::intersect(const QDocumentCursor& c) const
+{
+	if ( !hasSelection() )
+	{
+		//if ( c.hasSelection() && c.isWithinSelection(QDocumentCursor(this)) )
+		//	return QDocumentCursor(clone());
+		
+	} else if ( !c.hasSelection() ) {
+		
+		if ( isWithinSelection(c) )
+			return c;
+		
+	} else {
+		QDocumentCursorHandle *h = c.handle();
+
+		int lbeg, lend, cbeg, cend;
+		intersectBoundaries(h, lbeg, cbeg, lend, cend);
+		
+		if ( lbeg != -1 )
+		{
+			QDocumentCursor c(m_doc, lbeg, cbeg);
+			
+			if ( lend != -1 && (lbeg != lend || cbeg != cend) )
+			{
+				c.setSelectionBoundary(QDocumentCursor(m_doc, lend, cend));
+			}
+			
+			return c;
+		}
+	}
+	
+	return QDocumentCursor();
+}
+
+void QDocumentCursorHandle::removeSelectedText(bool keepAnchor)
+{
+	if ( !m_doc )
+		return;
+		
+	QDocumentLine l1 = m_doc->line(m_begLine), l2 = m_doc->line(m_endLine);
+	
+	if ( l1.isNull() || l2.isNull() )
+		return;
+		
+	QDocumentCommand *c;
+	
+	if ( m_begLine < m_endLine )
+	{
+		c = new QDocumentEraseCommand(
+										m_begLine,
+										m_begOffset,
+										m_endLine,
+										m_endOffset,
+										m_doc
+									);
+		
+	} else if ( m_begLine > m_endLine ) {
+		c = new QDocumentEraseCommand(
+										m_endLine,
+										m_endOffset,
+										m_begLine,
+										m_begOffset,
+										m_doc
+									);
+		
+		//m_begLine = m_endLine;
+		//m_begOffset = m_endOffset;
+		
+	} else {
+		c = new QDocumentEraseCommand(
+										m_begLine,
+										qMin(m_begOffset, m_endOffset),
+										m_endLine,
+										qMax(m_begOffset, m_endOffset),
+										m_doc
+									);
+		
+		//m_begOffset = qMin(m_begOffset, m_endOffset);
+		//m_endLine = -1;
+		//m_endOffset = -1;
+	}
+	
+	c->setKeepAnchor(keepAnchor);
+	c->setTargetCursor(this);
+	execute(c);
+}
+
+//////////////////
+
+/////////////////////////
+//	QDocumentPrivate
+/////////////////////////
+
+template <class T> T* getStaticDefault() { static T _globStatInst; return &_globStatInst; }
+
+QFont* QDocumentPrivate::m_font = 0;// = QApplication::font();
+QFontMetrics* QDocumentPrivate::m_fontMetrics = 0;//(m_font);
+
+int QDocumentPrivate::m_defaultTabStop = 4;
+QFormatScheme* QDocumentPrivate::m_defaultFormatScheme = getStaticDefault<QFormatScheme>();
+
+QList<QDocumentPrivate*> QDocumentPrivate::m_documents;
+
+bool QDocumentPrivate::m_fixedPitch;
+int QDocumentPrivate::m_ascent;// = m_fontMetrics.ascent();
+int QDocumentPrivate::m_descent;// = m_fontMetrics.descent();
+int QDocumentPrivate::m_leading;// = m_fontMetrics.leading();
+int QDocumentPrivate::m_spaceWidth;// = m_fontMetrics.width(' ');
+int QDocumentPrivate::m_lineHeight;// = m_fontMetrics.height();
+int QDocumentPrivate::m_lineSpacing;// = m_fontMetrics.lineSpacing();
+
+int QDocumentPrivate::m_leftMargin = 5;
+QDocument::WhiteSpaceMode QDocumentPrivate::m_showSpaces = QDocument::ShowNone;
+QDocument::LineEnding QDocumentPrivate::m_defaultLineEnding = QDocument::Conservative;
+
+int QDocumentPrivate::m_wrapMargin = 15;
+
+QDocumentPrivate::QDocumentPrivate(QDocument *d)
+ : 	m_doc(d),
+	m_editCursor(0),
+	m_lastGroupId(-1),
+	m_constrained(false),
+	m_width(0),
+	m_height(0),
+	m_tabStop(m_defaultTabStop),
+	m_formatScheme(0),
+	m_language(0),
+	m_maxMarksPerLine(0),
+	_nix(0),
+	_dos(0),
+	_mac(0),
+	m_lineEnding(m_defaultLineEnding)
+{
+	m_documents << this;
+	updateFormatCache();
+}
+
+QDocumentPrivate::~QDocumentPrivate()
+{
+	m_marks.clear();
+	m_largest.clear();
+	
+	m_deleting = true;
+	
+	//qDeleteAll(m_lines);
+	foreach ( QDocumentLineHandle *h, m_lines )
+		h->deref();
+		
+	m_lines.clear();
+	
+	m_deleting = false;
+	
+	m_commands.clear();
+	
+	m_documents.removeAll(this);
+}
+
+int QDocumentPrivate::findNextMark(int id, int from, int until)
+{
+	if ( from < 0 )
+		from += m_lines.count();
+		
+	QHash<QDocumentLineHandle*, QList<int> >::const_iterator e = m_marks.constEnd();
+	
+	int max = until;
+	
+	if ( max < 0 )
+		max += m_lines.count();
+	else if ( max < from )
+		max = m_lines.count() - 1;
+		
+	for ( int i = from; i <= max; ++i )
+	{
+		QDocumentLineHandle *h = m_lines.at(i);
+		
+		QHash<QDocumentLineHandle*, QList<int> >::const_iterator it = m_marks.constFind(h);
+		
+		if ( it != e && it->contains(id) )
+			return i;
+			
+	}
+	
+	if ( until > 0 && until < from )
+	{
+		for ( int i = 0; i <= until; ++i )
+		{
+			QDocumentLineHandle *h = m_lines.at(i);
+			
+			QHash<QDocumentLineHandle*, QList<int> >::const_iterator it = m_marks.constFind(h);
+			
+			if ( it != e && it->contains(id) )
+				return i;
+				
+		}
+	}
+	
+	return -1;
+}
+
+int QDocumentPrivate::findPreviousMark(int id, int from, int until)
+{
+	if ( from < 0 )
+		from += m_lines.count();
+		
+	if ( until < 0 )
+	{
+		until += m_lines.count();
+	} else if ( until >= m_lines.count() ) {
+		until = m_lines.count() - 1;
+	}
+	
+	QHash<QDocumentLineHandle*, QList<int> >::const_iterator e = m_marks.constEnd();
+	
+	int min = until;
+	
+	if ( min > from )
+		min = 0;
+		
+	for ( int i = from; i >= min; --i )
+	{
+		QDocumentLineHandle *h = m_lines.at(i);
+		
+		QHash<QDocumentLineHandle*, QList<int> >::const_iterator it = m_marks.constFind(h);
+		
+		if ( it != e && it->contains(id) )
+			return i;
+			
+	}
+	
+	if ( until > 0 && until > from )
+	{
+		for ( int i = m_lines.count() - 1; i >= until; --i )
+		{
+			QDocumentLineHandle *h = m_lines.at(i);
+			
+			QHash<QDocumentLineHandle*, QList<int> >::const_iterator it = m_marks.constFind(h);
+			
+			if ( it != e && it->contains(id) )
+				return i;
+				
+		}
+	}
+	
+	return -1;
+}
+
+void QDocumentPrivate::execute(QDocumentCommand *cmd)
+{
+	if ( !cmd )
+		return;
+	
+	m_lastModified = QDateTime::currentDateTime();
+	
+	//qDebug("adding a command...");
+	
+	//cmd->setTarget(m_doc);
+	
+	m_commands.push(cmd);
+}
+
+void QDocumentPrivate::draw(QPainter *p, QDocument::PaintContext& cxt)
+{
+	QDocumentLineHandle *h;
+	bool inSel = false, fullSel;
+	QList<QDocumentCursorHandle*>::iterator cit;
+	int i, realln, pos = 0, xOffset,
+		firstLine = qMax(0, cxt.yoffset / m_lineSpacing),
+		lastLine = qMax(0, firstLine + (cxt.height / m_lineSpacing));
+		
+	if ( cxt.height % m_lineSpacing )
+		++lastLine;
+		
+	p->setFont(*m_font);
+	
+	QBrush bg,
+		base = cxt.palette.base(),
+		selbg = cxt.palette.highlight(),
+		alternate = QLineMarksInfoCenter::instance()->markType("current").color;
+		
+	if ( !alternate.color().isValid() )
+		alternate = cxt.palette.alternateBase();
+		
+	QSmallArray m_cursorLines(0), m_selectionBoundaries(0);
+	
+	int wrap = 0;
+	i = textLine(firstLine, &wrap);
+	firstLine -= wrap;
+	realln = firstLine;
+	
+	//qDebug("lines [%i, %i]", firstLine, lastLine);
+	
+	pos += firstLine * m_lineSpacing;
+	
+	// adjust first line to take selections into account...
+	foreach ( const QDocumentSelection& s, cxt.selections )
+	{
+		if ( (s.startLine < i) && (s.endLine >= i) )
+		{
+			inSel = true;
+			break;
+		}
+	}
+	
+	for ( ; realln <= lastLine; ++i )
+	{
+		if ( i >= m_lines.count() )
+		{
+			//qDebug("line %i not valid", i);
+			break;
+		}
+		
+		h = m_lines.at(i);
+		
+		// ugly workaround...
+		if( !m_fixedPitch )
+			adjustWidth(i);
+		
+		const int wrap = h->m_frontiers.count();
+		const bool wrapped = wrap;
+		
+		//if ( wrapped )
+		//	qDebug("line %i is wrapped over %i sublines", i, *wit);
+		
+		// selections stuff (must do it before whatever the visibility...)
+		m_selectionBoundaries.clear();
+		
+		fullSel = false;
+		
+		if ( inSel )
+			m_selectionBoundaries.prepend(0);
+			
+		foreach ( const QDocumentSelection& s, cxt.selections )
+		{
+			if ( i == s.startLine )
+			{
+				if ( !(m_selectionBoundaries.count() & 1) )
+					m_selectionBoundaries.append(s.start);
+					
+				if ( i == s.endLine )
+				{
+					m_selectionBoundaries.append(s.end);
+				} else {
+					//++selLevel;
+					inSel = true;
+					//selEnd = h->m_text.length();
+				}
+			} else if ( inSel && (i == s.endLine) ) {
+				
+				if ( m_selectionBoundaries.count() % 2 )
+					m_selectionBoundaries.append(s.end);
+					
+				//--selLevel;
+				inSel = false;
+			}
+		}
+		
+		if ( inSel && m_selectionBoundaries.count() == 1 && m_selectionBoundaries.at(0) == 0 )
+		{
+			m_selectionBoundaries.clear();
+			fullSel = true;
+		}
+		
+		if ( h->hasFlag(QDocumentLine::Hidden) )
+		{
+			continue;
+		} else
+			++realln;
+			
+		if ( wrapped )
+			realln += wrap;
+			
+		m_cursorLines.clear();
+		
+		bg = base;
+		
+		// idx = column = 0;
+		xOffset = m_leftMargin; // margin
+		
+		// cursor(s) stuff
+		cit = cxt.cursors.begin();
+		
+		while ( cit != cxt.cursors.end() )
+		{
+			if ( (*cit)->lineNumber() == i )
+			{
+				if ( cxt.blinkingCursor )
+					m_cursorLines.append((*cit)->columnNumber());
+				
+				if ( cxt.fillCursorRect )
+					bg = alternate;
+					
+				cit = cxt.cursors.erase(cit);
+			} else {
+				++cit;
+			}
+		}
+		
+		cit = cxt.extra.begin();
+		
+		while ( cit != cxt.extra.end() )
+		{
+			if ( (*cit)->lineNumber() == i )
+			{
+				m_cursorLines.append((*cit)->columnNumber());
+				
+				cit = cxt.extra.erase(cit);
+			} else {
+				++cit;
+			}
+		}
+		
+		qSort(m_cursorLines);
+		
+		QList<int> m = marks(h);
+		
+		// line marks stuff
+		if ( m.count() )
+		{
+			QLineMarksInfoCenter *mic = QLineMarksInfoCenter::instance();
+			
+			QColor c = mic->markType(mic->priority(m)).color;
+			
+			if ( c.isValid() )
+				bg = c;
+				
+		}
+		
+		if ( realln < firstLine )
+			continue;
+			
+		//qDebug("drawing line %i (visual %i)", i, realln);
+		
+		p->fillRect(qMax(cxt.xoffset, m_leftMargin), pos,
+					cxt.width, m_lineSpacing,
+					fullSel ? selbg : bg);
+					
+		if ( wrapped )
+			p->fillRect(qMax(cxt.xoffset, m_leftMargin), pos + m_lineSpacing,
+						cxt.width, m_lineSpacing * wrap, fullSel ? selbg : bg);
+						
+		//p->fillRect(cxt.xoffset, pos + 1,
+		//			cxt.width, m_lineHeight,
+		//			bg);
+		
+		p->save();
+		
+		// simplify line drawing
+		p->translate(0, pos);
+		
+		// draw text
+		h->draw(p, cxt.xoffset, cxt.width, m_selectionBoundaries, m_cursorLines, cxt.palette, fullSel);
+		
+		// see above
+		p->translate(0, -pos);
+		
+		// draw fold rect indicator
+		if ( h->hasFlag(QDocumentLine::CollapsedBlockStart) )
+		{
+			p->setBrush(Qt::NoBrush);
+			p->setPen(QPen(Qt::blue, 1, Qt::DotLine));
+			
+			//p->drawRect(cxt.xoffset + 2, pos,
+			//			cxt.width - 4, m_lineSpacing - 1);
+			
+			p->drawRect(m_leftMargin, pos,
+						cxt.width - 4, m_lineSpacing * (wrap + 1) - 1);
+						
+		}
+		
+		p->restore();
+		
+		pos += m_lineSpacing;
+		
+		if ( wrapped )
+		{
+			pos += m_lineSpacing * wrap;
+		}
+		
+		//qDebug("drawing line %i in %i ms", i, t.elapsed());
+	}
+	
+	//qDebug("painting done"); // in %i ms...", t.elapsed());
+}
+
+int QDocumentPrivate::position(const QDocumentLineHandle *l) const
+{
+	int pos = 0;
+	
+	int idx = m_lines.indexOf(const_cast<QDocumentLineHandle*>(l));
+	
+	if ( idx == -1 )
+		return -1;
+		
+	for ( int i = 0; i < idx; i++ )
+		pos += m_lines.at(i)->length();
+		
+	return pos;
+}
+
+QDocumentLineHandle* QDocumentPrivate::lineForPosition(int& position) const
+{
+	int pos = 0, idx = 0;
+	
+	while ( (pos + m_lines.at(idx)->length()) < position )
+		pos += m_lines.at(idx++)->length();
+		
+	
+	return 0;
+}
+
+void QDocumentPrivate::setWidth(int width)
+{
+	int oldConstraint = m_constrained;
+	m_constrained = width > 0;
+	
+	if ( m_constrained )
+	{
+		int oldWidth = m_width;
+		
+		m_width = width;
+		
+		if ( oldConstraint && oldWidth < width )
+		{
+			// expand : simply remove old wraps if possible
+			
+			QMap<int, int>::iterator it = m_wrapped.begin();
+			
+			while ( it != m_wrapped.end() )
+			{
+				QDocumentLineHandle *h = it.key() < m_lines.count() ? m_lines.at(it.key()) : 0;
+				
+				if ( h )
+					h->updateWrap();
+				
+				int sz = h ? h->m_frontiers.count() : 0;
+				
+				if ( sz )
+				{
+					//qDebug("changing wrap at line %i from %i to %i", it.key(), *it, sz);
+					*it = sz;
+					++it;
+				} else {
+					//qDebug("removing wrap at line %i", it.key());
+					it = m_wrapped.erase(it);
+				}
+			}
+		} else if ( oldWidth > width ) {
+			// shrink : scan whole document and create new wraps wherever needed
+			//qDebug("global width scan [constraint on]");
+			//m_wrapped.clear();
+			setWidth();
+		}
+	} else {
+		//qDebug("global width scan [constraint off]");
+		m_wrapped.clear();
+		setWidth();
+	}
+	
+	if ( m_editCursor )
+	{
+		m_editCursor->refreshColumnMemory();
+	}
+	
+	emitWidthChanged();
+	setHeight();
+	
+	emitFormatsChanged();
+}
+
+void QDocumentPrivate::setWidth()
+{
+	m_largest.clear();
+	const int max = m_lines.count();
+	
+	if ( m_constrained )
+	{
+		int first = -1;
+		
+		for ( int i = 0; i < max; ++i )
+		{
+			QDocumentLineHandle *l = m_lines.at(i);
+			int olw = l->m_frontiers.count();
+			
+			l->updateWrap();
+			
+			int lw = l->m_frontiers.count();
+			
+			if ( olw == lw )
+				continue;
+				
+			if ( lw )
+			{
+				//qDebug("added wrap on line %i", line);
+				m_wrapped[i] = lw;
+			} else {
+				//qDebug("removed wrap on line %i", line);
+				m_wrapped.remove(i);
+			}
+			
+			if ( first != -1 )
+				first = i;
+		}
+		
+		if ( first != -1 )
+			emitFormatsChange(first, -1);
+	} else {
+		int oldWidth = m_width;
+		
+		m_width = 0;
+		
+		foreach ( QDocumentLineHandle *l, m_lines )
+		{
+			if ( l->hasFlag(QDocumentLine::Hidden) )
+				continue;
+				
+			l->m_frontiers.clear();
+			
+			int w = l->cursorToX(l->length());
+			
+			if ( w > m_width )
+			{
+				m_width = w;
+				
+				m_largest.clear();
+				m_largest << qMakePair(l, w);
+			}
+		}
+		
+		if ( m_width != oldWidth )
+			emitWidthChanged();
+	}
+}
+
+static const int widthCacheSize = 5;
+
+void QDocumentPrivate::adjustWidth(int line)
+{
+	if ( line < 0 || line >= m_lines.count() )
+		return;
+		
+	QDocumentLineHandle *l = m_lines.at(line);
+	
+	if ( m_constrained )
+	{
+		int olw = l->m_frontiers.count();
+		
+		l->updateWrap();
+		
+		int lw = l->m_frontiers.count();
+		
+		if ( olw == lw )
+			return;
+			
+		if ( l->m_layout )
+			l->setFlag(QDocumentLine::LayoutDirty);
+			
+		if ( lw )
+		{
+			//qDebug("added wrap on line %i", line);
+			m_wrapped[line] = lw;
+		} else {
+			//qDebug("removed wrap on line %i", line);
+			m_wrapped.remove(line);
+		}
+		
+		emitFormatsChange(line, -1);
+		setHeight();
+		
+	} else {
+		l->m_frontiers.clear();
+		
+		int w = l->cursorToX(l->length());
+		
+		if ( w > m_width )
+		{
+			m_width = w;
+			emitWidthChanged();
+			
+			m_largest.clear();
+			m_largest << qMakePair(l, w);
+		} else if ( m_largest.count() && (m_largest.at(0).first == l) ) {
+			int old = m_largest.at(0).second;
+			
+			if ( w < old )
+				setWidth();
+		}
+	}
+}
+
+void QDocumentPrivate::setHeight()
+{
+	int oldHeight = m_height;
+	int last = visualLine(m_lines.count() - 1) + 1;
+	
+	if ( m_lines.count() )
+		last += m_lines.last()->m_frontiers.count();
+		
+	m_height = last * m_lineSpacing;
+	
+	if ( oldHeight != m_height )
+		emitHeightChanged();
+}
+
+void QDocumentPrivate::setFont(const QFont& f)
+{
+	if ( !m_font )
+	{
+		m_font = new QFont;
+		m_fontMetrics = new QFontMetrics(*m_font);
+	}
+	
+	*m_font = f;
+	
+	// ensures the font is fixed pitch to avoid idsplay glitches
+	// and inconsistency of column selections
+	// :( does not work well...
+	//m_font->setFixedPitch(true);
+	
+	// set the styling so that if the font is not found Courier one will be used
+	m_font->setStyleHint(QFont::Courier, QFont::PreferQuality);
+	
+	*m_fontMetrics = QFontMetrics(*m_font);
+	
+	m_spaceWidth = m_fontMetrics->width(' ');
+	m_lineSpacing = m_fontMetrics->lineSpacing();
+	m_ascent = m_fontMetrics->ascent();
+	m_descent = m_fontMetrics->descent();
+	m_leading = m_fontMetrics->leading();
+	
+	m_lineHeight = m_fontMetrics->height();
+	//m_lineHeight = m_ascent + m_descent - 2;
+	
+	m_fixedPitch = QFontInfo(*m_font).fixedPitch();
+	
+	//if ( !m_fixedPitch )
+	//	qDebug("unsafe computations...");
+	
+	foreach ( QDocumentPrivate *d, m_documents )
+	{
+		d->updateFormatCache();
+		d->setWidth();
+		d->setHeight();
+	}
+}
+
+void QDocumentPrivate::setFormatScheme(QFormatScheme *f)
+{
+	m_formatScheme = f;
+	updateFormatCache();
+}
+
+void QDocumentPrivate::tunePainter(QPainter *p, int fid)
+{
+	if ( fid < m_fonts.count() )
+	{
+		p->setFont(m_fonts.at(fid));
+		//p->setPen(m_colors.at(fid));
+	} else {
+		p->setFont(*m_font);
+		//p->setPen(Qt::black);
+	}
+}
+
+void QDocumentPrivate::updateFormatCache()
+{
+	m_fonts.clear();
+	
+	if ( !m_font )
+		return;
+	
+	if ( !m_formatScheme )
+	{
+		m_fonts << *m_font;
+		return;
+	}
+	
+	QFont f(*m_font);
+	const int end = m_formatScheme->formatCount();
+	
+	m_fonts.reserve(end);
+	
+	for ( int i = 0; i < end; i++ )
+	{
+		QFormat fmt = m_formatScheme->format(i);
+		
+		f.setWeight(fmt.weight);
+		f.setItalic(fmt.italic);
+		
+		m_fonts << f;
+	}
+	
+	//foreach ( QDocumentPrivate *d, m_documents )
+	//	d->emitFormatsChanged();
+	
+	emitFormatsChanged();
+}
+
+void QDocumentPrivate::emitWidthChanged()
+{
+	if ( !m_doc )
+		return;
+		
+	emit m_doc->widthChanged(m_width);
+	
+	emit m_doc->sizeChanged(QSize(m_width, m_height));
+}
+
+void QDocumentPrivate::emitHeightChanged()
+{
+	if ( !m_doc )
+		return;
+		
+	emit m_doc->heightChanged(m_height);
+	
+	emit m_doc->sizeChanged(QSize(m_width, m_height));
+}
+
+void QDocumentPrivate::insertLines(int after, const QList<QDocumentLineHandle*>& l)
+{
+	//qDebug("inserting : %i, %i", after, l.count());
+	
+	int i = 0;
+	
+	foreach ( QDocumentLineHandle *h, l )
+	{
+		h->setFlag(QDocumentLine::Hidden, false);
+		h->setFlag(QDocumentLine::CollapsedBlockStart, false);
+		h->setFlag(QDocumentLine::CollapsedBlockEnd, false);
+		h->m_frontiers.clear();
+	}
+	
+	QMap<int, int>::iterator it = m_hidden.begin();
+	
+	while ( it != m_hidden.end() )
+	{
+		if ( (it.key() <= after) && ((it.key() + *it) > after) )
+		{
+			*it += l.count();
+			
+			foreach ( QDocumentLineHandle *h, l )
+				h->setFlag(QDocumentLine::Hidden, true);
+		}
+		
+		++it;
+	}
+	
+	++after;
+	updateHidden(after, l.count());
+	updateWrapped(after, l.count());
+	
+	while ( i < l.count() )
+	{
+		// TODO : move (and abstract somehow) inside the line (handle?)
+		l.at(i)->m_context.reset();
+		
+		m_lines.insert(after + i, l.at(i));
+		
+		adjustWidth(after + i);
+		
+		++i;
+	}
+	
+	emit m_doc->lineCountChanged(m_lines.count());
+	setHeight();
+}
+
+void QDocumentPrivate::removeLines(int after, int n)
+{
+	if ( (after >= 0) && (after < m_lines.count()) )
+		m_lines.at(after)->setFlag(QDocumentLine::CollapsedBlockStart, false);
+		
+	QMap<int, int>::iterator it = m_hidden.begin();
+	
+	//qDebug("translating %i", visualLine);
+	
+	while ( it != m_hidden.end() )
+	{
+		if ( (it.key() >= after) && (it.key() < (after + n)) )
+		{
+			int i = it.key(), end = i + *it, depth = 0;
+			
+			while ( i <= end )
+			{
+				if ( !depth )
+					m_lines.at(i)->setFlag(QDocumentLine::Hidden, false);
+					
+				if ( m_lines.at(i)->hasFlag(QDocumentLine::CollapsedBlockStart) )
+					++depth;
+				else if ( m_lines.at(i)->hasFlag(QDocumentLine::CollapsedBlockEnd) )
+					--depth;
+					
+				++i;
+			}
+			
+			it = m_hidden.erase(it);
+			
+		} else if ( (it.key() < after) && (it.key() + *it) >= after ) {
+			
+			if ( (it.key() + *it) > (after + n) )
+			{
+				// fully inside
+				*it -= n;
+				++it;
+			} else {
+				// goes beyond...
+				int i = it.key(), end = i + *it, depth = 0;
+				
+				while ( i <= end )
+				{
+					if ( !depth )
+						m_lines.at(i)->setFlag(QDocumentLine::Hidden, false);
+						
+					if ( m_lines.at(i)->hasFlag(QDocumentLine::CollapsedBlockStart) )
+						++depth;
+					else if ( m_lines.at(i)->hasFlag(QDocumentLine::CollapsedBlockEnd) )
+						--depth;
+						
+					++i;
+				}
+				
+				it = m_hidden.erase(it);
+			}
+		} else {
+			++it;
+		}
+	}
+	
+	it = m_wrapped.begin();
+	
+	while ( it != m_wrapped.end() )
+	{
+		if ( (it.key() > after) && (it.key() <= (after + n)) )
+		{
+			//qDebug("eraser %i", it.key());
+			it = m_wrapped.erase(it);
+		} else {
+			++it;
+		}
+	}
+	
+	++after;
+	updateHidden(after, -n);
+	updateWrapped(after, -n);
+	m_lines.remove(after, n);
+	
+	emit m_doc->lineCountChanged(m_lines.count());
+	setHeight();
+}
+
+QDocumentLineHandle* QDocumentPrivate::at(int line) const
+{
+	return ((line >= 0) && (line < m_lines.count())) ? m_lines.at(line) : 0;
+}
+
+int QDocumentPrivate::indexOf(const QDocumentLineHandle *l) const
+{
+	return m_lines.indexOf(const_cast<QDocumentLineHandle*>(l));
+}
+
+QDocumentIterator QDocumentPrivate::index(const QDocumentLineHandle *l)
+{
+	QDocumentIterator i = m_lines.begin();
+	
+	int idx = indexOf(l);
+	
+	return (idx != -1) ? i + idx : m_lines.end();
+}
+
+QDocumentConstIterator QDocumentPrivate::index(const QDocumentLineHandle *l) const
+{
+	QDocumentConstIterator i = m_lines.constBegin();
+	
+	int idx = indexOf(l);
+	
+	return (idx != -1) ? i + idx : m_lines.end();
+}
+
+QDocumentLineHandle* QDocumentPrivate::next(const QDocumentLineHandle *l) const
+{
+	if ( !l )
+		return m_lines.count() ? m_lines.first() : 0;
+		
+	int idx = m_lines.indexOf(const_cast<QDocumentLineHandle*>(l));
+	
+	return ((idx != -1) && ((idx + 1) < m_lines.count())) ? m_lines.at(idx + 1) : 0;
+}
+
+QDocumentLineHandle* QDocumentPrivate::previous(const QDocumentLineHandle *l) const
+{
+	if ( !l )
+		return m_lines.count() ? m_lines.last() : 0;
+		
+	int idx = m_lines.indexOf(const_cast<QDocumentLineHandle*>(l));
+	
+	return ((idx != -1) && (idx > 0)) ? m_lines.at(idx - 1) : 0;
+}
+
+void QDocumentPrivate::beginChangeBlock()
+{
+	//qDebug("<macro>");
+	m_commands.beginMacro(QString());
+}
+
+void QDocumentPrivate::endChangeBlock()
+{
+	m_commands.endMacro();
+	//qDebug("</macro>");
+}
+
+/*!
+	\brief Acquire group id
+*/
+int QDocumentPrivate::getNextGroupId()
+{
+	if ( m_freeGroupIds.count() )
+		return m_freeGroupIds.takeFirst();
+	
+	return ++m_lastGroupId;
+}
+
+/*!
+	\brief Relase group id
+*/
+void QDocumentPrivate::releaseGroupId(int groupId)
+{
+	if ( groupId == m_lastGroupId )
+	{
+		--m_lastGroupId;
+		while ( m_freeGroupIds.removeAll(m_lastGroupId) )
+		{
+			--m_lastGroupId;
+		}
+	} else {
+		m_freeGroupIds << groupId;
+	}
+}
+
+/*!
+	\brief Clear matches
+*/
+void QDocumentPrivate::clearMatches(int groupId)
+{
+	QHash<int, MatchList>::iterator mit = m_matches.find(groupId);
+	
+	if ( mit == m_matches.end() )
+	{
+		return;
+	}
+	
+	MatchList& matches = *mit;
+	
+	foreach ( const Match& m, matches )
+	{
+		m.h->removeOverlay(m.range);
+	}
+	
+	matches.index = matches.count();
+}
+
+/*!
+	\brief Highlight the matched sequences
+	
+	\note Both position are BEFORE the matched characters (cursor position).
+*/
+void QDocumentPrivate::addMatch(int groupId, int line, int pos, int len, int format)
+{
+	//qDebug("match (%i, %i, %i)", line, pos, len);
+	
+	Match m;
+	m.line = line;
+	m.h = at(line);
+	m.range = QFormatRange(pos, len, format);
+	m_matches[groupId] << m;
+	
+	m.h->addOverlay(m.range);
+}
+
+void QDocumentPrivate::flushMatches(int groupId)
+{
+	QHash<int, MatchList>::iterator mit = m_matches.find(groupId);
+	
+	if ( mit == m_matches.end() )
+	{
+		return;
+	}
+	
+	MatchList& matches = *mit;
+	
+	QMap<int, int> areas;
+	
+	foreach ( const Match& m, matches )
+	{
+		int n = 1;
+		int l = m.line;
+		
+		//qDebug("simple:(%i, %i)", l, 1);
+		
+		QMap<int, int>::iterator tmp, it = areas.find(l);
+		
+		if ( it != areas.end() )
+			continue;
+			
+		it = areas.insert(m.line, n);
+		
+		if ( it != areas.end() && (it - 1) != areas.end() )
+		{
+			tmp = it - 1;
+			int off = tmp.key() + *tmp - l;
+			
+			if ( off >= 0 && (off < n) )
+			{
+				*tmp += n - off;
+				it = areas.erase(it) - 1;
+			}
+		}
+		
+		if ( it != areas.end() && (it + 1) != areas.end() )
+		{
+			tmp = it + 1;
+			int off = it.key() + *it - tmp.key();
+			
+			if ( off >= 0 && (off < *tmp) )
+			{
+				*it += *tmp;
+				areas.erase(tmp);
+			}
+		}
+		//emitFormatsChange(m.line, 1);
+	}
+	
+	// remove old matches
+	while ( matches.index )
+	{
+		matches.removeFirst();
+		--matches.index;
+	}
+	
+	// send update messages
+	QMap<int, int>::const_iterator it = areas.constBegin();
+	
+	while ( it != areas.constEnd() )
+	{
+		//qDebug("merged:(%i, %i)", it.key(), *it);
+		emitFormatsChange(it.key(), *it);
+		
+		++it;
+	}
+	
+	// update storage "meta-data"
+	if ( matches.isEmpty() )
+	{
+		m_matches.remove(groupId);
+		
+		releaseGroupId(groupId);
+	}
+	//qDebug("done with matches");
+}
+
+QList<int> QDocumentPrivate::marks(QDocumentLineHandle *h) const
+{
+	//return QList<int>() << 1; //testcase
+	
+	return m_marks.contains(h) ? m_marks.value(h) : QList<int>();
+}
+
+void QDocumentPrivate::addMark(QDocumentLineHandle *h, int mid)
+{
+	QList<int>& l = m_marks[h];
+	
+	l << mid;
+	
+	m_maxMarksPerLine = qMax(l.count(), m_maxMarksPerLine);
+	
+	emitMarkChanged(h, mid, true);
+}
+
+void QDocumentPrivate::toggleMark(QDocumentLineHandle *h, int mid)
+{
+	if ( m_marks.value(h).contains(mid) )
+	{
+		removeMark(h, mid);
+	} else {
+		addMark(h, mid);
+	}
+}
+
+void QDocumentPrivate::removeMark(QDocumentLineHandle *h, int mid)
+{
+	QHash<QDocumentLineHandle*, QList<int> >::iterator it = m_marks.find(h);
+	
+	if ( it == m_marks.end() )
+		return;
+		
+	int count = it->count();
+	int n = it->removeAll(mid);
+	
+	if ( it->isEmpty() )
+		m_marks.erase(it);
+		
+	if ( n && (count == m_maxMarksPerLine) )
+	{
+		QHash<QDocumentLineHandle*, QList<int> >::const_iterator
+			rit = m_marks.constBegin(),
+			end = m_marks.constEnd();
+			
+		m_maxMarksPerLine = 0;
+		
+		while ( rit != end )
+		{
+			m_maxMarksPerLine = qMax(rit->count(), m_maxMarksPerLine);
+			++rit;
+		}
+	}
+	
+	emitMarkChanged(h, mid, false);
+}
+
+int QDocumentPrivate::visualLine(int textLine) const
+{
+	if ( textLine < 0 )
+		return 0;
+		
+	int hiddenLines = 0, wrappedLines = 0;
+	QMap<int, int>::const_iterator hit, wit, he, we;
+	hit = m_hidden.constBegin();
+	wit = m_wrapped.constBegin();
+	he = m_hidden.constEnd();
+	we = m_wrapped.constEnd();
+	
+	//qDebug("translating %i", visualLine);
+	
+	while ( hit != he || wit != we )
+	{
+		if ( hit != he && (wit == we || hit.key() <= wit.key()) )
+		{
+			int hl = hit.key();
+			
+			if ( hl >= textLine )
+				break;
+			
+			int max = 0;
+			
+			do
+			{
+				max = qMax(max, hit.key() - hl + *hit);
+				++hit;
+			} while ( (hit != he) && (hit.key() <= hl + max) );
+			
+			hiddenLines += max;
+			
+			if ( wit != we && wit.key() == hl )
+			{
+				wrappedLines += *wit;
+				++wit;
+			}
+			
+			while ( wit != we )
+			{
+				if ( wit.key() > hl + max )
+					break;
+				
+				++wit;
+			}
+			
+		} else {
+			if ( wit.key() >= textLine )
+				break;
+			
+			if ( m_lines.at(wit.key())->hasFlag(QDocumentLine::Hidden) )
+			{
+				++wit;
+				continue;
+			}
+			
+			wrappedLines += *wit;
+			++wit;
+		}
+	}
+	
+	//qDebug("translating %i => %i", textLine, textLine - hiddenLines + wrappedLines);
+	
+	return textLine - hiddenLines + wrappedLines;
+}
+
+int QDocumentPrivate::textLine(int visualLine, int *wrap) const
+{
+	if ( visualLine < 0 )
+		return 0;
+		
+	int hiddenLines = 0, wrappedLines = 0, vis = 0, txt = 0, mess = 0;
+	QMap<int, int>::const_iterator
+		h = m_hidden.constBegin(),
+		w = m_wrapped.constBegin(),
+		he = m_hidden.constEnd(),
+		we = m_wrapped.constEnd();
+		
+	//qDebug("translating %i", visualLine);
+	
+	while ( vis < visualLine )
+	{
+		if ( h != he )
+		{
+			int hl = h.key();
+			
+			if ( w == we || hl <= w.key() )
+			{
+				if ( visualLine + mess <= hl )
+					break;
+				
+				if ( w != we && w.key() == hl )
+				{
+					//qDebug("trying to solve : h=(%i, %i), w=(%i, %i)", hl, *h, w.key(), *w);
+					const int off = (visualLine + mess) - hl;
+					if ( off <= *w )
+					{
+						//qDebug("%i -> %i + %i", visualLine, hl, off);
+						if ( wrap )
+							*wrap = off;
+						
+						return hl;
+					}
+				}
+				
+				int max = 0;
+				
+				do
+				{
+					max = qMax(max, h.key() - hl + *h);
+					++h;
+				} while ( (h != he) && (h.key() <= hl + max) );
+				
+				// very important : do not forget possible wrapping on folded block start
+				if ( w != we && w.key() == hl )
+				{
+					wrappedLines += *w;
+					++w;
+				}
+				
+				while ( w != we )
+				{
+					if ( w.key() > txt + max )
+						break;
+					
+					++w;
+				}
+				
+				hiddenLines += max;
+				
+			} else {
+				txt = w.key();
+				
+				if ( m_lines.at(txt)->hasFlag(QDocumentLine::Hidden) )
+				{
+					++w;
+					continue;
+				}
+				
+				if ( visualLine + mess < txt )
+					break;
+				
+				wrappedLines += *w;
+				++w;
+			}
+		} else if ( w != we ) {
+			txt = w.key();
+			
+			if ( m_lines.at(txt)->hasFlag(QDocumentLine::Hidden) )
+			{
+				++w;
+				continue;
+			}
+			
+			if ( visualLine + mess < txt )
+				break;
+			
+			wrappedLines += *w;
+			++w;
+		} else {
+			break;
+		}
+		
+		mess = hiddenLines - wrappedLines;
+		vis = txt - mess;
+	}
+	
+	we = m_wrapped.constBegin();
+	
+	if ( m_wrapped.count() && w != we )
+	{
+		--w;
+		
+		int wl = w.key();
+		bool hwrap = m_lines.at(wl)->hasFlag(QDocumentLine::Hidden);
+		
+		if ( !hwrap )
+		{
+			int base = this->visualLine(wl);
+			
+			if ( visualLine >= base && visualLine <= base + *w )
+			{
+				//qDebug("rebased : %i to %i", visualLine, base);
+				
+				if ( wrap )
+					*wrap = visualLine - base;
+				
+				return wl;
+			}
+		}
+	}
+	
+	//qDebug("[visual:text] : %i : %i", visualLine, visualLine + mess);
+	int off = visualLine + mess - (m_lines.count() - 1);
+	
+	if ( off > 0 )
+	{
+		if ( wrap )
+			*wrap = m_lines.last()->m_frontiers.count();
+		
+		return m_lines.count() - 1;
+	}
+	
+	return visualLine + mess;
+}
+
+void QDocumentPrivate::hideEvent(int line, int count)
+{
+	m_hidden.insertMulti(line, count);
+	
+	setHeight();
+	//emitFormatsChange(line, count);
+	emitFormatsChanged();
+}
+
+void QDocumentPrivate::showEvent(int line, int count)
+{
+	QMap<int, int>::iterator it = m_hidden.find(line);
+	
+	while ( (it != m_hidden.end()) && (it.key() == line)  )
+	{
+		if ( *it == count )
+		{
+//			qDebug("showing %i lines from %i", count, line);
+			it = m_hidden.erase(it);
+		} else
+			++it;
+	}
+	
+	setHeight();
+	//emitFormatsChange(line, count);
+	emitFormatsChanged();
+}
+
+void QDocumentPrivate::updateHidden(int line, int count)
+{
+	if ( m_hidden.isEmpty() || (line > (m_hidden.constEnd() - 1).key() ) )
+		return;
+	
+	QMap<int, int> prev = m_hidden;
+	m_hidden.clear();
+	
+	QMap<int, int>::const_iterator it = prev.constBegin();
+	
+	//qDebug("shifting by %i from %i", count, line);
+	
+	while ( it != prev.constEnd() )
+	{
+		if ( it.key() < line )
+		{
+			m_hidden.insertMulti(it.key(), *it);
+		} else {
+			m_hidden.insertMulti(it.key() + count, *it);
+		}
+		
+		++it;
+	}
+}
+
+void QDocumentPrivate::updateWrapped(int line, int count)
+{
+	if ( m_wrapped.isEmpty() || (line > (m_wrapped.constEnd() - 1).key() ) )
+		return;
+		
+	QMap<int, int> prev = m_wrapped;
+	QMap<int, int>::iterator it = prev.begin();
+	
+	m_wrapped.clear();
+	
+	//qDebug("shifting by %i from %i", count, line);
+	
+	while ( it != prev.end() )
+	{
+		if ( it.key() < line )
+		{
+			m_wrapped.insert(it.key(), *it);
+		} else {
+			//qDebug("moved wrap from line %i to line %i", it.key(), it.key() + count);
+			m_wrapped.insert(it.key() + count, *it);
+		}
+		
+		++it;
+	}
+}
+
+void QDocumentPrivate::emitFormatsChange(int line, int lines)
+{
+	emit m_doc->formatsChange(line, lines);
+}
+
+void QDocumentPrivate::emitContentsChange(int line, int lines)
+{
+	//for ( int i = line; i < (line + lines); i++ )
+	//	m_lines.at(i)->cache();
+	
+	int n = lines;
+	
+	if ( m_language )
+	{
+		n = m_language->tokenize(m_doc, line, lines);
+	}
+	//qDebug("%i, %i : %i", line, lines, n);
+	
+	emit m_doc->contentsChange(line, lines);
+	emit m_doc->contentsChanged();
+	
+	if ( n > lines )
+		emitFormatsChange(line + lines, n - lines);
+}
+
+void QDocumentPrivate::emitFormatsChanged()
+{
+	emit m_doc->formatsChanged();
+}
+
+void QDocumentPrivate::emitContentsChanged()
+{
+	//emit m_doc->contentsChanged();
+}
+
+void QDocumentPrivate::emitLineDeleted(QDocumentLineHandle *h)
+{
+	if ( !m_deleting )
+	{
+		m_marks.remove(h);
+		
+		int idx = m_lines.indexOf(h);
+		
+		if ( idx != -1 )
+		{
+			//qDebug("removing line %i", idx);
+			
+			m_lines.remove(idx);
+			
+			if ( m_largest.count() && (m_largest.at(0).first == h) )
+			{
+				m_largest.remove(0);
+				setWidth();
+			}
+			
+			m_hidden.remove(idx);
+			m_wrapped.remove(idx);
+			
+			setHeight();
+		}
+	}
+	
+	emit m_doc->lineDeleted(h);
+}
+
+void QDocumentPrivate::emitMarkChanged(QDocumentLineHandle *l, int m, bool on)
+{
+	emitFormatsChanged();
+	emit m_doc->markChanged(l, m, on);
+}
+
+/*! @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocument.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,273 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QDOCUMENT_H_
+#define _QDOCUMENT_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qdocument.h
+	\brief Definition of the QDocument class
+	
+	\defgroup document Document related classes 
+*/
+
+#include <QList>
+#include <QVector>
+#include <QLinkedList>
+
+#include <QObject>
+#include <QPalette>
+#include <QMetaType>
+
+class QFont;
+class QRect;
+class QPrinter;
+class QDateTime;
+class QFormatScheme;
+class QLanguageDefinition;
+
+struct QCE_EXPORT QDocumentSelection
+{
+	int start, end;
+	int startLine, endLine;
+};
+
+class QDocumentLine;
+class QDocumentCursor;
+class QDocumentPrivate;
+class QDocumentCommand;
+class QDocumentLineHandle;
+class QDocumentCursorHandle;
+
+typedef QVector<QDocumentLineHandle*>::iterator QDocumentIterator;
+typedef QVector<QDocumentLineHandle*>::const_iterator QDocumentConstIterator;
+
+Q_DECLARE_METATYPE(QDocumentIterator)
+Q_DECLARE_METATYPE(QDocumentConstIterator)
+
+class QCE_EXPORT QDocument : public QObject
+{
+	friend class QMatcher;
+	friend class QDocumentPrivate;
+	friend class QDocumentCommand;
+	
+	Q_OBJECT
+	
+	public:
+		struct PaintContext
+		{
+			int width;
+			int height;
+			int xoffset;
+			int yoffset;
+			QPalette palette;
+			bool blinkingCursor;
+			bool fillCursorRect;
+			QList<QDocumentCursorHandle*> extra;
+			QList<QDocumentCursorHandle*> cursors;
+			QList<QDocumentSelection> selections;
+		};
+		
+		enum LineEnding
+		{
+			Conservative,
+			Local,
+			Unix,
+			Windows,
+			Mac,			// backward compat only : use OldMac instead (more self-explanatory)
+			OldMac = Mac
+		};
+		
+		enum TextProcessing
+		{
+			RemoveTrailingWS		= 1,
+			PreserveIndent			= 2,
+			RestoreTrailingIndent	= 4
+		};
+		
+		enum WhiteSpaceFlag
+		{
+			ShowNone		= 0x00,
+			ShowTrailing	= 0x01,
+			ShowLeading		= 0x02,
+			ShowTabs		= 0x04
+		};
+		
+		Q_DECLARE_FLAGS(WhiteSpaceMode, WhiteSpaceFlag)
+		
+		explicit QDocument(QObject *p = 0);
+		virtual ~QDocument();
+		
+		QString text(int mode) const;
+		QString text(bool removeTrailing = false, bool preserveIndent = true) const;
+		void setText(const QString& s);
+		
+		void startChunkLoading();
+		void stopChunkLoading();
+		void addChunk(const QString& txt);
+		
+		LineEnding lineEnding() const;
+		LineEnding originalLineEnding() const;
+		void setLineEnding(LineEnding le);
+		
+		QDateTime lastModified() const;
+		void setLastModified(const QDateTime& d);
+		
+		bool canUndo() const;
+		bool canRedo() const;
+		
+		int width() const;
+		int height() const;
+		int widthConstraint() const;
+		
+		int lines() const;
+		int lineCount() const;
+		int visualLines() const;
+		int visualLineCount() const;
+		
+		int visualLineNumber(int textLineNumber) const;
+		int textLineNumber(int visualLineNumber) const;
+		
+		int y(int line) const;
+		int lineNumber(int ypos, int *wrap = 0) const;
+		int y(const QDocumentLine& l) const;
+		
+		QRect lineRect(int line) const;
+		QRect lineRect(const QDocumentLine& l) const;
+		
+		QDocumentCursor* editCursor() const;
+		void setEditCursor(QDocumentCursor *c);
+		
+		QLanguageDefinition* languageDefinition() const;
+		void setLanguageDefinition(QLanguageDefinition *l);
+		
+		int maxMarksPerLine() const;
+		int findNextMark(int id, int from = 0, int until = -1) const;
+		int findPreviousMark(int id, int from = -1, int until = 0) const;
+		
+		QDocumentLine lineAt(const QPoint& p) const;
+		void cursorForDocumentPosition(const QPoint& p, int& line, int& column) const;
+		QDocumentCursor cursorAt(const QPoint& p) const;
+		
+		QDocumentLine line(int line) const;
+		QDocumentLine line(QDocumentConstIterator iterator) const;
+		
+		QDocumentCursor cursor(int line, int column = 0) const;
+		
+		QDocumentLine findLine(int& position) const;
+		
+		bool isLineModified(const QDocumentLine& l) const;
+		bool hasLineEverBeenModified(const QDocumentLine& l) const;
+		
+		virtual void draw(QPainter *p, PaintContext& cxt);
+		
+		void execute(QDocumentCommand *cmd);
+		
+		inline QDocumentPrivate* impl() { return m_impl; }
+		
+		QDocumentConstIterator begin() const;
+		QDocumentConstIterator end() const;
+		
+		QDocumentConstIterator iterator(int ln) const;
+		QDocumentConstIterator iterator(const QDocumentLine& l) const;
+		
+		void beginMacro();
+		void endMacro();
+		
+		QFormatScheme* formatScheme() const;
+		void setFormatScheme(QFormatScheme *f);
+		
+		int getNextGroupId();
+		void releaseGroupId(int groupId);
+		void clearMatches(int groupId);
+		void flushMatches(int groupId);
+		void addMatch(int groupId, int line, int pos, int len, int format);
+		
+		static QFont font();
+		static void setFont(const QFont& f);
+		static const QFontMetrics& fontMetrics();
+		
+		static LineEnding defaultLineEnding();
+		static void setDefaultLineEnding(LineEnding le);
+		
+		static int tabStop();
+		static void setTabStop(int n);
+		
+		static WhiteSpaceMode showSpaces();
+		static void setShowSpaces(WhiteSpaceMode y);
+		
+		static QFormatScheme* defaultFormatScheme();
+		static void setDefaultFormatScheme(QFormatScheme *f);
+		
+		static QFormatScheme* formatFactory();
+		static void setFormatFactory(QFormatScheme *f);
+		
+		static int screenLength(const QChar *d, int l, int tabStop);
+		static QString screenable(const QChar *d, int l, int tabStop);
+		
+		inline void markViewDirty() { formatsChanged(); }
+		
+		bool isClean() const;
+		
+	public slots:
+		void clear();
+		
+		void undo();
+		void redo();
+		
+		void setClean();
+		
+		void highlight();
+		
+		void print(QPrinter *p);
+		
+		void clearWidthConstraint();
+		void setWidthConstraint(int width);
+		
+	signals:
+		void cleanChanged(bool m);
+		
+		void undoAvailable(bool y);
+		void redoAvailable(bool y);
+		
+		void formatsChanged();
+		void contentsChanged();
+		
+		void formatsChange (int line, int lines);
+		void contentsChange(int line, int lines);
+		
+		void widthChanged(int width);
+		void heightChanged(int height);
+		void sizeChanged(const QSize& s);
+		
+		void lineCountChanged(int n);
+		void visualLineCountChanged(int n);
+		
+		void lineDeleted(QDocumentLineHandle *h);
+		void markChanged(QDocumentLineHandle *l, int m, bool on);
+		
+		void lineEndingChanged(int lineEnding);
+		
+	private:
+		QString m_leftOver;
+		QDocumentPrivate *m_impl;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDocument::WhiteSpaceMode)
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocument_p.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,224 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QDOCUMENT_P_H_
+#define _QDOCUMENT_P_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qdocument_p.h
+	\brief Definition of the private document API
+*/
+
+#include "qdocument.h"
+#include "qdocumentline.h"
+#include "qdocumentcursor.h"
+
+#include <QHash>
+#include <QFont>
+#include <QStack>
+#include <QQueue>
+#include <QDateTime>
+#include <QUndoStack>
+#include <QStringList>
+#include <QFontMetrics>
+#include <QUndoCommand>
+
+class QDocument;
+class QDocumentBuffer;
+class QDocumentPrivate;
+class QDocumentCommand;
+class QDocumentCommandBlock;
+
+class QLanguageDefinition;
+
+Q_DECLARE_TYPEINFO(QDocumentSelection, Q_PRIMITIVE_TYPE);
+
+#include "qdocumentline_p.h"
+
+#include "qdocumentcursor_p.h"
+
+class QCE_EXPORT QDocumentPrivate
+{
+	friend class QEditConfig;
+	
+	friend class QDocument;
+	friend class QDocumentCommand;
+	friend class QDocumentLineHandle;
+	friend class QDocumentCursorHandle;
+	
+	public:
+		QDocumentPrivate(QDocument *d);
+		~QDocumentPrivate();
+		
+		void execute(QDocumentCommand *cmd);
+		
+		void draw(QPainter *p, QDocument::PaintContext& cxt);
+		
+		QDocumentLineHandle* lineForPosition(int& position) const;
+		int position(const QDocumentLineHandle *l) const;
+		
+		QDocumentLineHandle* at(int line) const;
+		int indexOf(const QDocumentLineHandle *l) const;
+		
+		QDocumentIterator index(const QDocumentLineHandle *l);
+		QDocumentConstIterator index(const QDocumentLineHandle *l) const;
+		
+		QDocumentLineHandle* next(const QDocumentLineHandle *l) const;
+		QDocumentLineHandle* previous(const QDocumentLineHandle *l) const;
+		
+		void adjustWidth(int l);
+		//int checkWidth(QDocumentLineHandle *l, int w);
+		//int checkWidth(QDocumentLineHandle *l, const QString& s);
+		
+		void setWidth();
+		void setHeight();
+		
+		static void setFont(const QFont& f);
+		
+		void beginChangeBlock();
+		void endChangeBlock();
+		
+		inline int maxMarksPerLine() const
+		{ return m_maxMarksPerLine; }
+		
+		inline bool hasMarks() const
+		{ return m_marks.count(); }
+		
+		QList<int> marks(QDocumentLineHandle *h) const;
+		
+		void addMark(QDocumentLineHandle *h, int mid);
+		void toggleMark(QDocumentLineHandle *h, int mid);
+		void removeMark(QDocumentLineHandle *h, int mid);
+		
+		int findNextMark(int id, int from = 0, int until = -1);
+		int findPreviousMark(int id, int from = -1, int until = 0);
+		
+		int getNextGroupId();
+		void releaseGroupId(int groupId);
+		void clearMatches(int gid);
+		void flushMatches(int gid);
+		void addMatch(int gid, int line, int pos, int len, int format);
+		
+		void emitFormatsChange (int line, int lines);
+		void emitContentsChange(int line, int lines);
+		
+		int visualLine(int textLine) const;
+		int textLine(int visualLine, int *wrap = 0) const;
+		void hideEvent(int line, int count);
+		void showEvent(int line, int count);
+		
+		void setWidth(int width);
+		
+		void emitFormatsChanged();
+		void emitContentsChanged();
+		
+		void emitLineDeleted(QDocumentLineHandle *h);
+		void emitMarkChanged(QDocumentLineHandle *l, int m, bool on);
+		
+		inline QDocumentIterator begin() { return m_lines.begin(); }
+		inline QDocumentIterator end() { return m_lines.end(); }
+		
+		inline QDocumentConstIterator constBegin() const { return m_lines.constBegin(); }
+		inline QDocumentConstIterator constEnd() const { return m_lines.constEnd(); }
+		
+	protected:
+		void updateHidden(int line, int count);
+		void updateWrapped(int line, int count);
+		
+		void insertLines(int after, const QList<QDocumentLineHandle*>& l);
+		void removeLines(int after, int n);
+		
+		void emitWidthChanged();
+		void emitHeightChanged();
+		
+		void updateFormatCache();
+		void setFormatScheme(QFormatScheme *f);
+		void tunePainter(QPainter *p, int fid);
+		
+	private:
+		QDocument *m_doc;
+		QUndoStack m_commands;
+		QDocumentCursor *m_editCursor;
+		
+		bool m_suspend, m_deleting;
+		QQueue<QPair<int, int> > m_notifications;
+		
+		QMap<int, int> m_hidden;
+		QMap<int, int> m_wrapped;
+		QVector< QPair<QDocumentLineHandle*, int> > m_largest;
+		
+		struct Match
+		{
+			int line;
+			QFormatRange range;
+			QDocumentLineHandle *h;
+		};
+		
+		struct MatchList : QList<Match>
+		{
+			MatchList() : index(0) {}
+			
+			int index;
+		};
+		
+		int m_lastGroupId;
+		QList<int> m_freeGroupIds;
+		QHash<int, MatchList> m_matches;
+		
+		bool m_constrained;
+		int m_width, m_height;
+		
+		int m_tabStop;
+		static int m_defaultTabStop;
+		
+		static QFont *m_font;
+		static bool m_fixedPitch;
+		static QFontMetrics *m_fontMetrics;
+		static int m_leftMargin;
+		static QDocument::WhiteSpaceMode m_showSpaces;
+		static QDocument::LineEnding m_defaultLineEnding;
+		static int m_lineHeight;
+		static int m_lineSpacing;
+		static int m_spaceWidth;
+		static int m_ascent;
+		static int m_descent;
+		static int m_leading;
+		static int m_wrapMargin;
+		
+		QFormatScheme *m_formatScheme;
+		QLanguageDefinition *m_language;
+		static QFormatScheme *m_defaultFormatScheme;
+		
+		QVector<QFont> m_fonts;
+		
+		static QList<QDocumentPrivate*> m_documents;
+		
+		int m_maxMarksPerLine;
+		QHash<QDocumentLineHandle*, QList<int> > m_marks;
+		QHash<QDocumentLineHandle*, QPair<int, int> > m_status;
+		
+		int _nix, _dos, _mac;
+		QString m_lineEndingString;
+		QDocument::LineEnding m_lineEnding;
+		
+		QDateTime m_lastModified;
+		
+		QDocumentBuffer *m_buffer;
+		QVector<QDocumentLineHandle*> m_lines;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocumentbuffer.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,373 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qdocumentbuffer.h"
+
+/*
+	Notes on design :
+	
+	The idea is to fragment the storage to workaround the issue of Qt
+	containers alocation model (too much memory usage when number of items
+	grow) and provide faster modification of the content.
+	
+	The number one goal is to keep lookup by index as fast possible to avoid
+	significant impact on document iteration/drawing speed
+	
+	for such a storage to be useful the block size may not be fixed but instead
+	must be kept around an "average" value.
+*/
+
+QDocumentBuffer::QDocumentBuffer()
+ : m_safetyRoom(10), m_optimalSize(1000), m_forkThresold(1500), m_mergeThresold(100)
+{
+	
+}
+
+QDocumentBuffer::~QDocumentBuffer()
+{
+	qDeleteAll(m_blocks);
+}
+
+// for loading
+void QDocumentBuffer::appendLine(QDocumentLineHandle *l)
+{
+	Block *b = m_blocks.last();
+	
+	if ( b->size() >= m_optimalSize )
+	{
+		b = new Block();
+		m_blocks << b;
+	}
+	
+	b->lines.append(l);
+}
+
+int QDocumentBuffer::blockForLine(int index) const
+{
+	// TODO : binary search?
+	for ( int i = 0; i < m_blocks.count(); ++i )
+	{
+		if ( index < m_blocks.at(i)->end )
+			return i;
+	}
+	
+	// too high...
+	return -1;
+}
+
+QDocumentLineHandle* QDocumentBuffer::at(int index) const
+{
+	int blockIndex = blockForLine(index);
+	
+	return blockIndex != -1 ? m_blocks.at(blockIndex)->at(index) : 0;
+}
+
+void QDocumentBuffer::insertLine(int index, QDocumentLineHandle *l)
+{
+	int blockIndex = blockForLine(index);
+	
+	if ( blockIndex == -1 )
+	{
+		qWarning("cannot insert line at pos %i", index);
+		return;
+	}
+	
+	Block *b = m_blocks.at(blockIndex);
+	
+	if ( (b->size() + 1) >= m_forkThresold )
+	{
+		// split block
+		int bounds = b->start + m_optimalSize;
+		
+		Block *nb = new Block(bounds);
+		nb->insert(bounds, b->lines.constData() + m_optimalSize, b->size() - m_optimalSize);
+		nb->lines.append(l);
+		nb->end = bounds + nb->size();
+		m_blocks.insert(blockIndex + 1, nb);
+		
+		b->lines.resize(m_optimalSize);
+		b->end = bounds;
+		
+		blockIndex += 2;
+	} else {
+		b->insert(index, l);
+	}
+	
+	// update block boundaries
+	while ( blockIndex < m_blocks.count() )
+	{
+		b = m_blocks.at(blockIndex);
+		++b->start;
+		++b->end;
+	}
+}
+
+void QDocumentBuffer::removeLine(int index)
+{
+	int blockIndex = blockForLine(index);
+	
+	if ( blockIndex == -1 )
+	{
+		qWarning("cannot remove line at pos %i", index);
+		return;
+	}
+	
+	Block *b = m_blocks.at(blockIndex);
+	
+	b->remove(index);
+	--b->end;
+	
+	// if block too small, merge it with blocks around?
+	
+	if ( !b->size() )
+	{
+		// remove empty block
+		m_blocks.remove(blockIndex);
+		delete b;
+	} else if ( b->size() < m_mergeThresold ) {
+		// "merge" block with its neighbors
+		
+		int n = b->size();
+		n += qMin(1, n / m_safetyRoom);
+		
+		int roomPrev = blockIndex ? m_forkThresold - m_blocks.at(blockIndex - 1)->size() : 0;
+		int roomNext = blockIndex + 1 < m_blocks.count() ? m_forkThresold - m_blocks.at(blockIndex + 1)->size() : 0;
+		
+		bool maxPrev = false;
+		int maxRoom = 0, minRoom = 0;
+		Block *moreRoom = 0, *lessRoom = 0;
+		
+		if ( roomPrev > roomNext )
+		{
+			maxPrev = true;
+			maxRoom = roomPrev;
+			moreRoom = m_blocks.at(blockIndex - 1);
+			
+			minRoom = roomNext;
+			
+			if ( roomNext )
+				lessRoom = m_blocks.at(blockIndex + 1);
+		} else {
+			maxRoom = roomNext;
+			
+			if ( roomNext )
+				moreRoom = m_blocks.at(blockIndex + 1);
+			
+			minRoom = roomPrev;
+			
+			if ( roomPrev )
+				lessRoom = m_blocks.at(blockIndex - 1);
+		}
+		
+		if ( maxRoom > n )
+		{
+			// put everything in one
+			moreRoom->lines << b->lines;
+			moreRoom->end += b->size();
+			
+			m_blocks.remove(blockIndex);
+			delete b;
+		} else if ( (maxRoom + minRoom) > n ) {
+			// try to alloc evenly
+			int part = b->size() * maxRoom / (maxRoom + minRoom);
+			
+			if ( maxPrev )
+			{
+				moreRoom->append(b->lines.constData(), part);
+				lessRoom->prepend(b->lines.constData() + part, b->size() - part);
+			} else {
+				moreRoom->prepend(b->lines.constData(), part);
+				lessRoom->append(b->lines.constData() + part, b->size() - part);
+			}
+			
+			moreRoom->end += part;
+			lessRoom->end += b->size() - part;
+			
+			m_blocks.remove(blockIndex);
+			delete b;
+		} else {
+			// cannot merge simply... let's forget about it for now as it is not vital
+			++blockIndex;
+		}
+	} else {
+		++blockIndex;
+	}
+	
+	// update block boundaries
+	while ( blockIndex < m_blocks.count() )
+	{
+		b = m_blocks.at(blockIndex);
+		--b->start;
+		--b->end;
+	}
+}
+
+void QDocumentBuffer::insertLines(int after, const QVector<QDocumentLineHandle*>& l)
+{
+	int index = after + 1;
+	int blockIndex = blockForLine(index);
+	
+	if ( blockIndex == -1 )
+	{
+		qWarning("cannot insert line at pos %i", index);
+		return;
+	}
+	
+	int n = l.count();
+	Block *b = m_blocks.at(blockIndex);
+	
+	if ( (b->size() + 1) >= m_forkThresold )
+	{
+		// split block
+		int bounds = b->start + m_optimalSize;
+		
+		Block *nb = new Block(bounds);
+		nb->insert(bounds, b->lines.constData() + m_optimalSize, b->size() - m_optimalSize);
+		nb->append(l.constData(), n);
+		nb->end = bounds + nb->size();
+		m_blocks.insert(blockIndex + 1, nb);
+		
+		b->lines.resize(m_optimalSize);
+		b->end = bounds;
+		
+		blockIndex += 2;
+	} else {
+		b->insert(index, l.constData(), n);
+	}
+	
+	// update block boundaries
+	while ( blockIndex < m_blocks.count() )
+	{
+		b = m_blocks.at(blockIndex);
+		b->start += n;
+		b->end += n;
+	}
+}
+
+void QDocumentBuffer::removeLines(int after, int n)
+{
+	int index = after + 1;
+	int blockIndex = blockForLine(index);
+	
+	if ( blockIndex == -1 )
+	{
+		qWarning("cannot remove line at pos %i", index);
+		return;
+	}
+	
+	// update block boundaries
+	int count = n;
+	Block *b = m_blocks.at(blockIndex);
+	
+	while ( count > 0 )
+	{
+		int room = b->end - index;
+		int toRem = qMin(room, count);
+		
+		b->remove(index, toRem);
+		b->end -= toRem;
+		count -= toRem;
+		
+		if ( !b->size() )
+		{
+			m_blocks.remove(blockIndex);
+			delete b;
+		} else {
+			++blockIndex;
+		}
+		
+		if ( blockIndex >= m_blocks.count() )
+			break;
+		
+		b = m_blocks.at(blockIndex);
+		b->start -= toRem;
+	}
+	
+	if ( index )
+	{
+		qWarning("Troubles in line removal");
+	}
+	
+	if ( b->size() < m_mergeThresold )
+	{
+		// "merge" block with its neighbors
+		
+		int sz = b->size();
+		sz += qMin(1, sz / m_safetyRoom);
+		
+		int roomPrev = blockIndex ? m_forkThresold - m_blocks.at(blockIndex - 1)->size() : 0;
+		int roomNext = blockIndex + 1 < m_blocks.count() ? m_forkThresold - m_blocks.at(blockIndex + 1)->size() : 0;
+		
+		bool maxPrev = false;
+		int maxRoom = 0, minRoom = 0;
+		Block *moreRoom = 0, *lessRoom = 0;
+		
+		if ( roomPrev > roomNext )
+		{
+			maxPrev = true;
+			maxRoom = roomPrev;
+			moreRoom = m_blocks.at(blockIndex - 1);
+			
+			minRoom = roomNext;
+			
+			if ( roomNext )
+				lessRoom = m_blocks.at(blockIndex + 1);
+		} else {
+			maxRoom = roomNext;
+			
+			if ( roomNext )
+				moreRoom = m_blocks.at(blockIndex + 1);
+			
+			minRoom = roomPrev;
+			
+			if ( roomPrev )
+				lessRoom = m_blocks.at(blockIndex - 1);
+		}
+		
+		if ( maxRoom > sz )
+		{
+			// put everything in one
+			moreRoom->lines << b->lines;
+			moreRoom->end += b->size();
+			
+			m_blocks.remove(blockIndex);
+			delete b;
+		} else if ( (maxRoom + minRoom) > sz ) {
+			// try to alloc evenly
+			int part = b->size() * maxRoom / (maxRoom + minRoom);
+			
+			moreRoom->append(b->lines.constData(), part);
+			moreRoom->end += part;
+			lessRoom->end += b->size() - part;
+			lessRoom->append(b->lines.constData() + part, b->size() - part);
+			
+			m_blocks.remove(blockIndex);
+			delete b;
+		} else {
+			// cannot merge simply... let's forget about it for now as it is not vital
+			++blockIndex;
+		}
+	} else {
+		++blockIndex;
+	}
+	
+	// update block boundaries
+	while ( blockIndex < m_blocks.count() )
+	{
+		b = m_blocks.at(blockIndex);
+		b->start -= n;
+		b->end -= n;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocumentbuffer.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QDOCUMENT_BUFFER_H_
+#define _QDOCUMENT_BUFFER_H_
+
+#include "qce-config.h"
+
+#include <QVector>
+
+#include "qdocumentline_p.h"
+
+class QDocumentLineHandle;
+
+class QCE_EXPORT QDocumentBuffer
+{
+	friend class QDocumentLineHandle;
+	
+	public:
+		class iterator
+		{
+			public:
+				iterator(const iterator& i);
+				
+				bool atEnd() const;
+				
+				int lineNumber() const;
+				QDocumentLineHandle* lineHandle() const;
+				
+				void move(int numLines);
+				
+			protected:
+				iterator(QDocumentBuffer *buffer, int block, int line);
+				
+			private:
+				int m_block;
+				int m_line;
+				QDocumentBuffer *m_buffer;
+		};
+		
+		QDocumentBuffer();
+		~QDocumentBuffer();
+		
+		QDocumentLineHandle* at(int index) const;
+		
+		void appendLine(QDocumentLineHandle *l);
+		
+		void insertLine(int index, QDocumentLineHandle *l);
+		void removeLine(int index);
+		
+		void insertLines(int after, const QVector<QDocumentLineHandle*>& l);
+		void removeLines(int after, int n);
+		
+	private:
+		static void cleanHelper(QVector<QDocumentLineHandle*>& l)
+		{
+			foreach ( QDocumentLineHandle *h, l )
+				h->deref();
+		}
+		
+		struct Block
+		{
+			inline Block() : start(-1), end(-1) {}
+			inline Block(int line) : start(line), end(line) {}
+			~Block() { cleanHelper(lines); }
+			
+			inline void move(int numLines) { start += numLines; end += numLines; }
+			
+			inline int size() const { return lines.count(); }
+			inline QDocumentLineHandle* at(int index) const { return lines.at(index - start); }
+			
+			inline void append(QDocumentLineHandle *h) { lines.append(h); }
+			inline void prepend(QDocumentLineHandle *h) { lines.prepend(h); }
+			inline void insert(int index, QDocumentLineHandle *h) { lines.insert(index - start, h); }
+			inline void insert(int index, const QDocumentLineHandle* const* l, int n)
+			{
+				QDocumentLineHandle **d = const_cast<QDocumentLineHandle**>(l);
+				
+				int i = index - start;
+				lines.insert(i, n, 0);
+				
+				while ( n )
+				{
+					lines[i++] = *d;
+					++d;
+					--n;
+				}
+			}
+			
+			inline void append(const QDocumentLineHandle* const* l, int n)
+			{
+				QDocumentLineHandle **d = const_cast<QDocumentLineHandle**>(l);
+				
+				int i = lines.count();
+				lines.insert(i, n, 0);
+				
+				while ( n )
+				{
+					lines[i++] = *d;
+					++d;
+					--n;
+				}
+			}
+			
+			inline void prepend(const QDocumentLineHandle* const* l, int n)
+			{
+				QDocumentLineHandle **d = const_cast<QDocumentLineHandle**>(l);
+				
+				int i = 0;
+				lines.insert(i, n, 0);
+				
+				while ( n )
+				{
+					lines[i++] = *d;
+					++d;
+					--n;
+				}
+			}
+			
+			inline void remove(int index) { lines.remove(index - start); }
+			inline void remove(int index, int count) { lines.remove(index - start, qMin(count, end - index)); }
+			
+			int start, end;
+			QVector<QDocumentLineHandle*> lines;
+		};
+		
+		int blockForLine(int index) const;
+		
+		int m_safetyRoom;
+		int m_optimalSize;
+		int m_forkThresold;
+		int m_mergeThresold;
+		
+		QVector<Block*> m_blocks;
+};
+
+#endif // !_QDOCUMENT_BUFFER_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocumentcommand.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,946 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qdocumentcommand.h"
+
+/*!
+	\file qdocumentcommand.cpp
+	\brief Implementation of the QDocumentCommand class and its basic heirs.
+*/
+
+#include "qdocument_p.h"
+
+/*!
+	\ingroup document
+	@{
+*/
+
+/*!
+	\class QDocumentCommand
+	\brief The base class for document editing command
+*/
+
+QList<QDocumentCursorHandle*> QDocumentCommand::m_autoUpdated;
+
+/*!
+	\brief ctor
+*/
+QDocumentCommand::QDocumentCommand(Command c, QDocument *d, QDocumentCommand *p)
+ : QUndoCommand(p),
+	m_state(false), m_first(true), m_doc(d),
+	m_redoOffset(0), m_undoOffset(0),
+	m_silent(false), m_keepAnchor(false), m_command(c), m_cursor(0)
+{
+	
+}
+
+/*!
+	\brief dtor
+*/
+QDocumentCommand::~QDocumentCommand()
+{
+	if ( m_cursor )
+	{
+		// release the handle
+		m_cursor->deref();
+	}
+}
+
+/*!
+	\return command identifier
+*/
+int QDocumentCommand::id() const
+{
+	return m_command;
+}
+
+/*!
+	\brief Attempts to merge with another command
+	
+	Command merging is not implemented.
+*/
+bool QDocumentCommand::mergeWith(const QUndoCommand *)
+{
+	return false;
+}
+
+/*!
+	\brief Redo the command
+*/
+void QDocumentCommand::redo()
+{
+	QUndoCommand::redo();
+}
+
+/*!
+	\brief Undo the command
+*/
+void QDocumentCommand::undo()
+{
+	QUndoCommand::undo();
+}
+
+/*!
+	\return whether the command is silent
+	
+	Silent command do not update the editing cursor of the host document.
+*/
+bool QDocumentCommand::isSilent() const
+{
+	return m_silent;
+}
+
+/*!
+	\brief Set whether the command is silent
+*/
+void QDocumentCommand::setSilent(bool y)
+{
+	m_silent = y;
+}
+
+/*!
+	\return whether the command preserve selection of the target cursor
+	
+	When this property is true, cursor adjustement upon command execution
+	will preserve the anchor of target cursor and only alter its position
+	thus keeping a selection.
+	
+	\note This is disabled by default
+*/
+bool QDocumentCommand::keepAnchor() const
+{
+	return m_keepAnchor;
+}
+
+/*!
+	\brief Set whether the command preserve selection of the target cursor
+	
+	\note This is disabled by default
+*/
+void QDocumentCommand::setKeepAnchor(bool y)
+{
+	m_keepAnchor = y;
+}
+
+/*!
+	\brief Set the target cursor
+	
+	The position of the target cursor is update upon undo() and redo()
+*/
+void QDocumentCommand::setTargetCursor(QDocumentCursorHandle *h)
+{
+	if ( m_cursor )
+	{
+		// release the handle
+		m_cursor->deref();
+	}
+	
+	m_cursor = h;
+	
+	if ( m_cursor )
+	{
+		// make sure the handle does not get deleted while the command knows it
+		m_cursor->ref();
+	}
+}
+
+/*!
+	\brief ?
+*/
+void QDocumentCommand::setRedoOffset(int off)
+{
+	m_redoOffset = off;
+}
+
+/*!
+	\brief ?
+*/
+void QDocumentCommand::setUndoOffset(int off)
+{
+	m_undoOffset = off;
+}
+
+/*!
+	\brief Insert some text
+	\param line target line
+	\param pos target text position within line
+	\param s text to insert
+	
+	This helper method is provided so that subclasses may actually
+	modify the document contents without using private API.
+*/
+void QDocumentCommand::insertText(int line, int pos, const QString& s)
+{
+	if ( !m_doc )
+		return;
+	
+	QDocumentPrivate *pd = m_doc->impl();
+	QDocumentLineHandle *h = pd->m_lines.at(line);
+	
+	if ( !h )
+		return;
+	
+	h->textBuffer().insert(pos, s);
+	h->shiftOverlays(pos, s.length());
+	
+	pd->adjustWidth(line);
+}
+
+/*!
+	\brief Remove some text
+	\param line target line
+	\param pos target text position within line
+	\param length length of the text to remove
+	
+	This helper method is provided so that subclasses may actually
+	modify the document contents without using private API.
+*/
+void QDocumentCommand::removeText(int line, int pos, int length)
+{
+	if ( !m_doc )
+		return;
+	
+	QDocumentPrivate *pd = m_doc->impl();
+	QDocumentLineHandle *h = pd->m_lines.at(line);
+	
+	if ( !h || !length )
+		return;
+	
+	h->textBuffer().remove(pos, length);
+	h->shiftOverlays(pos, -length);
+	
+	pd->adjustWidth(line);
+}
+
+/*!
+	\brief Insert some lines in the host document
+	\param after where to insert lines (line number)
+	\param l list of lines to insert
+	
+	This helper method is provided so that subclasses may actually
+	modify the document contents without using too much private API
+	(QDocumentLineHandle is part of the private API...)
+*/
+void QDocumentCommand::insertLines(int after, const QList<QDocumentLineHandle*>& l)
+{
+	if ( l.isEmpty() || !m_doc->impl()->at(after) )
+		return;
+	
+	m_doc->impl()->insertLines(after, l);
+}
+
+void QDocumentCommand::updateCursorsOnInsertion(int line, int column, int prefixLength, int numLines, int suffixLength)
+{
+	//qDebug("inserting %i lines at (%i, %i) with (%i : %i) bounds", numLines, line, column, prefixLength, suffixLength);
+	
+	foreach ( QDocumentCursorHandle *ch, m_autoUpdated )
+	{
+		if ( ch == m_cursor || ch->document() != m_doc )
+			continue;
+		
+		//printf("[[watch:0x%x(%i, %i)]]", ch, ch->m_begLine, ch->m_begOffset);
+		
+		// TODO : better selection handling
+		if ( ch->hasSelection() )
+		{
+			int lbeg = line, cbeg = column, lend = line, cend = column;
+			
+			ch->intersectBoundaries(lbeg, cbeg, lend, cend);
+			
+			if ( lbeg == line && cbeg == column )
+			{
+				//qDebug("expand (%i, %i : %i, %i)", ch->m_begLine, ch->m_begOffset, ch->m_endLine, ch->m_endOffset);
+				if ( (ch->m_begLine > ch->m_endLine) || (ch->m_begLine == ch->m_endLine && ch->m_begOffset > ch->m_endOffset) )
+				{
+					if ( numLines )
+					{
+						if ( ch->m_begLine == line )
+							ch->m_begOffset -= column;
+						ch->m_begLine += numLines;
+						ch->m_begOffset += suffixLength;
+					} else if ( ch->m_begLine == line ) {
+						ch->m_begOffset += prefixLength;
+					}
+				} else {
+					if ( numLines )
+					{
+						if ( ch->m_endLine == line )
+							ch->m_endOffset -= column;
+						ch->m_endLine += numLines;
+						ch->m_endOffset += suffixLength;
+					} else if ( ch->m_endLine == line ) {
+						ch->m_endOffset += prefixLength;
+					}
+				}
+				//qDebug("into (%i, %i : %i, %i)", ch->m_begLine, ch->m_begOffset, ch->m_endLine, ch->m_endOffset);
+				continue;
+			}
+		}
+		
+		// move
+		if ( ch->m_begLine > line )
+		{
+			ch->m_begLine += numLines;
+		} else if ( ch->m_begLine == line && ch->m_begOffset >= column ) {
+			if ( numLines )
+			{
+				ch->m_begLine += numLines;
+				ch->m_begOffset -= column;
+				ch->m_begOffset += suffixLength;
+			} else {
+				ch->m_begOffset += prefixLength;
+			}
+		}
+		
+		if ( ch->m_endLine > line )
+		{
+			ch->m_endLine += numLines;
+		} else if ( ch->m_endLine == line && ch->m_endOffset >= column ) {
+			if ( numLines )
+			{
+				ch->m_endLine += numLines;
+				ch->m_endOffset -= column;
+				ch->m_endOffset += suffixLength;
+			} else {
+				ch->m_endOffset += prefixLength;
+			}
+		}
+	}
+}
+
+void QDocumentCommand::updateCursorsOnDeletion(int line, int column, int prefixLength, int numLines, int suffixLength)
+{
+	//qDebug("removing %i lines at (%i, %i) with (%i : %i) bounds", numLines, line, column, prefixLength, suffixLength);
+	
+	foreach ( QDocumentCursorHandle *ch, m_autoUpdated )
+	{
+		if ( ch == m_cursor || ch->document() != m_doc )
+			continue;
+		
+		//printf("[[watch:0x%x(%i, %i)]]", ch, ch->m_begLine, ch->m_begOffset);
+		
+		// TODO : better selection handling
+		if ( ch->hasSelection() )
+		{
+			int lbeg = line, cbeg = column, lend = line + numLines, cend = numLines ? suffixLength : column + prefixLength;
+			
+			ch->intersectBoundaries(lbeg, cbeg, lend, cend);
+			//qDebug("intersection (%i, %i : %i, %i)", lbeg, cbeg, lend, cend);
+			
+			if ( lbeg != -1 && cbeg != -1 && lend != -1 && cend != -1 )
+			{
+				//qDebug("shrink (%i, %i : %i, %i)", ch->m_begLine, ch->m_begOffset, ch->m_endLine, ch->m_endOffset);
+				//qDebug("of intersection (%i, %i : %i, %i)", lbeg, cbeg, lend, cend);
+				ch->substractBoundaries(lbeg, cbeg, lend, cend);
+				//qDebug("into (%i, %i : %i, %i)", ch->m_begLine, ch->m_begOffset, ch->m_endLine, ch->m_endOffset);
+				continue;
+			}
+		}
+		
+		// move
+		if ( ch->m_begLine > line + numLines )
+		{
+			ch->m_begLine -= numLines;
+		} else if ( ch->m_begLine == line + numLines && ch->m_begOffset >= suffixLength ) {
+			if ( numLines )
+			{
+				ch->m_begLine -= numLines;
+				ch->m_begOffset -= suffixLength;
+				ch->m_begOffset += column;
+			} else {
+				ch->m_begOffset -= prefixLength;
+			}
+		} else if ( ch->m_begLine > line || (ch->m_begLine == line && ch->m_begOffset > column) ) {
+			// cursor will become invalid in an unrecoverable way...
+			
+		}
+		
+		if ( ch->m_endLine > line + numLines )
+		{
+			ch->m_endLine -= numLines;
+		} else if ( ch->m_endLine == line + numLines && ch->m_endOffset >= suffixLength ) {
+			if ( numLines )
+			{
+				ch->m_endLine -= numLines;
+				ch->m_endOffset -= suffixLength;
+				ch->m_endOffset += column;
+			} else {
+				ch->m_endOffset -= prefixLength;
+			}
+		} else if ( ch->m_endLine > line || (ch->m_endLine == line && ch->m_endOffset > column) ) {
+			// cursor will become invalid in an unrecoverable way...
+			// except that it should have intersected in the first place...
+		}
+	}
+}
+
+/*!
+	\brief Remove some lines from the host document
+	\param after where to remove lines (line number)
+	\param n number of lines to remove
+	
+	This helper method is provided so that subclasses may actually
+	modify the document contents without using the private API.
+*/
+void QDocumentCommand::removeLines(int after, int n)
+{
+	if ( n <= 0 || !m_doc->impl()->at(after) || !m_doc->impl()->at(after + n) )
+		return;
+	
+	m_doc->impl()->removeLines(after, n);
+}
+
+/*!
+	\brief Update the target cursor
+	\param l target line
+	\param offset target text position within target line
+*/
+void QDocumentCommand::updateTarget(int l, int offset)
+{
+	//QDocumentLineHandle *h = m_doc->impl()->at(l);
+	
+	// update command sender if any
+	if ( m_cursor )
+	{
+//		qDebug("moving cursor [0x%x:beg] from (%i, %i) to line (%i, %i) as updating",
+//					m_cursor,
+//					m_cursor->m_begLine,
+//					m_cursor->m_begOffset,
+//					l,
+//					offset
+//					);
+//		
+		while ( l && (offset < 0) )
+		{
+			--l;
+			offset += m_doc->line(l).length() + 1;
+		}
+		
+		while ( (l + 1) < m_doc->lines() && m_doc->line(l).length() < offset )
+		{
+			offset -= m_doc->line(l).length() + 1;
+			++l;
+		}
+		
+		if ( !m_keepAnchor )
+		{
+			m_cursor->m_endLine = -1;
+			m_cursor->m_endOffset = -1;
+		} else if ( m_cursor->m_endLine == -1 ) {
+			m_cursor->m_endLine = m_cursor->m_begLine;
+			m_cursor->m_endOffset = m_cursor->m_begOffset;
+		}
+		
+		m_cursor->m_begLine = qMax(0, l);
+		m_cursor->m_begOffset = qMax(0, offset);
+		
+		m_cursor->refreshColumnMemory();
+	}
+}
+
+/*!
+	\return whether a given cursor is auto updated
+*/
+bool QDocumentCommand::isAutoUpdated(const QDocumentCursorHandle *h)
+{
+	return m_autoUpdated.contains(const_cast<QDocumentCursorHandle*>(h));
+}
+
+/*!
+	\brief Enable auto update for a given cursor
+*/
+void QDocumentCommand::enableAutoUpdate(QDocumentCursorHandle *h)
+{
+	//qDebug("up(0x%x)", h);
+	
+	if ( !m_autoUpdated.contains(h) )
+		m_autoUpdated << h;
+}
+
+/*!
+	\brief Disable auto update for a given cursor
+*/
+void QDocumentCommand::disableAutoUpdate(QDocumentCursorHandle *h)
+{
+	//qDebug("no-up(0x%x)", h);
+	m_autoUpdated.removeAll(h);
+}
+
+void QDocumentCommand::discardHandlesFromDocument(QDocument *d)
+{
+	int idx = 0;
+	
+	while ( idx < m_autoUpdated.count() )
+	{
+		if ( m_autoUpdated.at(idx)->document() == d )
+			m_autoUpdated.removeAt(idx);
+		else
+			++idx;
+	}
+}
+
+/*!
+	\brief Change the modification status of a line
+*/
+void QDocumentCommand::markRedone(QDocumentLineHandle *h, bool firstTime)
+{
+	QHash<QDocumentLineHandle*, QPair<int, int> >::iterator it = m_doc->impl()->m_status.find(h);
+	
+	if ( it != m_doc->impl()->m_status.end() )
+	{
+		if ( firstTime && it->first < it->second )
+			it->second = -1;
+		
+		++it->first;
+	} else {
+		m_doc->impl()->m_status[h] = qMakePair(1, 0);
+	}
+}
+
+/*!
+	\brief Change the modifiaction status of a line
+*/
+void QDocumentCommand::markUndone(QDocumentLineHandle *h)
+{
+	QHash<QDocumentLineHandle*, QPair<int, int> >::iterator it = m_doc->impl()->m_status.find(h);
+	
+	if ( it != m_doc->impl()->m_status.end() )
+	{
+		--it->first;
+	} else {
+		qDebug("warning: status data and/or undo stack corrupted...");
+		m_doc->impl()->m_status[h] = qMakePair(-1, 0);
+	}
+}
+
+////////////////////////////
+
+/*!
+	\class QDocumentInsertCommand
+	\brief A specialized command to insert text
+*/
+
+/*!
+	\brief ctor
+	\param l target line
+	\param offset target text position within target line
+	\param text text to insert (can contain line feeds, "\n", which will result in the creation of new lines)
+	\param doc host document
+	\param p parent command
+*/
+QDocumentInsertCommand::QDocumentInsertCommand(	int l, int offset,
+												const QString& text,
+												QDocument *doc,
+												QDocumentCommand *p)
+ : QDocumentCommand(Insert, doc, p)
+{
+	QStringList lines = text.split(QLatin1Char('\n'), QString::KeepEmptyParts);
+	
+	if ( !m_doc || text.isEmpty() )
+		qFatal("Invalid insert command");
+	
+	m_data.lineNumber = l;
+	m_data.startOffset = offset;
+	
+	m_data.begin = lines.takeAt(0);
+	m_data.endOffset = lines.count() ? lines.last().length() : -1;
+	
+	foreach ( const QString& s, lines )
+		m_data.handles << new QDocumentLineHandle(s, m_doc);
+	
+	QDocumentLine bl = m_doc->line(l);
+	
+	if ( m_data.handles.count() && (bl.length() > offset) )
+	{
+		m_data.end = bl.text().mid(offset);
+		m_data.handles.last()->textBuffer().append(m_data.end);
+	}
+	
+	/*
+	if ( (text == "\n") && m_data.handles.isEmpty() )
+		qWarning("Go fix it by hand...");
+	*/
+}
+
+/*!
+	\brief dtor
+*/
+QDocumentInsertCommand::~QDocumentInsertCommand()
+{
+	if ( m_state )
+		return;
+	
+	//foreach ( QDocumentLineHandle *h, m_data.handles )
+	//	h->deref();
+	
+}
+
+bool QDocumentInsertCommand::mergeWith(const QUndoCommand *)
+{
+	return false;
+}
+
+void QDocumentInsertCommand::redo()
+{
+	// state : handles used by doc
+	m_state = true;
+	
+	//QDocumentIterator it = m_doc->impl()->index(m_data.lineNumber);
+	
+	//qDebug("inserting %i lines after %i", m_data.handles.count(), m_data.lineNumber);
+	
+	QDocumentLineHandle *hl = m_doc->impl()->at(m_data.lineNumber);
+	
+	if ( m_data.handles.count() )
+	{
+		removeText(m_data.lineNumber, m_data.startOffset, m_data.end.count());
+	}
+	
+	insertText(m_data.lineNumber, m_data.startOffset, m_data.begin);
+	
+	insertLines(m_data.lineNumber, m_data.handles);
+	
+	if ( m_data.handles.count() )
+	{
+		QDocumentLineHandle *h = m_data.handles.last();
+		
+		//updateTarget(h, h->text().length() - m_data.end.length());
+		updateTarget(m_data.lineNumber + m_data.handles.count(), h->text().length() - m_data.end.length() + m_redoOffset);
+	} else {
+		updateTarget(m_data.lineNumber, m_data.startOffset + m_data.begin.length() + m_redoOffset);
+	}
+	
+	updateCursorsOnInsertion(m_data.lineNumber, m_data.startOffset, m_data.begin.length(), m_data.handles.count(), m_data.endOffset);
+	
+	m_doc->impl()->emitContentsChange(m_data.lineNumber, m_data.handles.count() + 1);
+	
+	markRedone(hl, m_first);
+	
+	foreach ( QDocumentLineHandle *h, m_data.handles )
+		markRedone(h, m_first);
+	
+	//m_doc->impl()->emitContentsChanged();
+	m_first = false;
+}
+
+void QDocumentInsertCommand::undo()
+{
+	// state : handles !used by doc
+	m_state = false;
+	
+	//QDocumentIterator it = m_doc->impl()->index(m_data.line);
+	
+	QDocumentLineHandle *hl = m_doc->impl()->at(m_data.lineNumber);
+	
+	removeLines(m_data.lineNumber, m_data.handles.count());
+	removeText(m_data.lineNumber, m_data.startOffset, m_data.begin.count());
+	
+	if ( m_data.handles.count() )
+	{
+		insertText(m_data.lineNumber, m_data.startOffset, m_data.end);
+	}
+	
+	updateTarget(m_data.lineNumber, m_data.startOffset + m_undoOffset);
+	
+	updateCursorsOnDeletion(m_data.lineNumber, m_data.startOffset, m_data.begin.length(), m_data.handles.count(), m_data.endOffset);
+	
+	m_doc->impl()->emitContentsChange(m_data.lineNumber, m_data.handles.count() + 1);
+	
+	markUndone(hl);
+	
+	foreach ( QDocumentLineHandle *h, m_data.handles )
+		markUndone(h);
+	
+	//m_doc->impl()->emitContentsChanged();
+}
+
+///////////////////////////
+
+/*!
+	\class QDocumentEraseCommand
+	\brief A specialized command to erase text
+*/
+
+/*!
+	\brief ctor
+	\param bl begin line of the target area
+	\param bo begin text position of the target area
+	\param el end line of the target area
+	\param eo end text position of the target area
+	\param doc host document
+	\param p parent command
+*/
+QDocumentEraseCommand::QDocumentEraseCommand(	int bl, int bo,
+												int el, int eo,
+												QDocument *doc,
+												QDocumentCommand *p)
+ : QDocumentCommand(Erase, doc, p)
+{
+	QDocumentLineHandle *start = m_doc->impl()->at(bl),
+						*end = m_doc->impl()->at(el);
+	
+	QDocumentConstIterator it = m_doc->impl()->begin() + bl; //index(start);
+	
+	m_data.lineNumber = bl;
+	m_data.startOffset = bo;
+	
+	if ( start == end )
+	{
+		m_data.begin = start->text().mid(bo, eo - bo);
+		
+		m_data.end = QString();
+		m_data.endOffset = -1;
+		
+	} else {
+		m_data.begin = start->text().mid(bo);
+		
+		m_data.endOffset = eo;
+		m_data.end = end->text().mid(eo);
+		
+		do
+		{
+			m_data.handles << *(++it);
+		} while ( *it != end );
+	}
+	
+	m_state = true;
+}
+
+/*!
+	\brief dtor
+*/
+QDocumentEraseCommand::~QDocumentEraseCommand()
+{
+	if ( m_state )
+		return;
+	
+	//qDeleteAll(m_data.handles);
+}
+
+bool QDocumentEraseCommand::mergeWith(const QUndoCommand *)
+{
+	return false;
+}
+
+void QDocumentEraseCommand::redo()
+{
+	// state : handles !used by doc
+	m_state = false;
+	
+	//QDocumentIterator it = m_doc->impl()->index(m_data.line);
+	
+	QDocumentLineHandle *hl = m_doc->impl()->at(m_data.lineNumber);
+	
+	if ( m_data.handles.isEmpty() )
+	{
+		removeText(m_data.lineNumber, m_data.startOffset, m_data.begin.count());
+		
+		m_doc->impl()->emitContentsChange(m_data.lineNumber, 1);
+		
+	} else {
+		removeText(m_data.lineNumber, m_data.startOffset, m_data.begin.count());
+		
+		if ( m_data.endOffset != -1 )
+			insertText(m_data.lineNumber, m_data.startOffset, m_data.end);
+		
+		removeLines(m_data.lineNumber, m_data.handles.count());
+		
+		m_doc->impl()->emitContentsChange(m_data.lineNumber, m_data.handles.count() + 1);
+	}
+	
+	updateTarget(m_data.lineNumber, m_data.startOffset + m_redoOffset);
+	
+	updateCursorsOnDeletion(m_data.lineNumber, m_data.startOffset, m_data.begin.length(), m_data.handles.count(), m_data.endOffset);
+	
+	markRedone(hl, m_first);
+	
+	foreach ( QDocumentLineHandle *h, m_data.handles )
+		markRedone(h, m_first);
+	
+	//m_doc->impl()->emitContentsChanged();
+	m_first = false;
+}
+
+void QDocumentEraseCommand::undo()
+{
+	// state : handles used by doc
+	m_state = true;
+	
+	//QDocumentIterator it = m_doc->impl()->index(m_data.line);
+	
+	QDocumentLineHandle *hl = m_doc->impl()->at(m_data.lineNumber);
+	
+	if ( m_data.handles.count() )
+	{
+		insertLines(m_data.lineNumber, m_data.handles);
+		
+		if ( m_data.endOffset != -1 )
+			removeText(m_data.lineNumber, m_data.startOffset, m_data.end.count());
+		
+		insertText(m_data.lineNumber, m_data.startOffset, m_data.begin);
+		
+		m_doc->impl()->emitContentsChange(m_data.lineNumber, m_data.handles.count() + 1);
+	} else {
+		
+		insertText(m_data.lineNumber, m_data.startOffset, m_data.begin);
+		
+		m_doc->impl()->emitContentsChange(m_data.lineNumber, 1);
+	}
+	
+	if ( m_data.handles.count() )
+	{
+		QDocumentLineHandle *h = m_data.handles.last();
+		
+		//updateTarget(h, h->text().length() - m_data.end.length());
+		updateTarget(m_data.lineNumber + m_data.handles.count(), h->text().length() - m_data.end.length() + m_undoOffset);
+	} else {
+		updateTarget(m_data.lineNumber, m_data.startOffset + m_data.begin.length() + m_undoOffset);
+	}
+	
+	updateCursorsOnInsertion(m_data.lineNumber, m_data.startOffset, m_data.begin.length(), m_data.handles.count(), m_data.endOffset);
+	
+	markUndone(hl);
+	
+	foreach ( QDocumentLineHandle *h, m_data.handles )
+		markUndone(h);
+	
+	//m_doc->impl()->emitContentsChanged();
+}
+
+///////////////////////////
+/*
+QDocumentReplaceCommand::QDocumentReplaceCommand(const QDocumentLine& l, int, int, const QString&)
+ : QDocumentCommand(Replace, l.document())
+{
+	
+}
+
+QDocumentReplaceCommand::~QDocumentReplaceCommand()
+{
+	
+}
+
+bool QDocumentReplaceCommand::mergeWith(const QUndoCommand *)
+{
+	return false;
+}
+
+void QDocumentReplaceCommand::redo()
+{
+	
+}
+
+void QDocumentReplaceCommand::undo()
+{
+	
+}
+*/
+
+//////////////////////
+
+
+/*!
+	\class QDocumentCommandBlock
+	\brief A meta command used for command grouping
+*/
+
+/*!
+	\brief ctor
+	\param d host document
+*/
+QDocumentCommandBlock::QDocumentCommandBlock(QDocument *d)
+ : QDocumentCommand(Custom, d), m_weakLocked(false)
+{
+	
+}
+
+/*!
+	\brief dtor
+*/
+QDocumentCommandBlock::~QDocumentCommandBlock()
+{
+	
+}
+
+void QDocumentCommandBlock::redo()
+{
+	if ( isWeakLocked() )
+	{
+		setWeakLock(false);
+		return;
+	}
+	
+	//foreach ( QDocumentCommand *c, m_commands )
+	//	c->redo();
+	
+	for ( int i = 0; i < m_commands.count(); ++i )
+		m_commands.at(i)->redo();
+	
+}
+
+void QDocumentCommandBlock::undo()
+{
+	//foreach ( QDocumentCommand *c, m_commands )
+	//	c->undo();
+	
+	for ( int i = m_commands.count() - 1; i >= 0; --i )
+		m_commands.at(i)->undo();
+	
+}
+
+/*!
+	\brief Set whether the block is weakly locked
+*/
+void QDocumentCommandBlock::setWeakLock(bool l)
+{
+	m_weakLocked = l;
+}
+
+/*!
+	\return whether the block is weakly locked
+	
+	Weak locking of command block is an obscure internal feature
+	which prevents the first redo() call from actually redo'ing
+	the grouped commands
+*/
+bool QDocumentCommandBlock::isWeakLocked() const
+{
+	return m_weakLocked;
+}
+
+/*!
+	\brief Add a command to the group
+	
+	\warning Doing that after having pushed the command on the undo/redo stack
+	is likely to result in corruption of the undo/redo stack
+*/
+void QDocumentCommandBlock::addCommand(QDocumentCommand *c)
+{
+	m_commands << c;
+}
+
+/*!
+	\brief Remove a command from the block
+	
+	\warning Doing that after having pushed the command on the undo/redo stack
+	is likely to result in corruption of the undo/redo stack
+*/
+void QDocumentCommandBlock::removeCommand(QDocumentCommand *c)
+{
+	m_commands.removeAll(c);
+}
+
+/*! @} */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocumentcommand.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QDOCUMENT_COMMAND_H_
+#define _QDOCUMENT_COMMAND_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qdocumentcommand.h
+	\brief Definition of the QDocumentCommand class
+*/
+
+#include <QUndoCommand>
+
+#include "qdocument.h"
+
+class QDocumentLine;
+class QDocumentLineHandle;
+class QDocumentCursorHandle;
+
+class QCE_EXPORT QDocumentCommand : public QUndoCommand
+{
+	public:
+		enum Command
+		{
+			None,
+			Insert,
+			Erase,
+			Replace,
+			Custom
+		};
+		
+		struct TextCommandData
+		{
+			QString begin, end;
+			int lineNumber, startOffset, endOffset;
+			QList<QDocumentLineHandle*> handles;
+		};
+		
+		QDocumentCommand(Command c, QDocument *d, QDocumentCommand *p = 0);
+		virtual ~QDocumentCommand();
+		
+		virtual int id() const;
+		
+		virtual bool mergeWith(const QUndoCommand *command);
+		
+		virtual void redo();
+		virtual void undo();
+		
+		bool isSilent() const;
+		void setSilent(bool y);
+		
+		bool keepAnchor() const;
+		void setKeepAnchor(bool y);
+		
+		void setTargetCursor(QDocumentCursorHandle *h);
+		
+		void setRedoOffset(int off);
+		void setUndoOffset(int off);
+		
+		static bool isAutoUpdated(const QDocumentCursorHandle *h);
+		static void enableAutoUpdate(QDocumentCursorHandle *h);
+		static void disableAutoUpdate(QDocumentCursorHandle *h);
+		static void discardHandlesFromDocument(QDocument *d);
+		
+	protected:
+		bool m_state, m_first;
+		QDocument *m_doc;
+		int m_redoOffset, m_undoOffset;
+		
+		void markRedone(QDocumentLineHandle *h, bool firstTime);
+		void markUndone(QDocumentLineHandle *h);
+		
+		void updateTarget(int l, int offset);
+		
+		void insertText(int line, int pos, const QString& s);
+		void removeText(int line, int pos, int length);
+		
+		void insertLines(int after, const QList<QDocumentLineHandle*>& l);
+		void removeLines(int after, int n);
+		
+		void updateCursorsOnInsertion(int line, int column, int prefixLength, int numLines, int suffixLength);
+		void updateCursorsOnDeletion(int line, int column, int prefixLength, int numLines, int suffixLength);
+		
+	private:
+		bool m_silent;
+		bool m_keepAnchor;
+		Command m_command;
+		QDocumentCursorHandle *m_cursor;
+		
+		static QList<QDocumentCursorHandle*> m_autoUpdated;
+};
+
+Q_DECLARE_TYPEINFO(QDocumentCommand::TextCommandData, Q_MOVABLE_TYPE);
+
+class QCE_EXPORT QDocumentInsertCommand : public QDocumentCommand
+{
+	public:
+		QDocumentInsertCommand(	int l, int offset,
+								const QString& text,
+								QDocument *doc,
+								QDocumentCommand *p = 0);
+		
+		virtual ~QDocumentInsertCommand();
+		
+		virtual bool mergeWith(const QUndoCommand *command);
+		
+		virtual void redo();
+		virtual void undo();
+		
+	private:
+		TextCommandData m_data;
+};
+
+class QCE_EXPORT QDocumentEraseCommand : public QDocumentCommand
+{
+	public:
+		QDocumentEraseCommand(	int bl, int bo,
+								int el, int eo,
+								QDocument *doc,
+								QDocumentCommand *p = 0);
+		
+		virtual ~QDocumentEraseCommand();
+		
+		virtual bool mergeWith(const QUndoCommand *command);
+		
+		virtual void redo();
+		virtual void undo();
+		
+	private:
+		TextCommandData m_data;
+};
+
+class QCE_EXPORT QDocumentCommandBlock : public QDocumentCommand
+{
+	public:
+		QDocumentCommandBlock(QDocument *d);
+		virtual ~QDocumentCommandBlock();
+		
+		virtual void redo();
+		virtual void undo();
+		
+		void setWeakLock(bool l);
+		bool isWeakLocked() const;
+		
+		virtual void addCommand(QDocumentCommand *c);
+		virtual void removeCommand(QDocumentCommand *c);
+		
+	private:
+		bool m_weakLocked;
+		QList<QDocumentCommand*> m_commands;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocumentcursor.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,852 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+/*!
+	\file qdocumentcursor.cpp
+	\brief Implementation of the QDocumentCursor class
+*/
+
+#include "qdocumentcursor.h"
+
+/*!
+	\ingroup document
+	@{
+*/
+
+#include "qdocument_p.h"
+
+#include "qdocumentline.h"
+
+/*!
+	\class QDocumentCursor
+	
+	\brief A cursor to navigate within documents and edit them
+	
+	QDocumentCursor is a central class of the public API.
+	
+	It is the best (as in fastest and easiest) way to iterate over
+	the content of a document.
+	
+	It is also the only class that allows to perform editing operations.
+	
+	A cursor position is defined by a line number and a text position
+	within the line.
+	
+	Every cursor can have one or two cursor positions. In the later
+	case, they delimit a selection. The first position set (before
+	selecting) is referred to as the "anchor" and the other (if it
+	is different from the anchor) is the actual cursor position.
+	
+	When the cursor does not have a selection, querying informations about
+	the anchor has the same result as querying informations about the cursor
+	position.
+	
+	Informations you can get about both the anchor and the posiotion :
+	<ul>
+	<li>the line number : the logical line to which the cursor position points inside the document
+	<li>the column number : the logical text column to which the cursor position points to, inside the pointed line.
+	<li>the wrapped line offset : when a cursor resides on a wrapped line, this indicates in which part of
+	the wrapped line it does
+	<li>the document position : document (x, y) coordinates corresponding to the place the cursor is drawn
+	</ul>
+	
+	The visual line to which a given cursor resides can be obtained as follows :
+	
+	\code
+	int visual_line = cursor.document()->visualLine(cursor.lineNumber()) + cursor.wrappedLineOffset();
+	\endcode
+	
+	\note The line and column numbers passed to/returned by a cursor method
+	always start at zero.
+
+	\note Quick overview of the various coordinate systems :
+	<ul>
+		<li>document coordinates aka viewport coordinates : (x, y) coords, in pixels, origin at the top left corner of
+		the rectangle occupied by the very first line of the document
+		<li>text coordinates : (line, column) in logical units (number of lines, number of characters)
+		<li>visual text coordinates : (line, column) in logical units but with a different mapping
+	</ul>
+*/
+
+QDocumentCursor::QDocumentCursor(QDocument *doc)
+ : m_handle(new QDocumentCursorHandle(doc))
+{
+	m_handle->ref();
+}
+
+QDocumentCursor::QDocumentCursor(const QDocumentCursor& cursor)
+ : m_handle(0)
+{
+	if ( cursor.m_handle )
+	{
+		m_handle = cursor.m_handle->clone();
+		m_handle->ref();
+	}
+}
+
+QDocumentCursor::QDocumentCursor(QDocument *doc, int line, int column)
+ : m_handle(new QDocumentCursorHandle(doc, line))
+{
+	m_handle->ref();
+	
+	m_handle->setColumnNumber(column);
+}
+
+/*
+QDocumentCursor::QDocumentCursor(const QDocumentLine& line, int column)
+ : m_handle(new QDocumentCursorHandle(line.document(), line.lineNumber()))
+{
+	m_handle->ref();
+	
+	m_handle->setColumnNumber(column);
+	//movePosition(qMin(column, line.length()));
+}
+*/
+
+QDocumentCursor::QDocumentCursor(QDocumentCursorHandle *handle)
+ : m_handle(handle)
+{
+	if ( m_handle )
+		m_handle->ref();
+}
+
+QDocumentCursor::~QDocumentCursor()
+{
+	if ( m_handle )
+		m_handle->deref();
+}
+
+QDocumentCursor QDocumentCursor::clone() const
+{
+	return m_handle ? QDocumentCursor(m_handle->clone()) : QDocumentCursor();
+}
+
+QDocumentCursor& QDocumentCursor::operator = (const QDocumentCursor& c)
+{
+	#if 0
+	if ( m_handle )
+		m_handle->deref();
+	
+	m_handle = c.m_handle ? c.m_handle->clone() : 0;
+	//m_handle = c.m_handle;
+	
+	if ( m_handle )
+		m_handle->ref();
+	#endif
+	
+	if ( c.m_handle )
+	{
+		if ( m_handle )
+		{
+			m_handle->copy(c.m_handle);
+		} else {
+			m_handle = c.m_handle->clone();
+			m_handle->ref();
+		}
+	} else if ( m_handle ) {
+		
+		//qWarning("Setting a cursor to null");
+		
+		m_handle->deref();
+		m_handle = 0;
+	}
+	
+	return *this;
+}
+
+/*!
+	\brief comparision operator
+	
+	\note If any of the operand is an invalid cursor, false is returned
+*/
+bool QDocumentCursor::operator == (const QDocumentCursor& c) const
+{
+	if ( !m_handle || !c.m_handle )
+		return false;
+	
+	return m_handle->eq(c.m_handle);
+}
+
+/*!
+	\brief comparision operator
+	
+	\note If any of the operand is an invalid cursor, true is returned (to preserve logical consistency with == )
+*/
+bool QDocumentCursor::operator != (const QDocumentCursor& c) const
+{
+	if ( !m_handle || !c.m_handle )
+		return true;
+	
+	return !m_handle->eq(c.m_handle);
+}
+
+/*!
+	\brief comparision operator
+	
+	\note If any of the operand is an invalid cursor, false is returned
+*/
+bool QDocumentCursor::operator < (const QDocumentCursor& c) const
+{
+	if ( !m_handle || !c.m_handle )
+		return false;
+	
+	return m_handle->lt(c.m_handle);
+}
+
+/*!
+	\brief comparision operator
+	
+	\note If any of the operand is an invalid cursor, false is returned
+*/
+bool QDocumentCursor::operator > (const QDocumentCursor& c) const
+{
+	if ( !m_handle || !c.m_handle )
+		return false;
+	
+	return m_handle->gt(c.m_handle);
+}
+
+/*!
+	\brief comparision operator
+	
+	\note If any of the operand is an invalid cursor, false is returned
+*/
+bool QDocumentCursor::operator <= (const QDocumentCursor& c) const
+{
+	if ( !m_handle || !c.m_handle )
+		return false;
+	
+	return m_handle->lt(c.m_handle) || m_handle->eq(c.m_handle);
+}
+
+/*!
+	\brief comparision operator
+	
+	\note If any of the operand is an invalid cursor, false is returned
+*/
+bool QDocumentCursor::operator >= (const QDocumentCursor& c) const
+{
+	if ( !m_handle || !c.m_handle )
+		return false;
+	
+	return m_handle->gt(c.m_handle) || m_handle->eq(c.m_handle);
+}
+
+/*!
+	\brief comparision operator
+*/
+bool QDocumentCursor::isNull() const
+{
+	return !m_handle || !m_handle->document() || !line().isValid();
+}
+
+/*!
+	\brief comparision operator
+*/
+bool QDocumentCursor::isValid() const
+{
+	return m_handle && m_handle->document() && line().isValid();
+}
+
+/*!
+	\return whether the cursor is at the end of the document
+*/
+bool QDocumentCursor::atEnd() const
+{
+	return m_handle ? m_handle->atEnd() : false;
+}
+
+/*!
+	\return whether the cursor is at the begining of the document
+*/
+bool QDocumentCursor::atStart() const
+{
+	return m_handle ? m_handle->atStart() : false;
+}
+
+/*!
+	\return whether the cursor is at the end of a block
+*/
+bool QDocumentCursor::atBlockEnd() const
+{
+	return m_handle ? m_handle->atBlockEnd() : false;
+}
+
+/*!
+	\return whether the cursor is at the start of a block
+*/
+bool QDocumentCursor::atBlockStart() const
+{
+	return m_handle ? m_handle->atBlockStart() : false;
+}
+
+/*!
+	\return whether the cursor is at the end of a line
+	
+	\note this may only differ from atBlockEnd() on wrapped lines
+*/
+bool QDocumentCursor::atLineEnd() const
+{
+	return m_handle ? m_handle->atLineEnd() : false;
+}
+
+/*!
+	\return whether the cursor is at the start of a line
+	
+	\note this may only differ from atBlockStart() on wrapped lines
+*/
+bool QDocumentCursor::atLineStart() const
+{
+	return m_handle ? m_handle->atLineStart() : false;
+}
+
+/*!
+	\return the document on which this cursor operates
+*/
+QDocument* QDocumentCursor::document() const
+{
+	return m_handle ? m_handle->document() : 0;
+}
+
+/*!
+	\return the text position (within the whole document) at which this cursor is
+	
+	\note available for compat with QTextCursor and ridiculously slow : avoid whenever possible
+*/
+int QDocumentCursor::position() const
+{
+	return m_handle ? m_handle->position() : -1;
+}
+
+/*!
+	\return the text column of the anchor
+*/
+int QDocumentCursor::anchorColumnNumber() const
+{
+	return m_handle ? m_handle->anchorColumnNumber() : -1;
+}
+
+/*!
+	\return the "visual" text column of the cursor
+	
+	\note this may only differ from columnNumber() when there are tabs on the line
+*/
+int QDocumentCursor::visualColumnNumber() const
+{
+	return m_handle ? m_handle->visualColumnNumber() : -1;
+}
+
+/*!
+	\return the text column of the cursor
+*/
+int QDocumentCursor::columnNumber() const
+{
+	return m_handle ? m_handle->columnNumber() : -1;
+}
+
+/*!
+	\brief Set the text column of the cursor
+	\param c text column to set
+	\param m move mode (determines whether text will be selected)
+*/
+void QDocumentCursor::setColumnNumber(int c, MoveMode m)
+{
+	if ( m_handle )
+		m_handle->setColumnNumber(c, m);
+}
+
+/*!
+	\return The line number to which the cursor points
+*/
+int QDocumentCursor::lineNumber() const
+{
+	return m_handle ? m_handle->lineNumber() : -1;
+}
+
+/*!
+	\return The line number to which the cursor points
+*/
+int QDocumentCursor::anchorLineNumber() const
+{
+	return m_handle ? m_handle->anchorLineNumber() : -1;
+}
+
+/*!
+	\return The wrapped line on which the cursor resides
+	
+	Wrapped line are "sublines" of logical lines.
+*/
+int QDocumentCursor::wrappedLineOffset() const
+{
+	return line().wrappedLineForCursor(columnNumber());
+}
+
+/*!
+	\return The line number on which the anchor resides
+*/
+int QDocumentCursor::anchorWrappedLineOffset() const
+{
+	return anchorLine().wrappedLineForCursor(anchorColumnNumber());
+}
+
+/*!
+	\return the document position at which the cursor is
+	
+	Document position and viewport position are two terms used interchangeably.
+	The only difference is the former refers to model perception (QDocument)
+	whereas the later refers to view perception (QEditor)
+*/
+QPoint QDocumentCursor::documentPosition() const
+{
+	return m_handle ? m_handle->documentPosition() : QPoint();
+}
+
+/*!
+	\return the document position of the anchor
+*/
+QPoint QDocumentCursor::anchorDocumentPosition() const
+{
+	return m_handle ? m_handle->anchorDocumentPosition() : QPoint();
+}
+
+QPolygon QDocumentCursor::documentRegion() const
+{
+	return m_handle ? m_handle->documentRegion() : QPolygon();
+}
+
+/*!
+	\return The line object on which the cursor resides
+*/
+QDocumentLine QDocumentCursor::line() const
+{
+	return m_handle ? m_handle->line() : QDocumentLine();
+}
+
+/*!
+	\return The line object on which the anchor resides
+*/
+QDocumentLine QDocumentCursor::anchorLine() const
+{
+	return m_handle ? m_handle->anchorLine() : QDocumentLine();
+}
+
+/*!
+	\brief Shift cursor position (text column) by a number of columns (characters)
+*/
+void QDocumentCursor::shift(int offset)
+{
+	if ( m_handle )
+		m_handle->shift(offset);
+}
+
+/*!
+	\brief Set the text position of the cursor (within the whole document)
+	
+	Remark made about position() applies.
+*/
+void QDocumentCursor::setPosition(int pos, MoveMode m)
+{
+	if ( m_handle )
+		m_handle->setPosition(pos, m);
+}
+
+/*!
+	\brief Moves the cursor position
+	\param offset number of times the selected move will be done
+	\param op movement type
+	\param m movement mode (whether to select)
+	\return true on succes
+*/
+bool QDocumentCursor::movePosition(int offset, MoveOperation op, MoveMode m)
+{
+	return m_handle ? m_handle->movePosition(offset, op, m) : false;
+}
+
+/*!
+	\brief Jump to another cursor position
+	\param line target line number
+	\param colum target text column
+*/
+void QDocumentCursor::moveTo(int line, int column)
+{
+	if ( m_handle )
+		m_handle->moveTo(line, column);
+}
+
+/*!
+	\brief Jump to the position of another cursor
+	\param c target cursor
+*/
+void QDocumentCursor::moveTo(const QDocumentCursor &c)
+{
+	if ( m_handle )
+		m_handle->moveTo(c);
+}
+
+/*!
+	\brief Jump to another cursor position
+	\param l target line
+	\param column target text column
+	
+	\note Calls QDocumentLine::lineNumber() => SLOW : avoid whenever possible
+*/
+void QDocumentCursor::moveTo(const QDocumentLine &l, int column)
+{
+	if ( m_handle )
+		m_handle->moveTo(l.lineNumber(), column);
+}
+
+/*!
+	\return the character at the position immediately after the cursor
+*/
+QChar QDocumentCursor::nextChar() const
+{
+	return m_handle ? m_handle->nextChar() : QChar();
+}
+
+/*!
+	\return the character at the position immediately before the cursor
+*/
+QChar QDocumentCursor::previousChar() const
+{
+	return m_handle ? m_handle->previousChar() : QChar();
+}
+
+/*!
+	\brief Delete the character at the position immediately after the cursor
+*/
+void QDocumentCursor::deleteChar()
+{
+	if ( m_handle )
+		m_handle->deleteChar();
+}
+
+/*!
+	\brief Delete the character at the position immediately before the cursor
+*/
+void QDocumentCursor::deletePreviousChar()
+{
+	if ( m_handle )
+		m_handle->deletePreviousChar();
+}
+
+/*!
+	\brief erase the whole line the cursor is on, newline included
+*/
+void QDocumentCursor::eraseLine()
+{
+	if ( m_handle )
+		m_handle->eraseLine();
+}
+
+/*!
+	\brief insert a new line at the cursor position
+*/
+void QDocumentCursor::insertLine(bool keepAnchor)
+{
+	if ( m_handle )
+		m_handle->insertText("\n", keepAnchor);
+}
+
+/*!
+	\brief insert some text at the cursor position
+	
+	Selected text will be removed before insertion happens.
+	
+	\note Nothing happens if \a s is empty
+*/
+void QDocumentCursor::insertText(const QString& s, bool keepAnchor)
+{
+	if ( m_handle )
+		m_handle->insertText(s, keepAnchor);
+}
+
+/*!
+	\return A cursor pointing at the position of the selection start.
+	
+	Selection start is the position of the selection that is nearest to document start.
+	
+	\note an invalid cursor is returned when the cursor does not have a selection
+*/
+QDocumentCursor QDocumentCursor::selectionStart() const
+{
+	return m_handle ? m_handle->selectionStart() : QDocumentCursor();
+}
+
+/*!
+	\return A cursor pointing at the position of the selection end.
+	
+	Selection end is the position of the selection that is nearest to document end.
+	
+	\note an invalid cursor is returned when the cursor does not have a selection
+*/
+QDocumentCursor QDocumentCursor::selectionEnd() const
+{
+	return m_handle ? m_handle->selectionEnd() : QDocumentCursor();
+}
+
+/*!
+	\return The selected text
+*/
+QString QDocumentCursor::selectedText() const
+{
+	return m_handle ? m_handle->selectedText() : QString();
+}
+
+/*!
+	\brief Remove the selected text
+*/
+void QDocumentCursor::removeSelectedText()
+{
+	if ( m_handle )
+		m_handle->removeSelectedText();
+}
+
+/*!
+	\brief Replace the selected text
+	
+	This method differs from insertText() in two ways :
+	<ul>
+		<li>if \a text is empty the selection WILL be removed
+		<li>after the replacement happens this command will
+		cause the cursor to select the new text (note that this
+		information is NOT preserved by the undo/redo stack
+		however).
+	</ul>
+*/
+void QDocumentCursor::replaceSelectedText(const QString& text)
+{
+	if ( m_handle )
+		m_handle->replaceSelectedText(text);
+}
+
+/*!
+	\brief Begin an edit block
+	
+	Edit blocks are command groups. All the commands in an edit block
+	are executed in a row when the edit block is ended with endEditBlock().
+	
+	Edit blocks are considered as a single command as far as the undo/redo
+	stack is concerned.
+	
+	Edit blocks can be nested but that isn't of much use
+*/
+void QDocumentCursor::beginEditBlock()
+{
+	if ( m_handle )
+		m_handle->beginEditBlock();
+}
+
+/*!
+	\brief End an edit block
+*/
+void QDocumentCursor::endEditBlock()
+{
+	if ( m_handle )
+		m_handle->endEditBlock();
+}
+
+/*!
+	\return Whether the cursor is silent
+*/
+bool QDocumentCursor::isSilent() const
+{
+	return m_handle ? m_handle->isSilent() : true;
+}
+
+/*!
+	\brief Set whether the cursor is silent
+*/
+void QDocumentCursor::setSilent(bool y)
+{
+	if ( m_handle )
+		m_handle->setSilent(y);
+	
+}
+
+/*!
+	\return whether the cursor is auto updated
+	
+	An auto updated cursor will remain on the actual line it points
+	to when the document is modified.
+	
+	\code
+	QDocumentCursor c1(10, 0, document), c2(10, 0, document), c(5, 0, document);
+	
+	c1.setAutoUpdated(true);
+	
+	c.insertLine();
+	
+	// at this point c2 still points to line 10 whereas c1 points to line 11
+	\endcode
+*/
+bool QDocumentCursor::isAutoUpdated() const
+{
+	return m_handle ? m_handle->isAutoUpdated() : true;
+}
+
+/*!
+	\brief Set whether the cursor is aut updated
+*/
+void QDocumentCursor::setAutoUpdated(bool y)
+{
+	if ( m_handle )
+		m_handle->setAutoUpdated(y);
+	
+}
+
+/*!
+	\brief Refresh the column memory of the cursor
+	
+	This set the current column memory to the current column position.
+	
+	\note It is not recommended to call that yourself. The various
+	movement method should do that perfectly fine.
+*/
+void QDocumentCursor::refreshColumnMemory()
+{
+	if ( m_handle )
+		m_handle->refreshColumnMemory();
+	
+}
+
+/*!
+	\return Whether the cursor has column memory
+	
+	The column memory is a feature that allow a cursor
+	to remember its biggest column number so that moving
+	back and forth (with movePosition()) on lines of
+	different width does not result in the column to change.
+	
+*/
+bool QDocumentCursor::hasColumnMemory() const
+{
+	return m_handle ? m_handle->hasColumnMemory() : false;
+}
+
+/*!
+	\brief Set whether the cursor use column memory
+*/
+void QDocumentCursor::setColumnMemory(bool y)
+{
+	if ( m_handle )
+		m_handle->setColumnMemory(y);
+	
+}
+
+/*!
+	\return whether the cursor has a selection
+*/
+bool QDocumentCursor::hasSelection() const
+{
+	return m_handle ? m_handle->hasSelection() : false;
+}
+
+/*!
+	\brief clear the selection
+*/
+void QDocumentCursor::clearSelection()
+{
+	if ( m_handle )
+		m_handle->clearSelection();
+	
+}
+
+/*!
+	\brief Select something
+*/
+void QDocumentCursor::select(SelectionType t)
+{
+	if ( m_handle )
+		m_handle->select(t);
+	
+}
+
+/*!
+	\brief Set the selection boundary
+	
+	Select text between the current cursor anchor and the one
+	of \a c.
+	
+	\note We mean ANCHOR. If the cursor already has a selection the
+	anchor will not change, but the position will be set to that of
+	\a c.
+*/
+void QDocumentCursor::setSelectionBoundary(const QDocumentCursor& c)
+{
+	if ( m_handle )
+		m_handle->setSelectionBoundary(c);
+	
+}
+
+/*!
+	\return whether a given cursor is within the selection
+*/
+bool QDocumentCursor::isWithinSelection(const QDocumentCursor& c) const
+{
+	return m_handle ? m_handle->isWithinSelection(c) : false;
+}
+
+/*!
+	\return selection information
+	
+	\note The QDocumentSelection object is not updated if the selection
+	changes later on : use it right away and do not store it.
+*/
+QDocumentSelection QDocumentCursor::selection() const
+{
+	QDocumentSelection s;
+	
+	if ( isNull() || !hasSelection() )
+	{
+		qDebug("NULL selection");
+		
+		s.startLine = -1;
+		s.endLine = -1;
+		
+		s.start = -1;
+		s.end = -1;
+	} else if ( m_handle->m_begLine == m_handle->m_endLine ) {
+		
+		s.startLine = m_handle->m_begLine;
+		s.endLine = m_handle->m_begLine;
+		
+		s.start = qMin(m_handle->m_begOffset, m_handle->m_endOffset);
+		s.end = qMax(m_handle->m_begOffset, m_handle->m_endOffset);
+		
+	} else if ( m_handle->m_begLine > m_handle->m_endLine ) {
+		
+		s.startLine = m_handle->m_endLine;
+		s.endLine = m_handle->m_begLine;
+		
+		s.start = m_handle->m_endOffset;
+		s.end = m_handle->m_begOffset;
+		
+		//qDebug("[(%i,%i);(%i,%i)]", s.startLine.lineNumber(), s.start, s.endLine.lineNumber(), s.end);
+	} else {
+		s.startLine = m_handle->m_begLine;
+		s.endLine = m_handle->m_endLine;
+		
+		s.start = m_handle->m_begOffset;
+		s.end = m_handle->m_endOffset;
+		
+		//qDebug("[(%i,%i);(%i,%i)]", s.startLine.lineNumber(), s.start, s.endLine.lineNumber(), s.end);
+	}
+	
+	return s;
+}
+
+/*! @} */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocumentcursor.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QDOCUMENT_CURSOR_H_
+#define _QDOCUMENT_CURSOR_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qdocumentcursor.h
+	\brief Definition of the QDocumentCursor class
+*/
+
+class QChar;
+class QPoint;
+class QString;
+class QPolygon;
+
+class QDocument;
+class QDocumentLine;
+struct QDocumentSelection;
+class QDocumentCursorHandle;
+
+class QCE_EXPORT QDocumentCursor
+{
+	public:
+		enum MoveFlag
+		{
+			MoveAnchor	= 0,
+			KeepAnchor	= 1,
+			ThroughWrap	= 2
+		};
+		
+		Q_DECLARE_FLAGS(MoveMode, MoveFlag);
+		
+		enum MoveOperation
+		{
+			NoMove,
+			Up,
+			Down,
+			Left,
+			PreviousCharacter = Left,
+			Right,
+			NextCharacter = Right,
+			Start,
+			StartOfLine,
+			StartOfBlock = StartOfLine,
+			StartOfWord,
+			PreviousBlock,
+			PreviousLine = PreviousBlock,
+			PreviousWord,
+			WordLeft,
+			WordRight,
+			End,
+			EndOfLine,
+			EndOfBlock = EndOfLine,
+			EndOfWord,
+			NextWord,
+			NextBlock,
+			NextLine = NextBlock
+		};
+		
+		enum SelectionType
+		{
+			WordUnderCursor,
+			LineUnderCursor
+		};
+		
+		explicit QDocumentCursor(QDocument *doc);
+		QDocumentCursor(const QDocumentCursor& cursor);
+		QDocumentCursor(QDocument *doc, int line, int column = 0);
+		//QDocumentCursor(const QDocumentLine& line, int column = 0);
+		QDocumentCursor(QDocumentCursorHandle* handle = 0);
+		
+		~QDocumentCursor();
+		
+		QDocumentCursor clone() const;
+		
+		QDocumentCursor& operator = (const QDocumentCursor& c);
+		
+		bool operator == (const QDocumentCursor& c) const;
+		bool operator != (const QDocumentCursor& c) const;
+		
+		bool operator < (const QDocumentCursor& c) const;
+		bool operator > (const QDocumentCursor& c) const;
+		
+		bool operator <= (const QDocumentCursor& c) const;
+		bool operator >= (const QDocumentCursor& c) const;
+		
+		bool isNull() const;
+		bool isValid() const;
+		
+		bool atEnd() const;
+		bool atStart() const;
+		
+		bool atBlockEnd() const;
+		bool atBlockStart() const;
+		
+		bool atLineEnd() const;
+		bool atLineStart() const;
+		
+		bool hasSelection() const;
+		
+		bool isSilent() const;
+		void setSilent(bool y);
+		
+		bool isAutoUpdated() const;
+		void setAutoUpdated(bool y);
+		
+		int position() const;
+		
+		int lineNumber() const;
+		int columnNumber() const;
+		
+		int anchorLineNumber() const;
+		int anchorColumnNumber() const;
+		
+		int visualColumnNumber() const;
+		
+		void setColumnNumber(int c, MoveMode m = MoveAnchor);
+		
+		int wrappedLineOffset() const;
+		int anchorWrappedLineOffset() const;
+		
+		QPoint documentPosition() const;
+		QPoint anchorDocumentPosition() const;
+		
+		QPolygon documentRegion() const;
+		
+		QDocumentLine line() const;
+		QDocumentLine anchorLine() const;
+		
+		void shift(int offset);
+		void setPosition(int pos, MoveMode m = MoveAnchor);
+		bool movePosition(int offset, MoveOperation op = NextCharacter, MoveMode m = MoveAnchor);
+		
+		void moveTo(int line, int column);
+		void moveTo(const QDocumentCursor &c);
+		void moveTo(const QDocumentLine &l, int column);
+		
+		void eraseLine();
+		void insertLine(bool keepAnchor = false);
+		void insertText(const QString& s, bool keepAnchor = false);
+		
+		QDocumentCursor selectionStart() const;
+		QDocumentCursor selectionEnd() const;
+		
+		QString selectedText() const;
+		
+		void clearSelection();
+		void removeSelectedText();
+		void replaceSelectedText(const QString& text);
+		
+		void select(SelectionType t);
+		void setSelectionBoundary(const QDocumentCursor& c);
+		
+		bool isWithinSelection(const QDocumentCursor& c) const;
+		
+		QChar nextChar() const;
+		QChar previousChar() const;
+		
+		void deleteChar();
+		void deletePreviousChar();
+		
+		void beginEditBlock();
+		void endEditBlock();
+		
+		void refreshColumnMemory();
+		bool hasColumnMemory() const;
+		void setColumnMemory(bool y);
+		
+		QDocumentSelection selection() const;
+		
+		QDocument* document() const;
+		
+		inline QDocumentCursorHandle* handle() const
+		{ return m_handle; }
+		
+	private:
+		QDocumentCursorHandle *m_handle;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocumentcursor_p.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QDOCUMENT_CURSOR_P_H_
+#define _QDOCUMENT_CURSOR_P_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qdocumentcursor_p.h
+	\brief Definition of QDocumentCursorHandle
+*/
+
+#include "qdocumentcursor.h"
+
+#include <QStack>
+
+#if QT_VERSION < 0x040400
+#include <QAtomic>
+#else
+#include <QAtomicInt>
+#endif
+
+class QPoint;
+class QPolygon;
+
+class QDocument;
+class QDocumentLine;
+class QDocumentPrivate;
+class QDocumentCommand;
+class QDocumentCommandBlock;
+
+class QCE_EXPORT QDocumentCursorHandle
+{
+	friend class QDocumentCursor;
+	friend class QDocumentPrivate;
+	friend class QDocumentCommand;
+	
+	public:
+		enum Flags
+		{
+			Silent				= 1,
+			ColumnMemory		= 2,
+			MoveWithinWrapped	= 4
+		};
+
+		QDocument* document() const;
+		
+		bool atEnd() const;
+		bool atStart() const;
+		
+		bool atBlockEnd() const;
+		bool atBlockStart() const;
+		
+		bool atLineEnd() const;
+		bool atLineStart() const;
+		
+		bool hasSelection() const;
+		
+		bool isSilent() const;
+		void setSilent(bool y);
+		
+		bool isAutoUpdated() const;
+		void setAutoUpdated(bool y);
+		
+		QDocumentLine line() const;
+		QDocumentLine anchorLine() const;
+		
+		int lineNumber() const;
+		int columnNumber() const;
+		
+		int anchorLineNumber() const;
+		int anchorColumnNumber() const;
+		
+		int visualColumnNumber() const;
+		
+		void setColumnNumber(int c, int m = QDocumentCursor::MoveAnchor);
+		
+		QPoint documentPosition() const;
+		QPoint anchorDocumentPosition() const;
+		
+		QPolygon documentRegion() const;
+		
+		int position() const;
+		
+		void shift(int offset);
+		void setPosition(int pos, int m);
+		bool movePosition(int offset, int op, int m);
+		
+		void insertText(const QString& s, bool keepAnchor = false);
+		
+		QChar nextChar() const;
+		QChar previousChar() const;
+		
+		void eraseLine();
+		void deleteChar();
+		void deletePreviousChar();
+		
+		QDocumentCursor selectionStart() const;
+		QDocumentCursor selectionEnd() const;
+		
+		bool eq(const QDocumentCursorHandle *h);
+		bool lt(const QDocumentCursorHandle *h);
+		bool gt(const QDocumentCursorHandle *h);
+		
+		QString selectedText() const;
+		
+		void clearSelection();
+		void removeSelectedText(bool keepAnchor = false);
+		void replaceSelectedText(const QString& text);
+		
+		void select(QDocumentCursor::SelectionType t);
+		void setSelectionBoundary(const QDocumentCursor& c);
+		
+		bool isWithinSelection(const QDocumentCursor& c) const;
+		QDocumentCursor intersect(const QDocumentCursor& c) const;
+		
+		void beginBoundary(int& begline, int& begcol) const;
+		void endBoundary(int& endline, int& endcol) const;
+		void substractBoundaries(int lbeg, int cbeg, int lend, int cend);
+		void boundaries(int& begline, int& begcol, int& endline, int& endcol) const;
+		void intersectBoundaries(int& lbeg, int& cbeg, int& lend, int& cend) const;
+		void intersectBoundaries(QDocumentCursorHandle *h, int& lbeg, int& cbeg, int& lend, int& cend) const;
+		
+		void beginEditBlock();
+		void endEditBlock();
+		
+		void moveTo(int line, int column);
+		void moveTo(const QDocumentCursor &c);
+		
+		void copy(const QDocumentCursorHandle *c);
+		
+		void refreshColumnMemory();
+		bool hasColumnMemory() const;
+		void setColumnMemory(bool y);
+		
+		virtual void execute(QDocumentCommand *c);
+		
+		inline void ref() { m_ref.ref(); }
+		inline void deref() { if ( m_ref ) m_ref.deref(); if ( !m_ref ) delete this; }
+		
+		inline bool hasFlag(int f) const { return m_flags & f; }
+		inline void setFlag(int f) { m_flags |= f; }
+		inline void clearFlag(int f) { m_flags &= ~f; }
+		
+	protected:
+		QDocumentCursorHandle(QDocument *d, int line = 0);
+		virtual ~QDocumentCursorHandle();
+		
+		QDocumentCursorHandle* clone() const;
+		
+	private:
+		int m_flags;
+		QDocument *m_doc;
+#if QT_VERSION < 0x040400
+		QBasicAtomic m_ref;
+#else
+		QAtomicInt m_ref;
+#endif
+		int m_begOffset, m_endOffset, m_max, m_begLine, m_endLine;
+		QStack<QDocumentCommandBlock*> m_blocks;
+};
+
+Q_DECLARE_TYPEINFO(QDocumentCursorHandle*, Q_PRIMITIVE_TYPE);
+
+#endif // !_QDOCUMENT_CURSOR_P_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocumentline.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,602 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qdocumentline.h"
+
+/*!
+	\file qdocumentline.cpp
+	\brief Implementation of the QDocumentLine class.
+*/
+
+#include "qdocument_p.h"
+
+/*!
+	\ingroup document
+	@{
+*/
+
+/*!
+       \class QDocumentLine
+
+       \brief A reference to line objects
+
+       In QCodeEdit, documents are stored as a list of lines. A QDocumentLine holds
+       a pointer to the data of one line and gives access to its content.
+
+       It is not meant to be used to iterate over the document, though it is possible
+       for conveneience and compatibility reasons. Indeed, QDocumentLine does not now
+	   where in the document it is located. It can obtain that information but this is
+	   a O(n) operation. Navigation within the document is one of the task devoted to
+       QDocumentCursor which can move around in O(1) (or amortized O(1) in some rare
+	   cases).
+
+       Lines can be given formatting in various way : "regular" formatting used for
+       highlighting, overlays used mainly to display search matches and similar informations
+       and marks.
+*/
+
+QDocumentLine::QDocumentLine(QDocument *doc)
+ : m_handle(doc ? doc->impl()->at(0) : 0)
+{
+	//m_lines_backing_store << this;
+	
+	if ( m_handle )
+		m_handle->ref();
+	
+}
+
+QDocumentLine::QDocumentLine(const QDocumentLine& line)
+ : m_handle(line.m_handle)
+{
+	//m_lines_backing_store << this;
+	if ( m_handle )
+		m_handle->ref();
+	
+}
+
+QDocumentLine::QDocumentLine(QDocumentLineHandle* handle)
+ : m_handle(handle)
+{
+	//m_lines_backing_store << this;
+	if ( m_handle )
+		m_handle->ref();
+	
+}
+
+QDocumentLine::~QDocumentLine()
+{
+	if ( m_handle )
+		m_handle->deref();
+	
+	//m_lines_backing_store.removeAll(this);
+}
+
+/*!
+	\brief Comparision operator
+*/
+bool QDocumentLine::operator == (const QDocumentLine& l) const
+{
+	return m_handle == l.m_handle;
+	//return lineNumber() == l.lineNumber();
+}
+
+/*!
+	\brief Comparision operator
+*/
+bool QDocumentLine::operator != (const QDocumentLine& l) const
+{
+	return m_handle != l.m_handle;
+	//return lineNumber() != l.lineNumber();
+}
+
+/*!
+	\brief Comparision operator
+	
+	\note Line number based : avoid whenever possible
+*/
+bool QDocumentLine::operator < (const QDocumentLine& l) const
+{
+	return lineNumber() < l.lineNumber();
+}
+
+/*!
+	\brief Comparision operator
+	
+	\note Line number based : avoid whenever possible
+*/
+bool QDocumentLine::operator >= (const QDocumentLine& l) const
+{
+	return lineNumber() >= l.lineNumber();
+}
+
+/*!
+	\brief Comparision operator
+	
+	\note Line number based : avoid whenever possible
+*/
+bool QDocumentLine::operator > (const QDocumentLine& l) const
+{
+	return lineNumber() > l.lineNumber();
+}
+
+/*!
+	\brief Comparision operator
+	
+	\note Line number based : avoid whenever possible
+*/
+bool QDocumentLine::operator <= (const QDocumentLine& l) const
+{
+	return lineNumber() <= l.lineNumber();
+}
+
+/*!
+	\brief Iterate forward over the document
+*/
+QDocumentLine& QDocumentLine::operator ++ ()
+{
+	operator = (next());
+	return *this;
+}
+
+/*!
+	\brief Iterate backward over the document
+*/
+QDocumentLine& QDocumentLine::operator -- ()
+{
+	operator = (previous());
+	return *this;
+}
+
+/*!
+	\brief Iterate forward over the document
+*/
+void QDocumentLine::operator ++ (int)
+{
+	operator = (next());
+}
+
+/*!
+	\brief Iterate backward over the document
+*/
+void QDocumentLine::operator -- (int)
+{
+	operator = (previous());
+}
+
+/*!
+	\brief copy operator
+	
+	QDocumentLine objects are just wrappers around the "real" line data.
+	Copies of a QDocumentLine all points to the same underlying data and
+	modifying one affect them all (no implicit sharing).
+*/
+QDocumentLine& QDocumentLine::operator = (const QDocumentLine& l)
+{
+	if ( m_handle )
+		m_handle->deref();
+	
+	m_handle = l.m_handle;
+	
+	if ( m_handle )
+		m_handle->ref();
+	
+	return *this;
+}
+
+/*!
+	\return the document to which that line belongs
+*/
+QDocument* QDocumentLine::document() const
+{
+	return m_handle ? m_handle->document() : 0;
+}
+
+/*!
+	\return the line number of the line within the document
+	
+	Starts at 0, -1 for invalid lines.
+	
+	\note Avoid whenever possible : O(n) complexity, n being document size in lines
+	Prefer cursors over lines if you need to navigate within the document
+*/
+int QDocumentLine::lineNumber() const
+{
+	return m_handle ? m_handle->line() : -1;
+}
+
+/*!
+	\return the position of the line within the document
+	
+	\note This function is there for compatibility with QTextDocument & co
+	Avoid it whenever possible, it is ridiculously slow.
+*/
+int QDocumentLine::position() const
+{
+	return m_handle ? m_handle->position() : -1;
+}
+
+/*!
+	\brief Check whether a given flag is set to the line
+*/
+bool QDocumentLine::hasFlag(State s) const
+{
+	return m_handle ? m_handle->hasFlag(s) : false;
+}
+
+/*!
+	\brief Check whether any of the flags in a given combination is set to the line
+*/
+bool QDocumentLine::hasAnyFlag(int s) const
+{
+	return m_handle ? m_handle->hasFlag(s) : false;
+}
+
+/*!
+	\brief Set a flag of the line
+	
+	\warning Do not mess with flags unless you know what you are doing
+*/
+void QDocumentLine::setFlag(State s, bool y)
+{
+	if ( m_handle )
+		m_handle->setFlag(s, y);
+	
+}
+
+/*!
+	\return whether the line object is null (i.e invalid)
+*/
+bool QDocumentLine::isNull() const
+{
+	return m_handle ? !m_handle->document() : true;
+}
+
+/*!
+	\return whether the line object is valid
+*/
+bool QDocumentLine::isValid() const
+{
+	return m_handle ? m_handle->document() : false;
+}
+
+/*!
+	\return the text of the line
+*/
+QString QDocumentLine::text() const
+{
+	return m_handle ? m_handle->text() : QString();
+}
+
+/*!
+	\return The length of the line, in characters
+*/
+int QDocumentLine::length() const
+{
+	return m_handle ? m_handle->text().length() : 0;
+}
+
+/*!
+	\return the number of visual lines occupied by the line
+	
+	This is NOT set to zero when the line is hidden (e.g due to folding).
+*/
+int QDocumentLine::lineSpan() const
+{
+	return m_handle && m_handle->document() ? m_handle->m_frontiers.count() + 1 : 0;
+}
+
+/*!
+	\brief Returns the position of the first non-whitespace character
+	\return position of first non-whitespace char or -1 if there is none
+*/
+int QDocumentLine::firstChar() const
+{
+	return nextNonSpaceChar(0);
+}
+
+/*!
+	\brief Returns the position of the last non-whitespace character
+	\return position of last non-whitespace char or -1 if there is none
+*/
+int QDocumentLine::lastChar() const
+{
+	return previousNonSpaceChar(length() - 1);
+}
+
+int QDocumentLine::indent() const
+{
+	return m_handle ? m_handle->indent() : 0;
+}
+
+/*!
+	Find the position of the next char that is not a space.
+	\param pos Column of the character which is examined first.
+	\return True if the specified or a following character is not a space
+	Otherwise false.
+*/
+int QDocumentLine::nextNonSpaceChar(int pos) const
+{
+	return m_handle ? m_handle->nextNonSpaceChar(pos) : -1;
+}
+
+/*!
+	\brief Find the position of the previous char that is not a space.
+	\param pos Column of the character which is examined first.
+	\return The position of the first non-whitespace character preceding pos,
+   or -1 if none is found.
+*/
+int QDocumentLine::previousNonSpaceChar(int pos) const
+{
+	return m_handle ? m_handle->previousNonSpaceChar(pos) : -1;
+}
+
+/*!
+	\return The previous line
+	
+	\note Avoid using this function whenever possible, especially
+	inside loops or time-consuming processing : it is SLOW for big
+	documents as determination of the line number is O(n), n being
+	the total number of lines in the document
+*/
+QDocumentLine QDocumentLine::next() const
+{
+	return QDocumentLine(m_handle->next());
+}
+
+/*!
+	\return The next line
+	
+	\note Avoid using this function whenever possible, especially
+	inside loops or time-consuming processing : it is SLOW for big
+	documents as determination of the line number is O(n), n being
+	the total number of lines in the document
+*/
+QDocumentLine QDocumentLine::previous() const
+{
+	return QDocumentLine(m_handle->previous());
+}
+
+/*!
+	\brief Converts a cursor position (column) to a document position (unconstrained viewport)
+	
+	\deprecated Use cursorToDocOffset() instead
+	
+	This function is kept for compatribility only. It dates back to the time before line wrapping
+	was implemented. Due to the limitation of its design (i.e signature) it works in a somewhat
+	awkard way : the x position returned is that the cursor would have in an unconstrained viewport,
+	even when the line is wrapped so it does not map to an actual viewport coordinate, unless of
+	course no wrapping is used.
+*/
+int QDocumentLine::cursorToX(int cpos) const
+{
+	return m_handle ? m_handle->cursorToX(cpos) : -1;
+}
+
+/*!
+	\brief Converts a document position (unconstrained viewport) to a cursor position (column)
+	
+	\deprecated Use cursorToDocOffset() instead
+	
+	\see cursorToX() for more informations about this function
+*/
+int QDocumentLine::xToCursor(int xpos) const
+{
+	return m_handle ? m_handle->xToCursor(xpos) : -1;
+}
+
+/*!
+	\return The wrapped line (i.e "subline") to which a given cursor position resides
+	\param cpos cursor position, as a text column
+*/
+int QDocumentLine::wrappedLineForCursor(int cpos) const
+{
+	return m_handle ? m_handle->wrappedLineForCursor(cpos) : -1;
+}
+
+/*!
+	\brief Converts a document offset (viewport) to a cursor position (character / text column)
+	
+	The (x, y) coordinates given by this function are relative to the absolute
+	position of the line, which can be obtained from the document.
+*/
+int QDocumentLine::documentOffsetToCursor(int x, int y) const
+{
+	return m_handle ? m_handle->documentOffsetToCursor(x, y) : -1;
+}
+
+/*!
+	\brief Converts a cursor position (character / text column) to a document offset (viewport)
+	
+	The (x, y) coordinates given by this function are relative to the absolute
+	position of the line, which can be obtained from the document.
+*/
+void QDocumentLine::cursorToDocumentOffset(int cpos, int& x, int& y) const
+{
+	if ( m_handle )
+		m_handle->cursorToDocumentOffset(cpos, x, y);
+}
+
+/*!
+	\overload
+*/
+QPoint QDocumentLine::cursorToDocumentOffset(int cpos) const
+{
+	return m_handle ? m_handle->cursorToDocumentOffset(cpos) : QPoint();
+}
+
+/*!
+	\brief Toggle a mark on the line
+*/
+void QDocumentLine::addMark(int id)
+{
+	if ( !document() )
+		return;
+	
+	document()->impl()->addMark(m_handle, id);
+}
+
+/*!
+	\brief Toggle a mark on the line
+*/
+void QDocumentLine::toggleMark(int id)
+{
+	if ( !document() )
+		return;
+	
+	document()->impl()->toggleMark(m_handle, id);
+}
+
+/*!
+	\brief Remove a mark from the line
+*/
+void QDocumentLine::removeMark(int id)
+{
+	if ( !document() )
+		return;
+	
+	document()->impl()->removeMark(m_handle, id);
+}
+
+/*!
+	\return the list of marks set on this line
+*/
+QList<int> QDocumentLine::marks() const
+{
+	return document() ? document()->impl()->marks(m_handle) : QList<int>();
+}
+
+/*!
+	\return Whether a given mark has been set on the line
+*/
+bool QDocumentLine::hasMark(int id) const
+{
+	return marks().contains(id);
+}
+
+/*!
+	\brief Set the formatting of the line
+	
+	\note this method is made available for syntax engine use.
+	If you want to apply extra formatting on a line use overlays
+	instead
+	
+	\see addOverlay()
+*/
+void QDocumentLine::setFormats(const QVector<int>& formats)
+{
+	if ( !m_handle )
+		return;
+	
+	m_handle->setFormats(formats);
+}
+
+/*!
+	\return whether the line has at least one overlay of a given format id
+*/
+bool QDocumentLine::hasOverlay(int fid) const
+{
+	if ( !m_handle )
+		return false;
+	
+	foreach ( const QFormatRange& r, m_handle->m_overlays )
+		if ( r.format == fid )
+			return true;
+	
+	return false;
+}
+
+/*!
+	\brief Clear all overlays applied to the line
+*/
+QList<QFormatRange> QDocumentLine::overlays() const
+{
+	if ( !m_handle )
+		return QList<QFormatRange>();
+	
+	return m_handle->m_overlays;
+}
+
+/*!
+	\brief Clear all overlays applied to the line
+*/
+void QDocumentLine::clearOverlays()
+{
+	if ( !m_handle )
+		return;
+	
+	m_handle->clearOverlays();
+}
+
+/*!
+	\brief Add an overlay to the line
+	
+	Overlays are format range that get applied on top of regular formatting.
+	
+	They are typically used to display search matches, matching braces, ...
+*/
+void QDocumentLine::addOverlay(const QFormatRange& over)
+{
+	if ( !m_handle )
+		return;
+	
+	m_handle->addOverlay(over);
+}
+
+/*!
+	\brief Remove an overlay from the line
+*/
+void QDocumentLine::removeOverlay(const QFormatRange& over)
+{
+	if ( !m_handle )
+		return;
+	
+	m_handle->removeOverlay(over);
+}
+
+/*!
+	\return the list of parentheses present on the line
+	
+	\note This is language dependent.
+*/
+const QVector<QParenthesis>& QDocumentLine::parentheses() const
+{
+	Q_CHECK_PTR(m_handle);
+	
+	return m_handle->m_parens;
+}
+
+/*!
+	\brief Set the parentheses present on that line
+	
+	\note this should only be used by syntax engines
+*/
+void QDocumentLine::setParentheses(const QVector<QParenthesis>& parentheses)
+{
+	if ( !m_handle )
+		return;
+	
+	m_handle->m_parens = parentheses;
+}
+
+/*!
+	Reserved to syntax engines. do not mess with this unless you know what you are doing.
+*/
+QNFAMatchContext* QDocumentLine::matchContext()
+{
+	return m_handle ? &m_handle->m_context : 0;
+}
+
+/*! @} */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocumentline.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QDOCUMENT_LINE_H_
+#define _QDOCUMENT_LINE_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qdocumentline.h
+	\brief Definition of the QDocumentLine class
+*/
+
+#include "qformat.h"
+
+class QPoint;
+class QString;
+
+class QDocument;
+class QDocumentLineHandle;
+
+struct QNFAMatchContext;
+
+struct QParenthesis
+{
+	enum Role
+	{
+		Open		= 1,
+		Close		= 2,
+		Indent		= 4,
+		Fold		= 8,
+		Match		= 16
+	};
+	
+	inline QParenthesis()
+	 : id(0), role(0), offset(0), length(0)
+	{}
+	
+	inline QParenthesis(int i, quint8 r, int pos, int len)
+	 : id(i), role(r), offset(pos), length(len)
+	{}
+	
+	int id;
+	int role;
+	int offset;
+	int length;
+};
+
+Q_DECLARE_TYPEINFO(QParenthesis, Q_MOVABLE_TYPE);
+
+class QCE_EXPORT QDocumentLine
+{
+	friend class QDocumentLineHandle;
+	friend class QDocumentCursorHandle;
+	
+	public:
+		enum State
+		{
+			None				= 0,
+			Hidden				= 1,
+			CollapsedBlockStart	= 2,
+			CollapsedBlockEnd	= 4,
+			
+			LayoutDirty			= 16,
+			FormatsApplied		= 32
+		};
+		
+		Q_DECLARE_FLAGS(States, State);
+		
+		explicit QDocumentLine(QDocument *doc);
+		QDocumentLine(const QDocumentLine& line);
+		QDocumentLine(QDocumentLineHandle *h = 0);
+		
+		~QDocumentLine();
+		
+		bool isNull() const;
+		bool isValid() const;
+		
+		inline bool operator == (const QDocumentLineHandle* h) const
+		{
+			return m_handle == h;
+		}
+		
+		inline bool operator != (const QDocumentLineHandle* h) const
+		{
+			return m_handle != h;
+		}
+		
+		bool operator == (const QDocumentLine& l) const;
+		bool operator != (const QDocumentLine& l) const;
+		
+		bool operator < (const QDocumentLine& l) const;
+		bool operator >= (const QDocumentLine& l) const;
+		
+		bool operator > (const QDocumentLine& l) const;
+		bool operator <= (const QDocumentLine& l) const;
+		
+		QDocumentLine& operator ++ ();
+		QDocumentLine& operator -- ();
+		
+		void operator ++ (int);
+		void operator -- (int);
+		
+		QDocumentLine& operator = (const QDocumentLine& l);
+		
+		int lineNumber() const;
+		int position() const;
+		
+		QString text() const;
+		
+		int length() const;
+		int lineSpan() const;
+		
+		int firstChar() const;
+		int lastChar() const;
+		
+		int indent() const;
+		
+		int nextNonSpaceChar(int pos) const;
+		int previousNonSpaceChar(int pos) const;
+
+		inline QString indentation() const
+		{ int idx = firstChar(); return idx != -1 ? text().left(idx) : text(); }
+		
+		inline bool isHidden() const
+		{ return hasFlag(Hidden); }
+		
+		bool hasFlag(State s) const;
+		bool hasAnyFlag(int s) const;
+		void setFlag(State s, bool y = true);
+		
+		QDocumentLine next() const;
+		QDocumentLine previous() const;
+		
+		QDocument* document() const;
+		
+		int xToCursor(int x) const;
+		int cursorToX(int cpos) const;
+		
+		int wrappedLineForCursor(int cpos) const;
+		
+		int documentOffsetToCursor(int x, int y) const;
+		void cursorToDocumentOffset(int cpos, int& x, int& y) const;
+		
+		QPoint cursorToDocumentOffset(int cpos) const;
+		
+		void addMark(int id);
+		void removeMark(int id);
+		void toggleMark(int id);
+		
+		QList<int> marks() const;
+		bool hasMark(int id) const;
+		
+		bool hasOverlay(int fid) const;
+		QList<QFormatRange> overlays() const;
+		
+		void clearOverlays();
+		void addOverlay(const QFormatRange& over);
+		void removeOverlay(const QFormatRange& over);
+		
+		void setFormats(const QVector<int>& formats);
+		
+		const QVector<QParenthesis>& parentheses() const;
+		void setParentheses(const QVector<QParenthesis>& parentheses);
+		
+		inline QDocumentLineHandle* handle() const
+		{ return m_handle; }
+		
+		QNFAMatchContext* matchContext();
+		
+	private:
+		QDocumentLineHandle *m_handle;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDocumentLine::States)
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocumentline_p.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QDOCUMENT_LINE_P_H_
+#define _QDOCUMENT_LINE_P_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qdocumentline_p.h
+	\brief Definition of QDocumentLineHandle
+*/
+
+#include "qnfa.h"
+
+#include "qformat.h"
+
+#include "qdocumentline.h"
+
+#include <QPair>
+#include <QList>
+#include <QString>
+#include <QVector>
+
+#include <QTextLayout>
+
+#if QT_VERSION < 0x040400
+#include <QAtomic>
+#else
+#include <QAtomicInt>
+#endif
+
+typedef QVector<int> QSmallArray;
+typedef QVector<int> QMediumArray;
+
+class QPoint;
+
+class QDocument;
+class QDocumentLine;
+class QDocumentBuffer;
+class QDocumentPrivate;
+
+class QCE_EXPORT QDocumentLineHandle
+{
+	friend class QDocument;
+	friend class QDocumentLine;
+	friend class QDocumentBuffer;
+	friend class QDocumentPrivate;
+	
+	public:
+		QDocumentLineHandle(QDocument *d);
+		QDocumentLineHandle(const QString& s, QDocument *d);
+		
+		int count() const;
+		int length() const;
+		
+		int position() const;
+		
+		QString text() const;
+		
+		int line() const;
+		
+		int xToCursor(int x) const;
+		int cursorToX(int i) const;
+		
+		int wrappedLineForCursor(int cpos) const;
+		
+		int documentOffsetToCursor(int x, int y) const;
+		void cursorToDocumentOffset(int cpos, int& x, int& y) const;
+		
+		QPoint cursorToDocumentOffset(int cpos) const;
+		
+		int indent() const;
+		
+		int nextNonSpaceChar(uint pos) const;
+		int previousNonSpaceChar(int pos) const;
+		
+		bool hasFlag(int flag) const;
+		void setFlag(int flag, bool y = true) const;
+		
+		QDocument* document() const;
+		
+		QDocumentLineHandle* next() const;
+		QDocumentLineHandle* previous() const;
+		
+		void updateWrap() const;
+		
+		void setFormats(const QVector<int>& formats);
+		
+		void clearOverlays();
+		void addOverlay(const QFormatRange& over);
+		void removeOverlay(const QFormatRange& over);
+		
+		void shiftOverlays(int position, int offset);
+		
+		void draw(	QPainter *p,
+					int xOffset,
+					int vWidth,
+					const QSmallArray& sel,
+					const QSmallArray& cursors,
+					const QPalette& pal,
+					bool fullSel) const;
+		
+		inline QString& textBuffer() { setFlag(QDocumentLine::LayoutDirty, true); return m_text; }
+		
+		inline void ref() { m_ref.ref(); }
+		inline void deref() { if ( m_ref ) m_ref.deref(); if ( !m_ref ) delete this; }
+		
+	protected:
+		~QDocumentLineHandle();
+		
+	private:
+		void layout() const;
+		void applyOverlays() const;
+		
+		QMediumArray compose() const;
+		QList<QTextLayout::FormatRange> decorations() const;
+		
+		QString m_text;
+		QDocument *m_doc;
+#if QT_VERSION < 0x040400
+		QBasicAtomic m_ref;
+#else
+		QAtomicInt m_ref;
+#endif
+		mutable int m_indent;
+		mutable quint16 m_state;
+		mutable QTextLayout *m_layout;
+		mutable QVector<int> m_cache;
+		mutable QVector< QPair<int, int> > m_frontiers;
+		
+		QNFAMatchContext m_context;
+		
+		QVector<int> m_formats;
+		QVector<QParenthesis> m_parens;
+		QList<QFormatRange> m_overlays;
+};
+
+Q_DECLARE_TYPEINFO(QDocumentLineHandle*, Q_PRIMITIVE_TYPE);
+
+#endif // !_QDOCUMENT_LINE_P_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocumentsearch.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,663 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+/*!
+	\file qdocumentsearch.cpp
+	\brief Implementation of QDocumentSearch
+*/
+
+#include "qdocumentsearch.h"
+
+/*!
+	\ingroup document
+	@{
+*/
+
+#include "qeditor.h"
+#include "qdocument.h"
+#include "qdocument_p.h"
+#include "qdocumentline.h"
+#include "qformatscheme.h"
+
+#include <QMessageBox>
+
+/*!
+	\class QDocumentSearch
+	\brief An helper class to perform search in document
+	
+	QDocumentSearch offer means to perform complex search in documents.
+*/
+
+QDocumentSearch::QDocumentSearch(QEditor *e, const QString& f, Options opt, const QString& r)
+ : m_group(-1), m_option(opt), m_string(f), m_replace(r), m_editor(e)
+{
+	
+}
+
+QDocumentSearch::~QDocumentSearch()
+{
+	clearMatches();
+}
+
+QDocumentSearch::Options QDocumentSearch::options() const
+{
+	return m_option;
+}
+
+/*!
+	\brief Position of the current match among the indexed matches
+*/
+int QDocumentSearch::currentMatchIndex() const
+{
+	return m_highlight.count() ? m_index : -1;
+}
+
+/*!
+	\brief Number of availables indexed matches
+	
+	Indexed matches are only available when the whole scope is searched,
+	i.e when either the HighlightAll option is set to true or when next()
+	is called with the all parameter set to true.
+*/
+int QDocumentSearch::indexedMatchCount() const
+{
+	return m_highlight.count();
+}
+
+/*!
+	\return A cursor pointing to the n-th index match
+	\param idx index of the match to lookup
+	
+	The cursor returned, if valid, delimits the match through its selection.
+*/
+QDocumentCursor QDocumentSearch::match(int idx) const
+{
+	return idx >= 0 && idx < m_highlight.count() ? m_highlight.at(idx) : QDocumentCursor();
+}
+
+/*!
+	\brief Clear matches
+	
+	This function should be called anytime you perform a search with the HighlightAll option,
+	once you're done iterating over the matches.
+*/
+void QDocumentSearch::clearMatches()
+{
+	if ( !m_editor || !m_editor->document() )
+		return;
+	
+	//qDebug("clearing matches");
+	m_cursor = QDocumentCursor();
+	
+	if ( m_group != -1 )
+	{
+		m_editor->document()->clearMatches(m_group);
+		m_editor->document()->flushMatches(m_group);
+		m_group = -1;
+	}
+	
+	m_highlight.clear();
+}
+
+/*!
+	\return The search pattern
+*/
+QString QDocumentSearch::searchText() const
+{
+	return m_string;
+}
+
+/*!
+	\brief Set the search pattern
+*/
+void QDocumentSearch::setSearchText(const QString& f)
+{
+	m_string = f;
+	
+	clearMatches();
+}
+
+/*!
+	\brief Test whether a given option is enabled
+*/
+bool QDocumentSearch::hasOption(Option opt) const
+{
+	return m_option & opt;
+}
+
+/*!
+	\brief Set a search option
+	\param opt option to set
+	\param on whether to enable the option
+*/
+void QDocumentSearch::setOption(Option opt, bool on)
+{
+	if ( on )
+		m_option |= opt;
+	else
+		m_option &= ~opt;
+	
+	if ( (opt & QDocumentSearch::HighlightAll) && m_highlight.count() )
+	{
+		QDocument *d = m_editor->document();
+		
+		if ( m_group != -1 && !on )
+		{
+			d->clearMatches(m_group);
+			d->flushMatches(m_group);
+			m_group = -1;
+		} else if ( m_group == -1 && on ) {
+			m_group = d->getNextGroupId();
+			
+			QFormatScheme *f = d->formatScheme();
+			
+			if ( !f )
+				f = QDocument::formatFactory();
+			
+			if ( !f )
+			{
+				qWarning("No format scheme set to the document and no global default one available.\n"
+						"-> highlighting of search matches disabled.");
+				return;
+			}
+			
+			int sid = f->id("search");
+			
+			foreach ( const QDocumentCursor& c, m_highlight )
+			{
+				//QFormatRange r(c.anchorColumnNumber(), c.columnNumber() - c.anchorColumnNumber(), sid);
+				
+				d->addMatch(m_group,
+							c.lineNumber(),
+							c.anchorColumnNumber(),
+							c.columnNumber() - c.anchorColumnNumber(),
+							sid);
+			}
+			
+			//qDebug("%i matches in group %i", indexedMatchCount(), m_group);
+			d->flushMatches(m_group);
+		}
+	} else if (
+					(m_option & QDocumentSearch::HighlightAll)
+				&&
+					(
+						(opt & QDocumentSearch::RegExp)
+					||
+						(opt & QDocumentSearch::WholeWords)
+					||
+						(opt & QDocumentSearch::CaseSensitive)
+					)
+			)
+	{
+		// matches may have become invalid : update them
+		clearMatches();
+		next(false);
+	}
+}
+
+/*!
+	\return the replacement text
+*/
+QString QDocumentSearch::replaceText() const
+{
+	return m_replace;
+}
+
+/*!
+	\brief Set the replacement text
+*/
+void QDocumentSearch::setReplaceText(const QString& r)
+{
+	m_replace = r;
+	
+	clearMatches();
+}
+
+/*!
+	\return The current cursor position
+	
+	This is useful to examine matches after performing a search.
+*/
+QDocumentCursor QDocumentSearch::origin() const
+{
+	return m_origin;
+}
+
+/*!
+	\brief Set the cursor
+	
+	If the related option is set, search will start from that cursor position
+	
+	This also changes the cursor()
+*/
+void QDocumentSearch::setOrigin(const QDocumentCursor& c)
+{
+	m_cursor = QDocumentCursor();
+	
+	if ( c == m_origin )
+		return;
+	
+	m_origin = c;
+	
+	clearMatches();
+}
+
+/*!
+	\return The current cursor position
+	
+	This is useful to examine matches after performing a search.
+*/
+QDocumentCursor QDocumentSearch::cursor() const
+{
+	return m_cursor;
+}
+
+/*!
+	\brief Set the cursor
+	
+	If the related option is set, search will start from that cursor position
+*/
+void QDocumentSearch::setCursor(const QDocumentCursor& c)
+{
+	m_cursor = c;
+}
+
+/*!
+	\return The scope of the search
+	
+	An invalid cursor indicate that the scope is the whole document, otherwise
+	the scope is the selection of the returned cursor.
+*/
+QDocumentCursor QDocumentSearch::scope() const
+{
+	return m_scope;
+}
+
+/*!
+	\brief Set the search scope
+	
+	If the given cursor has no selection (a fortiori if it is invalid) then
+	the scope is the whole document.
+*/
+void QDocumentSearch::setScope(const QDocumentCursor& c)
+{
+	if ( c == m_scope )
+		return;
+	
+	if ( c.hasSelection() )
+		m_scope = c;
+	else
+		m_scope = QDocumentCursor();
+	
+	clearMatches();
+}
+
+/*!
+	\brief Test whether the end of the search scope has been reached
+*/
+bool QDocumentSearch::end(bool backward) const
+{
+	bool absEnd = backward ? m_cursor.atStart() : m_cursor.atEnd();
+	
+	if ( m_scope.isValid() && m_scope.hasSelection() )
+	{
+		absEnd |= !m_scope.isWithinSelection(m_cursor);
+		/*
+		qDebug(
+				"(%i, %i, %i) %s in {(%i, %i), (%i, %i)}",
+				m_cursor.lineNumber(),
+				m_cursor.anchorColumnNumber(),
+				m_cursor.columnNumber(),
+				absEnd ? "is not" : "is",
+				m_scope.selectionStart().lineNumber(),
+				m_scope.selectionStart().columnNumber(),
+				m_scope.selectionEnd().lineNumber(),
+				m_scope.selectionEnd().columnNumber()
+			);
+		*/
+	}
+	
+	return absEnd;
+}
+
+/*!
+	\brief Perform a search
+	\param backward whether to go backward or forward
+	\param all if true, the whole document will be searched first, all matches recorded and available for further navigation
+	
+	\note Technically speaking the all parameter make search behave similarly to the HighlightAll option, except that the former
+	option does not alter the formatting of the document.
+*/
+void QDocumentSearch::next(bool backward, bool all)
+{
+	if ( m_string.isEmpty() )
+		return;
+	
+	if ( !hasOption(Replace) && (all || hasOption(HighlightAll)) && m_highlight.count() )
+	{
+		if ( !backward )
+			++m_index;
+		
+		//m_index = m_index + (backward ? -1 : 1);
+		
+		if ( (m_index < 0 || m_index >= m_highlight.count()) )
+		{
+			if ( hasOption(Silent) )
+			{
+				m_cursor = QDocumentCursor();
+				return;
+			}
+			
+			int ret = 
+			QMessageBox::question(
+							m_editor,
+							tr("Failure"),
+							tr(
+								"End of matches reached.\n"
+								"Restart from the begining ?"
+							),
+							QMessageBox::Yes
+							| QMessageBox::No,
+							QMessageBox::Yes
+						);
+			
+			if ( ret == QMessageBox::Yes )
+			{
+				m_index = backward ? m_highlight.count() : 0;
+				--m_index;
+				next(backward);
+				return;
+			}
+		} else {
+			m_cursor = m_highlight.at(m_index);
+			
+			if ( m_editor && !hasOption(Silent) )
+				m_editor->setCursor(m_cursor);
+		}
+		
+		if ( backward )
+			--m_index;
+		
+		return;
+	}
+	
+	if ( m_cursor.isNull() )
+	{
+		m_cursor = m_origin;
+	}
+	
+	if ( m_cursor.isNull() )
+	{
+		if ( m_scope.isValid() && m_scope.hasSelection() )
+		{
+			if ( backward )
+				m_cursor = m_scope.selectionEnd();
+			else
+				m_cursor = m_scope.selectionStart();
+		} else if ( m_editor ) {
+			
+			m_cursor = QDocumentCursor(m_editor->document());
+			
+			if ( backward )
+				m_cursor.movePosition(1, QDocumentCursor::End);
+			
+		} else {
+			QMessageBox::warning(0, 0, "Unable to perform search operation");
+		}
+	}
+	
+	/*
+	qDebug(
+		"searching %s from line %i (column %i)",
+		backward ? "backward" : "forward",
+		m_cursor.lineNumber(),
+		m_cursor.columnNumber()
+	);
+	*/
+	
+	m_index = 0;
+	QRegExp m_regexp;
+	Qt::CaseSensitivity cs = hasOption(CaseSensitive)
+								?
+									Qt::CaseSensitive
+								:
+									Qt::CaseInsensitive;
+	
+	if ( hasOption(RegExp) )
+	{
+		m_regexp = QRegExp(m_string, cs, QRegExp::RegExp);
+	} else if ( hasOption(WholeWords) ) {
+		m_regexp = QRegExp(
+						QString("\\b%1\\b").arg(QRegExp::escape(m_string)),
+						cs,
+						QRegExp::RegExp
+					);
+	} else {
+		m_regexp = QRegExp(m_string, cs, QRegExp::FixedString);
+	}
+	
+	bool found = false;
+	QDocumentCursor::MoveOperation move;
+	QDocument *d = m_editor ? m_editor->document() : m_origin.document();
+	QFormatScheme *f = d->formatScheme() ? d->formatScheme() : QDocument::formatFactory();
+	int sid = f ? f->id("search") : 0;
+	
+	if ( !sid )
+		qWarning("Highlighting of search matches disabled due to unavailability of a format scheme.");
+	
+	move = backward ? QDocumentCursor::PreviousBlock : QDocumentCursor::NextBlock;
+	
+	QDocumentSelection boundaries;
+	bool bounded = m_scope.isValid() && m_scope.hasSelection();
+	
+	// condition only to avoid debug messages...
+	if ( bounded )
+		boundaries = m_scope.selection();
+	
+	while ( !end(backward) )
+	{
+		if ( backward && !m_cursor.columnNumber() )
+		{
+			m_cursor.movePosition(1, QDocumentCursor::PreviousCharacter);
+			continue;
+		}
+		
+		int ln = m_cursor.lineNumber();
+		QDocumentLine l = m_cursor.line();
+		
+		int coloffset = 0;
+		QString s = l.text();
+		
+		if ( backward )
+		{
+			if ( bounded && (boundaries.startLine == ln) )
+			{
+				s = s.mid(boundaries.start);
+				coloffset = boundaries.start;
+			}
+			
+			s = s.left(m_cursor.columnNumber());
+		} else {
+			if ( bounded && (boundaries.endLine == ln) )
+				s = s.left(boundaries.end);
+			
+		}
+		
+		int column = backward
+				?
+					m_regexp.lastIndexIn(s, m_cursor.columnNumber() - 1)
+				:
+					m_regexp.indexIn(s, m_cursor.columnNumber())
+				;
+		
+		/*
+		qDebug("searching %s in %s => %i",
+				qPrintable(m_regexp.pattern()),
+				qPrintable(s),
+				column);
+		*/
+		
+		if ( column != -1 && (backward || column >= m_cursor.columnNumber()) )
+		{
+			column += coloffset;
+			
+			if ( backward )
+			{
+				m_cursor.setColumnNumber(column + m_regexp.matchedLength());
+				m_cursor.setColumnNumber(column, QDocumentCursor::KeepAnchor);
+				
+				/*
+				m_cursor.movePosition(m_regexp.matchedLength(),
+									QDocumentCursor::PreviousCharacter,
+									QDocumentCursor::KeepAnchor);
+				*/
+			} else {
+				m_cursor.setColumnNumber(column);
+				m_cursor.setColumnNumber(column + m_regexp.matchedLength(), QDocumentCursor::KeepAnchor);
+				
+				/*
+				m_cursor.movePosition(m_regexp.matchedLength(),
+									QDocumentCursor::NextCharacter,
+									QDocumentCursor::KeepAnchor);
+				*/
+			}
+			
+			if ( m_editor && !hasOption(Silent) && !hasOption(HighlightAll) )
+				m_editor->setCursor(m_cursor);
+			
+			if ( hasOption(Replace) )
+			{
+				bool rep = true;
+				
+				if ( hasOption(Prompt) )
+				{
+					int ret = QMessageBox::question(m_editor, tr("Replacement prompt"),
+										tr("Shall it be replaced?"),
+										QMessageBox::Yes
+										| QMessageBox::No
+										| QMessageBox::Cancel,
+										QMessageBox::Yes);
+					
+					if ( ret == QMessageBox::Yes )
+					{
+						rep = true;
+					} else if ( ret == QMessageBox::No ) {
+						rep = false;
+					} else if ( QMessageBox::Cancel ) {
+						//m_cursor.setColumnNumber(m_cursor.columnNumber());
+						return;
+					}
+				}
+				
+				//
+				if ( rep )
+				{
+					QString replacement = m_replace;
+					
+					for ( int i = m_regexp.numCaptures(); i >= 0; --i )
+						replacement.replace(QString("\\") + QString::number(i),
+											m_regexp.cap(i));
+					
+					m_cursor.beginEditBlock();
+					m_cursor.removeSelectedText();
+					m_cursor.insertText(replacement);
+					m_cursor.endEditBlock();
+					
+					if ( backward )
+						m_cursor.movePosition(replacement.length(), QDocumentCursor::PreviousCharacter);
+				} else {
+					//qDebug("no rep");
+				}
+			} else if ( all || hasOption(HighlightAll) ) {
+				
+				if ( sid && hasOption(HighlightAll) )
+				{
+					if ( m_group == -1 )
+						m_group = d->getNextGroupId();
+					
+					d->addMatch(m_group,
+								m_cursor.lineNumber(),
+								m_cursor.anchorColumnNumber(),
+								m_cursor.columnNumber() - m_cursor.anchorColumnNumber(),
+								sid);
+					//QFormatRange r(
+					//			m_cursor.anchorColumnNumber(),
+					//			m_cursor.columnNumber() - m_cursor.anchorColumnNumber(),
+					//			m_editor->document()->formatScheme()->id("search")
+					//		);
+					
+					//qDebug("(%i, %i, %i)", r.offset, r.length, r.format);
+					//m_cursor.line().addOverlay(r);
+				}
+				
+				m_highlight << m_cursor;
+				m_highlight.last().setAutoUpdated(true);
+			}
+			
+			found = true;
+			
+			if ( !(all || hasOption(HighlightAll)) )
+				break;
+			
+		} else {
+			m_cursor.movePosition(1, move);
+		}
+	}
+	
+	if ( !hasOption(Replace) && hasOption(HighlightAll) && m_highlight.count() )
+	{
+		//qDebug("%i matches in group %i", indexedMatchCount(), m_group);
+		if ( indexedMatchCount() )
+		{
+			m_editor->document()->flushMatches(m_group);
+		} else {
+			m_editor->document()->releaseGroupId(m_group);
+			m_group = -1;
+		}
+		
+		m_index = backward ? m_highlight.count() : 0;
+		--m_index;
+		return next(backward);
+	}
+	
+	if ( !found )
+	{
+		m_cursor = QDocumentCursor();
+		
+		if ( hasOption(Silent) )
+			return;
+		
+		int ret = 
+		QMessageBox::question(
+						m_editor,
+						tr("Failure"),
+						tr(
+							"End of scope reached with no match.\n"
+							"Restart from the begining ?"
+						),
+						QMessageBox::Yes
+						| QMessageBox::No,
+						QMessageBox::Yes
+					);
+		
+		if ( ret == QMessageBox::Yes )
+		{
+			m_origin = QDocumentCursor();
+			next(backward);
+		}
+	}
+}
+
+/*! @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/document/qdocumentsearch.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QDOCUMENT_SEARCH_H_
+#define _QDOCUMENT_SEARCH_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qdocumentsearch.h
+	\brief Definition of the QDocumentSearch class
+*/
+
+#include <QString>
+#include <QRegExp>
+#include <QPointer>
+#include <QCoreApplication>
+
+#include "qdocumentcursor.h"
+
+class QEditor;
+
+class QCE_EXPORT QDocumentSearch
+{
+	Q_DECLARE_TR_FUNCTIONS(QDocumentSearch)
+	
+	public:
+		enum Option
+		{
+			WholeWords		= 1,
+			CaseSensitive	= 2,
+			RegExp			= 4,
+			Replace			= 8,
+			Prompt			= 16,
+			Silent			= 32,
+			HighlightAll	= 64
+		};
+		
+		Q_DECLARE_FLAGS(Options, Option);
+		
+		QDocumentSearch(QEditor *e, const QString& f, Options opt, const QString& r = QString());
+		~QDocumentSearch();
+		
+		int currentMatchIndex() const;
+		int indexedMatchCount() const;
+		QDocumentCursor match(int idx) const;
+		
+		QString searchText() const;
+		void setSearchText(const QString& f);
+		
+		Options options() const;
+		bool hasOption(Option opt) const;
+		void setOption(Option opt, bool on);
+		
+		QString replaceText() const;
+		void setReplaceText(const QString& r);
+		
+		QDocumentCursor origin() const;
+		void setOrigin(const QDocumentCursor& c);
+		
+		QDocumentCursor cursor() const;
+		void setCursor(const QDocumentCursor& c);
+		
+		QDocumentCursor scope() const;
+		void setScope(const QDocumentCursor& c);
+		
+		void next(bool backward, bool all = false);
+		
+	private:
+		bool end(bool backward) const;
+		
+		void clearMatches();
+		
+		int m_group;
+		int m_index;
+		Options m_option;
+		QString m_string;
+		QString m_replace;
+		QPointer<QEditor> m_editor;
+		QDocumentCursor m_cursor, m_scope, m_origin;
+		QList<QDocumentCursor> m_highlight;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QDocumentSearch::Options)
+
+#endif // !_QDOCUMENT_SEARCH_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/lib.pri	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,103 @@
+DEFINES += _QCODE_EDIT_BUILD_
+
+CONFIG *= qnfa console
+
+QT *= xml
+
+# Input
+
+HEADERS += qce-config.h \
+	qeditor.h \
+	qeditorfactory.h \
+	qeditorinputbindinginterface.h \
+	qeditorinputbinding.h \
+	qeditsession.h \
+	qcodeedit.h \
+	qpanellayout.h \
+	qformatfactory.h \
+	qformatscheme.h \
+	qlinemarksinfocenter.h \
+	qreliablefilewatch.h \
+	document/qdocument.h \
+	document/qdocument_p.h \
+	document/qdocumentcommand.h \
+	document/qdocumentcursor.h \
+	document/qdocumentline.h \
+	document/qdocumentsearch.h \
+	qcodecompletionengine.h \
+	qlanguagedefinition.h \
+	qlanguagefactory.h \
+	widgets/qpanel.h \
+	widgets/qlinenumberpanel.h \
+	widgets/qlinemarkpanel.h \
+	widgets/qlinechangepanel.h \
+	widgets/qfoldpanel.h \
+	widgets/qstatuspanel.h \
+	widgets/qgotolinepanel.h \
+	widgets/qsearchreplacepanel.h \
+	widgets/qgotolinedialog.h \
+	widgets/qeditconfig.h \
+	widgets/qformatconfig.h \
+	widgets/qsimplecolorpicker.h \
+	widgets/qcalltip.h \
+	snippets/qsnippet.h \
+	snippets/qsnippet_p.h \
+	snippets/qsnippetpatternloader.h \
+	snippets/qsnippetmanager.h \
+	snippets/qsnippetedit.h \
+	snippets/qsnippetbinding.h
+
+SOURCES += qeditor.cpp \
+	qeditorfactory.cpp \
+	qeditorinputbinding.cpp \
+	qeditsession.cpp \
+	qcodeedit.cpp \
+	qpanellayout.cpp \
+	qformatscheme.cpp \
+	qlinemarksinfocenter.cpp \
+	qreliablefilewatch.cpp \
+	document/qdocument.cpp \
+	document/qdocumentcommand.cpp \
+	document/qdocumentcursor.cpp \
+	document/qdocumentline.cpp \
+	document/qdocumentsearch.cpp \
+	qcodecompletionengine.cpp \
+	qlanguagedefinition.cpp \
+	qlanguagefactory.cpp \
+	widgets/qpanel.cpp \
+	widgets/qlinenumberpanel.cpp \
+	widgets/qlinemarkpanel.cpp \
+	widgets/qlinechangepanel.cpp \
+	widgets/qfoldpanel.cpp \
+	widgets/qstatuspanel.cpp \
+	widgets/qgotolinepanel.cpp \
+	widgets/qsearchreplacepanel.cpp \
+	widgets/qgotolinedialog.cpp \
+	widgets/qeditconfig.cpp \
+	widgets/qformatconfig.cpp \
+	widgets/qsimplecolorpicker.cpp \
+	widgets/qcalltip.cpp \
+	snippets/qsnippet.cpp \
+	snippets/qsnippetmanager.cpp \
+	snippets/qsnippetedit.cpp \
+	snippets/qsnippetbinding.cpp
+
+FORMS += widgets/searchreplace.ui \
+	widgets/gotoline.ui \
+	widgets/gotolinedialog.ui \
+	widgets/editconfig.ui \
+	widgets/formatconfig.ui \
+	snippets/snippetedit.ui
+
+qnfa {
+	DEFINES += QNFA_BUILD
+
+	HEADERS += qnfa/qnfa.h \
+		qnfa/qnfadefinition.h \
+		qnfa/light_vector.h
+
+	SOURCES += qnfa/qnfa.cpp \
+		qnfa/qnfadefinition.cpp \
+		qnfa/xml2qnfa.cpp
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/lib.pro	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,22 @@
+######################################################################
+# Automatically generated by qmake (2.01a) ven. juin 8 21:29:34 2007
+######################################################################
+
+TEMPLATE = lib
+TARGET = qcodeedit
+DESTDIR = ..
+CONFIG += staticlib
+
+DEPENDPATH += . document language widgets qnfa
+INCLUDEPATH += . document language widgets qnfa
+
+CONFIG += qnfa
+
+QT += xml
+
+UI_DIR = 
+MOC_DIR = moc-dir
+OBJECTS_DIR = objects.dir
+
+# Input
+include(lib.pri)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qce-config.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QCE_CONFIG_H_
+#define _QCE_CONFIG_H_
+
+/*!
+	\file qce-config.h
+	\brief Utility file for shared library creation
+*/
+
+#include <qglobal.h>
+
+/*!
+	\macro QCE_EXPORT
+	\brief Macro needed for cross-platform shared libraries creation
+*/
+#ifdef QCE_EXPORT
+	// QCE_EXPORT manually defined, trust the user
+#else
+	#ifdef _QCODE_EDIT_BUILD_
+		#ifdef _QCODE_EDIT_EMBED_
+			#define QCE_EXPORT
+		#else
+			#define QCE_EXPORT Q_DECL_EXPORT
+		#endif
+	#else
+		#define QCE_EXPORT Q_DECL_IMPORT
+	#endif
+#endif
+
+class QString;
+class QStringList;
+
+namespace QCE
+{
+	QString fetchDataFile(const QString& file);
+	
+	QStringList dataPathes();
+	void addDataPath(const QString& path);
+	
+	template <typename Registerable>
+	class Registar
+	{
+		public:
+			Registar()
+			{
+				Registerable::_register();
+			}
+	};
+}
+
+#define QCE_AUTO_REGISTER(T)							\
+	static QCE::Registar<T> _auto_##T##_registar;		\
+	
+
+
+#endif // !_QCE_CONFIG_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qcodecompletionengine.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qcodecompletionengine.h"
+
+/*!
+	\file qcompletionengine.cpp
+	\brief Implementation of the QCodeCompletionEngine class.
+*/
+
+#include "qeditor.h"
+
+#include <QAction>
+#include <QKeyEvent>
+#include <QTextCursor>
+
+#ifdef _QCODE_MODEL_
+#include "qcodebuffer.h"
+#endif
+
+/*!
+
+*/
+QCodeCompletionEngine::QCodeCompletionEngine(QObject *p)
+ : QObject(p), m_max(0)
+{
+	pForcedTrigger = new QAction(tr("&Trigger completion"), this);
+	
+	connect(pForcedTrigger	, SIGNAL( triggered() ),
+			this			, SLOT  ( complete() ) );
+	
+}
+
+/*!
+
+*/
+QCodeCompletionEngine::~QCodeCompletionEngine()
+{
+	
+}
+
+/*!
+	\return 
+*/
+QAction* QCodeCompletionEngine::triggerAction() const
+{
+	return pForcedTrigger;
+}
+
+/*!
+
+*/
+void QCodeCompletionEngine::retranslate()
+{
+	pForcedTrigger->setText(tr("&Trigger completion"));
+}
+
+/*!
+
+*/
+QStringList QCodeCompletionEngine::triggers() const
+{
+	return m_triggers;
+}
+
+/*!
+
+*/
+void QCodeCompletionEngine::addTrigger(const QString& s)
+{
+	if ( m_triggers.contains(s) )
+		return;
+	
+	if ( s.count() > m_max )
+		m_max = s.count();
+	
+	m_triggers << s;
+}
+
+/*!
+
+*/
+void QCodeCompletionEngine::removeTrigger(const QString& s)
+{
+	m_triggers.removeAll(s);
+}
+
+/*!
+
+*/
+void QCodeCompletionEngine::setCodeModel(QCodeModel *m)
+{
+	Q_UNUSED(m)
+}
+
+/*!
+
+*/
+QEditor* QCodeCompletionEngine::editor() const
+{
+	return pEdit;
+}
+
+/*!
+	\brief Attach the completion engine instance to a new editor object
+*/
+void QCodeCompletionEngine::setEditor(QEditor *e)
+{
+	if ( pEdit )
+	{
+		pEdit->removeAction(pForcedTrigger, "&Edit");
+		//pEdit->removeEventFilter(this);
+		
+		disconnect(	pEdit	, SIGNAL( textEdited(QKeyEvent*) ),
+					this	, SLOT  ( textEdited(QKeyEvent*) ) );
+	}
+	
+	pEdit = e;
+	
+	if ( pEdit )
+	{
+		//pEdit->installEventFilter(this);
+		pEdit->addAction(pForcedTrigger, "&Edit");
+		
+		connect(pEdit	, SIGNAL( textEdited(QKeyEvent*) ),
+				this	, SLOT  ( textEdited(QKeyEvent*) ) );
+	}
+}
+
+/*!
+	\internal
+*/
+void QCodeCompletionEngine::run()
+{
+	if ( m_cur.isNull() )
+		return;
+	
+	//qDebug("complete!");
+	
+	complete(m_cur, m_trig);
+	
+	m_cur = QDocumentCursor();
+	m_trig.clear();
+}
+
+/*!
+	\brief Forced completion trigger
+*/
+void QCodeCompletionEngine::complete()
+{
+	complete(editor()->cursor(), QString());
+}
+
+/*!
+	\brief Standard completion entry point for QEditor
+	\param e QKeyEvent that caused a modification of the text
+	
+	\note This slot is only called when editing happens without
+	any cursor mirrors
+*/
+void QCodeCompletionEngine::textEdited(QKeyEvent *k)
+{
+	QString s, txt = s = k->text();
+	QDocumentCursor cur = editor()->cursor();
+	
+	int count = txt.count();
+	
+	if ( txt.isEmpty() || m_triggers.isEmpty() )
+		return;
+	
+	//qDebug("should trigger completion? (bis)");
+	
+	if ( count > m_max )
+	{
+		txt = txt.right(m_max);
+		
+	} else if ( count < m_max ) {
+		
+		QDocumentCursor c(cur);
+		c.movePosition(m_max, QDocumentCursor::Left, QDocumentCursor::KeepAnchor);
+		
+		//qDebug("prev text : %s", qPrintable(c.selectedText()));
+		
+		txt = c.selectedText();
+	}
+	
+	//qDebug("text : %s", qPrintable(txt));
+	
+	foreach ( QString trig, m_triggers )
+	{
+		if ( txt.endsWith(trig) )
+		{
+			cur = editor()->cursor();
+			cur.movePosition(trig.count(), QDocumentCursor::PreviousCharacter);
+			
+			// notify completion trigger
+			emit completionTriggered(trig);
+			
+			//get rid of previous calltips/completions
+			editor()->setFocus();
+			
+			// trigger completion
+			complete(cur, trig);
+		}
+	}
+}
+
+/*!
+	\internal
+*/
+bool QCodeCompletionEngine::eventFilter(QObject *o, QEvent *e)
+{
+	if ( !e || !o || (e->type() != QEvent::KeyPress) || (o != pEdit) )
+		return false;
+	
+	//qDebug("should trigger completion?");
+	
+	QDocumentCursor cur = editor()->cursor();
+	QKeyEvent *k = static_cast<QKeyEvent*>(e);
+	
+	QString s, txt = s = k->text();
+	
+	int count = txt.count();
+	
+	if ( txt.isEmpty() || m_triggers.isEmpty() )
+		return false; // QThread::eventFilter(o, e);
+	
+	//qDebug("should trigger completion? (bis)");
+	
+	if ( count > m_max )
+	{
+		txt = txt.right(m_max);
+		
+	} else if ( count < m_max ) {
+		
+		QDocumentCursor c(cur);
+		c.movePosition(m_max - count, QDocumentCursor::Left, QDocumentCursor::KeepAnchor);
+		
+		//qDebug("prev text : %s", qPrintable(c.selectedText()));
+		
+		txt.prepend(c.selectedText());
+	}
+	
+	//qDebug("text : %s", qPrintable(txt));
+	
+	foreach ( QString trig, m_triggers )
+	{
+		if ( txt.endsWith(trig) )
+		{
+			editor()->write(s);
+			
+			cur = editor()->cursor();
+			cur.movePosition(trig.count(), QDocumentCursor::PreviousCharacter);
+			
+			// notify completion trigger
+			emit completionTriggered(trig);
+			
+			//get rid of previous calltips/completions
+			editor()->setFocus();
+			
+			// trigger completion
+			complete(cur, trig);
+			
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+/*!
+	\brief Completion callback
+*/
+void QCodeCompletionEngine::complete(const QDocumentCursor& c, const QString& trigger)
+{
+	#ifdef _QCODE_MODEL_
+	// TODO : 
+	//	* use a more efficient design by avoiding deep copy of the data
+	//	* only lex the requested part (stop at cursor or topmost frame required for proper class hierarchy)
+	
+	QDocumentCursor cc = c;
+	cc.movePosition(1, QDocumentCursor::Start, QDocumentCursor::KeepAnchor);
+	
+	//qDebug("%s", qPrintable(cc.selectedText()));
+	
+	QCodeBuffer buffer(cc.selectedText());
+	//QCodeBuffer buffer(c.document()->text());
+	complete(&buffer, trigger);
+	#else
+	Q_UNUSED(c)
+	Q_UNUSED(trigger)
+	qWarning("From complete(QDocumentCursor, QString)");
+	qWarning("QCodeCompletionEngine is not self-sufficient : subclasses should "
+			"reimplement at least on of the complete() method...");
+	#endif
+}
+
+/*!
+	\overload
+	\brief Overloaded completion callback
+*/
+void QCodeCompletionEngine::complete(QCodeStream *s, const QString& trigger)
+{
+	Q_UNUSED(s)
+	Q_UNUSED(trigger)
+	
+	qWarning("From complete(QCodeStream*, QString)");
+	qWarning("QCodeCompletionEngine is not self-sufficient : subclasses should"
+			"reimplement at least on of the complete() method...");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qcodecompletionengine.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QCOMPLETION_ENGINE_H_
+#define _QCOMPLETION_ENGINE_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qcompletionengine.h
+	\brief Definition of the QCodeCompletionEngine class.
+*/
+
+#include "qdocumentcursor.h"
+
+#include <QObject>
+#include <QPointer>
+#include <QStringList>
+
+class QEditor;
+class QAction;
+class QKeyEvent;
+class QCodeModel;
+class QCodeStream;
+
+class QCE_EXPORT QCodeCompletionEngine : public QObject
+{
+	Q_OBJECT
+	
+	public:
+		QCodeCompletionEngine(QObject *p = 0);
+		virtual ~QCodeCompletionEngine();
+		
+		virtual QCodeCompletionEngine* clone() = 0;
+		
+		virtual QString language() const = 0;
+		virtual QStringList extensions() const = 0;
+		
+		QAction* triggerAction() const;
+		
+		QEditor* editor() const;
+		void setEditor(QEditor *e);
+		
+		QStringList triggers() const;
+		
+		void addTrigger(const QString& s);
+		void removeTrigger(const QString& s);
+		
+		virtual void setCodeModel(QCodeModel *m);
+		
+		virtual void retranslate();
+		
+	signals:
+		void popup();
+		void cloned(QCodeCompletionEngine *e);
+		void completionTriggered(const QString& s);
+		
+	public slots:
+		void complete();
+		void textEdited(QKeyEvent *e);
+		
+	protected:
+		virtual void run();
+		virtual bool eventFilter(QObject *o, QEvent *e);
+		
+		virtual void complete(QCodeStream *s, const QString& trigger);
+		virtual void complete(const QDocumentCursor& c, const QString& trigger);
+		
+	private:
+		int m_max;
+		QString m_trig;
+		QDocumentCursor m_cur;
+		QAction *pForcedTrigger;
+		
+		QStringList m_triggers;
+		
+		QPointer<QEditor> pEdit;
+};
+
+#endif // _QCOMPLETION_ENGINE_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qcodeedit.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,489 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qcodeedit.h"
+
+/*!
+	\file qcodeedit.cpp
+	\brief Implementation of the QCodeEdit class
+*/
+
+#include "qpanel.h"
+#include "qeditor.h"
+#include "qpanellayout.h"
+
+#include <QDir>
+#include <QMenu>
+#include <QEvent>
+#include <QAction>
+#include <QFileInfo>
+#include <QStringList>
+#include <QMetaObject>
+
+/*!
+	\class QCodeEdit
+	\brief A thin layer over QEditor
+	
+	The QCodeEdit class provides simple means to associate panels with editors and manage them.
+*/
+
+/*!
+	\internal
+	\class QPanelWatcher
+	
+	A class designed to work around some limitations of the hide/show event system and allow
+	proper setting and conservation of default visibility for panels.
+*/
+class QPanelWatcher : public QObject
+{
+	public:
+		QPanelWatcher(QCodeEdit *e)
+		 : qce(e)
+		{
+		
+		}
+		
+		bool eventFilter(QObject *o, QEvent *e)
+		{
+			QPanel *p = qobject_cast<QPanel*>(o);
+			QAction *a = qce->toggleViewAction(p);
+			
+			if ( a )
+			{
+				bool sig = a->signalsBlocked();
+				a->blockSignals(true);
+				
+				if ( a->isChecked() && e->type() == QEvent::Hide )
+					a->setChecked(false);
+				else if ( !a->isChecked() && e->type() == QEvent::Show )
+					a->setChecked(true);
+				
+				a->blockSignals(sig);
+			}
+			
+			return QObject::eventFilter(o, e);
+		}
+		
+	private:
+		QCodeEdit *qce;
+};
+
+QStringList __qce_data_path;
+
+/*!
+	\brief Centralized access point to data fetching
+*/
+QString QCE::fetchDataFile(const QString& file)
+{
+	if ( QFileInfo(file).isAbsolute() )
+		return file;
+	
+	foreach ( QString dp, __qce_data_path )
+	{
+		QDir d(dp);
+		
+		if ( d.exists(file) )
+			return d.absoluteFilePath(file);
+	}
+	
+	return file;
+}
+
+/*!
+	\return The list of pathes used by QCE to fetch data
+*/
+QStringList QCE::dataPathes()
+{
+	return __qce_data_path;
+}
+
+/*!
+	\brief Add a path to the list of pathes used to fetch data
+*/
+void QCE::addDataPath(const QString& path)
+{
+	if ( !__qce_data_path.contains(path) )
+		__qce_data_path << path;
+}
+
+QList<QCodeEdit*> QCodeEdit::m_instances;
+
+/*!
+	\brief ctor
+	
+	The created editor object comes with builtin actions.
+*/
+QCodeEdit::QCodeEdit(QWidget *p)
+ : m_panelsMenu(0)
+{
+	m_editor = new QEditor(p);
+	m_watcher = new QPanelWatcher(this);
+	m_layout = new QPanelLayout(m_editor);
+	
+	m_instances << this;
+}
+
+/*!
+	\brief ctor
+	\param actions whether the QEditor object should create builtin actions
+*/
+QCodeEdit::QCodeEdit(bool actions, QWidget *p)
+ : m_panelsMenu(0)
+{
+	m_editor = new QEditor(actions, p);
+	m_watcher = new QPanelWatcher(this);
+	m_layout = new QPanelLayout(m_editor);
+	
+	m_instances << this;
+}
+
+/*!
+	\brief ctor
+	\param layout structure of the panel layout
+	
+	The created editor object comes with builtin actions.
+*/
+QCodeEdit::QCodeEdit(const QString& layout, QWidget *p)
+ : m_panelsMenu(0)
+{
+	m_editor = new QEditor(p);
+	m_watcher = new QPanelWatcher(this);
+	m_layout = new QPanelLayout(layout, m_editor);
+	
+	m_instances << this;
+}
+
+/*!
+	\brief ctor
+	\param layout structure of the panel layout
+	\param actions whether the QEditor object should create builtin actions
+*/
+QCodeEdit::QCodeEdit(const QString& layout, bool actions, QWidget *p)
+ : m_panelsMenu(0)
+{
+	m_editor = new QEditor(actions, p);
+	m_watcher = new QPanelWatcher(this);
+	m_layout = new QPanelLayout(layout, m_editor);
+	
+	m_instances << this;
+}
+
+/*!
+	\brief ctor
+	\param e editor to manage
+	\param p panel layout to associate with the editor
+*/
+QCodeEdit::QCodeEdit(QEditor *e, QPanelLayout *p)
+ : m_panelsMenu(0)
+{
+	m_editor = e;
+	m_watcher = new QPanelWatcher(this);
+	m_layout = p ? p : new QPanelLayout(m_editor);
+	
+	m_instances << this;
+}
+
+/*!
+	\brief ctor
+	\param e editor to manage
+	\param l structure of the panel layout
+*/
+QCodeEdit::QCodeEdit(QEditor *e, const QString& l)
+ : m_panelsMenu(0)
+{
+	m_editor = e;
+	m_watcher = new QPanelWatcher(this);
+	m_layout = new QPanelLayout(l, m_editor);
+	
+	m_instances << this;
+}
+
+/*!
+	\brief dtor
+	
+	\warning Destroyes the editor and the panel layout it manages
+*/
+QCodeEdit::~QCodeEdit()
+{
+	m_instances.removeAll(this);
+	
+	delete m_watcher;
+	delete m_editor;
+	delete m_layout;
+}
+
+/*!
+	\return the managed editor
+*/
+QEditor* QCodeEdit::editor() const
+{
+	return m_editor;
+}
+
+/*!
+	\return the panel layout associated with the managed editor
+*/
+QPanelLayout* QCodeEdit::panelLayout() const
+{
+	return m_layout;
+}
+
+/*!
+	\brief Add a panel
+	\return Toggle view action for the added panel
+	\param panel panel to add
+	\param pos position of the panel in the layout
+	\param _add whether to add the show action of the panel to the menu of the editor
+*/
+QAction* QCodeEdit::addPanel(QPanel *panel, Position pos, bool _add)
+{
+	panel->attach(m_editor);
+	
+	QAction *a = new QAction(panel->type(), m_editor);
+	a->setCheckable(true);
+	a->setChecked(panel->defaultVisibility());
+	
+	QObject::connect(a		, SIGNAL( toggled(bool) ),
+					panel	, SLOT  ( setVisible(bool) ) );
+	
+	m_layout->addWidget(panel, QPanelLayout::Position(pos));
+	m_layout->update();
+	
+	m_actions << a;
+	
+	panel->installEventFilter(m_watcher);
+	
+	if ( _add )
+	{
+		if ( !m_panelsMenu )
+		{
+			m_panelsMenu = new QMenu(QEditor::tr("Panels"), m_editor);
+			m_panelsMenu->menuAction()->setObjectName("panels");
+			m_editor->addAction(m_panelsMenu->menuAction(), QEditor::tr("&View"), QString());
+		}
+		
+		m_panelsMenu->addAction(a);
+	}
+
+	return a;
+}
+
+/*!
+	\overload
+	\return Toggle view action for the added panel
+	\param name name of panel to add
+	\param pos position of the panel in the layout
+	\param _add whether to add the show action of the panel to the menu of the editor
+*/
+QAction* QCodeEdit::addPanel(const QString& name, Position pos, bool _add)
+{
+	return addPanel(QPanel::panel(name, m_editor), pos, _add);
+}
+
+/*!
+	\return whether the editor has a panel of the given \a type
+*/
+bool QCodeEdit::hasPanel(const QString& type) const
+{
+	if ( !m_layout )
+		return false;
+	
+	QList<QPanel*> l = m_layout->panels();
+	
+	foreach ( QPanel *p, l )
+		if ( p->type() == type )
+			return true;
+	
+	return false;
+}
+
+/*!
+	\return a list of panels added to the editor
+	\param type Type of panel to look for (no filtering is performed if empty)
+*/
+QList<QPanel*> QCodeEdit::panels(const QString& type) const
+{
+	if ( !m_layout )
+		return QList<QPanel*>();
+	
+	QList<QPanel*> l = m_layout->panels();
+	
+	if ( type.isEmpty() )
+		return l;
+	
+	int i = 0;
+	
+	while ( i < l.count() )
+	{
+		if ( l.at(i)->type() == type )
+		{
+			++i;
+		} else {
+			l.removeAt(i);
+		}
+	}
+	
+	return l;
+}
+
+/*!
+	\return the toggle view action of a given panel
+*/
+QAction* QCodeEdit::toggleViewAction(QPanel *p) const
+{
+	int idx = panels().indexOf(p);
+	return idx == -1 ? 0 : m_actions.at(idx);
+}
+
+/*!
+	\brief Send a command to every panel of a given type
+	\param signature method name suitable for QMetaObject::invokeMethod()
+	\param args list of arguments suitable for QMetaObject::invokeMethod()
+	
+	Example use :
+	\code
+	sendPanelCommand("Status", "setVisible" Q_COMMAND << Q_ARG(bool, false));
+	\endcode
+*/
+void QCodeEdit::sendPanelCommand(	const QString& type,
+									const char *signature,
+									const QList<QGenericArgument>& args)
+{
+	QList<QPanel*> lp = panels();
+	
+	//qDebug("looking for panel of type %s", qPrintable(type));
+	
+	foreach ( QPanel *p, lp )
+	{
+		if ( p && (p->type() == type) )
+		{
+			//qDebug("found.");
+			
+			// TODO : ask trolltech to provide an overloaded invokeMetaMethod()
+			// taking a QList<> instead of nine defaulted args...
+			
+			if ( args.isEmpty() )
+				QMetaObject::invokeMethod(p, signature);
+			else if ( args.count() == 1 )
+				QMetaObject::invokeMethod(	p, signature,
+												args.at(0));
+			else if ( args.count() == 2 )
+				QMetaObject::invokeMethod(	p, signature,
+												args.at(0),
+												args.at(1));
+			else if ( args.count() == 3 )
+				QMetaObject::invokeMethod(	p, signature,
+												args.at(0),
+												args.at(1),
+												args.at(2));
+			else if ( args.count() == 4 )
+				QMetaObject::invokeMethod(	p, signature,
+												args.at(0),
+												args.at(1),
+												args.at(2),
+												args.at(3));
+			else if ( args.count() == 5 )
+				QMetaObject::invokeMethod(	p, signature,
+												args.at(0),
+												args.at(1),
+												args.at(2),
+												args.at(3),
+												args.at(4));
+			else if ( args.count() == 6 )
+				QMetaObject::invokeMethod(	p, signature,
+												args.at(0),
+												args.at(1),
+												args.at(2),
+												args.at(3),
+												args.at(4),
+												args.at(5));
+			else if ( args.count() == 7 )
+				QMetaObject::invokeMethod(	p, signature,
+												args.at(0),
+												args.at(1),
+												args.at(2),
+												args.at(3),
+												args.at(4),
+												args.at(5),
+												args.at(6));
+			else if ( args.count() == 7 )
+				QMetaObject::invokeMethod(	p, signature,
+												args.at(0),
+												args.at(1),
+												args.at(2),
+												args.at(3),
+												args.at(4),
+												args.at(5),
+												args.at(6));
+			else if ( args.count() == 8 )
+				QMetaObject::invokeMethod(	p, signature,
+												args.at(0),
+												args.at(1),
+												args.at(2),
+												args.at(3),
+												args.at(4),
+												args.at(5),
+												args.at(6),
+												args.at(7));
+			else if ( args.count() == 9 )
+				QMetaObject::invokeMethod(	p, signature,
+												args.at(0),
+												args.at(1),
+												args.at(2),
+												args.at(3),
+												args.at(4),
+												args.at(5),
+												args.at(7),
+												args.at(8));
+			else if ( args.count() == 10 )
+				QMetaObject::invokeMethod(	p, signature,
+												args.at(0),
+												args.at(1),
+												args.at(2),
+												args.at(3),
+												args.at(4),
+												args.at(5),
+												args.at(7),
+												args.at(8),
+												args.at(9));
+			
+		}
+	}
+}
+
+/*!
+	\return The QCodeEdit object managing a given editor or a null point if the given editor is unmanaged
+*/
+QCodeEdit* QCodeEdit::manager(QEditor *e)
+{
+	foreach ( QCodeEdit *m, m_instances )
+		if ( m->m_editor == e )
+			return m;
+	
+	return 0;
+}
+
+/*!
+	\brief The (first) managed editor editing a given file or a null pointer if none found
+*/
+QEditor* QCodeEdit::managed(const QString& f)
+{
+	foreach ( QCodeEdit *m, m_instances )
+		if ( m && m->m_editor && (m->m_editor->fileName() == f) )
+			return m->m_editor;
+	
+	return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qcodeedit.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QCODE_EDIT_H_
+#define _QCODE_EDIT_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qcodeedit.h
+	\brief Definition of the QCodeEdit class
+*/
+
+#include <QList>
+#include <QPointer>
+#include <QGenericArgument>
+
+class QMenu;
+class QPanel;
+class QEditor;
+class QWidget;
+class QString;
+class QAction;
+class QPanelLayout;
+class QPanelWatcher;
+
+#define Q_COMMAND QList<QGenericArgument>()
+
+class QCE_EXPORT QCodeEdit
+{
+	friend class QPanelWatcher;
+	
+	public:
+		enum Position
+		{
+			West,
+			North,
+			South,
+			East
+		};
+		
+		QCodeEdit(QWidget *p = 0);
+		QCodeEdit(bool actions, QWidget *p = 0);
+		QCodeEdit(const QString& layout, QWidget *p = 0);
+		QCodeEdit(const QString& layout, bool actions, QWidget *p = 0);
+		virtual ~QCodeEdit();
+		
+		QEditor* editor() const;
+		QPanelLayout* panelLayout() const;
+		
+		QAction* addPanel(QPanel *panel, Position pos, bool _add = false);
+		QAction* addPanel(const QString& name, Position pos, bool _add = false); 
+		
+		bool hasPanel(const QString& type) const;
+		QList<QPanel*> panels(const QString& type = QString()) const;
+		
+		QAction* toggleViewAction(QPanel *p) const;
+		
+		void sendPanelCommand(	const QString& type,
+								const char *signature,
+								const QList<QGenericArgument>& args = Q_COMMAND);
+		
+		static QCodeEdit* manager(QEditor *e);
+		static QEditor* managed(const QString& f);
+		
+	//protected:
+		QCodeEdit(QEditor *e, QPanelLayout *p);
+		QCodeEdit(QEditor *e, const QString& l);
+		
+	private:
+		QPanelWatcher *m_watcher;
+		QPointer<QEditor> m_editor;
+		QPointer<QPanelLayout> m_layout;
+		
+		QMenu *m_panelsMenu;
+		QList<QAction*> m_actions;
+		
+		static QList<QCodeEdit*> m_instances;
+};
+
+#endif // _QCODE_EDIT_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qeditor.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,4879 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qeditor.h"
+
+/*!
+	\file qeditor.cpp
+	\brief Implementation of the QEditor class
+*/
+
+#include "qeditorinputbindinginterface.h"
+
+#include "qdocument.h"
+#include "qdocument_p.h"
+#include "qdocumentline.h"
+#include "qdocumentcursor.h"
+
+#include "qlanguagedefinition.h"
+#include "qcodecompletionengine.h"
+
+#include "qcodeedit.h"
+#include "qpanellayout.h"
+#include "qgotolinedialog.h"
+#include "qlinemarksinfocenter.h"
+
+#include "qreliablefilewatch.h"
+
+#include <QFile>
+#include <QMenu>
+#include <QTimer>
+#include <QStyle>
+#include <QDebug>
+#include <QAction>
+#include <QPointer>
+#include <QPainter>
+#include <QPrinter>
+#include <QKeyEvent>
+#include <QMimeData>
+#include <QFileInfo>
+#include <QClipboard>
+#include <QScrollBar>
+#include <QTextCodec>
+#include <QFileDialog>
+#include <QTextStream>
+#include <QMessageBox>
+#include <QPrintDialog>
+#include <QApplication>
+#include <QActionGroup>
+
+//#define Q_GL_EDITOR
+
+#ifdef _QMDI_
+#include "qmdiserver.h"
+#endif
+
+#ifdef _EDYUK_
+#include "edyukapplication.h"
+#include "qshortcutmanager.h"
+
+#define Q_SHORTCUT(a, s, c) EDYUK_SHORTCUT(a, tr(c), tr(s))
+#else
+#define Q_SHORTCUT(a, s, c) a->setShortcut( QKeySequence( tr(s, c) ) )
+#endif
+
+#ifdef Q_GL_EDITOR
+#include <QGLWidget>
+#endif
+
+#define QCE_ACTION(name, action) { QAction *_a_ = m_actions.value(name); if ( _a_ ) _a_ action; }
+#define QCE_TR_ACTION(name, label) { QAction *_a_ = m_actions.value(name); if ( _a_ ) _a_->setText(label); }
+#define QCE_ENABLE_ACTION(name, yes) { QAction *_a_ = m_actions.value(name); if ( _a_ ) _a_->setEnabled(yes); }
+
+/*!
+	\ingroup editor
+	@{
+	
+	\class QEditor
+	\brief A text editing widget
+	
+	QEditor is the central widget in QCE. It allows user to view and edit a
+	document.
+	
+	QEditor has an API similar to that of QTextEdit and it behaves in a very
+	similar way.
+	
+	Notable differences are :
+	<ul>
+	<li>QEditor can be given an InputBinding which can change the way it
+	handle user inputs which enables such things as implementing emacs-like
+	or Vi-like editing (almost) effortlessly.</li>
+	<li>QEditor has actions instead of hard coded shortcuts and expose them
+	so that, among other things, they can be easily added to menus/toolbars
+	and their shortcuts can be changed</li>
+	<li>QEditor brings the notion of cursor mirrors. Column selection and
+	column editing are just special use case of cursor mirrors.</li>
+	<li>QEditor brings the notion of placeholders, snippets-editing is just
+	as special use case of placeholders.</li>
+	<li>QEditor allows easy encodings management</li>
+	</ul>
+	
+	QEditor can gain features when it is managed by a QCodeEdit class which
+	is responsible for panels management.
+*/
+
+
+/*!
+	\enum QEditor::CodecUpdatePolicy
+	\brief Specify the actions to take when changing the default codec
+	
+*/
+
+
+/*!
+	\enum QEditor::EditFlag
+	\brief Flag holding information about the state of an editor
+	
+	Some of these are public and can be modified freely and some
+	others are only meant to be used internally though they can
+	still be read.
+	
+*/
+
+/*!
+	\struct QEditor::PlaceHolder
+	\brief A small structure holding placeholder data
+	
+	Placeholders are basically lists of cursors. When several palceholders coexist, it is
+	possible to navigate among them using the key assigned to that function by the current
+	input binding (CTRL+arrows by default).
+	
+	Each placeholder consist of a primary cursor and a list of mirrors (modeling the internals
+	of QEditor and allowing extended snippet replacements easily).
+	
+	Additionaly a placeholder can have an Affector which allows the text of the mirrors to be
+	modified in any imaginable way
+*/
+
+/*!
+	\class QEditor::PlaceHolder::Affector
+	\brief A small class allowing "placeholder scripting"
+	
+	The purpose of this class is to affect/process/reformat (whichever word you understand/like
+	most) the content of placeholder mirrors.
+	
+	The main placeholder instance (primary cursor) will always contain the text typed by the user,
+	only mirrors can be affected.
+	
+	To allow a large panel of processing to be done the affector is passed the following data :
+	<ul>
+		<li>A stringlist containing placeholder contents (primary cursor of all placeholders present in the editor)
+		<li>The index of the current placeholder among these
+		<li>The key event leading to a modification of the current placeholder
+		<li>The index of the current mirror
+		<li>A reference to the text of that placeholder mirror. This text has already been modified according
+		to the key event. The original text can be retrieved from the first argument (stringlist). This text
+		can be modified in any way you see fit or left as it is.
+	</ul>
+*/
+
+////////////////////////////////////////////////////////////////////////
+//	Bindings handling
+////////////////////////////////////////////////////////////////////////
+
+QList<QEditor*> QEditor::m_editors;
+QEditorInputBindingInterface* QEditor::m_defaultBinding = 0;
+QHash<QString, QEditorInputBindingInterface*> QEditor::m_registeredBindings;
+
+/*!
+	\return A list of available input bindings
+*/
+QStringList QEditor::registeredInputBindingIds()
+{
+	return m_registeredBindings.keys();
+}
+
+/*!
+	\return the name of the default input binding
+	
+	\note The "Default" name (or its translation, obtained via QEditor::tr())
+	is used to indicate that no default input binding has been set.
+*/
+QString QEditor::defaultInputBindingId()
+{
+	return m_defaultBinding ? m_defaultBinding->name() : tr("Default");
+}
+
+/*!
+	\brief Add an input binding to make it available for all editors
+*/
+void QEditor::registerInputBinding(QEditorInputBindingInterface *b)
+{
+	m_registeredBindings[b->id()] = b;
+	
+	foreach ( QEditor *e, m_editors )
+		e->updateBindingsMenu();
+	
+}
+
+/*!
+	\brief Remove an input binding from the pool of publicly available ones
+*/
+void QEditor::unregisterInputBinding(QEditorInputBindingInterface *b)
+{
+	m_registeredBindings.remove(b->id());
+	
+	foreach ( QEditor *e, m_editors )
+		e->updateBindingsMenu();
+	
+}
+
+/*!
+	\brief Set the default input binding
+	
+	\note This does not change the current input binding of existing editors
+*/
+void QEditor::setDefaultInputBinding(QEditorInputBindingInterface *b)
+{
+	m_defaultBinding = b;
+}
+
+/*!
+	\brief Set the default input binding
+	
+	\note If no binding of the given name is available the default (null)
+	binding will be set back as default binding.
+	
+	\note This does not change the current input binding of existing editors
+*/
+void QEditor::setDefaultInputBinding(const QString& b)
+{
+	m_defaultBinding = m_registeredBindings.value(b);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+/*!
+	\return A pointer to the global "reliable" file monitor used by QEditor to avoid file conflicts
+	
+	The point of using a custom file watcher is to work around a bug (limitation) of QFileSystemWatcher
+	which sometimes emit multiple signals for a single file save. It also enables to use a single
+	object shared by all QEditor instances and reduce memory footprint.
+*/
+QReliableFileWatch* QEditor::watcher()
+{
+	static QPointer<QReliableFileWatch> _qce_shared;
+	
+	if ( !_qce_shared )
+		_qce_shared = new QReliableFileWatch;
+	
+	return _qce_shared;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+int QEditor::m_defaultFlags = QEditor::AutoIndent | QEditor::AdjustIndent;
+QTextCodec* QEditor::m_defaultCodec = 0;
+
+/*!
+	\return The default flags set to every QEditor upon construction
+	\note the default flags are a configuration-oriented feature which only expose "user" flags
+*/
+int QEditor::defaultFlags()
+{
+	return m_defaultFlags;
+}
+
+/*!
+	\brief Set the default editor flags
+	
+	Setting editor flags result in them being applied to ALL existing editors
+	and editors to be created later on.
+	
+	These can of course be modified on a per-editor basis later on.
+*/
+void QEditor::setDefaultFlags(int flags)
+{
+	m_defaultFlags = flags & Accessible;
+	
+	foreach ( QEditor *e, m_editors )
+	{
+		bool ontoWrap = (m_defaultFlags & LineWrap) && !(e->m_state & LineWrap);
+		bool outOfWrap = !(m_defaultFlags & LineWrap) && (e->m_state & LineWrap);
+		
+		e->m_state &= Internal;
+		e->m_state |= m_defaultFlags;
+		
+		if ( ontoWrap )
+		{
+			e->document()->setWidthConstraint(e->wrapWidth());
+		} else if ( outOfWrap ) {
+			e->document()->clearWidthConstraint();
+		}
+		
+		QAction *a = e->m_actions.value("wrap");
+		
+		if ( a && (a->isChecked() != (bool)(e->m_state & LineWrap)) )
+			a->setChecked(e->m_state & LineWrap);
+		
+	}
+}
+
+/*!
+	\return The default text codec used to load and save document contents
+	
+	\note a null pointer indicates that local 8 bit encoding is used.
+*/
+QTextCodec* QEditor::defaultCodec()
+{
+	return m_defaultCodec;
+}
+
+/*!
+	\overload
+	\param mib codec identifier
+	\param update Update policy
+*/
+void QEditor::setDefaultCodec(int mib, int update)
+{
+	setDefaultCodec(QTextCodec::codecForMib(mib), update);
+}
+
+/*!
+	\overload
+	\param name name of the codec to use
+	\param update Update policy
+*/
+void QEditor::setDefaultCodec(const char *name, int update)
+{
+	setDefaultCodec(QTextCodec::codecForName(name), update);
+}
+
+/*!
+	\overload
+	\param name name of the codec to use
+	\param update Update policy
+*/
+void QEditor::setDefaultCodec(const QByteArray& name, int update)
+{
+	setDefaultCodec(QTextCodec::codecForName(name), update);
+}
+
+/*!
+	\brief Set the default text codec
+	\param c codec to use
+	\param update Update policy
+	
+	The update policy determines whether existing editors are
+	affected by the change of the default codec.
+*/
+void QEditor::setDefaultCodec(QTextCodec *c, int update)
+{
+	foreach ( QEditor *e, m_editors )
+	{
+		if ( e->codec() == m_defaultCodec )
+		{
+			if ( update & UpdateOld )
+				e->setCodec(c);
+		} else if ( e->codec() ) {
+			if ( update & UpdateCustom )
+				e->setCodec(c);
+		} else {
+			if ( update & UpdateDefault )
+				e->setCodec(c);
+		}
+	}
+	
+	//qDebug("new codec is : 0x%x (%s)", c, c ? c->name().constData() : "System");
+	
+	m_defaultCodec = c;
+}
+
+/*!
+	\brief ctor
+	
+	\note Creates builtin menus/actions
+*/
+QEditor::QEditor(QWidget *p)
+ : QAbstractScrollArea(p),
+	pMenu(0), m_lineEndingsMenu(0), m_lineEndingsActions(0),
+	m_bindingsMenu(0), aDefaultBinding(0), m_bindingsActions(0),
+	m_doc(0), m_codec(m_defaultCodec), m_definition(0), m_curPlaceHolder(-1), m_state(defaultFlags())
+{
+	m_editors << this;
+	
+	m_saveState = Undefined;
+	
+	init();
+}
+
+/*!
+	\brief ctor
+	\param actions Whether builtin actions and menus should be created
+*/
+QEditor::QEditor(bool actions, QWidget *p)
+ : QAbstractScrollArea(p),
+	pMenu(0), m_lineEndingsMenu(0), m_lineEndingsActions(0),
+	m_bindingsMenu(0), aDefaultBinding(0), m_bindingsActions(0),
+	m_doc(0), m_codec(m_defaultCodec), m_definition(0), m_curPlaceHolder(-1), m_state(defaultFlags())
+{
+	m_editors << this;
+	
+	m_saveState = Undefined;
+	
+	init(actions);
+}
+
+/*!
+	\brief ctor
+	\param s file to load
+	
+	\note Creates builtin menus/actions
+*/
+QEditor::QEditor(const QString& s, QWidget *p)
+ : QAbstractScrollArea(p),
+	pMenu(0), m_lineEndingsMenu(0), m_lineEndingsActions(0),
+	m_bindingsMenu(0), aDefaultBinding(0), m_bindingsActions(0),
+	m_doc(0), m_codec(m_defaultCodec), m_definition(0), m_curPlaceHolder(-1), m_state(defaultFlags())
+{
+	m_editors << this;
+	
+	m_saveState = Undefined;
+	
+	init();
+	
+	setText(s);
+}
+
+/*!
+	\brief ctor
+	\param s file to load
+	\param actions Whether builtin actions and menus should be created
+	\note Creates builtin menus/action
+*/
+QEditor::QEditor(const QString& s, bool actions, QWidget *p)
+ : QAbstractScrollArea(p),
+	pMenu(0), m_lineEndingsMenu(0), m_lineEndingsActions(0),
+	m_bindingsMenu(0), aDefaultBinding(0), m_bindingsActions(0),
+	m_doc(0), m_codec(m_defaultCodec), m_definition(0), m_curPlaceHolder(-1), m_state(defaultFlags())
+{
+	m_editors << this;
+	
+	m_saveState = Undefined;
+	
+	init(actions);
+	
+	setText(s);
+}
+
+/*!
+	\brief dtor
+*/
+QEditor::~QEditor()
+{
+	m_editors.removeAll(this);
+	
+	if ( m_completionEngine )
+		delete m_completionEngine;
+	
+	if ( m_doc )
+		delete m_doc;
+	
+	if ( m_editors.isEmpty() )
+	{
+		delete watcher();
+	} else {
+		watcher()->removeWatch(this);
+	}
+}
+
+/*!
+	\internal
+*/
+void QEditor::init(bool actions)
+{
+	#ifdef Q_GL_EDITOR
+	setViewport(new QGLWidget);
+	#endif
+	
+	viewport()->setCursor(Qt::IBeamCursor);
+	viewport()->setBackgroundRole(QPalette::Base);
+	//viewport()->setAttribute(Qt::WA_OpaquePaintEvent, true);
+	viewport()->setAttribute(Qt::WA_KeyCompression, true);
+	viewport()->setAttribute(Qt::WA_InputMethodEnabled, true);
+	
+	verticalScrollBar()->setSingleStep(1);
+	horizontalScrollBar()->setSingleStep(20);
+	
+	setAcceptDrops(true);
+	//setDragEnabled(true);
+	setFrameShadow(QFrame::Plain);
+	setFocusPolicy(Qt::WheelFocus);
+	setAttribute(Qt::WA_KeyCompression, true);
+	setAttribute(Qt::WA_InputMethodEnabled, true);
+	
+	connect(this							,
+			SIGNAL( markChanged(QString, QDocumentLineHandle*, int, bool) ),
+			QLineMarksInfoCenter::instance(),
+			SLOT  ( markChanged(QString, QDocumentLineHandle*, int, bool) ) );
+	
+	m_doc = new QDocument(this);
+	
+	connect(m_doc	, SIGNAL( formatsChange (int, int) ),
+			this	, SLOT  ( repaintContent(int, int) ) );
+	
+	connect(m_doc	, SIGNAL( contentsChange(int, int) ),
+			this	, SLOT  ( updateContent (int, int) ) );
+	
+	connect(m_doc		, SIGNAL( formatsChanged() ),
+			viewport()	, SLOT  ( update() ) );
+	
+	connect(m_doc	, SIGNAL( widthChanged(int) ),
+			this	, SLOT  ( documentWidthChanged(int) ) );
+	
+	connect(m_doc	, SIGNAL( heightChanged(int) ),
+			this	, SLOT  ( documentHeightChanged(int) ) );
+	
+	connect(m_doc	, SIGNAL( cleanChanged(bool) ),
+			this	, SLOT  ( setContentClean(bool) ) );
+	
+	connect(m_doc	, SIGNAL( undoAvailable(bool) ),
+			this	, SIGNAL( undoAvailable(bool) ) );
+	
+	connect(m_doc	, SIGNAL( redoAvailable(bool) ),
+			this	, SIGNAL( redoAvailable(bool) ) );
+	
+	connect(m_doc	, SIGNAL( markChanged(QDocumentLineHandle*, int, bool) ),
+			this	, SLOT  ( markChanged(QDocumentLineHandle*, int, bool) ) );
+	
+	connect(m_doc	, SIGNAL( lineEndingChanged(int) ),
+			this	, SLOT  ( lineEndingChanged(int) ) );
+	
+	m_cursor = QDocumentCursor(m_doc);
+	m_cursor.setAutoUpdated(true);
+	
+	if ( m_defaultBinding )
+	{
+		m_bindings << m_defaultBinding;
+	}
+	
+	if ( actions )
+	{
+		pMenu = new QMenu;
+		
+		QAction *a, *sep;
+		
+		a = new QAction(QIcon(":/undo.png"), tr("&Undo"), this);
+		a->setObjectName("undo");
+		Q_SHORTCUT(a, "Ctrl+Z", "Edit");
+		a->setEnabled(false);
+		connect(this , SIGNAL( undoAvailable(bool) ),
+				a	, SLOT  ( setEnabled(bool) ) );
+		connect(a	, SIGNAL( triggered() ),
+				this , SLOT  ( undo() ) );
+		
+		addAction(a, "&Edit", "Edit");
+		
+		a = new QAction(QIcon(":/redo.png"), tr("&Redo"), this);
+		a->setObjectName("redo");
+		Q_SHORTCUT(a, "Ctrl+Y", "Edit");
+		a->setEnabled(false);
+		connect(this , SIGNAL( redoAvailable(bool) ),
+				a	, SLOT  ( setEnabled(bool) ) );
+		connect(a	, SIGNAL( triggered() ),
+				this , SLOT  ( redo() ) );
+		
+		addAction(a, "&Edit", "Edit");
+		
+		sep = new QAction(this);
+		sep->setSeparator(true);
+		addAction(sep, "&Edit", "Edit");
+
+		a = new QAction(QIcon(":/cut.png"), tr("Cu&t"), this);
+		a->setObjectName("cut");
+		Q_SHORTCUT(a, "Ctrl+X", "Edit");
+		a->setEnabled(false);
+		connect(this, SIGNAL( copyAvailable(bool) ),
+				a	, SLOT  ( setEnabled(bool) ) );
+		connect(a	, SIGNAL( triggered() ),
+				this, SLOT  ( cut() ) );
+		
+		addAction(a, "&Edit", "Edit");
+
+		a = new QAction(QIcon(":/copy.png"), tr("&Copy"), this);
+		a->setObjectName("copy");
+		Q_SHORTCUT(a, "Ctrl+C", "Edit");
+		a->setEnabled(false);
+		connect(this , SIGNAL( copyAvailable(bool) ),
+				a	, SLOT  ( setEnabled(bool) ) );
+		connect(a	, SIGNAL( triggered() ),
+				this , SLOT  ( copy() ) );
+		
+		addAction(a, "&Edit", "Edit");
+
+		a = new QAction(QIcon(":/paste.png"), tr("&Paste"), this);
+		a->setObjectName("paste");
+		//aPaste->setEnabled(QApplication::clipboard()->text().count());
+		Q_SHORTCUT(a, "Ctrl+V", "Edit");
+		connect(QApplication::clipboard()	, SIGNAL( dataChanged() ),
+				this						, SLOT  ( checkClipboard() ) );
+		
+		connect(a	, SIGNAL( triggered() ),
+				this, SLOT  ( paste() ) );
+		
+		addAction(a, "&Edit", "Edit");
+		
+		sep = new QAction(this);
+		sep->setSeparator(true);
+		addAction(sep, "&Edit", "Edit");
+		
+		a = new QAction(QIcon(":/indent.png"), tr("&Indent"), this);
+		a->setObjectName("indent");
+		Q_SHORTCUT(a, "Ctrl+I", "Edit");
+		connect(a	, SIGNAL( triggered() ),
+				this, SLOT  ( indentSelection() ) );
+		
+		addAction(a, "&Edit", "Edit");
+		
+		a = new QAction(QIcon(":/unindent.png"), tr("&Unindent"), this);
+		a->setObjectName("unindent");
+		Q_SHORTCUT(a, "Ctrl+Shift+I", "Edit");
+		connect(a	, SIGNAL( triggered() ),
+				this, SLOT  ( unindentSelection() ) );
+		
+		addAction(a, "&Edit", "Edit");
+		
+		sep = new QAction(this);
+		sep->setSeparator(true);
+		addAction(sep, "&Edit", "");
+		
+		a = new QAction(QIcon(":/comment.png"), tr("Co&mment"), this);
+		a->setObjectName("comment");
+		Q_SHORTCUT(a, "Ctrl+D", "Edit");
+		connect(a	, SIGNAL( triggered() ),
+				this, SLOT  ( commentSelection() ) );
+		
+		addAction(a, "&Edit", "Edit");
+		
+		a = new QAction(QIcon(":/uncomment.png"), tr("Unc&omment"), this);
+		a->setObjectName("uncomment");
+		Q_SHORTCUT(a, "Ctrl+Shift+D", "Edit");
+		connect(a	, SIGNAL( triggered() ),
+				this, SLOT  ( uncommentSelection() ) );
+		
+		addAction(a, "&Edit", "Edit");
+		
+		sep = new QAction(this);
+		sep->setSeparator(true);
+		addAction(sep, "&Edit", "");
+		
+		a = new QAction(tr("&Select all"), this);
+		a->setObjectName("selectAll");
+		Q_SHORTCUT(a, "Ctrl+A", "Edit");
+		connect(a	, SIGNAL( triggered() ),
+				this, SLOT  ( selectAll() ) );
+		
+		addAction(a, "&Edit", "Edit");
+		
+		sep = new QAction(this);
+		sep->setSeparator(true);
+		addAction(sep, QString());
+		
+		a = new QAction(QIcon(":/find.png"), tr("&Find"), this);
+		a->setObjectName("find");
+		Q_SHORTCUT(a, "Ctrl+F", "Search");
+		connect(a	, SIGNAL( triggered() ),
+				this, SLOT  ( find() ) );
+		
+		addAction(a, "&Search", "Search");
+		
+		a = new QAction(QIcon(":/next.png"), tr("Fin&d next"), pMenu);
+		a->setObjectName("findNext");
+		Q_SHORTCUT(a, "F3", "Search");
+		connect(a	, SIGNAL( triggered() ),
+				this, SLOT  ( findNext() ) );
+		
+		addAction(a, "&Search", "Search");
+		
+		a = new QAction(QIcon(":/replace.png"), tr("&Replace"), this);
+		a->setObjectName("replace");
+		Q_SHORTCUT(a, "Ctrl+R", "Search");
+		connect(a	, SIGNAL( triggered() ),
+				this, SLOT  ( replace() ) );
+		
+		addAction(a, "&Search", "Search");
+		
+		sep = new QAction(this);
+		sep->setSeparator(true);
+		addAction(sep, "&Search", "Search");
+		
+		a = new QAction(QIcon(":/goto.png"), tr("&Goto line..."), this);
+		a->setObjectName("goto");
+		Q_SHORTCUT(a, "Ctrl+G", "Search");
+		connect(a	, SIGNAL( triggered() ),
+				this, SLOT  ( gotoLine() ) );
+		
+		addAction(a, "&Search", "Search");
+		
+		sep = new QAction(this);
+		sep->setSeparator(true);
+		addAction(sep, "&Edit", "");
+		
+		a = new QAction(tr("Dynamic line wrapping"), this);
+		a->setObjectName("wrap");
+		a->setCheckable(true);
+		a->setChecked(flag(LineWrap));
+		
+		addAction(a, "&Edit", "");
+		
+		Q_SHORTCUT(a, "F10", "Edit");
+		connect(a	, SIGNAL( toggled(bool) ),
+				this, SLOT  ( setLineWrapping(bool) ) );
+		
+		
+		m_bindingsMenu = new QMenu(tr("Input binding"), this);
+		m_bindingsActions = new QActionGroup(m_bindingsMenu);
+		//m_bindingsActions->setExclusive(true);
+		
+		connect(m_bindingsActions	, SIGNAL( triggered(QAction*) ),
+				this				, SLOT  ( bindingSelected(QAction*) ) );
+		
+		aDefaultBinding = new QAction(tr("Default"), m_bindingsMenu);
+		aDefaultBinding->setCheckable(true);
+		aDefaultBinding->setData("default");
+		
+		m_bindingsMenu->addAction(aDefaultBinding);
+		m_bindingsMenu->addSeparator();
+		m_bindingsActions->addAction(aDefaultBinding);
+		m_registeredBindings["default"] = 0;
+		
+		updateBindingsMenu();
+		
+		m_bindingsMenu->menuAction()->setObjectName("bindings");
+		addAction(m_bindingsMenu->menuAction(), "&Edit", "");
+		
+		sep = new QAction(this);
+		sep->setSeparator(true);
+		addAction(sep, QString());
+		
+		m_lineEndingsMenu = new QMenu(tr("Line endings"), this);
+		m_lineEndingsActions = new QActionGroup(m_lineEndingsMenu);
+		m_lineEndingsActions->setExclusive(true);
+		
+		connect(m_lineEndingsActions, SIGNAL( triggered(QAction*) ),
+				this				, SLOT  ( lineEndingSelected(QAction*) ) );
+		
+		m_lineEndingsActions->addAction(tr("Conservative"))->setData("conservative");
+		m_lineEndingsActions->addAction(tr("Local"))->setData("local");
+		m_lineEndingsActions->addAction(tr("Unix/Linux"))->setData("unix");
+		m_lineEndingsActions->addAction(tr("Dos/Windows"))->setData("dos");
+		m_lineEndingsActions->addAction(tr("Old Mac"))->setData("mac");
+		
+		QList<QAction*> lle = m_lineEndingsActions->actions();
+		
+		foreach ( QAction *a, lle )
+		{
+			a->setCheckable(true);
+			m_lineEndingsMenu->addAction(a);
+		}
+		
+		lle.at(0)->setChecked(true);
+		
+		m_lineEndingsMenu->menuAction()->setObjectName("lineEndings");
+		addAction(m_lineEndingsMenu->menuAction(), "&Edit", "");
+		
+		/*
+		sep = new QAction(this);
+		sep->setSeparator(true);
+		addAction(sep, QString());
+		*/
+	}
+}
+
+/*!
+	\return wether the flag \a f is set
+*/
+bool QEditor::flag(EditFlag f) const
+{
+	return m_state & f;
+}
+
+/*!
+	\brief Sets the flag \a f
+*/
+void QEditor::setFlag(EditFlag f, bool b)
+{
+	if ( b )
+	{
+		m_state |= f;
+		
+		if ( f == LineWrap )
+		{
+			if ( isVisible() )
+				m_doc->setWidthConstraint(wrapWidth());
+			
+			m_cursor.refreshColumnMemory();
+			
+			QAction *a = m_actions.value("wrap");
+			
+			if ( a && !a->isChecked() )
+				a->setChecked(true);
+		}
+	} else {
+		m_state &= ~f;
+		
+		if ( f == LineWrap )
+		{
+			if ( isVisible() )
+				m_doc->clearWidthConstraint();
+			
+			m_cursor.refreshColumnMemory();
+			
+			QAction *a = m_actions.value("wrap");
+			
+			if ( a && a->isChecked() )
+				a->setChecked(false);
+		}
+	}
+	
+	// TODO : only update cpos if cursor used to be visible?
+	if ( f == LineWrap )
+		ensureCursorVisible();
+	
+}
+
+/*!
+	\return whether it is possible to call undo()
+*/
+bool QEditor::canUndo() const
+{
+	return m_doc ? m_doc->canUndo() : false;
+}
+
+/*!
+	\return whether it is possible to call redo()
+*/
+bool QEditor::canRedo() const
+{
+	return m_doc ? m_doc->canRedo() : false;
+}
+
+/*!
+	\brief Set line wrapping
+	\param on line wrap on/off
+	
+	\note the function also enables "cursor movement within wrapped lines"
+	which can be disabled manually using setFlag(QEditor::CursorJumpPastWrap, false);
+*/
+void QEditor::setLineWrapping(bool on)
+{
+	setFlag(LineWrap, on);
+	setFlag(CursorJumpPastWrap, on);
+}
+
+/*!
+	\return The whole text being edited
+*/
+QString QEditor::text() const
+{
+	return m_doc ? m_doc->text() : QString();
+}
+
+/*!
+	\return The text at a given line
+	\param line text line to extract, using C++ array conventions (start at zero)
+*/
+QString QEditor::text(int line) const
+{
+	return m_doc ? m_doc->line(line).text() : QString();
+}
+
+/*!
+	\brief Set the text of the underlying document and update display
+*/
+void QEditor::setText(const QString& s)
+{
+	clearPlaceHolders();
+	
+	if ( m_doc )
+		m_doc->setText(s);
+	
+	setCursor(QDocumentCursor(m_doc));
+
+	documentWidthChanged(m_doc->width());
+	documentHeightChanged(m_doc->height());
+	viewport()->update();
+}
+
+/*!
+	\brief Save the underlying document to a file
+	
+	\see fileName()
+*/
+void QEditor::save()
+{
+	if ( !m_doc )
+		return;
+	
+	QString oldFileName = fileName();
+	
+	if ( fileName().isEmpty() )
+	{
+		QString fn = QFileDialog::getSaveFileName();
+		
+		if ( fn.isEmpty() )
+			return;
+		
+		setFileName(fn);
+	} else if ( isInConflict() ) {
+		int ret = QMessageBox::warning(this,
+										tr("Conflict!"),
+										tr(
+											"%1\nhas been modified by another application.\n"
+											"Press \"Save\" to overwrite the file on disk\n"
+											"Press \"Reset\"to be reload the file from disk.\n"
+											"Press \"Discard\" to ignore this warning.\n"
+										).arg(fileName()),
+											QMessageBox::Save
+										|
+											QMessageBox::Reset
+										|
+											QMessageBox::Discard
+										|
+											QMessageBox::Cancel
+										);
+		if ( ret == QMessageBox::Save )
+		{
+			m_saveState = Undefined;
+		} else if ( ret == QMessageBox::Reset ) {
+			load(fileName());
+			m_saveState = Undefined;
+			return;
+		} else if ( ret == QMessageBox::Discard ) {
+			m_saveState = Undefined;
+			return;
+		} else {
+			return;
+		}
+	}
+	
+	m_saveState = Saving;
+	
+	if ( oldFileName.count() )
+	{
+		watcher()->removeWatch(oldFileName, this);
+	}
+	
+	QFile f(fileName());
+	
+	if ( !f.open(QFile::WriteOnly) )
+	{
+		m_saveState = Undefined;
+		reconnectWatcher();
+		
+		return;
+	}
+	
+	//QTextStream s(&f);
+	//s << text();
+	QString txt = m_doc->text(flag(RemoveTrailing), flag(PreserveTrailingIndent));
+	
+	if ( m_codec )
+		f.write(m_codec->fromUnicode(txt));
+	else
+		f.write(txt.toLocal8Bit());
+	
+	m_doc->setClean();
+	
+	emit saved(this, fileName());
+	m_saveState = Saved;
+	
+	QTimer::singleShot(100, this, SLOT( reconnectWatcher() ));
+	
+	update();
+}
+
+/*!
+	\brief Save the content of the editor to a file
+	
+	\note This method renames the editor, stop monitoring the old
+	file and monitor the new one
+*/
+void QEditor::save(const QString& fn)
+{
+	if ( fileName().count() )
+	{
+		watcher()->removeWatch(fileName(), this);
+	}
+	
+	QFile f(fn);
+	
+	if ( !f.open(QFile::WriteOnly) )
+	{
+		m_saveState = Undefined;
+		reconnectWatcher();
+		
+		return;
+	}
+	
+	QString txt = m_doc->text(flag(RemoveTrailing), flag(PreserveTrailingIndent));
+	
+	if ( m_codec )
+		f.write(m_codec->fromUnicode(txt));
+	else
+		f.write(txt.toLocal8Bit());
+	
+	m_doc->setClean();
+	
+	setFileName(fn);
+	emit saved(this, fn);
+	m_saveState = Saved;
+	
+	QTimer::singleShot(100, this, SLOT( reconnectWatcher() ));
+}
+
+/*!
+	\internal
+*/
+void QEditor::checkClipboard()
+{
+	// LOOKS LIKE THIS FUNCTION NEVER GETS CALLED DESPITE THE CONNECTION...
+	
+	//const QMimeData *d = QApplication::clipboard()->mimeData();
+	
+	//qDebug("checking clipboard : %s", d);
+	
+	//QCE_ENABLE_ACTION("paste", d && d->hasText())
+}
+
+/*!
+	\internal
+*/
+void QEditor::reconnectWatcher()
+{
+	watcher()->addWatch(fileName(), this);
+}
+
+/*!
+	\internal
+*/
+void QEditor::fileChanged(const QString& file)
+{
+	if ( (file != fileName()) || (m_saveState == Saving) )
+		return;
+	
+	/*
+	if ( m_saveState == Saved )
+	{
+		qApp->processEvents();
+		
+		m_saveState = Undefined;
+		return;
+	}
+	*/
+	
+	if ( !isContentModified() )
+	{
+		// silently reload file if the editor contains no modification?
+		// -> result in undo/redo history loss, still ask confirmation ?
+		bool autoReload = true;
+
+		if ( canUndo() || canRedo() )
+		{
+			int ret = QMessageBox::warning(this,
+										tr("File changed"),
+										tr(
+											"%1\nhas been modified by another application.\n\n"
+											"Undo/Redo stack would be discarded by the auto-reload.\n"
+											"Do you wish to keep up to date by reloading the file?"
+										).arg(fileName()),
+											QMessageBox::Yes
+										|
+											QMessageBox::No
+										);
+			
+			if ( ret == QMessageBox::No )
+				autoReload = false;
+		}
+		
+		if ( autoReload )
+		{
+			load(fileName());
+			m_saveState = Undefined;
+			return;
+		}
+	}
+	
+	// TODO : check for actual modification (using a checksum?)
+	// TODO : conflict reversible (checksum again?)
+	
+	//qDebug("conflict!");
+	m_saveState = Conflict;
+}
+
+/*!
+	\return Whether a file conflict has been detected
+	
+	File conflicts happen when the loaded file is modified
+	on disk by another application if the text has been
+	modified in QCE
+*/
+bool QEditor::isInConflict() const
+{
+	return m_saveState == Conflict;
+}
+
+/*!
+	\brief Print the content of the editor
+*/
+void QEditor::print()
+{
+	if ( !m_doc )
+		return;
+	
+	QPrinter printer;
+	
+	// TODO : create a custom print dialog, page range sucks, lines range would be better
+	QPrintDialog dialog(&printer, this);
+	dialog.setEnabledOptions(QPrintDialog::PrintToFile | QPrintDialog::PrintPageRange);
+	
+	if ( dialog.exec() == QDialog::Accepted )
+	{
+		m_doc->print(&printer);
+	}
+}
+
+/*!
+	\brief Show the search/replace panel, if any
+*/
+void QEditor::find()
+{
+	QCodeEdit *m = QCodeEdit::manager(this);
+	
+	if ( m )
+	{
+		// makes sense hiding this one if present...
+		m->sendPanelCommand("Goto", "hide");
+		
+		m->sendPanelCommand("Search",
+							"display",
+							Q_COMMAND
+								<< Q_ARG(int, 1)
+								<< Q_ARG(bool, false)
+							);
+		
+	} else {
+		qDebug("Unmanaged QEditor");
+	}
+}
+
+/*!
+	\brief Ask the search/replace panel, if any, to move to next match
+*/
+void QEditor::findNext()
+{
+	QCodeEdit *m = QCodeEdit::manager(this);
+	
+	if ( m )
+	{
+		// makes sense hiding this one if present...
+		m->sendPanelCommand("Goto", "hide");
+		
+		m->sendPanelCommand("Search",
+							"find",
+							Q_COMMAND
+								<< Q_ARG(int, -1)
+							);
+		
+	} else {
+		qDebug("Unmanaged QEditor");
+	}
+}
+
+/*!
+	\brief Show the search/replace panel, if any
+*/
+void QEditor::replace()
+{
+	QCodeEdit *m = QCodeEdit::manager(this);
+	
+	if ( m )
+	{
+		// makes sense hiding this one if present...
+		m->sendPanelCommand("Goto", "hide");
+		
+		m->sendPanelCommand("Search",
+							"display",
+							Q_COMMAND
+								<< Q_ARG(int, 1)
+								<< Q_ARG(bool, true)
+							);
+		
+	} else {
+		qDebug("Unmanaged QEditor");
+	}
+}
+
+/*!
+	\brief Show a panel or dialog to go to a specific line
+*/
+void QEditor::gotoLine()
+{
+	QCodeEdit *m = QCodeEdit::manager(this);
+	
+	if ( m && m->hasPanel("Goto") )
+	{
+		// makes sense hiding this one if present...
+		m->sendPanelCommand("Search", "hide");
+		
+		m->sendPanelCommand("Goto", "show");
+	} else {
+		QGotoLineDialog dlg(this);
+		
+		dlg.exec(this);
+	}
+}
+
+/*!
+	\brief Run time translation entry point for compat with Edyuk
+*/
+void QEditor::retranslate()
+{
+	QCE_TR_ACTION("undo", tr("&Undo"))
+	QCE_TR_ACTION("redo", tr("&Redo"))
+
+	QCE_TR_ACTION("cut", tr("Cu&t"))
+	QCE_TR_ACTION("copy", tr("&Copy"))
+	QCE_TR_ACTION("paste", tr("&Paste"))
+	
+	QCE_TR_ACTION("indent", tr("&Indent"))
+	QCE_TR_ACTION("unindent", tr("&Unindent"))
+	QCE_TR_ACTION("comment", tr("Co&mment"))
+	QCE_TR_ACTION("uncomment", tr("Unc&omment"))
+	
+	QCE_TR_ACTION("selectAll", tr("&Select all"))
+	
+	QCE_TR_ACTION("find", tr("&Find"))
+	QCE_TR_ACTION("findNext", tr("Fin&d next"))
+	QCE_TR_ACTION("replace", tr("&Replace"))
+	
+	QCE_TR_ACTION("goto", tr("&Goto line..."))
+	
+	if ( m_completionEngine )
+		m_completionEngine->retranslate();
+	
+	if ( m_bindingsMenu )
+		m_bindingsMenu->setTitle(tr("Input binding"));
+	
+	if ( aDefaultBinding )
+		aDefaultBinding->setText(tr("Default"));
+	
+	#ifdef _QMDI_
+	menus.setTranslation("&Edit", tr("&Edit"));
+	menus.setTranslation("&Search", tr("&Search"));
+	
+	toolbars.setTranslation("Edit", tr("Edit"));
+	toolbars.setTranslation("Search", tr("Search"));
+	#endif
+}
+
+/*!
+	\return the action associated with a given name, if the QEditor has been created with actions on
+*/
+QAction* QEditor::action(const QString& s)
+{
+	QHash<QString, QAction*>::const_iterator it = m_actions.constFind(s);
+
+	return it != m_actions.constEnd() ? *it : 0;
+}
+
+/*!
+	\brief Add an action to the editor
+	\param a action to add
+	\param menu if not empty (and if QCE is built with qmdilib support) the action will be added to that menu
+	\param toolbar similar to \a menu but acts on toolbars
+	
+	\see removeAction()
+*/
+void QEditor::addAction(QAction *a, const QString& menu, const QString& toolbar)
+{
+	if ( !a )
+		return;
+
+	QWidget::addAction(a);
+	
+	m_actions[a->objectName()] = a;
+	
+	if ( pMenu && menu.count() )
+	{
+		pMenu->addAction(a);
+		
+		#ifdef _QMDI_
+		menus[menu]->addAction(a);
+		#endif
+	}
+	
+	if ( toolbar.count() )
+	{
+		#ifdef _QMDI_
+		toolbars[toolbar]->addAction(a);
+		#endif
+	}
+}
+
+/*!
+	\brief remove an action form the editor
+	\param a action to add
+	\param menu if not empty (and if QCE is built with qmdilib support) the action will be added to that menu
+	\param toolbar similar to \a menu but acts on toolbars
+	
+	\see addAction()
+*/
+void QEditor::removeAction(QAction *a, const QString& menu, const QString& toolbar)
+{
+	if ( !a )
+		return;
+	
+	QWidget::removeAction(a);
+	
+	//m_actions.remove(a->objectName());
+
+	if ( pMenu )
+		pMenu->removeAction(a);
+	
+	#ifdef _QMDI_
+	if ( menu.count() )
+	{
+		menus[menu]->removeAction(a);
+	}
+	
+	if ( toolbar.count() )
+	{
+		toolbars[toolbar]->removeAction(a);
+	}
+	#else
+	Q_UNUSED(menu)
+	Q_UNUSED(toolbar)
+	#endif
+}
+
+/*!
+	\brief load a text file
+	\param file file to load
+	
+	If the file cannot be loaded, previous content is cleared.
+*/
+void QEditor::load(const QString& file)
+{
+	QFile f(file);
+	
+	// gotta handle line endings ourselves if we want to detect current line ending style...
+	//if ( !f.open(QFile::Text | QFile::ReadOnly) )
+	if ( !f.open(QFile::ReadOnly) )
+	{
+		setText(QString());
+		return;
+	}
+	
+	const int size = f.size();
+	//const int size = m_lastFileState.size = f.size();
+	
+	if ( size < 500000 )
+	{
+		// instant load for files smaller than 500kb
+		QByteArray d = f.readAll();
+		//m_lastFileState.checksum = qChecksum(d.constData(), d.size());
+		if ( m_codec )
+			setText(m_codec->toUnicode(d));
+		else
+			setText(QString::fromLocal8Bit(d));
+	} else {
+		// load by chunks of 100kb otherwise to avoid huge peaks of memory usage
+		// and driving mad the disk drivers
+		
+		int count = 0;
+		QByteArray ba;
+		
+		m_doc->startChunkLoading();
+		//m_lastFileState.checksum = 0;
+		
+		do
+		{
+			ba = f.read(100000);
+			count += ba.count();
+			
+			//m_lastFileState.checksum ^= qChecksum(ba.constData(), ba.size());
+			
+			if ( m_codec )
+				m_doc->addChunk(m_codec->toUnicode(ba));
+			else
+				m_doc->addChunk(QString::fromLocal8Bit(ba));
+			
+		} while ( (count < size) && ba.count() );
+		
+		m_doc->stopChunkLoading();
+		
+		setCursor(QDocumentCursor(m_doc));
+		
+		documentWidthChanged(m_doc->width());
+		documentHeightChanged(m_doc->height());
+	}
+	
+	m_doc->setLastModified(QFileInfo(file).lastModified());
+	
+	//qDebug("checksum = %i", m_lastFileState.checksum);
+	
+	if ( m_lineEndingsActions )
+	{
+		// TODO : update Conservative to report original line endings
+		static const QRegExp rx(" \\[\\w+\\]");
+		QAction *a = m_lineEndingsActions->actions().at(0);
+		
+		if ( a )
+		{
+			QDocument::LineEnding le = m_doc->originalLineEnding();
+			
+			QString det, txt = a->text();
+			txt.remove(rx);
+			
+			if ( le == QDocument::Windows )
+				det = tr("Windows");
+			else if ( le == QDocument::OldMac )
+				det = tr("Old Mac");
+			else if ( le == QDocument::Unix )
+				det = tr("Unix");
+			
+			if ( det.count() )
+			{
+				txt += " [";
+				txt += det;
+				txt += ']';
+			}
+			
+			a->setText(txt);
+		}
+	}
+	
+	setFileName(file);
+	
+	emit loaded(this, file);
+}
+
+/*!
+	\return a pointer to the underlying QDocument object
+*/
+QDocument* QEditor::document() const
+{
+	return m_doc;
+}
+
+/*!
+	\internal
+*/
+void QEditor::setDocument(QDocument *d)
+{
+	Q_UNUSED(d)
+	
+	qWarning("QEditor::setDocument() is not working yet...");
+}
+
+/*!
+	\return The text codec to use for load/save operations
+*/
+QTextCodec* QEditor::codec() const
+{
+	return m_codec;
+}
+
+/*!
+	\overload
+*/
+void QEditor::setCodec(int mib)
+{
+	setCodec(QTextCodec::codecForMib(mib));
+}
+
+/*!
+	\overload
+*/
+void QEditor::setCodec(const char *name)
+{
+	setCodec(QTextCodec::codecForName(name));
+}
+
+/*!
+	\overload
+*/
+void QEditor::setCodec(const QByteArray& name)
+{
+	setCodec(QTextCodec::codecForName(name));
+}
+
+/*!
+	\brief Set the text codec to use for load/save operations
+*/
+void QEditor::setCodec(QTextCodec *c)
+{
+	if ( c == m_codec )
+		return;
+	
+	m_codec = c;
+	
+	// TODO : reload file?
+	if ( fileName().count() && QFile::exists(fileName()) )
+	{
+		if ( !isContentModified() )
+		{
+			load(fileName());
+		}
+	}
+}
+
+/*!
+	\brief Force a full re-highlighting of the document
+*/
+void QEditor::highlight()
+{
+	m_doc->highlight();
+	//updateContent(0, m_doc->lines());
+}
+
+/*!
+	\return the current InputBinding
+*/
+QList<QEditorInputBindingInterface*> QEditor::inputBindings() const
+{
+	return m_bindings;
+}
+
+/*!
+	\brief Set the current input binding
+*/
+void QEditor::addInputBinding(QEditorInputBindingInterface *b)
+{
+	if ( b )
+		m_bindings << b;
+	
+	if ( !aDefaultBinding || !m_bindingsActions )
+		return;
+	
+	QString id = b ? b->id() : QString();
+	aDefaultBinding->setChecked(!b);
+	
+	if ( !b )
+		return;
+	
+	QList<QAction*> actions = m_bindingsActions->actions();
+	
+	foreach ( QAction *a, actions )
+	{
+		if ( a->data().toString() != id )
+			a->setChecked(true);
+	}
+}
+
+/*!
+	\brief Set the current input binding
+*/
+void QEditor::removeInputBinding(QEditorInputBindingInterface *b)
+{
+	int n = m_bindings.removeAll(b);
+	
+	if ( !aDefaultBinding || !m_bindingsActions || !n )
+		return;
+	
+	QString id = b ? b->id() : QString();
+	aDefaultBinding->setChecked(!b);
+	
+	if ( !b )
+		return;
+	
+	QList<QAction*> actions = m_bindingsActions->actions();
+	
+	foreach ( QAction *a, actions )
+	{
+		if ( a->data().toString() != id )
+			a->setChecked(false);
+	}
+}
+
+/*!
+	\brief Set the current input binding
+*/
+void QEditor::setInputBinding(QEditorInputBindingInterface *b)
+{
+	m_bindings.clear();
+	
+	if ( b )
+		m_bindings << b;
+	
+	if ( !aDefaultBinding || !m_bindingsActions )
+		return;
+	
+	QString id = b ? b->id() : QString();
+	aDefaultBinding->setChecked(!b);
+	
+	if ( !b )
+		return;
+	
+	QList<QAction*> actions = m_bindingsActions->actions();
+	
+	foreach ( QAction *a, actions )
+	{
+		if ( a )
+			a->setChecked(a->data().toString() != id);
+	}
+}
+
+/*!
+	\internal
+*/
+void QEditor::updateBindingsMenu()
+{
+	if ( !aDefaultBinding || !m_bindingsMenu || !m_bindingsActions )
+		return;
+
+	QStringList bindings = registeredInputBindingIds();
+	QList<QAction*> actions = m_bindingsActions->actions();
+	
+	aDefaultBinding->setChecked(m_bindings.contains(m_defaultBinding));
+	
+	foreach ( QAction *a, actions )
+	{
+		int idx = bindings.indexOf(a->data().toString());
+		
+		if ( idx == -1 )
+		{
+			m_bindingsMenu->removeAction(a);
+			m_bindingsActions->removeAction(a);
+			delete a;
+		} else {
+			bindings.removeAt(idx);
+			
+			foreach ( QEditorInputBindingInterface *b, m_bindings )
+				if ( a->data().toString() == b->id() )
+					a->setChecked(true);
+			
+		}
+	}
+	
+	bindings.removeAll("default");
+	
+	foreach ( QString s, bindings )
+	{
+		QEditorInputBindingInterface *b = m_registeredBindings.value(s);
+		
+		if ( !b )
+			continue;
+		
+		QAction *a = new QAction(b->name(), m_bindingsMenu);
+		a->setData(b->id());
+		a->setCheckable(true);
+		
+		m_bindingsActions->addAction(a);
+		m_bindingsMenu->addAction(a);
+	}
+}
+
+/*!
+	\internal
+*/
+void QEditor::bindingSelected(QAction *a)
+{
+	//a = m_bindingsActions->checkedAction();
+	
+	if ( !a )
+		return;
+	
+	QEditorInputBindingInterface *b = m_registeredBindings.value(a->data().toString());
+	
+	if ( a->isChecked() )
+		addInputBinding(b);
+	else
+		removeInputBinding(b);
+	
+	//qDebug("setting binding to %s [0x%x]", qPrintable(a->data().toString()), m_binding);
+	
+	updateMicroFocus();
+}
+
+/*!
+	\internal
+*/
+void QEditor::lineEndingSelected(QAction *a)
+{
+	a = m_lineEndingsActions->checkedAction();
+	
+	if ( !a )
+		return;
+	
+	QString le = a->data().toString();
+	
+	if ( le == "conservative" )
+		m_doc->setLineEnding(QDocument::Conservative);
+	else if ( le == "local" )
+		m_doc->setLineEnding(QDocument::Local);
+	else if ( le == "unix" )
+		m_doc->setLineEnding(QDocument::Unix);
+	else if ( le == "dos" )
+		m_doc->setLineEnding(QDocument::Windows);
+	else if ( le == "mac" )
+		m_doc->setLineEnding(QDocument::OldMac);
+	
+	
+	updateMicroFocus();
+}
+
+/*!
+	\internal
+*/
+void QEditor::lineEndingChanged(int lineEnding)
+{
+	if ( !m_lineEndingsActions )
+		return;
+	
+	QAction *a = m_lineEndingsActions->checkedAction(),
+			*n = m_lineEndingsActions->actions().at(lineEnding);
+	
+	if ( a != n )
+		n->setChecked(true);
+	
+}
+
+/*!
+	\return the current cursor
+*/
+QDocumentCursor QEditor::cursor() const
+{
+	QDocumentCursor copy = m_cursor;
+	copy.setAutoUpdated(false);
+	return copy;
+}
+
+/*!
+	\brief Set the document cursor
+*/
+void QEditor::setCursor(const QDocumentCursor& c)
+{
+	repaintCursor();
+	
+	m_cursor = c.isValid() ? c : QDocumentCursor(m_doc);
+	m_cursor.setAutoUpdated(true);
+	clearCursorMirrors();
+	
+	if ( m_curPlaceHolder != -1 )
+	{
+		const PlaceHolder& ph = m_placeHolders[m_curPlaceHolder];
+		
+		if ( !ph.cursor.isWithinSelection(m_cursor) )
+		{
+			m_curPlaceHolder = -1;
+			viewport()->update();
+		}
+	}
+	
+	emitCursorPositionChanged();
+	
+	setFlag(CursorOn, true);
+	repaintCursor();
+	ensureCursorVisible();
+	selectionChange();
+	
+	updateMicroFocus();
+}
+
+/*!
+	\brief Set the cursor
+	\param line document line to move the cursor to (start at zero)
+	\param index column index of the new cursor (start at zero)
+*/
+void QEditor::setCursorPosition(int line, int index)
+{
+	setCursor(QDocumentCursor(m_doc, line, index));
+}
+
+/*!
+	\brief Write the current cursor position to to integers
+*/
+void QEditor::getCursorPosition(int &line, int &index)
+{
+	line = m_cursor.lineNumber();
+	index = m_cursor.columnNumber();
+}
+
+/*!
+	\return the number of cursor mirrors currently used
+*/
+int QEditor::cursorMirrorCount() const
+{
+	return m_mirrors.count();
+}
+
+/*!
+	\return the cursor mirror at index \a i
+	
+	Index has no extra meaning : you cannot deduce anything about
+	the cursor mirror it corresponds to from it. For instance, the
+	cursor mirror at index 0 is neither the first mirror added nor
+	the one at smallest document position (well : it *might* be but
+	that would be a coincidence...)
+*/
+QDocumentCursor QEditor::cursorMirror(int i) const
+{
+	return i >= 0 && i < m_mirrors.count() ? m_mirrors.at(i) : QDocumentCursor();
+}
+
+/*!
+	\brief Clear all placeholders
+*/
+void QEditor::clearPlaceHolders()
+{
+	bool updateView = m_placeHolders.count() && m_curPlaceHolder != -1;
+	
+	m_curPlaceHolder = -1;
+	
+	for ( int i = 0; i < m_placeHolders.count(); ++i )
+	{
+		PlaceHolder& ph = m_placeHolders[i];
+		
+		ph.cursor.setAutoUpdated(false);
+		
+		for ( int j = 0; j < ph.mirrors.count(); ++j )
+		{
+			ph.mirrors[j].setAutoUpdated(false);
+		}
+		
+		ph.mirrors.clear();
+	}
+	
+	m_placeHolders.clear();
+	
+	if ( updateView )
+		viewport()->update();
+	
+}
+
+/*!
+	\brief Add a placeholder
+	\param p placeholder data
+	\param autoUpdate whether to force auto updating of all cursors used by the placeholder
+	
+	Auto update is on by default and it is recommended not to disable it unless you know what you are doing.
+*/
+void QEditor::addPlaceHolder(const PlaceHolder& p, bool autoUpdate)
+{
+	m_placeHolders << p;
+
+	PlaceHolder& ph = m_placeHolders.last();
+
+	ph.cursor.setAutoUpdated(autoUpdate);
+	ph.cursor.movePosition(ph.length, QDocumentCursor::NextCharacter, QDocumentCursor::KeepAnchor);
+	
+	for ( int i = 0; i < ph.mirrors.count(); ++i )
+	{
+		ph.mirrors[i].setAutoUpdated(autoUpdate);
+		ph.mirrors[i].movePosition(ph.length, QDocumentCursor::NextCharacter, QDocumentCursor::KeepAnchor);
+	}
+}
+
+/*!
+	\brief Remove a placeholder
+	\param i placeholder index
+	
+	\note if the current placeholder is removed there will be NO automatic switching to a remaining one.
+*/
+void QEditor::removePlaceHolder(int id)
+{
+	if ( id == m_curPlaceHolder)
+		clearCursorMirrors();
+	
+	PlaceHolder& ph = m_placeHolders[id];
+	
+	for ( int i = 0; i < ph.mirrors.count(); ++i )
+		ph.mirrors[i].setAutoUpdated(false);
+	
+	ph.mirrors.clear();
+	ph.cursor.setAutoUpdated(false);
+	m_placeHolders.removeAt(id);
+	
+	if ( id < m_curPlaceHolder )
+		--m_curPlaceHolder;
+	
+}
+
+/*!
+	\return the number of placeholders currently set
+*/
+int QEditor::placeHolderCount() const
+{
+	return m_placeHolders.count();
+}
+
+/*!
+	\return the id of the current placeholder
+*/
+int QEditor::currentPlaceHolder() const
+{
+	return m_curPlaceHolder;
+}
+
+/*!
+	\brief Set the current placeholder to use
+	
+	This function change the cursor and the cursor mirrors.
+*/
+void QEditor::setPlaceHolder(int i)
+{
+	if ( i < 0 || i >= m_placeHolders.count() )
+		return;
+	
+	clearCursorMirrors();
+	
+	const PlaceHolder& ph = m_placeHolders.at(i);
+	QDocumentCursor cc = ph.cursor;
+	
+	setCursor(cc);
+	
+	/*
+		ditch cursor mirrors in favor of QDocumentCursor::replaceSelectedText()
+		
+			* workaround mirror limitations re movement (no way to ensure proper
+			synchronization when moving up/down)
+			
+			* make it relatively easy to implement affectors
+	*/
+	
+	m_curPlaceHolder = i;
+	
+	viewport()->update();
+}
+
+/*!
+	\brief Move to next placeholder
+	
+	\see setPlaceHolder
+*/
+void QEditor::nextPlaceHolder()
+{
+	if ( m_placeHolders.isEmpty() )
+		return;
+	
+	++m_curPlaceHolder;
+	
+	if ( m_curPlaceHolder >= m_placeHolders.count() )
+		m_curPlaceHolder = 0;
+	
+	setPlaceHolder(m_curPlaceHolder);
+}
+
+/*!
+	\brief Move to previous placeholder
+	
+	\see setPlaceHolder
+*/
+void QEditor::previousPlaceHolder()
+{
+	if ( m_placeHolders.isEmpty() )
+		return;
+	
+	if ( m_curPlaceHolder <= 0 )
+		m_curPlaceHolder = m_placeHolders.count();
+	
+	--m_curPlaceHolder;
+	
+	setPlaceHolder(m_curPlaceHolder);
+}
+
+/*!
+	\return the code completion engine set to this editor, if any
+*/
+QCodeCompletionEngine* QEditor::completionEngine() const
+{
+	return m_completionEngine;
+}
+
+/*!
+	\brief Set a code completion engine to the editor
+	
+	\warning Most completion engines can only be attached
+	to a single editor due to issues in the widget used to
+	dispaly matches so you got to clone them and, as a consequence
+	QEditor will take ownership of the completion engines
+	and delete them.
+*/
+void QEditor::setCompletionEngine(QCodeCompletionEngine *e)
+{
+	if ( m_completionEngine )
+	{
+		m_completionEngine->setEditor(0);
+		m_completionEngine->deleteLater();
+	}
+	
+	m_completionEngine = e;
+	
+	if ( m_completionEngine )
+	{
+		m_completionEngine->setEditor(this);
+	}
+}
+
+/*!
+	\return the language definition set to this editor, if any
+*/
+QLanguageDefinition* QEditor::languageDefinition() const
+{
+	return m_definition;
+}
+
+/*!
+	\brief Set a language definition to the editor
+*/
+void QEditor::setLanguageDefinition(QLanguageDefinition *d)
+{
+	m_definition = d;
+	
+	if ( m_doc )
+		m_doc->setLanguageDefinition(d);
+	
+	if ( m_definition )
+	{
+		bool cuc = d->singleLineComment().count();
+		
+		QCE_ENABLE_ACTION("comment", cuc)
+		QCE_ENABLE_ACTION("uncomment", cuc)
+	} else {
+		QCE_ENABLE_ACTION("comment", false)
+		QCE_ENABLE_ACTION("uncomment", false)
+	}
+}
+
+/*!
+	\return the line at a given viewport position
+*/
+QDocumentLine QEditor::lineAtPosition(const QPoint& p) const
+{
+	return m_doc ? m_doc->lineAt(p) : QDocumentLine();
+}
+
+/*!
+	\return The cursor object nearest to the given viewport position
+*/
+QDocumentCursor QEditor::cursorForPosition(const QPoint& p) const
+{
+	//qDebug("cursor for : (%i, %i)", p.x(), p.y());
+	
+	return m_doc ? m_doc->cursorAt(p) : QDocumentCursor();
+}
+
+/*!
+	\brief Set the cursor to that nearest to a given viewport position
+*/
+void QEditor::setCursorPosition(const QPoint& p)
+{
+	//qDebug("cursor for : (%i, %i)", p.x(), p.y());
+	
+	QDocumentCursor c = cursorForPosition(p);
+	
+	if ( c.isValid() )
+	{
+		setCursor(c);
+	}
+}
+
+/*!
+	\brief Emitted whenever the position of the cursor changes
+*/
+void QEditor::emitCursorPositionChanged()
+{
+	emit cursorPositionChanged();
+	emit copyAvailable(m_cursor.hasSelection());
+	
+	if ( m_definition )
+		m_definition->match(m_cursor);
+	
+	if ( m_doc->impl()->hasMarks() )
+		QLineMarksInfoCenter::instance()->cursorMoved(this);
+	
+}
+
+/*!
+	\brief Undo the last editing operation, if any on the stack
+*/
+void QEditor::undo()
+{
+	if ( m_doc )
+	{
+		if ( m_definition )
+			m_definition->clearMatches(m_doc);
+		
+		m_doc->undo();
+		
+		selectionChange();
+		ensureCursorVisible();
+		setFlag(CursorOn, true);
+		emitCursorPositionChanged();
+		repaintCursor();
+	}
+}
+
+/*!
+	\brief Redo the last undone editing operation, if any on the stack
+*/
+void QEditor::redo()
+{
+	if ( m_doc )
+	{
+		if ( m_definition )
+			m_definition->clearMatches(m_doc);
+		
+		m_doc->redo();
+		
+		selectionChange();
+		ensureCursorVisible();
+		setFlag(CursorOn, true);
+		emitCursorPositionChanged();
+		repaintCursor();
+	}
+}
+
+/*!
+	\brief Cut the selected text, if any
+*/
+void QEditor::cut()
+{
+	copy();
+	
+	bool macro = m_mirrors.count();
+	
+	if ( macro )
+		m_doc->beginMacro();
+	
+	m_cursor.removeSelectedText();
+	
+	for ( int i = 0; i < m_mirrors.count(); ++i )
+		m_mirrors[i].removeSelectedText();
+	
+	if ( macro )
+		m_doc->endMacro();
+	
+	clearCursorMirrors();
+	
+	ensureCursorVisible();
+	setFlag(CursorOn, true);
+	emitCursorPositionChanged();
+	repaintCursor();
+}
+
+/*!
+	\brief Copy the selected text, if any
+	
+	\note Column selection may be created but the can only be copied properly in a QCE editor
+*/
+void QEditor::copy()
+{
+	if ( !m_cursor.hasSelection() )
+		return;
+	
+	QMimeData *d = createMimeDataFromSelection();
+	QApplication::clipboard()->setMimeData(d);
+	
+	//qDebug("%s", qPrintable(m_cursor.selectedText()));
+	//QApplication::clipboard()->setText(m_cursor.selectedText());
+}
+
+/*!
+	\brief Paste text from the clipboard to the current cursor position
+	
+	\note May paste column selections from other QCE editors
+*/
+void QEditor::paste()
+{
+	const QMimeData *d = QApplication::clipboard()->mimeData();
+	
+	if ( d )
+		insertFromMimeData(d);
+}
+
+static bool unindent(const QDocumentCursor& cur)
+{
+	QDocumentLine beg(cur.line());
+	int r = 0, n = 0, t = QDocument::tabStop();
+	QString txt = beg.text().left(beg.firstChar());
+	
+	while ( txt.count() && (n < t) )
+	{
+		if ( txt.at(txt.length() - 1) == '\t' )
+			n += t - (n % t);
+		else
+			++n;
+		
+		++r;
+		txt.chop(1);
+	}
+	
+	if ( !r )
+		return false;
+	
+	QDocumentCursor c(cur);
+	c.setSilent(true);
+	c.movePosition(1, QDocumentCursor::StartOfBlock, QDocumentCursor::MoveAnchor);
+	c.movePosition(r, QDocumentCursor::Right, QDocumentCursor::KeepAnchor);
+	c.removeSelectedText();
+	
+	return true;
+}
+
+static void insert(const QDocumentCursor& cur, const QString& txt)
+{
+	QDocumentCursor c(cur);
+	c.setSilent(true);
+	c.setColumnNumber(0);
+	c.insertText(txt);
+}
+
+static void removeFromStart(const QDocumentCursor& cur, const QString& txt)
+{
+	QDocumentLine l = cur.line();
+	int pos = l.firstChar();
+	
+	if ( l.text().mid(pos, txt.length()) != txt )
+		return;
+	
+	QDocumentCursor c(cur.document(), cur.lineNumber(), pos);
+	c.setSilent(true);
+	c.movePosition(txt.length(),
+					QDocumentCursor::NextCharacter,
+					QDocumentCursor::KeepAnchor);
+	c.removeSelectedText();
+}
+
+/*!
+	\brief Indent the selection
+*/
+void QEditor::indentSelection()
+{
+	// TODO : respect tab stops in case of screwed up indent (correct it?)
+	
+	QString txt = flag(ReplaceTabs) ? QString(m_doc->tabStop(), ' ') : QString("\t");
+	
+	if ( m_mirrors.count() )
+	{
+		m_doc->beginMacro();
+		
+		if ( !protectedCursor(m_cursor) )
+			insert(m_cursor, txt);
+		
+		foreach ( const QDocumentCursor& m, m_mirrors )
+			if ( !protectedCursor(m) )
+				insert(m, txt);
+		
+		m_doc->endMacro();
+		
+	} else if ( !m_cursor.hasSelection() ) {
+		if ( !protectedCursor(m_cursor) )
+			insert(m_cursor, txt);
+	} else if ( !protectedCursor(m_cursor) ) {
+		QDocumentSelection s = m_cursor.selection();
+		QDocumentCursor c(m_doc, s.startLine);
+		c.setSilent(true);
+		c.beginEditBlock();
+		
+		while ( c.isValid() && (c.lineNumber() <= s.endLine) )
+		{
+			c.insertText(txt);
+			c.movePosition(1, QDocumentCursor::NextLine);
+			
+			if ( c.atEnd() )
+				break;
+		}
+		
+		c.endEditBlock();
+	}
+}
+
+/*!
+	\brief Unindent the selection
+*/
+void QEditor::unindentSelection()
+{
+	if ( !m_cursor.line().firstChar() )
+		return;
+	
+	if ( m_mirrors.count() )
+	{
+		m_doc->beginMacro();
+		
+		if ( !protectedCursor(m_cursor) )
+			unindent(m_cursor);
+		
+		foreach ( const QDocumentCursor& m, m_mirrors )
+			unindent(m);
+		
+		m_doc->endMacro();
+		
+	} else if ( !m_cursor.hasSelection() ) {
+		unindent(m_cursor);
+	} else if ( !protectedCursor(m_cursor) ) {
+		QDocumentSelection s = m_cursor.selection();
+		
+		m_doc->beginMacro();
+		
+		for ( int i = s.startLine; i <= s.endLine; ++i )
+		{
+			unindent(QDocumentCursor(m_doc, i));
+		}
+		
+		m_doc->endMacro();
+	}
+}
+
+/*!
+	\brief Comment the selection (or the current line) using single line comments supported by the language 
+*/
+void QEditor::commentSelection()
+{
+	if ( !m_definition )
+		return;
+	
+	QString txt = m_definition->singleLineComment();
+	
+	if ( txt.isEmpty() )
+		return;
+	
+	if ( m_mirrors.count() )
+	{
+		m_doc->beginMacro();
+		
+		if ( !protectedCursor(m_cursor) )
+			insert(m_cursor, txt);
+		
+		foreach ( const QDocumentCursor& m, m_mirrors )
+			if ( !protectedCursor(m) )
+				insert(m, txt);
+		
+		m_doc->endMacro();
+		
+	} else if ( !m_cursor.hasSelection() ) {
+		if ( !protectedCursor(m_cursor) )
+			insert(m_cursor, txt);
+	} else if ( !protectedCursor(m_cursor) ) {
+		QDocumentSelection s = m_cursor.selection();
+		QDocumentCursor c(m_doc, s.startLine);
+		c.setSilent(true);
+		c.beginEditBlock();
+		
+		while ( c.isValid() && (c.lineNumber() <= s.endLine) )
+		{
+			c.insertText(txt);
+			c.movePosition(1, QDocumentCursor::NextLine);
+			
+			if ( c.atEnd() )
+				break;
+		}
+		
+		c.endEditBlock();
+	}
+}
+
+/*!
+	\brief Uncomment the selection (or current line), provided it has been commented with single line comments
+*/
+void QEditor::uncommentSelection()
+{
+	if ( !m_definition )
+		return;
+	
+	QString txt = m_definition->singleLineComment();
+	
+	if ( txt.isEmpty() )
+		return;
+	
+	if ( m_mirrors.count() )
+	{
+		m_doc->beginMacro();
+		
+		if ( !protectedCursor(m_cursor) )
+			removeFromStart(m_cursor, txt);
+		
+		foreach ( const QDocumentCursor& m, m_mirrors )
+			if ( !protectedCursor(m) )
+				removeFromStart(m, txt);
+		
+		m_doc->endMacro();
+		
+	} else if ( !m_cursor.hasSelection() ) {
+		if ( !protectedCursor(m_cursor) )
+			removeFromStart(m_cursor, txt);
+	} else if ( !protectedCursor(m_cursor) ) {
+		QDocumentSelection s = m_cursor.selection();
+		
+		m_doc->beginMacro();
+		
+		for ( int i = s.startLine; i <= s.endLine; ++i )
+		{
+			removeFromStart(QDocumentCursor(m_doc, i), txt);
+		}
+		
+		m_doc->endMacro();
+	}
+}
+
+/*!
+	\brief Select the whole text
+*/
+void QEditor::selectAll()
+{
+	clearCursorMirrors();
+	
+	m_cursor.movePosition(1, QDocumentCursor::Start);
+	m_cursor.movePosition(1, QDocumentCursor::End, QDocumentCursor::KeepAnchor);
+	
+	emitCursorPositionChanged();
+	selectionChange(true);
+	
+	viewport()->update();
+}
+
+/*!
+	\internal
+*/
+bool QEditor::event(QEvent *e)
+{
+	bool r = QAbstractScrollArea::event(e);
+	
+	if ( (e->type() == QEvent::Resize || e->type() == QEvent::Show) && m_doc )
+		verticalScrollBar()->setMaximum(qMax(0, 1 + (m_doc->height() - viewport()->height()) / m_doc->fontMetrics().lineSpacing()));
+	
+	if ( e->type() == QEvent::Resize && flag(LineWrap) )
+	{
+		//qDebug("resize adjust (1) : wrapping to %i", viewport()->width());
+		m_doc->setWidthConstraint(wrapWidth());
+		ensureCursorVisible();
+	}
+	
+	return r;
+}
+
+/*!
+	\internal
+*/
+void QEditor::paintEvent(QPaintEvent *e)
+{
+	if ( !m_doc )
+		return;
+	
+	QPainter p(viewport());
+	const int yOffset = verticalOffset();
+	const int xOffset = horizontalOffset();
+	
+	#ifdef Q_GL_EDITOR
+	//QRect r(e->rect());
+	QRect r(0, 0, viewport()->width(), viewport()->height());
+	#else
+	QRect r(e->rect());
+	#endif
+	
+	//qDebug() << r;
+	
+	//p.setClipping(false);
+	p.translate(-xOffset, -yOffset);
+	
+	QDocument::PaintContext ctx;
+	ctx.xoffset = xOffset;
+	ctx.yoffset = r.y() + yOffset;
+	ctx.width = viewport()->width();
+	ctx.height = qMin(r.height(), viewport()->height());
+	ctx.palette = palette();
+	ctx.cursors << m_cursor.handle();
+	ctx.fillCursorRect = true;
+	ctx.blinkingCursor = flag(CursorOn);
+	
+	if ( m_cursor.hasSelection() )
+	{
+		//qDebug("atempting to draw selected text");
+		QDocumentSelection s = m_cursor.selection();
+		
+		ctx.selections << s;
+	}
+	
+	// cursor mirrors :D
+	foreach ( const QDocumentCursor& m, m_mirrors )
+	{
+		if ( ctx.blinkingCursor )
+			ctx.extra << m.handle();
+		
+		if ( m.hasSelection() )
+		{
+			QDocumentSelection s = m.selection();
+			
+			ctx.selections << s;
+		}
+	}
+	
+	if ( m_dragAndDrop.isValid() )
+	{
+		ctx.extra << m_dragAndDrop.handle();
+	}
+	
+	p.save();
+	m_doc->draw(&p, ctx);
+	p.restore();
+	
+	if ( m_curPlaceHolder >= 0 && m_curPlaceHolder < m_placeHolders.count() )
+	{
+		const PlaceHolder& ph = m_placeHolders.at(m_curPlaceHolder);
+		
+		p.setPen(Qt::red);
+		p.drawConvexPolygon(ph.cursor.documentRegion());
+		
+		p.setPen(Qt::yellow);
+		foreach ( const QDocumentCursor& m, ph.mirrors )
+		{
+			if ( m.isValid() )
+				p.drawConvexPolygon(m.documentRegion());
+		}
+	}
+	
+	if ( viewport()->height() > m_doc->height() )
+	{
+		p.fillRect(	0,
+					m_doc->height(),
+					viewport()->width(),
+					viewport()->height() - m_doc->height(),
+					palette().base()
+				);
+	}
+}
+
+/*!
+	\internal
+*/
+void QEditor::timerEvent(QTimerEvent *e)
+{
+	int id = e->timerId();
+	
+	if ( id == m_blink.timerId() )
+	{
+		bool on = !flag(CursorOn);
+		
+		if ( m_cursor.hasSelection() )
+			on &= style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected,
+									0,
+									this) != 0;
+		
+		setFlag(CursorOn, on);
+		
+		repaintCursor();
+		
+	} else if ( id == m_drag.timerId() ) {
+		m_drag.stop();
+		//startDrag();
+	} else if ( id == m_click.timerId() ) {
+		m_click.stop();
+	}
+}
+
+static int max(const QList<QDocumentCursor>& l)
+{
+	int ln = 0;
+	
+	foreach ( const QDocumentCursor& c, l )
+		if ( c.lineNumber() > ln )
+			ln = c.lineNumber();
+	
+	return ln;
+}
+
+static int min(const QList<QDocumentCursor>& l)
+{
+	// beware the sign bit...
+	int ln = 0x7fffffff;
+	
+	foreach ( const QDocumentCursor& c, l )
+		if ( (c.lineNumber() < ln) || (ln < 0) )
+			ln = c.lineNumber();
+	
+	return ln;
+}
+
+bool QEditor::protectedCursor(const QDocumentCursor& c) const
+{
+	if ( c.hasSelection() )
+	{
+		int line = qMin(c.lineNumber(), c.anchorLineNumber()), end = qMax(c.lineNumber(), c.anchorLineNumber());
+		
+		while ( line <= end )
+		{
+			if ( m_doc->line(line).hasAnyFlag(QDocumentLine::Hidden | QDocumentLine::CollapsedBlockStart | QDocumentLine::CollapsedBlockEnd) )
+				return true;
+			
+			++line;
+		}
+		
+	} else {
+		return m_doc->line(c.lineNumber()).hasAnyFlag(QDocumentLine::Hidden | QDocumentLine::CollapsedBlockStart | QDocumentLine::CollapsedBlockEnd);
+	}
+	
+	return false;
+}
+
+/*!
+	\internal
+*/
+void QEditor::keyPressEvent(QKeyEvent *e)
+{
+	foreach ( QEditorInputBindingInterface *b, m_bindings )
+		if ( b->keyPressEvent(e, this) )
+			return;
+	
+	forever
+	{
+		bool leave = false;
+		
+		// try mirrors bindings first
+		if ( (e->modifiers() & Qt::AltModifier) && (e->modifiers() & Qt::ControlModifier) )
+		{
+			int ln = - 1;
+			QDocumentLine l;
+			
+			if ( e->key() == Qt::Key_Up )
+			{
+				ln = m_cursor.lineNumber();
+				
+				if ( m_mirrors.count() )
+					ln = qMin(ln, min(m_mirrors));
+				
+				//qDebug("first %i", ln);
+				
+				l = m_doc->line(--ln);
+			} else if ( e->key() == Qt::Key_Down ) {
+				ln = m_cursor.lineNumber();
+				
+				if ( m_mirrors.count() )
+					ln = qMax(ln, max(m_mirrors));
+				
+				l = m_doc->line(++ln);
+			}
+			
+			if ( l.isValid() )
+			{
+				addCursorMirror(QDocumentCursor(m_doc, ln, m_cursor.anchorColumnNumber()));
+				repaintCursor();
+				emitCursorPositionChanged();
+				
+				break;
+			}
+		}
+		
+		selectionChange();
+		
+		// placeholders handling
+		bool bHandled = false;
+		
+		if ( m_placeHolders.count() && e->modifiers() == Qt::ControlModifier )
+		{
+			if ( e->key() == Qt::Key_Up || e->key() == Qt::Key_Left )
+			{
+				bHandled = true;
+				previousPlaceHolder();
+			} else if ( e->key() == Qt::Key_Down || e->key() == Qt::Key_Right ) {
+				bHandled = true;
+				nextPlaceHolder();
+			}
+		}
+		
+		// default shortcuts
+		if ( e->matches(QKeySequence::Undo) )
+		{
+			undo();
+			break;
+		} else if ( e->matches(QKeySequence::Redo) ) {
+			redo();
+			break;
+		} else if ( e->matches(QKeySequence::Copy) ) {
+			copy();
+			break;
+		} else if ( e->matches(QKeySequence::Paste) ) {
+			paste();
+			break;
+		} else if ( e->matches(QKeySequence::Cut) ) {
+			cut();
+			break;
+		} else if ( e->matches(QKeySequence::Print) ) {
+			print();
+			break;
+		} else if ( e->matches(QKeySequence::SelectAll) ) {
+			selectAll();
+			break;
+		} else if ( e->matches(QKeySequence::Find) ) {
+			find();
+			break;
+		} else if ( e->matches(QKeySequence::FindNext) ) {
+			findNext();
+			break;
+		} else if ( e->matches(QKeySequence::Replace) ) {
+			replace();
+			break;
+		}
+		
+		// regular moves
+		if ( !bHandled )
+		{
+			if ( moveKeyEvent(m_cursor, e, &leave) )
+			{
+				e->accept();
+				
+				//setFlag(CursorOn, true);
+				//ensureCursorVisible();
+				
+				if ( !leave )
+					for ( int i = 0; !leave && (i < m_mirrors.count()); ++i )
+						moveKeyEvent(m_mirrors[i], e, &leave);
+				
+				if ( leave && m_mirrors.count() )
+				{
+					for ( int i = 0; i < m_mirrors.count(); ++i )
+					{
+						m_mirrors[i].setAutoUpdated(false);
+					}
+					
+					clearCursorMirrors();
+					viewport()->update();
+				} else {
+					repaintCursor();
+					selectionChange();
+				}
+				
+				bHandled = true;
+			}
+		}
+		
+		bool bOk = true;
+		if ( !bHandled )
+		{
+			int offset = 0;
+			bool pke = isProcessingKeyEvent(e, &offset);
+			bool prot = protectedCursor(m_cursor);
+			
+			foreach ( const QDocumentCursor& c, m_mirrors )
+				prot |= protectedCursor(c);
+			
+			if ( !pke || prot )
+			{
+				bHandled = false;
+			} else {
+				
+				// clear matches to avoid offsetting and subsequent remanence of matches
+				if ( m_definition )
+					m_definition->clearMatches(m_doc);
+				
+				bool hasPH = m_placeHolders.count() && m_curPlaceHolder != -1;
+				bool macroing = hasPH || m_mirrors.count();
+				
+				if ( macroing )
+					m_doc->beginMacro();
+				
+				QStringList prevText;
+				
+				if ( hasPH )
+				{
+					for ( int k = 0; k < m_placeHolders.count(); ++k )
+						prevText << m_placeHolders.at(k).cursor.selectedText();
+					
+				}
+				
+				bHandled = processCursor(m_cursor, e, bOk);
+				
+				if ( hasPH )
+				{
+					PlaceHolder& ph = m_placeHolders[m_curPlaceHolder];
+					
+					QString baseText = ph.cursor.selectedText();
+					
+					for ( int phm = 0; phm < ph.mirrors.count(); ++phm )
+					{
+						QString s = baseText;
+						
+						if ( ph.affector )
+							ph.affector->affect(prevText, m_curPlaceHolder, e, phm, s);
+						
+						ph.mirrors[phm].replaceSelectedText(s);
+					}
+				}
+				
+				if ( m_mirrors.isEmpty() )
+				{
+					// this signal is NOT emitted when cursor mirrors are used ON PURPOSE
+					// as it is the "standard" entry point for code completion, which cannot
+					// work properly with cursor mirrors (art least not always and not simply)
+					if ( bHandled )
+						emit textEdited(e);
+					
+				} else {
+					
+					for ( int i = 0; bOk && (i < m_mirrors.count()); ++i )
+						processCursor(m_mirrors[i], e, bOk);
+					
+				}
+				
+				if ( macroing )
+					m_doc->endMacro();
+				
+			}
+		}
+		
+		if ( !bHandled )
+		{
+			QAbstractScrollArea::keyPressEvent(e);
+			
+			break;
+		}
+		
+		e->accept();
+		emitCursorPositionChanged();
+		setFlag(CursorOn, true);
+		ensureCursorVisible();
+		repaintCursor();
+		selectionChange();
+		break;
+	}
+	
+	foreach ( QEditorInputBindingInterface *b, m_bindings )
+		b->postKeyPressEvent(e, this);
+	
+}
+
+/*!
+	\internal
+*/
+void QEditor::inputMethodEvent(QInputMethodEvent* e)
+{
+	foreach ( QEditorInputBindingInterface *b, m_bindings )
+		if ( b->inputMethodEvent(e, this) )
+			return;
+	
+	/*
+	if ( m_doc->readOnly() )
+	{
+		e->ignore();
+		return;
+	}
+	*/
+	
+	m_cursor.beginEditBlock();
+	
+	if ( e->commitString().count() )
+		m_cursor.insertText(e->commitString());
+	
+	m_cursor.endEditBlock();
+	
+	foreach ( QEditorInputBindingInterface *b, m_bindings )
+		b->postInputMethodEvent(e, this);
+	
+}
+
+/*!
+	\internal
+*/
+void QEditor::mouseMoveEvent(QMouseEvent *e)
+{
+	foreach ( QEditorInputBindingInterface *b, m_bindings )
+		if ( b->mouseMoveEvent(e, this) )
+			return;
+	
+	forever
+	{
+		if ( !(e->buttons() & Qt::LeftButton) )
+			break;
+		
+		if ( !( flag(MousePressed) || m_doubleClick.hasSelection() ) )
+			break;
+		
+		if ( flag(MaybeDrag) )
+		{
+			m_drag.stop();
+			
+			if (	(e->globalPos() - m_dragPoint).manhattanLength() >
+					QApplication::startDragDistance()
+				)
+				startDrag();
+			
+			//emit clearAutoCloseStack();
+			break;
+		}
+		
+		repaintCursor();
+		selectionChange();
+		
+		const QPoint mousePos = mapToContents(e->pos());
+		
+		if ( m_scroll.isActive() )
+		{
+			if ( viewport()->rect().contains(e->pos()) )
+				m_scroll.stop();
+		} else {
+			if ( !viewport()->rect().contains(e->pos()) )
+				m_scroll.start(100, this);
+		}
+		
+		QDocumentCursor newCursor = cursorForPosition(mousePos);
+		
+		if ( newCursor.isNull() )
+			break;
+		
+		if ( e->modifiers() & Qt::ControlModifier )
+		{
+			
+			// get column number for column selection
+			int org = m_cursor.anchorColumnNumber();
+			int dst = newCursor.columnNumber();
+			// TODO : adapt to line wrapping...
+			
+			clearCursorMirrors();
+			//m_cursor.clearSelection();
+			int min = qMin(m_cursor.lineNumber(), newCursor.lineNumber());
+			int max = qMax(m_cursor.lineNumber(), newCursor.lineNumber());
+			
+			if ( min != max )
+			{
+				for ( int l = min; l <= max; ++l )
+				{
+					if ( l != m_cursor.lineNumber() )
+						addCursorMirror(QDocumentCursor(m_doc, l, org));
+					
+				}
+				
+				if ( e->modifiers() & Qt::ShiftModifier )
+				{
+					m_cursor.setColumnNumber(dst, QDocumentCursor::KeepAnchor);
+					
+					for ( int i = 0; i < m_mirrors.count(); ++i )
+						m_mirrors[i].setColumnNumber(dst, QDocumentCursor::KeepAnchor);
+				}
+			} else {
+				m_cursor.setSelectionBoundary(newCursor);
+			}
+		} else {
+			m_cursor.setSelectionBoundary(newCursor);
+			//setFlag(FoldedCursor, isCollapsed());
+		}
+		
+		selectionChange(true);
+		ensureCursorVisible();
+		//emit clearAutoCloseStack();
+		emitCursorPositionChanged();
+		
+		repaintCursor();
+		break;
+	}
+	
+	foreach ( QEditorInputBindingInterface *b, m_bindings )
+		b->postMouseMoveEvent(e, this);
+	
+}
+
+/*!
+	\internal
+*/
+void QEditor::mousePressEvent(QMouseEvent *e)
+{
+	foreach ( QEditorInputBindingInterface *b, m_bindings )
+		if ( b->mousePressEvent(e, this) )
+			return;
+	
+	forever
+	{
+		if ( !(e->buttons() & Qt::LeftButton) )
+			break;
+		
+		QPoint p = mapToContents(e->pos());
+		
+		setFlag(MousePressed, true);
+		setFlag(MaybeDrag, false);
+		
+		repaintCursor();
+		selectionChange();
+		
+		if ( m_click.isActive() &&
+			(( e->globalPos() - m_clickPoint).manhattanLength() <
+				QApplication::startDragDistance() ))
+		{
+	#if defined(Q_WS_MAC)
+			m_cursor.select(QDocumentCursor::LineUnderCursor);
+			m_doubleClick = m_cursor;
+	#else
+			m_cursor.movePosition(1, QDocumentCursor::StartOfBlock);
+			m_cursor.movePosition(1, QDocumentCursor::EndOfBlock, QDocumentCursor::KeepAnchor);
+	#endif
+			
+			m_click.stop();
+		} else {
+			QDocumentCursor cursor = cursorForPosition(p);
+			
+			if ( cursor.isNull() )
+				break;
+			
+			if ( e->modifiers() == Qt::ShiftModifier )
+			{
+				clearCursorMirrors();
+				m_cursor.setSelectionBoundary(cursor);
+			} else if ( e->modifiers() & Qt::ControlModifier && ((e->modifiers() & Qt::ShiftModifier) || (e->modifiers() & Qt::AltModifier)) ) {
+				//m_mirrors << cursor;
+				if ( e->modifiers() & Qt::ShiftModifier )
+				{
+					// get column number for column selection
+					int org = m_cursor.anchorColumnNumber();
+					int dst = cursor.columnNumber();
+					// TODO : fix and adapt to line wrapping...
+					
+					clearCursorMirrors();
+					//m_cursor.clearSelection();
+					int min = qMin(m_cursor.lineNumber(), cursor.lineNumber());
+					int max = qMax(m_cursor.lineNumber(), cursor.lineNumber());
+					
+					if ( min != max )
+					{
+						for ( int l = min; l <= max; ++l )
+						{
+							if ( l != m_cursor.lineNumber() )
+								addCursorMirror(QDocumentCursor(m_doc, l, org));
+							
+						}
+						
+						if ( e->modifiers() & Qt::ShiftModifier )
+						{
+							m_cursor.setColumnNumber(dst, QDocumentCursor::KeepAnchor);
+							
+							for ( int i = 0; i < m_mirrors.count(); ++i )
+								m_mirrors[i].setColumnNumber(dst, QDocumentCursor::KeepAnchor);
+						}
+					} else {
+						m_cursor.setSelectionBoundary(cursor);
+					}
+				} else if ( (e->modifiers() & Qt::AltModifier) ) {
+					addCursorMirror(cursor);
+				}
+			} else {
+				
+				const QDocumentCursor& cur = m_cursor;
+				
+				if ( m_cursor.hasSelection() )
+				{
+					bool inSel = cur.isWithinSelection(cursor);
+					
+					if ( !inSel )
+					{
+						foreach ( const QDocumentCursor& m, m_mirrors )
+						{
+							inSel = m.isWithinSelection(cursor);
+							
+							if ( inSel )
+								break;
+						}
+					}
+					
+					if ( inSel )
+					{
+						setFlag(MaybeDrag, true);
+						
+						m_dragPoint = e->globalPos();
+						m_drag.start(QApplication::startDragTime(), this);
+						
+						break;
+					}
+				}
+				
+				m_doubleClick = QDocumentCursor();
+				setCursor(cursor);
+				break;
+			}
+		}
+		
+		ensureCursorVisible();
+		//emit clearAutoCloseStack();
+		emitCursorPositionChanged();
+		repaintCursor();
+		selectionChange();
+		break;
+	}
+	
+	foreach ( QEditorInputBindingInterface *b, m_bindings )
+		b->postMousePressEvent(e, this);
+	
+}
+
+/*!
+	\internal
+*/
+void QEditor::mouseReleaseEvent(QMouseEvent *e)
+{
+	foreach ( QEditorInputBindingInterface *b, m_bindings )
+		if ( b->mouseReleaseEvent(e, this) )
+			return;
+	
+	m_scroll.stop();
+	
+	repaintCursor();
+	selectionChange();
+	
+	if ( flag(MaybeDrag) )
+	{
+		setFlag(MousePressed, false);
+		setCursorPosition(mapToContents(e->pos()));
+		
+		m_cursor.clearSelection();
+	}
+	
+	if ( flag(MousePressed) )
+	{
+		setFlag(MousePressed, false);
+		
+		setClipboardSelection();
+	} else if (	e->button() == Qt::MidButton
+				&& QApplication::clipboard()->supportsSelection()) {
+		setCursorPosition(mapToContents(e->pos()));
+		//setCursorPosition(viewport()->mapFromGlobal(e->globalPos()));
+		
+		const QMimeData *md = QApplication::clipboard()
+								->mimeData(QClipboard::Selection);
+		
+		if ( md )
+			insertFromMimeData(md);
+	}
+	
+	repaintCursor();
+	
+	if ( m_drag.isActive() )
+		m_drag.stop();
+	
+	selectionChange();
+	
+	foreach ( QEditorInputBindingInterface *b, m_bindings )
+		b->postMouseReleaseEvent(e, this);
+	
+}
+
+/*!
+	\internal
+*/
+void QEditor::mouseDoubleClickEvent(QMouseEvent *e)
+{
+	foreach ( QEditorInputBindingInterface *b, m_bindings )
+		if ( b->mouseDoubleClickEvent(e, this) )
+			return;
+	
+	forever
+	{
+		if ( e->button() != Qt::LeftButton )
+		{
+			e->ignore();
+			break;
+		}
+		
+		setFlag(MaybeDrag, false);
+		
+		repaintCursor();
+		selectionChange();
+		clearCursorMirrors();
+		setCursorPosition(mapToContents(e->pos()));
+		
+		//setFlag(FoldedCursor, isCollapsed());
+		
+		if ( m_cursor.isValid() )
+		{
+			m_cursor.select(QDocumentCursor::WordUnderCursor);
+			
+			setClipboardSelection();
+			//emit clearAutoCloseStack();
+			emitCursorPositionChanged();
+			
+			repaintCursor();
+			selectionChange();
+		} else {
+			//qDebug("invalid cursor");
+		}
+		
+		m_doubleClick = m_cursor;
+		
+		m_clickPoint = e->globalPos();
+		m_click.start(qApp->doubleClickInterval(), this);
+		break;
+	}
+	
+	foreach ( QEditorInputBindingInterface *b, m_bindings )
+		b->postMouseDoubleClickEvent(e, this);
+	
+}
+
+/*!
+	\internal
+*/
+void QEditor::dragEnterEvent(QDragEnterEvent *e)
+{
+	if (
+			e
+		&&
+			e->mimeData()
+		&&
+			(
+				e->mimeData()->hasFormat("text/plain")
+			||
+				e->mimeData()->hasFormat("text/html")
+			)
+		&&
+			!e->mimeData()->hasFormat("text/uri-list")
+		)
+		e->acceptProposedAction();
+	else
+		return;
+	
+	m_dragAndDrop = QDocumentCursor();
+}
+
+/*!
+	\internal
+*/
+void QEditor::dragLeaveEvent(QDragLeaveEvent *)
+{
+	const QRect crect = cursorRect(m_dragAndDrop);
+	m_dragAndDrop = QDocumentCursor();
+	
+	if ( crect.isValid() )
+		viewport()->update(crect);
+	
+}
+
+/*!
+	\internal
+*/
+void QEditor::dragMoveEvent(QDragMoveEvent *e)
+{
+	if (
+			e
+		&&
+			e->mimeData()
+		&&
+			(
+				e->mimeData()->hasFormat("text/plain")
+			||
+				e->mimeData()->hasFormat("text/html")
+			)
+		&&
+			!e->mimeData()->hasFormat("text/uri-list")
+		)
+		e->acceptProposedAction();
+	else
+		return;
+	
+	QDocumentCursor c = cursorForPosition(mapToContents(e->pos()));
+	
+	if ( c.isValid() )
+	{
+		QRect crect = cursorRect(m_dragAndDrop);
+		
+		if ( crect.isValid() )
+			viewport()->update(crect);
+		
+		m_dragAndDrop = c;
+		
+		crect = cursorRect(m_dragAndDrop);
+		viewport()->update(crect);
+	}
+	
+	//e->acceptProposedAction();
+}
+
+/*!
+	\internal
+*/
+void QEditor::dropEvent(QDropEvent *e)
+{
+	m_dragAndDrop = QDocumentCursor();
+	
+	QDocumentCursor c(cursorForPosition(mapToContents(e->pos())));
+	
+	if ( (e->source() == this) && (m_cursor.isWithinSelection(c)) )
+		return;
+	
+	if (
+			e
+		&&
+			e->mimeData()
+		&&
+			(
+				e->mimeData()->hasFormat("text/plain")
+			||
+				e->mimeData()->hasFormat("text/html")
+			)
+		&&
+			!e->mimeData()->hasFormat("text/uri-list")
+		&&
+			!flag(FoldedCursor)
+		)
+	{
+		e->acceptProposedAction();
+	} else {
+		return;
+	}
+	
+	//repaintSelection();
+	
+	m_doc->beginMacro();
+	//m_cursor.beginEditBlock();
+	
+	if (
+			(e->dropAction() == Qt::MoveAction)
+		&&
+			(
+				(e->source() == this)
+			||
+				(e->source() == viewport())
+			)
+		)
+	{
+		m_cursor.removeSelectedText();
+		
+		for ( int i = 0; i < m_mirrors.count(); ++i )
+			m_mirrors[i].removeSelectedText();
+		
+	} else {
+		//qDebug("action : %i", e->dropAction());
+		m_cursor.clearSelection();
+	}
+	
+	clearCursorMirrors();
+	m_cursor.moveTo(cursorForPosition(mapToContents(e->pos())));
+	insertFromMimeData(e->mimeData());
+	//m_cursor.endEditBlock();
+	
+	m_doc->endMacro();
+	
+	selectionChange();
+}
+
+/*!
+	\internal
+*/
+void QEditor::changeEvent(QEvent *e)
+{
+	QAbstractScrollArea::changeEvent(e);
+	
+	if (
+			e->type() == QEvent::ApplicationFontChange
+		||
+			e->type() == QEvent::FontChange
+		)
+	{
+		if ( !m_doc )
+			return;
+		
+		m_doc->setFont(font());
+		//setTabStop(iTab);
+		
+	}  else if ( e->type() == QEvent::ActivationChange ) {
+		if ( !isActiveWindow() )
+			m_scroll.stop();
+	}
+}
+
+/*!
+	\internal
+*/
+void QEditor::showEvent(QShowEvent *e)
+{
+	QCodeEdit *ce = QCodeEdit::manager(this);
+	
+	if ( ce )
+		ce->panelLayout()->update();
+	
+	QAbstractScrollArea::showEvent(e);
+	
+	if ( flag(LineWrap) )
+	{
+		m_doc->setWidthConstraint(wrapWidth());
+	}
+	
+	if ( flag(EnsureVisible) )
+		ensureCursorVisible();
+	
+}
+
+/*!
+	\internal
+	\brief Zoom in/out upon ctrl+wheel
+*/
+void QEditor::wheelEvent(QWheelEvent *e)
+{
+	if ( e->modifiers() & Qt::ControlModifier )
+	{
+		const int delta = e->delta();
+		
+		if ( delta > 0 )
+			zoom(-1);
+		else if ( delta < 0 )
+			zoom(1);
+		
+		//viewport()->update();
+		
+		return;
+	}
+	
+	QAbstractScrollArea::wheelEvent(e);
+	updateMicroFocus();
+	//viewport()->update();
+}
+
+/*!
+	\internal
+*/
+void QEditor::resizeEvent(QResizeEvent *)
+{
+	const QSize viewportSize = viewport()->size();
+	
+	if ( flag(LineWrap) )
+	{
+		//qDebug("resize t (2) : wrapping to %i", viewport()->width());
+		
+		m_doc->setWidthConstraint(wrapWidth());
+	} else {
+		horizontalScrollBar()->setMaximum(qMax(0, m_doc->width() - viewportSize.width()));
+		horizontalScrollBar()->setPageStep(viewportSize.width());
+	}
+	
+	const int ls = m_doc->fontMetrics().lineSpacing();
+	verticalScrollBar()->setMaximum(qMax(0, 1 + (m_doc->height() - viewportSize.height()) / ls));
+	verticalScrollBar()->setPageStep(viewportSize.height() / ls);
+	
+	//qDebug("page step : %i", viewportSize.height() / ls);
+	
+	//if ( isCursorVisible() && flag(LineWrap) )
+	//	ensureCursorVisible();
+}
+
+/*!
+	\internal
+*/
+void QEditor::focusInEvent(QFocusEvent *e)
+{
+	setFlag(CursorOn, true);
+	m_blink.start(QApplication::cursorFlashTime() / 2, this);
+	//ensureCursorVisible();
+	
+	QAbstractScrollArea::focusInEvent(e);
+}
+
+/*!
+	\internal
+*/
+void QEditor::focusOutEvent(QFocusEvent *e)
+{
+	setFlag(CursorOn, false);
+	m_blink.stop();
+	
+	QAbstractScrollArea::focusOutEvent(e);
+}
+
+/*!
+	\brief Context menu event
+	
+	All the (managed) actions added to the editor are showed in it by default.
+*/
+void QEditor::contextMenuEvent(QContextMenuEvent *e)
+{
+	foreach ( QEditorInputBindingInterface *b, m_bindings )
+		if ( b->contextMenuEvent(e, this) )
+			return;
+	
+	if ( !pMenu )
+	{
+		e->ignore();
+		return;
+	}
+	
+	selectionChange();
+	
+	e->accept();
+	
+	pMenu->exec(e->globalPos());
+}
+
+/*!
+	\brief Close event
+	
+	When build with qmdilib support (e.g in Edyuk) this check for
+	modifications and a dialog pops up to offer various options
+	(like saving, discarding or canceling)
+*/
+void QEditor::closeEvent(QCloseEvent *e)
+{
+	#ifdef _QMDI_
+	bool bOK = true;
+	
+	if ( isContentModified() )
+		bOK = server()->maybeSave(this);
+	
+	if ( bOK )
+	{
+		e->accept();
+		notifyDeletion();
+	} else {
+		e->ignore();
+	}
+	#else
+	QAbstractScrollArea::closeEvent(e);
+	#endif
+}
+
+#ifndef _QMDI_
+/*!
+	\return Whether the document has been modified.
+*/
+bool QEditor::isContentModified() const
+{
+	return m_doc ? !m_doc->isClean() : false;
+}
+#endif
+
+/*!
+	\brief Notify that the content is clean (modifications undone or document saved)
+	
+	\note Don't mess with this. The document knows better.
+*/
+void QEditor::setContentClean(bool y)
+{
+	setContentModified(!y);
+}
+
+/*!
+	\brief Notify that the content has been modified
+	
+	\note Don't mess with this. The document knows better.
+*/
+void QEditor::setContentModified(bool y)
+{
+	#ifdef _QMDI_
+	qmdiClient::setContentModified(y);
+	#endif
+	
+	setWindowModified(y);
+	emit contentModified(y);
+}
+
+/*!
+	\brief Changes the file name
+	
+	This method does not affect files on disk (no save/load/move occurs)
+*/
+void QEditor::setFileName(const QString& f)
+{
+	QString prev = fileName();
+	
+	if ( f == prev )
+		return;
+	
+	/*
+	QStringList l = m_watcher->files();
+	
+	if ( l.count() )
+		m_watcher->removePaths(l);
+	*/
+	
+	watcher()->removeWatch(QString(), this);
+	
+	#ifdef _QMDI_
+	qmdiClient::setFileName(f);
+	#else
+	m_fileName = f;
+	m_name = QFileInfo(f).fileName();
+	#endif
+	
+	//if ( fileName().count() )
+	//	m_watcher->addPath(fileName());
+	
+	if ( fileName().count() )
+		watcher()->addWatch(fileName(), this);
+	
+	setTitle(name().count() ? name() : "untitled");
+}
+
+/*!
+	\brief Set the title of the widget
+	
+	Take care of adding a "[*]" prefix so that document changes are visible
+	on title bars.
+*/
+void QEditor::setTitle(const QString& title)
+{
+	QString s(title);
+	
+	if ( !s.contains("[*]") )
+		s.prepend("[*]");
+	
+	setWindowTitle(s);
+	emit titleChanged(title);
+}
+
+#ifndef _QMDI_
+/*!
+	\return The name of the file being edited (without its path)
+*/
+QString QEditor::name() const
+{
+	return m_name;
+}
+
+/*!
+	\return The full filename of the file being edited
+*/
+QString QEditor::fileName() const
+{
+	return m_fileName;
+}
+#endif
+
+/*!
+	\brief Prevent tab key press to be considered as widget navigation
+*/
+bool QEditor::focusNextPrevChild(bool)
+{
+	// make sure we catch tabs :)
+	
+	return false;
+}
+
+/*!
+	\brief Start a drag and drop operation using the current selection
+*/
+void QEditor::startDrag()
+{
+	setFlag(MousePressed, false);
+	QMimeData *data = createMimeDataFromSelection();
+	
+	QDrag *drag = new QDrag(this);
+	drag->setMimeData(data);
+	
+	Qt::DropActions actions = Qt::CopyAction | Qt::MoveAction;
+	Qt::DropAction action = drag->start(actions);
+	
+	if ( (action == Qt::MoveAction) && (drag->target() != this) )
+	{
+		m_cursor.removeSelectedText();
+		
+		for ( int i = 0; i < m_mirrors.count(); ++i )
+			m_mirrors[i].removeSelectedText();
+	}
+}
+
+/*!
+	\brief Handle cursor movements upon key event
+*/
+bool QEditor::moveKeyEvent(QDocumentCursor& cursor, QKeyEvent *e, bool *leave)
+{
+	QDocumentCursor::MoveMode mode = e->modifiers() & Qt::ShiftModifier
+								? QDocumentCursor::KeepAnchor
+								: QDocumentCursor::MoveAnchor;
+	
+	if ( flag(LineWrap) && flag(CursorJumpPastWrap) )
+		mode |= QDocumentCursor::ThroughWrap;
+	
+	QDocumentCursor::MoveOperation op = QDocumentCursor::NoMove;
+#ifdef Q_WS_MAC
+	// There can be only one modifier (+ shift), but we also need to make sure
+	// that we have a "move key" pressed before we reject it.
+	bool twoModifiers
+		= ((e->modifiers() & (Qt::ControlModifier | Qt::AltModifier))
+			== (Qt::ControlModifier | Qt::AltModifier))
+		|| ((e->modifiers() & (Qt::ControlModifier | Qt::MetaModifier))
+			== (Qt::ControlModifier | Qt::MetaModifier))
+		|| ((e->modifiers() & (Qt::AltModifier | Qt::MetaModifier))
+			== (Qt::AltModifier | Qt::MetaModifier));
+#else
+	if (e->modifiers() & (Qt::AltModifier |
+		Qt::MetaModifier | Qt::KeypadModifier) )
+	{
+		e->ignore();
+		if ( leave ) *leave = false;
+		return false;
+	}
+#endif
+	
+	switch ( e->key() )
+	{
+#ifndef Q_WS_MAC  // Use the default Windows bindings.
+        case Qt::Key_Up:
+            op = QDocumentCursor::Up;
+            break;
+        case Qt::Key_Down:
+            op = QDocumentCursor::Down;
+            /*
+            if (mode == QDocumentCursor::KeepAnchor) {
+                QTextBlock block = cursor.block();
+                QTextLine line = currentTextLine(cursor);
+                if (!block.next().isValid()
+                    && line.isValid()
+                    && line.lineNumber() == block.layout()->lineCount() - 1)
+                    op = QDocumentCursor::End;
+            }
+            */
+            break;
+        case Qt::Key_Left:
+            op = e->modifiers() & Qt::ControlModifier
+                 ? QDocumentCursor::WordLeft
+                 : QDocumentCursor::Left;
+            break;
+        case Qt::Key_Right:
+            op = e->modifiers() & Qt::ControlModifier
+                 ? QDocumentCursor::WordRight
+                 : QDocumentCursor::Right;
+            break;
+        case Qt::Key_Home:
+            op = e->modifiers() & Qt::ControlModifier
+                 ? QDocumentCursor::Start
+                 : QDocumentCursor::StartOfLine;
+            break;
+        case Qt::Key_End:
+            op = e->modifiers() & Qt::ControlModifier
+                 ? QDocumentCursor::End
+                 : QDocumentCursor::EndOfLine;
+            break;
+#else
+/*
+	Except for pageup and pagedown, Mac OS X has very different behavior, we
+	don't do it all, but here's the breakdown:
+	
+	Shift still works as an anchor, but only one of the other keys can be dow
+	Ctrl (Command), Alt (Option), or Meta (Control).
+	
+	Command/Control + Left/Right -- Move to left or right of the line
+					+ Up/Down -- Move to top bottom of the file.
+					(Control doesn't move the cursor)
+	
+	Option	+ Left/Right -- Move one word Left/right.
+			+ Up/Down  -- Begin/End of Paragraph.
+	
+	Home/End Top/Bottom of file. (usually don't move the cursor, but will select)
+*/
+        case Qt::Key_Up:
+            if (twoModifiers) {
+                QApplication::beep();
+                if ( leave ) *leave = false;
+                return true;
+            } else {
+                if (e->modifiers() & (Qt::ControlModifier | Qt::MetaModifier))
+                    op = QDocumentCursor::Start;
+                else if (e->modifiers() & Qt::AltModifier)
+                    op = QDocumentCursor::StartOfBlock;
+                else
+                    op = QDocumentCursor::Up;
+            }
+            break;
+        case Qt::Key_Down:
+            if (twoModifiers) {
+                QApplication::beep();
+                if ( leave ) *leave = false;
+                return true;
+            } else {
+                if (e->modifiers() & (Qt::ControlModifier | Qt::MetaModifier))
+                {
+                    op = QDocumentCursor::End;
+                } else if (e->modifiers() & Qt::AltModifier) {
+                    op = QDocumentCursor::EndOfBlock;
+                } else {
+                    op = QDocumentCursor::Down;
+                    /*
+                    if (mode == QDocumentCursor::KeepAnchor) {
+                        QTextBlock block = cursor.block();
+                        QTextLine line = currentTextLine(cursor);
+                        if (!block.next().isValid()
+                            && line.isValid()
+                            && line.lineNumber() ==
+                            	block.layout()->lineCount() - 1)
+                            op = QDocumentCursor::End;
+                    }
+                    */
+                }
+            }
+            break;
+        case Qt::Key_Left:
+            if (twoModifiers) {
+                QApplication::beep();
+                if ( leave ) *leave = false;
+                return true;
+            } else {
+                if (e->modifiers() & (Qt::ControlModifier | Qt::MetaModifier))
+                    op = QDocumentCursor::StartOfLine;
+                else if (e->modifiers() & Qt::AltModifier)
+                    op = QDocumentCursor::WordLeft;
+                else
+                    op = QDocumentCursor::Left;
+            }
+            break;
+        case Qt::Key_Right:
+            if ( twoModifiers )
+            {
+                QApplication::beep();
+                if ( leave ) *leave = false;
+                return true;
+            } else {
+                if (e->modifiers() & (Qt::ControlModifier | Qt::MetaModifier))
+                    op = QDocumentCursor::EndOfLine;
+                else if (e->modifiers() & Qt::AltModifier)
+                    op = QDocumentCursor::WordRight;
+                else
+                    op = QDocumentCursor::Right;
+            }
+            break;
+        case Qt::Key_Home:
+            if (e->modifiers() & (Qt::ControlModifier |
+            	Qt::MetaModifier | Qt::AltModifier) )
+            {
+                QApplication::beep();
+                if ( leave ) *leave = false;
+                return true;
+            } else {
+                op = QDocumentCursor::Start;
+            }
+            break;
+        case Qt::Key_End:
+            if (e->modifiers() & (Qt::ControlModifier |
+            	Qt::MetaModifier | Qt::AltModifier))
+            {
+                QApplication::beep();
+                if ( leave ) *leave = false;
+                return true;
+            } else {
+                op = QDocumentCursor::End;
+            }
+            break;
+#endif
+		case Qt::Key_PageDown:
+			if ( leave ) *leave = true;
+			pageDown(mode);
+			return true;
+			
+		case Qt::Key_PageUp:
+			if ( leave ) *leave = true;
+			pageUp(mode);
+			return true;
+			
+		case Qt::Key_Insert :
+			if ( !e->modifiers() )
+			{
+				if ( leave ) *leave = false;
+				setFlag(Overwrite, !flag(Overwrite));
+				
+				// hack to make sure status panel gets updated...
+				// TODO : emit signals on flag change?
+				emitCursorPositionChanged();
+				return false;
+			}
+			
+		default:
+			return false;
+	}
+	
+	int prev = cursor.lineNumber();
+	
+	//const bool moved = 
+	cursor.movePosition(1, op, mode);
+	
+	if ( prev != cursor.lineNumber() )
+	{
+		if ( m_curPlaceHolder >= 0 && m_curPlaceHolder < m_placeHolders.count() )
+		{
+			// allow mirror movement out of line while in placeholder
+			PlaceHolder& ph = m_placeHolders[m_curPlaceHolder];
+			if ( ph.cursor.isWithinSelection(cursor) )
+				return true;
+			for ( int i = 0; i < ph.mirrors.count(); ++i )
+				if ( ph.mirrors.at(i).isWithinSelection(cursor) )
+					return true;
+		}
+		//moved = true;
+		if ( leave ) *leave = true;
+		m_curPlaceHolder = -1;
+	}
+	
+	return true;
+}
+
+/*!
+	\brief Go up by one page
+	
+	\note This method clears all cursor mirrors and suspend placeholder edition.
+*/
+void QEditor::pageUp(QDocumentCursor::MoveMode moveMode)
+{
+	clearCursorMirrors();
+	m_curPlaceHolder = -1;
+	
+	if ( m_cursor.atStart() )
+		return;
+	
+	int n = viewport()->height() / QDocument::fontMetrics().lineSpacing();
+	
+	repaintCursor();
+	m_cursor.movePosition(n, QDocumentCursor::Up, moveMode);
+	
+	ensureCursorVisible();
+	emitCursorPositionChanged();
+	//updateMicroFocus();
+}
+
+/*!
+	\brief Go down by one page
+	
+	\note This method clears all cursor mirrors.
+*/
+void QEditor::pageDown(QDocumentCursor::MoveMode moveMode)
+{
+	clearCursorMirrors();
+	m_curPlaceHolder = -1;
+	
+	if ( m_cursor.atEnd() )
+		return;
+	
+	int n = viewport()->height() / QDocument::fontMetrics().lineSpacing();
+	
+	repaintCursor();
+	m_cursor.movePosition(n, QDocumentCursor::Down, moveMode);
+	
+	ensureCursorVisible();
+	emitCursorPositionChanged();
+}
+
+/*!
+	\brief Determine whether a given key event is an editing operation
+*/
+bool QEditor::isProcessingKeyEvent(QKeyEvent *e, int *offset)
+{
+	if ( flag(FoldedCursor) )
+		return false;
+	
+	switch ( e->key() )
+	{
+		case Qt::Key_Backspace :
+			//--*offset;
+			break;
+			
+		case Qt::Key_Delete :
+			//--*offset;
+			break;
+			
+		case Qt::Key_Enter :
+		case Qt::Key_Return :
+			if ( offset )
+				++*offset;
+			break;
+			
+		default :
+		{
+			QString text = e->text();
+			
+			if ( text.isEmpty() || !(text.at(0).isPrint() || (text.at(0) == '\t')) )
+				return false;
+			
+			//if ( offset )
+			//	*offset += text.length();
+			
+			break;
+		}
+	}
+	
+	return true;
+}
+
+/*!
+	\internal
+	\brief Process a key event for a given cursor
+	
+	This method only take care of editing operations, not movements.
+*/
+bool QEditor::processCursor(QDocumentCursor& c, QKeyEvent *e, bool& b)
+{
+	if ( !b )
+		return false;
+	
+	bool hasSelection = c.hasSelection();
+	
+	switch ( e->key() )
+	{
+		case Qt::Key_Backspace :
+			if ( flag(FoldedCursor) )
+				return false;
+			
+			if ( hasSelection )
+				c.removeSelectedText();
+			else
+				c.deletePreviousChar();
+			
+			break;
+			
+		case Qt::Key_Delete :
+			if ( flag(FoldedCursor) )
+				return false;
+			
+			if ( hasSelection )
+			
+				c.removeSelectedText();
+			else
+				c.deleteChar();
+			
+			//emit clearAutoCloseStack();
+			break;
+			
+		case Qt::Key_Enter :
+		case Qt::Key_Return :
+		{
+			if ( flag(FoldedCursor) )
+				return false;
+			
+			c.beginEditBlock();
+			
+			if ( hasSelection )
+				c.removeSelectedText();
+			else if ( flag(Overwrite) )
+				c.deleteChar();
+			
+			QString indent;
+			
+			if ( flag(AutoIndent) && (m_curPlaceHolder == -1) )
+			{
+				if ( m_definition )
+				{
+					indent = m_definition->indent(c);
+				} else {
+					// default : keep leading ws from previous line...
+					QDocumentLine l = c.line();
+					const int idx = qMin(l.firstChar(), c.columnNumber());
+					
+					indent = l.text();
+					
+					if ( idx != -1 )
+						indent.resize(idx);
+					
+				}
+			}
+			
+			if ( indent.count() )
+			{
+				indent.prepend("\n");
+				c.insertText(indent);
+			} else {
+				c.insertLine();
+			}
+			
+			c.endEditBlock();
+			
+			break;
+		}
+			
+		default :
+		{
+			QString text = e->text();
+			
+			if ( text.isEmpty() || !(text.at(0).isPrint() || (text.at(0) == '\t')) )
+			{
+				b = false;
+				return false;
+			}
+			
+			if ( flag(ReplaceTabs) )
+			{
+				text.replace("\t", QString(m_doc->tabStop(), ' '));
+			}
+			
+			c.beginEditBlock();
+			insertText(c, text);
+			c.endEditBlock();
+			
+			break;
+		}
+	}
+	
+	selectionChange();
+	
+	return true;
+}
+
+void QEditor::preInsert(QDocumentCursor& c, const QString& s)
+{
+	if (
+			flag(AutoIndent)
+		&&
+			(m_curPlaceHolder == -1)
+		&&
+			c.columnNumber()
+		&&
+			m_definition
+		&&
+			m_definition->unindent(c, s)
+		)
+	{
+		int firstNS = 0;
+		QString txt = c.line().text();
+		
+		while ( (firstNS < txt.length()) && txt.at(firstNS).isSpace() )
+			++firstNS;
+		
+		if ( !firstNS )
+			return;
+		
+		const int off = c.columnNumber() - firstNS;
+		
+		if ( off > 0 )
+			c.movePosition(off, QDocumentCursor::PreviousCharacter);
+		
+		/*
+			It might be possible to improve that part to have a more natural/smarter unindenting
+			by trying to guess the scheme used by the user...
+		*/
+		
+		if ( txt.at(firstNS - 1) == '\t' )
+		{
+			c.movePosition(1, QDocumentCursor::Left, QDocumentCursor::KeepAnchor);
+		} else {
+			const int ts = m_doc->tabStop();
+			
+			do
+			{
+				--firstNS;
+				c.movePosition(1, QDocumentCursor::Left, QDocumentCursor::KeepAnchor);
+			} while ( QDocument::screenLength(txt.constData(), firstNS, ts) % ts );
+		}
+		
+		c.removeSelectedText();
+		
+		if ( off > 0 )
+			c.movePosition(off, QDocumentCursor::NextCharacter);
+		
+	}
+}
+
+/*!
+	\brief Insert some text at a given cursor position
+	
+	This function is provided to keep indenting/outdenting working when editing
+*/
+void QEditor::insertText(QDocumentCursor& c, const QString& text)
+{
+	if ( protectedCursor(c) )
+		return;
+	
+	bool hasSelection = c.hasSelection();
+	
+	if ( hasSelection )
+		c.removeSelectedText();
+	
+	if ( !hasSelection && flag(Overwrite) )
+		c.deleteChar();
+	
+	QStringList lines = text.split('\n', QString::KeepEmptyParts);
+	
+	if ( (lines.count() == 1) || !flag(AdjustIndent) )
+	{
+		preInsert(c, lines.first());
+		
+		if ( flag(ReplaceTabs) )
+		{
+			// TODO : replace tabs by spaces properly
+		}
+		
+		c.insertText(text);
+	} else {
+		
+		preInsert(c, lines.first());
+		c.insertText(lines.takeFirst());
+		
+		QString indent;
+		// FIXME ? work on strings to make sure command grouping does not interfere with cursor state...
+		
+		indent = c.line().text().left(qMax(0, qMin(c.line().firstChar(), c.columnNumber())));
+		
+		foreach ( QString l, lines )
+		{
+			int n = 0;
+			
+			while ( n < l.count() && l.at(n).isSpace() )
+				++n;
+			
+			l.remove(0, n);
+			
+			if ( m_definition )
+			{
+				// FIXME ? work on strings to make sure command grouping does not interfere with cursor state...
+				indent = m_definition->indent(c);
+				
+				if ( flag(ReplaceTabs) )
+					indent.replace("\t", QString(m_doc->tabStop(), ' '));
+			}
+			
+			c.insertLine();
+			c.insertText(indent);
+			
+			preInsert(c, l);
+			
+			c.insertText(l);
+		}
+	}
+}
+
+/*!
+	\brief Write some text at the current cursor position
+	
+	This function is provided to make editing operations easier
+	from the outside and to keep them compatible with cursor
+	mirrors.
+*/
+void QEditor::write(const QString& s)
+{
+	m_doc->beginMacro();
+	
+	insertText(m_cursor, s);
+	
+	for ( int i = 0; i < m_mirrors.count(); ++i )
+		insertText(m_mirrors[i], s);
+	
+	m_doc->endMacro();
+	
+	emitCursorPositionChanged();
+	setFlag(CursorOn, true);
+	ensureCursorVisible();
+	repaintCursor();
+	selectionChange();
+}
+
+/*!
+	\brief Zoom
+	\param n relative zoom factor
+	
+	Zooming is achieved by changing the point size of the font as follow :
+	
+	fontPointSize += \a n
+*/
+void QEditor::zoom(int n)
+{
+	if ( !m_doc )
+		return;
+	
+	QFont f = m_doc->font();
+	f.setPointSize(qMax(1, f.pointSize() + n));
+	m_doc->setFont(f);
+}
+
+/*!
+	\brief Obtain the value of panel margins
+	\param l left margin
+	\param t top margin
+	\param r right margin
+	\param b bottom margin
+*/
+void QEditor::getPanelMargins(int *l, int *t, int *r, int *b) const
+{
+	m_margins.getCoords(l, t, r, b);
+}
+
+/*!
+	\brief Change the viewport margins to make room for panels
+	\param l left margin
+	\param t top margin
+	\param r right margin
+	\param b bottom margin
+*/
+void QEditor::setPanelMargins(int l, int t, int r, int b)
+{
+	m_margins.setCoords(l, t, r, b);
+	
+	setViewportMargins(l, t, r, b);
+
+	if ( flag(LineWrap) )
+	{
+		//qDebug("panel adjust : wrapping to %i", viewport()->width());
+		m_doc->setWidthConstraint(wrapWidth());
+	}
+}
+
+/*!
+	\deprecated
+	\brief Does not do anything anymore...
+*/
+void QEditor::selectionChange(bool force)
+{
+	Q_UNUSED(force)
+	// TODO : repaint only selection rect
+	/*
+	if ( false )//force )
+	{
+		//qDebug("repainting selection... [%i]", force);
+		viewport()->update();
+	} else if ( m_cursor.hasSelection() ) {
+		viewport()->update(selectionRect());
+	}
+	
+	m_selection = m_cursor.hasSelection();
+	*/
+}
+
+/*!
+	\brief Request repaint (using QWidget::update()) for the region occupied by the cursor
+*/
+void QEditor::repaintCursor()
+{
+	if ( m_mirrors.count() )
+		viewport()->update();
+	
+	QRect r = cursorRect();
+	
+	if ( m_crect != r )
+	{
+		viewport()->update(m_crect.translated(horizontalOffset(), 0));
+		m_crect = r;
+		viewport()->update(m_crect.translated(horizontalOffset(), 0));
+	} else {
+		viewport()->update(m_crect.translated(horizontalOffset(), 0));
+	}
+}
+
+/*!
+	\return whether the cursor is currently visible
+*/
+bool QEditor::isCursorVisible() const
+{
+	QPoint pos = m_cursor.documentPosition();
+	
+	const QRect cursor(pos.x(), pos.y(), 1, QDocument::fontMetrics().lineSpacing());
+	const QRect display(horizontalOffset(), verticalOffset(), viewport()->width(), viewport()->height());
+	
+	//qDebug() << pos << " belongs to " << display << " ?";
+	
+	return display.contains(pos); //cursor);
+}
+
+/*!
+	\brief Ensure that the current cursor is visible
+*/
+void QEditor::ensureCursorVisible()
+{
+	if ( !isVisible() )
+	{
+		setFlag(EnsureVisible, true);
+		return;
+	}
+	
+	QPoint pos = m_cursor.documentPosition();
+	
+	const int ls = QDocument::fontMetrics().lineSpacing();
+	
+	int ypos = pos.y(),
+		yval = verticalOffset(),
+		ylen = viewport()->height(),
+		yend = ypos + ls;
+	
+	if ( ypos < yval )
+		verticalScrollBar()->setValue(ypos / ls);
+	else if ( yend > (yval + ylen) )
+		verticalScrollBar()->setValue(1 + (yend - ylen) / ls);
+	
+	int xval = horizontalOffset(),
+		xlen = viewport()->width(),
+		xpos = pos.x();
+	
+	if ( xpos < xval )
+	{
+		//qDebug("scroll leftward");
+		horizontalScrollBar()->setValue(qMax(0, xpos - 4));
+	} else if ( xpos > (xval + xlen - 4) ) {
+		//qDebug("scroll rightward : %i", xpos - xlen + 4);
+		horizontalScrollBar()
+			->setValue(qMax(horizontalScrollBar()->value(), xpos - xlen + 4));
+	}
+	
+	setFlag(EnsureVisible, false);
+}
+
+/*!
+	\brief ensure that a given line is visible by updating scrollbars if needed
+*/
+void QEditor::ensureVisible(int line)
+{
+	if ( !m_doc )
+		return;
+	
+	const int ls = QDocument::fontMetrics().lineSpacing();
+	int ypos = m_doc->y(line),
+		yval = verticalOffset(),
+		ylen = viewport()->height(),
+		yend = ypos + ls;
+	
+	if ( ypos < yval )
+		verticalScrollBar()->setValue(ypos / ls);
+	else if ( yend > (yval + ylen) )
+		verticalScrollBar()->setValue(1 + (yend - ylen) / ls);
+	
+}
+
+/*!
+	\brief Ensure that a given rect is visible by updating scrollbars if needed
+*/
+void QEditor::ensureVisible(const QRect &rect)
+{
+	if ( !m_doc )
+		return;
+	
+	const int ls = QDocument::fontMetrics().lineSpacing();
+	int ypos = rect.y(),
+		yval = verticalOffset(),
+		ylen = viewport()->height(),
+		yend = ypos + rect.height();
+	
+	if ( ypos < yval )
+		verticalScrollBar()->setValue(ypos / ls);
+	else if ( yend > (yval + ylen) )
+		verticalScrollBar()->setValue(1 + (yend - ylen) / ls);
+	
+	//verticalScrollBar()->setValue(rect.y());
+}
+
+/*!
+	\return the rectangle occupied by the current cursor
+	
+	This will either return a cursorRect for the current cursor or
+	the selectionRect() if the cursor has a selection.
+	
+	The cursor position, which would be the top left corner of the actual
+	rectangle occupied by the cursor can be obtained using QDocumentCursor::documentPosition()
+	
+	The behavior of this method may surprise newcomers but it is actually quite sensible
+	as this rectangle is mainly used to specify the update rect of the widget and the whole
+	line needs to be updated to properly update the line background whenever the cursor move
+	from a line to another.
+*/
+QRect QEditor::cursorRect() const
+{
+	return m_cursor.hasSelection() ? selectionRect() : cursorRect(m_cursor);
+}
+
+/*!
+	\return the rectangle occupied by the selection in viewport coordinates
+	
+	If the current cursor does not have a selection, its cursorRect() is returned.
+	
+	The returned rectangle will always be bigger than the actual selection has
+	it is actually the union of all the rectangles occupied by all lines the selection
+	spans over.
+*/
+QRect QEditor::selectionRect() const
+{
+	if ( !m_cursor.hasSelection() )
+		return cursorRect(m_cursor);
+	
+	QDocumentSelection s = m_cursor.selection();
+	
+	if ( s.startLine == s.endLine )
+		return cursorRect(m_cursor);
+	
+	int y = m_doc->y(s.startLine);
+	QRect r = m_doc->lineRect(s.endLine);
+	int height = r.y() + r.height() - y;
+	
+	r = QRect(0, y, viewport()->width(), height);
+	r.translate(-horizontalOffset(), -verticalOffset());
+	return r;
+}
+
+/*!
+	\return the rectangle occupied by the given line, in viewport coordinates
+	
+	The width of the returned rectangle will always be the viewport width.
+*/
+QRect QEditor::lineRect(int line) const
+{
+	if ( !m_doc )
+		return QRect();
+	
+	QRect r = m_doc->lineRect(line);
+	r.setWidth(viewport()->width());
+	r.translate(-horizontalOffset(), -verticalOffset());
+	
+	return r;
+}
+
+/*!
+	\overload
+	
+	\note This function relies on QDocumentLine::lineNumber() so avoid
+	it whenever possible as it is much slower than providing a line number
+	directly.
+*/
+QRect QEditor::lineRect(const QDocumentLine& l) const
+{
+	//qFatal("bad practice...");
+	
+	if ( !m_doc )
+		return QRect();
+	
+	QRect r = m_doc->lineRect(l);
+	r.setWidth(viewport()->width());
+	r.translate(-horizontalOffset(), -verticalOffset());
+	
+	return r;
+}
+
+/*!
+	\return The line rect of the given cursor
+*/
+QRect QEditor::cursorRect(const QDocumentCursor& c) const
+{
+	return lineRect(c.lineNumber());
+}
+
+/*!
+	\brief creates a valid QMimeData object depending on the selection
+*/
+QMimeData* QEditor::createMimeDataFromSelection() const
+{
+	QMimeData *d = new QMimeData;
+	
+	if ( !m_cursor.hasSelection() )
+	{
+		qWarning("Generated empty MIME data");
+		return d;
+	}
+	
+	if ( m_mirrors.isEmpty() )
+	{
+		d->setText(m_cursor.selectedText());
+	} else {
+		QString serialized = m_cursor.selectedText();
+		
+		foreach ( const QDocumentCursor& m, m_mirrors )
+		{
+			serialized += '\n';
+			serialized += m.selectedText();
+		}
+		
+		d->setText(serialized);
+		d->setData("text/column-selection", serialized.toLocal8Bit());
+	}
+	
+	//qDebug("generated selection from : \"%s\"", qPrintable(d->text()));
+	
+	return d;
+}
+
+static void fixLineEndings(QString& text)
+{
+	// deal with Dos first to avoid line endings duplication
+	text.replace("\r\n", "\n");
+	
+	text.replace('\r', '\n');
+}
+
+/*!
+	\brief Inserts the content of a QMimeData object at the cursor position
+	
+	\note Only plain text is supported... \see QMimeData::hasText()
+*/
+void QEditor::insertFromMimeData(const QMimeData *d)
+{
+	bool s = m_cursor.hasSelection();
+	
+	if ( !d )
+		return;
+	
+	if ( d->hasFormat("text/uri-list") )
+	{
+		
+		return;
+	}
+	
+	if ( m_cursor.isValid() )
+	{
+		if ( d->hasFormat("text/column-selection") )
+		{
+			clearCursorMirrors();
+			
+			QStringList columns = QString::fromLocal8Bit(
+										d->data("text/column-selection")
+									).split('\n');
+			
+			m_doc->beginMacro();
+			
+			if ( s )
+				m_cursor.removeSelectedText();
+			
+			int col = m_cursor.columnNumber();
+			//m_cursor.insertText(columns.takeFirst());
+			insertText(m_cursor, columns.takeFirst());
+			QDocumentCursor c = m_cursor;
+			
+			while ( columns.count() )
+			{
+				// check for end of doc and add line if needed...
+				c.setColumnNumber(c.line().length());
+				
+				if ( c.atEnd() )
+					c.insertText("\n");
+				else
+					c.movePosition(1, QDocumentCursor::NextCharacter);
+				
+				// align
+				c.setColumnNumber(qMin(col, c.line().length()));
+				
+				// copy content of clipboard
+				//c.insertText(columns.takeFirst());
+				insertText(c, columns.takeFirst());
+				addCursorMirror(c);
+			}
+			
+			m_doc->endMacro();
+			
+		} else {
+			m_doc->beginMacro();
+			
+			//if ( s )
+			//{
+			//	m_cursor.removeSelectedText();
+			//}
+			
+			QString txt;
+			
+			if ( d->hasFormat("text/plain") )
+				txt = d->text();
+			else if ( d->hasFormat("text/html") )
+				txt = d->html();
+			
+			fixLineEndings(txt);
+			
+			insertText(m_cursor, txt);
+			
+			for ( int i = 0; i < m_mirrors.count(); ++i )
+			{
+				insertText(m_mirrors[i], txt);
+			}
+			
+			m_doc->endMacro();
+		}
+		
+		ensureCursorVisible();
+		setFlag(CursorOn, true);
+		
+		emitCursorPositionChanged();
+	}
+}
+
+/*!
+	\brief Removes all cursor mirrors
+*/
+void QEditor::clearCursorMirrors()
+{
+	if ( m_mirrors.isEmpty() )
+		return;
+	
+	m_curPlaceHolder = -1;
+	repaintCursor();
+
+	for ( int i = 0; i < m_mirrors.count(); ++i )
+	{
+		m_mirrors[i].setAutoUpdated(false);
+	}
+	
+	m_mirrors.clear();
+	
+	viewport()->update();
+}
+
+/*!
+	\brief Add a cursor mirror
+*/
+void QEditor::addCursorMirror(const QDocumentCursor& c)
+{
+	if ( c.isNull() || (c == m_cursor) || m_mirrors.contains(c) )
+		return;
+	
+	m_mirrors << c;
+	
+	// necessary for smooth mirroring
+	m_mirrors.last().setSilent(true);
+	m_mirrors.last().setAutoUpdated(true);
+}
+
+/*!
+	\internal
+	\brief Copy the selection to the clipboard
+*/
+void QEditor::setClipboardSelection()
+{
+	QClipboard *clipboard = QApplication::clipboard();
+	
+	if ( !clipboard->supportsSelection() || !m_cursor.hasSelection() )
+		return;
+	
+	QMimeData *data = createMimeDataFromSelection();
+	
+	clipboard->setMimeData(data, QClipboard::Selection);
+}
+
+/*!
+	\internal
+	\brief Scroll contents
+	
+	Refer to QAbstractScrollArea doc for more info.
+*/
+void QEditor::scrollContentsBy(int dx, int dy)
+{
+	#ifdef Q_GL_EDITOR
+	viewport()->update();
+	#else
+	const int ls = m_doc->fontMetrics().lineSpacing();
+	viewport()->scroll(dx, dy * ls);
+	#endif
+}
+
+/*!
+	\internal
+	\brief Workaround inconsistent width determination of viewport width
+	accross platfroms when scrollbars are visible...
+*/
+int QEditor::wrapWidth() const
+{
+	#ifdef Q_WS_WIN
+	//if ( verticalScrollBar()->isVisible() )
+	//	return viewport()->width() - verticalScrollBar()->width();
+	#endif
+	return viewport()->width();
+}
+
+/*!
+	\internal
+	\brief Slot called whenever document width changes
+	
+	Horizontal scrollbar is updated here.
+	
+	\note ensureCursorVisible() is NOT called.
+*/
+void QEditor::documentWidthChanged(int newWidth)
+{
+	if ( flag(LineWrap) )
+	{
+		horizontalScrollBar()->setMaximum(0);
+		return;
+	}
+	
+	int nv = qMax(0, newWidth - wrapWidth());
+	
+	horizontalScrollBar()->setMaximum(nv);
+	
+	//ensureCursorVisible();
+}
+
+/*!
+	\internal
+	\brief Slot called whenever document height changes
+	
+	Vertical scrollbar is updated here (maximum is changed
+	and value is modified if needed to ensure that the cursor is visible)
+*/
+void QEditor::documentHeightChanged(int newHeight)
+{
+	if ( flag(LineWrap) )
+	{
+		m_doc->setWidthConstraint(wrapWidth());
+	}
+	const int ls = m_doc->fontMetrics().lineSpacing();
+	verticalScrollBar()->setMaximum(qMax(0, 1 + (newHeight - viewport()->height()) / ls));
+	//ensureCursorVisible();
+}
+
+/*!
+	\internal
+	\brief Request paint event upon modification
+	\param i first modified line
+	\param n number of modified lines
+*/
+void QEditor::repaintContent(int i, int n)
+{
+	if ( !m_doc )
+		return;
+	
+	#ifdef Q_GL_EDITOR
+	viewport()->update();
+	#else
+	if ( n <= 0 )
+	{
+		viewport()->update();
+	}
+	
+	QRect frect = m_doc->lineRect(i);
+	
+	const int yoff = verticalOffset() + viewport()->height();
+	
+	if ( frect.y() > yoff )
+		return;
+	
+	if ( n == 1 )
+	{
+		frect.translate(0, -verticalOffset());
+		//qDebug() << frect;
+		viewport()->update(frect);
+		return;
+	}
+	
+	QRect lrect = m_doc->lineRect(i + n - 1);
+	
+	if ( (n > 0) && (lrect.y() + lrect.height()) < verticalOffset() )
+		return;
+	
+	//qDebug("repainting %i lines starting from %ith one", n, i);
+	
+	//rect.setWidth(viewport()->width());
+	//rect.setHeight(qMin(viewport()->height(), rect.height() * n));
+	
+	const int paintOffset = frect.y() - verticalOffset();
+	const int paintHeight = lrect.y() + lrect.height() - frect.y();
+	const int maxPaintHeight = viewport()->height() - paintOffset;
+	
+	QRect rect = QRect(
+				frect.x(),
+				paintOffset,
+				viewport()->width(),
+					(n <= 0)
+				?
+					maxPaintHeight
+				:
+					qMin(maxPaintHeight, paintHeight)
+			);
+	
+	//qDebug() << rect;
+	
+	viewport()->update(rect);
+	#endif
+}
+
+/*!
+	\internal
+	\brief Update function called upon editing action
+	\param i First modified line
+	\param n Number of modified lines
+	
+	If more than one line has been modified this function
+	causes a repaint from the first visible line to the end
+	of the viewport due to the way QAbstractScrollArea
+	handles scrolling.
+	
+	\note This function used to update formatting but
+	the highlighting has been moved to QDocument recently
+*/
+void QEditor::updateContent (int i, int n)
+{
+	if ( !m_doc )
+		return;
+	
+	//qDebug("updating %i, %i", i, n);
+	
+	bool cont = n > 1;
+	
+	repaintContent(i, cont ? -1 : n);
+}
+
+/*!
+	\internal
+*/
+void QEditor::markChanged(QDocumentLineHandle *l, int mark, bool on)
+{
+	emit markChanged(fileName(), l, mark, on);
+}
+
+/*! @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qeditor.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,471 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QEDITOR_H_
+#define _QEDITOR_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qeditor.h
+	\brief Definition of the QEditor class
+*/
+
+#include <QHash>
+#include <QPointer>
+#include <QScrollBar>
+#include <QBasicTimer>
+#include <QFontMetrics>
+#include <QAbstractScrollArea>
+
+#include "qdocument.h"
+#include "qdocumentcursor.h"
+
+#ifdef _QMDI_
+	#include "qmdiclient.h"
+#endif
+
+class QMenu;
+class QAction;
+class QMimeData;
+class QTextCodec;
+class QActionGroup;
+
+class QReliableFileWatch;
+
+class QDocumentLineHandle;
+
+class QLanguageDefinition;
+class QCodeCompletionEngine;
+
+class QEditorInputBindingInterface;
+
+class QCE_EXPORT QEditor : public QAbstractScrollArea
+#ifdef _QMDI_
+, public qmdiClient
+#endif
+{
+	friend class QEditConfig;
+	friend class QEditorFactory;
+	
+	Q_OBJECT
+	
+	public:
+		enum CodecUpdatePolicy
+		{
+			NoUpdate		= 0,
+			UpdateOld		= 1,
+			UpdateDefault	= 2,
+			UpdateCustom	= 4,
+			
+			UpdateAll		= 7
+		};
+		
+		enum EditFlag
+		{
+			None			= 0,
+			
+			Overwrite		= 0x001,
+			CursorOn		= 0x002,
+			ReadOnly		= 0x004,
+			MousePressed	= 0x008,
+			MaybeDrag		= 0x010,
+			Selection		= 0x020,
+			EnsureVisible	= 0x040,
+			
+			FoldedCursor	= 0x100,
+			
+			Internal				= 0x00000fff,
+			
+			LineWrap				= 0x00001000,
+			
+			CtrlNavigation			= 0x00010000,
+			CursorJumpPastWrap		= 0x00020000,
+			
+			ReplaceTabs				= 0x00100000,
+			RemoveTrailing			= 0x00200000,
+			PreserveTrailingIndent	= 0x00400000,
+			AdjustIndent			= 0x00800000,
+			
+			AutoCloseChars			= 0x01000000,
+			AutoIndent				= 0x02000000,
+			
+			Accessible				= 0xfffff000
+		};
+		
+		Q_DECLARE_FLAGS(State, EditFlag)
+		
+		struct PlaceHolder
+		{
+			class Affector
+			{
+				public:
+					virtual ~Affector() {}
+					virtual void affect(const QStringList& base, int ph, const QKeyEvent *e, int mirror, QString& after) const = 0;
+			};
+			
+			PlaceHolder() : length(0), autoRemove(false), affector(0) {}
+			PlaceHolder(const PlaceHolder& ph) : length(ph.length), autoRemove(ph.autoRemove), affector(ph.affector)
+			{
+				cursor = ph.cursor;
+				mirrors << ph.mirrors;
+			}
+			
+			int length;
+			bool autoRemove;
+			Affector *affector;
+			QDocumentCursor cursor;
+			QList<QDocumentCursor> mirrors;
+		};
+		
+		QEditor(QWidget *p = 0);
+		QEditor(bool actions, QWidget *p = 0);
+		QEditor(const QString& s, QWidget *p = 0);
+		QEditor(const QString& s, bool actions, QWidget *p = 0);
+		virtual ~QEditor();
+		
+		bool flag(EditFlag) const;
+		
+		bool canUndo() const;
+		bool canRedo() const;
+		
+		QString text() const;
+		QString text(int line) const;
+		
+		QTextCodec* codec() const;
+		QDocument* document() const;
+		
+		QList<QEditorInputBindingInterface*> inputBindings() const;
+		
+		bool isCursorVisible() const;
+		QDocumentCursor cursor() const;
+		
+		int cursorMirrorCount() const;
+		QDocumentCursor cursorMirror(int i) const;
+		
+		QLanguageDefinition* languageDefinition() const;
+		QCodeCompletionEngine* completionEngine() const;
+		
+		QAction* action(const QString& s);
+		
+		virtual QRect cursorRect() const;
+		virtual QRect selectionRect() const;
+		virtual QRect lineRect(int line) const;
+		virtual QRect lineRect(const QDocumentLine& l) const;
+		virtual QRect cursorRect(const QDocumentCursor& c) const;
+		
+		#ifndef _QMDI_
+		QString name() const;
+		QString fileName() const;
+		
+		bool isContentModified() const;
+		#endif
+		
+		bool isInConflict() const;
+		
+		int wrapWidth() const;
+		
+		inline int horizontalOffset() const
+		{ return horizontalScrollBar()->isVisible() ? horizontalScrollBar()->value() : 0; }
+		inline int verticalOffset() const
+		{ return verticalScrollBar()->isVisible() ? verticalScrollBar()->value() * m_doc->fontMetrics().lineSpacing() : 0; }
+		
+		inline QPoint mapToContents(const QPoint &point) const
+		{
+			return QPoint(	point.x() + horizontalOffset(),
+							point.y() + verticalOffset() );
+		}
+		
+		inline QPoint mapFromContents(const QPoint &point) const
+		{
+			return QPoint(	point.x() - horizontalOffset(),
+							point.y() - verticalOffset() );
+		}
+		
+		virtual bool protectedCursor(const QDocumentCursor& c) const;
+		
+		static int defaultFlags();
+		static void setDefaultFlags(int f);
+		
+		static QTextCodec* defaultCodec();
+		static void setDefaultCodec(int mib, int update);
+		static void setDefaultCodec(QTextCodec *c, int update);
+		static void setDefaultCodec(const char *name, int update);
+		static void setDefaultCodec(const QByteArray& name, int update);
+		
+		static QEditorInputBindingInterface* registeredInputBinding(const QString& n);
+		static QString defaultInputBindingId();
+		static QStringList registeredInputBindingIds();
+		static void registerInputBinding(QEditorInputBindingInterface *b);
+		static void unregisterInputBinding(QEditorInputBindingInterface *b);
+		static void setDefaultInputBinding(QEditorInputBindingInterface *b);
+		static void setDefaultInputBinding(const QString& b);
+		
+		static inline const QList<QEditor*>& editors() { return m_editors; }
+		
+	public slots:
+		void undo();
+		void redo();
+		
+		void cut();
+		void copy();
+		void paste();
+		
+		void selectAll();
+		
+		void find();
+		void findNext();
+		void replace();
+		
+		void gotoLine();
+		
+		void indentSelection();
+		void unindentSelection();
+		
+		void commentSelection();
+		void uncommentSelection();
+		
+		void setLineWrapping(bool on);
+		
+		virtual void save();
+		void save(const QString& filename);
+		
+		virtual void print();
+		
+		virtual void retranslate();
+		
+		virtual void write(const QString& s);
+		
+		void addAction(QAction *a, const QString& menu, const QString& toolbar = QString());
+		void removeAction(QAction *a, const QString& menu, const QString& toolbar = QString());
+		
+		void load(const QString& file);
+		void setText(const QString& s);
+		
+		void setCodec(int mib);
+		void setCodec(QTextCodec *c);
+		void setCodec(const char *name);
+		void setCodec(const QByteArray& name);
+		
+		void setDocument(QDocument *d);
+		
+		void addInputBinding(QEditorInputBindingInterface *b);
+		void removeInputBinding(QEditorInputBindingInterface *b);
+		void setInputBinding(QEditorInputBindingInterface *b);
+		
+		void setCursor(const QDocumentCursor& c);
+		
+		void setLanguageDefinition(QLanguageDefinition *d);
+		
+		void setCompletionEngine(QCodeCompletionEngine *e);
+		
+		void zoom(int n);
+		
+		void setPanelMargins(int l, int t, int r, int b);
+		void getPanelMargins(int *l, int *t, int *r, int *b) const;
+		
+		void setTitle(const QString& title);
+		
+		void highlight();
+		
+		void clearPlaceHolders();
+		void removePlaceHolder(int i);
+		void addPlaceHolder(const PlaceHolder& p, bool autoUpdate = true);
+		
+		int placeHolderCount() const;
+		int currentPlaceHolder() const;
+		
+		void nextPlaceHolder();
+		void previousPlaceHolder();
+		void setPlaceHolder(int i);
+		
+		virtual void setFileName(const QString& f);
+		
+	signals:
+		void loaded(QEditor *e, const QString& s);
+		void saved(QEditor *e, const QString& s);
+		
+		void contentModified(bool y);
+		void titleChanged(const QString& title);
+		
+		void textEdited(QKeyEvent *e);
+		void cursorPositionChanged();
+		
+		void copyAvailable(bool y);
+		
+		void undoAvailable(bool y);
+		void redoAvailable(bool y);
+		
+		void markChanged(const QString& f, QDocumentLineHandle *l, int mark, bool on);
+		
+	public slots:
+		void checkClipboard();
+		void reconnectWatcher();
+		void fileChanged(const QString& f);
+		
+		void setContentClean(bool y);
+		
+		void emitCursorPositionChanged();
+		
+		virtual void setContentModified(bool y);
+		
+	protected:
+		virtual bool event(QEvent *e);
+		
+		virtual void paintEvent(QPaintEvent *e);
+		virtual void timerEvent(QTimerEvent *e);
+		
+		virtual void keyPressEvent(QKeyEvent *e);
+		
+		virtual void inputMethodEvent(QInputMethodEvent* e);
+		
+		virtual void mouseMoveEvent(QMouseEvent *e);
+		virtual void mousePressEvent(QMouseEvent *e);
+		virtual void mouseReleaseEvent(QMouseEvent *e);
+		virtual void mouseDoubleClickEvent(QMouseEvent *e);
+		
+		virtual void dragEnterEvent(QDragEnterEvent *e);
+		virtual void dragLeaveEvent(QDragLeaveEvent *e);
+		virtual void dragMoveEvent(QDragMoveEvent *e);
+		virtual void dropEvent(QDropEvent *e);
+		
+		virtual void changeEvent(QEvent *e);
+		virtual void showEvent(QShowEvent *);
+		virtual void wheelEvent(QWheelEvent *e);
+		virtual void resizeEvent(QResizeEvent *e);
+		virtual void focusInEvent(QFocusEvent *e);
+		virtual void focusOutEvent(QFocusEvent *e);
+		
+		virtual void contextMenuEvent(QContextMenuEvent *e);
+		
+		virtual void closeEvent(QCloseEvent *e);
+		
+		virtual bool focusNextPrevChild(bool next);
+		
+		virtual bool moveKeyEvent(QDocumentCursor& c, QKeyEvent *e, bool *leave);
+		virtual bool isProcessingKeyEvent(QKeyEvent *e, int *offset = 0);
+		virtual bool processCursor(QDocumentCursor& c, QKeyEvent *e, bool& b);
+		
+		virtual void startDrag();
+		virtual QMimeData* createMimeDataFromSelection() const;
+		virtual void insertFromMimeData(const QMimeData *d);
+		
+		virtual void scrollContentsBy(int dx, int dy);
+		
+		// got to make it public for bindings
+	public:
+		void setFlag(EditFlag f, bool b);
+		
+		void pageUp(QDocumentCursor::MoveMode moveMode);
+		void pageDown(QDocumentCursor::MoveMode moveMode);
+		
+		void selectionChange(bool force = false);
+		
+		void repaintCursor();
+		void ensureCursorVisible();
+		void ensureVisible(int line);
+		void ensureVisible(const QRect &rect);
+		
+		void preInsert(QDocumentCursor& c, const QString& text);
+		void insertText(QDocumentCursor& c, const QString& text);
+		
+		QDocumentLine lineAtPosition(const QPoint& p) const;
+		QDocumentCursor cursorForPosition(const QPoint& p) const;
+		
+		void setClipboardSelection();
+		void setCursorPosition(const QPoint& p);
+		
+		void setCursorPosition(int line, int index);
+		void getCursorPosition(int &line, int &index);
+		
+		void clearCursorMirrors();
+		void addCursorMirror(const QDocumentCursor& c);
+		
+	protected slots:
+		void documentWidthChanged(int newWidth);
+		void documentHeightChanged(int newWidth);
+		
+		void repaintContent(int i, int n);
+		void updateContent (int i, int n);
+		
+		void markChanged(QDocumentLineHandle *l, int mark, bool on);
+		
+		void bindingSelected(QAction *a);
+		
+		void lineEndingSelected(QAction *a);
+		void lineEndingChanged(int lineEnding);
+		
+	protected:
+		enum SaveState
+		{
+			Undefined,
+			Saving,
+			Saved,
+			Conflict
+		};
+		
+		void init(bool actions = true);
+		void updateBindingsMenu();
+		
+		#ifndef _QMDI_
+		QString m_name, m_fileName;
+		#endif
+		
+		QMenu *pMenu;
+		QHash<QString, QAction*> m_actions;
+		
+		QMenu *m_lineEndingsMenu;
+		QActionGroup *m_lineEndingsActions;
+		
+		QMenu *m_bindingsMenu;
+		QAction *aDefaultBinding;
+		QActionGroup *m_bindingsActions;
+		
+		char m_saveState;
+		quint16 m_checksum;
+		
+		QDocument *m_doc;
+		QTextCodec *m_codec;
+		QList<QEditorInputBindingInterface*> m_bindings;
+		
+		QLanguageDefinition *m_definition;
+		QPointer<QCodeCompletionEngine> m_completionEngine;
+		
+		QDocumentCursor m_cursor, m_doubleClick, m_dragAndDrop;
+		
+		QList<QDocumentCursor> m_mirrors;
+		
+		int m_curPlaceHolder, m_cphOffset;
+		QList<PlaceHolder> m_placeHolders;
+		
+		int m_state;
+		bool m_selection;
+		QRect m_crect, m_margins;
+		QPoint m_clickPoint, m_dragPoint;
+		QBasicTimer m_blink, m_scroll, m_click, m_drag;
+		
+		static QReliableFileWatch* watcher();
+		
+		static int m_defaultFlags;
+		static QTextCodec *m_defaultCodec;
+		
+		static QList<QEditor*> m_editors;
+		static QEditorInputBindingInterface *m_defaultBinding;
+		static QHash<QString, QEditorInputBindingInterface*> m_registeredBindings;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QEditor::State);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qeditorfactory.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,341 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qeditorfactory.h"
+
+#ifdef _QSAFE_SHARED_SETTINGS_
+
+/*!
+	\file qeditorfactory.cpp
+	\brief Implementation of the QEditorFactory class.
+*/
+
+#include "qcodeedit.h"
+
+#include "qformatscheme.h"
+#include "qlanguagefactory.h"
+#include "qcodecompletionengine.h"
+
+#include "qfoldpanel.h"
+#include "qlinemarkpanel.h"
+#include "qlinenumberpanel.h"
+#include "qlinechangepanel.h"
+#include "qgotolinepanel.h"
+#include "qstatuspanel.h"
+#include "qsearchreplacepanel.h"
+
+#include "qeditor.h"
+#include "qlinemarksinfocenter.h"
+
+#include "qsettingsserver.h"
+
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QTextStream>
+#include <QApplication>
+
+/*!
+	\ingroup editor
+	@{
+	
+	\class QEditorFactory
+	\brief Convenience class that manages editors.
+	
+	QCodeEdit widgets are created through QEditorFactory using a simple
+	QString representing a panel id. Each panel id is associated to a
+	serialized panel layout (\see QPanelLayout::serialized() ).
+	
+	\see QCodeEdit
+	\see QLanguageFactory
+	\see QFormatScheme
+*/
+
+/*!
+	\brief Construct a working editor factory
+*/
+QEditorFactory::QEditorFactory(QSettingsServer *s)
+ :
+#ifdef _QMDI_
+	qmdiClientFactory(s),
+#else
+	QObject(s),
+#endif
+	QSettingsClient(s, "editor")
+{
+	m_defaultScheme = new QFormatScheme(QCE::fetchDataFile("formats.qxf"), this);
+	
+	QDocument::setFormatFactory(m_defaultScheme);
+	
+	m_languageFactory = new QLanguageFactory(m_defaultScheme, this);
+	
+	foreach ( QString dp, QCE::dataPathes() )
+	{
+		m_languageFactory->addDefinitionPath(dp);
+	}
+	
+	if ( value("version").toInt() != 3 )
+	{
+		setValue("version", 3);
+		
+		// setup default layouts...
+		beginGroup("layouts");
+		
+		setValue("default", "default");
+		
+		beginGroup("availables");
+		
+		beginGroup("empty");
+		setValue("struct", QString());
+		setValue("name", "No panels");
+		endGroup();
+		
+		beginGroup("default");
+		setValue("struct",
+				QString::number(QCodeEdit::West)
+				+ "{"
+				+ Q_PANEL_ID(QLineMarkPanel)
+				+ ","
+				+ Q_PANEL_ID(QLineNumberPanel)
+				+ ","
+				+ Q_PANEL_ID(QFoldPanel)
+				+ ","
+				+ Q_PANEL_ID(QLineChangePanel)
+				+ "}"
+				
+				+ QString::number(QCodeEdit::South)
+				+ "{"
+				+ Q_PANEL_ID(QStatusPanel)
+				+ ","
+				+ Q_PANEL_ID(QGotoLinePanel)
+				+ ","
+				+ Q_PANEL_ID(QSearchReplacePanel)
+				+ "}"
+				);
+		
+		setValue("name", "Default panel layout");
+		endGroup();
+		
+		beginGroup("simple");
+		setValue("struct",
+				QString::number(QCodeEdit::West)
+				+ "{"
+				+ Q_PANEL_ID(QLineNumberPanel)
+				+ ","
+				+ Q_PANEL_ID(QFoldPanel)
+				+ "}"
+				
+				+ QString::number(QCodeEdit::South)
+				+ "{"
+				+ Q_PANEL_ID(QStatusPanel)
+				+ "}"
+				);
+		
+		setValue("name", "Trimmed-down panel layout");
+		endGroup();
+		
+		endGroup();
+		
+		endGroup();
+	}
+	
+}
+
+/*!
+	\brief dtor
+*/
+QEditorFactory::~QEditorFactory()
+{
+	
+}
+
+/*!
+	\reimp
+	\brief Creates an editor with default layout for the given file
+	\param filename file to load in the editor
+	\return a managed QEditor object
+*/
+qmdiClient* QEditorFactory::createClient(const QString& filename) const
+{
+	return editor(filename, defaultLayout())->editor();
+}
+
+/*!
+	\brief Create a managed editor
+	\param f file to load
+	\param layout panel layout to use
+*/
+QCodeEdit* QEditorFactory::editor(const QString& f, const QString& layout) const
+{
+	QCodeEdit *e = new QCodeEdit(layout.isEmpty() ? defaultLayout() : layout);
+	
+	//m_config->hookEditor(def, e);
+	
+	connect(e->editor()	, SIGNAL( loaded(QEditor*, QString) ),
+			this		, SLOT  ( loaded(QEditor*, QString) ) );
+	
+	connect(e->editor()	, SIGNAL( saved(QEditor*, QString) ),
+			this		, SLOT  ( saved(QEditor*, QString) ) );
+	
+	// set syntax handlers
+	m_languageFactory->setLanguage(e->editor(), f);
+	
+	if ( f.count() && QFile::exists(f) )
+	{
+		// load contents
+		e->editor()->load(f);
+		
+		// set line marks back...
+		QLineMarksInfoCenter::instance()->flush(f);
+	} else {
+		e->editor()->setTitle(tr("untitled"));
+		e->editor()->setContentModified(true);
+	}
+	
+	return e;
+}
+
+/*!
+	\overload
+	\param f file to load
+	\param l language definition to use
+	\param s format scheme to use
+	\param en code completion engine to use
+	\param layout panel layout to use
+*/
+QCodeEdit* QEditorFactory::editor(	const QString& f,
+									QLanguageDefinition *l,
+									QFormatScheme *s,
+									QCodeCompletionEngine *en,
+									const QString& layout) const
+{
+	QCodeEdit *e = new QCodeEdit(layout.isEmpty() ? defaultLayout() : layout);
+	
+	//m_config->hookEditor(def, e);
+	
+	connect(e->editor()	, SIGNAL( loaded(QEditor*, QString) ),
+			this		, SLOT  ( loaded(QEditor*, QString) ) );
+	
+	connect(e->editor()	, SIGNAL( saved(QEditor*, QString) ),
+			this		, SLOT  ( saved(QEditor*, QString) ) );
+	
+	// set syntax handlers
+	//m_languageFactory->setLanguage(e->editor(), l, en);
+	e->editor()->setLanguageDefinition(l);
+	e->editor()->document()->setFormatScheme(s ? s : m_defaultScheme);
+	e->editor()->setCompletionEngine(en ? en->clone() : 0);
+	
+	if ( f.count() && QFile::exists(f) )
+	{
+		// load contents
+		e->editor()->load(f);
+		
+		// set line marks back...
+		QLineMarksInfoCenter::instance()->flush(f);
+	} else {
+		e->editor()->setTitle(tr("untitled"));
+		e->editor()->setContentModified(true);
+	}
+	
+	return e;
+}
+
+/*!
+	\brief Called whenever a managed editor save its content
+	
+	Update the language definition/code completion engine if needed
+	and emits the fileSaved signal
+*/
+void QEditorFactory::saved(QEditor *e, const QString& f)
+{
+	if ( !e || !e->document() )
+		return;
+	
+	m_languageFactory->setLanguage(e, f);
+	emit fileSaved(f);
+}
+
+/*!
+	\brief Placeholder
+*/
+void QEditorFactory::loaded(QEditor *e, const QString& f)
+{
+	Q_UNUSED(f)
+	
+	if ( !e || !e->document() )
+		return;
+	
+}
+
+/*!
+	\return The default panel layout
+*/
+QString QEditorFactory::defaultLayout() const
+{
+	QSettingsClient c(*this);
+	
+	c.beginGroup("layouts");
+	QString a = c.value("default").toString();
+	
+	if ( a.isEmpty() )
+	{
+		c.beginGroup("availables");
+		
+		a = childGroups().at(0);
+		
+		c.endGroup();
+	}
+	
+	c.endGroup();
+	
+	return layout(a);
+}
+
+/*!
+	\return The layout structure associated with a given layout alias
+*/
+QString QEditorFactory::layout(const QString& alias) const
+{
+	return value("layouts/availables/" + alias + "/struct").toString();
+}
+
+/*!
+	\brief Register a layout
+	\param a layout alias
+	\param layout layout structure
+*/
+void QEditorFactory::registerLayout(const QString& a, const QString& layout)
+{
+	beginGroup("layouts");
+	beginGroup("availables");
+	beginGroup(a);
+	setValue("struct", layout);
+	setValue("name", a);
+	endGroup();
+	endGroup();
+	endGroup();
+}
+
+/*!
+	\return an accessor to the settings associated with a given layout alias
+*/
+QSettingsClient QEditorFactory::settings(const QString& alias)
+{
+	return QSettingsClient(*this, "layouts/availables/" + alias);
+}
+
+/*! @} */
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qeditorfactory.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QEDITOR_FACTORY_H_
+#define _QEDITOR_FACTORY_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qeditorfactory.h
+	\brief Definition of the QEditorFactory class
+*/
+
+#ifdef _QSAFE_SHARED_SETTINGS_
+
+#ifndef _QMDI_
+	#define Q_EDITOR_FACTORY_BASE QObject
+	#define Q_EDITOR_FACTORY_EMIT(client)
+#else
+	#include "qmdiclientfactory.h"
+	
+	#define Q_EDITOR_FACTORY_BASE qmdiClientFactory
+	#define Q_EDITOR_FACTORY_EMIT(client) emit clientCreated(client);
+#endif
+
+#include "qsettingsclient.h"
+
+#include <QStringList>
+
+class QEditor;
+class QCodeEdit;
+class QFormatScheme;
+class QLanguageFactory;
+class QCodeCompletionEngine;
+class QLanguageDefinition;
+class QEditorConfiguration;
+
+class QCE_EXPORT QEditorFactory : public Q_EDITOR_FACTORY_BASE, public QSettingsClient
+{
+	Q_OBJECT
+	
+	public:
+		QEditorFactory(QSettingsServer *s);
+		virtual ~QEditorFactory();
+		
+		inline QFormatScheme* defaultFormatScheme() const
+		{ return m_defaultScheme; }
+		
+		inline QLanguageFactory* languageFactory() const
+		{ return m_languageFactory; }
+		
+		virtual qmdiClient* createClient(const QString& filename) const;
+		
+		QCodeEdit* editor(	const QString& file,
+							const QString& layout = QString()) const;
+		
+		QCodeEdit* editor(	const QString& file,
+							QLanguageDefinition *l,
+							QFormatScheme *s = 0,
+							QCodeCompletionEngine *e = 0,
+							const QString& layout = QString()) const;
+		
+		QString defaultLayout() const;
+		QString layout(const QString& alias) const;
+		void registerLayout(const QString& alias, const QString& layout);
+		
+		QSettingsClient settings(const QString& alias);
+		
+	signals:
+		void fileSaved(const QString& f);
+		
+	private slots:
+		void saved(QEditor *e, const QString& f);
+		void loaded(QEditor *e, const QString& f);
+		
+	private:
+		QEditorConfiguration *m_config;
+		
+		QFormatScheme *m_defaultScheme;
+		QLanguageFactory *m_languageFactory;
+};
+
+#endif // _QSAFE_SHARED_SETTINGS_
+
+#endif // ! _QEDITOR_FACTORY_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qeditorinputbinding.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,306 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qeditorinputbinding.h"
+
+#include "qeditor.h"
+#include "qdocument.h"
+#include "qdocumentcursor.h"
+
+#include <QKeyEvent>
+
+/*!
+	\class QEditorInputBindingInterface
+	\brief A class designed to allow extending user input in a transparent way
+	
+	An input binding interface, when set to an editor, can intercept all the events the
+	editor receive and radically change the behavior.
+	
+	The main purpose of this class is twofold :
+	<ul>
+	<li>Allow vi-like (or emacs-like, ...) editing to be implemented with little extra work.
+	And allow the user to easily switch between input modes</li>
+	<li>Allow applications using QCE to easily add extra features (e.g extended code
+	navigation within projects, jump to documentation, ...) with little extra work</li>
+	</ul>
+*/
+
+/*!
+	\class QEditorInputBinding
+	\brief A "managed" input binding interface
+	
+	This subclass of QEditorInputBindingInterface is meant to make the creatio of input
+	bindings easier and more intuitive by abstracting away most of the low-level event
+	handling logic.
+*/
+
+/////////////////////////////////////////////////////////////////////////////
+
+QEditorInputBinding::MotionCommand::MotionCommand(QDocumentCursor::MoveOperation op, QDocumentCursor::MoveMode m, int n)
+ : count(n), mode(m), operation(op)
+{
+	
+}
+
+void QEditorInputBinding::MotionCommand::exec(QEditor *e)
+{
+	QDocumentCursor c = e->cursor();
+	c.movePosition(count, operation, mode);
+	e->setCursor(c);
+}
+
+QEditorInputBinding::EditCommand::EditCommand(Operation op)
+ : operation(op)
+{
+	
+}
+
+void QEditorInputBinding::EditCommand::exec(QEditor *e)
+{
+	QDocumentCursor c = e->cursor();
+	
+	switch ( operation )
+	{
+		case ClearSelection :
+			c.clearSelection();
+			break;
+			
+		case SelectWord :
+			c.select(QDocumentCursor::WordUnderCursor);
+			break;
+			
+		case SelectLine :
+			c.select(QDocumentCursor::LineUnderCursor);
+			break;
+			
+		case SelectDocument :
+			c.movePosition(1, QDocumentCursor::Start, QDocumentCursor::MoveAnchor);
+			c.movePosition(1, QDocumentCursor::End, QDocumentCursor::KeepAnchor);
+			break;
+			
+		case DeleteChar :
+			c.deleteChar();
+			break;
+			
+		case DeletePreviousChar :
+			c.deletePreviousChar();
+			break;
+			
+		case DeleteLine :
+			c.eraseLine();
+			break;
+			
+		case DeleteSelection :
+			c.removeSelectedText();
+			break;
+			
+		case InsertLine :
+			c.insertLine();
+			break;
+			
+		case InsertClipBoard :
+			e->paste();
+			return;
+			
+		default:
+			
+			break;
+	}
+	
+	e->setCursor(c);
+}
+
+QEditorInputBinding::WriteCommand::WriteCommand(const QString& t)
+ : text(t)
+{
+	
+}
+
+void QEditorInputBinding::WriteCommand::exec(QEditor *e)
+{
+	e->write(text);
+}
+
+void QEditorInputBinding::GroupCommand::addCommand(Command *c)
+{
+	commands << c;
+}
+
+void QEditorInputBinding::GroupCommand::exec(QEditor *e)
+{
+	foreach ( Command *c, commands )
+		c->exec(e);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+QEditorInputBinding::QEditorInputBinding()
+{
+}
+
+QEditorInputBinding::~QEditorInputBinding()
+{
+	qDeleteAll(m_actions);
+}
+
+void QEditorInputBinding::setMapping(const QKeySequence& ks, Command *cmd)
+{
+	for ( int i = 0; i < m_keys.count(); ++i )
+	{
+		if ( m_keys.at(i) == ks )
+		{
+			delete m_actions[i];
+			m_actions[i] = cmd;
+			return;
+		}
+	}
+	
+	m_index << 0;
+	m_keys << ks;
+	m_actions << cmd;
+}
+
+bool QEditorInputBinding::isExclusive() const
+{
+	return false;
+}
+
+bool QEditorInputBinding::keyPressEvent(QKeyEvent *event, QEditor *editor)
+{
+	bool filter = false;
+	
+	for ( int i = 0; i < m_keys.count(); ++i )
+	{
+		int idx = m_index.at(i);
+		const QKeySequence& ks = m_keys.at(i);
+		
+		if ( idx < (int)ks.count() )
+		{
+			if ( ks[idx] == event->key() )
+			{
+				++idx;
+				
+				if ( idx == (int)ks.count() )
+				{
+					//qDebug("match");
+					
+					// key sequence matched
+					m_actions.at(i)->exec(editor);
+					
+					// cancel other in progress matches ?
+					m_index.fill(0);
+					
+					//return true;
+				} else {
+					//qDebug("step");
+					m_index[i] = idx;
+				}
+				
+				// filter out the event
+				filter = true;
+			} else {
+				m_index[i] = 0;
+			}
+		} else {
+			m_index[i] = 0;
+		}
+	}
+	
+	return filter;
+}
+
+void QEditorInputBinding::postKeyPressEvent(QKeyEvent *event, QEditor *editor)
+{
+	Q_UNUSED(event)
+	Q_UNUSED(editor)
+}
+
+bool QEditorInputBinding::inputMethodEvent(QInputMethodEvent* event, QEditor *editor)
+{
+	Q_UNUSED(event)
+	Q_UNUSED(editor)
+	
+	return false;
+}
+
+void QEditorInputBinding::postInputMethodEvent(QInputMethodEvent *event, QEditor *editor)
+{
+	Q_UNUSED(event)
+	Q_UNUSED(editor)
+}
+
+bool QEditorInputBinding::mouseMoveEvent(QMouseEvent *event, QEditor *editor)
+{
+	Q_UNUSED(event)
+	Q_UNUSED(editor)
+	
+	return false;
+}
+
+void QEditorInputBinding::postMouseMoveEvent(QMouseEvent *event, QEditor *editor)
+{
+	Q_UNUSED(event)
+	Q_UNUSED(editor)
+}
+
+bool QEditorInputBinding::mousePressEvent(QMouseEvent *event, QEditor *editor)
+{
+	Q_UNUSED(event)
+	Q_UNUSED(editor)
+	
+	return false;
+}
+
+void QEditorInputBinding::postMousePressEvent(QMouseEvent *event, QEditor *editor)
+{
+	Q_UNUSED(event)
+	Q_UNUSED(editor)
+}
+
+bool QEditorInputBinding::mouseReleaseEvent(QMouseEvent *event, QEditor *editor)
+{
+	Q_UNUSED(event)
+	Q_UNUSED(editor)
+	
+	return false;
+}
+
+void QEditorInputBinding::postMouseReleaseEvent(QMouseEvent *event, QEditor *editor)
+{
+	Q_UNUSED(event)
+	Q_UNUSED(editor)
+}
+
+bool QEditorInputBinding::mouseDoubleClickEvent(QMouseEvent *event, QEditor *editor)
+{
+	Q_UNUSED(event)
+	Q_UNUSED(editor)
+	
+	return false;
+}
+
+void QEditorInputBinding::postMouseDoubleClickEvent(QMouseEvent *event, QEditor *editor)
+{
+	Q_UNUSED(event)
+	Q_UNUSED(editor)
+}
+
+bool QEditorInputBinding::contextMenuEvent(QContextMenuEvent *event, QEditor *editor)
+{
+	Q_UNUSED(event)
+	Q_UNUSED(editor)
+	
+	return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qeditorinputbinding.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QEDITOR_INPUT_BINDING_H_
+#define _QEDITOR_INPUT_BINDING_H_
+
+#include "qeditorinputbindinginterface.h"
+
+#include "qdocumentcursor.h"
+
+#include <QList>
+#include <QVector>
+#include <QString>
+#include <QKeySequence>
+
+class QCE_EXPORT QEditorInputBinding : public QEditorInputBindingInterface
+{
+	public:
+		class Command
+		{
+			public:
+				virtual ~Command() {}
+				
+				virtual void exec(QEditor *e) = 0;
+		};
+		
+		class MotionCommand : public Command
+		{
+			public:
+				MotionCommand(QDocumentCursor::MoveOperation op, QDocumentCursor::MoveMode m, int n = 1);
+				
+				virtual void exec(QEditor *e);
+				
+			private:
+				int count;
+				QDocumentCursor::MoveMode mode;
+				QDocumentCursor::MoveOperation operation;
+		};
+		
+		class EditCommand : public Command
+		{
+			public:
+				enum Operation
+				{
+					ClearSelection,
+					SelectWord,
+					SelectLine,
+					SelectDocument,
+					
+					DeleteChar,
+					DeletePreviousChar,
+					DeleteSelection,
+					DeleteLine,
+					
+					InsertLine,
+					InsertClipBoard,
+				};
+				
+				EditCommand(Operation op);
+				
+				virtual void exec(QEditor *e);
+				
+			private:
+				Operation operation;
+		};
+		
+		class WriteCommand : public Command
+		{
+			public:
+				WriteCommand(const QString& t);
+				
+				virtual void exec(QEditor *e);
+				
+			private:
+				QString text;
+		};
+		
+		class GroupCommand : public Command
+		{
+			public:
+				void addCommand(Command *c);
+				
+				virtual void exec(QEditor *e);
+				
+			private:
+				QList<Command*> commands;
+		};
+		
+		QEditorInputBinding();
+		~QEditorInputBinding();
+		
+		void setMapping(const QKeySequence& ks, Command *cmd);
+		
+		virtual bool isExclusive() const;
+		
+		virtual bool keyPressEvent(QKeyEvent *event, QEditor *editor);
+		virtual void postKeyPressEvent(QKeyEvent *event, QEditor *editor);
+		
+		virtual bool inputMethodEvent(QInputMethodEvent* event, QEditor *editor);
+		virtual void postInputMethodEvent(QInputMethodEvent *event, QEditor *editor);
+		
+		virtual bool mouseMoveEvent(QMouseEvent *event, QEditor *editor);
+		virtual void postMouseMoveEvent(QMouseEvent *event, QEditor *editor);
+		
+		virtual bool mousePressEvent(QMouseEvent *event, QEditor *editor);
+		virtual void postMousePressEvent(QMouseEvent *event, QEditor *editor);
+		
+		virtual bool mouseReleaseEvent(QMouseEvent *event, QEditor *editor);
+		virtual void postMouseReleaseEvent(QMouseEvent *event, QEditor *editor);
+		
+		virtual bool mouseDoubleClickEvent(QMouseEvent *event, QEditor *editor);
+		virtual void postMouseDoubleClickEvent(QMouseEvent *event, QEditor *editor);
+		
+		virtual bool contextMenuEvent(QContextMenuEvent *event, QEditor *editor);
+		
+	private:
+		QVector<int> m_index;
+		QVector<Command*> m_actions;
+		QVector<QKeySequence> m_keys;
+};
+
+#endif // _QEDITOR_INPUT_BINDING_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qeditorinputbindinginterface.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QEDITOR_INPUT_BINDING_INTERFACE_H_
+#define _QEDITOR_INPUT_BINDING_INTERFACE_H_
+
+#include "qce-config.h"
+
+class QEditor;
+
+class QString;
+class QKeyEvent;
+class QMouseEvent;
+class QInputMethodEvent;
+class QContextMenuEvent;
+
+class QEditorInputBindingInterface
+{
+	public:
+		virtual ~QEditorInputBindingInterface() {}
+		
+		virtual QString id() const = 0;
+		virtual QString name() const = 0;
+		
+		virtual bool isExclusive() const = 0;
+		
+		virtual bool keyPressEvent(QKeyEvent *event, QEditor *editor) = 0;
+		virtual void postKeyPressEvent(QKeyEvent *event, QEditor *editor) = 0;
+		
+		virtual bool inputMethodEvent(QInputMethodEvent* event, QEditor *editor) = 0;
+		virtual void postInputMethodEvent(QInputMethodEvent *event, QEditor *editor) = 0;
+		
+		virtual bool mouseMoveEvent(QMouseEvent *event, QEditor *editor) = 0;
+		virtual void postMouseMoveEvent(QMouseEvent *event, QEditor *editor) = 0;
+		
+		virtual bool mousePressEvent(QMouseEvent *event, QEditor *editor) = 0;
+		virtual void postMousePressEvent(QMouseEvent *event, QEditor *editor) = 0;
+		
+		virtual bool mouseReleaseEvent(QMouseEvent *event, QEditor *editor) = 0;
+		virtual void postMouseReleaseEvent(QMouseEvent *event, QEditor *editor) = 0;
+		
+		virtual bool mouseDoubleClickEvent(QMouseEvent *event, QEditor *editor) = 0;
+		virtual void postMouseDoubleClickEvent(QMouseEvent *event, QEditor *editor) = 0;
+		
+		virtual bool contextMenuEvent(QContextMenuEvent *event, QEditor *editor) = 0;
+};
+
+#endif // _QEDITOR_INPUT_BINDING_INTERFACE_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qeditsession.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,534 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qeditsession.h"
+
+/*!
+	\file qeditsession.cpp
+	\brief Implementation of the QEditSession class.
+*/
+
+#include "qeditor.h"
+#include "qdocument.h"
+#include "qdocument_p.h"
+#include "qdocumentline.h"
+#include "qdocumentcursor.h"
+
+#include "qlinemarksinfocenter.h"
+
+#include <QFile>
+#include <QFileInfo>
+#include <QDataStream>
+#include <QScrollBar>
+
+/*!
+	\class QEditSession
+	
+	\brief A session recording class
+	
+	The purpose of this class is to collect session data from several QEditor object,
+	to serialize it and to re-create the same session by deserializing the stored data.
+*/
+
+/*!
+	\brief ctor
+*/
+QEditSession::QEditSession(QObject *p)
+ : QObject(p), m_id(-1), m_delay(0)
+{
+	
+}
+
+/*!
+	\brief ctor
+*/
+QEditSession::QEditSession(const QString& f, QObject *p)
+ : QObject(p), m_id(-1), m_delay(0)
+{
+	setFileName(f);
+}
+
+/*!
+	\brief dtor
+*/
+QEditSession::~QEditSession()
+{
+	
+}
+
+/*!
+	\return The update interval, in milliseconds
+	
+	A value of zero means the data is NOT automatically updated.
+	
+	\see updateData()
+*/
+int QEditSession::autoUpdateInterval() const
+{
+	return m_delay;
+}
+
+/*!
+	\brief Set the update interval
+	
+	If \a ms is strictly positive then the data will be
+	updated every \a ms milliseconds
+	
+	If the session has been given a valid filename, the updated
+	data will automatically be saved to that file.
+*/
+void QEditSession::setAutoUpdateInterval(int ms)
+{
+	if ( m_delay )
+	{
+		killTimer(m_id);
+		m_id = -1;
+	}
+	
+	m_delay = ms;
+	
+	if ( m_delay )
+	{
+		m_id = startTimer(m_delay);
+	}
+}
+
+/*!
+	\return The file name used as storage
+	
+	If it is empty then no auto-save is performed.
+*/
+QString QEditSession::fileName() const
+{
+	return m_fileName;
+}
+
+/*!
+	\brief Set the storage destination
+	
+	Every time the data is updated, either when the autoupdate timer
+	ticks or when updateData() is called programmatically, it will be
+	written to that file, provided the filename is valid and points
+	to a writeable location.
+	
+	\see updateData()
+	\see autoUpdateInterval()
+*/
+void QEditSession::setFileName(const QString& filename, bool r)
+{
+	m_fileName = filename;
+	
+	if ( r )
+		restore();
+	
+}
+
+/*!
+	\brief Add an editor to the session
+*/
+void QEditSession::addEditor(QEditor *e)
+{
+	if ( m_editors.contains(e) )
+		return;
+	
+	//qDebug("+ 0x%x", e);
+	
+	Document *d = new Document;
+	
+	m_editors << e;
+	m_sessionData << d;
+	
+	connect(e	, SIGNAL( destroyed(QObject*) ),
+			this, SLOT  ( destroyed(QObject*) ) );
+	
+	connect(e	, SIGNAL( saved(QEditor*, QString) ),
+			this, SLOT  ( saved(QEditor*, QString) ) );
+	
+	connect(e	, SIGNAL( loaded(QEditor*, QString) ),
+			this, SLOT  ( loaded(QEditor*, QString) ) );
+	
+	update(e, d);
+}
+
+/*!
+	\brief Remove an editor from the session
+*/
+void QEditSession::removeEditor(QEditor *e)
+{
+	int idx = m_editors.indexOf(e);
+	
+	if ( idx == -1 )
+		return;
+	
+	//qDebug("- 0x%x", e);
+	
+	disconnect(	e	, SIGNAL( destroyed(QObject*) ),
+				this, SLOT  ( destroyed(QObject*) ) );
+	
+	disconnect(	e	, SIGNAL( saved(QEditor*, QString) ),
+				this, SLOT  ( saved(QEditor*, QString) ) );
+	
+	disconnect(	e	, SIGNAL( loaded(QEditor*, QString) ),
+				this, SLOT  ( loaded(QEditor*, QString) ) );
+	
+	m_editors.removeAt(idx);
+	delete m_sessionData.takeAt(idx);
+}
+
+/*!
+	
+*/
+void QEditSession::clear(bool cleanup)
+{
+	if ( cleanup )
+		qDeleteAll(m_editors);
+	
+	qDeleteAll(m_sessionData);
+	
+	m_editors.clear();
+	m_sessionData.clear();
+}
+
+/*!
+	\brief Serialize session data
+*/
+void QEditSession::save()
+{
+	QFile f(m_fileName);
+	
+	if ( f.open(QFile::WriteOnly) )
+	{
+		QDataStream s(&f);
+		
+		save(s);
+	}
+}
+
+/*!
+	\brief Serialize session data
+*/
+void QEditSession::restore()
+{
+	QFile f(m_fileName);
+	
+	if ( f.open(QFile::ReadOnly) )
+	{
+		QDataStream s(&f);
+		
+		restore(s);
+	}
+}
+
+static const char _magic[] = "QES ";
+
+/*!
+	\brief Serialize session data
+*/
+void QEditSession::save(QDataStream& s)
+{
+	//qDebug("saving");
+	
+	s << *(reinterpret_cast<const quint32*>(_magic));
+	s << m_sessionData.count();
+	
+	foreach ( Document *d, m_sessionData )
+	{
+		//qDebug("> %s", qPrintable(d->fileName));
+		
+		s << d->fileName;
+		s << d->timeStamp;
+		
+		s << d->cursors.count();
+		
+		foreach ( const Cursor& c, d->cursors )
+			s << c.beginLine << c.beginColumn << c.endLine << c.endColumn;
+		
+		s << d->marks.count();
+		
+		QHash<int, QList<int> >::const_iterator it = d->marks.constBegin();
+		const QHash<int, QList<int> >::const_iterator end = d->marks.constEnd();
+		
+		while ( it != end )
+		{
+			s << it.key() << *it;
+		}
+		
+		s << d->scrollX;
+		s << d->scrollY;
+	}
+}
+
+/*!
+	\brief Deserialize session data
+*/
+void QEditSession::restore(QDataStream& s)
+{
+	//qDebug("restoring");
+	
+	quint32 magic;
+	
+	s >> magic;
+	
+	if ( magic != *(reinterpret_cast<const quint32*>(_magic)) )
+	{
+		qDebug("header mismatch : %i, %i", magic, s.status());
+		return;
+	}
+	
+	int documentCount = 0;
+	
+	s >> documentCount;
+	
+	for ( int i = 0; i < documentCount; ++i )
+	{
+		Document *d = new Document;
+		
+		s >> d->fileName;
+		s >> d->timeStamp;
+		
+		//qDebug("> %s", qPrintable(d->fileName));
+		
+		int cursorCount = 0;
+		
+		s >> cursorCount;
+		
+		bool exist = QFile::exists(d->fileName);
+		QEditor *e = exist ? createEditor() : 0;
+		
+		if ( e )
+			e->load(d->fileName);
+		
+		for ( int j = 0; j < cursorCount; ++j )
+		{
+			Cursor c;
+			
+			s >> c.beginLine;
+			s >> c.beginColumn;
+			s >> c.endLine;
+			s >> c.endColumn;
+			
+			d->cursors << c;
+		}
+		
+		int markCount = 0;
+		s >> markCount;
+		
+		for ( int j = 0; j < markCount; ++j )
+		{
+			int line = 0;
+			QList<int> marks;
+			
+			s >> line;
+			s >> marks;
+			
+			d->marks[line] = marks;
+			
+			foreach ( int mark, marks )
+				e->document()->line(line).addMark(mark);
+		}
+		
+		s >> d->scrollX;
+		s >> d->scrollY;
+		
+		if ( e && cursorCount )
+		{
+			QDocumentCursor c = d->cursors.first().toDocumentCursor(e->document());
+			
+			e->setCursor(c);
+			
+			for ( int j = 1; j < cursorCount; ++j )
+			{
+				e->addCursorMirror(d->cursors.at(j).toDocumentCursor(e->document()));
+			}
+		}
+		
+		// TODO : defer. it does not seem to work properly that way
+		// TODO : view size independency (store the first visible line number)
+		e->verticalScrollBar()->setValue(d->scrollY);
+		e->horizontalScrollBar()->setValue(d->scrollX);
+		
+		if ( e )
+		{
+			connect(e	, SIGNAL( destroyed(QObject*) ),
+					this, SLOT  ( destroyed(QObject*) ) );
+			
+			connect(e	, SIGNAL( saved(QEditor*, QString) ),
+					this, SLOT  ( saved(QEditor*, QString) ) );
+			
+			connect(e	, SIGNAL( loaded(QEditor*, QString) ),
+					this, SLOT  ( loaded(QEditor*, QString) ) );
+			
+			m_editors << e;
+			m_sessionData << d;
+			
+			emit restored(e);
+		} else {
+			delete d;
+		}
+	}
+}
+
+/*!
+	\brief Updates the data
+	
+	Fetches up-to-date session data from the attached editors.
+	
+	If the session has been given a valid filename the data will
+	automatically be saved.
+	
+	\note This will NOT affect the automatic updates timing
+*/
+void QEditSession::updateData()
+{
+	for ( int i = 0; i < m_editors.count(); ++i )
+	{
+		QEditor *e = m_editors.at(i);
+		Document *d = m_sessionData.at(i);
+		
+		update(e, d);
+	}
+	
+	save();
+}
+
+void QEditSession::destroyed(QObject *o)
+{
+	//qDebug("~ 0x%x", o);
+	
+	for ( int i = 0; i < m_editors.count(); ++i )
+	{
+		QEditor *e = m_editors.at(i);
+		
+		if ( !e || ((QObject*)e == o) )
+		{
+			delete m_sessionData.takeAt(i);
+			m_editors.removeAt(i);
+			break;
+		}
+	}
+}
+
+/*!
+	\brief Called whenever an editor is saved
+	
+	This handler is responsible for updating file names and time stamps
+	which is needed to avoid data loss upon session restoration
+*/
+void QEditSession::saved(QEditor *e, const QString& fn)
+{
+	int idx = m_editors.indexOf(e);
+	
+	if ( idx == -1 )
+		return;
+	
+	//qDebug("saved : %s", qPrintable(fn));
+	
+	Document *d = m_sessionData.at(idx);
+	
+	//d->timeStamp = QDateTime::currentDateTime();
+	
+	update(e, d);
+}
+
+/*!
+	\brief Called whenever an editor is loaded with new content
+	
+	This handler is responsible for updating file names and time stamps
+	which is needed to avoid data loss upon session restoration
+*/
+void QEditSession::loaded(QEditor *e, const QString& fn)
+{
+	int idx = m_editors.indexOf(e);
+	
+	if ( idx == -1 )
+		return;
+	
+	//qDebug("loaded : %s", qPrintable(fn));
+	
+	Document *d = m_sessionData.at(idx);
+	
+	//d->timeStamp = QDateTime::currentDateTime();
+	
+	update(e, d);
+}
+
+void QEditSession::update(QEditor *e, Document *d)
+{
+	if ( !e || !d )
+		return;
+	
+	//qDebug(">>%s", qPrintable(e->fileName()));
+	
+	d->fileName = e->fileName();
+	d->timeStamp = QFileInfo(d->fileName).lastModified();
+	
+	d->cursors.clear();
+	d->cursors << Cursor(e->cursor());
+	
+	for ( int i = 0; i < e->cursorMirrorCount(); ++i )
+		d->cursors << Cursor(e->cursorMirror(i));
+	
+	QLineMarkList marks = QLineMarksInfoCenter::instance()->marks(d->fileName);
+	
+	foreach ( const QLineMark& mark, marks )
+	{
+		d->marks[mark.line] << mark.mark;
+	}
+	
+	d->scrollX = e->verticalScrollBar()->value();
+	d->scrollY = e->horizontalScrollBar()->value();
+}
+
+/*!
+	\internal
+*/
+void QEditSession::timerEvent(QTimerEvent *e)
+{
+	if ( e->timerId() == m_id )
+	{
+		updateData();
+	}
+}
+
+QEditor* QEditSession::createEditor()
+{
+	return new QEditor;
+}
+
+QEditSession::Cursor::Cursor(const QDocumentCursor& c)
+{
+	beginLine = c.lineNumber();
+	beginColumn = c.columnNumber();
+	endLine = c.hasSelection() ? c.anchorLineNumber() : -1;
+	endColumn = c.hasSelection() ? c.anchorColumnNumber() : -1;
+	
+	//qDebug("((%i, %i), (%i, %i))", beginLine, beginColumn, endLine, endColumn);
+}
+
+QDocumentCursor QEditSession::Cursor::toDocumentCursor(QDocument *d) const
+{
+	//qDebug("((%i, %i), (%i, %i))", beginLine, beginColumn, endLine, endColumn);
+	
+	QDocumentCursor beg(d, beginLine, beginColumn);
+	QDocumentCursor end(d, endLine, endColumn);
+	
+	if ( endLine != -1 )
+	{
+		end.setSelectionBoundary(beg);
+		return end;
+	}
+	
+	return beg;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qeditsession.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QEDIT_SESSION_H_
+#define _QEDIT_SESSION_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qeditsession.h
+	\brief Definition of the QEditSession class.
+*/
+
+#include <QHash>
+#include <QObject>
+#include <QPointer>
+#include <QDateTime>
+#include <QStringList>
+
+class QEditor;
+
+class QDocument;
+class QDocumentCursor;
+class QDocumentCommand;
+
+class QDataStream;
+
+class QCE_EXPORT QEditSession : public QObject
+{
+	Q_OBJECT
+	
+	public:
+		QEditSession(QObject *p = 0);
+		QEditSession(const QString& f, QObject *p = 0);
+		virtual ~QEditSession();
+		
+		int autoUpdateInterval() const;
+		
+		QString fileName() const;
+		
+	public slots:
+		virtual void addEditor(QEditor *e);
+		virtual void removeEditor(QEditor *e);
+		
+		virtual void updateData();
+		
+		virtual void setAutoUpdateInterval(int ms);
+		
+		virtual void setFileName(const QString& filename, bool restore = false);
+		
+		virtual void clear(bool cleanup = false);
+		
+		virtual void save();
+		virtual void restore();
+		
+		virtual void save(QDataStream& s);
+		virtual void restore(QDataStream& s);
+		
+	signals:
+		void restored(QEditor *e);
+		
+	protected slots:
+		virtual void destroyed(QObject *o);
+		
+		virtual void saved(QEditor *e, const QString& fn);
+		virtual void loaded(QEditor *e, const QString& fn);
+		
+	protected:
+		virtual void timerEvent(QTimerEvent *e);
+		
+		virtual QEditor* createEditor();
+		
+		struct Cursor
+		{
+			Cursor()
+			 : beginLine(-1), beginColumn(-1), endLine(-1), endColumn(-1) {}
+			
+			Cursor(int line, int column)
+			 : beginLine(line), beginColumn(column), endLine(-1), endColumn(-1) {}
+			
+			Cursor(const Cursor& c)
+			 : beginLine(c.beginLine), beginColumn(c.beginColumn), endLine(c.endLine), endColumn(c.endColumn) {}
+			
+			Cursor(const QDocumentCursor& c);
+			
+			QDocumentCursor toDocumentCursor(QDocument *d) const;
+			
+			int beginLine;
+			int beginColumn;
+			int endLine;
+			int endColumn;
+		};
+		
+		struct Document
+		{
+			QString fileName;
+			QDateTime timeStamp;
+			
+			int scrollX, scrollY;
+			
+			QList<Cursor> cursors;
+			QHash<int, QList<int> > marks;
+		};
+		
+		virtual void update(QEditor *e, Document *d);
+		
+		int m_id;
+		int m_delay;
+		QString m_fileName;
+		
+		QList<QEditor*> m_editors;
+		QList<Document*> m_sessionData;
+};
+
+#endif // ! _QEDIT_SESSION_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qformat.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QFORMAT_H_
+#define _QFORMAT_H_
+
+/*!
+	\file qformat.h
+	\brief Definition of the QFormat class
+*/
+
+#include <QFont>
+#include <QColor>
+#include <QTextCharFormat>
+
+template <typename T>
+class QVector;
+
+struct QFormat
+{
+	inline QFormat()
+	 : weight(QFont::Normal), italic(false), overline(false), underline(false), strikeout(false), waveUnderline(false)
+	{}
+	
+	inline QFormat(const QColor& c)
+	 : weight(QFont::Normal), italic(false), overline(false), underline(false), strikeout(false), waveUnderline(false), foreground(c)
+	{}
+	
+	inline QFormat(int w, const QColor& c)
+	 : weight(w), italic(false), overline(false), underline(false), strikeout(false), waveUnderline(false), foreground(c)
+	{}
+	
+	inline QFormat(int w, bool i, bool u, bool s, const QColor& c)
+	 : weight(w), italic(i), overline(false), underline(u), strikeout(s), waveUnderline(false), foreground(c)
+	{}
+	
+	inline QFormat(int w, bool i, bool o, bool u, bool s, bool wu, const QColor& c)
+	 : weight(w), italic(i), overline(o), underline(u), strikeout(s), waveUnderline(wu), foreground(c)
+	{}
+	
+	inline QFormat(const QFormat& f)
+	 : weight(f.weight), italic(f.italic),
+	 	overline(f.overline), underline(f.underline), strikeout(f.strikeout), waveUnderline(f.waveUnderline),
+	 	foreground(f.foreground), background(f.background), linescolor(f.linescolor)
+	{}
+	
+	inline QFormat& operator = (const QFormat& f)
+	{
+		weight = f.weight;
+		italic = f.italic;
+		overline = f.overline;
+		underline = f.underline;
+		strikeout = f.strikeout;
+		foreground = f.foreground;
+		background = f.background;
+		linescolor = f.linescolor;
+		waveUnderline = f.waveUnderline;
+		
+		return *this;
+	}
+	
+	inline bool operator == (const QFormat& f) const
+	{
+		return 		(weight == f.weight)
+				&&
+					(italic == f.italic)
+				&&
+					(overline == f.overline)
+				&&
+					(underline == f.underline)
+				&&
+					(strikeout == f.strikeout)
+				&&
+					(foreground == f.foreground)
+				&&
+					(background == f.background)
+				&&
+					(linescolor == f.linescolor)
+				&&
+					(waveUnderline == f.waveUnderline)
+				;
+	}
+	
+	inline bool operator != (const QFormat& f) const
+	{
+		return 		(weight != f.weight)
+				||
+					(italic != f.italic)
+				||
+					(overline != f.overline)
+				||
+					(underline != f.underline)
+				||
+					(strikeout != f.strikeout)
+				||
+					(foreground != f.foreground)
+				||
+					(background != f.background)
+				||
+					(linescolor != f.linescolor)
+				||
+					(waveUnderline != f.waveUnderline)
+				;
+	}
+	
+	QTextCharFormat toTextCharFormat() const
+	{
+		QTextCharFormat f;
+		f.setFontWeight(weight);
+		f.setFontItalic(italic);
+		f.setFontOverline(overline);
+		f.setFontUnderline(underline);
+		f.setFontStrikeOut(strikeout);
+		f.setUnderlineColor(linescolor);
+		
+		if ( waveUnderline )
+		{
+		    f.setUnderlineStyle(QTextCharFormat::WaveUnderline);
+		}
+		
+		if ( foreground.isValid() )
+			f.setForeground(foreground);
+		
+		if ( background.isValid() )
+			f.setBackground(background);
+		
+		return f;
+	}
+	
+	int weight;
+	bool italic;
+	bool overline;
+	bool underline;
+	bool strikeout;
+	bool waveUnderline;
+	QColor foreground;
+	QColor background;
+	QColor linescolor;
+};
+
+Q_DECLARE_TYPEINFO(QFormat, Q_MOVABLE_TYPE);
+
+struct QFormatRange
+{
+	inline QFormatRange()
+	 : offset(0), length(0), format(0)
+	{}
+	
+	inline QFormatRange(int o, int l, int f)
+	 : offset(o), length(l), format(f)
+	{}
+	
+	inline bool operator == (const QFormatRange& o)
+	{ return (offset == o.offset) && (length == o.length) && (format == o.format); }
+	
+	inline bool operator != (const QFormatRange& o)
+	{ return (offset != o.offset) || (length != o.length) || (format != o.format); }
+	
+	int offset;
+	int length;
+	int format;
+};
+
+Q_DECLARE_TYPEINFO(QFormatRange, Q_PRIMITIVE_TYPE);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qformatfactory.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,16 @@
+/*
+	Transition header file.
+*/
+
+#ifndef _QFORMAT_FACTORY_H_
+
+#include "qformatscheme.h"
+
+class QFormatFactory : public QFormatScheme
+{
+	public:
+		inline QFormatFactory(QObject *p = 0) : QFormatScheme(p) {}
+		inline QFormatFactory(const QString& f, QObject *p = 0) : QFormatScheme(f, p) {}
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qformatscheme.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,493 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qformatscheme.h"
+
+/*!
+	\file qformatscheme.cpp
+	\brief Implementation of QFormatScheme
+	
+	\see QFormatScheme
+*/
+
+/*!
+	\ingroup language
+	@{
+	
+	\class QFormatScheme
+	\brief A storage/configuration class for shared highlighting formats
+	
+	It stores text formats used by highlighters interfaces and provides
+	a default serializing format in QXF format (XML-based).
+	
+	\see QLanguageFactory
+	\see QHighlighter
+*/
+
+#include "qformat.h"
+
+#include <QFile>
+#include <QDomText>
+#include <QSettings>
+#include <QStringList>
+#include <QDomElement>
+#include <QDomDocument>
+
+#define QFORMAT_VERSION "1.0"
+
+static bool bool_cast(const QString& s)
+{
+	return !QString::compare(s, QLatin1String("true")) || s.toUInt() == 1;
+}
+
+/*!
+	\brief Constructor
+*/
+QFormatScheme::QFormatScheme(QObject *p)
+ : QObject(p)
+{
+	setFormat("normal", QFormat());
+}
+
+/*!
+	\brief Constructor
+	\param f Filename of a format settings file to load
+*/
+QFormatScheme::QFormatScheme(const QString& f, QObject *p)
+ : QObject(p)
+{
+	load(f);
+}
+
+/*!
+	\brief Destructor
+*/
+QFormatScheme::~QFormatScheme()
+{
+}
+
+/*!
+	\brief Re-initialize the format scheme
+	
+	Calling this method leaves the format scheme with only one
+	format : the "normal" one, set to a default-constructed QFormat
+*/
+void QFormatScheme::clear()
+{
+	m_formatKeys.clear();
+	m_formatValues.clear();
+	
+	setFormat("normal", QFormat());
+}
+
+/*!
+	\brief Load format settings from a file
+	\param f file to load data from
+
+	The default implementation loads data in QXF format (XML-based)
+
+	\note Previous content is discarded
+*/
+void QFormatScheme::load(const QString& f)
+{
+	clear();
+	m_settings = f;
+
+	QFile settings(f);
+	
+	if ( settings.open(QFile::ReadOnly | QFile::Text) )
+	{
+		QDomDocument doc;
+		doc.setContent(&settings);
+		
+		load(doc.documentElement());
+	}
+}
+
+/*!
+	\brief Save the format settings to a file
+	\param f target file (if none specified, last value passed to load is used)
+
+	The default implementation saves data in QXF format (XML-based)
+*/
+void QFormatScheme::save(const QString& f) const
+{
+	QFile settings(f.count() ? f : m_settings);
+	
+	if ( settings.open(QFile::WriteOnly | QFile::Text) )
+	{
+		QDomDocument doc("QXF");
+		QDomElement root = doc.createElement("QXF");
+		save(root);
+		doc.appendChild(root);
+		settings.write(doc.toByteArray(4));
+	}
+}
+
+/*!
+	\overload
+	\param elem Source element to scan
+	\param ignoreNewIds whether unknown format identifiers should be ignored
+	
+	The given dom element must contain a proper version attribute and format
+	data as child elements (&lt;format&gt; tags)
+	
+	\note Previous content is not discarded
+*/
+void QFormatScheme::load(const QDomElement& elem, bool ignoreNewIds)
+{
+	if ( elem.attribute("version") < QFORMAT_VERSION )
+	{
+		qWarning("Format encoding version mismatch : [found]%s != [expected]%s",
+				qPrintable(elem.attribute("version")),
+				QFORMAT_VERSION);
+		
+		return;
+	}
+	
+	QDomElement e, c;
+	QDomNodeList l, f = elem.elementsByTagName("format");
+	
+	for ( int i = 0; i < f.count(); i++ )
+	{
+		e = f.at(i).toElement();
+		
+		if ( ignoreNewIds && !m_formatKeys.contains(e.attribute("id")) )
+			continue;
+		
+		l = e.childNodes();
+		
+		QFormat fmt;
+		
+		for ( int i = 0; i < l.count(); i++ )
+		{
+			c = l.at(i).toElement();
+			
+			if ( c.isNull() )
+				continue;
+			
+			QString field = c.tagName(),
+					value = c.firstChild().toText().data();
+			
+			if ( field == "bold" )
+				fmt.weight = bool_cast(value) ? QFont::Bold : QFont::Normal;
+			else if ( field == "italic" )
+				fmt.italic = bool_cast(value);
+			else if ( field == "overline" )
+				fmt.overline = bool_cast(value);
+			else if ( field == "underline" )
+				fmt.underline = bool_cast(value);
+			else if ( field == "strikeout" )
+				fmt.strikeout = bool_cast(value);
+			else if ( field == "waveUnderline" )
+				fmt.waveUnderline = bool_cast(value);
+			else if ( field == "color" || field == "foreground" )
+				fmt.foreground = QColor(value);
+			else if ( field == "background" )
+				fmt.background = QColor(value);
+			else if ( field == "linescolor" )
+				fmt.linescolor = QColor(value);
+			
+		}
+		
+		setFormat(e.attribute("id"), fmt);
+	}
+}
+
+/*!
+	\overload
+*/
+void QFormatScheme::save(QDomElement& elem) const
+{
+	QDomDocument doc = elem.ownerDocument();
+	elem.setAttribute("version", QFORMAT_VERSION);
+	
+	for ( int i = 0; i < m_formatKeys.count(); ++i )
+	{
+		QDomText t;
+		QDomElement f, c = doc.createElement("format");
+		
+		c.setAttribute("id", m_formatKeys.at(i));
+		
+		const QFormat& fmt = m_formatValues.at(i);
+		
+		f = doc.createElement("bold");
+		t = doc.createTextNode((fmt.weight == QFont::Bold) ? "true" : "false");
+		f.appendChild(t);
+		c.appendChild(f);
+		
+		f = doc.createElement("italic");
+		t = doc.createTextNode(fmt.italic ? "true" : "false");
+		f.appendChild(t);
+		c.appendChild(f);
+		
+		f = doc.createElement("overline");
+		t = doc.createTextNode(fmt.overline ? "true" : "false");
+		f.appendChild(t);
+		c.appendChild(f);
+		
+		f = doc.createElement("underline");
+		t = doc.createTextNode(fmt.underline ? "true" : "false");
+		f.appendChild(t);
+		c.appendChild(f);
+		
+		f = doc.createElement("strikeout");
+		t = doc.createTextNode(fmt.strikeout ? "true" : "false");
+		f.appendChild(t);
+		c.appendChild(f);
+		
+		f = doc.createElement("waveUnderline");
+		t = doc.createTextNode(fmt.waveUnderline ? "true" : "false");
+		f.appendChild(t);
+		c.appendChild(f);
+		
+		if ( fmt.foreground.isValid() )
+		{
+			f = doc.createElement("foreground");
+			t = doc.createTextNode(fmt.foreground.name());
+			f.appendChild(t);
+			c.appendChild(f);
+		}
+		
+		if ( fmt.background.isValid() )
+		{
+			f = doc.createElement("background");
+			t = doc.createTextNode(fmt.background.name());
+			f.appendChild(t);
+			c.appendChild(f);
+		}
+		
+		if ( fmt.linescolor.isValid() )
+		{
+			f = doc.createElement("linescolor");
+			t = doc.createTextNode(fmt.linescolor.name());
+			f.appendChild(t);
+			c.appendChild(f);
+		}
+		
+		elem.appendChild(c);
+	}
+}
+
+/*!
+	\overload
+	\brief Load format data from a QSettings object
+	\param s QSettings object from which data will be fetched
+	\param ignoreNewIds whether unknown format identifiers should be ignored
+	
+	The QSettings object is assumed to be initialized properly and to
+	point to a correct location.
+	
+	\note Previous content is not discarded
+*/
+void QFormatScheme::load(QSettings& s, bool ignoreNewIds)
+{
+	QString version = s.value("version").toString();
+	
+	if ( version < QFORMAT_VERSION )
+	{
+		qWarning("Format encoding version mismatch : [found]%s != [expected]%s",
+				qPrintable(version),
+				QFORMAT_VERSION);
+		
+		return;
+	}
+	
+	s.beginGroup("data");
+	
+	QStringList l = s.childGroups();
+	
+	foreach ( QString id, l )
+	{
+		if ( ignoreNewIds && !m_formatKeys.contains(id) )
+			continue;
+		
+		s.beginGroup(id);
+		
+		QFormat fmt;
+		QStringList fields = s.childKeys();
+		
+		foreach ( QString field, fields )
+		{
+			QString value = s.value(field).toString();
+			
+			if ( field == "bold" )
+				fmt.weight = bool_cast(value) ? QFont::Bold : QFont::Normal;
+			else if ( field == "italic" )
+				fmt.italic = bool_cast(value);
+			else if ( field == "overline" )
+				fmt.overline = bool_cast(value);
+			else if ( field == "underline" )
+				fmt.underline = bool_cast(value);
+			else if ( field == "strikeout" )
+				fmt.strikeout = bool_cast(value);
+			else if ( field == "waveUnderline" )
+				fmt.waveUnderline = bool_cast(value);
+			else if ( field == "color" || field == "foreground" )
+				fmt.foreground = QColor(value);
+			else if ( field == "background" )
+				fmt.background = QColor(value);
+			else if ( field == "linescolor" )
+				fmt.linescolor = QColor(value);
+			
+		}
+		
+		setFormat(id, fmt);
+		s.endGroup();
+	}
+	
+	s.endGroup();
+}
+
+/*!
+	\overload
+*/
+void QFormatScheme::save(QSettings& s) const
+{
+	s.setValue("version", QFORMAT_VERSION);
+	
+	s.beginGroup("data");
+	
+	for ( int i = 0; i < m_formatKeys.count(); ++i )
+	{
+		s.beginGroup(m_formatKeys.at(i));
+		
+		const QFormat& fmt = m_formatValues.at(i);
+		
+		s.setValue("bold", (fmt.weight == QFont::Bold) ? "true" : "false");
+		s.setValue("italic", fmt.italic ? "true" : "false");
+		s.setValue("overline", fmt.overline ? "true" : "false");
+		s.setValue("underline", fmt.underline ? "true" : "false");
+		s.setValue("strikeout", fmt.strikeout ? "true" : "false");
+		s.setValue("waveUnderline", fmt.waveUnderline ? "true" : "false");
+		
+		if ( fmt.foreground.isValid() )
+		{
+			s.setValue("foreground", fmt.foreground.name());
+		}
+		
+		if ( fmt.background.isValid() )
+		{
+			s.setValue("background", fmt.background.name());
+		}
+		
+		if ( fmt.linescolor.isValid() )
+		{
+			s.setValue("linescolor", fmt.linescolor.name());
+		}
+		
+		s.endGroup();
+	}
+	
+	s.endGroup();
+}
+
+/*!
+	\return The number of available formats
+*/
+int QFormatScheme::formatCount() const
+{
+	return m_formatValues.count();
+}
+
+/*!
+	\return A list of available format keys
+*/
+QStringList QFormatScheme::formats() const
+{
+	return m_formatKeys.toList();
+}
+
+/*!
+	\return The format key associated to integer format id \a ifid
+*/
+QString QFormatScheme::id(int ifid) const
+{
+	return m_formatKeys.at(ifid);
+}
+
+/*!
+	\return The integer format id associated to format key \a fid
+*/
+int QFormatScheme::id(const QString& sfid) const
+{
+	int idx = m_formatKeys.indexOf(sfid);
+	
+	return (idx == -1) ? 0 : idx;
+}
+
+/*!
+	\return The text format associated with format key \a fid
+	
+	\warning Use at your own risks : if there are no format associated
+	with the requested id this function will crash
+*/
+QFormat& QFormatScheme::formatRef(int ifid)
+{
+	return m_formatValues[ifid];
+}
+
+/*!
+	\return The a reference to the text format associated with format key \a fid
+	
+	\warning Use at your own risks : if there are no format associated
+	with the requested id this function will crash.
+*/
+QFormat& QFormatScheme::formatRef(const QString& sfid)
+{
+	return m_formatValues[id(sfid)];
+}
+
+/*!
+	\return The text format associated with format key \a fid
+*/
+QFormat QFormatScheme::format(int ifid) const
+{
+	//qDebug("Querying format id %i within ]-1, %i[", ifid, m_formatValues.count());
+	
+	return (ifid < m_formatValues.count()) ? m_formatValues.at(ifid) : QFormat();
+}
+
+/*!
+	\return The text format associated with format key \a fid
+*/
+QFormat QFormatScheme::format(const QString& sfid) const
+{
+	return format(id(sfid));
+}
+
+/*!
+	\brief Set text format for key
+	\param fid Format key
+	\param fmt Format value
+*/
+void QFormatScheme::setFormat(const QString& fid, const QFormat& fmt)
+{
+	const int idx = m_formatKeys.indexOf(fid);
+	
+	if ( idx != -1 )
+	{
+		m_formatValues[idx] = fmt;
+	} else {
+		
+		//qDebug("adding format %s [%i]", qPrintable(fid), m_formatKeys.count());
+		
+		m_formatKeys << fid;
+		m_formatValues << fmt;
+	}
+}
+
+/*! @} */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qformatscheme.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QFORMAT_SCHEME_H_
+#define _QFORMAT_SCHEME_H_
+
+/*!
+	\file qformatscheme.h
+	\brief Definition of the QFormatScheme class.
+	
+	\see QFormatScheme
+*/
+
+/*!
+	\defgroup language Language framework
+*/
+
+#include "qce-config.h"
+
+#include <QVector>
+#include <QObject>
+
+struct QFormat;
+class QString;
+class QSettings;
+class QStringList;
+class QDomElement;
+
+class QCE_EXPORT QFormatScheme : public QObject
+{
+	Q_OBJECT
+	
+	public:
+		QFormatScheme(QObject *p = 0);
+		QFormatScheme(const QString& f, QObject *p = 0);
+		virtual ~QFormatScheme();
+		
+		void clear();
+		
+		virtual void load(const QString& filename);
+		virtual void save(const QString& filename = QString()) const;
+		
+		virtual void load(const QDomElement& doc, bool ignoreNewIds = false);
+		virtual void save(QDomElement& elem) const;
+		
+		virtual void load(QSettings& s, bool ignoreNewIds = false);
+		virtual void save(QSettings& s) const;
+		
+		int formatCount() const;
+		QStringList formats() const;
+		
+		virtual QString id(int ifid) const;
+		virtual int id(const QString& sfid) const;
+		
+		virtual QFormat& formatRef(int ifid);
+		virtual QFormat& formatRef(const QString& sfid);
+		
+		virtual QFormat format(int ifid) const;
+		virtual QFormat format(const QString& sfid) const;
+		
+	public slots:
+		virtual void setFormat(const QString& fid, const QFormat& fmt);
+		
+	protected:
+		QString m_settings;
+		
+		QVector<QString> m_formatKeys;
+		QVector<QFormat> m_formatValues;
+};
+
+#endif // !_QFORMAT_SCHEME_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qlanguagedefinition.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,173 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qlanguagedefinition.h"
+
+/*!
+	\file qlanguagedefinition.cpp
+	\brief Implementation of QLanguageDefinition
+	
+	\see QLanguageDefinition
+*/
+
+/*!
+	\ingroup language
+	@{
+	
+	\class QLanguageDefinition
+	\brief Interface for language definition.
+	
+	This class is meant to be subclassed, see \see QGenericDefinition for more
+	informations, and added to a QLanguageFactory.
+	
+	A language definition is a wrapper that creates interfaces for a given file
+	extension from internally handled data (XML files in the case of 
+	QGenericDefinition)
+	
+	\see QLanguageFactory
+*/
+
+#include "qdocument.h"
+#include "qdocumentline.h"
+#include "qdocumentcursor.h"
+
+#include "qlanguagefactory.h"
+
+#include <QKeyEvent>
+
+/*!
+	\brief Empty constructor
+*/
+QLanguageDefinition::QLanguageDefinition()
+{
+}
+
+/*!
+	\brief Empty destructor
+*/
+QLanguageDefinition::~QLanguageDefinition()
+{
+}
+
+/*!
+	\fn QLanguageDefinition::language() 
+	
+	\return The language supported by this definition
+*/
+
+/*!
+	\fn QLanguageDefinition::extensions()
+	
+	\return the file extensions corrseponding to the supported language
+	
+	\see language()
+	\see QFileInfo::completeSuffix()
+*/
+
+/*!
+	\brief Entry point for syntax highlighting
+*/
+int QLanguageDefinition::tokenize(QDocument *d, int line, int count)
+{
+	Q_UNUSED(d)
+	Q_UNUSED(line)
+	
+	return count;
+}
+
+/*!
+	\brief Return the string starting a single line comment, if any offered by the language
+*/
+QString QLanguageDefinition::singleLineComment() const
+{
+	return QString();
+}
+
+/*!
+	\brief Let language specify which line mark should be toggled by left clicking a line mark panel
+*/
+QString QLanguageDefinition::defaultLineMark() const
+{
+	return QString();
+}
+
+/*!
+	\brief Brace matching entry point
+*/
+void QLanguageDefinition::clearMatches(QDocument *d)
+{
+	Q_UNUSED(d)
+}
+
+/*!
+	\brief Brace matching entry point
+*/
+void QLanguageDefinition::match(QDocumentCursor& c)
+{
+	Q_UNUSED(c)
+}
+
+/*!
+	\brief Return the indent to use when inserting a line at a given cursor position
+*/
+QString QLanguageDefinition::indent(const QDocumentCursor& c)
+{
+	Q_UNUSED(c)
+	
+	return QString();
+}
+
+/*!
+	\brief Determines whether the given key event at the given position should cause unindent to happen
+*/
+bool QLanguageDefinition::unindent (const QDocumentCursor& c, const QString& ktxt)
+{
+	Q_UNUSED(c)
+	Q_UNUSED(ktxt)
+	
+	return false;
+}
+
+/*!
+	\brief Expand a collapsed block at a given line
+*/
+void QLanguageDefinition::expand(QDocument *d, int line)
+{
+	Q_UNUSED(d)
+	Q_UNUSED(line)
+}
+
+/*!
+	\brief Collapse a text block at a given line
+*/
+void QLanguageDefinition::collapse(QDocument *d, int line)
+{
+	Q_UNUSED(d)
+	Q_UNUSED(line)
+}
+
+/*!
+	\brief Compute the collapse state of a line
+*/
+int QLanguageDefinition::blockFlags(QDocument *d, int line, int depth) const
+{
+	Q_UNUSED(d)
+	Q_UNUSED(line)
+	Q_UNUSED(depth)
+	
+	return 0;
+}
+
+/*! @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qlanguagedefinition.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QLANGUAGE_DEFINITION_H_
+#define _QLANGUAGE_DEFINITION_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qlanguagedefinition.h
+	\brief Definition of the QLanguageDefinition class.
+	
+	\see QLanguageDefinition
+*/
+
+#include "qformat.h"
+
+#include <QStringList>
+
+class QKeyEvent;
+class QDocument;
+class QDocumentCursor;
+
+#define QCE_FOLD_FLAGS(flags, open, close) ((flags) | (open & QLanguageDefinition::OpenMask) | ((close << 12) & QLanguageDefinition::CloseMask))
+#define QCE_FOLD_OPEN_COUNT(flags) ((flags) & QLanguageDefinition::OpenMask)
+#define QCE_FOLD_CLOSE_COUNT(flags) (((flags) & QLanguageDefinition::CloseMask) >> 12)
+
+class QCE_EXPORT QLanguageDefinition
+{
+	public:
+		/// Collapse state of a line
+		enum CollapseFlag
+		{
+			None		= 0x00000000,		///< The line cannot be collapsed nor expanded
+			Collapsible	= 0x10000000,		///< The line is expanded and can thus be collapsed
+			Collapsed	= 0x20000000,		///< The line is collapsed and can thus be expanded
+			Closure		= 0x40000000,		///< The line is expanded and mark the end of a block
+			
+			CloseMask	= 0x00fff000,		///< Number of actual closing fold mark
+			OpenMask	= 0x00000fff		///< Number of actual open fold mark
+		};
+		
+		Q_DECLARE_FLAGS(CollapseState, CollapseFlag);
+		
+		QLanguageDefinition();
+		virtual ~QLanguageDefinition();
+		
+		virtual QString language() const = 0;
+		virtual QStringList extensions() const = 0;
+		
+		virtual int tokenize(QDocument *d, int line, int count);
+		
+		virtual QString singleLineComment() const;
+		
+		virtual QString defaultLineMark() const;
+		
+		virtual void match(QDocumentCursor& c);
+		virtual void clearMatches(QDocument *d);
+		
+		virtual QString indent(const QDocumentCursor& c);
+		virtual bool unindent (const QDocumentCursor& c, const QString& ktxt);
+		
+		virtual void expand(QDocument *d, int line);
+		virtual void collapse(QDocument *d, int line);
+		virtual int blockFlags(QDocument *d, int line, int depth = 0) const;
+};
+
+#endif // _QLANGUAGE_DEFINITION_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qlanguagefactory.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qlanguagefactory.h"
+
+/*!
+	\file qlanguagefactory.cpp
+	\brief Implementation of QLanguageFactory
+	
+	\see QLanguageFactory
+*/
+
+/*!
+	\ingroup language
+	@{
+	
+	\class QLanguageFactory
+	\brief A class managing language definitions.
+	
+	It stores language definitions, added programmatically or found in XML files,
+	in specified locations and only if generic components are built-in. From 
+	these definitions, QLanguageFactory generates matchers, indenters and
+	highlighters for a text editor, according to a file name.
+	
+	\see QLanguageDefinition
+*/
+
+#include <QDir>
+#include <QFileInfo>
+#include <QStringList>
+
+#ifdef _QCODE_EDIT_DEBUG_
+#include <QtDebug>
+#endif
+
+#include "qeditor.h"
+#include "qformatscheme.h"
+
+#include "qlanguagedefinition.h"
+#include "qcodecompletionengine.h"
+
+#ifdef QNFA_BUILD
+#include "qnfadefinition.h"
+#endif
+
+/*!
+	\brief Empty constructor
+*/
+QLanguageFactory::QLanguageFactory(QFormatScheme *fmt, QObject *p)
+ : QObject(p), m_defaultFormatScheme(fmt)
+{
+	
+}
+
+/*!
+	\brief Empty destructor
+*/
+QLanguageFactory::~QLanguageFactory()
+{
+	foreach ( QString l, m_languages )
+	{
+		const LangData& d = m_data[l];
+		
+		if ( d.s != m_defaultFormatScheme )
+			delete d.s;
+		
+		delete d.d;
+		//delete d.e;
+	}
+}
+
+/*!
+	\return a list of languages supported by this factory
+*/
+QStringList QLanguageFactory::languages() const
+{
+	return m_languages;
+}
+
+/*!
+	\return a list of file filters supported by this factory
+	
+	\note This list is NEVER empty and the last item is always "All files (*)"
+*/
+QStringList QLanguageFactory::fileFilters() const
+{
+	QStringList l;
+	
+	foreach ( QString lng, m_languages )
+		l << tr("%1 files (*.%2)").arg(lng).arg(m_data[lng].extensions.join(" *."));
+	
+	l << tr("All files (*)");
+	
+	return l;
+}
+
+/*!
+	\param e target editor
+	\param file filename displayed by the editor
+	
+	The \a file parameter may actuall be either a filename, an extension or the name of the language,
+	checked in that order.
+	
+	If it is a filename, complete extension as higher priority than simple extension
+	(see QFileInfo suffix() and completeSuffix()).
+	
+	Matches are first done case-sensitively. 
+	
+	If no matching language definition is found for all three possible interpretations of the \a file
+	parameter, the same search is done case-insensitively.
+	
+	If no matching language is found the previous language definition/completion engine of the editor
+	are removed, leaving it blank, and the format scheme of the document is set to the defaultFormatScheme()
+*/
+void QLanguageFactory::setLanguage(QEditor *e, const QString& file)
+{
+	QString lang;
+	QFileInfo inf(file);
+	const QString ext = inf.suffix(),
+				cext = inf.completeSuffix();
+	
+	//qDebug("suff:%s; compSuff:%s", qPrintable(ext), qPrintable(cext));
+	
+	QLanguageDefinition *oldLang = e->languageDefinition();
+	
+	if ( file.count() )
+	{
+		QList<Qt::CaseSensitivity> lcs;
+		lcs << Qt::CaseSensitive << Qt::CaseInsensitive;
+		
+		foreach ( Qt::CaseSensitivity cs, lcs )
+		{
+			int n = 0, idx = -1;
+			QStringList ext_langs, cext_langs, fcext_langs;
+			
+			foreach ( QString lang, m_languages )
+			{
+				const QStringList& exts = m_data[lang].extensions;
+				
+				//qDebug("%s in (%s) ?", qPrintable(ext), qPrintable(exts.join(" ")));
+				
+				foreach ( QString x, exts )
+				{
+					if ( !x.compare(ext, cs) )
+						ext_langs << lang;
+					
+					if ( !x.compare(cext, cs) )
+						cext_langs << lang;
+					
+					if ( !x.compare(file, cs) )
+						fcext_langs << lang;
+				}
+				
+				if ( !lang.compare(file, cs) )
+					idx = n;
+				
+				++n;
+			}
+			
+			if ( cext_langs.count() )
+			{
+				// TODO : use MIME types to resolve ambiguity
+				lang = cext_langs.first();
+			} else if ( ext_langs.count() ) {
+				// TODO : use MIME types to resolve ambiguity
+				lang = ext_langs.first();
+			} else if ( fcext_langs.count() ) {
+				// TODO : use MIME types to resolve ambiguity
+				lang = fcext_langs.first();
+			} else if ( idx != -1 ) {
+				lang = m_languages.at(idx);
+			}
+			
+			if ( lang.count() )
+				break;
+		}
+	}
+	
+	if ( lang.isEmpty() )
+	{
+		//qDebug("no lang match for %s", qPrintable(file));
+		e->setLanguageDefinition(0);
+		e->setCompletionEngine(0);
+		e->document()->setFormatScheme(m_defaultFormatScheme);
+		
+		if ( oldLang )
+			e->highlight();
+		
+	} else {
+		//qDebug("lang match for %s : %s", qPrintable(file), qPrintable(lang));
+		const LangData& data = m_data[lang];
+		
+		e->setLanguageDefinition(data.d);
+		e->setCompletionEngine(data.e ? data.e->clone() : 0);
+		e->document()->setFormatScheme(data.s ? data.s : m_defaultFormatScheme);
+		
+		if ( oldLang != data.d )
+			e->highlight();
+	}
+}
+
+/*!
+	\brief Adds a language to the factory
+	
+	\param d language data
+	
+	\note The language data will overwrite any existing one for the same language
+*/
+void QLanguageFactory::addLanguage(const QLanguageFactory::LangData& d)
+{
+	m_data[d.lang] = d;
+	
+	if ( !d.e )
+	{
+		foreach ( QCodeCompletionEngine *e, m_unusedEngines )
+		{
+			if ( e->language() == d.lang )
+			{
+				m_data[d.lang].e = e;
+				break;
+			}
+		}
+	}
+	
+	if ( !m_languages.contains(d.lang) )
+		m_languages << d.lang;
+}
+
+/*!
+	\brief Lookup language data for a matching language
+	
+	The primary purpose of this function is to make it easy to create configuration dialogs (mainly for
+	format schemes). Beware though : some language may use the default format scheme. It is recommended
+	to check for that before modifying a format scheme or users might be surprised...
+	
+	\warning This function will lead to crashes if you pass it a language name not contained in languages().
+*/
+const QLanguageFactory::LangData& QLanguageFactory::languageData(const QString& lang)
+{
+	return m_data[lang];
+}
+
+/*!
+	\brief Registers a new completion engine
+	
+	\note This engine will NOT be used if there are no language definition for the
+	language it supports...
+*/
+void QLanguageFactory::addLanguageDefinition(QLanguageDefinition *l)
+{
+	Q_UNUSED(l)
+	
+	qWarning("New design does not allow this sorry...");
+}
+
+/*!
+	\brief Registers a new completion engine
+	
+	\note This engine will NOT be used if there are no language definition for the
+	language it supports...
+*/
+void QLanguageFactory::addCompletionEngine(QCodeCompletionEngine *e)
+{
+	foreach ( QString l, m_languages )
+	{
+		if ( l == e->language() )
+		{
+			m_data[l].e = e;
+			return;
+		}
+	}
+	
+	m_unusedEngines << e;
+}
+
+/*!
+	\brief Fetches syntax definitions from files in \a path
+*/
+void QLanguageFactory::addDefinitionPath(const QString& path)
+{
+	QDir d(path);
+	
+	foreach ( QString f, d.entryList(QDir::Files | QDir::Readable) )
+	{
+		#ifdef QNFA_BUILD
+		if ( f.endsWith(".qnfa") )
+		{
+			//qDebug("loading file %s", qPrintable(f));
+			QFileInfo info(d.filePath(f));
+			QString specificFormatScheme = QDir(info.path()).filePath(info.baseName() + ".qxf");
+			
+			QFormatScheme *scheme = m_defaultFormatScheme;
+			
+			if ( QFile::exists(specificFormatScheme) )
+			{
+				scheme = new QFormatScheme(specificFormatScheme);
+			}
+			
+			LangData data;
+			QNFADefinition::load(d.filePath(f), &data, scheme);
+			
+			//qDebug("%s : (%s | %s)", qPrintable(data.lang), qPrintable(data.mime), qPrintable(data.extensions.join(", ")));
+			addLanguage(data);
+			//addLanguageDefinition(new QNFADefinition(d.filePath(f), this));
+		}
+		#endif
+	}
+}
+
+/*! @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qlanguagefactory.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QLANGUAGE_FACTORY_H_
+#define _QLANGUAGE_FACTORY_H_
+
+/*!
+	\file qlanguagefactory.h
+	\brief Definition of the QLanguageFactory class.
+	
+	\see QLanguageFactory
+*/
+
+/*!
+	\defgroup language Language framework
+*/
+
+#include "qce-config.h"
+
+#include <QHash>
+#include <QObject>
+#include <QStringList>
+
+class QEditor;
+class QFormatScheme;
+class QLanguageDefinition;
+class QCodeCompletionEngine;
+
+class QCE_EXPORT QLanguageFactory : public QObject
+{
+	Q_OBJECT
+	
+	public:
+		struct LangData
+		{
+			QString lang, mime;
+			QStringList extensions;
+			
+			QFormatScheme *s;
+			
+			QLanguageDefinition *d;
+			QCodeCompletionEngine *e;
+		};
+		
+		QLanguageFactory(QFormatScheme *fmt, QObject *p = 0);
+		virtual ~QLanguageFactory();
+		
+		QStringList languages() const;
+		QStringList fileFilters() const;
+		
+		const LangData& languageData(const QString& lang);
+		
+		void addDefinitionPath(const QString& path);
+		
+		inline QFormatScheme* defaultFormatScheme() const { return m_defaultFormatScheme; }
+		
+	public slots:
+		void addLanguage(const LangData& d);
+		void addLanguageDefinition(QLanguageDefinition *l);
+		void addCompletionEngine(QCodeCompletionEngine *e);
+		
+		virtual void setLanguage(QEditor *e, const QString& f);
+		
+	private:
+		QStringList m_languages;
+		QHash<QString, LangData> m_data;
+		QList<QCodeCompletionEngine*> m_unusedEngines;
+		
+		QFormatScheme *m_defaultFormatScheme;
+};
+
+#endif // _QLANGUAGE_FACTORY_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qlinemarksinfocenter.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,643 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qlinemarksinfocenter.h"
+
+/*!
+	\file qlinemarksinfocenter.cpp
+	\brief Implementation of QLineMarksInfoCenter
+	
+	\see QLineMarksInfoCenter
+*/
+
+/*!
+	\ingroup language
+	@{
+	
+	\class QLineMarksInfoCenter
+	\brief A class managing line marks accross all managed editors
+	
+	QLineMarksInfoCenter provides mean to read/write line marks on managed editors
+	but also to serialize and deserialize that data.
+*/
+
+#include "qeditor.h"
+#include "qcodeedit.h"
+
+#include "qdocument.h"
+#include "qdocument_p.h"
+#include "qdocumentline.h"
+
+#include <QFile>
+#include <QDataStream>
+#include <QDomDocument>
+
+#define QLINE_MARKS_DUMP_VERSION		1
+#define QLINE_MARKS_DUMP_VERSION_MIN	1
+
+QLineMarksInfoCenter* QLineMarksInfoCenter::m_instance = 0;
+
+QLineMarksInfoCenter* QLineMarksInfoCenter::instance()
+{
+	if ( !m_instance )
+		m_instance = new QLineMarksInfoCenter;
+	
+	return m_instance;
+}
+
+void QLineMarksInfoCenter::destroy()
+{
+	if ( m_instance )
+		delete m_instance;
+	
+	m_instance = 0;
+}
+
+QLineMarksInfoCenter::QLineMarksInfoCenter()
+ : QObject(0)
+{
+	qRegisterMetaType<QLineMark>("QLineMark");
+}
+
+QLineMarksInfoCenter::~QLineMarksInfoCenter()
+{
+	
+}
+
+/*!
+	\return the list of line marks set on a given file
+*/
+QLineMarkList QLineMarksInfoCenter::marks(const QString& file)
+{
+	QLineMarkList l;
+	bool check = file.count();
+	
+	foreach ( QLineMarkHandle m, m_lineMarks )
+	{
+		if ( !check || (m.file == file) )
+			l << QLineMark(file, m.line->line() + 1, m.mark);
+	}
+	
+	return l;
+}
+
+/*!
+	\brief Remove all line marks on all files
+*/
+void QLineMarksInfoCenter::clear()
+{
+	foreach ( QLineMarkHandle m, m_lineMarks )
+	{
+		removeLineMark(m);
+	}
+}
+
+/*!
+	\brief Remove all line marks on a given file
+*/
+void QLineMarksInfoCenter::removeMarks(const QString& file)
+{
+	foreach ( QLineMarkHandle m, m_lineMarks )
+		if ( m.file == file )
+			removeLineMark(m);
+	
+}
+
+/*!
+	\brief Add a line mark
+	
+	If the target file is not found the toggling will be delayed.
+*/
+void QLineMarksInfoCenter::addLineMark(const QLineMark& mark)
+{
+	QEditor *e = QCodeEdit::managed(mark.file);
+	
+	if ( !e )
+	{
+		m_delayed << mark;
+		return;
+	}
+	
+	QDocumentLine l = e->document()->line(mark.line - 1);
+	
+	if ( !l.isValid() )
+		return;
+	
+	e->setCursor(QDocumentCursor(e->document(), mark.line - 1));
+	l.addMark(mark.mark);
+}
+
+/*!
+	\brief Remove a line mark
+	
+	If the target file is not found the addition will be delayed.
+*/
+void QLineMarksInfoCenter::toggleLineMark(const QLineMark& mark)
+{
+	QEditor *e = QCodeEdit::managed(mark.file);
+	
+	if ( !e )
+	{
+		m_delayed << mark;
+		return;
+	}
+	
+	QDocumentLine l = e->document()->line(mark.line - 1);
+	
+	if ( !l.isValid() )
+		return;
+	
+	e->setCursor(QDocumentCursor(e->document(), mark.line - 1));
+	l.toggleMark(mark.mark);
+}
+
+/*!
+	\brief Toggle a line mark
+	
+	If the target file is not found the removal will be delayed.
+*/
+void QLineMarksInfoCenter::removeLineMark(const QLineMark& mark)
+{
+	QEditor *e = QCodeEdit::managed(mark.file);
+	
+	if ( !e )
+		return;
+	
+	QDocumentLine l = e->document()->line(mark.line - 1);
+	
+	if ( !l.isValid() )
+		return;
+	
+	l.removeMark(mark.mark);
+	
+	//e->setCursor(QDocumentCursor(l));
+}
+
+/*!
+	\brief Add a line mark
+*/
+void QLineMarksInfoCenter::addLineMark(const QLineMarkHandle& mark)
+{
+	QDocumentLine l(mark.line);
+	
+	if ( l.isValid() )
+		l.addMark(mark.mark);
+	
+}
+
+/*!
+	\brief Toggle a line mark
+*/
+void QLineMarksInfoCenter::toggleLineMark(const QLineMarkHandle& mark)
+{
+	QDocumentLine l(mark.line);
+	
+	if ( l.isValid() )
+		l.toggleMark(mark.mark);
+	
+}
+
+/*!
+	\brief Remove a line mark
+*/
+void QLineMarksInfoCenter::removeLineMark(const QLineMarkHandle& mark)
+{
+	QDocumentLine l(mark.line);
+	
+	if ( l.isValid() )
+		l.removeMark(mark.mark);
+	
+}
+
+/*!
+	\brief Flush all delayed line marks addition/removal/toggling for a given file
+*/
+void QLineMarksInfoCenter::flush(const QString& file)
+{
+	QLineMarkList::iterator i = m_delayed.begin();
+	
+	while ( i != m_delayed.end() )
+	{
+		if ( i->file == file )
+		{
+			addLineMark(*i);
+			i = m_delayed.erase(i);
+		} else {
+			++i;
+		}
+	}
+}
+
+/*!
+	\brief Load serialized line marks data from a file
+*/
+void QLineMarksInfoCenter::loadMarks(const QString& f)
+{
+	QFile file(f);
+	
+	if ( !file.open(QFile::ReadOnly) )
+		return;
+	
+	QDataStream stream(&file);
+	
+	int version;
+	
+	stream >> version;
+	
+	if ( version < QLINE_MARKS_DUMP_VERSION_MIN )
+	{
+		qWarning("QLineMarksInfoCenter : dump file version mismatch");
+		return;
+	} else if ( version > QLINE_MARKS_DUMP_VERSION ) {
+		qWarning("QLineMarksInfoCenter : dump file version mismatch");
+		return;
+	}
+	
+	QLineMark mark;
+	
+	while ( !stream.atEnd() )
+	{
+		stream >> mark;
+		
+		addLineMark(mark);
+	}
+}
+
+/*!
+	\brief Write serialized line marks data to a file
+*/
+void QLineMarksInfoCenter::saveMarks(const QString& f)
+{
+	QFile file(f);
+	
+	if ( !file.open(QFile::WriteOnly) )
+		return;
+	
+	QDataStream stream(&file);
+	
+	stream << QLINE_MARKS_DUMP_VERSION;
+	
+	foreach ( QLineMarkHandle mark, m_lineMarks )
+	{
+		stream << mark.line->line() + 1;
+		stream << mark.file;
+		stream << QLineMarksInfoCenter::instance()->markTypeId(mark.mark);
+		//stream << mark;
+	}
+}
+
+QDataStream& operator >> (QDataStream& d, QLineMark& m)
+{
+	int line;
+	QString file, mark;
+	
+	d >> line;
+	d >> file;
+	d >> mark;
+	
+	m.line = line;
+	m.file = file;
+	m.mark = QLineMarksInfoCenter::instance()->markTypeId(mark);
+	
+	return d;
+}
+
+QDataStream& operator << (QDataStream& d, const QLineMark& m)
+{
+	int line = m.line;
+	QString file = m.file,
+			mark = QLineMarksInfoCenter::instance()->markTypeId(m.mark);
+	
+	d << line;
+	d << file;
+	d << mark;
+	
+	return d;
+}
+
+/*!
+	\brief Load line marks definition from a file
+*/
+void QLineMarksInfoCenter::loadMarkTypes(const QString& f)
+{
+	QFile file(f);
+	
+	if ( !file.open(QFile::ReadOnly | QFile::Text) )
+		return;
+	
+	// TODO : prefer QXmlStreamReader when building against Qt 4.3.0
+	
+	QDomDocument doc;
+	doc.setContent(&file);
+	
+	QDomNodeList l = doc.documentElement().childNodes();
+	
+	for ( int i = 0; i < l.count(); i++ )
+	{
+		QDomElement e = l.at(i).toElement();
+		
+		if ( e.isNull() || (e.tagName() != "mark") )
+			continue;
+		
+		QLineMarkType t;
+		QDomNodeList c = e.childNodes();
+		
+		//qDebug("mark {");
+		
+		for ( int j = 0; j < c.count(); j++ )
+		{
+			QDomElement attr = c.at(j).toElement();
+			
+			if ( attr.isNull() )
+				continue;
+			
+			const QString field = attr.tagName();
+			const QString value = attr.firstChild().toText().data();
+			
+			//qDebug("\t%s = %s;", qPrintable(field), qPrintable(value));
+			
+			const bool flag = (value == "true") || value.toUInt();
+			
+			if ( field == "id" )
+			{
+				t.id = value;
+			} else if ( field == "user" ) {
+				t.user = flag;
+			} else if ( field == "focus" ) {
+				t.focus = flag;
+			} else if ( field == "icon" ) {
+				t.icon = QPixmap(value);
+			} else if ( field == "color" ) {
+				//t.color = QColor(value);
+				
+				/*
+					color value MUST be a valid value for QColor::setNamedColor()
+					with one exception though : an alpha channel indication (unsupported
+					by QColor::setNamedColor()) can be prepended using '@' followed by a
+					sequence of hex digits (preferabily two of them...)
+					
+					examples :
+						#ff0c80
+						#ff0c80@80
+						blue
+						blue@10
+				*/
+				
+				if ( value.contains('@') )
+				{
+					t.color = QColor(value.section('@', 0, 0, QString::SectionSkipEmpty));
+					t.color.setAlpha(value.section('@', 1, 1, QString::SectionSkipEmpty).toUInt(0, 16));
+				} else {
+					t.color = QColor(value);
+				}
+			} else if ( field == "priority" ) {
+				t.priority = value.toUInt();
+			} else if ( field == "persistency" ) {
+				t.persistency = value.toUInt();
+			} else if ( field == "rule" ) {
+				t.rules << value;
+			}
+			
+		}
+		
+		m_lineMarkTypes << t;
+		
+		//qDebug("};");
+	}
+}
+
+/*!
+	\brief int -> string mark type identifier conversion
+*/
+QString QLineMarksInfoCenter::markTypeId(int id)
+{
+	return ((id >= 0) && (id < m_lineMarkTypes.count())) ? m_lineMarkTypes.at(id).id : QString();
+}
+
+/*!
+	\brief string -> int mark type identifier conversion
+*/
+int QLineMarksInfoCenter::markTypeId(const QString& id)
+{
+	for ( int idx = 0; idx < m_lineMarkTypes.count(); ++idx )
+		if ( m_lineMarkTypes.at(idx).id == id )
+			return idx;
+	
+	return -1;
+}
+
+/*!
+	\return The mark type definition associated with a given id
+*/
+QLineMarkType QLineMarksInfoCenter::markType(int id)
+{
+	return ((id >= 0) && (id < m_lineMarkTypes.count())) ? m_lineMarkTypes.at(id) : QLineMarkType();
+}
+
+/*!
+	\return the mark type definition associated with a given id
+*/
+QLineMarkType QLineMarksInfoCenter::markType(const QString& id)
+{
+	foreach ( QLineMarkType t, m_lineMarkTypes )
+		if ( t.id == id )
+			return t;
+	
+	return QLineMarkType();
+}
+
+/*!
+	\return A list of available mark types
+	\param context context filter (no filtering is performed if empty)
+*/
+QStringList QLineMarksInfoCenter::availableMarkTypes(const QString& context)
+{
+	QStringList l;
+	
+	foreach ( QLineMarkType t, m_lineMarkTypes )
+	{
+		if (
+				context.count()
+			&&
+				(
+					!t.user
+				||
+					(
+						t.rules.contains("#out")
+					&&
+						!t.rules.contains(context)
+					)
+				||
+					(
+						t.rules.contains("#in")
+					&&
+						t.rules.contains("!" + context)
+					)
+				)
+			)
+		{
+			//qDebug("mark[%s] mismatched", qPrintable(t.id));
+		} else {
+			l << t.id;
+		}
+	}
+	
+	return l;
+}
+
+/*!
+	\return the mark that has the highest priority among a list of marks
+*/
+int QLineMarksInfoCenter::priority(const QList<int>& marks)
+{
+	int higher = -1;
+	int mark = marks.isEmpty() ? -1 : marks.at(0);
+	
+	for ( int i = 0; i < m_lineMarkTypes.count(); ++i )
+	{
+		if ( marks.contains(i) && (m_lineMarkTypes.at(i).priority > higher) )
+		{
+			mark = i;
+			higher = m_lineMarkTypes.at(i).priority;
+		}
+	}
+	
+	return mark;
+}
+
+/*!
+	\return the mark that has the highest priority among a list of marks
+*/
+QString QLineMarksInfoCenter::priority(const QStringList& marks)
+{
+	QString mark;
+	int higher = -1;
+	
+	foreach ( QLineMarkType t, m_lineMarkTypes )
+	{
+		if ( marks.contains(t.id) && (t.priority > higher) )
+		{
+			mark = t.id;
+			higher = t.priority;
+		}
+	}
+	
+	return (mark.count() || !marks.count()) ? mark : marks.at(0);
+}
+
+/*!
+	\brief Useless for now
+*/
+QList<QStringList> QLineMarksInfoCenter::marksLayout(const QString& context)
+{
+	QList<QStringList> l;
+	
+	
+	foreach ( QString id, availableMarkTypes(context) )
+	{
+		l << QStringList(id);
+	}
+	
+	/*
+	foreach ( QLineMarkType t, availableMarks(context) )
+	{
+		
+	}
+	*/
+	
+	return l;
+}
+
+/*!
+	\internal
+*/
+void QLineMarksInfoCenter::cursorMoved(QEditor *e)
+{
+	foreach ( const QLineMarkHandle& lmh, m_lineMarks )
+	{
+		QLineMarkType t = markType(lmh.mark);
+		
+		if (
+				(e->fileName() != lmh.file)
+			||
+				(e->document() != lmh.line->document())
+			||
+				(t.persistency == 2)
+			)
+			continue;
+		
+		if ( !t.persistency || (lmh.line != e->cursor().line().handle()) )
+		{
+			removeLineMark(lmh);
+			cursorMoved(e);
+			break;
+		}
+	}
+}
+
+/*!
+	\internal
+*/
+void QLineMarksInfoCenter::lineDeleted(QDocumentLineHandle *h)
+{
+	QLineMarkHandleList::iterator i = m_lineMarks.begin();
+	
+	while ( i != m_lineMarks.end() )
+	{
+		if ( i->line == h )
+		{
+			QLineMark mrk(i->file, i->line->line() + 1, i->mark);
+			
+			i = m_lineMarks.erase(i);
+			
+			emit lineMarkRemoved(mrk);
+		} else {
+			++i;
+		}
+	}
+}
+
+/*!
+	\brief Entry point for changes in documents
+	
+	Every document notify through this function a change in its line marks...
+*/
+void QLineMarksInfoCenter::markChanged(const QString& f, QDocumentLineHandle *line, int mark, bool on)
+{
+	QLineMarkHandle m(f, line, mark);
+	bool in = m_lineMarks.contains(m);
+	QLineMark mrk(f, line->line() + 1, mark);
+	
+	if ( !on && in )
+	{
+		m_lineMarks.removeAll(m);
+		
+		emit lineMarkRemoved(mrk);
+	} else if ( on && !in ) {
+		m_lineMarks << m;
+		
+		emit lineMarkAdded(mrk);
+	}
+	
+	/*
+	foreach ( const QLineMarkHandle& h, m_lineMarks )
+	{
+		qDebug("\t%s:%i [%i]", qPrintable(h.file), h.line->line() + 1, h.mark);
+	}
+	*/
+}
+
+/*! @} */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qlinemarksinfocenter.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QLINE_MARKS_INFO_CENTER_H_
+#define _QLINE_MARKS_INFO_CENTER_H_
+
+/*!
+	\file qlinemarksinfocenter.h
+	\brief Definition of the QLineMarksInfoCenter class.
+	
+	\see QLineMarksInfoCenter
+*/
+
+/*!
+	\defgroup language Language framework
+*/
+
+#include "qce-config.h"
+
+#include <QColor>
+#include <QPixmap>
+#include <QObject>
+#include <QMetaType>
+#include <QStringList>
+
+class QEditor;
+class QDataStream;
+class QDocumentLineHandle;
+
+struct QLineMark
+{
+	inline QLineMark() : line(-1) {}
+	
+	inline QLineMark(const QString& f, int l, int m)
+	 : mark(m), line(l), file(f)
+	{}
+	
+	inline bool operator == (const QLineMark& m)
+	{ return (line == m.line) && (file == m.file) && (mark == m.mark); }
+	
+	inline bool operator != (const QLineMark& m)
+	{ return (line != m.line) || (file != m.file) || (mark != m.mark); }
+	
+	int mark;
+	int line;
+	QString file;
+};
+
+Q_DECLARE_METATYPE(QLineMark)
+
+typedef QList<QLineMark> QLineMarkList;
+
+Q_DECLARE_TYPEINFO(QLineMark, Q_MOVABLE_TYPE);
+
+struct QLineMarkHandle
+{
+	inline QLineMarkHandle() : line(0) {}
+	
+	inline QLineMarkHandle(const QString& f, QDocumentLineHandle *l, int m)
+	 : mark(m), line(l), file(f)
+	{}
+	
+	inline bool operator == (const QLineMarkHandle& m)
+	{ return (line == m.line) && (file == m.file) && (mark == m.mark); }
+	
+	inline bool operator != (const QLineMarkHandle& m)
+	{ return (line != m.line) || (file != m.file) || (mark != m.mark); }
+	
+	int mark;
+	QDocumentLineHandle *line;
+	QString file;
+};
+
+Q_DECLARE_METATYPE(QLineMarkHandle)
+
+typedef QList<QLineMarkHandle> QLineMarkHandleList;
+
+Q_DECLARE_TYPEINFO(QLineMarkHandle, Q_MOVABLE_TYPE);
+
+QCE_EXPORT QDataStream& operator >> (QDataStream& d, QLineMark& m);
+QCE_EXPORT QDataStream& operator << (QDataStream& d, const QLineMark& m);
+
+struct QLineMarkType
+{
+	inline QLineMarkType()
+	 : user(false), focus(false), priority(-1), persistency(0)
+	{}
+	
+	bool user;
+	bool focus;
+	QString id;
+	QPixmap icon;
+	QColor color;
+	int priority;
+	int persistency;
+	QStringList rules;
+};
+
+Q_DECLARE_METATYPE(QLineMarkType)
+
+typedef QList<QLineMarkType> QLineMarkTypeList;
+
+Q_DECLARE_TYPEINFO(QLineMarkType, Q_MOVABLE_TYPE);
+
+class QCE_EXPORT QLineMarksInfoCenter : public QObject
+{
+	friend class QEditor;
+	friend class QCodeEdit;
+	
+	Q_OBJECT
+	
+	public:
+		static QLineMarksInfoCenter* instance();
+		static void destroy();
+		
+		QLineMarkList marks(const QString& file = QString());
+		
+		QString markTypeId(int id);
+		int markTypeId(const QString& id);
+		
+		QLineMarkType markType(int id);
+		QLineMarkType markType(const QString& id);
+		
+		int priority(const QList<int>& marks);
+		QString priority(const QStringList& marks);
+		
+		QStringList availableMarkTypes(const QString& context = QString());
+		QList<QStringList> marksLayout(const QString& context = QString());
+		
+	public slots:
+		void loadMarks(const QString& f);
+		void saveMarks(const QString& f);
+		
+		void loadMarkTypes(const QString& f);
+		
+		void clear();
+		
+		void removeMarks(const QString& file);
+		
+		void addLineMark(const QLineMark& mark);
+		void toggleLineMark(const QLineMark& mark);
+		void removeLineMark(const QLineMark& mark);
+		
+		void addLineMark(const QLineMarkHandle& mark);
+		void toggleLineMark(const QLineMarkHandle& mark);
+		void removeLineMark(const QLineMarkHandle& mark);
+		
+		void flush(const QString& file);
+		
+	signals:
+		void lineMarkAdded(const QLineMark& mark);
+		void lineMarkRemoved(const QLineMark& mark);
+		
+	protected:
+		QLineMarksInfoCenter();
+		virtual ~QLineMarksInfoCenter();
+		
+	protected slots:
+		void cursorMoved(QEditor *e);
+		void lineDeleted(QDocumentLineHandle *h);
+		void markChanged(const QString& f, QDocumentLineHandle *h, int mark, bool on);
+		
+	private:
+		QLineMarkList m_delayed;
+		QLineMarkHandleList m_lineMarks;
+		QLineMarkTypeList m_lineMarkTypes;
+		
+		static QLineMarksInfoCenter *m_instance;
+};
+
+#endif // !_QLINE_MARKS_INFO_CENTER_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qnfa/light_vector.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _LIGHT_VECTOR_H_
+#define _LIGHT_VECTOR_H_
+
+#include <qglobal.h>
+
+/*!
+	\file light_vector.h
+	\brief Definition of the light_vector class
+*/
+
+template <typename T>
+class light_vector
+{
+	public:
+		light_vector() : m_data(0), size(0) {}
+		~light_vector() { free(m_data); }
+		
+		light_vector& operator = (const light_vector& o)
+		{
+			size = o.size;
+			m_data = o.m_data;
+			
+			return *this;
+		}
+		
+		light_vector& operator << (const T& v)
+		{
+			append(v);
+			
+			return *this;
+		}
+		
+		inline quint16 length() const
+		{ return size; }
+		
+		inline quint16 count() const
+		{ return size; }
+		
+		inline T* data()
+		{ return m_data; }
+		
+		void alloc(int pos, size_t n)
+		{
+			size += n;
+			m_data = !m_data ? (T*)malloc(size * sizeof(T)) : (T*)realloc(m_data, size * sizeof(T));
+			
+			for ( int i = size - 1; (i > pos) && (i >= (int)n); --i )
+				m_data[i] = m_data[i - n];
+			
+			//for ( int i = pos; (i < (pos + n)) && ((i + n) < size); ++i )
+			//	m_data[i + n] = m_data[i];
+			
+		}
+		
+		inline void prepend(const T& v)
+		{
+			insert(0, v);
+		}
+		
+		void insert(int i, const T& v)
+		{
+			i = qBound(0, i, (int)size);
+			
+			alloc(i, 1);
+			m_data[i] = v;
+		}
+		
+		void append(const T& v)
+		{
+			++size;
+			m_data = !m_data ? (T*)malloc(size * sizeof(T)) : (T*)realloc(m_data, size * sizeof(T));
+			m_data[size - 1] = v;
+		}
+		
+		inline const T& at(quint16 i)
+		{
+			return *(m_data + i);
+		}
+		
+		inline T& operator [] (quint16 i)
+		{
+			return *(m_data + i);
+		}
+		
+		bool contains(const T& v) const
+		{
+			for ( int i = 0; i < size; i++ )
+				if ( m_data[i] == v )
+					return true;
+			
+			return false;
+		}
+		
+	private:
+		T* m_data;
+		quint16 size;
+};
+
+#endif // _LIGHT_VECTOR_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qnfa/qnfa.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,1039 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qnfa.h"
+
+/*!
+	\file qnfa.cpp
+	\brief Implementation of the core QNFA syntax engine
+*/
+
+#include <QHash>
+#include <QList>
+
+quint32 QNFA::_count = 0;
+static QList<QNFA*> _deleted;
+
+QNFA::QNFA()
+ : type(Char), assertion(0), actionid(0)
+{
+	out.next = 0;
+	
+	++_count;
+	
+	//qDebug("alloc(0x%x) => QNFA syntax[%i];", this, _count);
+}
+
+QNFA::~QNFA()
+{
+	--_count;
+	
+	// some nfa nodes are shared... gotta make sure they are free'd once only
+	_deleted << this;
+	
+	//qDebug("free(0x%x) => QNFA syntax[%i];", this, _count);
+	
+	tree.clear();
+	
+	if ( (type & CxtBeg) && out.branch )
+	{
+		delete out.branch;
+		out.branch = 0;
+	}
+	
+	if ( out.next && !_deleted.contains(out.next) )
+	{
+		delete out.next;
+		out.next = 0;
+	}
+}
+
+
+QNFABranch::~QNFABranch()
+{
+	//qDebug("branch to %i nodes", count());
+	for ( int i = 0; i < count(); ++i )
+	{
+		if ( at(i) && !_deleted.contains(at(i)) )
+		{
+			delete (*this)[i];
+			(*this)[i] = 0;
+		}
+	}
+}
+
+inline bool isWord(QChar c)
+{ return c.isLetterOrNumber() || (c.unicode() == '_'); }
+
+static bool match(QChar cc, QNFA *chain)
+{
+	bool found = true;
+	quint16 cu = cc.unicode();
+	bool notEmpty = chain->c.count();
+	
+	if ( notEmpty && (chain->c.at(0) == '\0') )
+		found = false;
+	
+	if ( notEmpty )
+		if ( chain->c.contains(cu) )
+			return found;
+	
+	int ass = chain->assertion;
+	
+	if ( ass )
+	{
+		if ( cc.isDigit() )
+		{
+			if ( ass & Digit )
+				return found;
+		} else {
+			if ( ass & NonDigit )
+				return found;
+			
+			if ( cc.isSpace() )
+			{
+				if ( ass & Space )
+					return found;
+			} else {
+				if ( ass & NonSpace )
+					return found;
+				
+				if ( cc.isLetterOrNumber() || (cu == '_') )
+				{
+					if ( ass & Word )
+						return found;
+				} else {
+					if ( ass & NonWord )
+						return found;
+				}
+			}
+		}
+	}
+	
+	return !found;
+}
+
+void match(QNFAMatchContext *lexer, const QChar *d, int length, QNFAMatchNotifier notify)
+{
+	if ( !lexer || !lexer->context )
+	{
+		//qWarning("get off you scum!");
+		return;
+	}
+	
+	// restore message buffering
+	
+	notify.clear();
+	
+	int olvls = lexer->parents.count(),
+		nlvls = 0,
+		lvls = olvls;
+	
+	if ( lvls )
+		notify.startBuffering();
+	
+	//
+	
+	quint16 c = 0;
+	const QChar *di = d;
+	QNFA *chain = 0, *start = 0;
+	int index = 0, lastCxt = 0, len, idx;
+	bool bFound, bEscape = false, bEscaped = false;
+	bool wPrev = false, wCur = false;
+	
+	while ( index < length )
+	{
+		bFound = false;
+		bEscaped = false;
+		//bEscape &= !lexer->meaningless.contains(d[index].unicode());
+		
+		//while ( lexer->meaningless.contains(d[index].unicode()) && ((index + 1) < length) )
+		//	++index;
+		
+		if ( index >= length )
+			break;
+		
+		c = di->unicode();
+		
+		wCur = isWord(*di);
+
+		int plainIndex = -1, plainMatch, plainLength;
+		
+		// try fast plain matching
+		if ( !(wPrev && wCur) )
+		{
+			//qDebug("trying plain...");
+			
+			//len = 0;
+			idx = index;
+			QCharTree::const_iterator it, match, end;
+			
+			it = lexer->context->tree.constFind(c);
+			
+			if ( it != lexer->context->tree.constEnd() )
+			{
+				//qDebug("plain on %c", c);
+				do
+				{
+					++di;
+					++idx;
+					
+					end = it->next.constEnd();
+					match = it->next.constFind(0);
+					
+					if ( idx < length )
+					{
+						c = di->unicode();
+						it = it->next.constFind(c);
+					} else {
+						it = end;
+					}
+					
+					if ( it == end )
+					{
+						if ( (match != end) && !isWord(*di) )
+						{
+							//word boundary found
+							// corresponding token end found
+							wPrev = isWord(*(di - 1));
+							bFound = true;
+							if ( match->value.action & 0x40000000 )
+							{
+								// try regexps before notifying
+								plainIndex = index;
+								plainLength = idx - index;
+								plainMatch = match->value.action;
+								//qDebug("ambiguity.");
+							} else {
+								notify(index, idx - index, match->value.action);
+								index = idx;
+							}
+							//qDebug("next step : %c", d[index].toLatin1());
+							//bMonitor = true;
+						}
+						
+						break;
+					}
+				} while ( idx < length ) ;
+				
+				if ( bFound )
+				{
+					bEscape = false;
+
+					if ( plainIndex == -1 )
+						continue;
+					
+					bFound = false;
+				}
+
+				di -= idx - index;
+			}
+		}
+		
+		// fallback on regexp-like NFA-based matching
+		QNFABranch* children = lexer->context->out.branch;
+		
+		if ( children )
+		{
+			//qDebug("trying %i sub nfas on %c", children->count(), d[index].toLatin1());
+			int max = children->count();
+			
+			for ( quint16 i = 0; i < max; ++i )
+			{
+				len = 0;
+				idx = index;
+				start = chain = children->at(i);
+				
+				//qDebug("%ith attempt on %c", i, d[index + len].toLatin1());
+				
+				while ( (idx < length) || (chain->type & Match) )
+				{
+					bEscaped = false;
+					
+					if ( chain->type & Match )
+					{
+						if (
+								(chain->assertion & WordEnd)
+							&&
+								(idx < length)
+							&&
+								isWord(*di)
+							&&
+								isWord(*(di - 1))
+							)
+						{
+							//qDebug("end assertion failed...");
+							break;
+						}
+						
+						//qDebug("matched to end");
+						
+						if ( chain->type & CxtBeg )
+						{
+							//qDebug("entering context : 0x%x", chain);
+							
+							++nlvls;
+							
+							bool notifySub = notify.bufferLevel();
+							
+							if ( notifySub )
+							{
+								// pop one message buffer
+								notify.stopBuffering();
+							}
+							
+							// notify content of previous context until nest
+							notify(lastCxt, index - lastCxt, lexer->context->actionid | 0x80000000);
+							
+							if ( notifySub )
+							{
+								// notify sub matches so far to avoid tricky handling later on
+								notify.flush();
+								
+								//notify.startBuffering();
+							}
+							
+							// notify begin marker
+							notify(index, len, start->actionid ? start->actionid : chain->actionid);
+							
+							// update context stack
+							lexer->parents.push(lexer->context);
+							lexer->context = chain;
+							
+							// update nest index
+							lastCxt = idx;
+							
+							// push a message buffer
+							notify.startBuffering();
+							
+						} else if ( chain->type & CxtEnd ) {
+							//qDebug("leaving context :");
+							
+							if ( lexer->parents.isEmpty() )
+								qFatal("context nesting problem");
+							
+							if ( bEscape )
+							{
+								// not really end : escape found...
+								
+								bEscape = false;
+								bEscaped = true;
+							} else {
+								
+								if ( nlvls )
+									--nlvls;
+								else
+									--lvls;
+								
+								// pop one message buffer
+								notify.stopBuffering();
+								
+								// notify context content from last nest
+								notify(lastCxt, index - lastCxt, lexer->context->actionid | 0x80000000);
+								
+								// flush sub matches
+								notify.flush();
+								
+								// update context stack
+								lexer->context = lexer->parents.pop();
+								
+								if ( lexer->parents.count() )
+									notify.startBuffering();
+								
+								// update nest index
+								lastCxt = idx;
+								
+								// notify end marker
+								notify(index, len, chain->actionid);
+								
+								//qDebug("cxt notif...");
+								
+								if ( chain->type & Exclusive )
+									index = idx;
+								
+								--index;
+								--di;
+								
+								bFound = true;
+								break;
+							}
+						} else if ( chain->type & CxtEsc )  {
+							//qDebug("matched %s", qPrintable(QString(index, len)));
+							
+							//notify(index, len, chain->actionid);
+							bEscape = !bEscape;
+						} else {
+							//qDebug("matched %s", qPrintable(QString(d + index, len)));
+							
+							if ( plainIndex != -1 && plainLength >= len )
+							{
+								break;
+							}
+							
+							notify(index, len, chain->actionid);
+							bEscape = false;
+						}
+						
+						bFound = true;
+						index = idx;
+						--index;
+						--di;
+						
+						//qDebug("next step : %c", d[index + 1].toLatin1());
+						//bMonitor = true;
+						
+						break;
+					} else {
+						// "regular" nfa match (no match yet...)
+						
+						if (
+								(chain->assertion & WordStart)
+							&&
+								(idx >= 1)
+							&&
+								(
+									isWord(*(di - 1))
+								&&
+									isWord(*di)
+								)
+							)
+						{
+							//qDebug("beg assertion failed...");
+							
+							break;
+						}
+						
+						QChar cc = *di;
+						bool found = match(cc, chain);
+						
+						if (
+								!(chain->assertion & ZeroOrOne)
+							&&
+								!(chain->assertion & ZeroOrMore)
+							&&
+								!found
+							)
+						{
+							//if ( cc.toLatin1() == ')' )
+							//	qDebug("mismatch : %c != %c", cc.toLatin1(), chain->c.at(0));
+							
+							break;
+						}
+						
+						if ( found )
+						{
+							//qDebug("%c", d[index + len].toLatin1());
+							
+							if (
+									(chain->assertion & OneOrMore)
+								||
+									(chain->assertion & ZeroOrMore)
+								)
+							{
+								do
+								{
+									++di;
+									++len;
+									++idx;
+								} while (
+											(idx < length)
+										&&
+											match(*di, chain)
+										);
+								
+							} else {
+								++len;
+								++idx;
+								++di;
+							}
+							
+						} else {
+							//qDebug("! %c", d[index + len].toLatin1());
+						}
+						
+						chain = chain->out.next;
+					}
+				}
+				
+				if ( bFound )
+					break;
+				
+				di -= len;
+			}
+		}
+		
+		if ( !bFound )
+		{
+			if ( plainIndex != -1 )
+			{
+				notify(plainIndex, plainLength, plainMatch);
+				index = plainIndex + plainLength;
+				di += plainLength;
+				continue;
+			}
+
+			bEscape = false;
+			//++index;
+			wPrev = wCur;
+		} else {
+			wPrev = isWord(*di);
+		}
+		
+		++index;
+		++di;
+	}
+	
+	// flush messages
+	
+	if ( !notify.bufferLevel() )
+		return;
+	
+	//qDebug("%i context nests", notify.bufferLevel());
+	//qDebug("[%i;+00[ : 0x%x", lastCxt, lexer->context->actionid | 0x80000000);
+	
+	// pop down one buffer
+	notify.stopBuffering();
+	
+	// notify overlapping context so far
+	notify(lastCxt, length - lastCxt, lexer->context->actionid | 0x80000000);
+	
+	// notify sub matches
+	notify.flush();
+	
+	// make sure we leave a blank notifier...
+	notify.clear();
+	
+	// preserve escape power...
+	if ( bEscaped )
+		return;
+	
+	// some existing left AND new one(s)
+	if ( (olvls == lvls) && nlvls )
+		++lvls;
+	
+	// close stay-on-line contexts, if any
+	QStack<QNFA*>::iterator it = lexer->parents.begin() + lvls;
+	
+	while ( it != lexer->parents.end() )
+	{
+		if ( (*it)->type & StayOnLine )
+		{
+			//qDebug("staid...");
+			it = lexer->parents.erase(it);
+		} else {
+			++it;
+		}
+	}
+	
+	if ( (lexer->context->type & StayOnLine) && nlvls && lexer->parents.count() )
+		lexer->context = lexer->parents.pop();
+	
+}
+
+QNFA* lexer()
+{
+	QNFA *lex = new QNFA;
+	
+	lex->type = ContextBegin;
+	lex->out.branch = new QNFABranch;
+	
+	return lex;
+}
+
+QNFA* sharedContext(const QString& start, QNFA *other, bool cs)
+{
+	QNFA *nfa, *end, *beg = sequence(start.constData(), start.length(), &end, cs);
+	
+	nfa = new QNFA;
+	nfa->type = ContextBegin;
+	nfa->out.branch = other->out.branch;
+	
+	end->out.next = nfa;
+	
+	return beg;
+}
+
+QNFA* context(const QString& start, const QString& stop, const QString&, int action, QNFA **handler, bool cs)
+{
+	QNFA *nfa, *end, *beg = sequence(start.constData(), start.length(), &end, cs);
+	
+	nfa = new QNFA;
+	nfa->type = ContextBegin;
+	nfa->actionid = action;
+	nfa->out.branch = new QNFABranch;
+	
+	if ( handler )
+		*handler = nfa;
+	//else
+	//	qDebug("no handler set [0x%x]", nfa);
+	
+	end->out.next = nfa;
+	end = nfa;
+	
+	QNFA *endmark, *begendmark = sequence(stop.constData(), stop.length(), &endmark, cs);
+	
+	nfa = new QNFA;
+	nfa->type = ContextEnd;
+	nfa->actionid = action;
+	
+	endmark->out.next = nfa;
+	
+	//end->out->branch->append(endmark);
+	addNFA(end, begendmark);
+	
+	return beg;
+}
+
+void addWord(QNFA *lexer, const QString& w, int action, bool cs)
+{
+	if ( !lexer || !(lexer->type & CxtBeg) || !lexer->out.branch )
+		return;
+	
+	// try using the fastest way if possible
+	
+	QString pt;
+	
+	if ( plain(w, &pt) && cs )
+	{
+		addWord(lexer->tree, pt, action, cs);
+		return;
+	}
+	
+	// fallback on (fast) regexp-like NFA-based semi-compiled parsing
+	QNFA *nfa, *word, *end;
+	
+	word = sequence(w.constData(), w.length(), &end, cs);
+	word->assertion |= WordStart;
+	
+	nfa = new QNFA;
+	nfa->type = Match;
+	nfa->assertion = WordEnd;
+	nfa->actionid = action;
+	
+	end->out.next = nfa;
+	
+	//lexer->out.branch->append(word);
+	addNFA(lexer, word);
+}
+
+void addSequence(QNFA *lexer, const QString& w, int action, bool cs)
+{
+	if ( !lexer || !(lexer->type & CxtBeg) || !lexer->out.branch )
+	{
+		return;
+	}
+	
+	QNFA *seq, *end, *nfa;
+	
+	seq = sequence(w.constData(), w.length(), &end, cs);
+	
+	nfa = new QNFA;
+	nfa->type = Match;
+	nfa->actionid = action;
+	
+	end->out.next = nfa;
+	
+	//lexer->out.branch->append(seq);
+	addNFA(lexer, seq);
+}
+
+QNFA* sequence(const QChar *d, int length, QNFA **end, bool cs)
+{
+	QNFA *nfa, *set = 0, *prev = 0, *first = 0;
+	
+	for ( int i = 0; i < length; ++i )
+	{
+		QChar c = d[i];
+		
+		if ( c == QLatin1Char('\\') )
+		{
+			c = d[++i];
+			
+			if ( c == QLatin1Char('n') )
+			{
+				c = '\n';
+			} else if ( c == QLatin1Char('t') ) {
+				c = '\t';
+			} else if ( c == QLatin1Char('r') ) {
+				c = '\r';
+			}
+			
+			if ( set )
+			{
+				set->c << c.unicode();
+			} else {
+				nfa = new QNFA;
+				nfa->c << c.unicode();
+				
+				if ( prev )
+					prev->out.next = nfa;
+				
+				prev = nfa;
+			}
+		} else if ( c == QLatin1Char('$') ) {
+			// char classes
+			c = d[++i];
+			
+			if ( set )
+			{
+				if ( c == QLatin1Char('s') )
+					set->assertion |= Space;
+				else if ( c == QLatin1Char('S') )
+					set->assertion |= NonSpace;
+				else if ( c == QLatin1Char('d') )
+					set->assertion |= Digit;
+				else if ( c == QLatin1Char('D') )
+					set->assertion |= NonDigit;
+				else if ( c == QLatin1Char('w') )
+					set->assertion |= Word;
+				else if ( c == QLatin1Char('W') )
+					set->assertion |= NonWord;
+				else
+					set->c << QLatin1Char('$').unicode() << c.unicode();
+				
+			} else {
+				nfa = new QNFA;
+				
+				if ( c == QLatin1Char('s') )
+					nfa->assertion |= Space;
+				else if ( c == QLatin1Char('S') )
+					nfa->assertion |= NonSpace;
+				else if ( c == QLatin1Char('d') )
+					nfa->assertion |= Digit;
+				else if ( c == QLatin1Char('D') )
+					nfa->assertion |= NonDigit;
+				else if ( c == QLatin1Char('w') )
+					nfa->assertion |= Word;
+				else if ( c == QLatin1Char('W') )
+					nfa->assertion |= NonWord;
+				else {
+					nfa->c << QLatin1Char('$').unicode();
+					--i;
+				}
+				
+				if ( prev )
+					prev->out.next = nfa;
+				
+				prev = nfa;
+			}
+		} else if ( c == QLatin1Char('[') ) {
+			
+			if ( set )
+			{
+				set->c << c.unicode();
+				//	qWarning("Nested sets are not supported (and useless BTW)...");
+				continue;
+			}
+			
+			// enter set...
+			
+			set = new QNFA;
+			
+			//qDebug("set start");
+			
+		} else if ( c == QLatin1Char(']') ) {
+			
+			if ( !set )
+			{
+				qWarning("Unmatched set closing marker");
+				continue;
+			}
+			
+			// leave set...
+			
+			if ( prev )
+				prev->out.next = set;
+			
+			prev = set;
+			set = 0;
+			
+			//qDebug("set end");
+			/*
+		} else if ( c == QLatin1Char('(') ) {
+			// allow trivial groups
+			
+			QList<int> cuts;
+			int idx = i, nest = 1;
+			
+			while ( nest && (++idx < length) )
+			{
+				if ( d[idx] == '\\' )
+				{
+					++idx;
+					continue;
+				} else if ( d[idx] == '(' ) {
+					++nest;
+				} else if ( d[idx] == ')' ) {
+					--nest;
+				} else if ( (nest == 1) && (d[idx] == '|') ) {
+					cuts << idx;
+				} else if ( d[idx] == '[' ) {
+					while ( ++idx < length )
+					{
+						if ( d[idx] == '\\' )
+						{
+							++idx;
+							continue;
+						} else if ( d[idx] == ']' ) {
+							break;
+						}
+					}
+				}
+			}
+			
+			*/
+		} else if ( set ) {
+			
+			if ( (c == QLatin1Char('^')) && !set->c.count() )
+			{
+				set->c << '\0';
+				continue;
+			}
+			
+			quint16 prev = set->c.count() ? set->c.at(set->c.length() - 1) : '\0';
+			
+			if ( (c == '-') && (prev != '\0') && ((i + 1) < length) )
+			{
+				quint16 cse = d[++i].unicode();
+				
+				for ( quint16 csi = prev + 1; csi <= cse; ++csi )
+				{
+					QChar csc(csi);
+					
+					if ( c.isLetter() && !cs )
+						set->c << c.toLower().unicode() << c.toUpper().unicode();
+					else
+						set->c << csi;
+				}
+			} else {
+				if ( c.isLetter() && !cs )
+					set->c << c.toLower().unicode() << c.toUpper().unicode();
+				else
+					set->c << c.unicode();
+			}
+			//qDebug("set << %c", c.toLatin1());
+			
+		} else if ( c == QLatin1Char('+') ) {
+			if ( prev ) prev->assertion |= OneOrMore;
+		} else if ( c == QLatin1Char('*') ) {
+			if ( prev ) prev->assertion |= ZeroOrMore;
+		} else if ( c == QLatin1Char('?') ) {
+			if ( prev ) prev->assertion |= ZeroOrOne;
+		} else {
+			nfa = new QNFA;
+			
+			if ( c.isLetter() && !cs )
+			{
+				nfa->c << c.toLower().unicode() << c.toUpper().unicode();
+			} else {
+				nfa->c << c.unicode();
+			}
+			
+			if ( prev )
+				prev->out.next = nfa;
+			
+			prev = nfa;
+		}
+		
+		if ( !first )
+			first = prev;
+	}
+	
+	if ( end )
+	{
+		*end = prev;
+	}
+	
+	return first;
+}
+
+bool plain(const QString& word, QString *dest)
+{
+	if ( dest )
+		dest->clear();
+	
+	for ( int i = 0; i < word.length(); i++ )
+	{
+		QChar c = word.at(i);
+		
+		if ( c == QLatin1Char('\\') )
+		{
+			if ( dest && ((i + 1) < word.length()) )
+			{
+				c = word.at(++i);
+				
+				if ( c == QLatin1Char('n') )
+					dest->append('\n');
+				else if ( c == QLatin1Char('t') )
+					dest->append('\t');
+				else if ( c == QLatin1Char('r') )
+					dest->append('\r');
+				else
+					dest->append(c);
+			}
+		} else if (
+						c == QLatin1Char('[')
+					||
+						c == QLatin1Char(']')
+					||
+						c == QLatin1Char('+')
+					||
+						c == QLatin1Char('*')
+					||
+						c == QLatin1Char('?')
+					||
+						c == QLatin1Char('$')
+					)
+		{
+			if ( dest )
+				dest->clear();
+			
+			return false;
+		} else {
+			
+			if ( dest )
+				dest->append(c);
+			
+		}
+	}
+	
+	return true;
+}
+
+void addWord(QCharTree& tree, const QString& w, int action, bool cs)
+{
+	//qDebug("Adding word to char tree : %s", qPrintable(w));
+	
+	if ( cs )
+	{
+		quint16 u = w.at(0).unicode();
+		QCharTree::iterator it = tree.find(u), tmp;
+		
+		if ( it == tree.end() )
+			it = tree.insert(u, QCharTreeNode(u));
+		
+		for ( int i = 1; i < w.count(); i++ )
+		{
+			u = w.at(i).unicode();
+			
+			//qDebug("char %c", w.at(i).toLatin1());
+			
+			tmp = it->next.find(u);
+			
+			if ( tmp == it->next.end() )
+				tmp = it->next.insert(u, QCharTreeNode(u));
+			
+			it = tmp;
+		}
+		
+		// add action handler
+		QCharTreeNode node;
+		node.value.action = action;
+		
+		it->next[0] = node;
+	} else if ( 0 ) {
+		QChar c = w.at(0);
+		quint16 u = c.unicode();
+		
+		QCharTree::iterator it, tmp;
+		QList<QCharTree::iterator> l, ltmp;
+		
+		if ( c.isLetter() )
+		{
+			u = c.toLower().unicode();
+			tmp = tree.find(u);
+			
+			if ( tmp == tree.end() )
+				tmp = tree.insert(u, QCharTreeNode(u));
+			
+			l << tmp;
+			
+			u = c.toUpper().unicode();
+			tmp = tree.find(u);
+			
+			if ( tmp == tree.end() )
+				tmp = tree.insert(u, QCharTreeNode(u));
+			
+			l << tmp;
+		} else {
+			tmp = tree.find(u);
+			
+			if ( tmp == tree.end() )
+				tmp = tree.insert(u, QCharTreeNode(u));
+			
+			l << tmp;
+		}
+		
+		for ( int i = 1; i < w.count(); ++i )
+		{
+			c = w.at(i);
+			QList<QChar> lc;
+			
+			if ( c.isLetter() )
+				lc << c.toLower() << c.toUpper();
+			else
+				lc << c;
+			
+			foreach ( c, lc )
+			{
+				u = c.unicode();
+				
+				foreach ( it, l )
+				{
+					tmp = it->next.find(u);
+					
+					if ( tmp == it->next.end() )
+						tmp = it->next.insert(u, QCharTreeNode(u));
+					
+					ltmp << tmp;
+				}
+			}
+			
+			l = ltmp;
+		}
+		
+		// add action handler
+		QCharTreeNode node;
+		node.value.action = action;
+		
+		foreach ( it, l )
+			it->next[0] = node;
+	}
+}
+
+void squeeze(QNFA *nfa)
+{
+	squeeze(nfa->tree);
+	
+	if ( nfa->type & Match )
+	{
+		if ( nfa->out.branch )
+			for ( int i = 0; i < nfa->out.branch->count(); ++i )
+				squeeze(nfa->out.branch->at(i));
+		
+	} else if ( nfa->out.next ) {
+		squeeze(nfa->out.next);
+	}
+}
+
+void squeeze(QCharTreeLevel& lvl)
+{
+	lvl.squeeze();
+	
+	QCharTreeLevel::iterator it = lvl.begin();
+	
+	while ( it != lvl.end() )
+		squeeze((it++)->next);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qnfa/qnfa.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,306 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _Q_NFA_H_
+#define _Q_NFA_H_
+
+/*!
+	\file qnfa.h
+	\brief Definition of the core QNFA syntax engine
+*/
+
+#include <QChar>
+#include <QList>
+#include <QHash>
+#include <QStack>
+#include <QString>
+
+#include "light_vector.h"
+
+struct QNFA;
+
+typedef light_vector<quint16> QNFASet;
+
+class QNFABranch : public light_vector<QNFA*>
+{
+	public:
+		~QNFABranch();
+};
+
+enum NFAType
+{
+	Char			= 0,
+	
+	Match			= 1,
+	
+	CxtBeg			= 2,
+	CxtEnd			= 4,
+	CxtEsc			= 8,
+	
+	ContextBegin	= Match | CxtBeg,
+	ContextEnd		= Match | CxtEnd,
+	EscapeSeq		= Match | CxtEsc,
+	
+	Escaped			= 16,
+	Exclusive		= 32,
+	StayOnLine		= 64,
+	
+	Reserved		= 128
+};
+
+enum NFAAssertion
+{
+	NoAssertion		= 0,
+	
+	One				= 0,		// default standard
+	ZeroOrOne		= 1,		// ?
+	ZeroOrMore		= 2,		// *
+	OneOrMore		= 4,		// +
+	
+	WordStart		= 8,
+	WordEnd			= 16,
+	
+	Word			= 32,
+	NonWord			= 64,
+	
+	Digit			= 128,
+	NonDigit		= 256,
+	
+	Space			= 512,
+	NonSpace		= 1024,
+	
+	CaseSensitive	= 2048
+};
+
+struct QCharTreeNode;
+
+typedef QHash<quint16, QCharTreeNode> QCharTreeLevel;
+
+struct QCharTreeNode
+{
+	inline QCharTreeNode(quint16 v = 0) { value.unicode = v; }
+	inline QCharTreeNode(const QCharTreeNode& o) { value = o.value; next = o.next; }
+	
+	union
+	{
+		int action;
+		quint16 unicode;
+	} value;
+	
+	QCharTreeLevel next;
+};
+
+Q_DECLARE_TYPEINFO(QCharTreeNode, Q_MOVABLE_TYPE);
+
+typedef QCharTreeLevel QCharTree;
+
+struct QNFA
+{
+	QNFA();
+	~QNFA();
+	
+	QNFASet c;
+	QCharTree tree;
+	
+	union
+	{
+		QNFA *next;
+		QNFABranch *branch;
+	} out;
+	
+	quint8 type;
+	quint16 assertion;
+	
+	int actionid;
+	
+	static quint32 _count;
+};
+
+struct QNFAMatchContext
+{
+	inline QNFAMatchContext(QNFA *root = 0) : context(root) {}
+	
+	inline QNFAMatchContext& operator = (QNFAMatchContext *c)
+	{
+		if ( c )
+		{
+			context = c->context;
+			parents = c->parents;
+			meaningless = c->meaningless;
+		} else {
+			reset();
+		}
+		
+		return *this;
+	}
+	
+	inline QNFAMatchContext& operator = (const QNFAMatchContext& c)
+	{
+		context = c.context;
+		parents = c.parents;
+		meaningless = c.meaningless;
+		
+		return *this;
+	}
+	
+	inline void reset()
+	{
+		context = 0;
+		
+		while ( parents.count() )
+			context = parents.pop();
+	}
+	
+	QNFA *context;
+	QNFASet meaningless;
+	QStack<QNFA*> parents;
+};
+
+class QNFAMatchHandler
+{
+	public:
+		virtual ~QNFAMatchHandler() {}
+		
+		virtual void matched(int pos, int len, int action) = 0;
+};
+
+class QNFAMatchNotifier
+{
+	private:
+		struct Command
+		{
+			inline Command(int p, int len, int act)
+			 : pos(p), length(len), action(act) {}
+			
+			int pos;
+			int length;
+			int action;
+		};
+		
+		typedef QList<Command> CommandList;
+		
+	public:
+		inline QNFAMatchNotifier(QNFAMatchHandler *h)
+		 : handler(h) {}
+		
+		inline QNFAMatchNotifier& operator = (const QNFAMatchNotifier& n)
+		{
+			handler = n.handler;
+			
+			return *this;
+		}
+		
+		inline void operator () (int pos, int len, int action)
+		{
+			if ( handler && (m_buffers.isEmpty() || m_pending.count()) )
+				handler->matched(pos, len, action);
+			else
+				m_buffers.top() << Command(pos, len, action);
+		}
+		
+		inline int bufferLevel() const
+		{
+			return m_buffers.count();
+		}
+		
+		inline void startBuffering()
+		{
+			m_buffers.push(CommandList());
+		}
+		
+		inline void stopBuffering()
+		{
+			m_pending = m_buffers.pop();
+		}
+		
+		inline void flush()
+		{
+			foreach ( Command c, m_pending )
+				handler->matched(c.pos, c.length, c.action);
+			
+			m_pending.clear();
+		}
+		
+		inline void clear()
+		{
+			m_pending.clear();
+			m_buffers.clear();
+		}
+		
+	private:
+		QNFAMatchHandler *handler;
+		
+		CommandList m_pending;
+		QStack<CommandList> m_buffers;
+};
+
+void match(			QNFAMatchContext *lexer,
+					const QChar *d,
+					int length,
+					QNFAMatchNotifier notify);
+
+inline void match(	QNFAMatchContext *lexer,
+					const QString& s,
+					QNFAMatchNotifier notify)
+{ match(lexer, s.constData(), s.length(), notify); }
+
+QNFA* lexer();
+
+void squeeze(QNFA *nfa);
+void squeeze(QCharTreeLevel& lvl);
+
+QNFA* sharedContext(const QString& start,
+					QNFA *other,
+					bool cs);
+
+QNFA* context(		const QString& start,
+					const QString& stop,
+					const QString& escape,
+					int action,
+					QNFA **handler = 0,
+					bool cs = true);
+
+inline void addNFA(QNFA *context, QNFA *nfa)
+{ context->out.branch->append(nfa); }
+
+bool plain(const QString& word, QString *dest);
+
+void addWord(		QCharTree& tree,
+					const QString& w,
+					int action,
+					bool cs);
+
+void addWord(		QNFA *lexer,
+					const QString& w,
+					int action,
+					bool cs);
+
+void addSequence(	QNFA *lexer,
+					const QString& w,
+					int action,
+					bool cs);
+
+QNFA* sequence(		const QChar *d,
+					int length,
+					QNFA **end,
+					bool cs);
+
+inline QNFA* sequence(
+					const QString& s,
+					QNFA **end,
+					bool cs)
+{ return sequence(s.constData(), s.length(), end, cs); }
+
+#endif //!_Q_NFA_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qnfa/qnfadefinition.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,1804 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qnfadefinition.h"
+
+/*!
+	\file qnfadefinition.cpp
+	\brief Implementation of the QNFADefinition class.
+*/
+
+#include "qnfa.h"
+
+#include "qformatscheme.h"
+
+#include "qlinemarksinfocenter.h"
+
+#include "qdocument.h"
+#include "qdocument_p.h"
+#include "qdocumentline.h"
+#include "qdocumentcursor.h"
+
+#include <QFile>
+#include <QKeyEvent>
+
+#include <QDomText>
+#include <QDomElement>
+#include <QDomDocument>
+
+uint qHash(const QPointer<QDocument>& p) { return qHash((QDocument*)(p)); }
+
+class QNFANotifier : public QNFAMatchHandler
+{
+	public:
+		QNFANotifier(const QString& line)
+		{
+			m_formats.fill(0, line.length());
+		}
+		
+		QNFANotifier(const QDocumentLine& line)
+		 : m_line(line)
+		{
+			m_formats.fill(0, line.length());
+		}
+		
+		~QNFANotifier()
+		{
+			if ( m_line.isValid() )
+			{
+				m_line.setFormats(m_formats);
+				m_line.setParentheses(m_parens);
+			}
+		}
+		
+		const QVector<int>& formats() const
+		{
+			return m_formats;
+		}
+		
+		const QVector<QParenthesis>& parentheses() const
+		{
+			return m_parens;
+		}
+		
+		virtual void matched(int pos, int len, int action)
+		{
+			//qDebug("action 0x%x on [%s]", action, qPrintable(m_line.text().mid(pos, len)));
+			
+			if ( !len )
+				return;
+			
+			//qDebug("matched \"%s\"", qPrintable(m_line.text().mid(pos, len)));
+			
+			if (
+					!(action & QNFAAction::Content)
+				&&
+					(
+						action
+					&
+						(
+							QNFAAction::ParenOpen
+						|
+							QNFAAction::ParenClose
+						|
+							QNFAAction::Indent
+						|
+							QNFAAction::Fold
+						)
+					)
+				)
+			{
+				//qDebug("matched paren : %s", qPrintable(m_line.text().mid(pos, len)));
+				
+				QParenthesis par(
+									(action & QNFAAction::ParenMask) >> 8,
+									0,
+									pos,
+									len
+								);
+				
+				if ( action & QNFAAction::ParenOpen )
+					par.role |= QParenthesis::Open;
+				
+				if ( action & QNFAAction::ParenClose )
+					par.role |= QParenthesis::Close;
+				
+				if ( action & QNFAAction::MatchParen )
+					par.role |= QParenthesis::Match;
+				
+				if ( action & QNFAAction::Indent )
+					par.role |= QParenthesis::Indent;
+				
+				if ( action & QNFAAction::Fold )
+					par.role |= QParenthesis::Fold;
+				
+				m_parens << par;
+			}
+			
+			if ( action & QNFAAction::Highlight )
+			{
+				int i = qMax(pos, 0);
+				int max = qMin(i + len, m_formats.count());
+				
+				while ( i < max )
+					m_formats[i++] = action & QNFAAction::FormatMask;
+			}
+		}
+		
+	private:
+		QDocumentLine m_line;
+		QVector<int> m_formats;
+		QVector<QParenthesis> m_parens;
+};
+
+extern QString *_singleLineCommentTarget;
+void embed(QNFA *src, QNFA *dest, int index);
+void fillContext(QNFA *cxt, QDomElement e, QFormatScheme *f, QHash<QString, int>& pids, bool cs);
+
+static inline bool match(const QParenthesis& open, const QParenthesis& close)
+{
+	return open.id == close.id;
+}
+
+#if 0
+class QNFAMatcher : public QMatcherInterface
+{
+	public:
+		QNFAMatcher(QNFADefinition *d, bool indent = false)
+		 : m_definition(d), m_indentFold(indent)
+		{
+		
+		}
+		
+		virtual void match(const QDocumentCursor& c, QMatcher *m)
+		{
+			//qDebug("trying to match...");
+			
+			QDocument *d = c.document();
+			QDocumentLine b = c.line();
+			
+			if ( !d || !b.isValid() )
+				return;
+			
+			int pos = c.columnNumber();
+			const QVector<QParenthesis>& m_parens = b.parentheses();
+			
+			if ( m_parens.isEmpty() )
+				return;
+			
+			QParenthesis p;
+			
+			m->clearMatches();
+			
+			foreach ( p, m_parens )
+			{
+				if ( (pos != p.offset) && (pos != (p.offset + p.length)) )
+					continue;
+				
+				int line = c.lineNumber(),
+					beg = -1,
+					end = -1,
+					beglen = 0,
+					endlen = 0;
+				
+				if (
+						(p.role & QParenthesis::Open)
+					&&
+						(p.role & QParenthesis::Match)
+					)
+				{
+					beg = p.offset;
+					beglen = p.length;
+					endlen = matchOpen(d, line, p, end);
+					
+					if ( endlen )
+						m->addMatch(c.lineNumber(), beg, beglen, line, end, endlen);
+					
+				} else if (
+								(p.role & QParenthesis::Close)
+							&&
+								(p.role & QParenthesis::Match)
+							)
+				{
+					end = p.offset;
+					endlen = p.length;
+					beglen = matchClose(d, line, p, beg);
+					
+					if ( beglen )
+						m->addMatch(line, beg, beglen, c.lineNumber(), end, endlen);
+					
+				}
+			}
+		}
+		
+		virtual QChar autoClose(QChar)
+		{
+			return QChar();
+		}
+		
+		virtual int blockFlags(int b, int depth, QMatcher *m)
+		{
+			if ( m_indentFold )
+			{
+				QDocument *d = m->document();
+				
+				QDocumentLine
+					prev = d->line(b - 1),
+					curr = d->line(b),
+					next = d->line(b + 1);
+				
+				if ( curr.hasFlag(QDocumentLine::CollapsedBlockStart) )
+					return QMatcher::Collapsed;
+				
+				int id = m_indentGuess.value(d, 0),
+					cc = curr.firstChar(),
+					pc = prev.firstChar(),
+					nc = next.firstChar();
+				
+				int k = b;
+				
+				do {
+					prev = d->line(--k);
+					pc = prev.firstChar();
+				} while ( prev.isValid() && (pc == -1) );
+				
+				k = b;
+				
+				do {
+					next = d->line(++k);
+					nc = next.firstChar();
+				} while ( next.isValid() && (nc == -1) );
+				
+				if ( !id && (depth > 0) && (pc > 0) )
+				{
+					id = pc / depth;
+					m_indentGuess[d] = id;
+				}
+				
+				if ( cc != -1 )
+				{
+					if ( nc > cc )
+						return QMatcher::Collapsible;
+					
+					if ( nc < cc )
+					{
+						if ( !id && depth )
+						{
+							id = cc / depth;
+							m_indentGuess[d] = id;
+						}
+						
+						//qDebug("cc=%i; nc=%i; id=%i => do=%i", cc, nc, id, (cc - nc) / id);
+						return QMatcher::Closure | ((cc - nc) / id);
+					}
+				}
+				/*
+				if ( (nc != cc) && (nc <= 0) && depth )
+				{
+					return QMatcher::Closure | depth;
+				}*/
+			}
+			
+			return collapseState(b, m, 0);
+		}
+		
+		int collapseState(int ln, QMatcher *m, QParenthesis *l)
+		{
+			Q_UNUSED(m)
+			
+			QDocumentLine b = m->document()->line(ln);
+			
+			if ( !b.isValid() )
+				return QMatcher::None;
+			
+			int open = 0;
+			
+			if ( b.hasFlag(QDocumentLine::CollapsedBlockStart) )
+				return QMatcher::Collapsed;
+			
+			foreach ( QParenthesis p, b.parentheses() )
+			{
+				if ( !(p.role & QParenthesis::Fold) )
+					continue;
+				
+				if ( p.role & QParenthesis::Open )
+					++open;
+				else
+					--open;
+				
+				if ( l )
+					*l = p;
+			}
+			
+			if ( open > 0 )
+				return QMatcher::Collapsible;
+			else if ( open < 0 )
+				return QMatcher::Closure | qAbs(open);
+			
+			return QMatcher::None;
+		}
+		
+		virtual void expand(int ln, QMatcher *m)
+		{
+			Q_UNUSED(m)
+			
+			QDocument *d = m->document();
+			QDocumentLine b = d->line(ln);
+			
+			if ( !b.isValid() || !b.hasFlag(QDocumentLine::CollapsedBlockStart) )
+				return;
+			
+			int depth = 1,
+				count = 1,
+				indent = b.firstChar() / m_indentGuess.value(d, 1);
+			
+			QDocumentLine l = d->line(ln + count);
+			
+			while ( l.isValid() )
+			{
+				if ( depth == 1 )
+					l.setFlag(QDocumentLine::Hidden, false);
+				
+				if ( l.hasFlag(QDocumentLine::CollapsedBlockStart) )
+				{
+					++depth;
+				} else if ( l.hasFlag(QDocumentLine::CollapsedBlockEnd) ) {
+					int flags = blockFlags(ln + count, depth + indent, m);
+					int doff = qMax(1, flags & QMatcher::DataMask);
+					
+					if ( (depth == 1) && (doff > 0) )
+						l.setFlag(QDocumentLine::CollapsedBlockEnd, false);
+					
+					depth -= doff;
+					
+					//qDebug("depth offset = %i > depth = %i", doff, depth);
+				}
+				
+				if ( depth <= 0 )
+					break;
+				
+				++count;
+				l = d->line(ln + count);
+			}
+			
+			if ( !l.isValid() )
+			{
+				--count;
+				l = d->line(ln + count);
+				l.setFlag(QDocumentLine::CollapsedBlockEnd, false);
+			}
+			
+			b.setFlag(QDocumentLine::CollapsedBlockStart, false);
+			d->impl()->showEvent(ln, count);
+			
+			d->impl()->setHeight();
+			d->impl()->emitFormatsChanged();
+		}
+		
+		virtual void collapse(int ln, QMatcher *m)
+		{
+			QDocument *d = m->document();
+			QDocumentLine b = d->line(ln);
+			
+			if ( !b.isValid() || b.hasFlag(QDocumentLine::CollapsedBlockStart) )
+				return;
+			
+			int count = 1,
+				indent = 0;
+			
+			QVector<QParenthesis> lp = b.parentheses();
+			
+			while ( lp.count() )
+			{
+				QParenthesis p = lp.first();
+				
+				if ( (p.role & QParenthesis::Open) && (p.role & QParenthesis::Fold) )
+				{
+					QParenthesis par;
+					int depth = 1, cd = 0;
+					QDocumentLine block = d->line(ln + count);
+					
+					if ( !b.isValid() )
+						return;
+					
+					while ( block.isValid() )
+					{
+						const int state = collapseState(ln + count, m, &par);
+						
+						if ( state & QMatcher::Closure )
+						{
+//							qDebug("at line %i depth fall by %i", ln + count, state & QMatcher::DataMask);
+							depth -= state & QMatcher::DataMask;
+							
+							if ( depth <= 0 )
+								break;
+							
+						} else if ( state & (QMatcher::Collapsible | QMatcher::Collapsed) ) {
+							++depth;
+						}
+						
+						++count;
+						block = d->line(ln + count);
+					}
+					
+					if ( !block.isValid() )
+					{
+						// fold to END for malformed blocks or syntax that allow it
+						
+						--count;
+						block = d->line(ln + count);
+					}
+
+					b.setFlag(QDocumentLine::CollapsedBlockStart);
+					
+					for ( int i = ln + 1; i <= ln + count; ++i )
+					{
+						d->line(i).setFlag(QDocumentLine::Hidden);
+					}
+					
+					block.setFlag(QDocumentLine::Hidden);
+					block.setFlag(QDocumentLine::CollapsedBlockEnd);
+					
+					d->impl()->hideEvent(ln, count);
+					d->impl()->setHeight();
+					
+					d->impl()->emitFormatsChanged();
+					return;
+				}
+				
+				lp.pop_front();
+			}
+			
+			
+			if ( !m_indentFold )
+				return;
+			
+			int i = ln + 1, k;
+			QDocumentLine block = d->line(i);
+			
+			if ( !block.isValid() )
+				return;
+			
+			indent = block.firstChar();
+			
+			do
+			{
+				block = d->line(++i);
+				k = block.firstChar();
+			} while ( block.isValid() && ((k >= indent) || (k == -1)) );
+			
+			if ( k < indent )
+			{
+				block = d->line(--i);
+				k = block.firstChar();
+			}
+			
+			while ( block.isValid() && (i > ln) && (k == -1) )
+			{
+				block = d->line(--i);
+				k = block.firstChar();
+			}
+			
+			b.setFlag(QDocumentLine::CollapsedBlockStart);
+			
+			//qDebug("hidding from %i to %i", ln + 1, i);
+			
+			for ( int j = ln + 1; j <= i; ++j )
+			{
+				d->line(j).setFlag(QDocumentLine::Hidden);
+			}
+			
+			d->line(i).setFlag(QDocumentLine::CollapsedBlockEnd);
+			
+			d->impl()->hideEvent(ln, i - ln);
+			d->impl()->setHeight();
+			
+			d->impl()->emitFormatsChanged();
+		}
+		
+	protected:
+		int matchOpen(QDocument *d, int& line, QParenthesis p, int& end)
+		{
+			int pos = p.offset;
+			QVector<QParenthesis> m_parens = d->line(line).parentheses();
+			
+			bool bMatch = false;
+			QParenthesis par;
+			QStack<QParenthesis> parens;
+			
+			forever
+			{
+				foreach ( par, m_parens )
+				{
+					if ( par.offset < pos )
+						continue;
+					
+					if ( par.role & QParenthesis::Open )
+					{
+						parens.push(par);
+					} else if ( par.role & QParenthesis::Close ) {
+						if ( (bMatch = ::match(parens.top(), par)) )
+						{
+							bMatch &= parens.count() == 1;
+							
+							if ( bMatch )
+								break;
+							else if ( parens.count() )
+								parens.pop();
+							else
+								qWarning("bad paren nesting...");
+						} else {
+							return 0;
+						}
+					}
+				}
+				
+				if ( bMatch )
+					break;
+				
+				pos = 0;
+				++line;
+				
+				QDocumentLine b = d->line(line);
+				
+				if ( !b.isValid() )
+					return 0;
+				
+				m_parens = b.parentheses();
+			}
+			
+			end = par.offset;
+			
+			return par.length;
+		}
+		
+		int matchClose(QDocument *d, int& line, QParenthesis p, int& beg)
+		{
+			int pos = p.offset;
+			QVector<QParenthesis> m_parens = d->line(line).parentheses();
+			
+			QParenthesis par;
+			bool bMatch = false;
+			QStack<QParenthesis> parens;
+			
+			forever
+			{
+				for ( int i = m_parens.count() - 1; i >= 0; --i )
+				{
+					par = m_parens.at(i);
+					
+					if ( par.offset > pos )
+						continue;
+					
+					if ( par.role & QParenthesis::Close )
+					{
+						parens.push(par);
+					} else if ( par.role & QParenthesis::Open ) {
+						if ( (bMatch = ::match(par, parens.top())) )
+						{
+							bMatch &= parens.count() == 1;
+							
+							if ( bMatch )
+								break;
+							else if ( parens.count() )
+								parens.pop();
+							else
+								qWarning("bad paren nesting...");
+						} else {
+							return 0;
+						}
+					}
+				}
+				
+				if ( bMatch )
+					break;
+				
+				--line;
+				
+				QDocumentLine b = d->line(line);
+				pos = b.length();
+				
+				if ( !b.isValid() )
+					return 0;
+				
+				m_parens = b.parentheses();
+			}
+			
+			beg = par.offset;
+			
+			return par.length;
+		}
+		
+	private:
+		QNFADefinition *m_definition;
+		bool m_indentFold;
+		QHash<QDocument*, int> m_indentGuess;
+};
+
+class QNFAIndenter : public QIndenterInterface
+{
+	public:
+		QNFAIndenter(QNFADefinition *d)
+		 : m_definition(d)
+		{
+		
+		}
+		
+		virtual QString indent(const QDocumentCursor& c, QIndenter *i)
+		{
+			Q_UNUSED(i)
+			
+			if ( c.isNull() || c.line().isNull() )
+				return QString();
+			
+			QDocumentLine b = c.line();
+			int pos, max = qMin(c.columnNumber(), b.text().size());
+			
+			QString s = b.text().left(max);
+			
+			//qDebug("line %i, column %i : %s", b.lineNumber(), c.columnNumber(), qPrintable(s));
+			
+			for ( pos = 0; pos < max; pos++ )
+				if ( !s.at(pos).isSpace() )
+					break;
+			
+			int indent = 0;
+			bool open = false;
+			QString spaces = s.left(pos);
+			
+			//qDebug("spaces : \"%s\"", qPrintable(spaces));
+			
+			foreach ( QParenthesis p, b.parentheses() )
+			{
+				if  ( p.offset >= max )
+				{
+					break;
+				} else if ( !(p.role & QParenthesis::Indent) ) {
+					open = true;
+				} else if ( p.role & QParenthesis::Close ) {
+					
+					if ( open )
+						--indent;
+					
+				} else { //if ( p.role & QParenthesis::Open ) {
+					open = true;
+					++indent;
+				}
+			}
+			
+			//qDebug("indent : %i", indent);
+			
+			if ( indent > 0 )
+				spaces += QString(indent, '\t');
+			
+			return spaces;
+		}
+		
+		virtual bool unindent (const QDocumentCursor& c, QKeyEvent *k)
+		{
+			if ( c.isNull() || c.line().isNull() )
+				return false;
+			
+			QDocumentLine b = c.line();
+			int pos, max = qMin(c.columnNumber(), b.text().size());
+			
+			QString ktxt = k->text(),
+					s = b.text().left(max);
+			
+			if ( ktxt.isEmpty() )
+				return false;
+			
+			for ( pos = 0; pos < max; pos++ ) 
+				if ( !s.at(pos).isSpace() )
+					break;
+			
+			QString spaces = s.left(pos),
+					text = s.mid(pos) + ktxt;
+			
+			if ( spaces.isEmpty() || text.isEmpty() )
+				return false;
+			
+			QNFAMatchContext cxt;
+			QNFANotifier notify(text);
+			
+			QDocumentLine prev = b.previous();
+			
+			if ( prev.isValid() )
+			{
+				cxt = prev.matchContext();
+			} else {
+				// first line
+				cxt = b.matchContext();
+				cxt.reset();
+			}
+			
+			match(&cxt, text, &notify);
+			
+			const QVector<QParenthesis>& parens = notify.parentheses();
+			
+			if ( parens.isEmpty() )
+				return false;
+			
+			QParenthesis p = parens.last();
+			
+			return (
+						(p.role & QParenthesis::Close)
+					&&
+						(p.role & QParenthesis::Indent)
+					&&
+						(p.offset == 0)
+					&&
+						(p.length == text.count())
+					);
+		}
+		
+	private:
+		QNFADefinition *m_definition;
+};
+
+class QNFAHighlighter : public QHighlighterInterface
+{
+	public:
+		QNFAHighlighter(QNFADefinition *d)
+		 : m_definition(d)
+		{
+		
+		}
+		
+		virtual QString singleLineComment() const
+		{
+			return m_definition->m_singleLineComment;
+		}
+		
+		virtual void highlight(QDocumentLine& block, QFormatScheme *)
+		{
+			if ( !block.matchContext()->context )
+				block.matchContext()->context = m_definition->m_root;
+			
+			QNFANotifier notifier(block);
+			QString txt = block.text() + "\n";
+			match(block.matchContext(), txt, &notifier);
+		}
+		
+	private:
+		QNFADefinition *m_definition;
+};
+#endif
+
+extern bool stringToBool(const QString& s, bool previous);
+
+QHash<QString, int> QNFADefinition::m_paren;
+QHash<QString, QNFA*> QNFADefinition::m_contexts;
+//QHash<QString, QNFADefinition*> QNFADefinition::m_definitions;
+QHash<QString, QNFADefinition::EmbedRequestList> QNFADefinition::m_pendingEmbeds;
+
+void QNFADefinition::load(const QString& file, QLanguageFactory::LangData *d, QFormatScheme *s)
+{
+	QFile f(file);
+	
+	if ( !f.open(QFile::ReadOnly | QFile::Text) )
+	{
+		qWarning("QNFADefinition : failed to open file %s", qPrintable(file));
+		return;
+	}
+	
+	load(&f, d, s);
+}
+
+void QNFADefinition::load(QFile *f, QLanguageFactory::LangData *d, QFormatScheme *s)
+{
+	QDomDocument doc;
+	doc.setContent(f);
+	
+	load(doc, d, s);
+}
+
+void QNFADefinition::load(const QDomDocument& doc, QLanguageFactory::LangData *d, QFormatScheme *s)
+{
+	QDomElement root = doc.documentElement();
+	
+	QNFADefinition *nd = new QNFADefinition;
+	
+	nd->m_language = d->lang = root.attribute("language");
+	nd->m_indentFold = stringToBool(root.attribute("indentationFold"), false);
+	nd->m_extensions = d->extensions = root.attribute("extensions").split(";");
+	nd->m_defaultMark = root.attribute("defaultLineMark", "bookmark");
+	
+	/*
+	qDebug("Generating definition for %s language from XML file : %s",
+			qPrintable(m_language),
+			qPrintable(fn));
+	*/
+	
+	// create root entity
+	nd->m_root = lexer();
+	
+	_singleLineCommentTarget = &(nd->m_singleLineComment);
+	fillContext(nd->m_root, root, s, m_paren, true);
+	_singleLineCommentTarget = 0;
+	
+	squeeze(nd->m_root);
+	
+	//m_definitions[m_language] = this;
+	m_contexts[nd->m_language] = nd->m_root;
+	
+	flushEmbedRequests(nd->m_language);
+	
+	d->d = nd;
+	d->e = 0;
+	d->s = s;
+}
+
+QNFADefinition::QNFADefinition()
+ : m_indentFold(false), m_root(0)
+{
+	
+}
+
+QNFADefinition::~QNFADefinition()
+{
+	delete m_root;
+}
+
+QString QNFADefinition::language() const
+{
+	return m_language;
+}
+
+QStringList QNFADefinition::extensions() const
+{
+	return m_extensions;
+}
+
+/*!
+	\brief Entry point for syntax highlighting
+*/
+int QNFADefinition::tokenize(QDocument *d, int line, int count)
+{
+	int n = 0;
+	bool diffCxt = false;
+	
+	QNFA *prevcxt;
+	QDocumentLine l, prev = d->line(line - 1);
+	
+	//qDebug("reformating %i lines from %i...", count, line);
+	
+	while ( (n < count) || diffCxt )
+	{
+		l = d->line(line);
+		
+		if ( !l.isValid() )
+			break;
+		
+		// get last context nest to check for noteworthy modifications needing further work
+		prevcxt = l.matchContext()->context;
+		//qDebug("\tline %i, cxt : %i", line, prevcxt);
+		
+		if ( prev.isValid() )
+		{
+			// go on using previous match context (NFA naming...)
+			
+			l.matchContext()->context = prev.matchContext()->context;
+			l.matchContext()->parents = prev.matchContext()->parents;
+			l.matchContext()->meaningless = prev.matchContext()->meaningless;
+		} else {
+			// first line : reset context....
+			
+			l.matchContext()->reset();
+			
+			/*
+			qDebug("reset : popping down by %i contexts", line.matchContext()->parents.count());
+			
+			while ( line.matchContext()->parents.count() )
+				line.matchContext()->context = line.matchContext()->parents.pop();
+			*/
+		}
+		
+		// call the implementation
+		if ( !l.matchContext()->context )
+			l.matchContext()->context = m_root;
+		
+		QNFANotifier notifier(l);
+		QString txt = l.text() + "\n";
+		::match(l.matchContext(), txt, &notifier);
+		
+		// update cont state, i.e. whether or not highlighting info of next block shall be updated
+		diffCxt = (prevcxt != l.matchContext()->context);
+		//qDebug("\t->%i (%i)", l.matchContext()->context, diffCxt);
+		prev = l;
+		++line;
+		++n;
+	}
+	
+	return n;
+}
+
+/*!
+	\brief Return the string starting a single line comment, if any offered by the language
+*/
+QString QNFADefinition::singleLineComment() const
+{
+	return m_singleLineComment;
+}
+
+QString QNFADefinition::defaultLineMark() const
+{
+	return m_defaultMark;
+}
+
+/*!
+	\brief Brace matching entry point
+*/
+void QNFADefinition::clearMatches(QDocument *d)
+{
+	QHash<QPointer<QDocument>, int>::iterator it = m_matchGroups.find(d);
+	
+	if ( it != m_matchGroups.end() )
+	{
+		d->clearMatches(*it);
+		d->flushMatches(*it);
+		
+		// erase?
+		//m_matchGroups.erase(it);
+	}
+}
+
+/*!
+	\brief Brace matching entry point
+*/
+void QNFADefinition::match(QDocumentCursor& c)
+{
+	QDocumentLine b = c.line();
+	QDocument *d = c.document();
+	
+	if ( !d || !b.isValid() )
+	{
+		qDebug("invalid cursor");
+		return;
+	}
+	
+	int gid = 0;
+	QHash<QPointer<QDocument>, int>::iterator it = m_matchGroups.find(d);
+	
+	if ( it != m_matchGroups.end() )
+	{
+		d->clearMatches(*it);
+		d->flushMatches(*it);
+		*it = gid = d->getNextGroupId();
+	} else {
+		gid = d->getNextGroupId();
+		m_matchGroups[d] = gid;
+	}
+	
+	QFormatScheme *s = d->formatScheme();
+	
+	if ( !s )
+	{
+		qDebug("no fmt");
+		d->releaseGroupId(gid);
+		m_matchGroups.remove(d);
+		return;
+	}
+	
+	int matchFID = s->id("braceMatch"), mismatchFID = s->id("braceMismatch");
+	
+	int pos = c.columnNumber();
+	const QVector<QParenthesis>& m_parens = b.parentheses();
+	
+	if ( m_parens.isEmpty() )
+	{
+		// required to properly update display
+		d->releaseGroupId(gid);
+		m_matchGroups.remove(d);
+		return;
+	}
+	
+	QParenthesis p;
+	
+	//qDebug("matching on line %i (fid is %i)", c.lineNumber(), fid);
+	
+	int matchCount = 0;
+	foreach ( p, m_parens )
+	{
+		if ( (pos != p.offset) && (pos != (p.offset + p.length)) )
+			continue;
+		
+		if ( !(p.role & QParenthesis::Match) )
+			continue;
+		
+		PMatch m;
+		m.line[0] = c.lineNumber();
+		m.column[0] = p.offset;
+		m.length[0] = p.length;
+		
+		if ( (p.role & QParenthesis::Open) && (p.role & QParenthesis::Close) )
+		{
+			matchOpen(d, m);
+			
+			if ( m.type == PMatch::Match )
+			{
+				++matchCount;
+				
+				d->addMatch(gid, m.line[0], m.column[0], m.length[0], matchFID);
+				d->addMatch(gid, m.line[1], m.column[1], m.length[1], matchFID);
+			}
+			
+			m.line[0] = c.lineNumber();
+			m.column[0] = p.offset;
+			m.length[0] = p.length;
+
+			matchClose(d, m);
+			
+			if ( m.type == PMatch::Match )
+			{
+				++matchCount;
+				
+				d->addMatch(gid, m.line[0], m.column[0], m.length[0], matchFID);
+				d->addMatch(gid, m.line[1], m.column[1], m.length[1], matchFID);
+			}
+			
+			continue;
+		} else if ( p.role & QParenthesis::Open ) {
+			matchOpen(d, m);
+		} else if ( p.role & QParenthesis::Close ) {
+			matchClose(d, m);
+		}
+		
+		if ( m.type != PMatch::Invalid )
+		{
+			++matchCount;
+			
+			int mfid = m.type == PMatch::Match ? matchFID : mismatchFID;
+			d->addMatch(gid, m.line[0], m.column[0], m.length[0], mfid);
+			d->addMatch(gid, m.line[1], m.column[1], m.length[1], mfid);
+		}
+	}
+	
+	if ( matchCount )
+	{
+		d->flushMatches(gid);
+	} else {
+		d->releaseGroupId(gid);
+		m_matchGroups.remove(d);
+	}
+}
+
+void QNFADefinition::matchOpen(QDocument *d, PMatch& m)
+{
+	int line = m.line[0];
+	int pos = m.column[0];
+	QVector<QParenthesis> m_parens = d->line(line).parentheses();
+	
+	bool bMatch = false;
+	QParenthesis par;
+	QStack<int> lines;
+	QStack<QParenthesis> parens;
+	
+	forever
+	{
+		foreach ( par, m_parens )
+		{
+			if ( par.offset < pos )
+				continue;
+			
+			if ( (par.role & QParenthesis::Open) && (par.role & QParenthesis::Close) )
+			{
+				bool bInsert = true;
+				
+				if (  parens.count() )
+				{
+					if ( ::match(par, parens.top()) )
+					{
+						//qDebug("submatch at %i", line);
+						parens.pop();
+						lines.pop();
+						
+						if ( parens.isEmpty() )
+						{
+							bMatch = true;
+							//qDebug("match at %i", line);
+							m.type = PMatch::Match;
+							
+							break;
+						}
+					} else {
+						bInsert = false;
+
+						do
+						{
+							QParenthesis tp = parens.top();
+							
+							if ( (tp.role & QParenthesis::Open) && (tp.role & QParenthesis::Close) )
+							{
+								if ( par.id < tp.id )
+								{
+									parens.pop();
+								} else {
+									break;
+								}
+							} else {
+								break;
+							}
+							
+						} while ( parens.count() );
+
+						if ( parens.isEmpty() )
+						{
+							bMatch = true;
+							m.type = PMatch::Mismatch;
+							break;
+						}
+					}
+				}
+				
+				if ( bInsert )
+				{
+					parens.push(par);
+					lines.push(line);
+				}
+			} else if ( par.role & QParenthesis::Open ) {
+				lines.push(line);
+				parens.push(par);
+			} else if ( par.role & QParenthesis::Close ) {
+				if ( (bMatch = ::match(parens.top(), par)) )
+				{
+					bMatch &= parens.count() == 1;
+					
+					if ( bMatch )
+					{
+						m.type = PMatch::Match;
+						
+						break;
+					} else if ( parens.count() ) {
+						parens.pop();
+						lines.pop();
+					} else
+						qWarning("bad paren nesting...");
+				} else {
+					bMatch = true;
+					
+					QParenthesis p = parens.pop();
+					
+					m.line[0] = lines.pop();
+					m.column[0] = p.offset;
+					m.length[0] = p.length;
+					
+					m.type = PMatch::Mismatch;
+					
+					break;
+				}
+			}
+		}
+		
+		if ( bMatch )
+			break;
+		
+		pos = 0;
+		++line;
+		
+		QDocumentLine b = d->line(line);
+		
+		if ( !b.isValid() )
+		{
+			m.type = PMatch::Invalid;
+			return;
+		}
+		
+		m_parens = b.parentheses();
+	}
+	
+	m.line[1] = line;
+	m.column[1] = par.offset;
+	m.length[1] = par.length;
+}
+
+void QNFADefinition::matchClose(QDocument *d, PMatch& m)
+{
+	int line = m.line[0];
+	int pos = m.column[0];
+	QVector<QParenthesis> m_parens = d->line(line).parentheses();
+	
+	bool bMatch = false;
+	QParenthesis par;
+	QStack<int> lines;
+	QStack<QParenthesis> parens;
+	
+	forever
+	{
+		for ( int i = m_parens.count() - 1; i >= 0; --i )
+		{
+			par = m_parens.at(i);
+			
+			if ( par.offset > pos )
+				continue;
+			
+			if ( (par.role & QParenthesis::Open) && (par.role & QParenthesis::Close) )
+			{
+				bool bInsert = true;
+
+				if (  parens.count() )
+				{
+					if ( ::match(par, parens.top()) )
+					{
+						//qDebug("submatch at %i", line);
+						parens.pop();
+						lines.pop();
+						
+						if ( parens.isEmpty() )
+						{
+							//qDebug("match at %i", line);
+							bMatch = true;
+							m.type = PMatch::Match;
+							
+							break;
+						}
+					} else {
+						bInsert = false;
+						do
+						{
+							QParenthesis tp = parens.top();
+							
+							if ( (tp.role & QParenthesis::Open) && (tp.role & QParenthesis::Close) )
+							{
+								if ( par.id < tp.id )
+								{
+									parens.pop();
+								} else {
+									break;
+								}
+							} else {
+								break;
+							}
+							
+						} while ( parens.count() );
+						
+						if ( parens.isEmpty() )
+						{
+							bMatch = true;
+							m.type = PMatch::Mismatch;
+							break;
+						}
+					}
+				}
+				
+				if ( bInsert )
+				{
+					parens.push(par);
+					lines.push(line);
+				}
+			} else if ( par.role & QParenthesis::Close ) {
+				parens.push(par);
+				lines.push(line);
+			} else if ( par.role & QParenthesis::Open ) {
+				if ( ::match(par, parens.top()) )
+				{
+					bMatch = parens.count() == 1;
+					
+					if ( bMatch )
+					{
+						m.type = PMatch::Match;
+						
+						break;
+					} else if ( parens.count() ) {
+						parens.pop();
+						lines.pop();
+					} else
+						qWarning("bad paren nesting...");
+				} else {
+					bMatch = true;
+					
+					QParenthesis p = parens.pop();
+					
+					m.line[0] = lines.pop();
+					m.column[0] = p.offset;
+					m.length[0] = p.length;
+					
+					m.type = PMatch::Mismatch;
+					
+					break;
+				}
+			}
+		}
+		
+		if ( bMatch )
+			break;
+		
+		--line;
+		
+		QDocumentLine b = d->line(line);
+		pos = b.length();
+		
+		if ( !b.isValid() )
+		{
+			m.type = PMatch::Invalid;
+			return;
+		}
+		
+		m_parens = b.parentheses();
+	}
+	
+	m.line[1] = line;
+	m.column[1] = par.offset;
+	m.length[1] = par.length;
+}
+
+/*!
+	\brief Return the indent to use when inserting a line at a given cursor position
+*/
+QString QNFADefinition::indent(const QDocumentCursor& c)
+{
+	if ( c.isNull() || c.line().isNull() )
+		return QString();
+	
+	QDocumentLine b = c.line();
+	int pos, max = qMin(c.columnNumber(), b.text().size());
+	
+	QString s = b.text().left(max);
+	
+	//qDebug("line %i, column %i : %s", b.lineNumber(), c.columnNumber(), qPrintable(s));
+	
+	for ( pos = 0; pos < max; pos++ )
+		if ( !s.at(pos).isSpace() )
+			break;
+	
+	int indent = 0;
+	QString spaces = s.left(pos);
+	
+	foreach ( QParenthesis p, b.parentheses() )
+	{
+		if ( p.offset >= max )
+			break;
+		
+		if ( !(p.role & QParenthesis::Indent) )
+			continue;
+		
+		if ( p.role & QParenthesis::Open )
+		{
+			++indent;
+		} else if ( p.role & QParenthesis::Close ) {
+			--indent;
+		}
+	}
+	
+	//qDebug("indent : %i", indent);
+	
+	if ( indent > 0 )
+		spaces += QString(indent, '\t');
+	
+	return spaces;
+}
+
+/*!
+	\brief Determines whether the given key event at the given position should cause unindent to happen
+*/
+bool QNFADefinition::unindent (const QDocumentCursor& c, const QString& ktxt)
+{
+	if ( c.isNull() || c.line().isNull() || ktxt.isEmpty() )
+		return false;
+	
+	QDocumentLine b = c.line();
+	QDocumentLine prev = c.document()->line(c.lineNumber() - 1);
+	
+	if ( !prev.isValid() )
+		return false;
+	
+	int prevIndent = prev.indent(), curIndent = b.indent();
+	int pos, max = qMin(c.columnNumber(), b.text().size());
+	
+	if ( (prevIndent - curIndent) >= c.document()->tabStop() )
+		return false;
+	
+	QString s = b.text();
+	s.insert(max, ktxt);
+	
+	//qDebug("outdenting %s", qPrintable(s));
+	for ( pos = 0; pos < max; ++pos ) 
+		if ( !s.at(pos).isSpace() )
+			break;
+	
+	if ( !pos || pos >= c.columnNumber() + ktxt.length() )
+		return false;
+	
+	QString text = s.mid(pos);
+	
+	QNFAMatchContext cxt;
+	QNFANotifier notify(text);
+	
+	if ( prev.isValid() )
+	{
+		cxt = prev.matchContext();
+	} else {
+		// first line
+		cxt = b.matchContext();
+		cxt.reset();
+	}
+	
+	::match(&cxt, text, &notify);
+	
+	const QVector<QParenthesis>& parens = notify.parentheses();
+	
+	if ( parens.isEmpty() )
+		return false;
+	
+	//qDebug("%i parentheses", parens.count());
+	QParenthesis p = parens.first();
+	
+	//qDebug("%i, %i, %i", p.offset, p.length, c.columnNumber());
+	
+	return (
+				(p.role & QParenthesis::Close)
+			&&
+				(p.role & QParenthesis::Indent)
+			&&
+				(p.offset <= c.columnNumber() - pos)
+			&&
+				(p.offset + p.length > c.columnNumber() - pos)
+			);
+	
+}
+
+int QNFADefinition::findBlockEnd(QDocument *d, int line, bool *open)
+{
+	QDocumentLine b = d->line(line);
+	
+	if ( !b.isValid() )
+		return -1;
+	
+	QVector<QParenthesis> vp, lp = b.parentheses();
+	
+	while ( lp.count() )
+	{
+		QParenthesis p = lp.first();
+		lp.pop_front();
+		
+		if ( !(p.role & QParenthesis::Fold) )
+			continue;
+		
+		if ( p.role & QParenthesis::Close && vp.count() )
+			vp.pop_back();
+
+		if ( p.role & QParenthesis::Open )
+			vp << p;
+		
+	}
+	
+	if ( vp.count() )
+	{
+		QParenthesis p = vp.first();
+		
+		PMatch m;
+		m.line[0] = line;
+		m.column[0] = p.offset;
+		m.length[0] = p.length;
+		
+		matchOpen(d, m);
+		
+		if (
+				(m.type == PMatch::Match)
+			||
+				(
+					(m.type == PMatch::Mismatch)
+				&&
+					(m.line[0] == line)
+				&&
+					(m.column[0] == p.offset)
+				)
+			)
+		{
+			if ( open )
+			{
+				int flags = blockFlags(d, m.line[1], 0);
+
+				*open = QCE_FOLD_OPEN_COUNT(flags) | (m.type == PMatch::Mismatch);
+			}
+
+			return m.line[1];
+		} else if ( m.type == PMatch::Invalid ) {
+			return d->lines() - 1;
+		}
+	}
+
+	return -1;
+}
+
+
+/*!
+	\brief Expand a collapsed block at a given line
+*/
+void QNFADefinition::expand(QDocument *d, int line)
+{
+	QDocumentLine b = d->line(line);
+	
+	if ( !b.isValid() || !b.hasFlag(QDocumentLine::CollapsedBlockStart) )
+		return;
+	
+	bool open = false;
+	int end = findBlockEnd(d, line, &open);
+	
+	int count = end - line;
+	
+	if ( open )
+		--count;
+	
+	if ( count <= 0 )
+		return;
+	
+	b.setFlag(QDocumentLine::CollapsedBlockStart, false);
+	
+	bool shared = false;
+	int i = line + 1;
+	
+	while ( i < end )
+	{
+		QDocumentLine l = d->line(i);
+		l.setFlag(QDocumentLine::Hidden, false);
+		//qDebug("+%i", i);
+		if ( l.hasFlag(QDocumentLine::CollapsedBlockStart) )
+		{
+			bool bopen = false;
+			int bend = findBlockEnd(d, i, &bopen);
+			
+			i = bend;
+
+			if ( !bopen )
+				++i;
+			
+			if ( bend == end )
+			{
+				shared = true;
+			}
+		} else {
+			++i;
+		}
+	}
+	
+	if ( !shared )
+	{
+		d->line(end).setFlag(QDocumentLine::CollapsedBlockEnd, false);
+	}
+	
+	if ( !open && !shared )
+	{
+		//qDebug("+%i", end);
+		d->line(end).setFlag(QDocumentLine::Hidden, false);
+	}
+	
+	//qDebug("expanding %i lines from %i", count, line);
+	d->impl()->showEvent(line, count);
+}
+
+/*!
+	\brief Collapse a text block at a given line
+*/
+void QNFADefinition::collapse(QDocument *d, int line)
+{
+	QDocumentLine b = d->line(line);
+	
+	if ( !b.isValid() || b.hasFlag(QDocumentLine::CollapsedBlockStart) )
+		return;
+	
+	//qDebug("collapse line %i", line);
+	
+	bool open = false;
+	int end = findBlockEnd(d, line, &open);
+	
+	int count = end - line;
+	
+	if ( open )
+		--count;
+	
+	if ( count <= 0 )
+		return;
+	
+	b.setFlag(QDocumentLine::CollapsedBlockStart);
+	
+	for ( int i = line + 1; i < end; ++i )
+	{
+		if ( !d->line(i).hasFlag(QDocumentLine::Hidden) )
+		{
+			//qDebug("-%i", i);
+			d->line(i).setFlag(QDocumentLine::Hidden);
+		}
+	}
+	
+	d->line(end).setFlag(QDocumentLine::CollapsedBlockEnd);
+	
+	if ( !open )
+	{
+		if ( !d->line(end).hasFlag(QDocumentLine::Hidden) )
+		{
+			//qDebug("-%i", end);
+			d->line(end).setFlag(QDocumentLine::Hidden);
+		}
+	}
+	
+	//qDebug("collapsing %i lines from %i", count, line);
+	d->impl()->hideEvent(line, count);
+	
+	#if 0
+	if ( !m_indentFold )
+		return;
+	
+	int i = ln + 1, k;
+	QDocumentLine block = d->line(i);
+	
+	if ( !block.isValid() )
+		return;
+	
+	indent = block.firstChar();
+	
+	do
+	{
+		block = d->line(++i);
+		k = block.firstChar();
+	} while ( block.isValid() && ((k >= indent) || (k == -1)) );
+	
+	if ( k < indent )
+	{
+		block = d->line(--i);
+		k = block.firstChar();
+	}
+	
+	while ( block.isValid() && (i > ln) && (k == -1) )
+	{
+		block = d->line(--i);
+		k = block.firstChar();
+	}
+	
+	b.setFlag(QDocumentLine::CollapsedBlockStart);
+	
+	//qDebug("hidding from %i to %i", ln + 1, i);
+	
+	for ( int j = ln + 1; j <= i; ++j )
+	{
+		d->line(j).setFlag(QDocumentLine::Hidden);
+	}
+	
+	d->line(i).setFlag(QDocumentLine::CollapsedBlockEnd);
+	
+	d->impl()->hideEvent(ln, i - ln);
+	#endif
+}
+
+/*!
+	\brief Compute the collapse state of a line
+*/
+int QNFADefinition::blockFlags(QDocument *d, int line, int depth) const
+{
+	Q_UNUSED(depth)
+	
+	QDocumentLine b = d->line(line);
+	
+	if ( !b.isValid() )
+		return None;
+	
+	int ret = None;
+	short open = 0, close = 0;
+	
+	foreach ( QParenthesis p, b.parentheses() )
+	{
+		if ( !(p.role & QParenthesis::Fold) )
+			continue;
+		
+		if ( p.role & QParenthesis::Close )
+		{
+			if ( open )
+				--open;
+			else
+				++close;
+			
+		}
+		
+		if ( p.role & QParenthesis::Open )
+		{
+			++open;
+		}
+	}
+	
+	if ( b.hasFlag(QDocumentLine::CollapsedBlockStart) )
+		ret = Collapsed;
+	
+	if ( open )
+		ret |= Collapsible;
+	
+	if ( close )
+		ret |= Closure;
+	
+	//qDebug("%i : ret : %i (%i, %i)", line, ret, ret & 0xffff0000, short(((short)0) | (ret & 0xffff)));
+	
+	return QCE_FOLD_FLAGS(ret, open, close);
+}
+
+void QNFADefinition::addContext(const QString& id, QNFA *nfa)
+{
+	//qDebug("registering context : %s", qPrintable(id));
+	m_contexts[id] = nfa;
+}
+
+void QNFADefinition::flushEmbedRequests(const QString& lang)
+{
+	//qDebug("flushing requests for : %s", qPrintable(lang));
+	QHash<QString, EmbedRequestList>::iterator it;
+	
+	it = m_pendingEmbeds.begin();
+	
+	while ( it != m_pendingEmbeds.end() )
+	{
+		QString r = it.key();
+		
+		if (
+				r.startsWith(lang)
+			&&
+				(
+					(r.count() == lang.count())
+				||
+					(r.at(lang.count()) == ':')
+				)
+			)
+		{
+			QNFA *src = m_contexts.value(r);
+			
+			if ( !src )
+			{
+				++it;
+				continue;
+			}
+			
+			foreach( const EmbedRequest& request, *it )
+			{
+				//qDebug("embedding %s in 0x%x at index %i",
+				//		qPrintable(r), request.target, request.index);
+				
+				embed(src, request.target, request.index);
+			}
+			
+			it = m_pendingEmbeds.erase(it);
+		} else {
+			++it;
+		}
+	}
+}
+
+void QNFADefinition::addEmbedRequest(const QString& cxt, QNFA *dest)
+{
+	//qDebug("Adding request : %s", qPrintable(cxt));
+	
+	if ( m_contexts.contains(cxt) )
+	{
+		//qDebug("dealing with request : %s", qPrintable(cxt));
+		embed(m_contexts[cxt], dest, dest->out.branch->count());
+	} else {
+		m_pendingEmbeds[cxt] << EmbedRequest(dest, dest->out.branch->count());
+	}
+}
+
+void QNFADefinition::shareEmbedRequests(QNFA *src, QNFA *dest, int offset)
+{
+	QHash<QString, EmbedRequestList>::iterator it = m_pendingEmbeds.begin();
+	
+	while ( it != m_pendingEmbeds.end() )
+	{
+		foreach ( const EmbedRequest& request, *it )
+		{
+			if ( request.target == src )
+			{
+				//qDebug("sharing one embed request between 0x%x and 0x%x at %i + %i", src, dest, offset, request.index);
+				it->append(EmbedRequest(dest, request.index + offset));
+			}
+		}
+		
+		++it;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qnfa/qnfadefinition.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QNFA_DEFINITION_H_
+#define _QNFA_DEFINITION_H_
+
+/*!
+	\file qnfadefinition.h
+	\brief Definition of the QNFADefinition class.
+*/
+
+#include "qlanguagefactory.h"
+#include "qlanguagedefinition.h"
+
+#include <QHash>
+#include <QPointer>
+#include <QStringList>
+
+struct QNFA;
+
+class QParenthesis;
+
+class QFile;
+class QDomDocument;
+
+class QNFAAction
+{
+	public:
+		enum
+		{
+			NoAction	= 0,
+			
+			FormatMask	= 0x00000fff,
+			ParenMask	= 0x00fff000,
+			
+			Highlight	= 0x01000000,
+			Indent		= 0x02000000,
+			ParenOpen	= 0x04000000,
+			ParenClose	= 0x08000000,
+			MatchParen	= 0x10000000,
+			Fold		= 0x20000000,
+
+			Ambiguous	= 0x40000000,
+			
+			Content		= 0x80000000
+		};
+		
+		inline static int format(int id)
+		{ return id & FormatMask; }
+		
+		inline static int parenthesis(int id)
+		{ return id & ParenMask; }
+};
+
+class QCE_EXPORT QNFADefinition : public QLanguageDefinition
+{
+	public:
+		QNFADefinition();
+		virtual ~QNFADefinition();
+		
+		virtual QString language() const;
+		virtual QStringList extensions() const;
+		
+		virtual int tokenize(QDocument *d, int line, int count);
+		
+		virtual QString singleLineComment() const;
+		
+		virtual QString defaultLineMark() const;
+		
+		virtual void clearMatches(QDocument *d);
+		virtual void match(QDocumentCursor& c);
+		
+		virtual QString indent(const QDocumentCursor& c);
+		virtual bool unindent (const QDocumentCursor& c, const QString& ktxt);
+		
+		virtual void expand(QDocument *d, int line);
+		virtual void collapse(QDocument *d, int line);
+		virtual int blockFlags(QDocument *d, int line, int depth) const;
+		
+		static void load(QFile *f, QLanguageFactory::LangData *d, QFormatScheme *s);
+		static void load(const QString& file, QLanguageFactory::LangData *d, QFormatScheme *s);
+		static void load(const QDomDocument& doc, QLanguageFactory::LangData *d, QFormatScheme *s);
+		
+		static void addContext(const QString& id, QNFA *nfa);
+		static void addEmbedRequest(const QString& lang, QNFA *dest);
+		static void shareEmbedRequests(QNFA *src, QNFA *dest, int offset);
+		
+	private:
+		bool m_indentFold;
+		QString m_language,
+				m_defaultMark,
+				m_singleLineComment;
+		
+		QStringList m_extensions;
+		
+		QNFA *m_root;
+		
+		QHash<QPointer<QDocument>, int> m_matchGroups;
+		
+		static QHash<QString, int> m_paren;
+		static QHash<QString, QNFA*> m_contexts;
+		
+		struct PMatch
+		{
+			PMatch() : type(Invalid)
+			{
+				line[0] = -1;
+				line[1] = -1;
+				
+				column[0] = -1;
+				column[1] = -1;
+				
+				length[0] = 0;
+				length[1] = 0;
+			}
+			
+			enum Type
+			{
+				Invalid,
+				Match,
+				Mismatch
+			};
+			
+			char type;
+			
+			int line[2];
+			int column[2];
+			int length[2];
+		};
+		
+		void matchOpen(QDocument *d, PMatch& m);
+		void matchClose(QDocument *d, PMatch& m);
+		
+		int findBlockEnd(QDocument *d, int line, bool *open = 0);
+		
+		static void flushEmbedRequests(const QString& lang);
+		
+		struct EmbedRequest
+		{
+			inline EmbedRequest(QNFA *nfa, int idx) : index(idx), target(nfa) {}
+			
+			int index;
+			QNFA *target;
+		};
+		
+		typedef QList<EmbedRequest> EmbedRequestList;
+		
+		static QHash<QString, EmbedRequestList> m_pendingEmbeds;
+};
+
+#endif // !_QNFA_DEFINITION_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qnfa/xml2qnfa.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,466 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+/*!
+	\file xml2qnfa.cpp
+	\brief Implementation of the QNFA builder (fetch syntax engine data from XML files)
+*/
+
+#include "qnfa.h"
+#include "qnfadefinition.h"
+
+#include "qformatscheme.h"
+
+#include <QVariant>
+#include <QDomText>
+#include <QDomElement>
+#include <QDomDocument>
+
+/*
+	<QNFA>
+		<word></word>
+		<sequence></sequence>
+		
+		<context>
+			<start></start>
+			<stop></stop>
+			<escape></escape>
+			
+			...
+			
+		</context>
+	</QNFA>
+*/
+
+QString *_singleLineCommentTarget = 0;
+
+bool stringToBool(const QString& s, bool previous)
+{
+	if ( s.isEmpty() )
+		return previous;
+	
+	return
+			(
+				(s == "true")
+			||
+				(s == "enabled")
+			)
+		||
+			(
+				(s != "false")
+			&&
+				(s != "disabled")
+			&&
+				QVariant(s).toBool()
+			);
+}
+
+int pid(const QString& s, QHash<QString, int>& pids)
+{
+	if ( pids.contains(s) )
+		return pids.value(s);
+	
+	int id = (pids.count() + 1) << 12;
+	
+	pids[s] = id;
+	
+	return id;
+}
+
+int action(QDomElement c, QFormatScheme *f, QHash<QString, int>& pids, int fid = 0)
+{
+	QString paren, spid, spt, sfid;
+	
+	sfid = c.attribute("format");
+	
+	if ( sfid.count() )
+	{
+		fid |= QNFAAction::Highlight | QNFAAction::format(f->id(sfid));
+	}
+	
+	paren = c.attribute("parenthesis");
+	
+	if ( paren.count() )
+	{
+		spid = paren.section(':', 0, -2);
+		spt = paren.section(':', -1, -1);
+		
+		if ( spt.endsWith("@nomatch") )
+		{
+			spt.chop(8);
+		} else {
+			fid |= QNFAAction::MatchParen;
+		}
+		
+		if ( spid.count() )
+		{
+			/*qDebug("paren : [%s|%s] => 0x%x",
+					qPrintable(spid), qPrintable(spt),
+					(spt == "open" ? QNFAAction::ParenOpen : QNFAAction::ParenClose) | pid(spid, pids));
+			*/
+			
+			if ( spt == "open" )
+				fid |= QNFAAction::ParenOpen;
+			else if ( spt == "close" )
+				fid |= QNFAAction::ParenClose;
+			else if ( spt == "boundary" )
+				fid |= QNFAAction::ParenOpen | QNFAAction::ParenClose;
+
+			fid |= QNFAAction::parenthesis(pid(spid, pids));
+			
+			/*
+			qDebug("paren : [%s|%s] => 0x%x",
+					qPrintable(spid), qPrintable(spt),
+					fid & QNFAAction::ParenMask);
+			*/
+		}
+	}
+	
+	if ( stringToBool(c.attribute("indent"), false) )
+		fid |= QNFAAction::Indent;
+	
+	if ( stringToBool(c.attribute("fold"), false) )
+		fid |= QNFAAction::Fold;
+	
+	// TODO : determine ambiguity automatically
+	if ( stringToBool(c.attribute("ambiguous"), false) )
+		fid |= QNFAAction::Ambiguous;
+	
+	return fid;
+}
+
+void copy(const QCharTreeLevel& src, QCharTreeLevel& dest)
+{
+	QCharTreeLevel::const_iterator it = src.constBegin();
+	
+	while ( it != src.constEnd() )
+	{
+		//qDebug("copying char tree level %c", QChar(it.key()).toLatin1());
+		
+		if ( !dest.contains(it.key()) )
+			dest[it.key()] = *it;
+		else
+			copy(it->next, dest[it.key()].next);
+		
+		++it;
+	}
+}
+
+void embed(QNFA *src, QNFA *dest, int idx = 0)
+{
+	QNFA *nfa;
+	const int n = src->out.branch->count();
+	
+	//dest->out.branch->alloc(idx, n);
+	
+	//qDebug("\tembedding %i children", n);
+	
+	for ( int i = 0; i < n; ++i )
+	{
+		nfa = src->out.branch->at(i);
+		
+		if ( nfa->type & Reserved )
+			continue;
+		
+		//qDebug("\t\teffectively embedding 0x%x at %i", nfa, idx);
+		dest->out.branch->insert(idx++, nfa);
+	}
+	
+	copy(src->tree, dest->tree);
+}
+
+void fillContext(QNFA *cxt, QDomElement e, QFormatScheme *f, QHash<QString, int>& pids, bool cs);
+void fillContext(QNFA *cxt, QDomNodeList l, QFormatScheme *f, QHash<QString, int>& pids, bool cs);
+
+void addToContext(	QNFA *cxt, QDomElement c, int fid,
+					QFormatScheme *f, QHash<QString, int>& pids,
+					const QStringList& pref,
+					const QStringList& suff,
+					bool cs)
+{
+	QString tag = c.tagName();
+	
+	if ( !c.hasChildNodes() && tag != "embed" )
+		return;
+	
+	cs = stringToBool(c.attribute("caseSensitive"), cs);
+	
+	if ( (tag == "start") || (tag == "stop") || (tag == "escape") )
+	{
+		return;
+	} else if ( tag == "word" ) {
+		//qDebug("adding word : %s", qPrintable(c.firstChild().toText().data()));
+		const QString value = c.firstChild().toText().data();
+		
+		if ( pref.isEmpty() && suff.isEmpty() )
+		{
+			addWord(cxt, value, fid, cs);
+		} else if ( pref.count() ) {
+			foreach ( const QString& p, pref )
+			{
+				if ( suff.isEmpty() )
+				{
+					addWord(cxt, p + value, fid, cs);
+				} else {
+					foreach ( const QString& s, suff )
+					{
+						addWord(cxt, p + value + s, fid, cs);
+					}
+				}
+			}
+		} else {
+			foreach ( const QString& s, suff )
+			{
+				addWord(cxt, value + s, fid, cs);
+			}
+		}
+	} else if ( tag == "sequence" ) {
+		const QString value = c.firstChild().toText().data();
+		
+		//qDebug("adding sequence : %s [0x%x]", qPrintable(value), cxt);
+		if ( pref.isEmpty() && suff.isEmpty() )
+		{
+			addSequence(cxt, value, fid, cs);
+		} else if ( pref.count() ) {
+			foreach ( const QString& p, pref )
+			{
+				if ( suff.isEmpty() )
+				{
+					addSequence(cxt, p + value, fid, cs);
+				} else {
+					foreach ( const QString& s, suff )
+					{
+						addSequence(cxt, p + value + s, fid, cs);
+					}
+				}
+			}
+		} else {
+			foreach ( const QString& s, suff )
+			{
+				addSequence(cxt, value + s, fid, cs);
+			}
+		}
+	} else if ( tag == "list" ) {
+		QDomNodeList children = c.childNodes();
+		QStringList prefixes, suffixes;
+		
+		//qDebug("starting list");
+		for ( int j = 0; j < children.count(); ++j )
+		{
+			QDomElement cc = children.at(j).toElement();
+			
+			if ( cc.isNull() )
+				continue;
+			
+			const QString role = cc.tagName();
+			const QString value = cc.firstChild().toText().data();
+			
+			if ( role == "prefix" )
+				prefixes << value;
+			else if ( role == "suffix" )
+				suffixes << value;
+			else
+				addToContext(cxt, cc, action(cc, f, pids, fid), f, pids, prefixes, suffixes, cs);
+		}
+		//qDebug("ending list");
+		
+	} else if ( tag == "embed" ) {
+		QNFADefinition::addEmbedRequest(c.attribute("target"), cxt);
+	} else if ( tag == "context" ) {
+		QNFA	*nfa,
+				*start = 0,
+				*hstart = 0,
+				*cstart = 0,
+				*stop = 0,
+				*hstop = 0,
+				*escape = 0,
+				*hescape = 0;
+		
+		QList<QNFA*> lStart, lStop, lEscape;
+		
+		QString attr;
+		int defact = action(c, f, pids);
+		QDomNodeList children = c.childNodes();
+		
+		QString _id = c.attribute("id");
+		bool trans = stringToBool(c.attribute("transparency"), false);
+		bool stay = stringToBool(c.attribute("stayOnLine"), false);
+		
+		for ( int j = 0; j < children.count(); ++j )
+		{
+			QDomElement child = children.at(j).toElement();
+			
+			if ( child.isNull() || !child.hasChildNodes() )
+				continue;
+			
+			bool tcs = stringToBool(child.attribute("caseSensitive"), cs);
+			
+			int act = action(child, f, pids);
+			
+			if ( !(act & QNFAAction::Highlight) )
+				act |= QNFAAction::Highlight | QNFAAction::format(defact);
+			
+			const QString role = child.tagName();
+			const QString value = child.firstChild().toText().data();
+			
+			if ( role == "start" )
+			{
+				start = sequence(value, &hstart, tcs);
+				start->actionid = act;
+				//start->type |= Reserved;
+				lStart << start;
+				
+				if ( !cstart )
+				{
+					cstart = new QNFA;
+					cstart->type = ContextBegin | (stay ? StayOnLine : 0);
+					cstart->actionid = defact;
+					cstart->out.branch = new QNFABranch;
+					
+					// only the first sequence comes
+					if ( _singleLineCommentTarget && (_id == "comment/single") )
+						*_singleLineCommentTarget = value;
+					
+				}
+				
+				hstart->out.next = cstart;
+				hstart->actionid = act;
+				//hstart = nfa;
+				
+				//qDebug("cxt start seq : %s [0x%x, 0x%x]", qPrintable(value), start, nfa);
+				
+			} else if ( role == "stop" ) {
+				stop = sequence(value, &hstop, tcs);
+				stop->actionid = act;
+				stop->type |= Reserved;
+				lStop << stop;
+				
+				nfa = new QNFA;
+				nfa->type = ContextEnd;
+				nfa->actionid = act;
+				//nfa->out.branch = new QNFABranch;
+				
+				hstop->out.next = nfa;
+				hstop->actionid = act;
+				hstop = nfa;
+				
+				attr = child.attribute("exclusive");
+				
+				if ( attr.isEmpty() || (attr == "true") || attr.toUInt() )
+					hstop->type |= Exclusive;
+				
+				//qDebug("cxt stop seq : %s [0x%x]", qPrintable(value), act);
+				
+			} else if ( role == "escape" ) {
+				
+				escape = sequence(value, &hescape, tcs);
+				escape->type |= Reserved;
+				lEscape << escape;
+				
+				nfa = new QNFA;
+				nfa->type = EscapeSeq;
+				nfa->actionid = action(child, f, pids);
+				//nfa->out.branch = new QNFABranch;
+				
+				hescape->out.next = nfa;
+				//hescape = nfa;
+			}
+		}
+		
+		if ( hstart )
+		{
+			//qDebug("starting cxt %s:0x%x [0x%x]", qPrintable(c.attribute("id")), cstart, cxt);
+			
+			foreach ( escape, lEscape )
+			{
+				//cstart->type |= Escaped;
+				addNFA(cstart, escape);
+			}
+			
+			//qDebug("after esc : %i", cstart->out.branch->count());
+			
+			foreach ( stop, lStop )
+				addNFA(cstart, stop);
+			
+			//qDebug("after stop : %i", cstart->out.branch->count());
+		} else {
+			cstart = new QNFA;
+			cstart->type = ContextBegin | (stay ? StayOnLine : 0);
+			cstart->actionid = defact;
+			cstart->out.branch = new QNFABranch;
+		}
+		
+		fillContext(cstart, c, f, pids, cs);
+		
+		if ( c.hasAttribute("id") )
+		{
+			QNFADefinition::addContext(
+					c.ownerDocument().documentElement().attribute("language")
+					+ ":"
+					+ _id,
+					cstart
+				);
+			
+		} else {
+			//qDebug("unregistered context");
+		}
+		
+		//qDebug("after sub : %i", cstart->out.branch->count());
+		
+		if ( trans )
+		{
+			QNFADefinition::shareEmbedRequests(cxt, cstart, cstart->out.branch->count());
+			embed(cxt, cstart, cstart->out.branch->count());
+		}
+		
+		if ( hstart )
+		{
+			foreach ( start, lStart )
+				addNFA(cxt, start);
+			
+			//qDebug("ending cxt");
+		} else {
+			
+		}
+		
+		//fillContext(subcxt, c, f, pids);
+	} else {
+		//qDebug("unhandled tag : %s", qPrintable(tag));
+	}
+}
+
+void fillContext(QNFA *cxt, QDomElement e, QFormatScheme *f, QHash<QString, int>& pids, bool cs)
+{
+	cs = stringToBool(e.attribute("caseSensitive"), cs);
+	
+	fillContext(cxt, e.childNodes(), f, pids, cs);
+}
+
+void fillContext(QNFA *cxt, QDomNodeList l, QFormatScheme *f, QHash<QString, int>& pids, bool cs)
+{
+	//qDebug("filling context from %i nodes", l.count());
+	
+	for ( int i = 0; i < l.count(); i++ )
+	{
+		QDomElement c = l.at(i).toElement();
+		
+		if ( c.isNull() )
+			continue;
+		
+		addToContext(cxt, c, action(c, f, pids), f, pids, QStringList(), QStringList(), cs);
+	}
+	
+	//qDebug("context filled");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qpanellayout.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,435 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qpanellayout.h"
+
+/*!
+	\file qpanellayout.cpp
+	\brief Implementation of the QPanelLayout class.
+*/
+
+#include "qpanel.h"
+#include "qeditor.h"
+
+#include <QWidget>
+#include <QScrollBar>
+
+#ifdef Q_WS_WIN
+// panel position fix required on some systems to work around a bug in QAbstractScrollArea
+#define _PANEL_POSITION_FIX_
+#endif
+
+/*!
+	\class QPanelLayout
+	\brief A specialized layout taking care of panel display
+	
+	The panel layout is specialized in several ways :
+	<ul>
+	<li>It only operates on specific widgets (which inherit QPanel)</li>
+	<li>It can only layout widgets in the viewport margins of a QEditor (could work with
+	any QAbstractScrollArea if a single method was made public instead of protected...)
+	so it does not qualify as a "real" layout  (contrary to grid/box layouts)</li>
+	<li>It positions widgets on the border of the editor in the same way the Border Layout
+	example does (most of the layout code actually comes from there).</li>
+	<li>It provides serialization/deserialization of its layout structure</li>
+	</ul>
+*/
+
+/*
+	The layouting code is inspired from a Qt4 example : Border Layout
+*/
+
+/*!
+	\brief ctor
+*/
+QPanelLayout::QPanelLayout(QEditor *p)
+ : QLayout(p), m_parent(p)
+{
+	setSpacing(0);
+}
+
+/*!
+	\brief ctor
+	\param layout structure to deserailize
+*/
+QPanelLayout::QPanelLayout(const QString& layout, QEditor *p)
+ : QLayout(p), m_parent(p)
+{
+	setSpacing(0);
+	addSerialized(layout);
+}
+
+/*!
+	\brief dtor
+*/
+QPanelLayout::~QPanelLayout()
+{
+	QLayoutItem *l;
+	
+	while ( (l = takeAt(0)) )
+		delete l;
+}
+
+/*!
+	\return A serialized layout strucure
+*/
+QString QPanelLayout::serialized() const
+{
+	/*
+		Scheme :
+		
+		QPanelLayout::Position '{' comma-separated list of identifiers '}'
+	*/
+	
+	QHash<int, QString> posMap;
+	
+	for ( int i = 0; i < m_list.size(); ++i )
+	{
+		PanelWrapper *wrapper = m_list.at(i);
+		Position position = wrapper->position;
+		
+		QPanel *panel = qobject_cast<QPanel*>(wrapper->item->widget());
+		
+		if ( !panel )
+			continue;
+		
+		if ( !posMap.contains(position) )
+		{
+			posMap[position] = QString::number(position) + "{" + panel->id() + "}";
+		} else {
+			QString& ref = posMap[position];
+			
+			ref.insert(ref.count() - 2, QString(",") + panel->id());
+		}
+	}
+	
+	return QStringList(posMap.values()).join("");
+}
+
+/*!
+	\brief Add the content of a serialized layout structure
+*/
+void QPanelLayout::addSerialized(const QString& layout)
+{
+	//qDebug("layout : %s", qPrintable(layout));
+	
+	int last = 0, i = 0;
+	bool inList = false;
+	Position position = West;
+	
+	while ( i < layout.length() )
+	{
+		if ( inList )
+		{
+			if ( layout.at(i) == '}' )
+				inList = false;
+			
+			if ( !inList || (layout.at(i) == ',') )
+			{
+				QPanel *panel = QPanel::panel(layout.mid(last, i - last), m_parent);
+				
+				if ( panel )
+				{
+					panel->attach(m_parent);
+					addWidget(panel, position);
+					
+					//qDebug("\tpanel : %s", qPrintable(layout.mid(last, i - last)));
+				}
+				
+				last = i + 1;
+			}
+		} else if ( layout.at(i) == '{' ) {
+			inList = true;
+			position = Position(layout.mid(last, i - last).toInt());
+			
+			//qDebug("position : %i [%s]", position, qPrintable(layout.mid(last, i - last)));
+			
+			last = i + 1;
+		}
+		
+		++i;
+	}
+	
+	update();
+}
+
+/*!
+	\return the list of panels managed by the layout
+*/
+QList<QPanel*> QPanelLayout::panels() const
+{
+	QList<QPanel*> l;
+	
+	foreach ( PanelWrapper *w, m_list )
+	{
+		QPanel *p = qobject_cast<QPanel*>(w->item->widget());
+		
+		if ( p )
+			l << p;
+	}
+	
+	return l;
+}
+
+/*!
+	\return the count of managed panels
+*/
+int QPanelLayout::count() const
+{
+	return m_list.count();
+}
+
+/*!
+	\internal
+*/
+bool QPanelLayout::hasHeightForWidth() const
+{
+	return false;
+}
+
+/*!
+	\internal
+*/
+Qt::Orientations QPanelLayout::expandingDirections() const
+{
+	return Qt::Horizontal | Qt::Vertical;
+}
+
+/*!
+	\internal
+*/
+QSize QPanelLayout::sizeHint() const
+{
+	return calculateSize(SizeHint);
+}
+
+/*!
+	\internal
+*/
+QSize QPanelLayout::minimumSize() const
+{
+	return calculateSize(MinimumSize);
+}
+
+/*!
+	\internal
+*/
+void QPanelLayout::addItem(QLayoutItem *item)
+{
+	add(item, West);
+}
+
+/*!
+	\brief Add a panel at a given position
+*/
+void QPanelLayout::addWidget(QWidget *widget, Position position)
+{
+	add(new QWidgetItem(widget), position);
+}
+
+/*!
+	\internal
+*/
+QLayoutItem* QPanelLayout::itemAt(int idx) const
+{
+	PanelWrapper *wrapper = m_list.value(idx);
+	
+	if ( wrapper )
+		return wrapper->item;
+	else
+		return 0;
+	
+}
+
+/*!
+	\internal
+*/
+QLayoutItem* QPanelLayout::takeAt(int idx)
+{
+	if ( (idx >= 0) && (idx < m_list.size()) )
+	{
+		PanelWrapper *layoutStruct = m_list.takeAt(idx);
+		return layoutStruct->item;
+	}
+	
+	return 0;
+}
+
+/*!
+	\internal
+*/
+void QPanelLayout::setGeometry(const QRect &r)
+{
+	//qDebug("laying out %i panels", count());
+	#ifdef _PANEL_POSITION_FIX_
+	QScrollBar *vb = m_parent->verticalScrollBar(),
+			*hb = m_parent->horizontalScrollBar();
+	
+	QRect rect(	r.x(), r.y(),
+				r.width() - (vb->isVisibleTo(m_parent) ? vb->width() : 0),
+				r.height() - (hb->isVisibleTo(m_parent) ? hb->height() : 0)
+				);
+	#else
+	QRect rect(	r.x(), r.y(),
+				r.width(),
+				r.height()
+				);
+	#endif
+	
+	int i,
+		eastWidth = 0,
+		westWidth = 0,
+		northHeight = 0,
+		southHeight = 0,
+		centerHeight = 0;
+	
+	QLayout::setGeometry(rect);
+	
+	for ( i = 0; i < m_list.size(); ++i )
+	{
+		PanelWrapper *wrapper = m_list.at(i);
+		QLayoutItem *item = wrapper->item;
+		Position position = wrapper->position;
+		
+		if ( item->isEmpty()  )
+			continue;
+		
+		if ( position == North )
+		{
+			item->setGeometry(QRect(
+									rect.x(),
+									northHeight,
+									rect.width(),
+									item->sizeHint().height()
+									)
+							);
+			
+			northHeight += item->geometry().height() + spacing();
+		} else if (position == South) {
+			item->setGeometry(QRect(item->geometry().x(),
+									item->geometry().y(),
+									rect.width(),
+									item->sizeHint().height()
+									)
+							);
+			
+			southHeight += item->geometry().height() + spacing();
+			
+			item->setGeometry(QRect(rect.x(),
+									rect.y() + rect.height() - southHeight + spacing(),
+									item->geometry().width(),
+									item->geometry().height()
+									)
+							);
+			
+		}
+	}
+	
+	centerHeight = rect.height() - northHeight - southHeight;
+	
+	for ( i = 0; i < m_list.size(); ++i )
+	{
+		PanelWrapper *wrapper = m_list.at(i);
+		QLayoutItem *item = wrapper->item;
+		Position position = wrapper->position;
+		
+		if ( item->isEmpty() )
+			continue;
+		
+		if ( position == West )
+		{
+			item->setGeometry(QRect(rect.x() + westWidth,
+									northHeight,
+									item->sizeHint().width(),
+									centerHeight
+									)
+							);
+			
+			westWidth += item->geometry().width() + spacing();
+		} else if (position == East) {
+			item->setGeometry(QRect(item->geometry().x(),
+									item->geometry().y(),
+									item->sizeHint().width(),
+									centerHeight
+									)
+							);
+			
+			eastWidth += item->geometry().width() + spacing();
+			
+			item->setGeometry(QRect(rect.x() + rect.width() - eastWidth + spacing(),
+									northHeight,
+									item->geometry().width(),
+									item->geometry().height()
+									)
+							);
+			
+		}
+	}
+	
+	/*
+	if ( center )
+		center->item->setGeometry(QRect(westWidth, northHeight,
+										rect.width() - eastWidth - westWidth,
+										centerHeight));
+	*/
+	//qDebug("{%i, %i, %i, %i}", westWidth, northHeight, eastWidth, southHeight);
+	m_parent->setPanelMargins(westWidth, northHeight, eastWidth, southHeight);
+}
+
+/*!
+	\internal
+*/
+void QPanelLayout::add(QLayoutItem *item, Position position)
+{
+	QPanel *p;
+	
+	if ( (p = qobject_cast<QPanel*>(item->widget())) )
+	{
+		//p->setParent(m_parent);
+		p->setVisible(p->defaultVisibility());
+	}
+	
+	m_list.append(new PanelWrapper(item, position));
+}
+
+/*!
+	\internal
+*/
+QSize QPanelLayout::calculateSize(SizeType sizeType) const
+{
+	QSize totalSize;
+	
+	for ( int i = 0; i < m_list.size(); ++i )
+	{
+		QSize itemSize;
+		PanelWrapper *wrapper = m_list.at(i);
+		Position position = wrapper->position;
+		
+		if ( sizeType == MinimumSize )
+			itemSize = wrapper->item->minimumSize();
+		else // ( sizeType == SizeHint )
+			itemSize = wrapper->item->sizeHint();
+		
+		if ( (position == North) || (position == South) ) // || (position == Center) )
+			totalSize.rheight() += itemSize.height();
+		
+		if ( (position == West) || (position == East) ) // || (position == Center) )
+			totalSize.rwidth() += itemSize.width();
+		
+	}
+	
+	return totalSize;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qpanellayout.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QPANEL_LAYOUT_H_
+#define _QPANEL_LAYOUT_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qpanellayout.h
+	\brief Definition of the QPanelLayout class
+*/
+
+#include <QList>
+#include <QLayout>
+#include <QPointer>
+
+class QPanel;
+class QEditor;
+
+class QCE_EXPORT QPanelLayout : public QLayout
+{
+	Q_OBJECT
+	
+	public:
+		enum Position
+		{
+			West,
+			North,
+			South,
+			East
+		};
+		
+		QPanelLayout(QEditor *p);
+		QPanelLayout(const QString& layout, QEditor *p);
+		virtual ~QPanelLayout();
+		
+		virtual int count() const;
+		virtual bool hasHeightForWidth() const;
+		virtual Qt::Orientations expandingDirections() const;
+		
+		virtual QSize sizeHint() const;
+		virtual QSize minimumSize() const;
+		
+		virtual QLayoutItem *itemAt(int idx) const;
+		virtual QLayoutItem *takeAt(int idx);
+		
+		QString serialized() const;
+		void addSerialized(const QString& layout);
+		
+		QList<QPanel*> panels() const;
+		
+	public slots:
+		virtual void addItem(QLayoutItem *item);
+		virtual void setGeometry(const QRect &rect);
+		
+		void add(QLayoutItem *item, Position position);
+		void addWidget(QWidget *widget, Position position);
+		
+	private:
+		QPointer<QEditor> m_parent;
+		
+		struct PanelWrapper
+		{
+			PanelWrapper(QLayoutItem *i, Position p)
+			{
+				item = i;
+				position = p;
+			}
+			
+			QLayoutItem *item;
+			Position position;
+		};
+		
+		enum SizeType { MinimumSize, SizeHint };
+		QSize calculateSize(SizeType sizeType) const;
+		
+		QList<PanelWrapper*> m_list;
+};
+
+#endif // _QPANEL_LAYOUT_H_
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qreliablefilewatch.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qreliablefilewatch.h"
+
+/*!
+	\file qreliablefilewatch.cpp
+	\brief Implementation of the QReliableFileWatch class.
+*/
+
+#include <QFile>
+#include <QTimerEvent>
+
+/*!
+	\class QReliableFileWatch
+	\brief A specialized file monitor that works around some issues in QFileSystemWatcher
+*/
+
+QReliableFileWatch::QReliableFileWatch(QObject *p)
+ : QFileSystemWatcher(p)
+{
+	connect(this, SIGNAL( fileChanged(QString) ),
+			this, SLOT  ( sourceChanged(QString) ) );
+	
+}
+
+QReliableFileWatch::~QReliableFileWatch()
+{
+	
+}
+
+void QReliableFileWatch::addWatch(const QString& file, QObject *recipient)
+{
+	QHash<QString, Watch>::iterator it = m_targets.find(file);
+	
+	if ( it != m_targets.end() )
+	{
+		it->recipients << recipient;
+	} else {
+		QFile f(file);
+		
+		Watch w;
+		w.state = Clean;
+		w.size = f.size();
+		w.recipients << recipient;
+		m_targets[file] = w;
+		
+		addPath(file);
+	}
+}
+
+void QReliableFileWatch::removeWatch(QObject *recipient)
+{
+	removeWatch(QString(), recipient);
+}
+
+void QReliableFileWatch::removeWatch(const QString& file, QObject *recipient)
+{
+	QHash<QString, Watch>::iterator it = m_targets.find(file);
+	
+	if ( it == m_targets.end() )
+	{
+		if ( !recipient )
+			return;
+		
+		// given recipient stop watching any file
+		
+		it = m_targets.begin();
+		
+		while ( it != m_targets.end() )
+		{
+			int n = it->recipients.removeAll(recipient);
+			
+			if ( n && it->recipients.isEmpty() )
+			{
+				// no more recipients watching this file
+				removePath(it.key());
+				it = m_targets.erase(it);
+			} else {
+				++it;
+			}
+		}
+	} else {
+		if ( recipient )
+		{
+			// given recipient stops watching given file
+			it->recipients.removeAll(recipient);
+			
+			if ( it->recipients.isEmpty() )
+			{
+				// no more recipients watching this file
+				removePath(it.key());
+				m_targets.erase(it);
+			}
+		} else {
+			// stop watching given file at all
+			m_targets.erase(it);
+		}
+	} 
+}
+
+void QReliableFileWatch::timerEvent(QTimerEvent *e)
+{
+	if ( e->timerId() != m_timer.timerId() )
+		return QFileSystemWatcher::timerEvent(e);
+	
+	int postponedEmissions = 0;
+	QHash<QString, Watch>::iterator it = m_targets.begin();
+	
+	while ( it != m_targets.end() )
+	{
+		if ( it->state & Duplicate )
+		{
+			// postpone signal emission...
+			++postponedEmissions;
+			it->state = Recent;
+		} else if ( it->state & Recent ) {
+			// send signal
+			it->state = Clean;
+			
+			QFile f(it.key());
+			
+			if ( f.size() == it->size )
+			{
+				// TODO : avoid signal emission if checksum match
+				// DO this in editor or here?
+			}
+			
+			//qDebug("%s emission.", qPrintable(it.key()));
+			
+			it->recipients.removeAll(0);
+			
+			foreach ( QObject *r, it->recipients )
+				QMetaObject::invokeMethod(r, "fileChanged", Q_ARG(QString, it.key()));
+			
+			//it = m_state.erase(it);
+		}
+		
+		++it;
+	}
+	
+	if ( postponedEmissions )
+	{
+		//qDebug("%i postponed emissions", postponedEmissions);
+		m_timer.start(20, this);
+	}
+}
+
+void QReliableFileWatch::sourceChanged(const QString& filepath)
+{
+	m_timer.stop();
+	
+	QHash<QString, Watch>::iterator it = m_targets.find(filepath);
+	
+	if ( it == m_targets.end() )
+		return;
+	
+	//qDebug("%s modified.", qPrintable(filepath));
+	
+	if ( it->state )
+	{
+		it->state = Recent | Duplicate;
+	} else {
+		it->state = Recent;
+	}
+	
+	m_timer.start(20, this);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/qreliablefilewatch.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QRELIABLE_FILE_WATCH_H_
+#define _QRELIABLE_FILE_WATCH_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qreliablefilewatch.h
+	\brief Definition of the QReliableFileWatch class
+*/
+
+#include <QHash>
+#include <QTimer>
+#include <QPointer>
+#include <QFileSystemWatcher>
+
+class QCE_EXPORT QReliableFileWatch : protected QFileSystemWatcher
+{
+	friend class QPointer<QReliableFileWatch>;
+	
+	Q_OBJECT
+	
+	public:
+		QReliableFileWatch(QObject *p = 0);
+		virtual ~QReliableFileWatch();
+		
+	public slots:
+		void addWatch(const QString& file, QObject *recipient);
+		
+		void removeWatch(QObject *recipient);
+		void removeWatch(const QString& file, QObject *recipient);
+		
+	protected:
+		virtual void timerEvent(QTimerEvent *e);
+		
+	private slots:
+		void sourceChanged(const QString& filepath);
+		
+	private:
+		enum State
+		{
+			Clean		= 0,
+			Recent		= 1,
+			Duplicate	= 2
+		};
+		
+		struct Watch
+		{
+			char state;
+			qint64 size;
+			QList< QPointer<QObject> > recipients;
+		};
+		
+		QBasicTimer m_timer;
+		
+		QHash<QString, Watch> m_targets;
+};
+
+#endif // !_QRELIABLE_FILE_WATCH_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/snippets/qsnippet.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,376 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+/*!
+	\file qsnippet.cpp
+	\brief Implementation of the builtin snippet types and loaders
+*/
+
+#include "qsnippet_p.h"
+
+#include <QMap>
+
+/*!
+	\class QSnippet
+	\brief The base class for snippets
+*/
+
+/*!
+	\class QSnippetPatternLoader
+	\brief The base class for snippet loaders
+*/
+
+QSnippetInsertionCommand::QSnippetInsertionCommand(QEditor *e)
+ : QDocumentCommandBlock(e->document()), m_editor(e), m_cursor(e->cursor())
+{
+}
+
+QSnippetInsertionCommand::~QSnippetInsertionCommand()
+{
+	foreach ( const QEditor::PlaceHolder& ph, m_placeHolders )
+		delete ph.affector;
+}
+
+void QSnippetInsertionCommand::addPlaceHolder(const QEditor::PlaceHolder& ph)
+{
+	m_placeHolders << ph;
+}
+
+void QSnippetInsertionCommand::addCommand(QDocumentCommand *c)
+{
+	c->setTargetCursor(m_cursor.handle());
+	QDocumentCommandBlock::addCommand(c);
+}
+
+void QSnippetInsertionCommand::removeCommand(QDocumentCommand *c)
+{
+	c->setTargetCursor(0);
+	QDocumentCommandBlock::removeCommand(c);
+}
+
+void QSnippetInsertionCommand::redo()
+{
+	m_editor->clearPlaceHolders();
+	QDocumentCommandBlock::redo();
+
+	foreach ( const QEditor::PlaceHolder& ph, m_placeHolders )
+		m_editor->addPlaceHolder(ph);
+	
+	m_editor->nextPlaceHolder();
+}
+
+void QSnippetInsertionCommand::undo()
+{
+	// TODO : backup and restore previous placeholders?
+	m_editor->clearPlaceHolders();
+	QDocumentCommandBlock::undo();
+	m_editor->setCursor(m_cursor);
+}
+
+//
+
+bool QCE::Snippets::PlainText::loadSnippet(QSnippet *snip, const QString& pattern)
+{
+	PlainText *target = dynamic_cast<PlainText*>(snip);
+	
+	if ( !target )
+	{
+		qWarning("snippet/loader type mismatch.");
+		return false;
+	}
+	
+	target->m_data = pattern;
+	
+	return true;
+}
+
+void QCE::Snippets::PlainText::insert(QEditor *e) const
+{
+	/*
+	QDocumentCursor c = e->cursor();
+	c.insertText(m_data);
+	e->setCursor(c);
+	*/
+	
+	e->write(m_data);
+}
+
+//
+
+QString parsePlaceHolder(const QString& s, int& index, int max, QMap<int, QCE::Snippets::Simple::PlaceHolder>& p, int& line, int& column, int baseSize)
+{
+	QChar c;
+	QStringList segments;
+	int i = index, depth = 1, last = index + 1;
+	
+	while ( i + 1 < max )
+	{
+		c = s.at(++i);
+		
+		if ( c == QLatin1Char('{') )
+		{
+			++depth;
+		} else if ( c == QLatin1Char('}') ) {
+			--depth;
+			
+			if ( !depth )
+			{
+				segments << s.mid(last, i - last);
+				break;
+			}
+		} else if ( c == QLatin1Char(':') ) {
+			if ( depth == 1 )
+			{
+				segments << s.mid(last, i - last);
+				last = i + 1;
+			}
+		}
+	}
+	
+	if ( segments.isEmpty() )
+	{
+		qWarning("invalid placeholder");
+		return QString();
+	}
+	
+	int id = segments.at(0).toInt();
+	
+	QCE::Snippets::Simple::PlaceHolder& ph = p[id];
+	
+	if ( ph.length == -1 && segments.count() > 1 )
+	{
+		// new placeholder
+		ph.length = segments.last().count();
+		ph.lineOffset = line;
+		ph.columnOffset = column;
+		ph.defaultValue = segments.last();
+		// TODO : support recursive snippetting of default value...
+	} else {
+		// mirror of an existing placeholder
+		QCE::Snippets::Simple::Anchor a;
+		a.lineOffset = line;
+		a.columnOffset = column;
+		if ( ph.defaultValue.isEmpty() )
+			ph.unresolvedMirrors << baseSize << ph.mirrors.count();
+		ph.mirrors << a;
+	}
+	
+	index = i + 1;
+	return ph.defaultValue;
+}
+
+void performRelocation(QCE::Snippets::Simple::Anchor& a, const QHash<int, QList<int> >& relocationTable, int length)
+{
+	QHash<int, QList<int> >::const_iterator reloc = relocationTable.constFind(a.lineOffset);
+	
+	if ( reloc == relocationTable.constEnd() )
+		return;
+	
+	int idx = 0;
+	int relocOffset = 0;
+	const QList<int>& offsets = *reloc;
+	
+	while ( ((idx + 1) < offsets.count()) && (offsets.at(idx) <= a.columnOffset) )
+	{
+		int off = offsets.at(++idx);
+		
+		if ( offsets.at(idx - 1) < a.columnOffset || off != length )
+			relocOffset += off;
+		
+		++idx;
+	}
+	
+	a.columnOffset += relocOffset;
+}
+
+bool QCE::Snippets::Simple::loadSnippet(QSnippet *snip, const QString& pattern)
+{
+	Simple *target = dynamic_cast<Simple*>(snip);
+	
+	if ( !target )
+	{
+		qWarning("snippet/loader type mismatch");
+		return false;
+	}
+	
+	target->m_base.clear();
+	target->m_placeHolders.clear();
+	
+	int index = 0, line = 0, column = 0, max = pattern.length();
+	
+	QString tmp;
+	QStringList base;
+	QMap<int, PlaceHolder> p;
+	
+	while ( index < max )
+	{
+		QChar c = pattern.at(index);
+		
+		if ( c == QLatin1Char('$') )
+		{
+			base << tmp;
+			tmp.clear();
+			
+			c = pattern.at(++index);
+			
+			if ( c == QLatin1Char('{') )
+			{
+				QString val = parsePlaceHolder(pattern, index, max, p, line, column, base.count());
+				base << val;
+				
+				if ( val.count() )
+				{
+					int nl = val.count(QLatin1Char('\n'));
+					
+					line += nl;
+					
+					if ( nl )
+						column = val.count() - val.lastIndexOf(QLatin1Char('\n')) - 1;
+					else
+						column += val.count();
+				}
+				continue;
+			} else {
+				if ( c != QLatin1Char('$') )
+				{
+					c = pattern.at(--index);
+				}
+				
+				++column;
+			}
+		} else if ( c == QLatin1Char('\n') ) {
+			column = 0;
+			++line;
+		} else {
+			++column;
+		}
+		
+		tmp += c;
+		++index;
+	}
+	
+	if ( tmp.count() )
+		base << tmp;
+	
+	QHash<int, QList<int> > relocationTable;
+	QMap<int, PlaceHolder>::iterator it = p.begin();
+	
+	// first : build relocation table (in case several placeholders are on same line
+	while ( it != p.end() )
+	{
+		if ( it->unresolvedMirrors.count() && it->length )
+		{
+			for ( int i = 0; i + 1 < it->unresolvedMirrors.count(); ++i )
+			{
+				int idx = it->unresolvedMirrors.at(i);
+				int anchor = it->unresolvedMirrors.at(++i);
+				
+				base[idx] = it->defaultValue;
+				
+				const Anchor& a = it->mirrors.at(anchor);
+				relocationTable[a.lineOffset] << a.columnOffset << it->length;
+			}
+			
+			it->unresolvedMirrors.clear();
+		}
+		
+		++it;
+	}
+	
+	it = p.begin();
+	
+	// then : apply relocation and store the corrected placeholder data
+	while ( it != p.end() )
+	{
+		performRelocation(*it, relocationTable, it->length);
+		
+		for ( int i = 0; i < it->mirrors.count(); ++i )
+			performRelocation(it->mirrors[i], relocationTable, it->length);
+		
+		target->m_placeHolders << *it;
+		++it;
+	}
+	
+	target->m_base = base.join(QString::null);
+	
+	return true;
+}
+
+void QCE::Snippets::Simple::insert(QEditor *e) const
+{
+	// TODO : move into command and backup for proper undo/redo
+	e->clearPlaceHolders();
+	
+	QDocument *d = e->document();
+	QDocumentCursor c = e->cursor();
+	
+	if ( c.isNull() )
+		c = QDocumentCursor(d);
+	
+	int line = qMax(c.lineNumber(), 0), column = qMax(c.columnNumber(), 0);
+	
+	if ( line != c.lineNumber() || column != c.columnNumber() )
+		c = QDocumentCursor(d, line, column);
+	
+	QSnippetInsertionCommand *cmd = new QSnippetInsertionCommand(e);
+	
+	QDocumentCommand *scmd = 0;
+	
+	if ( c.hasSelection() )
+	{
+		QDocumentSelection sel = c.selection();
+		
+		//qDebug("((%i, %i), (%i, %i))", sel.startLine, sel.start, sel.endLine, sel.end);
+		scmd = new QDocumentEraseCommand(sel.startLine, sel.start, sel.endLine, sel.end, d);
+		
+		cmd->addCommand(scmd);
+		
+		line = sel.startLine;
+		column = sel.start;
+	}
+	
+	//qDebug("%s", qPrintable(m_base));
+	
+	if ( scmd )
+	{
+		// trick to get insert command to init properly
+		scmd->redo();
+	}
+	
+	cmd->addCommand(new QDocumentInsertCommand(line, column, m_base, d));
+	
+	if ( scmd )
+	{
+		// trick to get insert command to init properly
+		scmd->undo();
+	}
+	
+	if ( m_placeHolders.count() )
+	{
+		foreach ( const PlaceHolder& ph, m_placeHolders )
+		{
+			QEditor::PlaceHolder eph;
+			eph.length = ph.length;
+			eph.cursor = QDocumentCursor(d, line + ph.lineOffset, ph.columnOffset + (ph.lineOffset ? 0 : column));
+			//eph.affector = new StubAffector;
+			foreach ( const Anchor& a, ph.mirrors )
+				eph.mirrors << QDocumentCursor(d, line + a.lineOffset, a.columnOffset + (a.lineOffset ? 0 : column));
+			
+			cmd->addPlaceHolder(eph);
+		}
+	}
+	
+	d->execute(cmd);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/snippets/qsnippet.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QSNIPPET_H_
+#define _QSNIPPET_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qsnippet.h
+	\brief Definition of the QSnippet class
+*/
+
+#include <QStringList>
+
+class QEditor;
+class QSnippetManager;
+
+#include "qsnippetpatternloader.h"
+
+class QCE_EXPORT QSnippet
+{
+	friend class QSnippetManager;
+	
+	public:
+		inline QSnippet(const QSnippetPatternLoader *pl) : m_patternLoader(pl) {}
+		virtual ~QSnippet() {}
+		
+		inline QString name() const { return m_name; }
+		inline void setName(const QString& n) { m_name = n; }
+		
+		inline QStringList contexts() const { return m_contexts; }
+		inline void setContexts(const QStringList& l) { m_contexts = l; }
+		
+		inline QString pattern() const
+		{ return m_pattern; }
+		
+		inline void setPattern(const QString& p)
+		{ m_pattern = p; m_patternLoader->reloadSnippet(this, p); }
+		
+		virtual void insert(QEditor *e) const = 0;
+		
+	protected:
+		QString m_name;
+		QString m_pattern;
+		QStringList m_contexts;
+		const QSnippetPatternLoader *m_patternLoader;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/snippets/qsnippet_p.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QSNIPPET_P_H_
+#define _QSNIPPET_P_H_
+
+/*!
+	\file qsnippet_p.h
+	\brief Definition of the QSnippetInsertionCommand class
+*/
+
+#include "qsnippet.h"
+#include "qsnippetpatternloader.h"
+
+#include "qeditor.h"
+#include "qdocument.h"
+#include "qdocumentcursor.h"
+#include "qdocumentcommand.h"
+
+class QSnippetInsertionCommand : public QDocumentCommandBlock
+{
+	public:
+		QSnippetInsertionCommand(QEditor *e);
+		virtual ~QSnippetInsertionCommand();
+		
+		void addPlaceHolder(const QEditor::PlaceHolder& ph);
+		
+		virtual void addCommand(QDocumentCommand *c);
+		virtual void removeCommand(QDocumentCommand *c);
+		
+		virtual void redo();
+		virtual void undo();
+		
+	private:
+		QEditor *m_editor;
+		QDocumentCursor m_cursor;
+		QList<QEditor::PlaceHolder> m_placeHolders;
+};
+
+#define Q_SNIPPET(T)							\
+	friend class Loader;						\
+	public:										\
+	class Loader : public QSnippetPatternLoader \
+	{											\
+		public:									\
+			virtual QString type() const { return ""#T; }								\
+			virtual QSnippet* loadSnippet(const QString& pattern) const					\
+			{																			\
+				T *snip = new T(this);													\
+				snip->m_pattern = pattern;												\
+				bool ok = reloadSnippet(snip, pattern);									\
+				if ( !ok ) { delete snip; snip = 0; }									\
+				return snip;															\
+			}																			\
+			virtual bool reloadSnippet(QSnippet* snip, const QString& pattern) const	\
+			{ return T::loadSnippet(snip, pattern); }									\
+	};																					\
+	inline T(const QSnippetPatternLoader *pl) : QSnippet(pl) {}							\
+	private:																			\
+	
+
+namespace QCE
+{
+	namespace Snippets
+	{
+		class PlainText : public QSnippet
+		{
+			Q_SNIPPET(PlainText)
+			
+			public:
+				virtual void insert(QEditor *e) const;
+				
+				static bool loadSnippet(QSnippet *snip, const QString& pattern);
+				
+				QString m_data;
+		};
+
+		class Simple : public QSnippet
+		{
+			Q_SNIPPET(Simple)
+			
+			public:
+				struct Anchor
+				{
+					Anchor() : lineOffset(0), columnOffset(0) {}
+					
+					int lineOffset;
+					int columnOffset;
+				};
+				
+				struct PlaceHolder : public Anchor
+				{
+					PlaceHolder() : length(-1) {}
+					
+					int length;
+					QString defaultValue;
+					QList<Anchor> mirrors;
+					QList<int> unresolvedMirrors;
+				};
+				
+				virtual void insert(QEditor *e) const;
+				
+				static bool loadSnippet(QSnippet *snip, const QString& pattern);
+				
+				QString m_base;
+				QList<PlaceHolder> m_placeHolders;
+		};
+	}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/snippets/qsnippetbinding.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qsnippetbinding.h"
+
+/*!
+	\file qsnippetbinding.cpp
+	\brief Implementation of the QSnippetBinding class
+*/
+
+#include "qsnippet.h"
+#include "qsnippetmanager.h"
+
+#include "qeditor.h"
+#include "qdocumentcursor.h"
+
+#include <QKeyEvent>
+
+/*
+class QSnippetCommand : public QEditorInputBinding::Command
+{
+	public:
+		QSnippetCommand(QSnippetManager *m, int idx)
+		 : index(idx), manager(m)
+		{
+			
+		}
+		
+		virtual void exec(QEditor *e)
+		{
+			if ( index < manager->snippetCount() )
+				manager->snippet(index)->insert(e);
+		}
+		
+	private:
+		int index;
+		QSnippetManager *manager;
+};
+*/
+
+class QSnippetCommand : public QEditorInputBinding::Command
+{
+	public:
+		QSnippetCommand(QSnippet *s)
+		 : snip(s)
+		{
+			
+		}
+		
+		virtual void exec(QEditor *e)
+		{
+			snip->insert(e);
+		}
+		
+	private:
+		QSnippet *snip;
+};
+
+QSnippetBinding::QSnippetBinding(QSnippetManager *manager)
+ : m_manager(manager)
+{
+	//for ( int i = 0; i < 10; ++i )
+	//	setMapping(QKeySequence(Qt::Key_F1 + i), new SnippetCommand(manager, i));
+}
+
+QString QSnippetBinding::id() const
+{
+	return "snippet binding";
+}
+
+QString QSnippetBinding::name() const
+{
+	return "snippet binding";
+}
+
+bool QSnippetBinding::keyPressEvent(QKeyEvent *event, QEditor *editor)
+{
+	/*
+	if ( event->modifiers() & Qt::ControlModifier )
+	{
+		for ( int i = 0; i < qMin(10, m->snippetCount()); ++i )
+		{
+			if ( event->key() == (Qt::Key_F1 + i) )
+			{
+				m->snippet(i)->insert(editor);
+				return true;
+			}
+		}
+	}
+	*/
+	
+	if ( (event->modifiers() & Qt::AltModifier) && (event->key() == Qt::Key_Space || event->text() == " ") )
+	{
+		QDocumentCursor c = editor->cursor();
+		
+		//c.select(QDocumentCursor::SelectWord);
+		
+		if ( !c.hasSelection() )
+		{
+			c.movePosition(1, QDocumentCursor::PreviousWord, QDocumentCursor::KeepAnchor);
+			editor->setCursor(c);
+		}
+		
+		QString s = c.selectedText();
+		
+		for ( int i = 0; i < m_manager->snippetCount(); ++i )
+		{
+			QSnippet *snip = m_manager->snippet(i);
+			
+			if ( snip->name() == s )
+			{
+				snip->insert(editor);
+				return true;
+			}
+		}
+	}
+	
+	return QEditorInputBinding::keyPressEvent(event, editor);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/snippets/qsnippetbinding.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QSNIPPET_BINDING_H_
+#define _QSNIPPET_BINDING_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qsnippetbinding.h
+	\brief Definition of the QSnippetBinding class
+*/
+
+#include "qeditorinputbinding.h"
+
+class QSnippetManager;
+
+class QCE_EXPORT QSnippetBinding : public QEditorInputBinding
+{
+	public:
+		QSnippetBinding(QSnippetManager *manager);
+		
+		virtual QString id() const;
+		virtual QString name() const;
+		
+		virtual bool keyPressEvent(QKeyEvent *event, QEditor *editor);
+		
+	private:
+		QSnippetManager *m_manager;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/snippets/qsnippetedit.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qsnippetedit.h"
+
+/*!
+	\file qsnippetedit.cpp
+	\brief Implementation of the QSnippetEdit widget
+*/
+
+#include "qsnippet.h"
+#include "qsnippetmanager.h"
+
+#include <QMessageBox>
+
+/*!
+	\class QSnippetEdit
+	\brief A widget for snippets management
+	
+	
+*/
+
+QSnippetEdit::QSnippetEdit(QWidget *p)
+ : QWidget(p), m_editedSnippet(-1), m_manager(0)
+{
+	setupUi(this);
+	setEnabled(false);
+}
+
+QSnippetEdit::QSnippetEdit(QSnippetManager *mgr, QWidget *p)
+ : QWidget(p), m_editedSnippet(-1), m_manager(0)
+{
+	setupUi(this);
+	setSnippetManager(mgr);
+}
+
+QSnippetManager* QSnippetEdit::snippetManager() const
+{
+	return m_manager;
+}
+
+void QSnippetEdit::setSnippetManager(QSnippetManager *mgr)
+{
+	if ( m_manager )
+	{
+		disconnect(	m_manager	, SIGNAL( snippetAdded(QSnippet*) ),
+					this		, SLOT  ( snippetAdded(QSnippet*) ) );
+		
+		disconnect(	m_manager	, SIGNAL( snippetRemoved(int) ),
+					this		, SLOT  ( snippetRemoved(int) ) );
+		
+		QListWidgetItem *empty = lwSnippets->takeItem(0);
+		lwSnippets->clear();
+		lwSnippets->addItem(empty);
+	}
+	
+	m_manager = mgr;
+	setEnabled(mgr);
+	
+	if ( m_manager )
+	{
+		connect(m_manager	, SIGNAL( snippetAdded(QSnippet*) ),
+				this		, SLOT  ( snippetAdded(QSnippet*) ) );
+		
+		connect(m_manager	, SIGNAL( snippetRemoved(int) ),
+				this		, SLOT  ( snippetRemoved(int) ) );
+		
+		for ( int i = 0; i < m_manager->snippetCount(); ++i )
+		{
+			lwSnippets->addItem(m_manager->snippet(i)->name());
+		}
+	}
+	
+	lwSnippets->setCurrentItem(0);
+}
+
+void QSnippetEdit::snippetRemoved(int i)
+{
+	delete lwSnippets->takeItem(i + 1);
+}
+
+void QSnippetEdit::snippetAdded(QSnippet *s)
+{
+	lwSnippets->addItem(s->name());
+}
+
+void QSnippetEdit::retranslate()
+{
+	QSnippetManager *mgr = snippetManager();
+	setSnippetManager(0);
+	
+	lwSnippets->clear();
+	retranslateUi(this);
+	
+	setSnippetManager(mgr);
+}
+
+static const QRegExp _cxt_splitter("\\s*,\\s*");
+
+bool QSnippetEdit::maybeSave()
+{
+	static const QRegExp nonTrivial("\\S");
+	
+	QString pattern = eSnippet->text();
+	
+	if ( pattern.endsWith('\n') )
+		pattern.chop(1);
+	
+	QString name = leSnippetName->text();
+	QStringList contexts = leSnippetScope->text().split(_cxt_splitter);
+	bool nonTrivialPattern = pattern.contains(nonTrivial);
+	
+	if ( m_editedSnippet >= 0 )
+	{
+		QSnippet *snip = m_manager->snippet(m_editedSnippet);
+		
+		if ( snip->pattern() != pattern )
+		{
+			int ret = QMessageBox::warning(this,
+										tr("Unsaved changes"),
+										tr("Do you want to save pattern changes to snippet %1 ?")
+											.arg(snip->name()),
+										QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
+										QMessageBox::Yes
+										);
+			
+			if ( ret == QMessageBox::Cancel )
+			{
+				return true;
+			} else if ( ret == QMessageBox::Yes ) {
+				snip->setPattern(pattern);
+			}
+		}
+	} else if ( nonTrivialPattern ) {
+		int ret = QMessageBox::warning(this,
+									tr("Unsaved changes"),
+									tr("The current snippet data will be discarded. Do you want to continue?"),
+									QMessageBox::Yes | QMessageBox::No,
+									QMessageBox::Yes
+									);
+		
+		if ( ret == QMessageBox::No )
+		{
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+void QSnippetEdit::on_lwSnippets_currentRowChanged(int idx)
+{
+	if ( (idx - 1) == m_editedSnippet )
+		return;
+	
+	if ( maybeSave() )
+	{
+		lwSnippets->setCurrentRow(m_editedSnippet);
+		return;
+	}
+	
+	m_editedSnippet = idx - 1;
+	
+	if ( idx <= 0 )
+	{
+		eSnippet->setText(QString());
+		leSnippetName->setText(QString());
+		leSnippetScope->setText(QString());
+	} else {
+		QSnippet *snip = m_manager->snippet(m_editedSnippet);
+		
+		eSnippet->setText(snip->pattern());
+		leSnippetName->setText(snip->name());
+		leSnippetScope->setText(snip->contexts().join(","));
+		//eSnippet->highlight();
+	}
+	
+	eSnippet->setFocus();
+}
+
+void QSnippetEdit::on_leSnippetName_editingFinished()
+{
+	if ( m_editedSnippet < 0 )
+		return;
+	
+	QSnippet *snip = m_manager->snippet(m_editedSnippet);
+	
+	snip->setName(leSnippetName->text());
+	
+	lwSnippets->item(m_editedSnippet + 1)->setText(snip->name());
+}
+
+void QSnippetEdit::on_leSnippetScope_editingFinished()
+{
+	if ( m_editedSnippet < 0 )
+		return;
+	
+	QSnippet *snip = m_manager->snippet(m_editedSnippet);
+	
+	snip->setContexts(leSnippetScope->text().split(_cxt_splitter));
+}
+
+void QSnippetEdit::on_tbCreateSnippet_clicked()
+{
+	QString name = leSnippetName->text();
+	QString pattern = eSnippet->text();
+	QStringList contexts = leSnippetScope->text().split(_cxt_splitter);
+	
+	if ( pattern.endsWith('\n') )
+		pattern.chop(1);
+	
+	if ( name.isEmpty() || pattern.isEmpty() )
+	{
+		QMessageBox::information(0, tr("Missing data"), tr("Please provide a name and a content to create a new snippet"));
+		return;
+	}
+	
+	// TODO : allow pattern loader choice...
+	bool ok = m_manager->loadSnippetFromString(name, pattern, "Simple");
+	
+	if ( !ok )
+	{
+		QMessageBox::warning(0, tr("Error"), tr("Invalid snippet pattern."));
+		return;
+	}
+	
+	eSnippet->setText(QString());
+	leSnippetScope->clear();
+	leSnippetName->clear();
+	
+	
+	QSnippet *snip = m_manager->snippet(m_manager->snippetCount() - 1);
+	//snip->setName(name);
+	snip->setContexts(contexts);
+	
+	
+	lwSnippets->setCurrentRow(0);
+}
+
+void QSnippetEdit::on_tbDeleteSnippet_clicked()
+{
+	int row = lwSnippets->currentRow() - 1;
+	
+	if ( row < 0 )
+	{
+		QMessageBox::warning(0, tr("Error"), tr("Please select a valid snippet to erase"));
+		return;
+	}
+	
+	m_manager->removeSnippet(row);
+}
+
+void QSnippetEdit::on_bMoreSnippets_clicked()
+{
+	
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/snippets/qsnippetedit.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QSNIPPET_EDIT_H_
+#define _QSNIPPET_EDIT_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qsnippetedit.h
+	\brief Definition of the QSnippetEdit widget
+*/
+
+#include <QWidget>
+#include "ui_snippetedit.h"
+
+class QSnippet;
+class QSnippetManager;
+
+class QCE_EXPORT QSnippetEdit : public QWidget, private Ui::SnippetEdit
+{
+	Q_OBJECT
+	
+	public:
+		QSnippetEdit(QWidget *p = 0);
+		QSnippetEdit(QSnippetManager *mgr, QWidget *p = 0);
+		
+		QSnippetManager* snippetManager() const;
+		
+	public slots:
+		void setSnippetManager(QSnippetManager *mgr);
+		
+		bool maybeSave();
+		
+		void retranslate();
+		
+	private slots:
+		void on_lwSnippets_currentRowChanged(int idx);
+		
+		void on_leSnippetName_editingFinished();
+		void on_leSnippetScope_editingFinished();
+		
+		void on_tbCreateSnippet_clicked();
+		void on_tbDeleteSnippet_clicked();
+		void on_bMoreSnippets_clicked();
+		
+		void snippetRemoved(int i);
+		void snippetAdded(QSnippet *s);
+		
+	private:
+		int m_editedSnippet;
+		QSnippetManager *m_manager;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/snippets/qsnippetmanager.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,219 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+/*!
+	\file qsnippetmanager.cpp
+	\brief Implementation of the QSnippetManager class
+*/
+
+#include "qsnippetmanager.h"
+
+#include "qsnippet_p.h"
+
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QTextStream>
+
+/*
+class StubAffector : public QEditor::PlaceHolder::Affector
+{
+	public:
+		virtual void affect(const QStringList& base, int ph, const QKeyEvent *e, int mirror, QString& after) const
+		{
+			after = after.toUpper();
+		}
+};
+*/
+
+/*!
+	\class QSnippetManager
+	\brief A class managing code snippets
+	
+	
+*/
+
+QSnippetManager::QSnippetManager(QObject *p)
+ : QObject(p)
+{
+	addPatternLoader(new QCE::Snippets::PlainText::Loader);
+	addPatternLoader(new QCE::Snippets::Simple::Loader);
+}
+
+QSnippetManager::~QSnippetManager()
+{
+	qDeleteAll(m_snippets);
+	qDeleteAll(m_patternLoaders);
+}
+
+int QSnippetManager::snippetCount() const
+{
+	return m_snippets.count();
+}
+
+QSnippet* QSnippetManager::snippet(int i) const
+{
+	return i >= 0 && i < m_snippets.count() ? m_snippets.at(i) : 0;
+}
+
+void QSnippetManager::removeSnippet(int i, bool cleanup)
+{
+	if ( i < 0 || i >= m_snippets.count() )
+		return;
+	
+	QSnippet *snip = m_snippets.takeAt(i);
+	
+	emit snippetRemoved(i);
+	emit snippetRemoved(snip);
+	
+	if ( cleanup )
+		delete snip;
+}
+
+void QSnippetManager::removeSnippet(QSnippet *snip)
+{
+	int idx = m_snippets.indexOf(snip);
+	
+	if ( idx == -1 )
+		return;
+	
+	m_snippets.removeAt(idx);
+	
+	emit snippetRemoved(idx);
+	emit snippetRemoved(snip);
+}
+
+void QSnippetManager::addSnippet(QSnippet *snip)
+{
+	if ( !snip )
+		return;
+	
+	m_snippets << snip;
+	emit snippetAdded(snip);
+}
+
+bool QSnippetManager::loadSnippetFromString(const QString& name, const QString& s, const QString& type)
+{
+	QSnippetPatternLoader *pl = patternLoader(type);
+	
+	QSnippet *snip = pl->loadSnippet(s);
+	
+	if ( snip )
+		snip->setName(name);
+	
+	addSnippet(snip);
+	
+	return snip;
+}
+
+bool QSnippetManager::loadSnippetFromFile(const QString& file, const QString& type)
+{
+	QFile f(file);
+	
+	if ( !f.open(QFile::ReadOnly | QFile::Text) )
+	{
+		qWarning("Unable to load snippet from %s", qPrintable(file));
+		return false;
+	}
+	
+	//qDebug("loading from : %s", qPrintable(file));
+	
+	QString s = QString::fromLocal8Bit(f.readAll());
+	
+	static const QRegExp meta("# name:(\\S+) context:(\\S*)[^\n]*\n");
+	
+	int idx = meta.indexIn(s);
+	bool metaMatch = idx != -1;
+	
+	if ( metaMatch )
+	{
+		//qDebug("meta! : %i => %s", idx, qPrintable(meta.cap(0)));
+		s.remove(idx, meta.matchedLength());
+	}
+	
+	if ( s.endsWith('\n') )
+		s.chop(1);
+	
+	bool ok = loadSnippetFromString(metaMatch ? meta.cap(1) : QFileInfo(file).baseName(), s, type);
+	
+	if ( ok )
+	{
+		QSnippet *snip = m_snippets.last();
+		snip->setContexts(metaMatch ? meta.cap(2).split(",") : QStringList("all"));
+	}
+	
+	return ok;
+}
+
+QSnippetPatternLoader* QSnippetManager::patternLoader(const QString& type) const
+{
+	foreach ( QSnippetPatternLoader *pl, m_patternLoaders )
+	{
+		if ( pl->type() == type )
+			return pl;
+	}
+	
+	return 0;
+}
+
+void QSnippetManager::saveSnippetsToDirectory(const QString& path)
+{
+	QDir d(path);
+	
+	foreach ( QSnippet *snip, m_snippets )
+	{
+		QFile f(d.filePath(snip->name() + ".qcs"));
+		
+		if ( !f.open(QFile::WriteOnly | QFile::Text) )
+			continue;
+		
+		QTextStream s(&f);
+		s << "# name:" << snip->name() << " context:" << snip->contexts().join(",") << endl;
+		s << snip->pattern();
+	}
+}
+
+void QSnippetManager::loadSnippetsFromDirectory(const QString& path)
+{
+	QDir d(path);
+	
+	QFileInfoList l = d.entryInfoList(QDir::Files | QDir::Readable);
+	
+	foreach ( const QFileInfo& info, l )
+	{
+		if ( info.suffix() != "qcs" )
+			continue;
+		
+		// TODO : pattern selection?
+		loadSnippetFromFile(info.absoluteFilePath(), "Simple");
+	}
+}
+
+void QSnippetManager::addPatternLoader(QSnippetPatternLoader *pl)
+{
+	m_patternLoaders << pl;
+}
+
+void QSnippetManager::removePatternLoader(QSnippetPatternLoader *pl)
+{
+	m_patternLoaders.removeAll(pl);
+}
+
+QString QSnippetManager::typeGuess(const QString& pattern) const
+{
+	Q_UNUSED(pattern)
+	
+	return "Simple";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/snippets/qsnippetmanager.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QSNIPPET_MANAGER_H_
+#define _QSNIPPET_MANAGER_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qsnippetmanager.h
+	\brief Definition of the QSnippetManager class
+*/
+
+#include <QStringList>
+
+class QSnippet;
+class QSnippetPatternLoader;
+
+class QCE_EXPORT QSnippetManager : public QObject
+{
+	Q_OBJECT
+	
+	public:
+		QSnippetManager(QObject *p = 0);
+		virtual ~QSnippetManager();
+		
+		int snippetCount() const;
+		QSnippet* snippet(int i) const;
+		void removeSnippet(int i, bool cleanup = true);
+		
+		bool loadSnippetFromFile(const QString& file, const QString& type = QString());
+		bool loadSnippetFromString(const QString& name, const QString& pattern, const QString& type = QString());
+		
+		void saveSnippetsToDirectory(const QString& path);
+		void loadSnippetsFromDirectory(const QString& path);
+		
+	public slots:
+		void addSnippet(QSnippet *s);
+		void removeSnippet(QSnippet *s);
+		
+		void addPatternLoader(QSnippetPatternLoader *pl);
+		void removePatternLoader(QSnippetPatternLoader *pl);
+		
+	signals:
+		void snippetAdded(QSnippet *s);
+		
+		void snippetRemoved(int i);
+		void snippetRemoved(QSnippet *s);
+		
+	private:
+		QString typeGuess(const QString& pattern) const;
+		QSnippetPatternLoader* patternLoader(const QString& type) const;
+		
+		QList<QSnippet*> m_snippets;
+		QList<QSnippetPatternLoader*> m_patternLoaders;
+};
+
+#endif // !_SNIPPETS_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/snippets/qsnippetpatternloader.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QSNIPPET_PATTERN_LOADER_H_
+#define _QSNIPPET_PATTERN_LOADER_H_
+
+/*!
+	\file qsnippetpatternloader.h
+	\brief Definition of the QSnippetPatternLoader class
+*/
+
+class QString;
+
+class QSnippet;
+
+class QSnippetPatternLoader
+{
+	public:
+		virtual ~QSnippetPatternLoader() {}
+		
+		virtual QString type() const = 0;
+		
+		virtual QSnippet* loadSnippet(const QString& pattern) const = 0;
+		virtual bool reloadSnippet(QSnippet* snip, const QString& pattern) const = 0;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/snippets/snippetedit.ui	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SnippetEdit</class>
+ <widget class="QWidget" name="SnippetEdit">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>548</width>
+    <height>486</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string/>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0" rowspan="4" colspan="5">
+    <widget class="QListWidget" name="lwSnippets">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Maximum" vsizetype="Expanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>200</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <item>
+      <property name="text">
+       <string>empty</string>
+      </property>
+      <property name="icon">
+       <iconset>
+        <normaloff>new.png</normaloff>new.png</iconset>
+      </property>
+     </item>
+    </widget>
+   </item>
+   <item row="0" column="5">
+    <widget class="QLabel" name="label">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>Edit snippet</string>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="5" colspan="2">
+    <widget class="QEditor" name="eSnippet">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="frameShape">
+      <enum>QFrame::StyledPanel</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Raised</enum>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="5">
+    <widget class="QLabel" name="label_5">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text">
+      <string>Name/trigger</string>
+     </property>
+     <property name="buddy">
+      <cstring>leSnippetName</cstring>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="6">
+    <widget class="QLineEdit" name="leSnippetName">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="toolTip">
+      <string>Enter the name of the code snippet, which will also be its full-text trigger, if enabled.</string>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="5">
+    <widget class="QLabel" name="label_6">
+     <property name="text">
+      <string>Scope(s)</string>
+     </property>
+     <property name="buddy">
+      <cstring>leSnippetScope</cstring>
+     </property>
+    </widget>
+   </item>
+   <item row="3" column="6">
+    <widget class="QLineEdit" name="leSnippetScope">
+     <property name="toolTip">
+      <string>Enter a coma-separated list of languages in which the snippet can be used.</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="5" colspan="2">
+    <spacer name="verticalSpacer">
+     <property name="orientation">
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Preferred</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>20</width>
+       <height>40</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="4" column="3">
+    <widget class="QPushButton" name="bMoreSnippets">
+     <property name="text">
+      <string>More</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="2">
+    <spacer name="horizontalSpacer">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="sizeType">
+      <enum>QSizePolicy::Preferred</enum>
+     </property>
+     <property name="sizeHint" stdset="0">
+      <size>
+       <width>40</width>
+       <height>20</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+   <item row="4" column="1">
+    <widget class="QToolButton" name="tbDeleteSnippet">
+     <property name="text">
+      <string>-</string>
+     </property>
+    </widget>
+   </item>
+   <item row="4" column="0">
+    <widget class="QToolButton" name="tbCreateSnippet">
+     <property name="text">
+      <string>+</string>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>QEditor</class>
+   <extends>QFrame</extends>
+   <header>qeditor.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <tabstops>
+  <tabstop>lwSnippets</tabstop>
+  <tabstop>leSnippetName</tabstop>
+  <tabstop>leSnippetScope</tabstop>
+  <tabstop>tbCreateSnippet</tabstop>
+  <tabstop>tbDeleteSnippet</tabstop>
+  <tabstop>bMoreSnippets</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/editconfig.ui	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,325 @@
+<ui version="4.0" >
+ <class>EditorConfig</class>
+ <widget class="QWidget" name="EditorConfig" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>575</width>
+    <height>586</height>
+   </rect>
+  </property>
+  <layout class="QVBoxLayout" >
+   <item>
+    <widget class="QGroupBox" name="gbFont" >
+     <property name="sizePolicy" >
+      <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title" >
+      <string>Font</string>
+     </property>
+     <layout class="QGridLayout" >
+      <property name="margin" >
+       <number>4</number>
+      </property>
+      <item row="0" column="0" >
+       <widget class="QFontComboBox" name="cbFont" >
+        <property name="font" >
+         <font>
+          <family>Monospace</family>
+         </font>
+        </property>
+        <property name="currentFont" >
+         <font>
+          <family>DejaVu Sans Mono</family>
+         </font>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1" >
+       <widget class="QSpinBox" name="spnFontSize" >
+        <property name="buttonSymbols" >
+         <enum>QAbstractSpinBox::UpDownArrows</enum>
+        </property>
+        <property name="minimum" >
+         <number>6</number>
+        </property>
+        <property name="maximum" >
+         <number>50</number>
+        </property>
+        <property name="value" >
+         <number>10</number>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="0" colspan="3" >
+       <widget class="QLabel" name="lblSampleText" >
+        <property name="sizePolicy" >
+         <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="font" >
+         <font>
+          <family>Monospace</family>
+         </font>
+        </property>
+        <property name="frameShape" >
+         <enum>QFrame::StyledPanel</enum>
+        </property>
+        <property name="frameShadow" >
+         <enum>QFrame::Sunken</enum>
+        </property>
+        <property name="text" >
+         <string>text which &lt;i>should&lt;/i> be a &lt;b>fair&lt;/b> test of the font</string>
+        </property>
+        <property name="alignment" >
+         <set>Qt::AlignCenter</set>
+        </property>
+        <property name="margin" >
+         <number>0</number>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="2" >
+       <spacer>
+        <property name="orientation" >
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0" >
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="gbTabs" >
+     <property name="sizePolicy" >
+      <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="title" >
+      <string>Tabulators &amp;&amp; Whitespaces</string>
+     </property>
+     <layout class="QVBoxLayout" >
+      <property name="margin" >
+       <number>5</number>
+      </property>
+      <item>
+       <layout class="QHBoxLayout" >
+        <item>
+         <widget class="QLabel" name="lblTabWitdh" >
+          <property name="sizePolicy" >
+           <sizepolicy vsizetype="Preferred" hsizetype="Minimum" >
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="text" >
+           <string>Tab width</string>
+          </property>
+          <property name="buddy" >
+           <cstring>spnTabWidth</cstring>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <widget class="QSpinBox" name="spnTabWidth" >
+          <property name="value" >
+           <number>4</number>
+          </property>
+         </widget>
+        </item>
+        <item>
+         <spacer>
+          <property name="orientation" >
+           <enum>Qt::Horizontal</enum>
+          </property>
+          <property name="sizeHint" stdset="0" >
+           <size>
+            <width>40</width>
+            <height>20</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="chkShowLeadingWhitespace" >
+        <property name="text" >
+         <string>Show leading whitespaces</string>
+        </property>
+        <property name="checked" >
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="chkShowTabsInText" >
+        <property name="text" >
+         <string>Show tabs which are neither leading nor trailing</string>
+        </property>
+        <property name="checked" >
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="chkShowTrailingWhitespace" >
+        <property name="text" >
+         <string>Show trailing whitespaces</string>
+        </property>
+        <property name="checked" >
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="chkReplaceTabs" >
+        <property name="text" >
+         <string>Replace tabs by blanks</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="gbEncodings" >
+     <property name="title" >
+      <string>Load &amp;&amp; Save</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout" >
+      <item row="0" column="0" >
+       <widget class="QLabel" name="label" >
+        <property name="text" >
+         <string>Default encoding</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1" >
+       <widget class="QComboBox" name="cbEncoding" />
+      </item>
+      <item row="1" column="0" >
+       <widget class="QCheckBox" name="chkDetectLE" >
+        <property name="text" >
+         <string>Preserve line endings</string>
+        </property>
+        <property name="checked" >
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1" >
+       <widget class="QComboBox" name="cbLineEndings" >
+        <property name="enabled" >
+         <bool>false</bool>
+        </property>
+        <item>
+         <property name="text" >
+          <string>Local</string>
+         </property>
+        </item>
+        <item>
+         <property name="text" >
+          <string>Unix/Linux</string>
+         </property>
+        </item>
+        <item>
+         <property name="text" >
+          <string>DOS/Windows</string>
+         </property>
+        </item>
+        <item>
+         <property name="text" >
+          <string>Old Mac</string>
+         </property>
+        </item>
+       </widget>
+      </item>
+      <item row="2" column="0" >
+       <widget class="QCheckBox" name="chkAutoRemoveTrailingWhitespace" >
+        <property name="text" >
+         <string>Remove trailing spaces</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="1" >
+       <widget class="QCheckBox" name="chkPreserveTrailingIndent" >
+        <property name="enabled" >
+         <bool>false</bool>
+        </property>
+        <property name="text" >
+         <string>Preserve trailing indent</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <spacer>
+     <property name="orientation" >
+      <enum>Qt::Vertical</enum>
+     </property>
+     <property name="sizeType" >
+      <enum>QSizePolicy::MinimumExpanding</enum>
+     </property>
+     <property name="sizeHint" stdset="0" >
+      <size>
+       <width>492</width>
+       <height>10</height>
+      </size>
+     </property>
+    </spacer>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>chkDetectLE</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>cbLineEndings</receiver>
+   <slot>setDisabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>190</x>
+     <y>445</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>279</x>
+     <y>444</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>chkAutoRemoveTrailingWhitespace</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>chkPreserveTrailingIndent</receiver>
+   <slot>setEnabled(bool)</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>176</x>
+     <y>475</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>287</x>
+     <y>479</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/formatconfig.ui	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,114 @@
+<ui version="4.0" >
+ <class>FormatConfig</class>
+ <widget class="QWidget" name="FormatConfig" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>539</width>
+    <height>383</height>
+   </rect>
+  </property>
+  <property name="sizePolicy" >
+   <sizepolicy vsizetype="MinimumExpanding" hsizetype="MinimumExpanding" >
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle" >
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout" >
+   <item>
+    <widget class="QFrame" name="m_frame" >
+     <property name="frameShape" >
+      <enum>QFrame::NoFrame</enum>
+     </property>
+     <property name="frameShadow" >
+      <enum>QFrame::Plain</enum>
+     </property>
+     <layout class="QGridLayout" name="gridLayout" >
+      <item row="0" column="0" >
+       <widget class="QLabel" name="label" >
+        <property name="text" >
+         <string>Scheme :</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1" >
+       <widget class="QComboBox" name="m_selector" />
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QTableWidget" name="m_table" >
+     <property name="sizePolicy" >
+      <sizepolicy vsizetype="MinimumExpanding" hsizetype="MinimumExpanding" >
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="selectionMode" >
+      <enum>QAbstractItemView::NoSelection</enum>
+     </property>
+     <property name="selectionBehavior" >
+      <enum>QAbstractItemView::SelectRows</enum>
+     </property>
+     <column>
+      <property name="text" >
+       <string>Identifier</string>
+      </property>
+     </column>
+     <column>
+      <property name="text" >
+       <string/>
+      </property>
+     </column>
+     <column>
+      <property name="text" >
+       <string/>
+      </property>
+     </column>
+     <column>
+      <property name="text" >
+       <string/>
+      </property>
+     </column>
+     <column>
+      <property name="text" >
+       <string>O</string>
+      </property>
+     </column>
+     <column>
+      <property name="text" >
+       <string/>
+      </property>
+     </column>
+     <column>
+      <property name="text" >
+       <string>W</string>
+      </property>
+     </column>
+     <column>
+      <property name="text" >
+       <string/>
+      </property>
+     </column>
+     <column>
+      <property name="text" >
+       <string/>
+      </property>
+     </column>
+     <column>
+      <property name="text" >
+       <string/>
+      </property>
+     </column>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/gotoline.ui	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>GotoLine</class>
+ <widget class="QWidget" name="GotoLine">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>513</width>
+    <height>45</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QHBoxLayout" name="horizontalLayout">
+   <item>
+    <widget class="QToolButton" name="bClose">
+     <property name="text">
+      <string/>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="text">
+      <string>&amp;Go to line :</string>
+     </property>
+     <property name="buddy">
+      <cstring>spLine</cstring>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QSpinBox" name="spLine">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="prefix">
+      <string> </string>
+     </property>
+     <property name="minimum">
+      <number>1</number>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QPushButton" name="bGo">
+     <property name="text">
+      <string>G&amp;o</string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QSlider" name="slLine">
+     <property name="minimum">
+      <number>1</number>
+     </property>
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>spLine</tabstop>
+  <tabstop>bGo</tabstop>
+  <tabstop>bClose</tabstop>
+  <tabstop>slLine</tabstop>
+ </tabstops>
+ <resources/>
+ <connections/>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/gotolinedialog.ui	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,147 @@
+<ui version="4.0" >
+ <class>GotoDialog</class>
+ <widget class="QDialog" name="GotoDialog" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>210</width>
+    <height>103</height>
+   </rect>
+  </property>
+  <property name="sizePolicy" >
+   <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle" >
+   <string>Goto line ...</string>
+  </property>
+  <layout class="QGridLayout" >
+   <item row="0" column="0" colspan="2" >
+    <widget class="QLabel" name="label" >
+     <property name="sizePolicy" >
+      <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="text" >
+      <string>Select the line you want to go to :</string>
+     </property>
+     <property name="buddy" >
+      <cstring>spinLine</cstring>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="0" >
+    <widget class="QSlider" name="slideLine" >
+     <property name="minimum" >
+      <number>1</number>
+     </property>
+     <property name="orientation" >
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item row="1" column="1" >
+    <widget class="QSpinBox" name="spinLine" >
+     <property name="sizePolicy" >
+      <sizepolicy vsizetype="Fixed" hsizetype="Minimum" >
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="prefix" >
+      <string>line </string>
+     </property>
+     <property name="minimum" >
+      <number>1</number>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="2" >
+    <widget class="QDialogButtonBox" name="buttonBox" >
+     <property name="standardButtons" >
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <tabstops>
+  <tabstop>spinLine</tabstop>
+  <tabstop>slideLine</tabstop>
+  <tabstop>buttonBox</tabstop>
+ </tabstops>
+ <resources>
+  <include location="../../../../src/lib/images/Edyuk.qrc" />
+ </resources>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>GotoDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>67</x>
+     <y>165</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>205</x>
+     <y>64</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>GotoDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>44</x>
+     <y>164</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>30</x>
+     <y>67</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>slideLine</sender>
+   <signal>sliderMoved(int)</signal>
+   <receiver>spinLine</receiver>
+   <slot>setValue(int)</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>35</x>
+     <y>99</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>299</x>
+     <y>100</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>spinLine</sender>
+   <signal>valueChanged(int)</signal>
+   <receiver>slideLine</receiver>
+   <slot>setValue(int)</slot>
+   <hints>
+    <hint type="sourcelabel" >
+     <x>299</x>
+     <y>112</y>
+    </hint>
+    <hint type="destinationlabel" >
+     <x>82</x>
+     <y>99</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qcalltip.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,274 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qcalltip.h"
+
+/*!
+	\file qcalltip.cpp
+	\brief Implementation of the QCallTip class
+*/
+
+#include <QPainter>
+#include <QMouseEvent>
+
+/*!
+	\class QCallTip
+	\brief A widget dedicated to calltips display
+*/
+
+QCallTip::QCallTip(QWidget *p)
+ : QWidget(p), m_index(0)
+{
+	setCursor(Qt::ArrowCursor);
+	setFocusPolicy(Qt::StrongFocus);
+	setAttribute(Qt::WA_DeleteOnClose);
+}
+
+QCallTip::~QCallTip()
+{
+	
+}
+
+QStringList QCallTip::tips() const
+{
+	return m_tips;
+}
+
+void QCallTip::setTips(const QStringList& l)
+{
+	m_tips = l;
+	m_index = 0;
+}
+
+static int arrowWidth = 14;
+
+void QCallTip::paintEvent(QPaintEvent *e)
+{
+	Q_UNUSED(e)
+	
+	QPainter p(this);
+	QFontMetrics fm = fontMetrics();
+	
+	m_up = m_down = QRect();
+	
+	bool bPrev = m_index, bNext = (m_index + 1) < m_tips.count();
+	int offset = 3, whalf = arrowWidth / 2 - 3; //, hhalf = height() / 2;
+	
+	QRect bg(0, 0, fm.width(m_tips.at(m_index)) + 6, fm.height());
+	
+	if ( bPrev )
+	{
+		bg.setWidth(bg.width() + arrowWidth);
+	}
+	
+	if ( bNext )
+	{
+		bg.setWidth(bg.width() + arrowWidth);
+	}
+	
+	p.fillRect(bg, QColor(0xca, 0xff, 0x70));
+	//p.drawRect(bg);
+	
+	p.save();
+	
+	p.setPen(QColor(0x00, 0x00, 0x00));
+	p.drawLine(0, height() - 1, bg.width() - 1, height() - 1);
+	p.drawLine(bg.width() - 1, height() - 1, bg.width() - 1, 0);
+	
+	p.setPen(QColor(0xc0, 0xc0, 0xc0));
+	p.drawLine(0, height() - 1, 0, 0);
+	p.drawLine(0, 0, bg.width() - 1, 0);
+	
+	p.restore();
+	
+	int top = height() / 3, bottom = height() - height() / 3;
+	
+	if ( bPrev )
+	{
+		int x = offset + arrowWidth / 2 - 1;
+		
+		QPoint pts[] = {
+			QPoint(x - whalf, bottom),
+			QPoint(x + whalf, bottom),
+			QPoint(x, top)
+		};
+		
+		p.drawPolygon(pts, sizeof(pts) / sizeof(QPoint), Qt::WindingFill);
+		
+		m_up = QRect(offset, 0, offset + arrowWidth, height());
+		offset += arrowWidth;
+	}
+	
+	if ( bNext )
+	{
+		int x = offset + arrowWidth / 2 - 1;
+		
+		QPoint pts[] = {
+			QPoint(x - whalf, top),
+			QPoint(x + whalf, top),
+			QPoint(x, bottom)
+		};
+		
+		p.drawPolygon(pts, sizeof(pts) / sizeof(QPoint), Qt::WindingFill);
+		
+		m_down = QRect(offset, 0, offset + arrowWidth, height());
+		offset += arrowWidth;
+	}
+	
+	p.drawText(offset, fm.ascent() + 2, m_tips.at(m_index));
+	
+	setFixedSize(bg.size() + QSize(1, 1));
+}
+
+void QCallTip::keyPressEvent(QKeyEvent *e)
+{
+	if ( e->modifiers() & (Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier) )
+	{
+		close();
+		
+		if ( parentWidget() )
+			parentWidget()->setFocus();
+		
+		e->ignore();
+		return;
+	}
+	
+	QString prefix, text = e->text();
+	
+	switch ( e->key() )
+	{
+		case Qt::Key_Escape :
+			close();
+			
+			if ( parentWidget() )
+				parentWidget()->setFocus();
+			
+			e->accept();
+			break;
+			
+		case Qt::Key_Enter :
+		case Qt::Key_Return :
+		case Qt::Key_Tab :
+			//hide();
+			
+			close();
+			
+			if ( parentWidget() )
+				parentWidget()->setFocus();
+			
+			e->ignore();
+			
+			break;
+			
+		case Qt::Key_Up :
+			
+			if ( m_index )
+				--m_index;
+			
+			e->accept();
+			update();
+			break;
+			
+		case Qt::Key_Down :
+			
+			if ( (m_index + 1) < m_tips.count() )
+				++m_index;
+			
+			e->accept();
+			update();
+			break;
+			
+		case Qt::Key_Backspace :
+			
+			close();
+			
+			if ( parentWidget() )
+				parentWidget()->setFocus();
+			
+			e->ignore();
+			break;
+			
+		case Qt::Key_Shift :
+		case Qt::Key_Alt :
+		case Qt::Key_Control :
+			e->ignore();
+			break;
+			
+		default:
+			
+			if ( text.count() && text.at(0).isPrint() )
+			{
+				
+			} else {
+				close();
+				
+				if ( parentWidget() )
+					parentWidget()->setFocus();
+				
+			}
+			
+			e->ignore();
+			
+			break;
+	}
+}
+
+void QCallTip::focusInEvent(QFocusEvent *e)
+{
+	QWidget::focusInEvent(e);
+}
+
+void QCallTip::focusOutEvent(QFocusEvent *e)
+{
+	QWidget::focusOutEvent(e);
+	
+	close();
+	
+	if ( parentWidget() )
+		parentWidget()->setFocus();
+	
+}
+
+void QCallTip::mousePressEvent(QMouseEvent *e)
+{
+	if ( m_index && m_up.isValid() && m_up.contains(e->pos()) )
+	{
+		--m_index;
+	} else if (
+			((m_index + 1) < m_tips.count())
+		&&
+			m_down.isValid()
+		&&
+			m_down.contains(e->pos())
+		)
+	{
+		++m_index;
+	} else {
+		close();
+		
+		if ( parentWidget() )
+			parentWidget()->setFocus();
+		
+	}
+	
+	e->accept();
+	
+	update();
+}
+
+void QCallTip::mouseReleaseEvent(QMouseEvent *e)
+{
+	e->accept();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qcalltip.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QCALL_TIP_H_
+#define _QCALL_TIP_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qcalltip.h
+	\brief Definition of the QCallTip class
+*/
+
+#include <QWidget>
+
+class QCE_EXPORT QCallTip : public QWidget
+{
+	public:
+		QCallTip(QWidget *p = 0);
+		virtual ~QCallTip();
+		
+		QStringList tips() const;
+		void setTips(const QStringList& l);
+		
+	protected:
+		virtual void paintEvent(QPaintEvent *e);
+		virtual void keyPressEvent(QKeyEvent *e);
+		virtual void focusInEvent(QFocusEvent *e);
+		virtual void focusOutEvent(QFocusEvent *e);
+		virtual void mousePressEvent(QMouseEvent *e);
+		virtual void mouseReleaseEvent(QMouseEvent *e);
+		
+	private:
+		int m_index;
+		QStringList m_tips;
+		QRect m_up, m_down;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qeditconfig.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,614 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qeditconfig.h"
+
+/*!
+	\file qeditconfig.cpp
+	\brief Implementation of the QEditConfig class.
+	
+	\see QEditConfig
+*/
+
+#include "qeditor.h"
+#include "qdocument.h"
+#include "qdocument_p.h"
+
+#include <QDebug>
+#include <QTextCodec>
+
+/*!
+	\ingroup dialogs
+	@{
+	
+	\class QEditConfig
+	\brief A minimalistic, easy to embed, settings widget.
+	
+*/
+
+QEditConfig::QEditConfig(QWidget *w)
+ : QWidget(w), m_direct(false)
+{
+	setupUi(this);
+	
+	QStringList l;
+	QList<QByteArray> ens = QTextCodec::availableCodecs();
+	
+	foreach ( QByteArray b, ens )
+		l << QString::fromLatin1(b);
+	
+	cbEncoding->clear();
+	cbEncoding->addItems(l);
+	
+	restore();
+}
+
+/*!
+	\brief run-time translation entry point
+*/
+void QEditConfig::retranslate()
+{
+	retranslateUi(this);
+}
+
+/*!
+	\brief
+*/
+bool QEditConfig::hasUnsavedChanges() const
+{
+	if ( m_direct )
+		return false;
+	
+	QFont font = cbFont->currentFont();
+	//font.setPointSize(spnFontSize->value());
+	
+	const QFont& docFont = QDocument::font();
+	
+	if ( font.family() != docFont.family() || spnFontSize->value() != docFont.pointSize() )
+	{
+		//qDebug("font!");
+		return true;
+	}
+	
+	if ( spnTabWidth->value() != QDocument::tabStop() )
+	{
+		//qDebug("tab stop!");
+		return true;
+	}
+	
+	QDocument::LineEnding le = QDocument::defaultLineEnding();
+	
+	if ( chkDetectLE->isChecked() )
+	{
+		if ( le != QDocument::Conservative )
+		{
+			//qDebug("conservative line endings! : %i", le);
+			return true;
+		}
+	} else {
+		if ( le != QDocument::LineEnding(cbLineEndings->currentIndex() + 1) )
+		{
+			//qDebug("line endings!");
+			return true;
+		}
+	}
+	
+	QDocument::WhiteSpaceMode ws = QDocument::ShowNone;
+	
+	if ( chkShowLeadingWhitespace->isChecked() )
+		ws |= QDocument::ShowLeading;
+	
+	if ( chkShowTrailingWhitespace->isChecked() )
+		ws |= QDocument::ShowTrailing;
+	
+	if ( chkShowTabsInText->isChecked() )
+		ws |= QDocument::ShowTabs;
+	
+	if ( ws != QDocument::showSpaces() )
+	{
+		//qDebug("spaces!");
+		return true;
+	}
+	
+	QTextCodec *c = QEditor::defaultCodec();
+	
+	if ( cbEncoding->currentText() == "System" )
+	{
+		if ( c && c->name() != "System" )
+		{
+			//qDebug("system codec!");
+			return true;
+		}
+	} else {
+		if ( !c || c->name() != cbEncoding->currentText().toLatin1() )
+		{
+			//qDebug("codec!");
+			return true;
+		}
+	}
+	
+	int flags = QEditor::defaultFlags();
+	
+	if ( chkReplaceTabs->isChecked() )
+		flags |= QEditor::ReplaceTabs;
+	else
+		flags &= ~QEditor::ReplaceTabs;
+	
+	if ( chkAutoRemoveTrailingWhitespace->isChecked() )
+		flags |= QEditor::RemoveTrailing;
+	else
+		flags &= ~QEditor::RemoveTrailing;
+	
+	if ( chkPreserveTrailingIndent->isChecked() )
+		flags |= QEditor::PreserveTrailingIndent;
+	else
+		flags &= ~QEditor::PreserveTrailingIndent;
+	
+	if ( flags != QEditor::defaultFlags() )
+	{
+		//qDebug("flags!");
+		return true;
+	}
+	
+	return false;
+}
+
+/*!
+	\return whether user changes are immediately applied
+*/
+bool QEditConfig::applyImmediately() const
+{
+	return m_direct;
+}
+
+/*!
+	\brief Set whether user changes are immediately applied
+*/
+void QEditConfig::setApplyImmediately(bool y)
+{
+	m_direct = y;
+}
+
+/*!
+	\brief Apply changes
+*/
+void QEditConfig::apply()
+{
+	QFont font = cbFont->currentFont();
+	font.setPointSize(spnFontSize->value());
+	
+	QDocument::setFont(font);
+	QDocument::setTabStop(spnTabWidth->value());
+	
+	if ( chkDetectLE->isChecked() )
+		QDocument::setDefaultLineEnding(QDocument::Conservative);
+	else
+		QDocument::setDefaultLineEnding(QDocument::LineEnding(cbLineEndings->currentIndex() + 1));
+	
+	QDocument::WhiteSpaceMode ws = QDocument::ShowNone;
+	
+	if ( chkShowLeadingWhitespace->isChecked() )
+		ws |= QDocument::ShowLeading;
+	
+	if ( chkShowTrailingWhitespace->isChecked() )
+		ws |= QDocument::ShowTrailing;
+	
+	if ( chkShowTabsInText->isChecked() )
+		ws |= QDocument::ShowTabs;
+	
+	QDocument::setShowSpaces(ws);
+	
+	if ( cbEncoding->currentText() == "System" )
+		QEditor::setDefaultCodec(0, QEditor::UpdateAll);
+	else
+		QEditor::setDefaultCodec(cbEncoding->currentText().toLatin1(), QEditor::UpdateAll);
+	
+	int flags = QEditor::defaultFlags();
+	
+	if ( chkReplaceTabs->isChecked() )
+		flags |= QEditor::ReplaceTabs;
+	else
+		flags &= ~QEditor::ReplaceTabs;
+	
+	if ( chkAutoRemoveTrailingWhitespace->isChecked() )
+		flags |= QEditor::RemoveTrailing;
+	else
+		flags &= ~QEditor::RemoveTrailing;
+	
+	if ( chkPreserveTrailingIndent->isChecked() )
+		flags |= QEditor::PreserveTrailingIndent;
+	else
+		flags &= ~QEditor::PreserveTrailingIndent;
+	
+	QEditor::setDefaultFlags(flags);
+}
+
+/*!
+	\brief Reset the subcontrols to reflect the current settings
+	
+	The name can be a bit misleading at first, it has been chosen
+	because it directly maps to the effect a "cancel" button would
+	have on the widget
+*/
+void QEditConfig::cancel()
+{
+	// reload the current config
+	
+	bool oldDir = m_direct;
+	
+	m_direct = false;
+	
+	cbFont->setFont(QDocument::font());
+	spnFontSize->setValue(QDocument::font().pointSize());
+	
+	spnTabWidth->setValue(QDocument::tabStop());
+	
+	QDocument::WhiteSpaceMode ws = QDocument::showSpaces();
+	chkShowTabsInText->setChecked(ws & QDocument::ShowTabs);
+	chkShowLeadingWhitespace->setChecked(ws & QDocument::ShowLeading);
+	chkShowTrailingWhitespace->setChecked(ws & QDocument::ShowTrailing);
+	
+	QDocument::LineEnding le = QDocument::defaultLineEnding();
+	chkDetectLE->setChecked(le == QDocument::Conservative);
+	cbLineEndings->setCurrentIndex(le ? le - 1 : 0);
+	
+	int flags = QEditor::defaultFlags();
+	chkReplaceTabs->setChecked(flags & QEditor::ReplaceTabs);
+	chkAutoRemoveTrailingWhitespace->setChecked(flags & QEditor::RemoveTrailing);
+	chkPreserveTrailingIndent->setChecked(flags & QEditor::PreserveTrailingIndent);
+	
+	QTextCodec *c = QEditor::defaultCodec();
+	cbEncoding->setCurrentIndex(cbEncoding->findText(c ? c->name() : QTextCodec::codecForLocale()->name()));
+	
+	m_direct = oldDir;
+}
+
+/*!
+	\brief Restore default values for all subcontrols
+	
+	\note The widgets are changed but these changes are NOT applied.
+*/
+void QEditConfig::restore()
+{
+	// restore default configuration
+	
+	bool oldDir = m_direct;
+	
+	m_direct = false;
+	
+	QFont font("Monospace", 10);
+	font.setStyleHint(QFont::Courier);
+	
+	cbFont->setFont(font);
+	spnFontSize->setValue(10);
+	
+	spnTabWidth->setValue(4);
+	
+	chkShowTabsInText->setChecked(true);
+	chkShowLeadingWhitespace->setChecked(true);
+	chkShowTrailingWhitespace->setChecked(true);
+	
+	chkDetectLE->setChecked(true);
+	cbLineEndings->setCurrentIndex(0);
+	
+	chkReplaceTabs->setChecked(false);
+	chkAutoRemoveTrailingWhitespace->setChecked(false);
+	chkPreserveTrailingIndent->setChecked(true);
+	
+	cbEncoding->setCurrentIndex(cbEncoding->findText(QTextCodec::codecForLocale()->name()));
+	
+	m_direct = oldDir;
+}
+
+/*!
+	\brief Fills a settings map from the state of the subcontrols
+*/
+QMap<QString, QVariant> QEditConfig::dumpKeys() const
+{
+	QMap<QString, QVariant> m;
+	
+	QFont font = cbFont->currentFont();
+	font.setPointSize(spnFontSize->value());
+	
+	m.insert("font", font);
+	m.insert("tab_width", spnTabWidth->value());
+	
+	m.insert("show_leading_whitespace", chkShowLeadingWhitespace->isChecked());
+	m.insert("show_trailing_whitespace", chkShowTrailingWhitespace->isChecked());
+	m.insert("show_tabs_in_text", chkShowTabsInText->isChecked());
+	
+	m.insert("replace_tabs", chkReplaceTabs->isChecked());
+	m.insert("remove_trailing", chkAutoRemoveTrailingWhitespace->isChecked());
+	m.insert("preserve_trailing_indent", chkPreserveTrailingIndent->isChecked());
+	
+	m.insert("encoding", cbEncoding->currentText());
+	
+	if ( chkDetectLE->isChecked() )
+		m.insert("line_endings", (int)QDocument::Conservative);
+	else
+		m.insert("line_endings", cbLineEndings->currentIndex() + 1);
+	
+	return m;
+}
+
+/*!
+	\brief Fills the widget subcontrols from a settings map
+	
+	\param keys a key/value map that can be obtained from QSettings
+*/
+void QEditConfig::loadKeys(const QMap<QString, QVariant>& keys)
+{
+	//qDebug("loading %i keys", keys.count());
+	
+	// load
+	QMap<QString, QVariant>::const_iterator it = keys.constBegin();
+	
+	while ( it != keys.constEnd() )
+	{
+		if ( it.key() == "font" )
+		{
+			QFont f = qvariant_cast<QFont>(*it);
+			
+			cbFont->setCurrentFont(f);
+			spnFontSize->setValue(f.pointSize());
+			
+			if ( m_direct )
+				QDocument::setFont(f);
+			
+			lblSampleText->setFont(f);
+			
+		} else if ( it.key() == "tab_width" ) {
+			spnTabWidth->setValue(it->toInt());
+			
+			if ( m_direct )
+				on_spnTabWidth_valueChanged(it->toInt());
+		} else if ( it.key() == "replace_tabs" ) {
+			chkReplaceTabs->setChecked(it->toBool());
+			if ( m_direct )
+				on_chkReplaceTabs_toggled(it->toBool());
+		} else if ( it.key() == "remove_trailing" ) {
+			chkAutoRemoveTrailingWhitespace->setChecked(it->toBool());
+			if ( m_direct )
+				on_chkAutoRemoveTrailingWhitespace_toggled(it->toBool());
+		} else if ( it.key() == "preserve_trailing_indent" ) {
+			chkPreserveTrailingIndent->setChecked(it->toBool());
+			if ( m_direct )
+				on_chkPreserveTrailingIndent_toggled(it->toBool());
+		} else if ( it.key() == "show_tabs_in_text" ) {
+			chkShowTabsInText->setChecked(it->toBool());
+			if ( m_direct )
+				on_chkShowTabsInText_toggled(it->toBool());
+		} else if ( it.key() == "show_leading_whitespace" ) {
+			chkShowLeadingWhitespace->setChecked(it->toBool());
+			if ( m_direct )
+				on_chkShowLeadingWhitespace_toggled(it->toBool());
+		} else if ( it.key() == "show_trailing_whitespace" ) {
+			chkShowTrailingWhitespace->setChecked(it->toBool());
+			if ( m_direct )
+				on_chkShowTrailingWhitespace_toggled(it->toBool());
+		} else if ( it.key() == "encoding" ) {
+			cbEncoding->setCurrentIndex(cbEncoding->findText(it->toString()));
+			if ( m_direct )
+				on_cbEncoding_currentIndexChanged(it->toString());
+		} else if ( it.key() == "line_endings" ) {
+			int le = it->toInt();
+			
+			if ( le )
+			{
+				chkDetectLE->setChecked(false);
+				cbLineEndings->setCurrentIndex(le - 1);
+			} else {
+				cbLineEndings->setCurrentIndex(0);
+				chkDetectLE->setChecked(true);
+			}
+		} else {
+			/*
+			qWarning("QEditConfig::loadKeys() fed with unsupported settings key : \"%s\" ",
+					qPrintable(it.key())
+					);
+			*/
+		}
+		
+		++it;
+	}
+}
+
+/*!
+	\brief Slot used to apply font size settings
+*/
+void QEditConfig::on_spnFontSize_valueChanged(int size)
+{
+	QFont font = cbFont->currentFont();
+	font.setPointSize(size);
+	
+	lblSampleText->setFont(font);
+	
+	if ( m_direct )
+	{
+		QDocument::setFont(font);
+		emit keyChanged("font", font);
+	}
+}
+
+/*!
+	\brief Slot used to apply font family settings
+*/
+void QEditConfig::on_cbFont_currentFontChanged(QFont font)
+{
+	font.setPointSize(spnFontSize->value());
+	lblSampleText->setFont(font);
+	
+	if ( m_direct )
+	{
+		QDocument::setFont(font);
+		emit keyChanged("font", font);
+	}
+}
+
+/*!
+	\brief Slot used to apply tab width settings
+*/
+void QEditConfig::on_spnTabWidth_valueChanged(int n)
+{
+	if ( m_direct )
+	{
+		QDocument::setTabStop(n);
+		emit keyChanged("tab_width", n);
+	}
+}
+
+/*!
+	\brief Slot used to apply tabs replacement settings
+*/
+void QEditConfig::on_chkReplaceTabs_toggled(bool y)
+{
+	if ( m_direct )
+	{
+		// FIXME
+		foreach ( QEditor *e, QEditor::m_editors )
+		{
+			e->setFlag(QEditor::ReplaceTabs, y);
+		}
+		emit keyChanged("replace_tabs", y);
+	}
+}
+
+/*!
+	\brief Slot used to apply tabs display settings
+*/
+void QEditConfig::on_chkShowTabsInText_toggled(bool y)
+{
+	if ( m_direct )
+	{
+		if ( y )
+			QDocument::setShowSpaces(QDocument::showSpaces() | QDocument::ShowTabs);
+		else
+			QDocument::setShowSpaces(QDocument::showSpaces() & ~QDocument::ShowTabs);
+		
+		emit keyChanged("show_tabs_in_text", y);
+	}
+}
+
+/*!
+	\brief Slot used to apply trailing whitespace display settings
+*/
+void QEditConfig::on_chkShowLeadingWhitespace_toggled(bool y)
+{
+	if ( m_direct )
+	{
+		if ( y )
+			QDocument::setShowSpaces(QDocument::showSpaces() | QDocument::ShowLeading);
+		else
+			QDocument::setShowSpaces(QDocument::showSpaces() & ~QDocument::ShowLeading);
+		
+		emit keyChanged("show_leading_whitespace", y);
+	}
+}
+
+/*!
+	\brief Slot used to apply leading whitespace display settings
+*/
+void QEditConfig::on_chkShowTrailingWhitespace_toggled(bool y)
+{
+	if ( m_direct )
+	{
+		if ( y )
+			QDocument::setShowSpaces(QDocument::showSpaces() | QDocument::ShowTrailing);
+		else
+			QDocument::setShowSpaces(QDocument::showSpaces() & ~QDocument::ShowTrailing);
+		
+		emit keyChanged("show_trailing_whitespace", y);
+	}
+}
+
+/*!
+	\brief Slot used to apply encodings settings
+*/
+void QEditConfig::on_cbEncoding_currentIndexChanged(const QString& name)
+{
+	if ( m_direct )
+	{
+		QEditor::setDefaultCodec(name.toLatin1(), QEditor::UpdateAll);
+		emit keyChanged("encoding", name);
+	}
+}
+
+/*!
+	\brief Slot used to apply line endings settings
+*/
+void QEditConfig::on_cbLineEndings_currentIndexChanged(int idx)
+{
+	QDocument::LineEnding le = QDocument::LineEnding(idx + 1);
+	
+	if ( m_direct )
+	{
+		QDocument::setDefaultLineEnding(le);
+		emit keyChanged("line_endings", (int)le);
+	}
+}
+
+/*!
+	\brief Slot used to apply line endings auto detectionl settings
+*/
+void QEditConfig::on_chkDetectLE_toggled(bool y)
+{
+	QDocument::LineEnding le = QDocument::Conservative;
+	
+	if ( !y )
+	{
+		le = QDocument::LineEnding(cbLineEndings->currentIndex() + 1);
+	}
+	
+	if ( m_direct )
+	{
+		QDocument::setDefaultLineEnding(le);
+		emit keyChanged("line_endings", (int)le);
+	}
+}
+
+/*!
+	\brief Slot used to apply trailing space removal settings
+*/
+void QEditConfig::on_chkAutoRemoveTrailingWhitespace_toggled(bool y)
+{
+	if ( m_direct )
+	{
+		// FIXME
+		foreach ( QEditor *e, QEditor::m_editors )
+		{
+			e->setFlag(QEditor::RemoveTrailing, y);
+		}
+		emit keyChanged("remove_trailing", y);
+	}
+}
+
+/*!
+	\brief Slot used to indent preservation settings
+*/
+void QEditConfig::on_chkPreserveTrailingIndent_toggled(bool y)
+{
+	if ( m_direct )
+	{
+		// FIXME
+		foreach ( QEditor *e, QEditor::m_editors )
+		{
+			e->setFlag(QEditor::PreserveTrailingIndent, y);
+		}
+		emit keyChanged("preserve_trailing_indent", y);
+	}
+}
+
+/*! @} */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qeditconfig.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QEDIT_CONFIG_H_
+#define _QEDIT_CONFIG_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qeditconfig.h
+	\brief Definition of the QEditConfig widget
+	
+	\see QEditConfig
+*/
+
+#include "ui_editconfig.h"
+
+#include <QWidget>
+
+class QCE_EXPORT QEditConfig : public QWidget, private Ui::EditorConfig
+{
+	Q_OBJECT
+	
+	public:
+		QEditConfig(QWidget *w = 0);
+		
+		bool hasUnsavedChanges() const;
+		
+		bool applyImmediately() const;
+		
+		QMap<QString, QVariant> dumpKeys() const;
+		
+	public slots:
+		void retranslate();
+		
+		void apply();
+		void cancel();
+		void restore();
+		
+		void loadKeys(const QMap<QString, QVariant>& keys);
+		
+		void setApplyImmediately(bool y);
+		
+	signals:
+		void keyChanged(const QString& key, const QVariant& value);
+		
+	private slots:
+		void on_spnFontSize_valueChanged(int size);
+		void on_cbFont_currentFontChanged(QFont font);
+		
+		void on_spnTabWidth_valueChanged(int n);
+		
+		void on_chkReplaceTabs_toggled(bool y);
+		
+		void on_chkShowTabsInText_toggled(bool y);
+		void on_chkShowLeadingWhitespace_toggled(bool y);
+		void on_chkShowTrailingWhitespace_toggled(bool y);
+		
+		void on_cbEncoding_currentIndexChanged(const QString& name);
+		void on_cbLineEndings_currentIndexChanged(int idx);
+		void on_chkDetectLE_toggled(bool y);
+		void on_chkAutoRemoveTrailingWhitespace_toggled(bool y);
+		void on_chkPreserveTrailingIndent_toggled(bool y);
+		
+	private:
+		bool m_direct;
+};
+
+#endif // _QEDIT_CONFIG_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qfoldpanel.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,306 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qfoldpanel.h"
+
+/*!
+	\file qfoldpanel.cpp
+	\brief Implementation of the QFoldPanel class.
+	
+	\see QFoldPanel
+*/
+
+#include "qeditor.h"
+
+#include "qdocument.h"
+#include "qdocumentline.h"
+
+#include "qlanguagedefinition.h"
+
+#include <QStack>
+#include <QBitmap>
+#include <QPainter>
+#include <QScrollBar>
+#include <QMouseEvent>
+
+/*!
+	\ingroup widgets
+	@{
+*/
+
+/*!
+	\class QFoldPanel
+	\brief A panel that draw fold indicators and provide fold/unfold actions to the user
+*/
+
+QCE_AUTO_REGISTER(QFoldPanel)
+
+/*!
+	\brief Constructor
+*/
+QFoldPanel::QFoldPanel(QWidget *p)
+ :	QPanel(p)
+{
+	setFixedWidth(12);
+}
+
+/*!
+	\brief Empty destructor
+*/
+QFoldPanel::~QFoldPanel()
+{
+	
+}
+
+/*!
+
+*/
+QString QFoldPanel::type() const
+{
+	return "Fold indicators";
+}
+
+/*!
+
+*/
+void QFoldPanel::mousePressEvent(QMouseEvent *e)
+{
+	if ( !editor() || !editor()->languageDefinition() || (e->button() != Qt::LeftButton) )
+	{
+		QPanel::mousePressEvent(e);
+		return;
+	}
+	
+	bool act = false;
+	QDocument *doc = editor()->document();
+	QLanguageDefinition *def = editor()->languageDefinition();
+	
+	for ( int i = 0; i < m_rects.count(); ++i )
+	{
+		if ( !m_rects.at(i).contains(e->pos()) )
+			continue;
+		
+		int ln = m_lines.at(i);
+		
+		QDocumentLine b = doc->line(ln);
+		
+		if ( b.hasFlag(QDocumentLine::CollapsedBlockStart) )
+			def->expand(doc, ln);
+		else if ( def->blockFlags(doc, ln, 0) & QLanguageDefinition::Collapsible )
+			def->collapse(doc, ln);
+		
+		act = true;
+	}
+	
+	if ( act )
+		editor()->setFocus();
+	else
+		QPanel::mousePressEvent(e);
+	
+}
+
+/*!
+
+*/
+bool QFoldPanel::paint(QPainter *p, QEditor *e)
+{
+	QDocument *doc = editor()->document();
+	QLanguageDefinition *def = e->languageDefinition();
+	
+	if ( !def || !doc )
+	{
+		return true;
+	}
+	
+	m_rects.clear();
+	m_lines.clear();
+	
+	bool bVisible = false; //,
+	//	inCursorBlock = false;
+	
+	QDocumentLine block;
+	const QFontMetrics fm(doc->font());
+	
+	int n,
+		pos,
+		depth = 0,
+		max = doc->lines(),
+		ls = fm.lineSpacing(),
+		pageBottom = e->viewport()->height(),
+		contentsY = e->verticalOffset();
+	
+	pos = - contentsY;
+	
+	//qDebug("beg pos : %i", pos);
+	
+	for ( n = 0; n < max; ++n )
+	{
+		if ( pos > pageBottom )
+			break;
+		
+		block = doc->line(n);
+		
+		if ( block.isHidden() )
+		{
+			continue;
+		}
+		
+		int len = ls * block.lineSpan();
+		int flags = def->blockFlags(doc, n, depth);
+		short open = QCE_FOLD_OPEN_COUNT(flags);
+		short close = QCE_FOLD_CLOSE_COUNT(flags);
+		
+		bVisible = ((pos + len) >= 0);
+		
+		int oldDepth = depth;
+		
+		depth -= close;
+		
+		if ( depth < 0 )
+			depth = 0;
+		
+		depth += open;
+		
+		if ( open )
+		{
+			if ( flags & QLanguageDefinition::Collapsed )
+			{
+				int bound = (ls - 8) / 2;
+				int mid = pos + len - ls / 6;
+				
+				// outermost block folded : none of the opening is actually opened
+				depth -= open;
+				
+				if ( bVisible )
+				{
+					// draw icon
+					
+					if ( bound > 0 && oldDepth > 0 )
+					{
+						p->drawLine(7, pos, 7, pos + bound);
+					}
+					
+					if ( close )
+					{
+						p->drawLine(7, pos + 8 + bound, 7, mid);
+						p->drawLine(7, mid, 12, mid);
+					}
+					
+					m_lines << n;
+					m_rects << drawIcon(p, e, 3, pos + bound, true);
+				}
+				
+				int sub = open;
+				
+				//qDebug("%i : +%i", n, open);
+				
+				while ( sub > 0 && ((n + 1) < max) )
+				{
+					++n;
+					block = doc->line(n);
+					
+					if ( !block.isHidden() )
+					{
+						if ( bVisible )
+							p->drawLine(7, pos + 8 + bound, 7, pos + len);
+						
+						--n;
+						break;
+					}
+					
+					int sflags = def->blockFlags(doc, n, depth + 1);
+					short sopen = QCE_FOLD_OPEN_COUNT(sflags);
+					short sclose = QCE_FOLD_CLOSE_COUNT(sflags);
+					
+					sub -= sclose;
+					
+					if ( sub <= 0 )
+						break;
+					
+					sub += sopen;
+				}
+				
+				depth += sub;
+				
+				if ( bVisible && depth > 0 )
+				{
+					if ( close )
+						p->drawLine(7, mid, 7, pos + len);
+					else
+						p->drawLine(7, pos + 8 + bound, 7, pos + len);
+				}
+			} else {
+				if ( bVisible )
+				{
+					int bound = (ls - 8) / 2;
+					
+					if ( oldDepth > 0 && bound > 0 )
+						p->drawLine(7, pos, 7, pos + bound);
+					
+					m_lines << n;
+					m_rects << drawIcon(p, e, 3, pos + bound, false);
+					
+					int mid = pos + len - ls / 6;
+					
+					if ( close )
+						p->drawLine(7, mid, 12, mid);
+					
+					if ( bound > 0 )
+						p->drawLine(7, pos + 8 + bound, 7, pos + len);
+				}
+			}
+		} else if ( (oldDepth > 0) && bVisible ) {
+			if ( close )
+			{
+				int mid = pos + len - ls / 6;
+				
+				p->drawLine(7, pos, 7, mid);
+				p->drawLine(7, mid, 12, mid);
+				
+				if ( depth > 0 )
+					p->drawLine(7, pos, 7, pos + len);
+			} else  {
+				p->drawLine(7, pos, 7, pos + len);
+			}
+		}
+		
+		pos += len;
+	}
+	
+	return true;
+}
+
+QRect QFoldPanel::drawIcon(	QPainter *p, QEditor *,
+							int x, int y, bool toExpand)
+{
+	QRect symbolRect(x, y, 8, 8);
+	
+	//p->save();
+	//p->setRenderHint(QPainter::Antialiasing);
+	p->drawRect(symbolRect);
+	//p->restore();
+	
+	if ( toExpand )
+	{
+		p->drawLine(x + 2, y + 4, x + 6, y + 4);
+		p->drawLine(x + 4, y + 2, x + 4, y + 6);
+	} else {
+		p->drawLine(x + 2, y + 4, x + 6, y + 4);
+	}
+	
+	return symbolRect;
+}
+
+/*! @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qfoldpanel.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QFOLD_PANEL_H_
+#define _QFOLD_PANEL_H_
+
+#include "qpanel.h"
+
+/*!
+	\file qfoldpanel.h
+	\brief Definition of the QFoldPanel class.
+	
+	\see QFoldPanel
+*/
+
+class QDocumentLine;
+
+class QCE_EXPORT QFoldPanel : public QPanel
+{
+	Q_OBJECT
+	
+	public:
+		Q_PANEL(QFoldPanel, "Fold Panel")
+		
+		QFoldPanel(QWidget *p = 0);
+		virtual ~QFoldPanel();
+		
+		virtual QString type() const;
+		
+	protected:
+		virtual void mousePressEvent(QMouseEvent *e);
+		virtual bool paint(QPainter *p, QEditor *e);
+		
+		QRect drawIcon(	QPainter *p, QEditor *e,
+						int x, int y, bool expand);
+		
+	private:
+		QList<QRect> m_rects;
+		QList<int> m_lines;
+};
+
+#endif // _QFOLD_PANEL_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qformatconfig.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,491 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qformatconfig.h"
+
+/*!
+	\file qformatconfig.cpp
+	\brief Implementation of the QFormatConfig class.
+	
+	\see QFormatConfig
+*/
+
+#include "qformat.h"
+#include "qformatscheme.h"
+
+#include "qeditor.h"
+#include "qdocument.h"
+
+#include "qsimplecolorpicker.h"
+
+#include <QHeaderView>
+#include <QVBoxLayout>
+#include <QMessageBox>
+#include <QTableWidget>
+
+/*!
+	\ingroup dialogs
+	@{
+	
+	\class QFormatConfig
+	\brief A minimalistic, easy to embed, format settings widget.
+	
+*/
+
+QFormatConfig::QFormatConfig(QWidget *w)
+ : QWidget(w), m_autonomous(false), m_currentScheme(0)
+{
+	setupUi(this);
+	
+	m_frame->hide();
+	
+	m_table->verticalHeader()->hide();
+	
+	m_table->horizontalHeaderItem(1)->setIcon(QIcon(":/bold.png"));
+	m_table->horizontalHeaderItem(2)->setIcon(QIcon(":/italic.png"));
+	m_table->horizontalHeaderItem(3)->setIcon(QIcon(":/underline.png"));
+	//m_table->horizontalHeaderItem(4)->setIcon(QIcon(":/overline.png"));
+	m_table->horizontalHeaderItem(5)->setIcon(QIcon(":/strikeout.png"));
+	//m_table->horizontalHeaderItem(6)->setIcon(QIcon(":/waveUnderline.png"));
+	m_table->horizontalHeaderItem(7)->setIcon(QIcon(":/textcolor.png"));
+	m_table->horizontalHeaderItem(8)->setIcon(QIcon(":/fillcolor.png"));
+	m_table->horizontalHeaderItem(9)->setIcon(QIcon(":/strokecolor.png"));
+	
+	connect(m_table, SIGNAL( itemSelectionChanged() ),
+			m_table, SLOT  ( clearSelection() ) );
+	
+}
+
+/*!
+	\brief run-time translation entry point
+*/
+void QFormatConfig::retranslate()
+{
+	retranslateUi(this);
+}
+
+/*!
+	\return Whether the format config widget is in "autonomous" mode
+*/
+bool QFormatConfig::isAutonomous() const
+{
+	return m_autonomous;
+}
+
+/*!
+	\brief Turn on "autonomous" mode
+	
+	When the format config widget is autonomous it will automatically
+	check for changes upon hide event and ask the user whether he wishes
+	to commit them.
+*/
+void QFormatConfig::setAutonomous(bool y)
+{
+	m_autonomous = y;
+}
+
+/*!
+	\brief Check whether there are unsaved in the widget
+*/
+bool QFormatConfig::hasUnsavedChanges() const
+{
+	return modifiedFormats().count();
+}
+
+/*!
+	\return the list of format schemes this config widget "manages"
+*/
+QList<QFormatScheme*> QFormatConfig::schemes() const
+{
+	return m_schemes;
+}
+
+/*!
+	\brief Add a format scheme to the config widget
+	
+	Users will be able to edit that scheme (switching among schemes using
+	a combobox if several schemes are added to the widget)
+*/
+void QFormatConfig::addScheme(const QString& name, QFormatScheme *scheme)
+{
+	m_schemes << scheme;
+	
+	m_selector->addItem(name);
+	
+	if ( m_schemes.count() > 1 && m_schemes.contains(m_currentScheme) )
+	{
+		// show the scheme selector
+		m_frame->show();
+	}
+	
+	if ( !m_currentScheme )
+		setCurrentScheme(scheme);
+}
+
+/*!
+	\brief Remove a scheme from the config widget
+	
+	\note No attempt is made to commit unsaved changes
+*/
+void QFormatConfig::removeScheme(QFormatScheme *s)
+{
+	if ( m_currentScheme == s )
+	{
+		m_currentScheme = 0;
+	}
+	
+	for ( int i = 0; i < m_schemes.count(); ++i )
+	{
+		if ( m_schemes.at(i) == s )
+		{
+			m_selector->removeItem(i);
+			m_schemes.removeAt(i);
+		}
+	}
+	
+	if ( m_schemes.count() <= 1 )
+	{
+		// hide the scheme selector
+		m_frame->hide();
+	}
+}
+
+/*!
+	\brief Enforce the currently edited scheme
+	
+	\note It is possible to pass a scheme not previously added to the widget,
+	but it really isn't recommended.
+*/
+void QFormatConfig::setCurrentScheme(QFormatScheme *s)
+{
+	int idx = m_schemes.indexOf(s);
+	
+	if ( idx != -1 )
+	{
+		m_currentScheme = s;
+		
+		// update table widget
+		cancel();
+	} else {
+		m_selector->setCurrentIndex(idx);
+	}
+}
+
+/*!
+	\brief Apply changes made to the currently edited scheme, if any
+*/
+void QFormatConfig::apply()
+{
+	if ( m_currentScheme )
+	{
+		const int n = m_currentScheme->formatCount();
+		
+		m_table->setRowCount(n);
+		
+		for ( int i = 0 ; i < n; ++i )
+		{
+			QString fid = m_currentScheme->id(i);
+			QFormat& fmt = m_currentScheme->formatRef(i);
+			
+			QTableWidgetItem *item;
+			
+			item = m_table->item(i, 1);
+			fmt.weight = item->checkState() == Qt::Checked ? QFont::Bold : QFont::Normal;
+			
+			item = m_table->item(i, 2);
+			fmt.italic = item->checkState() == Qt::Checked;
+			
+			item = m_table->item(i, 3);
+			fmt.underline = item->checkState() == Qt::Checked;
+			
+			item = m_table->item(i, 4);
+			fmt.overline = item->checkState() == Qt::Checked;
+			
+			item = m_table->item(i, 5);
+			fmt.strikeout = item->checkState() == Qt::Checked;
+			
+			item = m_table->item(i, 6);
+			fmt.waveUnderline = item->checkState() == Qt::Checked;
+			
+			QSimpleColorPicker *cp;
+			
+			cp = qobject_cast<QSimpleColorPicker*>(m_table->cellWidget(i, 7));
+			if ( cp )
+				fmt.foreground = cp->color();
+			
+			cp = qobject_cast<QSimpleColorPicker*>(m_table->cellWidget(i, 8));
+			if ( cp )
+				fmt.background = cp->color();
+			
+			cp = qobject_cast<QSimpleColorPicker*>(m_table->cellWidget(i, 9));
+			if ( cp )
+				fmt.linescolor = cp->color();
+			
+		}
+		
+		// TODO : save scheme and update editors
+		
+		// this will only save schemes loaded from an existing file
+		m_currentScheme->save();
+		
+		if ( m_autonomous )
+		{
+			QList<QEditor*> editors = QEditor::editors();
+			
+			foreach ( QEditor *e, editors )
+			{
+				if ( e->document()->formatScheme() == m_currentScheme )
+					e->viewport()->update();
+			}
+		}
+	}
+}
+
+/*!
+	\brief Reset the subcontrols to reflect the data of the format scheme being edited
+	
+	The name can be a bit misleading at first, it has been chosen
+	because it directly maps to the effect a "cancel" button would
+	have on the widget
+*/
+void QFormatConfig::cancel()
+{
+	m_table->clearContents();
+	
+	if ( m_currentScheme )
+	{
+		const int n = m_currentScheme->formatCount();
+		
+		m_table->setRowCount(n);
+		
+		for ( int i = 0 ; i < n; ++i )
+		{
+			QString fid = m_currentScheme->id(i);
+			const QFormat& fmt = m_currentScheme->formatRef(i);
+			
+			QTableWidgetItem *item;
+			
+			item = new QTableWidgetItem(fid);
+			item->setFlags(Qt::ItemIsEnabled);
+			m_table->setItem(i, 0, item);
+			
+			item = new QTableWidgetItem;
+			item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
+			item->setCheckState(fmt.weight == QFont::Bold ? Qt::Checked : Qt::Unchecked);
+			item->setToolTip(tr("Bold"));
+			m_table->setItem(i, 1, item);
+			
+			item = new QTableWidgetItem;
+			item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
+			item->setCheckState(fmt.italic ? Qt::Checked : Qt::Unchecked);
+			item->setToolTip(tr("Italic"));
+			m_table->setItem(i, 2, item);
+			
+			item = new QTableWidgetItem;
+			item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
+			item->setCheckState(fmt.underline ? Qt::Checked : Qt::Unchecked);
+			item->setToolTip(tr("Underline"));
+			m_table->setItem(i, 3, item);
+			
+			item = new QTableWidgetItem;
+			item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
+			item->setCheckState(fmt.overline ? Qt::Checked : Qt::Unchecked);
+			item->setToolTip(tr("Overline"));
+			m_table->setItem(i, 4, item);
+			
+			item = new QTableWidgetItem;
+			item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
+			item->setCheckState(fmt.strikeout ? Qt::Checked : Qt::Unchecked);
+			item->setToolTip(tr("Strikeout"));
+			m_table->setItem(i, 5, item);
+			
+			item = new QTableWidgetItem;
+			item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable);
+			item->setCheckState(fmt.waveUnderline ? Qt::Checked : Qt::Unchecked);
+			item->setToolTip(tr("Wave underline"));
+			m_table->setItem(i, 6, item);
+			
+			m_table->setCellWidget(i, 7, new QSimpleColorPicker(fmt.foreground));
+			m_table->cellWidget(i, 7)->setToolTip(tr("Text color (aka foreground)"));
+			//m_table->cellWidget(i, 7)->setMaximumSize(22, 22);
+			
+			m_table->setCellWidget(i, 8, new QSimpleColorPicker(fmt.background));
+			m_table->cellWidget(i, 8)->setToolTip(tr("Background color"));
+			//m_table->cellWidget(i, 8)->setMaximumSize(22, 22);
+			
+			m_table->setCellWidget(i, 9, new QSimpleColorPicker(fmt.linescolor));
+			m_table->cellWidget(i, 9)->setToolTip(tr("Lines color (used by all lines formatting : underline, overline, ...)"));
+			//m_table->cellWidget(i, 9)->setMaximumSize(22, 22);
+		}
+	}
+	
+	m_table->resizeColumnsToContents();
+}
+
+/*!
+	\brief Restore default values for all subcontrols
+	
+	\note The widgets are changed but these changes are NOT applied.
+*/
+void QFormatConfig::restore()
+{
+	// restoring what? this is only provided for API consistency and in case
+	// (very unlikely to ever happen) design changes make restore() a sensible
+	// thing to do on format schemes
+}
+
+QList<int> QFormatConfig::modifiedFormats() const
+{
+	QList<int> hasModif;
+	
+	if ( m_currentScheme )
+	{
+		const int n = m_currentScheme->formatCount();
+		
+		m_table->setRowCount(n);
+		
+		for ( int i = 0 ; i < n; ++i )
+		{
+			QString fid = m_currentScheme->id(i);
+			QFormat& fmt = m_currentScheme->formatRef(i);
+			
+			QTableWidgetItem *item;
+			
+			item = m_table->item(i, 1);
+			if ( fmt.weight != (item->checkState() == Qt::Checked ? QFont::Bold : QFont::Normal) )
+			{
+				hasModif << i;
+				continue;
+			}
+			
+			item = m_table->item(i, 2);
+			if ( fmt.italic != (item->checkState() == Qt::Checked) )
+			{
+				hasModif << i;
+				continue;
+			}
+			
+			item = m_table->item(i, 3);
+			if ( fmt.underline != (item->checkState() == Qt::Checked) )
+			{
+				hasModif << i;
+				continue;
+			}
+			
+			item = m_table->item(i, 4);
+			if ( fmt.overline != (item->checkState() == Qt::Checked) )
+			{
+				hasModif << i;
+				continue;
+			}
+			
+			item = m_table->item(i, 5);
+			if ( fmt.strikeout != (item->checkState() == Qt::Checked) )
+			{
+				hasModif << i;
+				continue;
+			}
+			
+			item = m_table->item(i, 6);
+			if ( fmt.waveUnderline != (item->checkState() == Qt::Checked) )
+			{
+				hasModif << i;
+				continue;
+			}
+			
+			QSimpleColorPicker *cp;
+			
+			cp = qobject_cast<QSimpleColorPicker*>(m_table->cellWidget(i, 7));
+			if ( cp && fmt.foreground != cp->color() )
+			{
+				hasModif << i;
+				continue;
+			}
+			
+			cp = qobject_cast<QSimpleColorPicker*>(m_table->cellWidget(i, 8));
+			if ( cp && fmt.background != cp->color() )
+			{
+				hasModif << i;
+				continue;
+			}
+			
+			cp = qobject_cast<QSimpleColorPicker*>(m_table->cellWidget(i, 9));
+			if ( cp && fmt.linescolor != cp->color() )
+			{
+				hasModif << i;
+				continue;
+			}
+		}
+	}
+	
+	return hasModif;
+}
+
+void QFormatConfig::hideEvent(QHideEvent *e)
+{
+	Q_UNUSED(e)
+	
+	if ( !m_autonomous )
+		return;
+	
+	QList<int> hasModif = modifiedFormats();
+	
+	if ( hasModif.count() )
+	{
+		// TODO : provide custom widget to allow user to select which items should be saved?
+		int ret = QMessageBox::warning(
+									0, 
+									tr("Unsaved changes"),
+									tr("There are unsaved changes in this format scheme.\nDo you want them to be saved?"),
+									QMessageBox::Save | QMessageBox::Discard
+								);
+		
+		if ( ret == QMessageBox::Save )
+		{
+			apply();
+		} else {
+			cancel();
+		}
+	}
+}
+
+void QFormatConfig::on_m_selector_currentIndexChanged(int idx)
+{
+	QList<int> hasModif = modifiedFormats();
+	
+	if ( hasModif.count() )
+	{
+		// TODO : provide custom widget to allow user to select which items should be saved?
+		int ret = QMessageBox::warning(
+									0, 
+									tr("Unsaved changes"),
+									tr("There are unsaved changes in this format scheme.\nDo you want them to be saved?"),
+									QMessageBox::Save | QMessageBox::Discard
+								);
+		
+		if ( ret == QMessageBox::Save )
+		{
+			apply();
+		} else {
+			cancel();
+		}
+	}
+	
+	m_currentScheme = idx >= 0 && idx < m_schemes.count() ? m_schemes.at(idx) : 0;
+	
+	cancel();
+}
+
+/*! @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qformatconfig.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QFORMAT_CONFIG_H_
+#define _QFORMAT_CONFIG_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qformatconfig.h
+	\brief Definition of the QFormatConfig widget
+	
+	\see QFormatConfig
+*/
+
+#include <QWidget>
+
+#include "ui_formatconfig.h"
+
+class QFormatScheme;
+
+class QCE_EXPORT QFormatConfig : public QWidget, private Ui::FormatConfig
+{
+	Q_OBJECT
+	
+	public:
+		QFormatConfig(QWidget *w = 0);
+		
+		bool isAutonomous() const;
+		
+		bool hasUnsavedChanges() const;
+		
+		QList<QFormatScheme*> schemes() const;
+		
+	public slots:
+		void retranslate();
+		
+		void apply();
+		void cancel();
+		void restore();
+		
+		void setAutonomous(bool y);
+		
+		void addScheme(const QString& name, QFormatScheme *scheme);
+		void removeScheme(QFormatScheme *scheme);
+		
+		void setCurrentScheme(QFormatScheme *scheme);
+		
+	protected:
+		virtual void hideEvent(QHideEvent *e);
+		
+	private slots:
+		void on_m_selector_currentIndexChanged(int idx);
+		
+	private:
+		QList<int> modifiedFormats() const;
+		
+		bool m_autonomous;
+		QFormatScheme *m_currentScheme;
+		QList<QFormatScheme*> m_schemes;
+};
+
+#endif // _QFORMAT_CONFIG_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qgotolinedialog.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qgotolinedialog.h"
+
+/*!
+	\file qgotolinedialog.cpp
+	\brief Implementation of the QGotoDialog class.
+	
+	\see QGotoDialog
+*/
+
+#include "qeditor.h"
+
+#include "qdocument.h"
+#include "qdocumentline.h"
+#include "qdocumentcursor.h"
+
+/*!
+	\ingroup dialogs
+	@{
+	
+	\class QGotoLineDialog
+	\brief A Kate-like generic goto line dialog.
+	
+*/
+
+QGotoLineDialog::QGotoLineDialog(QWidget *w)
+ : QDialog(w)
+{
+	setupUi(this);
+}
+
+void QGotoLineDialog::exec(QEditor *e)
+{
+	if ( !e )
+		return;
+	
+	int ln = e->cursor().lineNumber() + 1,
+		max = e->document()->lines();
+	
+	spinLine->setValue(ln);
+	spinLine->setMaximum(max);
+	
+	slideLine->setValue(ln);
+	slideLine->setMaximum(max);
+	
+	spinLine->selectAll();
+	
+	if ( QDialog::exec() != QDialog::Accepted )
+		return;
+	
+	QDocumentCursor c(e->document(), spinLine->value() - 1);
+	
+	if ( c.isNull() )
+		return;
+	
+	//qDebug("going to line : %i [%i]", c.lineNumber(), spinLine->value());
+	
+	e->setCursor(c);
+}
+
+/*! @} */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qgotolinedialog.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QGOTO_LINE__DIALOG_H_
+#define _QGOTO_LINE__DIALOG_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qgotodialog.h
+	\brief Definition of the QGotoLineDialog class
+	
+	\see QGotoLineDialog
+*/
+
+#include "ui_gotolinedialog.h"
+
+#include <QDialog>
+
+class QEditor;
+
+class QCE_EXPORT QGotoLineDialog : public QDialog, private Ui::GotoDialog
+{
+	Q_OBJECT
+	
+	public:
+		QGotoLineDialog(QWidget *w = 0);
+		
+	public slots:
+		void exec(QEditor *e);
+};
+
+#endif // _QGOTO_LINE__DIALOG_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qgotolinepanel.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qgotolinepanel.h"
+
+/*!
+	\file qgotolinepanel.cpp
+	\brief Implementation of the QGotoLinePanel class.
+	
+	\see QGotoLinePanel
+*/
+
+#include "qeditor.h"
+
+#include "qdocument.h"
+#include "qdocumentline.h"
+#include "qdocumentcursor.h"
+
+#include <QKeyEvent>
+
+/*!
+	\ingroup widgets
+	@{
+*/
+
+/*!
+	\class QGotoLinePanel
+	\brief A panel that provide inline goto line functionalities
+*/
+
+QCE_AUTO_REGISTER(QGotoLinePanel)
+
+/*!
+	\brief Constructor
+*/
+QGotoLinePanel::QGotoLinePanel(QWidget *p)
+ : QPanel(p)
+{
+	setupUi(this);
+	setDefaultVisibility(false);
+	
+	bClose->setIcon(QPixmap(":/closeall.png"));
+}
+
+/*!
+	\brief Empty destructor
+*/
+QGotoLinePanel::~QGotoLinePanel()
+{
+	
+}
+
+/*!
+
+*/
+QString QGotoLinePanel::type() const
+{
+	return "Goto";
+}
+
+/*!
+	\brief 
+*/
+void QGotoLinePanel::editorChange(QEditor *e)
+{
+	if ( editor() )
+	{
+		disconnect(	editor(), SIGNAL( cursorPositionChanged() ),
+					this	, SLOT  ( cursorPositionChanged() ) );
+		
+		disconnect(	editor()->document(), SIGNAL( lineCountChanged(int) ),
+					this				, SLOT  ( lineCountChanged(int) ) );
+	}
+	
+	if ( e )
+	{
+		connect(e	, SIGNAL( cursorPositionChanged() ),
+				this, SLOT  ( cursorPositionChanged() ) );
+		
+		connect(e->document()	, SIGNAL( lineCountChanged(int) ),
+				this			, SLOT  ( lineCountChanged(int) ) );
+		
+		lineCountChanged(e->document()->lineCount());
+		spLine->setValue(e->cursor().lineNumber() + 1);
+		slLine->setValue(e->cursor().lineNumber() + 1);
+	}
+}
+
+bool QGotoLinePanel::forward(QMouseEvent *e)
+{
+	Q_UNUSED(e)
+	
+	/*
+		This panel does not need mouse events to be forwarded to the editor.
+		Even more, it requires them not to be forwarded...
+	*/
+	return false;
+}
+
+void QGotoLinePanel::showEvent(QShowEvent *e)
+{
+	Q_UNUSED(e)
+	
+	spLine->setFocus();
+	spLine->selectAll();
+}
+
+void QGotoLinePanel::keyPressEvent(QKeyEvent *e)
+{
+	if ( e->key() == Qt::Key_Escape )
+	{
+		on_bClose_clicked();
+	} else if ( e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter ) {
+		on_bGo_clicked();
+	} else {
+		QPanel::keyPressEvent(e);
+	}
+}
+
+void QGotoLinePanel::on_bClose_clicked()
+{
+	hide();
+	editor()->setFocus();
+}
+
+void QGotoLinePanel::on_bGo_clicked()
+{
+	editor()->setCursor(QDocumentCursor(editor()->document(), spLine->value() - 1));
+}
+
+void QGotoLinePanel::on_spLine_valueChanged(int v)
+{
+	if ( slLine->value() != v )
+		slLine->setValue(v);
+}
+
+void QGotoLinePanel::on_slLine_valueChanged(int v)
+{
+	if ( spLine->value() != v )
+		spLine->setValue(v);
+}
+
+void QGotoLinePanel::lineCountChanged(int n)
+{
+	spLine->setMaximum(n);
+	slLine->setMaximum(n);
+}
+
+void QGotoLinePanel::cursorPositionChanged()
+{
+	spLine->setValue(editor()->cursor().lineNumber() + 1);
+	slLine->setValue(editor()->cursor().lineNumber() + 1);
+}
+
+/*! @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qgotolinepanel.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QGOTO_LINE_PANEL_H_
+#define _QGOTO_LINE_PANEL_H_
+
+#include "qpanel.h"
+
+/*!
+	\file qgotolinepanel.h
+	\brief Definition of the QGotoLinePanel class.
+	
+	\see QGotoLinePanel
+*/
+
+#include "ui_gotoline.h"
+
+class QCE_EXPORT QGotoLinePanel : public QPanel, private Ui::GotoLine
+{
+	Q_OBJECT
+	
+	public:
+		Q_PANEL(QGotoLinePanel, "Goto Line Panel")
+		
+		QGotoLinePanel(QWidget *p = 0);
+		virtual ~QGotoLinePanel();
+		
+		virtual QString type() const;
+		
+	public slots:
+		
+		
+	protected:
+		virtual bool forward(QMouseEvent *e);
+		virtual void editorChange(QEditor *e);
+		virtual void showEvent(QShowEvent *e);
+		virtual void keyPressEvent(QKeyEvent *e);
+		
+	private slots:
+		void on_bClose_clicked();
+		
+		void on_bGo_clicked();
+		
+		void on_spLine_valueChanged(int v);
+		void on_slLine_valueChanged(int v);
+		
+		void lineCountChanged(int n);
+		void cursorPositionChanged();
+};
+
+#endif // _QGOTO_LINE_PANEL_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qlinechangepanel.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qlinechangepanel.h"
+
+/*!
+	\file qlinechangepanel.cpp
+	\brief Implementation of the QLineChangePanel class.
+*/
+
+#include "qeditor.h"
+
+#include "qdocument.h"
+#include "qdocumentline.h"
+
+#include <QIcon>
+#include <QMenu>
+#include <QPainter>
+#include <QScrollBar>
+#include <QContextMenuEvent>
+
+/*!
+	\ingroup widgets
+	@{
+*/
+
+/*!
+	\class QLineMarkPanel
+	\brief A specific panel in charge of drawing line numbers of an editor
+	
+	\see QEditorInterface
+*/
+
+QCE_AUTO_REGISTER(QLineChangePanel)
+
+/*!
+	\brief Constructor
+*/
+QLineChangePanel::QLineChangePanel(QWidget *p)
+ : QPanel(p)
+{
+	setFixedWidth(4);
+}
+
+/*!
+	\brief Empty destructor
+*/
+QLineChangePanel::~QLineChangePanel()
+{
+	
+}
+
+/*!
+
+*/
+QString QLineChangePanel::type() const
+{
+	return "Line changes";
+}
+
+/*!
+	\internal
+*/
+bool QLineChangePanel::paint(QPainter *p, QEditor *e)
+{
+	if ( !e || !e->document() )
+		return true;
+	
+	const QFontMetrics fm( e->document()->font() );
+	
+	int n, posY,
+		as = fm.ascent(),
+		ls = fm.lineSpacing(),
+		pageBottom = e->viewport()->height(),
+		contentsY = e->verticalOffset();
+	
+	QString txt;
+	
+	QDocument *d = e->document();
+	n = d->lineNumber(contentsY);
+	posY = 2 + d->y(n) - contentsY;
+	
+	for ( ; ; ++n )
+	{
+		//qDebug("n = %i; pos = %i", n, posY);
+		QDocumentLine line = d->line(n);
+		
+		if ( line.isNull() || ((posY - as) > pageBottom) )
+			break;
+		
+		if ( line.isHidden() )
+			continue;
+		
+		int span = line.lineSpan();
+		
+		if ( d->isLineModified(line) )
+		{
+			p->fillRect(1, posY, 2, ls * span, Qt::red);
+		} else if ( d->hasLineEverBeenModified(line) ) {
+			p->fillRect(1, posY, 2, ls * span, Qt::green);
+		}
+		
+		posY += ls * span;
+	}
+	
+	return true;
+}
+
+/*! @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qlinechangepanel.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QLINE_CHANGE_PANEL_H_
+#define _QLINE_CHANGE_PANEL_H_
+
+/*!
+	\file qlinechangepanel.h
+	\brief Definition of the QLineChangePanel class.
+	
+	\see QLineChangePanel
+*/
+
+#include "qpanel.h"
+
+#include <QHash>
+#include <QIcon>
+
+class QDocumentLine;
+
+class QCE_EXPORT QLineChangePanel : public QPanel
+{
+	Q_OBJECT
+	
+	public:
+		Q_PANEL(QLineChangePanel, "Line Change Panel")
+		
+		QLineChangePanel(QWidget *p = 0);
+		virtual ~QLineChangePanel();
+		
+		virtual QString type() const;
+		
+	protected:
+		virtual bool paint(QPainter *p, QEditor *e);
+		
+	private:
+		
+};
+
+#endif // _QLINE_CHANGE_PANEL_H_
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qlinemarkpanel.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,235 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qlinemarkpanel.h"
+
+/*!
+	\file qlinemarkpanel.cpp
+	\brief Implementation of the QLineMarkPanel class.
+*/
+
+#include "qeditor.h"
+
+#include "qdocument.h"
+#include "qdocumentline.h"
+
+#include "qlanguagedefinition.h"
+#include "qlinemarksinfocenter.h"
+
+#include <QIcon>
+#include <QMenu>
+#include <QPainter>
+#include <QScrollBar>
+#include <QMessageBox>
+#include <QContextMenuEvent>
+
+/*!
+	\ingroup widgets
+	@{
+*/
+
+/*!
+	\class QLineMarkPanel
+	\brief A specific panel in charge of drawing line marks of an editor
+*/
+
+QCE_AUTO_REGISTER(QLineMarkPanel)
+
+/*!
+	\brief Constructor
+*/
+QLineMarkPanel::QLineMarkPanel(QWidget *p)
+ : QPanel(p)
+{
+	setFixedWidth(18);
+}
+
+/*!
+	\brief Empty destructor
+*/
+QLineMarkPanel::~QLineMarkPanel()
+{
+	
+}
+
+/*!
+
+*/
+QString QLineMarkPanel::type() const
+{
+	return "Line marks";
+}
+
+/*!
+	\internal
+*/
+bool QLineMarkPanel::paint(QPainter *p, QEditor *e)
+{
+	if ( !e || !e->document() )
+		return true;
+	
+	m_rects.clear();
+	m_lines.clear();
+	QDocument *d = e->document();
+	
+	int maxMarksPerLine = d->maxMarksPerLine();
+	
+	setFixedWidth(maxMarksPerLine ? maxMarksPerLine * 16 + 2 : 18);
+	
+	const QFontMetrics fm( d->font() );
+	
+	int n, posY,
+		as = fm.ascent(),
+		ls = fm.lineSpacing(),
+		pageBottom = e->viewport()->height(),
+		contentsY = e->verticalOffset();
+	
+	QString txt;
+	const QFontMetrics sfm(fontMetrics());
+	QLineMarksInfoCenter *mic = QLineMarksInfoCenter::instance();
+	
+	n = d->lineNumber(contentsY);
+	posY = 2 + d->y(n) - contentsY;
+	
+	//qDebug("first = %i; last = %i", first, last);
+	//qDebug("beg pos : %i", posY);
+	//qDebug("<session>");
+	for ( ; ; ++n )
+	{
+		//qDebug("n = %i; pos = %i", n, posY);
+		QDocumentLine line = d->line(n);
+		
+		if ( line.isNull() || ((posY - as) > pageBottom) )
+			break;
+		
+		if ( line.isHidden() )
+			continue;
+		
+		m_lines << n;
+		m_rects << QRect(0, posY, width(), ls);
+		
+		if ( maxMarksPerLine )
+		{
+			int count = 1;
+			QList<int> lm = line.marks();
+			
+			foreach ( int id, lm )
+			{
+				QPixmap pix = mic->markType(id).icon;
+				
+				if ( pix.isNull() )
+					continue;
+				
+				int h = qMin(pix.height(), ls),
+					w = qMin(pix.width(), 16),
+					x = count,
+					y = posY + ( (ls - h) >> 1 );
+				
+				p->drawPixmap(x, y, w, h, pix);
+				
+				count += 16;
+			}
+		}
+
+		posY += ls * line.lineSpan();
+	}
+	//qDebug("</session>");
+	
+	//setFixedWidth(sfm.width(txt) + 5);
+	return true;
+}
+
+/*!
+	\internal
+*/
+void QLineMarkPanel::mousePressEvent(QMouseEvent *e)
+{
+// 	if ( !editor() || !editor()->document() || !editor()->marker() )
+// 	{
+// 		return QPanel::mousePressEvent(e);
+// 	}
+// 	
+	QPanel::mousePressEvent(e);
+ 	e->accept();
+}
+
+/*!
+	\internal
+*/
+void QLineMarkPanel::mouseReleaseEvent(QMouseEvent *e)
+{
+	if ( !editor() || !editor()->document() || !editor()->languageDefinition() )
+	{
+		QPanel::mouseReleaseEvent(e);
+		return;
+	}
+	
+	//QMessageBox::warning(0, 0, "clik.");
+	
+	QDocumentLine l;
+	QLanguageDefinition *d = editor()->languageDefinition();
+	const int id = QLineMarksInfoCenter::instance()->markTypeId(d->defaultLineMark());
+	
+	if ( id < 0 )
+		return;
+	
+	e->accept();
+	
+	for ( int i = 0; i < m_rects.count(); ++i )
+	{
+		if ( m_rects.at(i).contains(e->pos()) )
+		{
+			l = editor()->document()->line(m_lines.at(i));
+			l.toggleMark(id);
+			//m->toggleDefaultMark(l, -1);
+			
+			break;
+		}
+	}
+	
+	QPanel::mouseReleaseEvent(e);
+}
+
+/*!
+	\internal
+*/
+void QLineMarkPanel::contextMenuEvent(QContextMenuEvent *e)
+{
+	if ( !editor() || !editor()->document() )
+	{
+		e->ignore();
+		return;
+	}
+	
+	/*
+	QTextBlock b;
+	QMarker *m = editor()->marker();
+	QTextDocument *d = editor()->document();
+	
+	e->accept();
+	
+	QHash<int, QRect>::iterator i;
+	
+	for ( i = rects.begin(); i != rects.end(); i++ )
+	{
+		b = d->findBlock(i.key());
+		
+		if ( i->contains( e->pos() ) )
+			return m->menu(b, e->globalPos());
+	}
+	*/
+}
+
+/*! @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qlinemarkpanel.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QLINE_MARK_PANEL_H_
+#define _QLINE_MARK_PANEL_H_
+
+/*!
+	\file qlinemarkpanel.h
+	\brief Definition of the QLineMarkPanel class.
+	
+	\see QLineMarkPanel
+*/
+
+#include "qpanel.h"
+
+#include <QHash>
+#include <QIcon>
+
+class QDocumentLine;
+
+class QCE_EXPORT QLineMarkPanel : public QPanel
+{
+	Q_OBJECT
+	
+	public:
+		Q_PANEL(QLineMarkPanel, "Line Mark Panel")
+		
+		QLineMarkPanel(QWidget *p = 0);
+		virtual ~QLineMarkPanel();
+		
+		virtual QString type() const;
+		
+	protected:
+		virtual bool paint(QPainter *p, QEditor *e);
+		virtual void mousePressEvent(QMouseEvent *e);
+		virtual void mouseReleaseEvent(QMouseEvent *e);
+		virtual void contextMenuEvent(QContextMenuEvent *e);
+		
+	private:
+		QList<QRect> m_rects;
+		QList<int> m_lines;
+};
+
+#endif // _QLINE_MARK_PANEL_H_
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qlinenumberpanel.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qlinenumberpanel.h"
+
+/*!
+	\file qlinenumberpanel.cpp
+	\brief Implementation of the QLineNumberPanel class
+	
+	\see QLineNumberPanel
+*/
+
+#include <QPainter>
+#include <QScrollBar>
+
+#include "qeditor.h"
+#include "qdocument.h"
+#include "qdocument_p.h"
+#include "qdocumentline.h"
+
+
+/*!
+	\ingroup widgets
+	@{
+*/
+
+/*!
+	\class QLineNumberPanel
+	\brief A specific panel in charge of drawing line numbers of an editor
+*/
+
+QCE_AUTO_REGISTER(QLineNumberPanel)
+
+/*!
+	\brief Constructor
+*/
+QLineNumberPanel::QLineNumberPanel(QWidget *p)
+ : QPanel(p), m_verbose(false)
+{
+	setFixedWidth(20);
+}
+
+/*!
+	\brief Empty destructor
+*/
+QLineNumberPanel::~QLineNumberPanel()
+{
+	
+}
+
+/*!
+
+*/
+QString QLineNumberPanel::type() const
+{
+	return "Line numbers";
+}
+
+/*!
+
+*/
+bool QLineNumberPanel::isVerboseMode() const
+{
+	return m_verbose;
+}
+
+/*!
+	
+*/
+void QLineNumberPanel::setVerboseMode(bool y)
+{
+	m_verbose = y;
+	update();
+}
+
+/*!
+
+*/
+void QLineNumberPanel::editorChange(QEditor *e)
+{
+	if ( editor() )
+	{
+		disconnect(	editor(), SIGNAL( cursorPositionChanged() ),
+					this	, SLOT  ( update() ) );
+		
+	}
+	
+	if ( e )
+	{
+		setFixedWidth(fontMetrics().width(QString::number(e->document()->lines())) + 5);
+		
+		connect(e	, SIGNAL( cursorPositionChanged() ),
+				this, SLOT  ( update() ) );
+		
+	}
+}
+
+/*!
+
+*/
+bool QLineNumberPanel::paint(QPainter *p, QEditor *e)
+{
+	/*
+		possible Unicode caracter for wrapping arrow :
+			0x21B3
+			0x2937
+	*/
+	
+	QFont f(font());
+	f.setWeight(QFont::Bold);
+	const QFontMetrics sfm(f);
+	
+	#ifndef WIN32
+	static const QChar wrappingArrow(0x2937);
+	const QFontMetrics specialSfm(sfm);
+	#else
+	// 0xC4 gives a decent wrapping arrow in Wingdings fonts, availables on all windows systems
+	// this is a hackish fallback to workaround Windows issues with Unicode...
+	static const QChar wrappingArrow(0xC4);
+	QFont specialFont(font());
+	specialFont.setRawName("Wingdings");
+	const QFontMetrics specialSfm(specialFont);
+	#endif
+	
+	const int max = e->document()->lines();
+	const int panelWidth = sfm.width(QString::number(max)) + 5;
+	setFixedWidth(panelWidth);
+	
+	const QFontMetrics fm( e->document()->font() );
+	
+	int n, posY,
+		as = fm.ascent(),
+		ls = fm.lineSpacing(),
+		pageBottom = e->viewport()->height(),
+		contentsY = e->verticalOffset();
+	
+	QString txt;
+	QDocument *d = e->document();
+	const int cursorLine = e->cursor().lineNumber();
+	
+	n = d->lineNumber(contentsY);
+	posY = as + 2 + d->y(n) - contentsY;
+	
+	//qDebug("first = %i; last = %i", first, last);
+	//qDebug("beg pos : %i", posY);
+	
+	for ( ; ; ++n )
+	{
+		//qDebug("n = %i; pos = %i", n, posY);
+		QDocumentLine line = d->line(n);
+		
+		if ( line.isNull() || ((posY - as) > pageBottom) )
+			break;
+		
+		if ( line.isHidden() )
+			continue;
+		
+		bool draw = true;
+		
+		if ( !m_verbose )
+		{
+			draw = !((n + 1) % 10) || !n || line.marks().count();
+		}
+		
+		txt = QString::number(n + 1);
+		
+		if ( n == cursorLine )
+		{
+			draw = true;
+			
+			p->save();
+			QFont f = p->font();
+			f.setWeight(QFont::Bold);
+			
+			p->setFont(f);
+		}
+		
+		if ( draw )
+		{
+			p->drawText(width() - 2 - sfm.width(txt),
+						posY,
+						txt);
+			
+		} else {
+			int yOff = posY - (as + 1) + ls / 2;
+			
+			if ( (n + 1) % 5 )
+				p->drawPoint(width() - 5, yOff);
+			else
+				p->drawLine(width() - 7, yOff, width() - 2, yOff);
+		}
+		
+		if ( line.lineSpan() > 1 )
+		{
+			#ifdef Q_OS_WIN32
+			p->save();
+			specialFont.setBold(n == cursorLine); //todo: only get bold on the current wrapped line
+			p->setFont(specialFont);
+			#endif
+
+			for ( int i = 1; i < line.lineSpan(); ++i )
+			{
+				// draw line wrapping indicators
+				//p->drawText(width() - 2 - sfm.width(wrappingArrow), posY + i * ls, wrappingArrow);
+				p->drawText(width() - 1 - specialSfm.width(wrappingArrow), posY + i * ls, wrappingArrow);
+			}
+			
+			#ifdef Q_OS_WIN32
+			p->restore();
+			#endif
+		}
+		
+		if ( n == cursorLine )
+		{
+			p->restore();
+		}
+		
+		posY += ls * line.lineSpan();
+	}
+	
+	//p->setPen(Qt::DotLine);
+	//p->drawLine(width()-1, 0, width()-1, pageBottom);
+	
+	//setFixedWidth(sfm.width(txt) + 5);
+	return true;
+}
+
+/*! @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qlinenumberpanel.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QLINE_NUMBER_PANEL_H_
+#define _QLINE_NUMBER_PANEL_H_
+
+/*!
+	\file qlinenumberpanel.h
+	\brief Definition of the QLineNumberPanel class
+	
+	\see QLineNumberPanel
+*/
+
+#include "qpanel.h"
+
+class QCE_EXPORT QLineNumberPanel : public QPanel
+{
+	Q_OBJECT
+	
+	public:
+		Q_PANEL(QLineNumberPanel, "Line Number Panel")
+		
+		QLineNumberPanel(QWidget *p = 0);
+		virtual ~QLineNumberPanel();
+		
+		bool isVerboseMode() const;
+		
+		virtual QString type() const;
+		
+	public slots:
+		void setVerboseMode(bool y);
+		
+	protected:
+		virtual void editorChange(QEditor *e);
+		virtual bool paint(QPainter *p, QEditor *e);
+		
+		bool m_verbose;
+};
+
+#endif // _QLINE_NUMBER_PANEL_H_
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qpanel.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,317 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qpanel.h"
+
+/*!
+	\file qpanel.cpp
+	\brief Implementation of the QPanel class
+	
+	\see QPanel
+*/
+
+#include "qeditor.h"
+#include "qcodeedit.h"
+#include "qpanellayout.h"
+
+#include <QFont>
+#include <QFontMetrics>
+
+#include <QPainter>
+#include <QPaintEvent>
+
+#include <QScrollBar>
+
+#include <QMouseEvent>
+#include <QApplication>
+
+/*!
+	\ingroup widgets
+	@{
+	
+	\class QPanel
+	\brief Helper class for panels displayed by QCodeEdit
+	
+*/
+
+QHash<QString, QPanelCreator*>& QPanel::creators()
+{
+	static QHash<QString, QPanelCreator*> _c;
+	return _c;
+}
+
+QPanel* QPanel::panel(const QString& id, QWidget *p)
+{
+	if ( !creators().contains(id) )
+		return 0;
+	
+	return creators().value(id)->panel(p);
+}
+
+void QPanel::registerCreator(QPanelCreator *c)
+{
+	creators()[c->id()] = c;
+}
+
+static int _panels = 0;
+
+/*!
+	\brief Constructor
+	
+	If the parent is a text editor, it is automatically connected to the panel
+*/
+QPanel::QPanel(QWidget *p)
+ : QWidget(p), m_defaultVisibility(true), m_shownOnce(false)
+{
+	QEditor *e = qobject_cast<QEditor*>(p);
+	
+	if ( e )
+		attach(e);
+	
+	++_panels;
+}
+
+/*!
+	\brief Destructor
+*/
+QPanel::~QPanel()
+{
+	--_panels;
+	
+	//if ( !_panels )
+	//	qDebug("Panels cleared.");
+	
+}
+
+/*!
+*/
+QEditor* QPanel::editor()
+{
+	return m_editor;
+}
+
+/*!
+	\brief Connect the panel to a text editor
+*/
+void QPanel::attach(QEditor *e)
+{
+	if ( m_editor )
+	{
+		disconnect(	m_editor->document(),
+					SIGNAL( formatsChanged() ),
+					this,
+					SLOT  ( update() ) );
+		
+		disconnect(	m_editor->document(),
+					SIGNAL( contentsChanged() ),
+					this,
+					SLOT  ( update() ) );
+		
+		disconnect(	m_editor->verticalScrollBar(),
+					SIGNAL( valueChanged(int) ),
+					this,
+					SLOT  ( update() ) );
+		
+	}
+	
+	editorChange(e);
+	
+	m_editor = e;
+	setParent(e);
+	
+	if ( m_editor )
+	{
+		connect(m_editor->document(),
+				SIGNAL( formatsChanged() ),
+				this,
+				SLOT  ( update() ) );
+		
+		connect(m_editor->document(),
+				SIGNAL( contentsChanged() ),
+				this,
+				SLOT  ( update() ) );
+		
+		connect(m_editor->verticalScrollBar(),
+				SIGNAL( valueChanged(int) ),
+				this,
+				SLOT  ( update() ) );
+		
+	}
+}
+
+/*!
+	\brief 
+*/
+bool QPanel::shallShow() const
+{
+	return m_shownOnce ? isHidden() : m_defaultVisibility;
+}
+
+/*!
+	\brief 
+*/
+bool QPanel::defaultVisibility() const
+{
+	return m_defaultVisibility;
+}
+
+/*!
+	\brief 
+*/
+void QPanel::setDefaultVisibility(bool on)
+{
+	m_defaultVisibility = on;
+}
+
+/*!
+	\brief Callback
+	
+	Each time attach() is called, this function is called as well so that
+	the panel can fine tune its behaviour according to the editor monitored.
+	
+	\note the Default implementation does nothing...
+*/
+void QPanel::editorChange(QEditor *)
+{
+	
+}
+
+bool QPanel::forward(QMouseEvent *e)
+{
+	QPoint pos, globalPos = e->globalPos(), ref = editor()->viewport()->pos();
+	
+	if ( editor()->viewport()->parentWidget() )
+		ref = editor()->viewport()->parentWidget()->mapToGlobal(ref);
+	
+	globalPos.setX(qBound(ref.x(), globalPos.x(), ref.x() + editor()->width()));
+	globalPos.setY(qBound(ref.y(), globalPos.y(), ref.y() + editor()->height()));
+	
+	pos = editor()->viewport()->mapFromGlobal(globalPos);
+	
+	QMouseEvent fw(
+					e->type(),
+					pos,
+					globalPos,
+					e->button(),
+					e->buttons(),
+					e->modifiers()
+				);
+	
+	bool ok = qApp->sendEvent(editor()->viewport(), &fw) && fw.isAccepted();
+	
+	//qDebug("forwarding mouse event : (%i, %i) => %i", pos.x(), pos.y(), ok);
+	
+	return ok;
+}
+
+/*!
+	\internal
+*/
+void QPanel::mouseMoveEvent(QMouseEvent *e)
+{
+	if ( !editor() )
+		return;
+	
+	if ( forward(e) )
+		e->accept();
+	else
+		QWidget::mouseMoveEvent(e);
+}
+
+/*!
+	\internal
+*/
+void QPanel::mousePressEvent(QMouseEvent *e)
+{
+	if ( !editor() )
+		return;
+	
+	if ( forward(e) )
+		e->accept();
+	else
+		QWidget::mousePressEvent(e);
+}
+
+/*!
+	\internal
+*/
+void QPanel::mouseReleaseEvent(QMouseEvent *e)
+{
+	if ( !editor() )
+		return;
+	
+	if ( forward(e) )
+		e->accept();
+	else
+		QWidget::mouseReleaseEvent(e);
+}
+
+/*!
+	\internal
+*/
+void QPanel::showEvent(QShowEvent *e)
+{
+	m_shownOnce = true;
+	
+	QWidget::showEvent(e);
+}
+
+/*!
+	\internal
+*/
+void QPanel::hideEvent(QHideEvent *e)
+{
+	QCodeEdit *ce = QCodeEdit::manager(editor());
+	
+	if ( ce )
+		ce->panelLayout()->update();
+	
+	QWidget::hideEvent(e);
+}
+
+/*!
+	\internal
+*/
+void QPanel::paintEvent(QPaintEvent *e)
+{
+	if ( !m_editor || !m_editor->document() )
+	{
+		e->ignore();
+		return;
+	}
+	
+	e->accept();
+	
+	QPainter p(this);
+	
+	if ( !paint(&p, m_editor) )
+		QWidget::paintEvent(e);
+}
+
+/*!
+	\internal
+*/
+bool QPanel::paint(QPainter *, QEditor *)
+{
+	/*
+	qWarning("Bad panel implementation : "
+			"QPanel::paint(QPainter*, QEditor*)"
+			" is a stub that should not get called."
+			"\nCheck out the code of %s", qPrintable(type()));
+	*/
+	return false;
+}
+
+/* @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qpanel.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QPANEL_H_
+#define _QPANEL_H_
+
+/*!
+	\file qpanel.h
+	\brief Definition of the QPanel class
+	
+	\see QPanel
+	
+	\defgroup widgets
+*/
+
+#include "qce-config.h"
+
+#include <QHash>
+#include <QWidget>
+#include <QPointer>
+
+class QPainter;
+class QPaintEvent;
+
+class QEditor;
+class QPanelCreator;
+
+class QCE_EXPORT QPanel : public QWidget
+{
+	Q_OBJECT
+	
+	public:
+		QPanel(QWidget *p = 0);
+		virtual ~QPanel();
+		
+		virtual QString id() const = 0;
+		virtual QString type() const = 0;
+		
+		QEditor* editor();
+		void attach(QEditor *e);
+		
+		virtual bool shallShow() const;
+		
+		bool defaultVisibility() const;
+		void setDefaultVisibility(bool on);
+		
+		static QPanel* panel(const QString& id, QWidget *p = 0);
+		static void registerCreator(QPanelCreator *c);
+		
+	protected:
+		virtual bool forward(QMouseEvent *e);
+		
+		virtual void editorChange(QEditor *e);
+		
+		virtual void mouseMoveEvent(QMouseEvent *e);
+		virtual void mousePressEvent(QMouseEvent *e);
+		virtual void mouseReleaseEvent(QMouseEvent *e);
+		
+		virtual void showEvent(QShowEvent *e);
+		virtual void hideEvent(QHideEvent *e);
+		virtual void paintEvent(QPaintEvent *e);
+		virtual bool paint(QPainter *p, QEditor *e);
+		
+	private:
+		QPointer<QEditor> m_editor;
+		bool m_defaultVisibility, m_shownOnce;
+		static QHash<QString, QPanelCreator*>& creators();
+};
+
+class QPanelCreator
+{
+	public:
+		virtual ~QPanelCreator() {}
+		virtual QString id() const = 0;
+		virtual QPanel* panel(QWidget *p) = 0;
+};
+
+#define Q_PANEL(T, SID)									\
+	public:												\
+	class Creator : public QPanelCreator				\
+	{ 													\
+		public: 										\
+			virtual QString id() const					\
+			{											\
+				return SID;								\
+			}											\
+														\
+			virtual QPanel* panel(QWidget *p)			\
+			{											\
+				return new T(p);						\
+			}											\
+														\
+			static QPanelCreator* instance()			\
+			{											\
+				static Creator global;					\
+				return &global;							\
+			}											\
+														\
+			Creator() {}								\
+			virtual ~Creator() {}						\
+	};													\
+														\
+	QString id() const { return SID; }					\
+														\
+	static void _register()								\
+	{													\
+		QPanel::registerCreator(Creator::instance());	\
+	}													\
+	
+
+#define Q_PANEL_ID(T)									\
+	T::Creator::instance()->id()						\
+	
+
+#define Q_CREATE_PANEL(T)								\
+	QPanel::panel(Q_PANEL_ID(T))						\
+	
+
+#endif // _QPANEL_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qsearchreplacepanel.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,535 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qsearchreplacepanel.h"
+
+/*!
+	\file qsearchreplacepanel.cpp
+	\brief Implementation of the QSearchReplacePanel class.
+	
+	\see QSearchReplacePanel
+*/
+
+#include "qeditor.h"
+
+#include "qdocument.h"
+#include "qdocumentline.h"
+#include "qdocumentcursor.h"
+#include "qdocumentsearch.h"
+
+#include <QScrollBar>
+#include <QPaintEvent>
+
+static QString escapeCpp(const QString& s, bool rep)
+{
+	if ( !rep )
+		return s;
+	
+	QString es;
+	
+	for ( int i = 0; i < s.count(); ++i )
+	{
+		if ( (s.at(i) == '\\') && ((i + 1) < s.count()) )
+		{
+			QChar c = s.at(++i);
+			
+			if ( c == '\\' )
+				es += '\\';
+			else if ( c == 't' )
+				es += '\t';
+			else if ( c == 'n' )
+				es += '\n';
+			else if ( c == 'r' )
+				es += '\r';
+			else if ( c == '0' )
+				es += '\0';
+			
+		} else {
+			es += s.at(i);
+		}
+	}
+	
+	//qDebug("\"%s\" => \"%s\"", qPrintable(s), qPrintable(es));
+	
+	return es;
+}
+
+/*!
+	\ingroup widgets
+	@{
+*/
+
+/*!
+	\class QSearchReplacePanel
+	\brief A panel that provide inline search/replace functionalities
+*/
+
+QCE_AUTO_REGISTER(QSearchReplacePanel)
+
+/*!
+	\brief Constructor
+*/
+QSearchReplacePanel::QSearchReplacePanel(QWidget *p)
+ : QPanel(p), lastDirection(0), m_search(0)
+{
+	setupUi(this);
+	setDefaultVisibility(false);
+	
+	leFind->installEventFilter(this);
+	leReplace->installEventFilter(this);
+}
+
+/*!
+	\brief Empty destructor
+*/
+QSearchReplacePanel::~QSearchReplacePanel()
+{
+	if ( m_search )
+		delete m_search;
+}
+
+/*!
+
+*/
+QString QSearchReplacePanel::type() const
+{
+	return "Search";
+}
+
+/*!
+	\brief 
+*/
+void QSearchReplacePanel::editorChange(QEditor *e)
+{
+	if ( editor() )
+	{
+		disconnect(	editor(), SIGNAL( cursorPositionChanged() ),
+					this	, SLOT  ( cursorPositionChanged() ) );
+	}
+	
+	if ( e )
+	{
+		connect(e	, SIGNAL( cursorPositionChanged() ),
+				this, SLOT  ( cursorPositionChanged() ) );
+	}
+}
+
+bool QSearchReplacePanel::forward(QMouseEvent *e)
+{
+	Q_UNUSED(e)
+	
+	/*
+		This panel does not need mouse events to be forwarded to the editor.
+		Even more, it requires them not to be forwarded...
+	*/
+	return false;
+}
+
+/*!
+
+*/
+void QSearchReplacePanel::display(int mode, bool replace)
+{
+	//qDebug("display(%i)", replace);
+	bool visible = true;
+	
+	if ( mode < 0 )
+		visible = (replace != cbReplace->isChecked()) || isHidden();
+	else
+		visible = mode;
+	
+	if ( visible )
+	{
+		cbReplace->setChecked(replace);
+		//frameReplace->setVisible(replace);
+		leFind->setFocus();
+		leFind->selectAll();
+		//show();
+	}
+	
+	setVisible(visible);
+	
+	if ( !visible )
+		editor()->setFocus();
+}
+
+/*!
+
+*/
+void QSearchReplacePanel::find(int backward)
+{
+	if ( !m_search )
+	{
+		if ( !isVisible() )
+		{
+			display(1, false);
+			return;
+		} else {
+			init();
+		}
+		
+		if ( backward != -1 )
+			lastDirection = backward;
+	}
+	
+	bool replaceAll = cbReplace->isChecked() && cbReplaceAll->isChecked();
+	
+	if ( backward == -1 )
+	{
+		backward = lastDirection;
+	} else {
+		if ( lastDirection != backward && editor()->cursor().hasSelection() && !replaceAll )
+			m_search->next(backward, false); //the first hit is already selected
+		
+		lastDirection = backward;
+	}
+	
+	m_search->next(backward, replaceAll);
+	
+	if ( !leFind->hasFocus() && !leReplace->hasFocus() )
+		leFind->setFocus();
+}
+
+/*!
+
+*/
+void QSearchReplacePanel::hideEvent(QHideEvent *)
+{
+	/*
+	if ( m_search )
+		delete m_search;
+	
+	m_search = 0;
+	*/
+}
+
+bool QSearchReplacePanel::eventFilter(QObject *o, QEvent *e)
+{
+	int kc;
+	
+	if ( o == leFind || o == leReplace )
+	{
+		switch ( e->type() )
+		{
+			/*
+			case QEvent::FocusIn :
+				leFind->grabKeyboard();
+				break;
+				
+			case QEvent::FocusOut :
+				leFind->releaseKeyboard();
+				break;
+				*/
+				
+			case QEvent::KeyPress :
+				
+				kc = static_cast<QKeyEvent*>(e)->key();
+				
+				if ( (kc == Qt::Key_Enter) || (kc == Qt::Key_Return) )
+				{
+					//on_leFind_returnPressed();
+					on_leFind_returnPressed(Qt::ShiftModifier & static_cast<QKeyEvent*>(e)->modifiers());
+					return true;
+				} else if ( kc == Qt::Key_Escape) {
+					if ( cbReplace->isChecked() )
+						display(1,false);
+					else
+						display(0,false);
+					return true;
+				} else if ( kc == Qt::Key_Tab || kc == Qt::Key_Backtab ) {
+					if ( cbReplace->isChecked() )
+					{
+						if ( leFind->hasFocus() )
+							leReplace->setFocus();
+						else
+							leFind->setFocus();
+					}
+					return true;
+				}
+				break;
+				
+			default:
+				break;
+		}
+	}
+	
+	return QWidget::eventFilter(o, e);
+}
+
+void QSearchReplacePanel::on_leFind_textEdited(const QString& text)
+{
+	if ( cbReplace->isChecked() )
+	{
+		// do not perfrom incremental search when replacing
+		
+		if ( m_search )
+			m_search->setSearchText(text);
+		
+		leFind->setStyleSheet(QString());
+		return;
+	}
+	
+	bool hadSearch = m_search;
+	QDocumentCursor cur = editor()->cursor();
+	
+	if ( m_search ) 
+	{
+		cur = m_search->cursor();
+		
+		m_search->setSearchText(text);
+		
+		if ( cbCursor->isChecked() )
+		{
+			QDocumentCursor c = cur;
+			c.setColumnNumber(qMin(c.anchorColumnNumber(), c.columnNumber()));
+			
+			m_search->setCursor(c);
+		}
+	} else {
+		// TODO : make incremental search optional
+		init();
+	}
+	
+	if ( text.isEmpty() )
+	{
+		leFind->setStyleSheet(QString());
+		return;
+	}
+	
+	m_search->setOption(QDocumentSearch::Silent, true);
+	
+	find(0);
+	
+	m_search->setOption(QDocumentSearch::Silent, false);
+	
+	if ( m_search->cursor().isNull() )
+	{
+		leFind->setStyleSheet("QLineEdit { background: red; color : white; }");
+		
+		if ( hadSearch )
+		{
+			m_search->setCursor(cur);
+			
+			// figure out whether other matches are availables
+			QDocumentSearch::Options opts = m_search->options();
+			opts &= ~QDocumentSearch::HighlightAll;
+			opts |= QDocumentSearch::Silent;
+			
+			QDocumentSearch temp(editor(), text, opts);
+			temp.setOrigin(QDocumentCursor());
+			temp.setScope(m_search->scope());
+			temp.next(true);
+			
+			if ( temp.cursor().isValid() )
+			{
+				// other match found from doc start
+				leFind->setStyleSheet("QLineEdit { background: yellow; color : black; }");
+				m_search->setCursor(cur.document()->cursor(0,0));
+				find(0);
+			}
+		}
+	} else {
+		leFind->setStyleSheet(QString());
+		editor()->setCursor(m_search->cursor());
+	}
+}
+
+void QSearchReplacePanel::on_leFind_returnPressed(bool backward)
+{
+	leFind->setStyleSheet(QString());
+	
+	if ( backward )
+		find(1);
+	else
+		find(0);
+	
+}
+
+void QSearchReplacePanel::on_leReplace_textEdited(const QString& text)
+{
+	if ( m_search )
+		m_search->setReplaceText(text);
+	
+}
+
+void QSearchReplacePanel::on_cbReplace_toggled(bool on)
+{
+	if ( m_search )
+		m_search->setOption(QDocumentSearch::Replace, on);
+	
+	if ( leFind->isVisible() )
+		leFind->setFocus();
+}
+
+void QSearchReplacePanel::on_cbWords_toggled(bool on)
+{
+	if ( m_search )
+		m_search->setOption(QDocumentSearch::WholeWords, on);
+	
+	leFind->setFocus();
+}
+
+void QSearchReplacePanel::on_cbRegExp_toggled(bool on)
+{
+	if ( m_search )
+		m_search->setOption(QDocumentSearch::RegExp, on);
+	
+	leFind->setFocus();
+}
+
+void QSearchReplacePanel::on_cbCase_toggled(bool on)
+{
+	if ( m_search )
+		m_search->setOption(QDocumentSearch::CaseSensitive, on);
+	
+	leFind->setFocus();
+}
+
+void QSearchReplacePanel::on_cbCursor_toggled(bool on)
+{
+	if ( m_search )
+	{
+		m_search->setOrigin(on ? editor()->cursor() : QDocumentCursor());
+		
+		if ( cbHighlight->isChecked() )
+			m_search->next(false);
+	}
+	
+	leFind->setFocus();
+}
+
+void QSearchReplacePanel::on_cbHighlight_toggled(bool on)
+{
+	if ( !m_search )
+		init();
+	
+	if ( m_search )
+	{
+		m_search->setOption(QDocumentSearch::HighlightAll, on);
+		
+		if ( on && !m_search->indexedMatchCount() )
+			m_search->next(false);
+	}
+	
+	leFind->setFocus();
+}
+
+void QSearchReplacePanel::on_cbSelection_toggled(bool on)
+{
+	if ( m_search )
+		m_search->setScope(on ? editor()->cursor() : QDocumentCursor());
+	
+	leFind->setFocus();
+}
+
+void QSearchReplacePanel::on_cbPrompt_toggled(bool on)
+{
+	if ( m_search )
+		m_search->setOption(QDocumentSearch::Prompt, on);
+	
+	leFind->setFocus();
+}
+
+void QSearchReplacePanel::on_cbEscapeSeq_toggled(bool on)
+{
+	if ( m_search )
+		m_search->setReplaceText(escapeCpp(leReplace->text(), on));
+}
+
+void QSearchReplacePanel::on_bNext_clicked()
+{
+	if ( !m_search )
+		init();
+	
+	leFind->setStyleSheet(QString());
+	find(0);
+}
+
+void QSearchReplacePanel::on_bPrevious_clicked()
+{
+	if ( !m_search )
+		init();
+	
+	leFind->setStyleSheet(QString());
+	find(1);
+}
+
+void QSearchReplacePanel::on_bRefresh_clicked()
+{
+	init();
+}
+
+void QSearchReplacePanel::init()
+{
+	if ( m_search )
+	{
+		delete m_search;
+		m_search = 0;
+	}
+	
+	QDocumentSearch::Options opt;
+	
+	if ( cbRegExp->isChecked() )
+		opt |= QDocumentSearch::RegExp;
+	
+	if ( cbCase->isChecked() )
+		opt |= QDocumentSearch::CaseSensitive;
+	
+	if ( cbWords->isChecked() )
+		opt |= QDocumentSearch::WholeWords;
+	
+	if ( cbHighlight->isChecked() && !cbReplace->isVisible() )
+		opt |= QDocumentSearch::HighlightAll;
+	
+	if ( cbReplace->isChecked() && cbReplace->isVisible() )
+		opt |= QDocumentSearch::Replace;
+	
+	if ( cbPrompt->isChecked() )
+		opt |= QDocumentSearch::Prompt;
+	
+	m_search = new QDocumentSearch(	editor(),
+									leFind->text(),
+									opt,
+									cbReplace->isChecked()
+										?
+											escapeCpp(leReplace->text(), cbEscapeSeq->isChecked())
+										:
+											QString()
+									);
+	
+	
+	if ( cbCursor->isChecked() )
+		m_search->setCursor(editor()->cursor());
+	
+	if ( cbSelection->isChecked() )
+		m_search->setScope(editor()->cursor());
+	
+}
+
+void QSearchReplacePanel::cursorPositionChanged()
+{
+	if ( m_search )
+	{
+		if ( editor()->cursor() == m_search->cursor() || cbHighlight->isChecked() )
+			return;
+		
+		if ( cbCursor->isChecked() )
+			m_search->setOrigin(editor()->cursor());
+		
+		m_search->setCursor(editor()->cursor());
+	}
+}
+
+/*! @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qsearchreplacepanel.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QSEARCH_REPLACE_PANEL_H_
+#define _QSEARCH_REPLACE_PANEL_H_
+
+#include "qpanel.h"
+
+/*!
+	\file qsearchreplacepanel.h
+	\brief Definition of the QSearchReplacePanel class.
+	
+	\see QSearchReplacePanel
+*/
+
+#include "ui_searchreplace.h"
+
+class QDocumentLine;
+class QDocumentSearch;
+
+class QCE_EXPORT QSearchReplacePanel : public QPanel, private Ui::SearchReplace
+{
+	Q_OBJECT
+	
+	public:
+		Q_PANEL(QSearchReplacePanel, "Search Replace Panel")
+		
+		QSearchReplacePanel(QWidget *p = 0);
+		virtual ~QSearchReplacePanel();
+		
+		virtual QString type() const;
+		
+	public slots:
+		void display(int mode, bool replace);
+		
+		void find(int backward = -1);
+		
+	protected:
+		virtual bool forward(QMouseEvent *e);
+		virtual void editorChange(QEditor *e);
+		
+		virtual bool eventFilter(QObject *o, QEvent *e);
+		
+		virtual void hideEvent(QHideEvent *e);
+		
+	private slots:
+		void on_leFind_textEdited(const QString& text);
+		void on_leReplace_textEdited(const QString& text);
+		
+		void on_cbReplace_toggled(bool on);
+		
+		void on_cbCase_toggled(bool on);
+		void on_cbWords_toggled(bool on);
+		void on_cbRegExp_toggled(bool on);
+		void on_cbCursor_toggled(bool on);
+		void on_cbHighlight_toggled(bool on);
+		void on_cbSelection_toggled(bool on);
+		void on_cbPrompt_toggled(bool on);
+		void on_cbEscapeSeq_toggled(bool on);
+		
+		void on_bRefresh_clicked();
+		
+		void on_bNext_clicked();
+		void on_bPrevious_clicked();
+		
+		void cursorPositionChanged();
+		
+	private:
+		void init();
+		void on_leFind_returnPressed(bool backward);
+		
+		int lastDirection;
+		QDocumentSearch *m_search;
+};
+
+#endif // _QSEARCH_REPLACE_PANEL_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qsimplecolorpicker.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qsimplecolorpicker.h"
+
+/*!
+	\file qsimplecolorpicker.cpp
+	\brief Implementation of the QSimpleColorPicker class
+*/
+
+#include <QIcon>
+#include <QPixmap>
+#include <QPainter>
+#include <QResizeEvent>
+#include <QColorDialog>
+
+QSimpleColorPicker::QSimpleColorPicker(QWidget *w)
+ : QToolButton(w)
+{
+	setColor(QColor());
+	
+	connect(this, SIGNAL( clicked() ), this, SLOT( clicked() ) );
+}
+
+QSimpleColorPicker::QSimpleColorPicker(const QColor& c, QWidget *w)
+ : QToolButton(w)
+{
+	setColor(c);
+	
+	connect(this, SIGNAL( clicked() ), this, SLOT( clicked() ) );
+}
+
+const QColor& QSimpleColorPicker::color() const
+{
+	return m_color;
+}
+
+void QSimpleColorPicker::setColor(const QColor& c)
+{
+	m_color = c;
+	
+	updateIcon(size());
+}
+
+void QSimpleColorPicker::resizeEvent(QResizeEvent *e)
+{
+	updateIcon(e->size());
+	
+	QToolButton::resizeEvent(e);
+}
+
+void QSimpleColorPicker::contextMenuEvent(QContextMenuEvent *e)
+{
+	setColor(QColor());
+	
+	e->accept();
+	
+	QToolButton::contextMenuEvent(e);
+}
+
+void QSimpleColorPicker::updateIcon(const QSize& sz)
+{
+	QPixmap px(sz.width() - 3, sz.height() - 3);
+	QPainter p(&px);
+	
+	if ( m_color.isValid() )
+	{
+		p.fillRect(0, 0, px.width(), px.height(), m_color);
+		setIcon(QIcon(px));
+	} else {
+		//p.fillRect(0, 0, px.width(), px.height(), palette().window());
+		setIcon(QIcon());
+	}
+}
+
+void QSimpleColorPicker::clicked()
+{
+	QColor c = QColorDialog::getColor(m_color);
+	
+	if ( c.isValid() )
+	{
+		setColor(c);
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qsimplecolorpicker.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QSIMPLE_COLOR_PICKER_H_
+#define _QSIMPLE_COLOR_PICKER_H_
+
+#include "qce-config.h"
+
+/*!
+	\file qsimplecolorpicker.h
+	\brief Definition of the QSimpleColorPicker class
+*/
+
+#include <QToolButton>
+
+class QCE_EXPORT QSimpleColorPicker : public QToolButton
+{
+	Q_OBJECT
+	
+	Q_PROPERTY(QColor color READ color WRITE setColor)
+	
+	public:
+		QSimpleColorPicker(QWidget *w = 0);
+		QSimpleColorPicker(const QColor& c, QWidget *w = 0);
+		
+		const QColor& color() const;
+		
+	protected:
+		void resizeEvent(QResizeEvent *e);
+		void contextMenuEvent(QContextMenuEvent *e);
+		
+	public slots:
+		void setColor(const QColor& c);
+		
+		void updateIcon(const QSize& sz);
+		
+	private slots:
+		void clicked();
+		
+	private:
+		QColor m_color;
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qstatuspanel.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#include "qstatuspanel.h"
+
+/*!
+	\file qstatuspanel.cpp
+	\brief Implementation of the QStatusPanel class.
+	
+	\see QStatusPanel
+*/
+
+#include "qeditor.h"
+
+#include "qdocument.h"
+#include "qdocumentline.h"
+#include "qdocumentcursor.h"
+
+#include <QTimer>
+#include <QPainter>
+#include <QDateTime>
+#include <QPaintEvent>
+#include <QFontMetrics>
+#include <QApplication>
+
+/*!
+	\ingroup widgets
+	@{
+*/
+
+/*!
+	\class QStatusPanel
+	\brief A panel that display some status informations 
+*/
+
+QCE_AUTO_REGISTER(QStatusPanel)
+
+/*!
+	\brief Constructor
+*/
+QStatusPanel::QStatusPanel(QWidget *p)
+ : QPanel(p)
+{
+	setFixedHeight(fontMetrics().lineSpacing() + 4);
+}
+
+/*!
+	\brief Empty destructor
+*/
+QStatusPanel::~QStatusPanel()
+{
+	
+}
+
+/*!
+
+*/
+QString QStatusPanel::type() const
+{
+	return "Status";
+}
+
+/*!
+
+*/
+void QStatusPanel::editorChange(QEditor *e)
+{
+	if ( editor() )
+	{
+		disconnect(	editor(), SIGNAL( cursorPositionChanged() ),
+					this	, SLOT  ( update() ) );
+		
+	}
+	
+	if ( e )
+	{
+		connect(e	, SIGNAL( cursorPositionChanged() ),
+				this, SLOT  ( update() ) );
+		
+	}
+}
+
+/*!
+
+*/
+bool QStatusPanel::paint(QPainter *p, QEditor *e)
+{
+	//qDebug("drawing status panel... [%i, %i, %i, %i]",
+	//		geometry().x(),
+	//		geometry().y(),
+	//		geometry().width(),
+	//		geometry().height());
+	static QPixmap _warn(":/warning.png"), _mod(":/save.png");
+	
+	QString s;
+	int xpos = 10;
+	QDocumentCursor c = e->cursor();
+	const QFontMetrics fm(fontMetrics());
+	
+	const int ls = fm.lineSpacing();
+	const int ascent = fm.ascent() + 3;
+	
+	s = tr("Line : %1 Visual column : %2 Text column : %3")
+			.arg(c.lineNumber() + 1)
+			.arg(c.visualColumnNumber())
+			.arg(c.columnNumber());
+	
+	p->drawText(xpos, ascent, s);
+	xpos += fm.width(s) + 10;
+	
+	int sz = qMin(height(), _mod.height());
+	//int lastMod = d->lastModified().secsTo(QDateTime::currentDateTime());
+	//QString timeDiff = tr("(%1 min %2 s ago)").arg(lastMod / 60).arg(lastMod % 60);
+	
+	//xpos += 10;
+	if ( e->isContentModified() )
+	{
+		p->drawPixmap(xpos, (height() - sz) / 2, sz, sz, _mod);
+		//xpos += sz;
+		//xpos += 10;
+		//p->drawText(xpos, ascent, timeDiff);
+	}
+	xpos += sz + 10;
+	//xpos += fm.width(timeDiff);
+	//xpos += 20;
+	
+	s = editor()->flag(QEditor::Overwrite) ? tr("OVERWRITE") : tr("INSERT");
+	p->drawText(xpos, ascent, s);
+	xpos += fm.width(s) + 10;
+	
+	m_conflictSpot = 0;
+	
+	if ( editor()->isInConflict() )
+	{
+		s =  tr("Conflict");
+		int w = fm.width(s) + 30;
+		
+		if ( xpos + w + _warn.width() < width() )
+		{
+			m_conflictSpot = width() - (w + _warn.width());
+			p->drawText(width() - w + 15, ascent, s);
+			p->drawPixmap(m_conflictSpot, (ls - _warn.height()) / 2 + 2, _warn);
+		} else if ( xpos + _warn.width() < width() ) {
+			m_conflictSpot = width() - _warn.width();
+			p->drawPixmap(m_conflictSpot, (ls - _warn.height()) / 2 + 2, _warn);
+		}
+	}
+	
+	setFixedHeight(ls + 4);
+	
+	QTimer::singleShot(1000, this, SLOT( update() ) );
+	
+	return true;
+}
+
+/*!
+
+*/
+void QStatusPanel::mousePressEvent(QMouseEvent *e)
+{
+	if ( !editor() || (e->button() != Qt::LeftButton) || !m_conflictSpot || e->x() < m_conflictSpot )
+	{
+		editor()->setFocus();
+		return;
+	}
+	
+	editor()->save();
+}
+
+/*!
+
+*/
+void QStatusPanel::mouseReleaseEvent(QMouseEvent *e)
+{
+	Q_UNUSED(e)
+	
+	editor()->setFocus();
+}
+
+/*! @} */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/qstatuspanel.h	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2006-2009 fullmetalcoder <fullmetalcoder@hotmail.fr>
+**
+** This file is part of the Edyuk project <http://edyuk.org>
+** 
+** This file may be used under the terms of the GNU General Public License
+** version 3 as published by the Free Software Foundation and appearing in the
+** file GPL.txt included in the packaging of this file.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef _QSTATUS_PANEL_H_
+#define _QSTATUS_PANEL_H_
+
+#include "qpanel.h"
+
+/*!
+	\file qstatuspanel.h
+	\brief Definition of the QStatusPanel class.
+	
+	\see QStatusPanel
+*/
+
+class QLabel;
+
+class QDocumentLine;
+
+class QCE_EXPORT QStatusPanel : public QPanel
+{
+	Q_OBJECT
+	
+	public:
+		Q_PANEL(QStatusPanel, "Status Panel")
+		
+		QStatusPanel(QWidget *p = 0);
+		virtual ~QStatusPanel();
+		
+		virtual QString type() const;
+		
+	protected:
+		virtual void editorChange(QEditor *e);
+		virtual bool paint(QPainter *p, QEditor *e);
+		
+		virtual void mousePressEvent(QMouseEvent *e);
+		virtual void mouseReleaseEvent(QMouseEvent *e);
+		
+	private:
+		int m_conflictSpot;
+};
+
+#endif // _QSTATUS_PANEL_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gui//qcodeedit-2.2.3/widgets/searchreplace.ui	Mon Apr 11 18:44:09 2011 +0200
@@ -0,0 +1,514 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SearchReplace</class>
+ <widget class="QWidget" name="SearchReplace">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>801</width>
+    <height>82</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout">
+   <property name="spacing">
+    <number>0</number>
+   </property>
+   <property name="leftMargin">
+    <number>2</number>
+   </property>
+   <property name="topMargin">
+    <number>2</number>
+   </property>
+   <property name="rightMargin">
+    <number>2</number>
+   </property>
+   <property name="bottomMargin">
+    <number>1</number>
+   </property>
+   <item>
+    <widget class="QFrame" name="frameSearch">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>16</width>
+       <height>24</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>16777215</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="frameShape">
+      <enum>QFrame::NoFrame</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <layout class="QHBoxLayout">
+      <property name="spacing">
+       <number>2</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QToolButton" name="bClose">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Close search/replace panel</string>
+        </property>
+        <property name="text">
+         <string/>
+        </property>
+        <property name="icon">
+         <iconset resource="../../../../src/lib/images/Edyuk.qrc">
+          <normaloff>:/closeall.png</normaloff>:/closeall.png</iconset>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="bRefresh">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Refresh search underlying context (as an attempt to correct search behavior)</string>
+        </property>
+        <property name="text">
+         <string/>
+        </property>
+        <property name="icon">
+         <iconset resource="../../../../src/lib/images/Edyuk.qrc">
+          <normaloff>:/reload.png</normaloff>:/reload.png</iconset>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLabel" name="label">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string> Find :</string>
+        </property>
+        <property name="alignment">
+         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="leFind">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Maximum">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>120</width>
+          <height>22</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>120</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Text or pattern to search for</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="bNext">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Find next occurence</string>
+        </property>
+        <property name="text">
+         <string/>
+        </property>
+        <property name="icon">
+         <iconset resource="../../../../src/lib/images/Edyuk.qrc">
+          <normaloff>:/down.png</normaloff>:/down.png</iconset>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QToolButton" name="bPrevious">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Fixed" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>20</width>
+          <height>20</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Find previous occurence</string>
+        </property>
+        <property name="text">
+         <string/>
+        </property>
+        <property name="icon">
+         <iconset resource="../../../../src/lib/images/Edyuk.qrc">
+          <normaloff>:/up.png</normaloff>:/up.png</iconset>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer>
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Expanding</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cbWords">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Words</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cbCursor">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Cursor</string>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cbSelection">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Selection</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cbHighlight">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Highlight all</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cbRegExp">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Regexp</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cbCase">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Case</string>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QFrame" name="frameReplace">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize">
+      <size>
+       <width>16</width>
+       <height>24</height>
+      </size>
+     </property>
+     <property name="maximumSize">
+      <size>
+       <width>16777215</width>
+       <height>16777215</height>
+      </size>
+     </property>
+     <property name="frameShape">
+      <enum>QFrame::NoFrame</enum>
+     </property>
+     <property name="frameShadow">
+      <enum>QFrame::Plain</enum>
+     </property>
+     <layout class="QHBoxLayout">
+      <property name="spacing">
+       <number>2</number>
+      </property>
+      <property name="margin">
+       <number>0</number>
+      </property>
+      <item>
+       <widget class="QCheckBox" name="cbReplace">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Replace :</string>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QLineEdit" name="leReplace">
+        <property name="enabled">
+         <bool>true</bool>
+        </property>
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="minimumSize">
+         <size>
+          <width>168</width>
+          <height>22</height>
+         </size>
+        </property>
+        <property name="maximumSize">
+         <size>
+          <width>1200</width>
+          <height>16777215</height>
+         </size>
+        </property>
+        <property name="toolTip">
+         <string>Replacement text</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <spacer>
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeType">
+         <enum>QSizePolicy::Preferred</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>139</width>
+          <height>24</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cbPrompt">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Prompt on replace</string>
+        </property>
+        <property name="checked">
+         <bool>true</bool>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cbReplaceAll">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Replace all</string>
+        </property>
+       </widget>
+      </item>
+      <item>
+       <widget class="QCheckBox" name="cbEscapeSeq">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Escape sequences</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../../../src/lib/images/Edyuk.qrc"/>
+ </resources>
+ <connections>
+  <connection>
+   <sender>cbReplace</sender>
+   <signal>toggled(bool)</signal>
+   <receiver>frameReplace</receiver>
+   <slot>setVisible(bool)</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>46</x>
+     <y>47</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>249</x>
+     <y>49</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>bClose</sender>
+   <signal>clicked()</signal>
+   <receiver>SearchReplace</receiver>
+   <slot>hide()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>11</x>
+     <y>15</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>202</x>
+     <y>-27</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
--- a/gui//src/QTerminalWidget.cpp	Mon Apr 11 17:45:06 2011 +0200
+++ b/gui//src/QTerminalWidget.cpp	Mon Apr 11 18:44:09 2011 +0200
@@ -168,7 +168,7 @@
     m_impl->m_terminalDisplay->setScrollBarPosition((TerminalDisplay::ScrollBarPosition)pos);
 }
 
-void QTerminalWidget::sendText(QString &text)
+void QTerminalWidget::sendText(const QString &text)
 {
     m_impl->m_session->sendText(text); 
 }
--- a/gui//src/QTerminalWidget.h	Mon Apr 11 17:45:06 2011 +0200
+++ b/gui//src/QTerminalWidget.h	Mon Apr 11 18:44:09 2011 +0200
@@ -69,7 +69,7 @@
     void setScrollBarPosition(ScrollBarPosition);
     
     /** Send some text to the terminal. */
-    void sendText(QString &text);
+    void sendText(const QString &text);
             
 signals:
     /** Emitted, when the current program has finished. */