pax_global_header00006660000000000000000000000064137472171250014523gustar00rootroot0000000000000052 comment=c3a846009bc927828f184d7ec31ba63e56deb195 FeatherNotes-0.8.0/000077500000000000000000000000001374721712500141175ustar00rootroot00000000000000FeatherNotes-0.8.0/COPYING000066400000000000000000001045141374721712500151570ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. 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. Copyright (C) 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 . 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: Copyright (C) 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 . 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 . FeatherNotes-0.8.0/ChangeLog000066400000000000000000000322071374721712500156750ustar00rootroot00000000000000V0.8.0 --------- * Added support for customized background/foreground colors. * Updated the code for Qt 5.15. * Added overwrite prompt for HTML exporting. * Added a configurable date and time pasting. * Fixed an issue in changing the font of visited nodes. * Don't clear replacement highlights when the window is minimized or hidden. * Highlight only the first 1000 replacements if there are more. * Added an option for starting with the last opened file. * Removed the option for scroll jump workaround (because it wasn't FeatherNotes' job). * Prevent the editor font from changing when the application font changes. V0.7.0 --------- * Focus the visible unfocused search bar on activating its action. * Handle relative file paths correctly. * Overrode Qt's default behavior with the Home key. * Added optional spell checking with Hunspell, that can be enabled at compilation time. * Update the transparent side-pane's palette if the style changes in runtime. V0.6.0 --------- * Made some strings translatable. * Fixed a potential issue in translations. * Fixed a rare case of halted auto-saving. * Added a workaround for an old Qt bug, because of which, QTimer may not work after resuming from suspend or hibernation. * Give focus to text-edit/side-pane with Escape. * Don't let custom shortcuts be read from global config files. * Yet smarter Shift+Enter with alphabetical lists. V0.5.1 --------- * Considered the new behavior of horizontal wheel scrolling in Qt 5.14.0. * Added a workaround for the bug in horizontal scrollbars of Qt 5.14.0. V0.5.0 --------- * No need to elide the systray tooltip. * Added a shortcut editor to Preferences for customizing shortcuts. * Don't allow multiple custom shortcuts for one action. This is also a workaround for Qt's Meta key bug, that treats Meta like a non-modifier. * Added an info bar to Preferences. It shows up only when needed. * Always remember the Preferences dialog size. * Set the selected text and highlight colors if those of the app style aren't suitable. * Better placement of text context menu actions. * Replaced the Qt methods that were deprecated by Qt 5.13. * Basic Hurd support. * Don't let the current item change during a tree DND. * Drag a tree node only if there is a real mouse movement (and not when the view is scrolled by the wheel of a motionless mouse). * Smarter Shift+Enter, especially with numbered lists. * Added an option for auto-replacing (triple periods, double hyphens, etc.). * On triple clicking, select the current block without selecting its newline and start and end whitespaces. * Smooth wheel scrolling (touchpad scrolling is already smooth). * Fixed a problem in backward search and replacement. * Fixes for RTL, including a workaround for a Qt bug. V0.4.6 --------- * Removed an old workaround for KDE's clipboard. * Use C++11 raw string literals (thanks to shlyakpavel at GitHub). * Set the point size of the default document font to that of the widget font. * No focus for search buttons. * Many (similar) fixes in searching, replacing, printing and exporting. * Dropped QDesktopWidget. * Don't auto-save deleted files. * Allow compilation without X11. * macOS support by shlyakpavel at GitHub. * Fixed pasting of images into the doc. * Fixed DND with an image without extension. * Added an option for small toolbar icon size. * Separated the preferences code for adding new options more easily. * Update settings when the Preferences dialog is shown (because settings may have been changed in another FeatherNotes window). * Allow opening docs by DND. * Added a magic string to `text/feathernotes-fnx` but the extension has priority. V0.4.5 --------- * Added some text-editor shortcuts of FeatherPad. * Auto-bracketing support. * Better text tabulation. * Translation support. * Added SVG symbolic icons (that change color to have high contrast with their backgrounds) and removed system icon support because some important icons may not be found in system themes. * Support node icons. * First try "gio" for opening hyperlinks because Qt may resort to "xdg-open", which isn't a good choice sometimes. * Polish translation and a fix by Marcin Mikołajczak (m4sk1n at GitHub). * Added a workaround for a new bug in KDE's file dialog, which doesn't change directory with selectFile(). * Wayland support. V0.4.4 --------- * Transformed signal-slot connections into the new syntax. * Removed saving of window states because although it works with well-behaved window managers like kwin and openbox, some WM's don't respect window states completely. * Added a preliminary help doc. * Don't respond to the tray icon when there's a dialog! * Put the real image scale in the scale dialog! * Implemented auto-scrolling to selected file in file dialogs. * Added the ability to save selected images. * Added support for text zooming with Ctrl+wheel. * An option to set a fixed start size (700x500 by default). * Set minimum widths of some message boxes. * Changed node moving shortcuts from Ctrl+ to Alt+ for all of them to work when the text edit has focus. * Don't let a selected node be deselected by Ctrl + left click! * Fixed text direction (for RTL). * A workaround for Qt's backward search bug. * Removed the translucency workaround. * A method for bypassing focus stealing prevention. * Options for hiding toolbar or menubar. * An option to choose between own and system icons. * An option for a transparent tree view. * Support Shift+Enter (useful e.g. to create lists). V0.4.3 --------- * Readded own icons because, first, not all icon themes have all the needed icons and, second, QTBUG-50829 exists. * Interpret relative URLs as local paths. * Removed the senseless stylesheet of search and replace buttons. * When activating the window by clicking on the tray icon, also consider the current viewport in addition to the current desktop. For example, Compiz has only one desktop, which may be divided into multiple viewports. * When closing a node, consider the possibility that it may be the last node. * Added a minimal support for Enlightenment. V0.4.2 --------- * At last, found a simple workaround for Qt5's scroll jump bug. * Also unminimize the window if the tray icon is clicked. * At startup, wait 1 min for the system tray. * Don't hide but minimize the window on closing if the tray icon couldn't be created. * Added a "Raise/Hide" item to the tray menu. * Removed the Enlightenment setting. (Why caring for Enlightenment when it wants to have its own world?). * Never use native dialogs (since KFileDialog can't be trusted). * Fixed an old bug in auto-indentation. * Explicitly delete the timer and tray icon on exiting. V0.4.1 --------- * Removed own icons. * Added a setting for Enlightenment. * Included the header of QDataStream in 'simplecrypt.cpp' for compilation against Qt 5.5.1. * Set the modification flag on the main window. V0.4 --------- * Exported to Qt5 because Qt 5.4.2 seems OK. * Workaround for a Qt5 bug, which prevents insertion of the non-breaking space (zero-width non-joiner, ZWNJ) with SHIFT+SPACE. V0.3.1 --------- * Made the systray icon optional and added a command line option for starting minimized. * Give the main window an ID when starting minimized to tray for translucency to work with Kvantum. V0.3 --------- * Use QStackedWidget instead of QTabWidget. V0.2.5 --------- * Reversed the last three changes made in V0.2.4 and used another method for hiding/showing window based on reparenting with a dummy widget. * Guarantee a fixed height for lineedits. * Don't increase the row height; leave it to the style in use. V0.2.4 --------- * Faster mouse wheel scrolling when the mouse cursor is on the vertical scrollbar. * Rehighlight found matches after zooming out or changing font. * Emit resized() for TextEdit from resizeEvent() and not from event() because "QEvent::Resize" doesn't cover all kinds of resizing. * For returning to the default size to be possible under all circumstances, hide the window before resizing and show it again afterward. * On quitting with the tray icon, show the window only if something is unsaved. * Use changeEvent() to get the window state because not all window managers trigger resizeEvent() when a window is unmaximized. * Minimize the window without taskbar icon instead of hiding it when its tray icon is clicked. Only in this way, its state info is correctly preserved. * Instead of moving to the current desktop, hide and show the window to preserve its state info correctly. * Don't use native open or save dialogs because they may cause problems when "Qt::WA_WState_Created" is reset after showing the window in trayActivated(). V0.2.3 --------- * Put setGeometry() in showEvent() to make restoration of position possible with translucency. * Don't clear Qt::WA_WState_Created with translucency (-> BlurHelper() in oxygenblurhelper.cpp from oxygen-transparent). * Remove the settings for "max" and "fullscreen" when the window size isn't saved. * Under KDE, when text is selected for the first time after starting FeatherNotes, it isn't copied to the selection clipboard. Although I still don't know the cause (Klipper?), I found a workaround. * Activate auto-saving again if opening of another file is canceled. V0.2.2 --------- * Added text direction menu items and toolbar buttons because sometimes the direction isn't set automatically. * Keep tack of the window state and size even if they aren't supposed to be remembered because they're used when the tray icon is clicked. * By clearing the attribute "Qt::WA_WState_Created" before setGeometry() and setting it again after showing the window, the window positioning will be correct under all window managers on clicking the tray icon (see QWidget::setGeometry() in qwidget.cpp). So, there's no need to an extra option for position enforcing anymore. V0.2.1 --------- * Added '/usr/lib/x86_64-linux-gnu/libX11.so' as a system library to the project to fix the new error messages "x11.o: undefined reference to symbol...". * Don't use at() before checking the list size. * Made the background of the text area white with light themes. * Use tooltips in the Preferences dialog. * Also save the geometric settings on closing the Preferences dialog. * Always use restoreState() for the splitter. * Don't use setFixedSize() or resize() with dialogs because they may prevent them from being centered when shown. * Added an option for enforcing position when it's saved on exit because even by using the position of the client area, correct positioning isn't possible with all window managers or decorations. V0.2 --------- * Made FeatherNotes independent from any icon set. * Cleaned up auto-saving. * Added file path to the status bar info. * Change the status bar info when needed. * Always focus the text widget after raising the window with the tray icon. * Fixed bugs in searching for multiline strings. * When text is selected, use the left and right arrow keys to go to the start and end of the selection respectively. * Use the position of the client area for correct positioning under all desktop environments, including Gnome-Shell. V0.1.9 --------- * Set the text cursor at the position of right clicking if no text is selected. * When highlighting found matches, search for them only inside the visible part of the text. * Consider case-sensitivity when skipping nodes that don't contain the search string. * Use formatChanged() to set the pressed states of the format buttons after changing format. * If some text is selected and the cursor is put somewhere inside the selection with mouse, Qt may not emit currentCharFormatChanged() when it should. A workaround is added for this bug. * No need to enforce a central position for dialogs anymore. V0.1.8 --------- * Added keyboard shortcuts for text zooming (without changing the font size). V0.1.7 --------- * Don't write useless HTML code when there's nothing to see. * Added tree properties and menu based node renaming. * Close tag matches dialog when starting another type of search. * Added node name search. * Always use raise() after activateWindow(). V0.1.6 --------- * Added support for encryption and password protection. * Added command-line option. * Always cancel search if the search bar is closed. V0.1.5 --------- * Printing is complete now. * Added HTML export. V0.1.4 --------- * Added support for text tables. * Fixes. V0.1.3 --------- * Added support for clickable links. * Custom context menus for TextEdits. V0.1.2 --------- * Consider returnPressed() in line-edits and spin-boxes as confirmation in most dialogs. * When FeatherNotes is started minimized to tray, bring it to the current desktop on clicking its tray icon. * Always expand the current node after adding a child to it. * Added a context menu to the tree-view. * Added a keyboard shortcut for toggling minimization to tray (useful when in fullscreen). * Care for window states when showing the window from the tray. * Added icons for GTK+ based environments. V0.1.1 --------- * Implemented the ability to add searchable tags to each node (something I missed since I stopped using NoteCase after it went closed-source). V0.1 --------- * FeatherNotes is reborn in Qt :) And it's far better than its GTK+ predecessor. It's quite usable but not finished yet. FeatherNotes-0.8.0/INSTALL000066400000000000000000000053201374721712500151500ustar00rootroot00000000000000To compile FeatherNotes from its source, first install build dependencies. In Debian-based systems, they are: * g++ >= 5 * libx11-dev and libxext-dev (for X11) * qtbase5-dev and libqt5x11extras5-dev (for Qt5) * libqt5svg5-dev (for hard-coded SVG icons) * qttools5-dev-tools (for localization) * libhunspell-dev (optional, for spell checking) In Arch-based systems, the required package are: * gcc (or gcc-multilib for multilib systems) * libx11 and libxext (for X11) * qt5-base and qt5-x11extras (for Qt5) * qt5-svg (for hard-coded SVG icons) * qt5-tools (for localization) * hunspell (optional, for spell checking) In Red Hat based systems like Fedora: * gcc-c++ * libX11-devel * libXext-devel * qt5-qtx11extras-devel * qt5-qtbase-devel * qt5-qtsvg-devel * qt5-qttools-devel * hunspell-devel (optional, for spell checking) And, finally, in OpenSUSE: * gcc-c++ * libX11-devel * libXext-devel * libqt5-qtx11extras-devel * libqt5-qtbase-devel * libqt5-qtsvg-devel * libqt5-qttools-devel * hunspell-devel (optional, for spell checking) Then, open a terminal inside this folder and issue the following commands: qmake && make sudo make install If your default Qt installation is not Qt5, put the full path of Qt5 qmake in the first command but before that, put the full path of Qt5's "lrelease" binary into 'feathernotes/feathernotes.pro' (only one place). Afterward, you could use this command for cleaning the source directory: make distclean ********************************* * Compilation with Hunspell * ********************************* Under Linux and Unix, FeatherNotes supports spell checking with Hunspell if it is compiled with: qmake WITH_HUNSPELL=YES make See above for the build dependency. ******************************* * Compilation without X11 * ******************************* If you do not want the X11 support, you could compile FeatherNotes with: qmake WITHOUT_X11=YES make The result will have all features except for virtual desktop awareness. Please also note that, on Linux, FeatherNotes works under Wayland and you do not need to disable its X11 support for that. Compilation on macOS does not require "WITHOUT_X11=YES" either. ********************************** * Translation (Localization) * ********************************** The file 'feathernotes/data/translations/feathernotes.ts' can serve as the basis for translation. The translated file should be saved in the same directory as "feathernotes_LN.ts", where "LN" is the abbreviation for the target language, like "de", "fr", etc. If you have translated FeatherNotes's GUI into your language, please make a "Pull Request" (PR) at https://github.com/tsujan/FeatherNotes for your work to be merged into FeatherNotes! FeatherNotes-0.8.0/NEWS000066400000000000000000000001031374721712500146100ustar00rootroot00000000000000Latest version: 9 Oct 2020, V0.8.0 See "ChangeLog" for changes. FeatherNotes-0.8.0/README.md000066400000000000000000000026631374721712500154050ustar00rootroot00000000000000# FeatherNotes ## Overview FeatherNotes (by Pedram Pourang, a.k.a. Tsu Jan ) is a lightweight Qt hierarchical notes-manager for Linux. It is independent of any desktop environment and has: * Support for rich text formatting, image embedding and inserting editable tables; * Drag-and-drop capability for moving nodes and also for embedding images; * A tray icon for quick access on any desktop; * Correct position/size saving and restoring with most window managers; * Compact but complete search and replacement widgets; * The ability to include searchable tags (hidden info on each node); * Support for optional node icons; * Support for local and remote hyperlinks (bookmarks); * Text zooming; * Printing and exporting to HTML and PDF; * Password protection; * Auto-saving; * Optional spell checking with Hunspell (if enabled at compilation time); * macOS support (by [Pavel Shlyak](https://github.com/shlyakpavel)); and * Other features that can be found in its settings, on its menus or when it is actually used. Please see [INSTALL](INSTALL) for instructions on compilation, installation and translation! FeatherNotes' homepage is . ## Screenshot The active Qt widget style determines the look and feel of every Qt application. The following screenshot is taken with a Kvantum theme: ![FeatherNotes](screenshots/FeatherNotes.png?raw=true "FeatherNotes") FeatherNotes-0.8.0/feathernotes/000077500000000000000000000000001374721712500166065ustar00rootroot00000000000000FeatherNotes-0.8.0/feathernotes/about.ui000066400000000000000000000355071374721712500202710ustar00rootroot00000000000000 FeatherNotes::AboutDialog 0 0 400 300 Dialog 0 Qt::AlignCenter Qt::AlignCenter Qt::AlignCenter Qt::Vertical 20 5 Qt::Vertical 20 5 Qt::NoFocus <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Chinese:</span> You-Sheng Yang <a href="https://github.com/vicamo">(vicamo at GitHub)</a>, <a href="https://github.com/BavonChao">BavonChao at GitHub</a>, <a href="https://github.com/theyearthewas">theyearthewas at GitHub</a></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Czech:</span> <a href="https://github.com/p-bo">p-bo at GitHub</a></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Dutch:</span> Heimen Stoffels <a href="https://github.com/Vistaus">(Vistaus at GitHub)</a>, <a href="https://github.com/Pjotr123">Pjotr123 at GitHub</a>, <a href="https://github.com/PanderMusubi">PanderMusubi at GitHub</a></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Esperanto:</span> Tsu Jan (author)</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">French:</span> roxfr</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">German:</span> Alf Gaida <a href="https://github.com/agaida">(agaida at GitHub)</a>, Oliver Burkardt <a href="https://github.com/OliverBurkardt">(OliverBurkardt at GitHub)</a>, Ettore Atalan <a href="https://github.com/Atalanttore">(Atalanttore at GitHub)</a>, Pavel Shlyak <a href="https://github.com/shlyakpavel">(shlyakpavel at GitHub)</a></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Hebrew:</span> Yaron Shahrabani <a href="https://github.com/yarons">(yarons at GitHub)</a></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Hungarian:</span> <a href="https://github.com/zoli111">zoli111 at GitHub</a></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Indonesian:</span> Gema Aji Wardian <a href="https://github.com/nerdv2">(nerdv2 at GitHub)</a></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Japanese:</span> Masamichi Ito <a href="https://github.com/ito32bit">(ito32bit at GitHub)</a</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Lithuanian:</span> <a href="https://github.com/welaq">welaq at GitHub</a></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Polish:</span> Marcin Mikołajczak <a href="https://github.com/m4sk1n">(m4sk1n at GitHub)</a></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Portuguese (Brazil):</span> <a href="https://github.com/eltonfabricio10">eltonfabricio10 at GitHub</a>, Erik Kierski <a href="https://github.com/erikferki">(erikferki at GitHub)</a></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Portuguese (Portugal):</span> Ruan O. Lima</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Russian:</span> Pavel Shlyak <a href="https://github.com/shlyakpavel">(shlyakpavel at GitHub)</a>, Schwonder Reismus <a href="https://github.com/schw0reismus">(schw0reismus at GitHub)</a>, Николай Смольянинов <a href="https://github.com/smolnp">(smolnp at GitHub)</a></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Spanish:</span> <a href="https://github.com/micrococo">micrococo at GitHub</a>, Maximiliano Dvyhailo <a href="https://github.com/MaxiDvy"><span;>(MaxiDvy at GitHub)</span></a>, Robert Schneider</p></body></html> true License Qt::NoFocus <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">FeatherNotes</span> 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 <a href="https://spdx.org/licenses/GPL-3.0+.html">version 3 of the License</a>, or (at your option) any later version.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">FeatherNotes</span> is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.</p></body></html> true Qt::Horizontal QDialogButtonBox::Close buttonBox accepted() AboutDialog accept() 199 279 199 149 buttonBox rejected() AboutDialog reject() 199 279 199 149 FeatherNotes-0.8.0/feathernotes/colorLabel.cpp000066400000000000000000000035321374721712500213730ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016-2020 * * FeatherNotes 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. * * FeatherNotes 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 . */ #include "colorLabel.h" #include #include #include namespace FeatherNotes { ColorLabel::ColorLabel (QWidget *parent, Qt::WindowFlags f) : QLabel (parent, f) { setFrameStyle (QFrame::Panel | QFrame::Sunken); setLineWidth (1); setMinimumWidth (100); setToolTip (tr ("Click to change color.")); color_ = palette().color (QPalette::Window); } ColorLabel::~ColorLabel() {} void ColorLabel::setColor (const QColor &color) { if (!color.isValid()) return; color_ = color; color_.setAlpha (255); } QColor ColorLabel::getColor() const { return color_; } void ColorLabel::mousePressEvent (QMouseEvent* /*event*/) { QColor prevColor = getColor(); QColor color = QColorDialog::getColor (prevColor, window(), tr ("Select Color")); if (color.isValid() && color != prevColor) setColor (color); } void ColorLabel::paintEvent (QPaintEvent* /*event*/) { QPainter p (this); p.fillRect (contentsRect(), color_); QStyleOptionFrame opt; initStyleOption (&opt); style()->drawControl (QStyle::CE_ShapedFrame, &opt, &p, this); } } FeatherNotes-0.8.0/feathernotes/colorLabel.h000066400000000000000000000023711374721712500210400ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016-2020 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef COLORLABEL_H #define COLORLABEL_H #include #include #include namespace FeatherNotes { class ColorLabel : public QLabel { Q_OBJECT public: explicit ColorLabel (QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); ~ColorLabel(); void setColor (const QColor &color); QColor getColor() const; protected: void mousePressEvent (QMouseEvent *event) override; void paintEvent (QPaintEvent *event) override; private: QColor color_; }; } #endif // COLORLABEL_H FeatherNotes-0.8.0/feathernotes/data/000077500000000000000000000000001374721712500175175ustar00rootroot00000000000000FeatherNotes-0.8.0/feathernotes/data/feathernotes.desktop000066400000000000000000000007201374721712500236000ustar00rootroot00000000000000[Desktop Entry] Version=1.0 Name=FeatherNotes Comment=Lightweight notes manager Comment[hu]=Könnyed jegyzetkezelő Comment[cs]=Nenáročný správce poznámek Comment[lt]=Supaprastinta užrašų tvarkytuvė Comment[pl]=Lekki menedżer notatek Comment[ru]=Лёгкий менеджер заметок Exec=feathernotes %f Icon=feathernotes Terminal=false Type=Application MimeType=text/feathernotes-fnx; Categories=Qt;Utility;TextEditor; X-KDE-StartupNotify=false FeatherNotes-0.8.0/feathernotes/data/feathernotes.svg000066400000000000000000000125721374721712500227360ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/feathernotes.xml000066400000000000000000000006361374721712500227350ustar00rootroot00000000000000 FeatherNotes Document FeatherNotes-0.8.0/feathernotes/data/fn.qrc000066400000000000000000000056421374721712500206400ustar00rootroot00000000000000 icons/all.svg icons/application-exit.svg icons/application-menu.svg icons/arrow-down-double.svg icons/case.svg icons/child.svg icons/collapse.svg icons/dialog-cancel.svg icons/dialog-ok.svg icons/document-encrypt.svg icons/document-new.svg icons/document-open.svg icons/document-open-recent.svg icons/document-print.svg icons/document-properties.svg icons/document-save-as.svg icons/document-save.svg icons/edit-clear.svg icons/edit-copy.svg icons/edit-cut.svg icons/edit-delete.svg icons/edit-find-replace.svg icons/edit-find.svg icons/edit-paste.svg icons/edit-redo.svg icons/edit-rename.svg icons/edit-select-all.svg icons/edit-table-cell-merge.svg icons/edit-table-delete-column.svg icons/edit-table-delete-row.svg icons/edit-table-insert-column-left.svg icons/edit-table-insert-column-right.svg icons/edit-table-insert-row-above.svg icons/edit-table-insert-row-below.svg icons/edit-undo.svg icons/expand.svg icons/feathernotes.svg icons/format-fill-color.svg icons/format-justify-center.svg icons/format-justify-fill.svg icons/format-justify-left.svg icons/format-justify-right.svg icons/format-text-bold.svg icons/format-text-color.svg icons/format-text-direction-ltr.svg icons/format-text-direction-rtl.svg icons/format-text-italic.svg icons/format-text-strikethrough.svg icons/format-text-subscript.svg icons/format-text-superscript.svg icons/format-text-underline.svg icons/go-down.svg icons/go-next.svg icons/go-previous.svg icons/go-up.svg icons/help-about.svg icons/help-contents.svg icons/image-x-generic.svg icons/insert-link.svg icons/insert-table.svg icons/link.svg icons/preferences-desktop-font.svg icons/preferences-system.svg icons/tag.svg icons/sibling-above.svg icons/sibling-below.svg icons/user-trash.svg icons/whole.svg icons/zoom-in.svg FeatherNotes-0.8.0/feathernotes/data/icons/000077500000000000000000000000001374721712500206325ustar00rootroot00000000000000FeatherNotes-0.8.0/feathernotes/data/icons/all.svg000066400000000000000000000012731374721712500221260ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/application-exit.svg000066400000000000000000000020311374721712500246210ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/application-menu.svg000066400000000000000000000006051374721712500246210ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/arrow-down-double.svg000066400000000000000000000010751374721712500247250ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/case.svg000066400000000000000000000015731374721712500222740ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/child.svg000066400000000000000000000006101374721712500224330ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/collapse.svg000066400000000000000000000020721374721712500231560ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/dialog-cancel.svg000066400000000000000000000013021374721712500240310ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/dialog-ok.svg000066400000000000000000000006761374721712500232320ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/document-encrypt.svg000066400000000000000000000007211374721712500246530ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/document-new.svg000066400000000000000000000006671374721712500237710ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/document-open-recent.svg000066400000000000000000000015101374721712500254030ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/document-open.svg000066400000000000000000000007471374721712500241400ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/document-print.svg000066400000000000000000000007631374721712500243310ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/document-properties.svg000066400000000000000000000026401374721712500253650ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/document-save-as.svg000066400000000000000000000012741374721712500245320ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/document-save.svg000066400000000000000000000010561374721712500241270ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-clear.svg000066400000000000000000000010351374721712500233630ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-copy.svg000066400000000000000000000006421374721712500232520ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-cut.svg000066400000000000000000000024711374721712500230750ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-delete.svg000066400000000000000000000012241374721712500235370ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-find-replace.svg000066400000000000000000000020471374721712500246320ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-find.svg000066400000000000000000000012421374721712500232150ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-paste.svg000066400000000000000000000007031374721712500234120ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-redo.svg000066400000000000000000000011461374721712500232310ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-rename.svg000066400000000000000000000014711374721712500235500ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-select-all.svg000066400000000000000000000012171374721712500243240ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-table-cell-merge.svg000066400000000000000000000013371374721712500254030ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-table-delete-column.svg000066400000000000000000000007251374721712500261240ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-table-delete-row.svg000066400000000000000000000007271374721712500254400ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-table-insert-column-left.svg000066400000000000000000000007531374721712500271170ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-table-insert-column-right.svg000066400000000000000000000007611374721712500273010ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-table-insert-row-above.svg000066400000000000000000000007651374721712500265760ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-table-insert-row-below.svg000066400000000000000000000007511374721712500266050ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/edit-undo.svg000066400000000000000000000011431374721712500232420ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/expand.svg000066400000000000000000000021301374721712500226260ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/feathernotes.svg000066400000000000000000000033111374721712500240400ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-fill-color.svg000066400000000000000000000020261374721712500247030ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-justify-center.svg000066400000000000000000000007561374721712500256240ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-justify-fill.svg000066400000000000000000000007741374721712500252720ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-justify-left.svg000066400000000000000000000007551374721712500252750ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-justify-right.svg000066400000000000000000000007551374721712500254600ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-text-bold.svg000066400000000000000000000016321374721712500245450ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-text-color.svg000066400000000000000000000011121374721712500247340ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-text-direction-ltr.svg000066400000000000000000000010151374721712500263770ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-text-direction-rtl.svg000066400000000000000000000010151374721712500263770ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-text-italic.svg000066400000000000000000000007141374721712500250720ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-text-strikethrough.svg000066400000000000000000000012141374721712500265230ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-text-subscript.svg000066400000000000000000000016741374721712500256510ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-text-superscript.svg000066400000000000000000000016161374721712500262120ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/format-text-underline.svg000066400000000000000000000010351374721712500256070ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/go-down.svg000066400000000000000000000005641374721712500227320ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/go-next.svg000066400000000000000000000005621374721712500227370ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/go-previous.svg000066400000000000000000000005611374721712500236340ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/go-up.svg000066400000000000000000000005611374721712500224040ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/help-about.svg000066400000000000000000000007471374721712500234230ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/help-contents.svg000066400000000000000000000023331374721712500241370ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/image-x-generic.svg000066400000000000000000000011021374721712500243060ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/insert-link.svg000066400000000000000000000011201374721712500236040ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/insert-table.svg000066400000000000000000000011221374721712500237400ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/link.svg000066400000000000000000000015671374721712500223210ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/preferences-desktop-font.svg000066400000000000000000000006251374721712500262720ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/preferences-system.svg000066400000000000000000000034071374721712500252020ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/sibling-above.svg000066400000000000000000000006241374721712500240760ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/sibling-below.svg000066400000000000000000000006261374721712500241140ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/tag.svg000066400000000000000000000006441374721712500221320ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/user-trash.svg000066400000000000000000000005201374721712500234450ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/whole.svg000066400000000000000000000007371374721712500225000ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/icons/zoom-in.svg000066400000000000000000000006601374721712500227450ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/text-feathernotes-fnx.svg000066400000000000000000000031201374721712500244760ustar00rootroot00000000000000 FeatherNotes-0.8.0/feathernotes/data/translations/000077500000000000000000000000001374721712500222405ustar00rootroot00000000000000FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes.ts000066400000000000000000002071531374721712500253070ustar00rootroot00000000000000 FeatherNotes::AboutDialog License FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes Next (F3) F3 Previous (F4) F4 Search... Search only in names (Ctrl+Shift+F7) Ctrl+Shift+F7 Search only in tags (Shift+F7) Shift+F7 Search in all nodes (F7) F7 Whole Word (F6) Whole Word F6 Match Case (F5) Match Case F5 &File &Edit For&mat &Tree &Options &Search &Help Find: Replace with: To be replaced Replacing text Previous (F9) F9 Next (F8) F8 Replace all (F10) F10 &Save Save Ctrl+S &Open Open a file Ctrl+O &Undo Undo Ctrl+Z &Redo Redo Ctrl+Shift+Z &Find Show/hide searchbar Ctrl+F &Clear All Formats Clear all formats Ctrl+E &Bold Bold Ctrl+B &Italic Italic Ctrl+I &Underline Underline Ctrl+U &Strike Through Strike through Ctrl+T Te&xt Color Text color Alt+Shift+T Back&ground Color Background color Alt+Shift+B Options &New Note Ctrl+Alt+Shift+N Save &As Ctrl+Shift+S &Print Ctrl+P P&rint with Sub-Nodes Set Pass&word &Quit Ctrl+Q &Cut Ctrl+X C&opy Ctrl+C &Paste Ctrl+V &Delete &Select All Ctrl+A E&mbed Image Embed Image Ctrl+Alt+Shift+I E&xpand All Ctrl+Shift+Down Collap&se All Ctrl+Shift+Up &Append Sibling Ctrl+N Append &Child Ctrl+Shift+N &Delete Node Ctrl+D Move &Up Alt+Up Move Do&wn Alt+Down Re&name Node Ctrl+Shift+R Tree Pr&operties Ctrl+Shift+D Document &Font &Wrap Lines Ctrl+W &Auto-Indentation Ctrl+Shift+I &Preferences Ctrl+Shift+P Find and &Replace Ctrl+R Ctrl+H &About Pr&int All Nodes Superscrip&t Superscript Alt+Shift+U Subscri&pt Subscript Alt+Shift+S C&enter Align center Alt+Shift+Down &Right Align right Alt+Shift+Right &Left Align left Alt+Shift+Left &Justify Justify Alt+Shift+Up &Prepend Sibling Ctrl+M Move &Left Alt+Left Move &Right Alt+Right h&2 Header 2 Ctrl+2 h&1 Header 1 Ctrl+1 h&3 Header 3 Ctrl+3 &Node Font Node Font Scale I&mage(s) Paste &HTML Ctrl+Shift+V &Tags Ctrl+Shift+T Insert Lin&k Ctrl+L C&opy Link I&nsert Table Ctrl+Alt+Shift+T Append Row Delete Row Append Column Delete Column Merge Cells Prepend Row Prepend Column Export &HTML Save Ima&ge(s) RTL Ctrl+Alt+Shift+Left LTR Ctrl+Alt+Shift+Right Menu Node &Icon Ctrl+Shift+C Check Spelling F2 Document &Colors Paste Date and Time Node Icon &Raise/Hide <center><b><big>New note?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> Yes No <center><b><big>Save changes?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>The document has been removed.</i></center> Discard changes Cancel Open file... <center><b><big>Cannot be saved!</big></b></center> Close Save As... <center><b><big>Delete this node?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> Tags OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> %1 Matches One Match No Match Replacement No Replacement One Replacement %1 Replacements Insert Link Image path Open image Scaling percentage Open Image... &Raise New Node FeatherNotes documents (*.fnx);;All Files (*) Untitled Select Text Color Select Background Color Deletion Tag(s) for this node Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Select Document Font Select Node Font Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to % Scale Image(s) untitled Error <center><b><big>Image cannot be saved! Retry?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> Save Image As... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Insert Table Rows: Columns: Print Document Export HTML Export: &Current node With all &sub-nodes &All nodes Output file: Select path Question The file already exists. Do you want to replace it? Save HTML As... HTML Files (*.html *.htm) Set Password Type password Retype password <center>Passwords were different. Retry!</center> Enter Password <center>Wrong password. Retry!</center> A lightweight notes manager based on Qt Author About FeatherNotes Translators See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. FeatherNotes::LineEdit Clear text (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences Window Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Remember window &size Start with this size: px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Remember &tree width Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Save &position Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Add to s&ystray The command line option --tray can be used instead of this. Start i&conified to tray Merge the tree view with its surroundings? Transparent t&ree view By default, the active widget style determines the size of toolbar icons. Small toolbar icons Do not show t&oolbar If the menubar is hidden, a menu button appears on the toolbar. Do not show &menubar Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Running &under Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Shifts (X × Y): Text &Wrap lines by default Auto-&indent by default This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Auto-&bracket A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. &Replace some characters while typing Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every minute(s) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Action Shortcut Default Warning: Ambiguous shortcut detected! The typed shortcut was reserved. Application restart is needed for changes to take effect. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help QObject New Node FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_cs.ts000066400000000000000000002134021374721712500257660ustar00rootroot00000000000000 FeatherNotes::AboutDialog License Licence FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes Next (F3) Další (F3) F3 Previous (F4) Předchozí (F4) F4 Search... Hledat… Search only in names (Ctrl+Shift+F7) Hledat pouze v názvech (Ctrl+Shift+F7) Ctrl+Shift+F7 Search only in tags (Shift+F7) Hledat pouze ve štítcích (Shift+F7) Shift+F7 Search in all nodes (F7) Hledat ve všech uzlech (F7) F7 Whole Word (F6) Celé slovo (F6) Whole Word Celé slovo F6 Match Case (F5) Rozlišovat malá/VELKÁ písmena (F5) Match Case Rozlišovat malá/VELKÁ písmena F5 &File &Soubor &Edit &Upravit For&mat For&mát &Tree S&trom &Options M&ožnosti &Search &Hledat &Help &Nápověda Find: Najít: Replace with: Nahradit čím: To be replaced Má být nahrazeno Replacing text Nahrazující text Previous (F9) Předchozí (F9) F9 Next (F8) Další (F8) F8 Replace all (F10) Nahradit vše (F10) F10 &Save &Uložit Save Uložit Ctrl+S &Open &Otevřít Open a file Otevřít soubor Ctrl+O &Undo &Zpět Undo Zpět Ctrl+Z &Redo &Zopakovat Redo Zopakovat Ctrl+Shift+Z &Find &Najít Show/hide searchbar Zobrazit/skrýt lištu hledání Ctrl+F &Clear All Formats &Odebrat veškeré formátování Clear all formats Odebrat veškeré formátování Ctrl+E &Bold &Tučné Bold Tučné Ctrl+B &Italic &Kurzíva Italic Kurzíva Ctrl+I &Underline &Podtržení Underline Podtržení Ctrl+U &Strike Through &Přeškrtnuté Strike through Přeškrtnuté Ctrl+T Te&xt Color Barva te&xtu Text color Barva textu Alt+Shift+T Back&ground Color &Barva pozadí Background color Barva pozadí Alt+Shift+B Options Možnosti &New Note &Nová poznámka Ctrl+Alt+Shift+N Save &As Uložit j&ako Ctrl+Shift+S &Print &Tisk Ctrl+P P&rint with Sub-Nodes &Vytisknout s dílčími uzly Set Pass&word &Nastavit heslo &Quit &Ukončit Ctrl+Q &Cut &Vyjmout Ctrl+X C&opy Zk&opírovat Ctrl+C &Paste &Vložit Ctrl+V &Delete &Smazat &Select All &Vybrat vše Ctrl+A E&mbed Image &Zapouzdřit obrázek Embed Image Zapouzdřit obrázek Ctrl+Alt+Shift+I E&xpand All &Rozbalit vše Ctrl+Shift+Down Collap&se All &Sbalit vše Ctrl+Shift+Up Ctrl+Shift+Šipka nahoru &Append Sibling &Připojit příbuzné Ctrl+N Append &Child &Připojit podřízené Ctrl+Shift+N &Delete Node &Smazat uzel Ctrl+D Move &Up Přesunout nahor&u Alt+Up Alt+Šipka nahoru Move Do&wn &Přesunout dolů Alt+Down Alt+Šipka dolů Re&name Node Přejme&novat uzel Ctrl+Shift+R Tree Pr&operties Vlastn&osti stromu Ctrl+Shift+D Document &Font &Písmo dokumentu &Wrap Lines &Zalomit řádky Ctrl+W &Auto-Indentation &Automatické odsazování Ctrl+Shift+I &Preferences &Předvolby Ctrl+Shift+P Find and &Replace Najít a nah&radit Ctrl+R Ctrl+H &About O &aplikaci Pr&int All Nodes Vyt&isknout všechny uzly Superscrip&t &Horní index Superscript Horní index Alt+Shift+U Subscri&pt &Horní index Subscript Dolní index Alt+Shift+S C&enter Vystř&edit Align center Zarovnat na střed Alt+Shift+Down Alt+Shift+Šipka dolů &Right Vp&ravo Align right Zarovnat vpravo Alt+Shift+Right Alt+Shift+Šipka doprava &Left V&levo Align left Zarovnat doleva Alt+Shift+Left Alt+Shift+Šipka doleva &Justify &Vyrovnat Justify Vyrovnat Alt+Shift+Up Alt+Shift+Šipka nahoru &Prepend Sibling &Předřadit příbuzné Ctrl+M Move &Left Přesunout do&leva Alt+Left Alt+Šipka doleva Move &Right Přesunout dop&rava Alt+Right Alt+Šipka doprava h&2 n&2 Header 2 Nadpis 2 Ctrl+2 h&1 n&1 Header 1 Nadpis 1 Ctrl+1 h&3 n&3 Header 3 Nadpis 3 Ctrl+3 &Node Font &Písmo uzlu Node Font Písmo uzlu Scale I&mage(s) Změn&it měřítko obrázků Paste &HTML Vložit &HTML Ctrl+Shift+V &Tags Š&títky Ctrl+Shift+T Insert Lin&k Vložit od&kaz Ctrl+L C&opy Link Zk&opírovat odkaz I&nsert Table &Vložit tabulku Ctrl+Alt+Shift+T Append Row Přidat řádek za Delete Row Smazat řádek Append Column Přidat sloupec za Delete Column Smazat sloupec Merge Cells Sloučit buňky Prepend Row Vložit řádek před Prepend Column Vložit sloupec před Export &HTML Exportovat &HTML Save Ima&ge(s) &Uložit obrázky RTL Zprava doleva Ctrl+Alt+Shift+Left Ctrl+Alt+Shift+Šipka doprava LTR Zleva doprava Ctrl+Alt+Shift+Right Ctrl+Alt+Shift+Šipka doprava Menu Nabídka Node &Icon &Ikona uzlu Ctrl+Shift+C Check Spelling F2 Document &Colors Paste Date and Time Node Icon Ikona uzlu &Raise/Hide &Vyzdvihnout/skrýt <center><b><big>New note?</big></b></center> <center><b><big>Nová poznámka?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>Opravdu chcete tento dokument opustit</i></center> <center><i>a vytvořit nový prázdný?</i></center> Yes Ano No Ne <center><b><big>Save changes?</big></b></center> <center><b><big>Uložit změny?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>Dokument byl změněn.</i></center> <center><i>The document has been removed.</i></center> <center><i>Dokument byl odebrán.</i></center> Discard changes Zahodit změny Cancel Zrušit Open file... Otevřít soubor… <center><b><big>Cannot be saved!</big></b></center> <center><b><big>Není možné uložit!</big></b></center> Close Zavřít Save As... Uložit jako… <center><b><big>Delete this node?</big></b></center> <center><b><big>Smazat tento uzel?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>Varování!</i></b></center> <center>Tuto akci nelze vzít zpět.</center> Tags Štítky OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Hlavní uzly:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Všechny uzly:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>Poznámka:</b> <i>%1</i><br><b>Hlavní uzly:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Všechny uzly:</b> <i>%3</i> %1 Matches %1shod One Match Jedna shoda No Match Žádná shoda Replacement Nahrazení No Replacement Žádné nahrazení One Replacement Jedno nahrazení %1 Replacements %1 nahrazení Insert Link Vložit odkaz Image path Umístění obrázku Open image Otevřít obrázek Scaling percentage Procento měřítka Open Image... Otevřít obrázek… &Raise &Vyzdvihnout New Node Nový uzel FeatherNotes documents (*.fnx);;All Files (*) Dokumenty FeatherNotes (*.fnx);;Všechny soubory (*) Untitled Bez názvu Select Text Color Vybrat barvu textu Select Background Color Vybrat barvu pozadí Deletion Smazání Tag(s) for this node Štítky pro tento uzel Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Soubory s obrázky (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;Všechny soubory (*) Select Document Font Vybrat písmo pro dokument Select Node Font Vybrat písmo uzlu Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to Změnit měřítko na % Scale Image(s) Změnit měřítko obrázků untitled bez názvu Error Chyba <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>Obrázek se nepodařilo uložit! Zkusit znovu?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>Nejspíš jste nezvolili správnou příponu</center> <center>nebo nemáte oprávnění zapisovat do daného umístění.</center><p></p> Save Image As... Uložit obrázek jako… Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Soubory s obrázky (*.png *.jpg *.jpeg *.bmp);;Všechny soubory (*) Insert Table Vložit tabulku Rows: Řádky: Columns: Sloupce: Print Document Vytisknout dokument Export HTML Exportovat HTML Export: Exportovat: &Current node &Stávající uzel With all &sub-nodes &Se všemi dílčími uzly &All nodes &Všechny uzly Output file: Výstupní soubor: Select path Vyberte umístění Question The file already exists. Do you want to replace it? Save HTML As... Uložit HTML jako… HTML Files (*.html *.htm) HTML soubory (*.html *.htm) Set Password Nastavit heslo Type password Zadejte heslo Retype password Zopakujte zadání hesla <center>Passwords were different. Retry!</center> <center>Zadání hesla se neshodují. Zkuste to znovu!</center> Enter Password Zadejte heslo <center>Wrong password. Retry!</center> <center>Nesprávné heslo. Zkuste to znovu!</center> A lightweight notes manager Nenáročný správce poznámek based on Qt založeno na Qt Author Autor About FeatherNotes O aplikaci FeatherNotes Translators Překladatelé See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. alias FeatherNotes::LineEdit Clear text (Ctrl+K) Text bez formátování (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences Předvolby Window Okno Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Po zavření tohoto dialogu a také při ukončení aplikace uloží velikost okna. Pro nastavení pevné velikosti zrušte zaškrnutí! Remember window &size Zapamatovat si veliko&st okna Start with this size: Začít s touto velikostí: px obr. bodů Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Po zavření tohoto dialogu a také při ukončení aplikace uloží šířku stromu. Pro výchozí poměr šířky 170/530 zrušte zaškrtnutí. Remember &tree width Zapamatovat si šířku s&tromu Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Při zavření tohoto dialogu a také při ukončení aplikace uloží pozici. (Toto nemusí správně fungovat pod desktopovými prostředími, založenými na knihovnách GTK+ jako je Unity a Cinnamon.) Save &position Uložit &pozici Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Rozhoduje zda má být použita ikona v oznamovací oblasti systémového panelu. Pokud je zaškrtnuto, tlačítko zavřít na titulní liště okna ho namísto ukončení aplikace zminimalizuje do právě do oznamovací oblasti.. Aby se změna projevila, je třeba FeatherNotes zavřít a spustit znovu. Add to s&ystray Přidat do oznamovací oblasti s&ystém. panelu The command line option --tray can be used instead of this. Namísto tohoto je možné použít volbu příkazového řádku --tray Start i&conified to tray Spouštět zminimalizované do oznamovací oblasti Merge the tree view with its surroundings? Sloučit stromový pohled s jeho okolím? Transparent t&ree view Průhledný st&romový pohled By default, the active widget style determines the size of toolbar icons. Ve výchozím stavu je velikost ikon na liště nástrojů určována právě používaným stylem widgetů. Small toolbar icons Malé ikony na liště nástrojů Do not show t&oolbar Nezobrazovat lištu nástr&ojů If the menubar is hidden, a menu button appears on the toolbar. Pokud je lišta nástrojů skryta, na liště nástrojů se objeví tlačítko nabídky. Do not show &menubar Nezobrazovat lištu &nabídky Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Toto zaškrtněte pod Enlightenment (nebo, nejspíš jiným desktop. prostředím), aby ikona v oznamovací oblasti byla snáze použitelná! Running &under Enlightenment? Provoz&ujete v Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Některá desktopová prostředí (jako např. Enlightenment) nehlásí správnou pozici okna. Pokud je tomu tak, je možné se pokusit to napravit zde. Pokud je panel dole nebo nahoře, měla by být nastavena souřadnice Y. Pokud vlevo nebo vpravo, pak souřadnice X. Po zvolení posunu souřadnice, umístěte okno do správné pozice, FeatherNotes ukončete a spusťte znovu! Shifts (X × Y): Posuny (X × Y): Text &Wrap lines by default &Zalamovat řádky už ve výchozím stavu Auto-&indent by default Automaticky odsazovat už ve výchozím stavu This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Toto zahrnuje kulaté, složené a hranaté závorky a také uvozovky. Aby se změna projevila, je třeba FeatherNotes ukončit a spustit znovu. Auto-&bracket Automatické uzavírání závorek A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. Za správných podmínek, jsou tři tečky jsou nahrazeny výpustkou, dva spojovníky pomlčkou, atd – zatímco uživatel píše. &Replace some characters while typing Nah&razovat některé znaky v průběhu psaní Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every &Automaticky uložit každých minute(s) minut Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Zkratky Action Akce Shortcut Zkratka Default Výchozí Warning: Ambiguous shortcut detected! Varování: zjištěna opakující se zkratka! The typed shortcut was reserved. Zadaná klávesová zkratka je vyhrazena pro něco jiného. Application restart is needed for changes to take effect. Aby se změny projevily, je třeba aplikaci restartovat. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Nahradit čím: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help Nápověda QObject New Node Nový uzel FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_cy.ts000066400000000000000000001746731374721712500260140ustar00rootroot00000000000000 FeatherNotes::AboutDialog License FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes Next (F3) F3 Previous (F4) F4 Search... Search only in names (Ctrl+Shift+F7) Ctrl+Shift+F7 Search only in tags (Shift+F7) Shift+F7 Search in all nodes (F7) F7 Whole Word (F6) Whole Word F6 Match Case (F5) Match Case F5 &File &Edit For&mat &Tree &Options &Search &Help Find: Replace with: To be replaced Replacing text Previous (F9) F9 Next (F8) F8 Replace all (F10) F10 &Save Save Ctrl+S &Open Open a file Ctrl+O &Undo Undo Ctrl+Z &Redo Redo Ctrl+Shift+Z &Find Show/hide searchbar Ctrl+F &Clear All Formats Clear all formats Ctrl+E &Bold Bold Ctrl+B &Italic Italic Ctrl+I &Underline Underline Ctrl+U &Strike Through Strike through Ctrl+T Te&xt Color Text color Alt+Shift+T Back&ground Color Background color Alt+Shift+B Options &New Note Ctrl+Alt+Shift+N Save &As Ctrl+Shift+S &Print Ctrl+P P&rint with Sub-Nodes Set Pass&word &Quit Ctrl+Q &Cut Ctrl+X C&opy Ctrl+C &Paste Ctrl+V &Delete &Select All Ctrl+A E&mbed Image Embed Image Ctrl+Alt+Shift+I E&xpand All Ctrl+Shift+Down Collap&se All Ctrl+Shift+Up &Append Sibling Ctrl+N Append &Child Ctrl+Shift+N &Delete Node Ctrl+D Move &Up Alt+Up Move Do&wn Alt+Down Re&name Node Ctrl+Shift+R Tree Pr&operties Ctrl+Shift+D Document &Font &Wrap Lines Ctrl+W &Auto-Indentation Ctrl+Shift+I &Preferences Ctrl+Shift+P Find and &Replace Ctrl+R Ctrl+H &About Pr&int All Nodes Superscrip&t Superscript Alt+Shift+U Subscri&pt Subscript Alt+Shift+S C&enter Align center Alt+Shift+Down &Right Align right Alt+Shift+Right &Left Align left Alt+Shift+Left &Justify Justify Alt+Shift+Up &Prepend Sibling Ctrl+M Move &Left Alt+Left Move &Right Alt+Right h&2 Header 2 Ctrl+2 h&1 Header 1 Ctrl+1 h&3 Header 3 Ctrl+3 &Node Font Node Font Scale I&mage(s) Paste &HTML Ctrl+Shift+V &Tags Ctrl+Shift+T Insert Lin&k Ctrl+L C&opy Link I&nsert Table Ctrl+Alt+Shift+T Append Row Delete Row Append Column Delete Column Merge Cells Prepend Row Prepend Column Export &HTML Save Ima&ge(s) RTL Ctrl+Alt+Shift+Left LTR Ctrl+Alt+Shift+Right Menu Node &Icon Ctrl+Shift+C Check Spelling F2 Document &Colors Paste Date and Time Node Icon &Raise/Hide <center><b><big>New note?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> Yes No <center><b><big>Save changes?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>The document has been removed.</i></center> Discard changes Cancel Open file... <center><b><big>Cannot be saved!</big></b></center> Close Save As... <center><b><big>Delete this node?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> Tags OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> %1 Matches One Match No Match Replacement No Replacement One Replacement %1 Replacements Insert Link Image path Open image Scaling percentage Open Image... &Raise New Node FeatherNotes documents (*.fnx);;All Files (*) Untitled Select Text Color Select Background Color Deletion Tag(s) for this node Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Select Document Font Select Node Font Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to % Scale Image(s) untitled Error <center><b><big>Image cannot be saved! Retry?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> Save Image As... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Insert Table Rows: Columns: Print Document Export HTML Export: &Current node With all &sub-nodes &All nodes Output file: Select path Question The file already exists. Do you want to replace it? Save HTML As... HTML Files (*.html *.htm) Set Password Type password Retype password <center>Passwords were different. Retry!</center> Enter Password <center>Wrong password. Retry!</center> A lightweight notes manager based on Qt Author About FeatherNotes Translators See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. FeatherNotes::LineEdit Clear text (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences Window Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Remember window &size Start with this size: px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Remember &tree width Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Save &position Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Add to s&ystray The command line option --tray can be used instead of this. Start i&conified to tray Merge the tree view with its surroundings? Transparent t&ree view By default, the active widget style determines the size of toolbar icons. Small toolbar icons Do not show t&oolbar If the menubar is hidden, a menu button appears on the toolbar. Do not show &menubar Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Running &under Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Shifts (X × Y): Text &Wrap lines by default Auto-&indent by default This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Auto-&bracket A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. &Replace some characters while typing Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every minute(s) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Action Shortcut Default Warning: Ambiguous shortcut detected! The typed shortcut was reserved. Application restart is needed for changes to take effect. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help QObject New Node FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_de.ts000066400000000000000000002137171374721712500257620ustar00rootroot00000000000000 FeatherNotes::AboutDialog License Lizenz FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes Next (F3) Vor (F3) F3 Previous (F4) Zurück (F4) F4 Search... Suchen… Search only in names (Ctrl+Shift+F7) Suche nur in Namen (Strg+Umschalt+F7) Ctrl+Shift+F7 Strg+Umschalt+F7 Search only in tags (Shift+F7) Suche nur in Tags (Umschalt+F7) Shift+F7 Umschalt+F7 Search in all nodes (F7) In allen Knoten suchen (F7) F7 Whole Word (F6) Ganzes Worte (F6) Whole Word Ganzes Worte F6 Match Case (F5) Groß-/Kleinschreibung beachten (F5) Match Case Groß-/Kleinschreibung beachten F5 &File &Datei &Edit &Bearbeiten For&mat &Tree &Baumansicht &Options &Optionen &Search &Suchen &Help &Hilfe Find: Suchen: Replace with: Ersetzen mit: To be replaced Zu ersetzen Replacing text Ersetze Text Previous (F9) Vorheriger (F9) F9 Next (F8) Nächster (F8) F8 Replace all (F10) Ersetze alles (F10) F10 &Save &Speichern Save Speichern Ctrl+S Strg+S &Open &Öffnen Open a file Datei öffnen Ctrl+O Strg+O &Undo &Rückgängig Undo Rückgängig Ctrl+Z Strg+Z &Redo &Wiederholen Redo Wiederholen Ctrl+Shift+Z Strg+Umschalt+Z &Find &Suchen Show/hide searchbar Suchleiste zeigen/verbergen Ctrl+F Strg+F &Clear All Formats &Entferne alle Formatierungen Clear all formats Entferne alle Formatierungen Ctrl+E Strg+E &Bold &Fett Bold Fett Ctrl+B Strg+B &Italic &Kursiv Italic Kursiv Ctrl+I Strg+I &Underline &Unterstreichen Underline Unterstreichen Ctrl+U Strg+U &Strike Through &Durchstreichen Strike through Durchstreichen Ctrl+T Strg+T Te&xt Color Te&xtfarbe Text color Textfarbe Alt+Shift+T Alt+Umschalt+T Back&ground Color Hinter&grundfarbe Background color Hintergrundfarbe Alt+Shift+B Alt+Umschalt+B Options Optionen &New Note &Neue Notiz Ctrl+Alt+Shift+N Strg+Alt+Umschalt+N Save &As Speichern &unter Ctrl+Shift+S Strg+Umschalt+S &Print &Drucken Ctrl+P Strg+P P&rint with Sub-Nodes Mit Unterknoten d&rucken Set Pass&word Pass&wort setzen &Quit &Beenden Ctrl+Q Strg+Q &Cut &Auschneiden Ctrl+X Strg+X C&opy &Kopieren Ctrl+C Strg+C &Paste &Einfügen Ctrl+V Strg+V &Delete &Löschen &Select All Alles a&uswählen Ctrl+A Strg+A E&mbed Image Bild ein&betten Embed Image Bild einbetten Ctrl+Alt+Shift+I Strg+Alt+Umschalt+I E&xpand All Alles a&ufklappen Ctrl+Shift+Down Strg+Umschalt+Runter Collap&se All Alles zu&klappen Ctrl+Shift+Up Strg+Umschalt+Hoch &Append Sibling Ctrl+N Strg+N Append &Child &Kind anhängen Ctrl+Shift+N Strg+Umschalt+N &Delete Node Ctrl+D Strg+D Move &Up Nach &oben Alt+Up Alt+Hoch Move Do&wn Nach &unten Alt+Down Alt+Runter Re&name Node Ctrl+Shift+R Strg+Umschalt+R Tree Pr&operties Baumei&genschaften Ctrl+Shift+D Strg+Umschalt+D Document &Font Dokumentenschri&ftart &Wrap Lines &Zeilenumbruch Ctrl+W Strg+W &Auto-Indentation &Auto-Einrückung Ctrl+Shift+I Strg+Umschalt+I &Preferences &Einstellungen Ctrl+Shift+P Strg+Umschalt+P Find and &Replace Suchen und E&setzen Ctrl+R Strg+R Ctrl+H Strg+H &About &Über Pr&int All Nodes Alle Knoten &drucken Superscrip&t Hochgestell&t Superscript Hochgestellt Alt+Shift+U Alt+Umschalt+U Subscri&pt Tief&gestellt Subscript Tiefgestellt Alt+Shift+S Alt+Umschalt+S C&enter &Zentrieren Align center Mittig ausrichten Alt+Shift+Down Alt+Umschalt+Runter &Right &Rechts Align right Rechtsbündig ausrichten Alt+Shift+Right Alt+Umschalt+Rechts &Left &Links Align left Linksbündig ausrichten Alt+Shift+Left Alt+Umschalt+Links &Justify &Justieren Justify Justieren Alt+Shift+Up Alt+Umschalt+Hoch &Prepend Sibling Ctrl+M Strg+M Move &Left Nach links verschieben Alt+Left Alt+Links Move &Right Nach rechts verschieben Alt+Right Alt+Rechts h&2 Header 2 Überschrift 2 Ctrl+2 Strg+2 h&1 Header 1 Überschrift 1 Ctrl+1 Strg+1 h&3 Header 3 Überschrift 3 Ctrl+3 Strg+3 &Node Font Node Font Scale I&mage(s) Bild(er) s&kalieren Paste &HTML &HTML einfügen Ctrl+Shift+V Strg+Umschalt+V &Tags Ctrl+Shift+T Strg+Umschalt+T Insert Lin&k Lin&k einfügen Ctrl+L Strg+L C&opy Link Link &kopieren I&nsert Table Tabelle e&infügen Ctrl+Alt+Shift+T Strg+Alt+Umschalt+T Append Row Zeile anhängen Delete Row Zeile löschen Append Column Spalte anfügen Delete Column Spalte löschen Merge Cells Zellen vereinen Prepend Row Zeile voranstellen Prepend Column Spalte voranstellen Export &HTML &HTML exportieren Save Ima&ge(s) Bild(er) speichern RTL Ctrl+Alt+Shift+Left Strg+Alt+Umschlt+Links LTR Ctrl+Alt+Shift+Right Strg+Alt+Umschalt+Rechts Menu Menü Node &Icon Ctrl+Shift+C Strg+Umschalt+C Check Spelling F2 Document &Colors Paste Date and Time Node Icon &Raise/Hide E&rhöhen/Ausblenden <center><b><big>New note?</big></b></center> <center><b><big>Neue Notiz?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>Wollen Sie wirklich dieses Dokument verlassen</i></center> <center><i>und ein leeres erstellen?</i></center> Yes Ja No Nein <center><b><big>Save changes?</big></b></center> <center><b><big>Änderungen speichern?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>Das Dokument wurde verändert.</i></center> <center><i>The document has been removed.</i></center> <center><i>Das Dokument wurde entfernt.</i></center> Discard changes Änderungen verwerfen Cancel Abbrechen Open file... Öffne Datei… <center><b><big>Cannot be saved!</big></b></center> <center><b><big>Kann nicht gesichert werden!</big></b></center> Close Schließen Save As... Speichern als… <center><b><big>Delete this node?</big></b></center> <center><b><big>Diesen Knotenpunkt entfernen?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>Warnung!</i></b></center> <center>Diese Aktionn kann nicht rückgängig gemacht werden.</center> Tags OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Hauptknotenpunke:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Gesamtknotenpunkte:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>Hinweis:</b> <i>%1</i><br><b>Hauptknoten:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Alle Knoten:</b> <i>%3</i> %1 Matches %1 Übereinstimmungen One Match Eine Übereinstimmung No Match Keine Übereinstimmung Replacement Ersetzung No Replacement Keine Ersetzung One Replacement Eine Ersetzung %1 Replacements %1 Ersetzungen Insert Link Link einfügen Image path Bildpfad Open image Bild öffnen Scaling percentage Skalierungsprozentsatz Open Image... Bild öffnen… &Raise &Hervorheben New Node Neuer Knotenpunkt FeatherNotes documents (*.fnx);;All Files (*) FeatherNotes Dokumente (*.fnx);;All Dateien (*) Untitled Unbenannt Select Text Color Wählen Sie Textfarbe aus Select Background Color Wählen Sie die Hintergrundfarbe aus Deletion Löschung Tag(s) for this node Schlagwort(e) für diesen Knotenpunkt Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Bilddateien (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Dateien (*) Select Document Font Wählen Sie Dokumentschriftart Select Node Font Wählen Sie Knotenschriftart Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to Skaliere zu % Scale Image(s) Skaliere Bild(er) untitled Unbenannt Error <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>Das Bild kann nicht gespeichert werden! Wiederholen?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>Auswahl einer womöglich nicht geeigneten Dateiendung</center> <center>oder keine Schreibberechtigung.</center><p></p> Save Image As... Bild speichern als… Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Bilddateien (*.png *.jpg *.jpeg *.bmp);;All Dateien (*) Insert Table Tabelle einfügen Rows: Zeilen: Columns: Spalten: Print Document Dokument drucken Export HTML HTML exportieren Export: Exportieren: &Current node &Aktueller Knotenpunkt With all &sub-nodes Mit allen &Unterknotenpunkten &All nodes &Alle Knotenpunkte Output file: Ausgabedatei: Select path Pfad wählen Question The file already exists. Do you want to replace it? Save HTML As... Speichere HTML als… HTML Files (*.html *.htm) HTML-Dateien (*.html *.htm) Set Password Kennwort setzen Type password Kennwort eingeben Retype password Kennwort wiederholen <center>Passwords were different. Retry!</center> <center>Die Passwörter unterscheiden sich. Noch einmal versuchen!</center> Enter Password Kennwort eingeben <center>Wrong password. Retry!</center> <center>Falsches Kennwort. Noch einmal versuchen!</center> A lightweight notes manager Eine leichtgewichtige Notiz-Verwaltung based on Qt basierend auf Qt Author Autor About FeatherNotes Über FeatherNotes Translators Übersetzer See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. FeatherNotes::LineEdit Clear text (Ctrl+K) Text zurücksetzen (Strg+K) Ctrl+K Clear text Strg+K FeatherNotes::PrefDialog Preferences Einstellungen Window Fenster Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Speichert Fenstergröße nach Schließen dieses Dialoges und Beenden des Programms. Auswahl aufheben für vorgegebene Fenstergröße! Remember window &size &Fenstergröße speichern Start with this size: Starte mit dieser Größe: px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Speichert Breite des Baumverzeichnisses nach Schließen dieses Dialoges und Beenden des Programms. Auswahl aufheben für ein Breitenverhältnis von 170/530. Remember &tree width Baumbrei&te beibehalten Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Speichert Fensterposition nach Schließen dieses Dialoges und Beendung des Programms. (Die einwandfreie Funktionsfähigkeit unter GTK+ Desktopumgebungen wie Unity und Cinnamon ist nicht gewährleistet.) Save &position &Position speichern Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Entscheidet darüber, ob ein Systemleistensymbol verwendet werden soll. Wenn ausgewählt, wird das offene Fenster geschlossen und in der Systemleiste angezeigt ohne die Anwendung selbst zu schließen. Dies benötigt den Neustart von FeatherNotes, um wirksam zu werden. Add to s&ystray Zur S&ystemleiste hinzufügen The command line option --tray can be used instead of this. Die Option der Kommandozeile --Die Systemleiste kann stattdessen verwendet werden. Start i&conified to tray Starte minimiert in der S&ystemleiste Merge the tree view with its surroundings? Die Ansicht des Verzeichnisbaums an seine Umgebung anpassen? Transparent t&ree view Transpa&rente Baumansicht By default, the active widget style determines the size of toolbar icons. Standardmäßig bestimmt der aktive Bedienelementestil die Größe der Werkzeugleistensymbole. Small toolbar icons Kleine Werkzeugleistensymbole Do not show t&oolbar Werkzeu&gleiste verbergen If the menubar is hidden, a menu button appears on the toolbar. Wenn die Menüleiste verborgen ist, dann erscheint ein Knopf in der Werkzeugleiste. Do not show &menubar &Menüleiste verbergen Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Treffe diese Auswahl unter Benutzung von Enlightenment (oder ähnlichen Desktopumgebungen), um das Symbol von FeatherNotes in der Systemleiste einfacher verwenden zu können! Running &under Enlightenment? Läuft dieses System unter Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Einige Desktopumgebungen (wie Enlightenment) könnten die Fensterposition nicht korrekt darstellen. Sollte dies der Fall sein, so kann an dieser Stelle versucht werden, dieses Problem zu beheben. Befindet sich die Leiste unten oder oben, so müssen die Y-Koordinaten eingestellt werden; befindet sie sich links oder rechts, so müssen die X-Koordinaten eingestellt werden. Nach Einstellung des Versatzes, das Fenster geeignet platzieren und FeatherNotes neustarten! Shifts (X × Y): Tausche (X × Y): Text &Wrap lines by default Automatischer &Zeilenumbruch Auto-&indent by default Automatische &Einrückung This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Dies beinhaltet runde- , geschweifte-, eckige Klammern und Anführungszeichen. Dies benötigt den Neustart von FeatherNotes, um wirksam zu werden. Auto-&bracket Automatische Klammern A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. &Replace some characters while typing Manche Zeichen während der Eingabe e&rsetzen Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every &Automatisch Speichern alle minute(s) Minute(n) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Tastenkombinationen Action Aktion Shortcut Default Standard Warning: Ambiguous shortcut detected! Warnung: Mehrdeutiger Tastatur-Kurzbefehl erkannt! The typed shortcut was reserved. Die eingegebene Verknüpfung wurde reserviert. Application restart is needed for changes to take effect. Damit die Änderungen wirksam werden, ist ein Neustart der Anwendung erforderlich. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Ersetzen mit: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help Hilfe QObject New Node Neuer Knotenpunkt FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_eo.ts000066400000000000000000002122511374721712500257650ustar00rootroot00000000000000 FeatherNotes::AboutDialog License Licenco FeatherNotes::ColorLabel Click to change color. Alklaku por ŝanĝi la koloron. Select Color Elekti Koloron FeatherNotes::FN FeatherNotes Next (F3) Sekva (F3) F3 Previous (F4) Antaŭa (F4) F4 Search... Serĉi... Search only in names (Ctrl+Shift+F7) Serĉi nur la nomojn (Ctrl+Shift+F7) Ctrl+Shift+F7 Search only in tags (Shift+F7) Serĉi nur la etikedojn (Shift+F7) Shift+F7 Search in all nodes (F7) Serĉi ĉiujn nodojn (F7) F7 Whole Word (F6) Tuta Vorto (F6) Whole Word Tuta Vorto F6 Match Case (F5) Uskleciva (F5) Match Case Uskleciva F5 &File &Dosiero &Edit R&edakti For&mat For&mato &Tree &Arbo &Options A&gordoj &Search &Serĉi &Help &Helpo Find: Trovu: Replace with: Anstataŭigu per: To be replaced Anstataŭigota teksto Replacing text Anstataŭiganta teksto Previous (F9) Antaŭa (F9) F9 Next (F8) Sekva (F8) F8 Replace all (F10) Anstataŭigu ĉion (F10) F10 &Save Kon&servi Save Konservi Ctrl+S &Open &Malfermi Open a file Malfermi dosieron Ctrl+O &Undo Malfar&u Undo Malfaru Ctrl+Z &Redo Refa&ru Redo Refaru Ctrl+Shift+Z &Find &Trovi Show/hide searchbar Enfokusigi/malkaŝi la serĉ-breton Ctrl+F &Clear All Formats &Viŝi ĉiujn formatojn Clear all formats Viŝi ĉiujn formatojn Ctrl+E &Bold &Diklitera Bold Diklitera Ctrl+B &Italic Kurs&iva Italic Kursiva Ctrl+I &Underline S&ubstreki Underline Substreki Ctrl+U &Strike Through Tra&streki Strike through Trastreki Ctrl+T Te&xt Color Te&kst-koloro Text color Tekst-koloro Alt+Shift+T Back&ground Color Fo&n-koloro Background color Fon-koloro Alt+Shift+B Options Agordoj &New Note &Nova Noto Ctrl+Alt+Shift+N Save &As Konser&vi Kiel Ctrl+Shift+S &Print &Presi Ctrl+P P&rint with Sub-Nodes P&resi kub Sub-Nodoj Set Pass&word Aldoni Pas&vorton &Quit Forl&asi Ctrl+Q &Cut &Tranĉu Ctrl+X C&opy &Kopiu Ctrl+C &Paste Algl&uu Ctrl+V &Delete &Forviŝu &Select All Elektu &Ĉion Ctrl+A E&mbed Image En&meti Bildon Embed Image Enmeti Bildon Ctrl+Alt+Shift+I E&xpand All E&kspansii Ĉion Ctrl+Shift+Down Collap&se All Kolap&si Ĉion Ctrl+Shift+Up &Append Sibling &Aldoni Gefraton Suben Ctrl+N Append &Child Aldoni Id&on Ctrl+Shift+N &Delete Node &Forviŝi la Nodon Ctrl+D Move &Up Movi S&upren Alt+Up Move Do&wn Movi Malsu&pren Alt+Down Re&name Node Re&nomi la Nodon Ctrl+Shift+R Tree Pr&operties Eco&j Ctrl+Shift+D Document &Font Dokumenta &Tiparo &Wrap Lines Ĉirkaŭ&fermi Liniojn Ctrl+W &Auto-Indentation &Mem-Alinei Ctrl+Shift+I &Preferences A&gordoj Ctrl+Shift+P Find and &Replace T&rovi kaj Anstataŭigi Ctrl+R Ctrl+H &About &Pri Pr&int All Nodes Pres&i Ĉiujn Nodojn Superscrip&t Suprindi&co Superscript Suprindico Alt+Shift+U Subscri&pt Subindic&o Subscript Subindico Alt+Shift+S C&enter C&entrigi Align center Centra vicigo Alt+Shift+Down &Right Dekst&ren Align right Dekstra vicigo Alt+Shift+Right &Left Ma&ldekstren Align left Maldekstra vicigo Alt+Shift+Left &Justify Alka&drigi Justify Alkadrigi Alt+Shift+Up &Prepend Sibling Aldoni &Gefraton Supren Ctrl+M Move &Left Movi Ma&ldekstren Alt+Left Move &Right Movi Deskt&ren Alt+Right h&2 Header 2 Kaplinio 2 Ctrl+2 h&1 Header 1 Kaplinio 1 Ctrl+1 h&3 Header 3 Kaplinio 3 Ctrl+3 &Node Font &Noda Tiparo Node Font Noda Tiparo Scale I&mage(s) Regrandigi Bildo(&j)n Paste &HTML Algluu &HTML Ctrl+Shift+V &Tags E&tikedoj Ctrl+Shift+T Insert Lin&k Enmeti Li&gilon Ctrl+L C&opy Link K&opii Ligilon I&nsert Table E&nmenti Tabelon Ctrl+Alt+Shift+T Append Row Aldoni Vicon Delete Row Forviŝi Vicon Append Column Aldoni Kolumnon Delete Column Forviŝi Kolumnon Merge Cells Kunigi Ĉelojn Prepend Row Aldoni Vicon Antaŭen Prepend Column Aldoni Kolumnon Antaŭen Export &HTML Eksporti &HTML Save Ima&ge(s) Konservi Bildo(&j)n RTL Desktra alliniigo Ctrl+Alt+Shift+Left LTR Maldesktra alliniigo Ctrl+Alt+Shift+Right Menu Menuo Node &Icon &Ikono por Nodo Ctrl+Shift+C Check Spelling Kontroli Literumadon F2 Document &Colors &Koloroj de Dokumento Paste Date and Time Algluu la Daton kaj Tempon Node Icon Ikono por Nodo &Raise/Hide Le&vi/Kaŝi <center><b><big>New note?</big></b></center> <center><b><big>Novan noton?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>Ĉu vi vere volas forlasi ĉi tiun dokumenton</i></center> <center><i>kaj estigi alian malplenan?</i></center> Yes Jes No Ne <center><b><big>Save changes?</big></b></center> <center><b><big>Konservi la ŝanĝojn?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>La dokumento estas modifita.</i></center> <center><i>The document has been removed.</i></center> <center><i>La dokumento forestas.</i></center> Discard changes Preterlasi ŝanĝojn Cancel Rezigni Open file... Malfermi dosieron... <center><b><big>Cannot be saved!</big></b></center> <center><b><big>Ne eblas konservi!</big></b></center> Close Fermi Save As... Konservi Kiel... <center><b><big>Delete this node?</big></b></center> <center><b><big>Forviŝi la nodon?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>Averto!</i></b></center> <center>Ĉi tiu ago ne malfareblas.</center> Tags Etikedoj OK Bone <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Ĉefaj nodoj:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Ĉiuj nodoj:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>Noto:</b> <i>%1</i><br><b>Ĉefaj nodoj:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Ĉiuj nodoj:</b> <i>%3</i> %1 Matches %1 Trovitaj One Match Unu Trovita No Match Nenio Trovita Replacement Anstataŭigo No Replacement Neniu Anstataŭigo One Replacement Unu Anstataŭigo %1 Replacements %1 Anstataŭigoj Insert Link Enmeti Ligilon Image path Bildpado Open image Malfermi bildon Scaling percentage Regrandiga procento Open Image... Malfermi Bildon... &Raise &Levi New Node Nova Nodo FeatherNotes documents (*.fnx);;All Files (*) Dokumentoj de FeatherNotes (*.fnx);;Ĉiuj Dosieroj (*) Untitled Sentitola Select Text Color Elekti Tekstan Koloron Select Background Color Elekti Fonan Koloron Deletion Forviŝado Tag(s) for this node Etikedo(j) por ĉi tiu nodo Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Bild-Dosieroj (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;Ĉiuj Dosieroj (*) Select Document Font Elekti Dokumentan Tiparon Select Node Font Elekti Nodan Tiparon Set Document Colors Agordi Kolorojn de Dokumento These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Ĉi tiuj koloroj aperos en la estontaj nodoj.<br>Ili eblas efiki aŭ ne efiki al la estantaj nodoj<br>sed estas bone remalfermi la dokumenton. Background color: Fona Koloro: Text color: Tekst-Koloro: The first 1000 replacements are highlighted. La unuaj 1000 anstataŭigoj estas markitaj. Scale to Regrandigu al % Scale Image(s) Regrandigi Bildo(j)n untitled sentitola Error Eraro <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>La bildo ne povas esto konservita! Reprovi?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>Eble vi ne elektis ĝustan dosiertipon</center> <center>aŭ vi ne havas permeson por skribi.</center><p></p> Save Image As... Konservi Bildon Kiel... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Bild-Dosieroj (*png *.jpg *.jpeg *.bmp);;Ĉiuj Dosieroj (*) Insert Table Enmenti Tabelon Rows: Vicoj: Columns: Kolumnoj: Print Document Presi la Dokumenton Export HTML Eksporti HTML Export: Eksporti: &Current node La &nunan nodon With all &sub-nodes Kun ĉiuj ĝiaj &subnodoj &All nodes Ĉi&ujn nodojn Output file: Eliga dosiero: Select path Elekti padon Question Demando The file already exists. Do you want to replace it? La dosiero jam ekzistas. Ĉu vi volas anstataŭigi ĝin? Save HTML As... Konservi HTML Kiel... HTML Files (*.html *.htm) HTML-Dosieroj (*.html *.htm) Set Password Aldoni Pasvorton Type password Tajpu pasvorton Retype password Retajpu pasvorton <center>Passwords were different. Retry!</center> <center>La pasvortoj estis malsamaj. Reprovu!</center> Enter Password Enmetu Pasvorton <center>Wrong password. Retry!</center> <center>Malĝusta pasvorto. Reprovu!</center> A lightweight notes manager Malpeza notadministrilo based on Qt bazita sur Qt Author Verkinto About FeatherNotes Pri FeatherNotes Translators Tradukintoj See Preferences → Text → Spell Checking! Vidu Agordoj → Texto → Literumada Kontrolo! You need to add a Hunspell dictionary. Vi bezonas Hunspell-vortaron. The Hunspell dictionary does not exist. La Hunspell-vortaro ne ĉeestas. The Hunspell dictionary is not accompanied by an affix file. La Hunspell-vortaro ne estas kune kun afiksa dosiero. No misspelling from text cursor. Neniu misliterumo ĉeestas en la dokumento. Spell Checking Literumada Kontrolo aka. akk. FeatherNotes::LineEdit Clear text (Ctrl+K) Viŝi la tekston (Ctrl+K) Ctrl+K Clear text Viŝi la tekston Ctrl+K FeatherNotes::PrefDialog Preferences Agordoj Window Fenestro Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Konservu la grandon de la fenestro post ĉi tiu dialogo estas fermita kaj forlasante. Malmarku por fiksita grando! Remember window &size Memoru la &grandon de la fenestro Start with this size: Startu kun ĉi tiu grando: px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Konservu la larĝon de la flankpanelo post ĉi tiu dialogo estas fermita kaj forlasante. Malmarku por la proprcio 170/530. Remember &tree width Memoru la larĝon de la &flankpanelo Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Konservu la pozicion post ĉi tiu dialogo estas fermita kaj forlasante. (Ĉi tio eble ne havas ĝustan efikon kun labortablaj medioj bazitaj sur GTK+.) Save &position Konservu la &pozicion Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Ĉi tio determinas ĉu taskopleto devas esti uzita. Se ĝi estus markita, la fermanta butono de la titolbreto ikonigus la fenestron en al taskopleton anstataŭ fermi ĝin. Restartigo de la aplikaĵo necesas. Add to s&ystray Aldonu al la ta&skopleto The command line option --tray can be used instead of this. La komandlinia opcio --tray povas esti uzita anstataŭe. Start i&conified to tray Startu i&konigite en la taskopleton Merge the tree view with its surroundings? Kunfandi la arbovidon kun ĝia ĉirkaŭaĵo? Transparent t&ree view Diafana a&rbovido By default, the active widget style determines the size of toolbar icons. Defaŭlte, la aktiva fenestraĵa etoso determinas kiom grandaj estas la ilbretaj ikonoj. Small toolbar icons Malgrandaj ilbretaj ikonoj Do not show t&oolbar Kaŝu la ilbre&ton If the menubar is hidden, a menu button appears on the toolbar. Se la menubreto estus kaŝita, menubutono aperus sur la ilbreto. Do not show &menubar Kaŝu la &menubreton Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Marku ĉi tion sub Enlightenment (aŭ eble alia labortabla medio) por uzi la taskopletan ikonon pli facile! Running &under Enlightenment? Funkcii su&b Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Iuj labortablaj medioj eblas ne sciigi la pozicion de la fenstro ĝuste. Ĉe tia okazo, vi povas provi forigi la problemon ĉi tie. Shifts (X × Y): Movoj (X × Y): Text Teksto &Wrap lines by default Ĉirkaŭfermu la &liniojn defaŭlte Auto-&indent by default Mem-al&ineu defaŭlte This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Ĉi tio pritraktas la rondan, rektan kaj kunigan krampojn kaj ankaŭ la citmarkojn. Restartigo de la aplikaĵo necesas. Auto-&bracket &Aŭtomata enkrampigo A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. La triobla punkto, duobla streketo ktp estas respektive anstataŭigitaj de la tripunkto, longa streketo ktp, dum tajpado kaj ĉe konvenaj cirkonstancoj. &Replace some characters while typing Anstataŭigu iujn &signojn dum tajpado Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Uzita por alglui la daton kaj tempon. Lasu ĉi tion malplena por la sistema defaŭlto. Efektiviĝos post kiam ĉi tiu dialogo estas fermita. Date and time format: Datoprezento: &Auto-save every Mem-konser&vu ĉiun minute(s) minuto(j)n Spell Checking Literumada Kontrolo A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". La Hunspell-vortaro havas nomon, kies finaĵo estas ".dic", kaj devas akompani afiksan dosieron, kiu havas la saman nomon se kun la finaĵo ".aff". Hunspell dictionary path: Pado de Hunspell-vortaro: Add dictionary... Aldoni vortaron... Files Dosieroj Start with the last opened file Startu kun la laste malfermita dosiero Shortcuts Fulmoklavoj Action Ago Shortcut Fulmoklavo Default Defaŭlto Warning: Ambiguous shortcut detected! Averto: Ambigua fulmoklavo estas detektita! The typed shortcut was reserved. La fulmoklavo tajpita estis rezervita. Application restart is needed for changes to take effect. Restartigo de la aplikaĵo necesas por ke la ŝanĝoj efektiviĝu. Hunspell Dictionary Files (*.dic) Hunspell-Vortaraj Dosieroj (*.dic) FeatherNotes::SpellDialog Unknown word: Nekonita vorto: Add To Dictionary Aldonu Al Vortaro Replace with: Anstataŭigu per: Ignore Once Ĝustigi Unufoje Ignore All Ignori Ĉiam Correct Once Ĝustigi Unufoje Correct All Ignori Ĉiam FeatherNotes::helpDialog Help Helpo QObject New Node Nova Nodo FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_es.ts000066400000000000000000002137111374721712500257730ustar00rootroot00000000000000 FeatherNotes::AboutDialog License Licencia FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes Next (F3) Siguiente (F3) F3 Previous (F4) Anterior (F4) F4 Search... Buscar... Search only in names (Ctrl+Shift+F7) Buscar solo en nombres (Ctrl+Mayús+F7) Ctrl+Shift+F7 Ctrl+Mayús+F7 Search only in tags (Shift+F7) Buscar solo en etiquetas (Mayús+F7) Shift+F7 Mayús+F7 Search in all nodes (F7) Buscar en todos los nodos (F7) F7 Whole Word (F6) Palabras completas (F6) Whole Word Palabra completa F6 Match Case (F5) Distinguir mayúsculas de minúsculas (F5) Match Case Distinguir mayúsculas de minúsculas F5 &File &Archivo &Edit &Editar For&mat &Formato &Tree Á&rbol &Options &Opciones &Search &Buscar &Help A&yuda Find: Buscar: Replace with: Sustituir con: To be replaced A sustituir Replacing text Texto de sustitución Previous (F9) Anterior (F9) F9 Next (F8) Siguiente (F8) F8 Replace all (F10) Sustituir todo (F10) F10 &Save &Guardar Save Guardar Ctrl+S &Open &Abrir Open a file Abrir un archivo Ctrl+O &Undo &Deshacer Undo Deshacer Ctrl+Z &Redo &Rehacer Redo Rehacer Ctrl+Shift+Z Ctrl+Mayús+Z &Find &Buscar Show/hide searchbar Mostrar/Ocultar la barra de búsqueda Ctrl+F &Clear All Formats &Limpiar todo el formato Clear all formats Limpiar todo el formato Ctrl+E &Bold &Negrita Bold Negrita Ctrl+B &Italic &Cursiva Italic Cursiva Ctrl+I &Underline &Subrayado Underline Subrayado Ctrl+U &Strike Through &Tachado Strike through Tachado Ctrl+T Te&xt Color Color del te&xto Text color Color del texto Alt+Shift+T Alt+Mayús+T Back&ground Color Color de &fondo Background color Color de fondo Alt+Shift+B Alt+Mayús+B Options Opciones &New Note &Nueva nota Ctrl+Alt+Shift+N Ctrl+Alt+Mayús+N Save &As Guardar &como Ctrl+Shift+S Ctrl+Mayús+S &Print &Imprimir Ctrl+P P&rint with Sub-Nodes Imprimir con &subnodos Set Pass&word &Establecer la contraseña &Quit &Salir Ctrl+Q &Cut &Cortar Ctrl+X C&opy C&opiar Ctrl+C &Paste &Pegar Ctrl+V &Delete &Borrar &Select All &Seleccionar todo Ctrl+A E&mbed Image Insertar una i&magen Embed Image Insertar imagen Ctrl+Alt+Shift+I Ctrl+Alt+Mayús+I E&xpand All E&xpandir todo Ctrl+Shift+Down Ctrl+Mayús+Abajo Collap&se All &Contraer todo Ctrl+Shift+Up Ctrl+Mayús+Arriba &Append Sibling &Añadir un hermano Ctrl+N Append &Child Añadir un &hijo Ctrl+Shift+N Ctrl+Mayús+N &Delete Node Borrar el &nodo Ctrl+D Move &Up &Subir Alt+Up Alt+Arriba Move Do&wn &Bajar Alt+Down Alt+Abajo Re&name Node &Renombrar el nodo Ctrl+Shift+R Ctrl+Mayús+R Tree Pr&operties Pr&opiedades del árbol Ctrl+Shift+D Ctrl+Mayús+D Document &Font Fuente del &documento &Wrap Lines &Dividir las líneas Ctrl+W &Auto-Indentation Sangría &automática Ctrl+Shift+I Ctrl+Mayús+I &Preferences &Preferencias Ctrl+Shift+P Ctrl+Mayús+P Find and &Replace Busca&r y sustituir Ctrl+R Ctrl+H &About &Acerca de Pr&int All Nodes Imprimir todos los &nodos Superscrip&t Su&períndice Superscript Superíndice Alt+Shift+U Alt+Mayús+U Subscri&pt Su&bíndice Subscript Subíndice Alt+Shift+S Alt+Mayús+S C&enter C&entrado Align center Alinear al centro Alt+Shift+Down Alt+Mayús+Abajo &Right &Derecha Align right Alinear a la derecha Alt+Shift+Right Alt+Mayús+Derecha &Left &Izquierda Align left Alinear a la izquierda Alt+Shift+Left Alt+Mayús+Izquierda &Justify &Justificado Justify Justificar Alt+Shift+Up Alt+Mayús+Arriba &Prepend Sibling &Preañadir un hermano Ctrl+M Move &Left Mover a la &izquierda Alt+Left Alt+Izquierda Move &Right Mover a la &derecha Alt+Right Alt+Derecha h&2 Header 2 Encabezado 2 Ctrl+2 h&1 Header 1 Encabezado 1 Ctrl+1 h&3 Header 3 Encabezado 3 Ctrl+3 &Node Font Fuente del &nodo Node Font Fuente del nodo Scale I&mage(s) Escalar las i&mágenes Paste &HTML Pegar &HTML Ctrl+Shift+V Ctrl+Mayús+V &Tags E&tiquetas Ctrl+Shift+T Ctrl+Mayús+T Insert Lin&k Insertar &un enlace Ctrl+L C&opy Link C&opiar enlace I&nsert Table I&nsertar una tabla Ctrl+Alt+Shift+T Ctrl+Alt+Mayús+T Append Row Añadir una fila Delete Row Borrar la fila Append Column Añadir una columna Delete Column Borrar la columna Merge Cells Fusionar las celdas Prepend Row Preañadir una fila Prepend Column Preañadir una columna Export &HTML Exportar a &HTML Save Ima&ge(s) Guardar imá&genes RTL De derecha a izquierda Ctrl+Alt+Shift+Left Ctrl+Alt+Mayús+Izquieda LTR De izquierda a derecha Ctrl+Alt+Shift+Right Ctrl+Alt+Mayús+Derecha Menu Menú Node &Icon &Icono del nodo Ctrl+Shift+C Ctrl+Mayús+C Check Spelling F2 Document &Colors Paste Date and Time Node Icon Icono del nodo &Raise/Hide &Elevar/Ocultar <center><b><big>New note?</big></b></center> <center><b><big>¿Desea crear una nueva nota?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>¿Seguro que quiere descartar este documento</i></center> <center><i>y crear uno vacío?</i></center> Yes No No <center><b><big>Save changes?</big></b></center> <center><b><big>¿Desea guardar los cambios?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>El documendo ha sido modificado.</i></center> <center><i>The document has been removed.</i></center> <center><i>El documento ha sido borrado.</i></center> Discard changes Descartar los cambios Cancel Cancelar Open file... Abrir archivo... <center><b><big>Cannot be saved!</big></b></center> <center><b><big>¡No se puede guardar!</big></b></center> Close Cerrar Save As... Guardar como... <center><b><big>Delete this node?</big></b></center> <center><b><big>¿Quiere borrar este nodo?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>¡Advertencia!</i></b></center> <center>Esta acción no se podrá deshacer.</center> Tags Etiquetas OK Aceptar <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Nodos principales:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Todos los nodos:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>Nota:</b> <i>%1</i><br><b>Nodos principales:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Todos los nodos:</b> <i>%3</i> %1 Matches %1 coincidencias One Match Una coincidencia No Match No hay coincidencias Replacement Sustitución No Replacement No han habido sustituciones One Replacement Una sustitución %1 Replacements %1 sustituciones Insert Link Insertar un enlace Image path Insertar ruta Open image Abrir una imagen Scaling percentage Porcentaje de escala Open Image... Abrir imagen... &Raise &Elevar New Node Nuevo nodo FeatherNotes documents (*.fnx);;All Files (*) Documentos de FeatherNotes (*.fnx);;Todos los archivos (*) Untitled Sin título Select Text Color Select Background Color Deletion Borrado Tag(s) for this node Etiqueta(s) para este nodo Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Archivos de imagen (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;Todos los archivos (*) Select Document Font Select Node Font Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to Escalar al % Scale Image(s) Escalar imágenes untitled sin título Error <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>¡No se pudo guradar la imagen! ¿Quiere volver a intentarlo?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>Puede que no eligiera una extensión adecuada</center> <center>o que no tenga permisos de escritura.</center><p></p> Save Image As... Guardar imagen como... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Archivos de imagen (*.png *.jpg *.jpeg *.bmp);;Todos los archivos (*) Insert Table Insertar tabla Rows: Filas: Columns: Columnas: Print Document Imprimir el documento Export HTML Exportar a HTML Export: Exportar: &Current node Nodo a&ctual With all &sub-nodes Con todos los &subnodos &All nodes Todos los &nodos Output file: Archivo de salida: Select path Seleccionar la ruta Question The file already exists. Do you want to replace it? Save HTML As... Guardar HTML como... HTML Files (*.html *.htm) Archivos HTML (*.html *.htm) Set Password Establecer la contraseña Type password Escriba la contraseña Retype password Reescriba la contraseña <center>Passwords were different. Retry!</center> <center>Las contraseñas no coinciden. ¡Reinténtalo!</center> Enter Password Introduzca la contraseña <center>Wrong password. Retry!</center> <center>Contraseña incorrecta. ¡Vuelva a intentarlo!</center> A lightweight notes manager Un gestor de notas ligero based on Qt basado en Qt Author Autor About FeatherNotes Acerca de FeatherNotes Translators Traductores See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. alias. FeatherNotes::LineEdit Clear text (Ctrl+K) Limpiar el texto (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences Preferencias Window Ventana Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Guarda el tamaño de la ventana al cerrar este diálogo y también al salir ¡Desmárquelo para hacer el tamaño fijo! Remember window &size Recordar el tamaño de la &ventana Start with this size: Empezar con este tamaño: px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Guarda el ancho del árbol al cerrar este diálogo y también al salir. Desmárquelo para un ratio de anchura de 170/530. Remember &tree width Recordar el &ancho del árbol Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Guarda la posición al cerrar este diálogo y también al salir. (Puede no funcionar correctamente en escritorios GTK+ como Unity y Cinnamon.) Save &position Guardar la &posición Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Decide si se usa un icono en la bandeja del sistema. Si se marca, el botón de cierre de la barra de título minimiza la ventana a la bandeja del sistema en vez de salir. Es necesario reiniciar FeatherNotes para que tenga efecto. Add to s&ystray Añadir a la bande&ja del sistema The command line option --tray can be used instead of this. Se puede usar la opción de la línea de comandos --tray en vez de esto. Start i&conified to tray Ini&ciar minimizado en la bandeja Merge the tree view with its surroundings? ¿Quiere fusionar la vista de árbol con lo que la rodea? Transparent t&ree view Vista de árbol t&ransparente By default, the active widget style determines the size of toolbar icons. Por defecto, el estilo del control activo determina el tamaño de los iconos de la barra de herramientas. Small toolbar icons Iconos pequeños de la barra de herramientas Do not show t&oolbar N&o mostrar la barra de herramientas If the menubar is hidden, a menu button appears on the toolbar. Si la barra de menu está oculta, aparece un botón de menú en la barra de herramientas. Do not show &menubar No mostrar la barra de &menús Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! ¡Marque esto en Enlightenment (o, quizás, otro entorno de escritorio) para usar la bandeja del sistema con más facilidad! Running &under Enlightenment? ¿Está &usando Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Algunos entornos de escritorio (como Enlightenment) pueden no reportar la posición de la ventana correctamente. En ese caso, puede intentar arreglar el problema aquí. Si el panel está abajo o arriba, debe asignar un valor a la coordenada Y; si está a la izquierda o a la derecha, se lo debe asignar a la coordenada X. ¡Después de elegir los desplazamientos de coordenadas, ponga la ventana en una posición adecuada y reinicie FeatherNotes! Shifts (X × Y): Desplazamientos (X × Y): Text Texto &Wrap lines by default &Dividir las líneas por omisión Auto-&indent by default Sangría automát&ica por omisón This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Esto incluye paréntesis, llaves, corchetes y comillas. Es necesario reiniciar FeatherNotes para que tenga effecto. Auto-&bracket &Paréntesis automáticos A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. Mientras el usuario escribe, y en las circunstancias apropiadas, tres puntos seguidos se sustituyen por puntos suspensivos, dos guiones por un guión largo, etc. &Replace some characters while typing &Reemplazar algunos caracteres mientras se escribe Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every &Autoguardar cada minute(s) minuto(s) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Atajos Action Acción Shortcut Atajo Default Predeterminado Warning: Ambiguous shortcut detected! Advertencia: ¡Se ha encontrado un atajo equivocado! The typed shortcut was reserved. El atajo que intenta utilizar se encuentra reservado. Application restart is needed for changes to take effect. Es necesario reiniciar la aplicación para que los cambios tengan efecto. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Sustituir con: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help Ayuda QObject New Node Nuevo nodo FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_fr.ts000066400000000000000000002137221374721712500257750ustar00rootroot00000000000000 FeatherNotes::AboutDialog License Licence FeatherNotes::ColorLabel Click to change color. Cliquer pour changer de couleur. Select Color Sélectionner une couleur FeatherNotes::FN FeatherNotes Next (F3) Suivant (F3) F3 Previous (F4) Précédent (F4) F4 Search... Chercher... Search only in names (Ctrl+Shift+F7) Rechercher uniquement dans les noms (Ctrl+Maj+F7) Ctrl+Shift+F7 Ctrl+Maj+F7 Search only in tags (Shift+F7) Rechercher uniquement dans les balises (Maj+F7) Shift+F7 Maj+F7 Search in all nodes (F7) Rechercher dans tous les nœuds (F7) F7 Whole Word (F6) Mot entier (F6) Whole Word Mot entier F6 Match Case (F5) Respecter la casse (F5) Match Case Respecter la casse F5 &File &Fichier &Edit &Éditer For&mat &Tree &Arborescence &Options &Search &Chercher &Help &Aide Find: Trouver : Replace with: Remplacer par : To be replaced À remplacer Replacing text Texte de remplacement Previous (F9) Précédent (F9) F9 Next (F8) Suivant (F8) F8 Replace all (F10) Tout remplacer (F10) F10 &Save &Enregistrer Save Enregistrer Ctrl+S &Open &Ouvrir Open a file Ouvrir un fichier Ctrl+O &Undo &Annuler Undo Annuler Ctrl+Z &Redo &Refaire Redo Refaire Ctrl+Shift+Z &Find &Trouver Show/hide searchbar Afficher/masquer la barre de recherche Ctrl+F &Clear All Formats &Effacer tous les formats Clear all formats Effacer tous les formats Ctrl+E &Bold &Gras Bold Gras Ctrl+B &Italic Italic Ctrl+I &Underline &Souligner Underline Souligner Ctrl+U &Strike Through &Frapper à travers Strike through Frapper à travers Ctrl+T Te&xt Color Text color Alt+Shift+T Back&ground Color Couleur de &fond Background color Couleur de fond Alt+Shift+B Options &New Note Ctrl+Alt+Shift+N Save &As Enregistrer &sous Ctrl+Shift+S &Print &Imprimer Ctrl+P P&rint with Sub-Nodes Imp&rimer avec les sous-nœuds Set Pass&word &Quit &Quitter Ctrl+Q &Cut &Couper Ctrl+X C&opy C&opier Ctrl+C &Paste Col&ler Ctrl+V &Delete &Select All &Tout sélectionner Ctrl+A E&mbed Image In&tégrer l'image Embed Image Intégrer l'image Ctrl+Alt+Shift+I E&xpand All Dé&velopper tout Ctrl+Shift+Down Collap&se All Rédui&re tout Ctrl+Shift+Up &Append Sibling &Ajouter un frère Ctrl+N Append &Child Ajouter un &enfant Ctrl+Shift+N &Delete Node Ctrl+D Move &Up Déplacer vers le &haut Alt+Up Move Do&wn &Descendre Alt+Down Re&name Node Ctrl+Shift+R Tree Pr&operties Pr&opriétés de l'arbre Ctrl+Shift+D Document &Font &Wrap Lines &Retour à la ligne Ctrl+W &Auto-Indentation &Indentation automatique Ctrl+Shift+I &Preferences &Préférences Ctrl+Shift+P Find and &Replace Trouver et &remplacer Ctrl+R Ctrl+H &About À &propos Pr&int All Nodes Impr&imer tous les nœuds Superscrip&t En exposan&t Superscript En exposant Alt+Shift+U Subscri&pt Indi&ce Subscript Indice Alt+Shift+S C&enter Align center Aligner au centre Alt+Shift+Down &Right Align right Aligner à droite Alt+Shift+Right &Left &Gauche Align left Aligner à gauche Alt+Shift+Left Alt+Maj+Gauche &Justify &Justifier Justify Justifier Alt+Shift+Up &Prepend Sibling &Préfini enfant de mêmes parents Ctrl+M Move &Left Déplacer à &gauche Alt+Left Alt+Gauche Move &Right Déplacer à &droite Alt+Right h&2 Header 2 En-tête 2 Ctrl+2 h&1 Header 1 En-tête 1 Ctrl+1 h&3 Header 3 En-tête 3 Ctrl+3 &Node Font Node Font Scale I&mage(s) Image(s) d'échelle Paste &HTML Coller &HTML Ctrl+Shift+V &Tags Ctrl+Shift+T Insert Lin&k Insérer un &lien Ctrl+L C&opy Link C&opier un lien I&nsert Table I&nsérer un tableau Ctrl+Alt+Shift+T Append Row Ajouter une ligne Delete Row Supprimer la ligne Append Column Ajouter une colonne Delete Column Supprimer la colonne Merge Cells Fusionner les cellules Prepend Row Ligne de début Prepend Column Préfixe colonne Export &HTML Save Ima&ge(s) Enregistrer les ima&ge(s) RTL Ctrl+Alt+Shift+Left Ctrl+Alt+Maj+Gauche LTR Ctrl+Alt+Shift+Right Menu Node &Icon Ctrl+Shift+C Check Spelling Vérifier l'orthographe F2 F2 Document &Colors &Couleurs du document Paste Date and Time Coller la date et l'heure Node Icon &Raise/Hide &Élever/Cacher <center><b><big>New note?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>Voulez-vous vraiment laisser ce document</i></center> <center><i>et créer un vide ? </i></center> Yes Oui No <center><b><big>Save changes?</big></b></center> <center><b><big>Enregistrer les modifications ?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>Le document a été modifié.</i></center> <center><i>The document has been removed.</i></center> <center><i>Le document a été supprimé.</i></center> Discard changes Annuler les modifications Cancel Annuler Open file... <center><b><big>Cannot be saved!</big></b></center> <center><b><big>Ne peut pas être enregistré !</big></b></center> Close Fermer Save As... Enregistrer sous... <center><b><big>Delete this node?</big></b></center> <center><b><big>Supprimer ce nœud ?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>Avertissement !</i></b></center> <center>Cette action ne peut pas être annulée.</center> Tags OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Noeuds principaux : </b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Tous les noeuds : </b><i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>Note : </b><i>%1</i><br><b>Noeuds principaux : </b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Tous les noeuds : </b><i>%3</i> %1 Matches %1 Correspondances One Match Une correspondance No Match Pas de correspondance Replacement Remplacement No Replacement Pas de remplacement One Replacement Un remplacement %1 Replacements %1 Remplacements Insert Link Image path Chemin de l'image Open image Scaling percentage Échelle de pourcentage Open Image... &Raise &Augmenter New Node FeatherNotes documents (*.fnx);;All Files (*) FeatherNotes documents (*.fnx);;Tous les fichiers (*) Untitled Sans titre Select Text Color Sélectionner la couleur du texte Select Background Color Sélectionner la couleur d'arrière-plan Deletion Effacement Tag(s) for this node Tag(s) pour ce noeud Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Fichiers d'image (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;Tous les fichiers (*) Select Document Font Sélectionner la police du document Select Node Font Sélectionner la police du nœud Set Document Colors Définir les couleurs du document These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Ces couleurs seront appliquées aux nouveaux nœuds.<br>Elles peuvent ou non affecter les nœuds existants<br>mais la réouverture du document est recommandée. Background color: Couleur de l'arrière plan : Text color: Couleur du texte : The first 1000 replacements are highlighted. Les 1000 premiers remplacements sont mis en évidence. Scale to Échelle à % Scale Image(s) Échelle des image(s) untitled sans titre Error Erreur <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>L'image ne peut pas être enregistrée ! Réessayez ?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>Peut-être que vous n'avez pas choisi une extension adéquate</center> <center>ou que vous n'avez pas l'autorisation d'écriture.</center><p></p> Save Image As... Enregistrer l'image sous... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Fichiers d'image (*.png *.jpg *.jpeg *.bmp);;Tous les fichiers (*) Insert Table Rows: Lignes : Columns: Colonnes : Print Document Imprimer le document Export HTML Export: Exporter : &Current node Noeud &actuel With all &sub-nodes Avec tous les &sous-nœuds &All nodes &Tous les nœuds Output file: Fichier de sortie : Select path Sélectionner le chemin Question Question The file already exists. Do you want to replace it? Le fichier existe déjà. Voulez-vous le remplacer ? Save HTML As... Enregistrer HTML sous... HTML Files (*.html *.htm) Fichiers HTML (*.html *.htm) Set Password Type password Retype password Retaper le mot de passe <center>Passwords were different. Retry!</center> <center>Les mots de passe sont différents. Réessayer !</center> Enter Password <center>Wrong password. Retry!</center> <center>Mauvais mot de passe. Réessayer !</center> A lightweight notes manager Un gestionnaire de notes léger based on Qt basé sur Qt Author About FeatherNotes À propos de FeatherNotes Translators Traducteurs See Preferences → Text → Spell Checking! Voir Préférences → Texte → Vérification orthographique ! You need to add a Hunspell dictionary. Vous devez ajouter un dictionnaire Hunspell. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking Vérification orthographique aka. FeatherNotes::LineEdit Clear text (Ctrl+K) Effacer le texte (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences Préférences Window Fenêtre Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Enregistrer la taille de la fenêtre après la fermeture de cette boîte de dialogue et également à sa sortie. Décocher pour définir une taille fixe ! Remember window &size Se rappeler de la &taille de la fenêtre Start with this size: Démarrer avec la taille : px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Enregistrer la largeur de l’arbre après la fermeture de cette boîte de dialogue et également à sa sortie. Décocher la case pour un rapport de largeur de 170/530. Remember &tree width Se rappeler de la largeur de l'&arbre Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Enregistrer la position après la fermeture de cette boîte de dialogue et également à la sortie. (Cela peut ne pas fonctionner correctement sous GTK + et les DE comme Unity et Cinnamon.) Save &position Sauvegarder la &position Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Décider si un icône de la zone de notification doit être utilisé. Si cette case est cochée, le bouton de fermeture de la barre de titre iconifie la fenêtre dans la barre des tâches au lieu de quitter. Nécessite de redémarrer FeatherNotes pour prendre effet. Add to s&ystray Ajouter à la zone de notification The command line option --tray can be used instead of this. L'option de ligne de commande --tray peut être utilisé à la place de cela. Start i&conified to tray Démarrer iconifié sur le plateau Merge the tree view with its surroundings? Fusionner la vue de l'arbre avec ses environs ? Transparent t&ree view Vue transparente de l'&arbre By default, the active widget style determines the size of toolbar icons. Par défaut, le style de widget actif détermine la taille des icônes de la barre d'outils. Small toolbar icons Petites icônes de la barre d'outils Do not show t&oolbar Ne pas afficher la barre d'&outils If the menubar is hidden, a menu button appears on the toolbar. Si la barre de menu est masquée, un bouton de menu apparaît dans la barre d'outils. Do not show &menubar Ne pas afficher la barre de &menu Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Cocher cette case sous Enlightenment (ou probablement un autre DE) utiliser l'icône de la zone de notification plus facilement ! Running &under Enlightenment? Courir sous Enlightenment ? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Certains DE (comme Enlightenment) peuvent ne pas indiquer correctement la position de la fenêtre. Si tel est le cas, vous pouvez essayer de résoudre le problème ici. Si le panneau est en bas ou en haut, les coordonnées Y doivent être définies ; si elle est à gauche ou à droite, les coordonnées X devront être définies. Après avoir choisi les décalages de coordonnées, placer la fenêtre dans la position appropriée puis redémarrer FeatherNotes ! Shifts (X × Y): Changements (X × Y): Text &Wrap lines by default &Retour à la ligne par défaut Auto-&indent by default Indentation auto&matique par défaut This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Cela couvre les parenthèses, les accolades, les crochets et les citations. Nécessite de redémarrer FeatherNotes pour prendre effet. Auto-&bracket &Crochet automatique A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. Une triple période est remplacée par une ellipse, un double trait d'union avec un long tiret, etc. l'utilisateur tape dans des circonstances appropriées. &Replace some characters while typing &Remplacer certains caractères lors de la saisie Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Utilisé pour coller la date et l'heure. Laissez vide pour la valeur par défaut du système. Prend effet après la fermeture de cette boîte de dialogue. Date and time format: Format de la date et de l'heure : &Auto-save every &Sauvegarde automatique tous les minute(s) Spell Checking Vérification orthographique A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Ajouter un dictionnaire... Files Fichiers Start with the last opened file Démarrer avec le dernier fichier ouvert Shortcuts Raccourcis Action Action Shortcut Raccourci Default Par défaut Warning: Ambiguous shortcut detected! Attention : raccourci ambigu détecté ! The typed shortcut was reserved. Le raccourci saisi est réservé. Application restart is needed for changes to take effect. Un redémarrage de l’application est nécessaire pour que les changements prennent effet. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Mot inconnu : Add To Dictionary Ajouter Au Dictionnaire Replace with: Remplacer par : Ignore Once Ignorer un Ignore All Tout ignorer Correct Once Corriger Correct All Tout corriger FeatherNotes::helpDialog Help QObject New Node FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_he.ts000066400000000000000000002175001374721712500257600ustar00rootroot00000000000000 FeatherNotes::AboutDialog License רישיון FeatherNotes::ColorLabel Click to change color. לחיצה לשינוי צבע. Select Color בחירת צבע FeatherNotes::FN FeatherNotes Next (F3) הבא (F3) F3 Previous (F4) הקודם (F4) F4 Search... חיפוש… Search only in names (Ctrl+Shift+F7) חיפוש בשמות בלבד (Ctrl+Shift+F7) Ctrl+Shift+F7 Search only in tags (Shift+F7) חיפוש בתגיות בלבד (Shift+F7) Shift+F7 Search in all nodes (F7) חיפוש בכל המפרקים (F7) F7 Whole Word (F6) מילה שלמה (F6) Whole Word מילה שלמה F6 Match Case (F5) התאמת רישיות (F5) Match Case התאמת רישיות F5 &File &קובץ &Edit ע&ריכה For&mat &עיצוב &Tree ע&ץ &Options &אפשרויות &Search &חיפוש &Help ע&זרה Find: איתור: Replace with: החלפה ב־: To be replaced להחלפה Replacing text טקסט מחליף Previous (F9) הקודם (F9) F9 Next (F8) הבא (F8) F8 Replace all (F10) להחליף הכול (F10) F10 &Save &שמירה Save שמירה Ctrl+S &Open &פתיחה Open a file פתיחת קובץ Ctrl+O &Undo &ביטול Undo ביטול Ctrl+Z &Redo ביצוע &חוזר Redo ביצוע חוזר Ctrl+Shift+Z &Find &חיפוש Show/hide searchbar הצגה/הסתרה של סרגל החיפוש Ctrl+F &Clear All Formats &ניקוי כל העיצובים Clear all formats ניקוי כל העיצובים Ctrl+E &Bold מו&דגש Bold מודגש Ctrl+B &Italic &נטוי Italic נטוי Ctrl+I &Underline &קו תחתי Underline קו תחתי Ctrl+U &Strike Through קו &חוצה Strike through קו חוצה Ctrl+T Te&xt Color צבע ה&טקסט Text color צבע הטקסט Alt+Shift+T Back&ground Color צבע ה&רקע Background color צבע הרקע Alt+Shift+B Options אפשרויות &New Note &פתק חדש Ctrl+Alt+Shift+N Save &As שמירה &בשם Ctrl+Shift+S &Print ה&דפסה Ctrl+P P&rint with Sub-Nodes הדפסה עם תת־&צמתים Set Pass&word הגדרת &ססמה &Quit &יציאה Ctrl+Q &Cut &גזירה Ctrl+X C&opy ה&עתקה Ctrl+C &Paste ה&דבקה Ctrl+V &Delete מ&חיקה &Select All לבחור ה&כול Ctrl+A E&mbed Image ה&טמעת תמונה Embed Image הטמעת תמונה Ctrl+Alt+Shift+I E&xpand All לה&רחיב הכול Ctrl+Shift+Down ‪Ctrl+Shift+למטה Collap&se All ל&צמצם הכול Ctrl+Shift+Up ‪Ctrl+Shift+למעלה &Append Sibling הוספת &אח בהתחלה Ctrl+N Append &Child הוספת &צאצא בהתחלה Ctrl+Shift+N &Delete Node מחיקת צו&מת Ctrl+D Move &Up ה&גבהה Alt+Up ‪Alt+למעלה Move Do&wn ה&נמכה Alt+Down ‪Alt+למטה Re&name Node שינוי &שם מפרק Ctrl+Shift+R Tree Pr&operties מאפייני &עץ Ctrl+Shift+D Document &Font &גופן מסמך &Wrap Lines ג&לישת שורות Ctrl+W &Auto-Indentation ה&זחה אוטומטית Ctrl+Shift+I &Preferences ה&עדפות Ctrl+Shift+P Find and &Replace &חיפוש והחלפה Ctrl+R Ctrl+H &About על &אודות Pr&int All Nodes הדפסת &כל המפרקים Superscrip&t כתב &עלי Superscript כתב עלי Alt+Shift+U Subscri&pt כתב ת&חתי Subscript כתב תחתי Alt+Shift+S C&enter מ&רכז Align center למרכז Alt+Shift+Down ‪Alt+Shift+למטה &Right י&מין Align right יישור לימין Alt+Shift+Right ‪Alt+Shift+ימינה &Left &שמאל Align left יישור לשמאל Alt+Shift+Left ‪Alt+Shift+שמאלה &Justify יישור &דו־צדדי Justify יישור דו־צדדי Alt+Shift+Up ‪Alt+Shift+למעלה &Prepend Sibling הוספת אח ב&סוף Ctrl+M Move &Left הזזה &שמאלה Alt+Left ‪Alt+שמאלה Move &Right הזזה ימי&נה Alt+Right ‪Alt+ימינה h&2 כ&2 Header 2 כותרת 2 Ctrl+2 h&1 כ&1 Header 1 כותרת 1 Ctrl+1 h&3 כ&3 Header 3 כותרת 3 Ctrl+3 &Node Font &גופן המפרק Node Font גופן המפרק Scale I&mage(s) שינוי &גודל תמונות Paste &HTML ה&דבקת HTML Ctrl+Shift+V &Tags &תגיות Ctrl+Shift+T Insert Lin&k הוספת &קישור Ctrl+L C&opy Link ה&עתקת קישור I&nsert Table הוספת &טבלה Ctrl+Alt+Shift+T Append Row הוספת שורה בהתחלה Delete Row מחיקת שורה Append Column הוספת עמודה בהתחלה Delete Column מחיקת עמודה Merge Cells מיזוג תאים Prepend Row הוספת שורה בסוף Prepend Column הוספת עמודה בסוף Export &HTML יי&צוא HTML Save Ima&ge(s) &שמירת תמונות RTL Ctrl+Alt+Shift+Left ‪Ctrl+Alt+Shift+שמאלה LTR Ctrl+Alt+Shift+Right ‪Ctrl+Alt+Shift+ימינה Menu תפריט Node &Icon &סמל מפרק Ctrl+Shift+C Check Spelling בדיקת איות F2 F2 Document &Colors &צבעי המסמך Paste Date and Time הדבקת התאריך והשעה Node Icon סמל מפרק &Raise/Hide ה&רמה/הסתרה <center><b><big>New note?</big></b></center> <center><b><big>פתקית חדשה?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center>לצאת מהמסמך הזה</center> <center>וליצור אחד ריק?</center> Yes כן No לא <center><b><big>Save changes?</big></b></center> <center><b><big>לשמור את השינויים?</big></b></center> <center><i>The document has been modified.</i></center> <center>המסמך נערך.</center> <center><i>The document has been removed.</i></center> <center>המסמך הוסר.</center> Discard changes התעלמות מהשינויים Cancel ביטול Open file... פתיחת קובץ… <center><b><big>Cannot be saved!</big></b></center> <center><b><big>לא ניתן לשמור!</big></b></center> Close סגירה Save As... שמירה בשם… <center><b><big>Delete this node?</big></b></center> <center><b><big>למחוק את המפרק הזה?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b>אזהרה!</b></center> <center>פעולה זו אינה הפיכה.</center> Tags תגיות OK אישור <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>מפרקים ראשיים:</b>%1&nbsp;&nbsp;&nbsp;&nbsp;<b>כל המפרקים:</b>%2 <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>הערה:</b> %1<br><b>מפרקים ראשיים:</b> %2&nbsp;&nbsp;&nbsp;&nbsp;<b>כל המפרקים:</b> %3 %1 Matches %1 תוצאות One Match תוצאה אחת No Match אין תוצאות Replacement החלפה No Replacement אין החלפה One Replacement החלפה אחת %1 Replacements %1 החלפות Insert Link הוספת קישור Image path נתיב לתמונה Open image פתיחת תמונה Scaling percentage אחוז שינוי גודל Open Image... פתיחת תמונה… &Raise ה&רמה New Node מפרק חדש FeatherNotes documents (*.fnx);;All Files (*) מסמכי FeatherNotes‏ (‎*.fnx);;כל הקבצים (*) Untitled ללא כותרת Select Text Color בחירת צבע טקסט Select Background Color בחירת צבע רקע Deletion מחיקה Tag(s) for this node תגיות למפרק זה Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) קובצי תמונות (‎*.svg *.png *.jpg *.jpeg *.bmp *.gif);;כל הקבצים (*) Select Document Font בחירת גופן מסמך Select Node Font בחירת גופן מפרק Set Document Colors הגדרת צבעי המסמך These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. הצבעים האלו יחולו על מפרקים חדשים.<br>הם עשויים להשפיע על מפרקים קיימים<br>מומלץ לפתוח את המסמך מחדש בכל מקרה. Background color: צבע הרקע: Text color: צבע הטקסט: The first 1000 replacements are highlighted. 1000 ההחלפות הראשונות מודגשות. Scale to שינוי גודל לכדי % Scale Image(s) שינוי גודל תמונות untitled ללא כותרת Error שגיאה <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>לא ניתן לשמור את התמונה! לנסות שוב?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>אולי לא בחרת את הסיומת הנכונה</center> <center>או שיש בעיית הרשאות.</center><p></p> Save Image As... שמירת תמונה בשם… Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) קובצי תמונות (‎*.png *.jpg *.jpeg *.bmp);;כל הקבצים (*) Insert Table הוספת טבלה Rows: שורות: Columns: עמודות: Print Document הדפסת מסמך Export HTML ייצוא HTML Export: ייצוא: &Current node מפרק &נוכחי With all &sub-nodes &עם כל תת־המפרקים &All nodes &כל המפרקים Output file: קובץ פלט: Select path בחירת נתיב Question שאלה The file already exists. Do you want to replace it? קובץ זה כבר קיים. להחליף אותו? Save HTML As... לשמור HTML בשם… HTML Files (*.html *.htm) קובצי HTML‏ (‎*.html *.htm) Set Password הגדרת ססמה Type password נא להקליד ססמה Retype password להקליד את הססמה שוב <center>Passwords were different. Retry!</center> <center>הססמאות אינן זהות. נא לנסות שוב!</center> Enter Password נא להקליד ססמה <center>Wrong password. Retry!</center> <center>ססמה שגויה. נא לנסות שוב!</center> A lightweight notes manager מנהל פתקיות קליל based on Qt מבוסס על Qt Author יוצר About FeatherNotes על אודות FeatherNotes Translators מתרגמים See Preferences → Text → Spell Checking! יש לפנות אל העדפות ← טקסט ← בדיקת איות! You need to add a Hunspell dictionary. יש להוסיף מילון Hunspell. The Hunspell dictionary does not exist. מילון Hunspell לא קיים. The Hunspell dictionary is not accompanied by an affix file. מילון ה־Hunspell אינו מלווה בקובץ מוספית. No misspelling from text cursor. אין שגיאות איות מסמן הטקסט. Spell Checking בדיקת איות aka. גם בשם FeatherNotes::LineEdit Clear text (Ctrl+K) טקסט פשוט (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences העדפות Window חלון Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! שמירת גודל החלון לאחר סגירת תיבת דו־שיח זו וגם ביציאה. ניתן לבטל את הסימן כדי לקבוע גודל קבוע! Remember window &size לזכור את &גודל החלון Start with this size: להתחיל בגודל הזה: px פיקסלים Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. שמירת רוחב העץ לאחר סגירת דו־שיח זה וגם ביציאה. ניתן לבטל את הסימון לקבלת יחס רוחב של 170/530. Remember &tree width לזכור את &רוחב העץ Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) שמירת המיקום לאחר סגירת דו־שיח זה וגם ביציאה. (עשוי לא לפעול כראוי בסביבות שולחן עבודה מסוג GTK+‎ כגון Unity ו־Cinnamon.) Save &position &שמירת המיקום Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. ההחלטה האם יש להשתמש בסמל במגש המערכת. אם האפשרות מסומנת, כפתור הסגירה בשורת הכותרת יצמצם את החלון לתוך הסמל במקום לסגור את התכנית. נדרשת הפעלה מחדש של FeatherNotes כדי שהגדרה זו תיכנס לתוקף. Add to s&ystray הוספה למגש המ&ערכת The command line option --tray can be used instead of this. ניתן להשתמש באפשרות ‎--tray בשורת הפקודה במקום הגדרה זו. Start i&conified to tray להתחיל ממוזער כ&סמל במגש המערכת Merge the tree view with its surroundings? למזג את העץ עם סביבתו? Transparent t&ree view תצוגת עץ &שקופה By default, the active widget style determines the size of toolbar icons. כבררת מחדל, סגנון הווידג׳ט הפעיל מגדיר את גודל הסמלים בסרגל הכלים. Small toolbar icons סמלים קטנים בסרגל הכלים Do not show t&oolbar לא לה&ציג סרגל כלים If the menubar is hidden, a menu button appears on the toolbar. אם סרגל התפריטים מוסתר, מופיע כפתור תפריט בסרגל הכלים. Do not show &menubar לא להציג את סרגל ה&תפריטים Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! ניתן לבדוק זאת תחת Enlightenment (או אולי תחת סביבת שולחן עבודה אחרת) כדי להשתמש בסמל מגש המערכת ביתר קלות! Running &under Enlightenment? מופעל ת&חת Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! חלק מסביבות שולחן העבודה (כגון Enlightenment) עשויים לשגות בדיווח על מיקום החלון. אם המצב, ניתן לשנות לתקן את התקלה מפה. אם הלוח הוא למטה או למעלה, ציר ה־Y אמור להיות מוגדר; אם הוא משמאל או מימין, ציר ה־X אמור להיות מוגדר. לאחר בחירת הזחת נקודות הציון, יש להציב את החלון במיקום ראוי ולאחר מכן להפעיל את FeatherNotes מחדש! Shifts (X × Y): הזחות (X × Y): Text טקסט &Wrap lines by default גלישת שורות כ&בררת מחדל Auto-&indent by default הזחה &אוטומטית כבררת מחדל This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. זה כולל סוגריים, סוגריים מסולסלים, סוגריים מרובעים ומירכאות. נדרשת הפעלה מחדש של FeatherNotes כדי שהשינוי ייכנס לתוקף. Auto-&bracket &סוגריים אוטומטיים A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. שלוש נקודות מוחלפות באליפסיס (סימן השמטה), שני מינוסים יוחלפו בקו ארוך וכו׳ תוך כדי הקלדה ותחת תנאים מתאימים. &Replace some characters while typing ה&חלפת חלק מהתווים בזמן ההקלדה Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. בשימוש להדבקת התאריך והשעה. יש להשאיר ריק עבור ברירת המחדל של המערכת. השינויים ייכנסו לתוקף לאחר סגירת דו־שיח זה. Date and time format: תבנית תאריך ושעה: &Auto-save every ל&שמור אוטומטית בכל minute(s) דקות Spell Checking בדיקת איות A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". למילון Hunspell יש שם שמסתיים ב־„‎.dic” ואמור להיות לצד קובץ מוספית באותו השם רק עם הסיומת „‎.aff”. Hunspell dictionary path: נתיב מילון Hunspell: Add dictionary... הוספת מילון... Files קבצים Start with the last opened file להתחיל עם הקובץ האחרון שנפתח Shortcuts קיצורי דרך Action פעולה Shortcut קיצור דרך Default בררת מחדל Warning: Ambiguous shortcut detected! אזהרה: התגלה קיצור דרך שאינו ייחודי! The typed shortcut was reserved. קיצור הדרך שהוקלד נשמר מראש. Application restart is needed for changes to take effect. יש להפעיל את היישום מחדש כדי שהשינויים ייכנסו לתוקף. Hunspell Dictionary Files (*.dic) קובצי מילון Hunspell‏ (‎*.dic) FeatherNotes::SpellDialog Unknown word: מילה לא ידועה: Add To Dictionary הוספה למילון Replace with: להחליף עם: Ignore Once להתעלם מאחד Ignore All להתעלם מהכול Correct Once לתקן אחד Correct All לתקן הכול FeatherNotes::helpDialog Help עזרה QObject New Node מפרק חדש FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_hu.ts000066400000000000000000002150041374721712500257750ustar00rootroot00000000000000 FeatherNotes::AboutDialog License Licenc FeatherNotes::ColorLabel Click to change color. Kattintás a szín kiválasztásához. Select Color Szín kiválasztása FeatherNotes::FN FeatherNotes FeatherNotes Next (F3) Következő (F3) F3 F3 Previous (F4) Előző (F4) F4 F4 Search... Keresés... Search only in names (Ctrl+Shift+F7) Keresés az elemek nevében (Ctrl+Shift+F7) Ctrl+Shift+F7 Ctrl+Shift+F7 Search only in tags (Shift+F7) Keresés a címkékben (Shift+F7) Shift+F7 Shift+F7 Search in all nodes (F7) Keresés az elemek tartalmában (F7) F7 F7 Whole Word (F6) Teljes szó (F6) Whole Word Teljes szó F6 F6 Match Case (F5) Nagybetűérzékeny (F5) Match Case Nagybetűérzékeny F5 F5 &File &Fájl &Edit S&zerkesztés For&mat For&mátum &Tree &Elemek &Options &Beállítások &Search &Keresés &Help &Súgó Find: Ezt: Replace with: Erre: To be replaced lecserélni Replacing text a szövegre Previous (F9) Előző (F9) F9 F9 Next (F8) Következő (F8) F8 F8 Replace all (F10) Összes cseréje (F10) F10 F10 &Save &Mentés Save Mentés Ctrl+S Ctrl+S &Open Me&gnyitás Open a file Fájl megnyitása Ctrl+O Ctrl+O &Undo &Visszavonás Undo Visszavonás Ctrl+Z Ctrl+Z &Redo &Mégis Redo Mégis Ctrl+Shift+Z Ctrl+Shift+Z &Find &Keresés Show/hide searchbar Keresősáv megjelenítése/elrejtése Ctrl+F Ctrl+F &Clear All Formats &Formátumok törlése Clear all formats Formátumok törlése Ctrl+E Ctrl+E &Bold Fé&lkövér Bold Félkövér Ctrl+B Ctrl+B &Italic &Dőlt Italic Dőlt Ctrl+I Ctrl+I &Underline &Aláhúzott Underline Aláhúzott Ctrl+U Ctrl+U &Strike Through Át&húzott Strike through Áthúzott Ctrl+T Ctrl+T Te&xt Color Szö&vegszín Text color Szövegszín Alt+Shift+T Alt+Shift+T Back&ground Color Hátté&rszín Background color Háttérszín Alt+Shift+B Alt+Shift+B Options Beállítások &New Note Ú&j jegyzet Ctrl+Alt+Shift+N Ctrl+Alt+Shift+N Save &As Me&ntés másként Ctrl+Shift+S Ctrl+Shift+S &Print N&yomtatás Ctrl+P Ctrl+P P&rint with Sub-Nodes Ny&omtatás al-elemekkel Set Pass&word Jelszó b&eállítása &Quit &Kilépés Ctrl+Q Ctrl+Q &Cut &Kivágás Ctrl+X Ctrl+X C&opy Má&solás Ctrl+C Ctrl+C &Paste &Beillesztés Ctrl+V Ctrl+V &Delete &Törlés &Select All Öss&zes kijelölése Ctrl+A Ctrl+A E&mbed Image Ké&p beágyazása Embed Image Kép beágyazása Ctrl+Alt+Shift+I Ctrl+Alt+Shift+I E&xpand All Ö&sszes kinyitása Ctrl+Shift+Down Ctrl+Shift+Le Collap&se All Öss&zes becsukása Ctrl+Shift+Up Ctrl+Shift+Fel &Append Sibling Új e&lem alá Ctrl+N Ctrl+N Append &Child Új &al-elem Ctrl+Shift+N Ctrl+Shift+N &Delete Node Elem &törlése Ctrl+D Ctrl+D Move &Up &Fel Alt+Up Alt+Fel Move Do&wn L&e Alt+Down Alt+Le Re&name Node Elem át&nevezése Ctrl+Shift+R Ctrl+Shift+R Tree Pr&operties Ele&mek száma Ctrl+Shift+D Ctrl+Shift+D Document &Font D&okumentum betűtípusa &Wrap Lines &Sortörés Ctrl+W Ctrl+W &Auto-Indentation &Automatikus behúzás Ctrl+Shift+I Ctrl+Shift+I &Preferences &Beállítások Ctrl+Shift+P Ctrl+Shift+P Find and &Replace Keresés és &csere Ctrl+R Ctrl+R Ctrl+H Ctrl+H &About &Névjegy Pr&int All Nodes Ö&sszes elem nyomtatása Superscrip&t F&első index Superscript Felső index Alt+Shift+U Alt+Shift+U Subscri&pt Alsó inde&x Subscript Alsó index Alt+Shift+S Alt+Shift+S C&enter &Középre igazítás Align center Középre igazítás Alt+Shift+Down Alt+Shift+Le &Right &Jobbra igazítás Align right Jobbra igazítás Alt+Shift+Right Alt+Shift+Bal &Left &Balra igazítás Align left Balra igazítás Alt+Shift+Left Alt+Shift+Bal &Justify &Sorkizárás Justify Sorkizárás Alt+Shift+Up Alt+Shift+Fel &Prepend Sibling Ú&j elem fölé Ctrl+M Ctrl+M Move &Left &Kintebb Alt+Left Alt+Bal Move &Right &Bentebb Alt+Right Alt+Jobb h&2 Címsor &2 Header 2 Címsor 2 Ctrl+2 Ctrl+2 h&1 Címsor &1 Header 1 Címsor 1 Ctrl+1 Ctrl+1 h&3 Címsor &3 Header 3 Címsor 3 Ctrl+3 Ctrl+3 &Node Font &Elemek betűtípusa Node Font Elemek betűtípusa Scale I&mage(s) Kép(ek) át&méretezése Paste &HTML &HTML beillesztése Ctrl+Shift+V Ctrl+Shift+V &Tags &Címkék Ctrl+Shift+T Ctrl+Shift+T Insert Lin&k L&ink beszúrása Ctrl+L Ctrl+L C&opy Link &Link másolása I&nsert Table &Táblázat beszúrása Ctrl+Alt+Shift+T Ctrl+Alt+Shift+T Append Row Új sor alá Delete Row Sor törlése Append Column Új oszlop mögé Delete Column Oszlop törlése Merge Cells Cellák egyesítése Prepend Row Új sor fölé Prepend Column Új oszlop elé Export &HTML &HTML exportálása Save Ima&ge(s) Képek m&entése RTL Jobbról balra Ctrl+Alt+Shift+Left Ctrl+Alt+Shift+Bal LTR Balról jobbra Ctrl+Alt+Shift+Right Ctrl+Alt+Shift+Jobb Menu Menü Node &Icon Elem&ikon Ctrl+Shift+C Ctrl+Shift+C Check Spelling Helyesírás-ellenőrzés F2 F2 Document &Colors &Dokumentumszínek Paste Date and Time Dátum és idő beillesztése Node Icon Elemikon &Raise/Hide &Megjelenítés/Elrejtés <center><b><big>New note?</big></b></center> <center><b><big>Új jegyzet?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>Biztosan bezárja a dokumentumot</i></center> <center><i>és létrehoz egy újat?</i></center> Yes Igen No Nem <center><b><big>Save changes?</big></b></center> <center><b><big>Menti a változtatásokat?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>A dokumentum módosítva lett.</i></center> <center><i>The document has been removed.</i></center> <center><i>A dokumentum törölve lett.</i></center> Discard changes Elvetés Cancel Mégse Open file... Fájl megnyitása... <center><b><big>Cannot be saved!</big></b></center> <center><b><big>Nem menthető!</big></b></center> Close Bezárás Save As... Mentés másként... <center><b><big>Delete this node?</big></b></center> <center><b><big>Törli ezt az elemet?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>Figyelmeztetés!</i></b></center> <center>Ezt a műveletet nem lehet visszavonni.</center> Tags Címkék OK OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Főelemek:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Összes elem:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>Jegyzet:</b> <i>%1</i><br><b>Fő elemek:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Összes elem:</b> <i>%3</i> %1 Matches %1 egyezés One Match Egy egyezés No Match Nincs egyezés Replacement Csere No Replacement Nincs csere One Replacement Egy csere %1 Replacements %1 csere Insert Link Link beszúrása Image path Kép útvonala Open image Kép megnyitása Scaling percentage Átméretezés százalékban Open Image... Kép megnyitása... &Raise &Megjelenítés New Node Új elem FeatherNotes documents (*.fnx);;All Files (*) FeatherNotes dokumentumok (*.fnx);;Minden fájl (*) Untitled Névtelen Select Text Color Szövegszín kiválasztása Select Background Color Háttérszín kiválasztása Deletion Törlés Tag(s) for this node Címkék az elemhez Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Képfájlok (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;Minden fájl (*) Select Document Font Dokumentum betűtípusának kiválasztása Select Node Font Elemek betűtípusának kiválasztása Set Document Colors Dokumentumszínek beállítása These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Ezek a színek lesznek alkalmazva az új elemekre.<br>Ezek vagy érintik, vagy nem érintik a meglévő elemeket,<br>de javasolt a dokumentum újbóli megnyitása. Background color: Háttérszín: Text color: Szövegszín: The first 1000 replacements are highlighted. Az első 1000 csere van kiemelve. Scale to Átméretezés % % Scale Image(s) Kép(ek) átméretezése untitled névtelen Error Hiba <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>A kép nem menthető! Újrapróbálja?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>Lehet hogy nem jó a fájl kiterjesztése,</center> <center>vagy nincs írási engedélye.</center><p></p> Save Image As... Kép mentése másként... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Képfájlok (*.png *.jpg *.jpeg *.bmp);;Minden fájl (*) Insert Table Táblázat beszúrása Rows: Sorok: Columns: Oszlopok: Print Document Dokumentum nyomtatása Export HTML HTML exportálása Export: Exportálás: &Current node &Legutóbbi elem With all &sub-nodes A&l-elemekkel &All nodes &Összes elem Output file: Kimeneti fájl: Select path Útvonal kiválasztása Question Kérdés The file already exists. Do you want to replace it? A fájl már létezik. Szeretné cserélni? Save HTML As... HTML mentése másként... HTML Files (*.html *.htm) HTML fájlok (*.html *.htm) Set Password Jelszó beállítása Type password Jelszó Retype password Jelszó újra <center>Passwords were different. Retry!</center> <center>A jelszavak nem egyeznek. Próbálja újra!</center> Enter Password Jelszó <center>Wrong password. Retry!</center> <center>Hibás jelszó. Próbálja újra!</center> A lightweight notes manager Egy könnyed jegyzetkezelő based on Qt amely a Qt-ön alapul Author Szerző About FeatherNotes FeatherNotes névjegye Translators Fordítók See Preferences → Text → Spell Checking! Lásd: Beállítások → Szöveg → Helyesírás-ellenőrzés! You need to add a Hunspell dictionary. Hozzá kell adnia egy Hunspell szótárat. The Hunspell dictionary does not exist. A Hunspell szótár nem létezik. The Hunspell dictionary is not accompanied by an affix file. A Hunspell szótárhoz nem kapcsolódik affix fájl. No misspelling from text cursor. Nincs elírás a szövegkurzortól. Spell Checking Helyesírás ellenőrzés aka. más néven FeatherNotes::LineEdit Clear text (Ctrl+K) Szöveg törlése (Ctrl+K) Ctrl+K Clear text Ctrl+K FeatherNotes::PrefDialog Preferences Beállítások Window Ablak Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Ablakméret megjegyzése a párbeszédpanel bezárása után. Ne jelölje be, ha fix méretet szeretne! Remember window &size Ablakméret megjegyzé&se Start with this size: Indulás ezzel a mérettel: px px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Oldalsáv szélességének mentése bezárás után. A párbeszédablak bezárása után lép érvénybe. Ha nincs bejelölve akkor az alapértelmezett arány 170/530 lesz. Remember &tree width O&ldalsáv szélességének megjegyzése Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Ablakhelyzet mentése bezáráskor. A párbeszédpanel bezárása után lép érvénybe. (Ez lehet, hogy nem működik megfelelően a GTK+ asztali környezetek alatt, mint az Unity vagy a Cinnamon.) Save &position &Ablakhelyzet mentése Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Meghatározza, hogy kell-e használni a tálcaikont. Ha be van jelölve, a címsor bezárás gombja csak lerakja az ablakot a rendszertálcára, bezárás helyett. Az érvényesítéséhez újra kell indítania a FeatherNotes-t. Add to s&ystray H&ozzáadás rendszertálcához The command line option --tray can be used instead of this. A --tray parancssori opció használható ehelyett. Start i&conified to tray Indítás tál&caikonként Merge the tree view with its surroundings? Az oldalsáv a környezete háttérszínét kapja meg? Transparent t&ree view Áttetsző ol&dalsáv By default, the active widget style determines the size of toolbar icons. Alapértelmezetten az aktuális elemstílus határozza meg az eszköztár ikonméretét. Small toolbar icons Kis eszköztárikonok Do not show t&oolbar Esz&köztár elrejtése If the menubar is hidden, a menu button appears on the toolbar. Ha a menüsor rejtett, a menü gomb megjelenik az eszköztáron. Do not show &menubar &Menüsor elrejtése Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Jelölje be Enlightenment (vagy esetleg másik asztali környezet) alatt, hogy a tálcaikon helyesen működjön! Running &under Enlightenment? Enlightenment alatt &használja? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Néhány asztali környezet (mint az Enlightenment) nem jelenti helyesen az ablakok helyzetét. Ebben az esetben megpróbálhatja kijavítani a problémát. Ha a panel a képernyő tetején vagy az alján helyezkedik el, az Y-koordinátát kell beállítani; Ha pedig jobb-, vagy baloldalt, akkor az X-et. Miután beállította az eltolást, húzza az ablakot a megfelelő helyzetbe, majd indítsa újra a FeatherNotes-t! Shifts (X × Y): Eltolás (X × Y): Text Szöveg &Wrap lines by default &Sortörés alapértelmezetten Auto-&indent by default Automat&ikus behúzás alapértelmezetten This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Ez bezárja a zárójeleket, és az idézőjeleket. Az érvényesítéséhez újra kell indítania a FeatherNotes-t. Auto-&bracket A&utomatikus zárójelkiegészítés A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. Gépeléskor, megfelelő körülmények között a három pont le lesz cserélve hármasponttal, a kettő kötőjel hosszú kötőjellel, stb. &Replace some characters while typing &Néhány karakter cseréje gépelés közben Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. A dátum és idő beillesztésére használatos. Hagyja üresen az alapértelmezetthez. A párbeszédpanel bezárása után lép érvénybe. Date and time format: Dátum és idő fermátuma: &Auto-save every &Automatikus mentés minden minute(s) percben Spell Checking Helyesírás-ellenőrzés A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". A Hunspell szótárfájlnak ".dic"-re kell végződnie és kell mellette lennie egy affix fájlnak aminek ugyanaz a neve csak ".aff"-ra végződik. Hunspell dictionary path: Hunspell szótár útvonala: Add dictionary... Szótár hozzáadása... Files Fájlok Start with the last opened file Indulás az utolsó megnyitott fájllal Shortcuts Gyorsbillentyűk Action Művelet Shortcut Kombináció Default Alapértelmezett Warning: Ambiguous shortcut detected! Figyelmeztetés: Többször használt gyorsbillentyű észlelve! The typed shortcut was reserved. A beírt gyorsbillentyű foglalt. Application restart is needed for changes to take effect. Az érvényesítéséhez újra kell indítania az alkalmazást. Hunspell Dictionary Files (*.dic) Hunspell szótárfájlok (*.dic) FeatherNotes::SpellDialog Unknown word: Ismeretlen szó: Add To Dictionary Hozzáadás szótárhoz Replace with: Csere erre: Ignore Once Mellőzés egyszer Ignore All Összes mellőzése Correct Once Javítás egyszer Correct All Összes javítása FeatherNotes::helpDialog Help Súgó QObject New Node Új elem FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_id.ts000066400000000000000000002054611374721712500257630ustar00rootroot00000000000000 FeatherNotes::AboutDialog License Lisensi FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes Next (F3) Berikutnya (F3) F3 Previous (F4) Sebelumnya (F4) F4 Search... Cari... Search only in names (Ctrl+Shift+F7) Cari berdasarkan nama (Ctrl + Shift + F7) Ctrl+Shift+F7 Search only in tags (Shift+F7) Cari bedasarkan tags (Shift+F7) Shift+F7 Search in all nodes (F7) Cari di semua node (F7) F7 Whole Word (F6) Seluruh Kata (F6) Whole Word Seluruh Kata F6 Match Case (F5) Peka huruf (F5) Match Case Peka huruf F5 &File &Edit Sunting For&mat &Tree &Options &Opsi &Search Cari &Help Bantuan Find: Cari: Replace with: Ganti dengan: To be replaced Untuk diganti Replacing text Mengganti teks Previous (F9) Sebelumnya (F9) F9 Next (F8) Selanjutnya (F8) F8 Replace all (F10) Ganti semua (F10) F10 &Save &Simpan Save Simpan Ctrl+S &Open Buka Open a file Buka sebuah berkas Ctrl+O &Undo Tak jadi Undo Tak jadi Ctrl+Z &Redo Jadi lagi Redo Jadi lagi Ctrl+Shift+Z &Find Cari Show/hide searchbar Tampilkan/sembunyikan kotak pencarian Ctrl+F &Clear All Formats Bersihkan semua format Clear all formats Bersihkan semua format Ctrl+E &Bold Tebal Bold Tebal Ctrl+B &Italic Miring Italic Miring Ctrl+I &Underline Garis Bawah Underline Garis Bawah Ctrl+U &Strike Through Coret Strike through Coret Ctrl+T Te&xt Color Warna teks Text color Warna teks Alt+Shift+T Back&ground Color Warna latar belakang Background color Warna latar belakang Alt+Shift+B Options Opsi &New Note Catatan Baru Ctrl+Alt+Shift+N Save &As Simpan Seb&agai Ctrl+Shift+S &Print Cetak Ctrl+P P&rint with Sub-Nodes P&rint dengan Sub-Nodes Set Pass&word &Quit Keluar Ctrl+Q &Cut Potong Ctrl+X C&opy Salin Ctrl+C &Paste Tem&pel Ctrl+V &Delete Hapus &Select All Pilih &Semua Ctrl+A E&mbed Image E&mbed Gambar Embed Image Embed Gambar Ctrl+Alt+Shift+I E&xpand All Memperluas Semua Ctrl+Shift+Down Collap&se All Tutup Semua Ctrl+Shift+Up &Append Sibling Tambahkan Sibling Ctrl+N Append &Child Tambahkan &Child Ctrl+Shift+N &Delete Node Hapus Node Ctrl+D Move &Up Pindahkan Ke Atas Alt+Up Move Do&wn Pindahkan Ke Bawah Alt+Down Re&name Node Hapus Node Ctrl+Shift+R Tree Pr&operties Properti Tree Ctrl+Shift+D Document &Font Dokumen & Font &Wrap Lines Ctrl+W &Auto-Indentation Indentasi otomatis Ctrl+Shift+I &Preferences &Pengaturan Ctrl+Shift+P Find and &Replace Temukan dan ganti Ctrl+R Ctrl+H &About Tentang Pr&int All Nodes Pr&int Semua Node Superscrip&t Superscript Alt+Shift+U Subscri&pt Subscript Alt+Shift+S C&enter Align center Alt+Shift+Down &Right Align right Alt+Shift+Right &Left Align left Alt+Shift+Left &Justify Justify Alt+Shift+Up &Prepend Sibling Ctrl+M Move &Left Alt+Left Move &Right Alt+Right h&2 Header 2 Ctrl+2 h&1 Header 1 Ctrl+1 h&3 Header 3 Ctrl+3 &Node Font Node Font Scale I&mage(s) Paste &HTML Tempel &HTML Ctrl+Shift+V &Tags Ctrl+Shift+T Insert Lin&k Masukan Lin&k Ctrl+L C&opy Link Salin Link I&nsert Table Masukan Table Ctrl+Alt+Shift+T Append Row Tambah Baris Delete Row Hapus Baris Append Column Tambahkan Kolom Delete Column Hapus Kolom Merge Cells Gabungkan Sel Prepend Row Tambah Baris Sebelumnya Prepend Column Tambah Kolom Sebelumnya Export &HTML Ekspor &HTML Save Ima&ge(s) Simpan &Gambar RTL Ctrl+Alt+Shift+Left LTR Ctrl+Alt+Shift+Right Menu Node &Icon Ctrl+Shift+C Check Spelling F2 Document &Colors Paste Date and Time Node Icon &Raise/Hide <center><b><big>New note?</big></b></center> <center><b><big>Catatan baru?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>Apakah Anda benar-benar ingin meninggalkan dokumen ini</i></center> <center><i>dan membuat yang kosong?</i></center> Yes Ya No Tidak <center><b><big>Save changes?</big></b></center> <center><b><big>Simpan perubahan?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>Dokumen ini telah dimodifikasi.</i></center> <center><i>The document has been removed.</i></center> <center><i>Dokumen ini telah dihapus.</i></center> Discard changes Abaikan perubahan Cancel Batal Open file... Buka berkas... <center><b><big>Cannot be saved!</big></b></center> <center><b><big>Tidak dapat di simpan!</big></b></center> Close Tutup Save As... Simpan Sebagai... <center><b><big>Delete this node?</big></b></center> <center><b><big>Hapus node ini?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>Peringatan!</i></b></center> <center>Tindakan ini tidak bisa dibatalkan.</center> Tags OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Node utama:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Semua node:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>Catatan:</b> <i>%1</i><br><b>Node utama:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Semua node:</b> <i>%3</i> %1 Matches %1 Cocok One Match Satu Cocok No Match Tak ada yang cocok Replacement Pengganti No Replacement Tidak ada pengganti One Replacement Satu penggantian %1 Replacements %1 Penggantian Insert Link Masukan Link Image path Tempat gambar Open image Buka gambar Scaling percentage Persentase penskalaan Open Image... Buka Gambar... &Raise Naikan New Node Node Baru FeatherNotes documents (*.fnx);;All Files (*) Dokumen FeatherNotes (* .fnx);;Semua Berkas (*) Untitled Tanpa Judul Select Text Color Select Background Color Deletion Penghapusan Tag(s) for this node Tag untuk node ini Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) File Gambar (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;Semua File (*) Select Document Font Select Node Font Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to Skala ke % Scale Image(s) Skala Gambar untitled tanpa judul Error <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>Gambar tidak dapat disimpan! Coba lagi?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>Mungkin anda tidak memiliki ekstensi yang tepat</center> <center>atau tidak memiliki izin menulis.</center><p></p> Save Image As... Simpan Gambar Sebagai... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Berkas Gambar (*.png *.jpg *.jpeg *.bmp);;Semua Berkas (*) Insert Table Masukan Table Rows: Baris: Columns: Kolom: Print Document Export HTML Export: &Current node With all &sub-nodes &All nodes Output file: Select path Question The file already exists. Do you want to replace it? Save HTML As... HTML Files (*.html *.htm) Set Password Type password Retype password <center>Passwords were different. Retry!</center> Enter Password <center>Wrong password. Retry!</center> A lightweight notes manager based on Qt Author About FeatherNotes Translators See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. FeatherNotes::LineEdit Clear text (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences Pengaturan Window Jendela Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Simpan ukuran jendela setelah menutup dialog ini dan saat keluar aplikasi. Hapus centang untuk mengatur ukuran tetap! Remember window &size Simpan ukuran jendela Start with this size: Mulai dengan ukuran ini: px px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Simpan lebar tree setelah menutup dialog ini dan saat keluar aplikasi. Hapus centang untuk mengatur rasio lebar ke 170/530. Remember &tree width Ingat lebar &tree Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Menyimpan posisi setelah menutup dialog ini dan juga saat keluar. (Ini mungkin tidak berfungsi secara benar dengan GTK + DE seperti Unity dan Cinnamon.) Save &position Simpan &posisi Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Memutuskan apakah ikon systray harus digunakan. Jika dicentang, tombol tutup batang judul melambangkan jendela ke systray alih-alih berhenti. Perlu memulai ulang FeatherNotes agar dapat berfungsi. Add to s&ystray Tambahkan ke s&ystray The command line option --tray can be used instead of this. Opsi baris perintah --tray dapat digunakan sebagai ganti dari ini. Start i&conified to tray Merge the tree view with its surroundings? Transparent t&ree view By default, the active widget style determines the size of toolbar icons. Small toolbar icons Do not show t&oolbar If the menubar is hidden, a menu button appears on the toolbar. Do not show &menubar Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Running &under Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Shifts (X × Y): Text &Wrap lines by default Auto-&indent by default This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Auto-&bracket A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. &Replace some characters while typing Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every minute(s) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Action Shortcut Default Warning: Ambiguous shortcut detected! The typed shortcut was reserved. Application restart is needed for changes to take effect. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Ganti dengan: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help QObject New Node FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_it.ts000066400000000000000000002071541374721712500260040ustar00rootroot00000000000000 FeatherNotes::AboutDialog License LIcenza FeatherNotes::ColorLabel Click to change color. Clicca per cambiare colore. Select Color Seleziona colore FeatherNotes::FN FeatherNotes FeatherNotes Next (F3) Avanti (F3) F3 F3 Previous (F4) Indietro (F4) F4 F4 Search... Cerca... Search only in names (Ctrl+Shift+F7) Ctrl+Shift+F7 Search only in tags (Shift+F7) Shift+F7 Search in all nodes (F7) F7 F7 Whole Word (F6) Whole Word F6 F6 Match Case (F5) Match Case F5 F5 &File &Edit For&mat &Tree &Options &Search &Help Find: Replace with: To be replaced Replacing text Previous (F9) Indietro (F4) {9)?} F9 F9 Next (F8) Avanti (F3) {8)?} F8 F8 Replace all (F10) F10 F10 &Save Save Ctrl+S &Open Open a file Ctrl+O &Undo Undo Ctrl+Z &Redo Redo Ctrl+Shift+Z &Find Show/hide searchbar Ctrl+F &Clear All Formats Clear all formats Ctrl+E &Bold Bold Ctrl+B &Italic Italic Ctrl+I &Underline Underline Ctrl+U &Strike Through Strike through Ctrl+T Te&xt Color Text color Alt+Shift+T Back&ground Color Background color Alt+Shift+B Options &New Note Ctrl+Alt+Shift+N Save &As Ctrl+Shift+S &Print Ctrl+P P&rint with Sub-Nodes Set Pass&word &Quit Ctrl+Q &Cut Ctrl+X C&opy Ctrl+C &Paste Ctrl+V &Delete &Select All Ctrl+A E&mbed Image Embed Image Ctrl+Alt+Shift+I E&xpand All Ctrl+Shift+Down Collap&se All Ctrl+Shift+Up &Append Sibling Ctrl+N Append &Child Ctrl+Shift+N &Delete Node Ctrl+D Move &Up Alt+Up Move Do&wn Alt+Down Re&name Node Ctrl+Shift+R Tree Pr&operties Ctrl+Shift+D Document &Font &Wrap Lines Ctrl+W &Auto-Indentation Ctrl+Shift+I &Preferences Ctrl+Shift+P Find and &Replace Ctrl+R Ctrl+H &About Pr&int All Nodes Superscrip&t Superscript Alt+Shift+U Subscri&pt Subscript Alt+Shift+S C&enter Align center Alt+Shift+Down &Right Align right Alt+Shift+Right &Left Align left Alt+Shift+Left &Justify Justify Alt+Shift+Up &Prepend Sibling Ctrl+M Move &Left Alt+Left Move &Right Alt+Right h&2 Header 2 Ctrl+2 h&1 Header 1 Ctrl+1 h&3 Header 3 Ctrl+3 &Node Font Node Font Scale I&mage(s) Paste &HTML Ctrl+Shift+V &Tags Ctrl+Shift+T Insert Lin&k Ctrl+L C&opy Link I&nsert Table Ctrl+Alt+Shift+T Append Row Delete Row Append Column Delete Column Merge Cells Prepend Row Prepend Column Export &HTML Save Ima&ge(s) RTL Ctrl+Alt+Shift+Left LTR Ctrl+Alt+Shift+Right Menu Node &Icon Ctrl+Shift+C Check Spelling F2 F2 Document &Colors Paste Date and Time Node Icon &Raise/Hide <center><b><big>New note?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> Yes No <center><b><big>Save changes?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>The document has been removed.</i></center> Discard changes Cancel Open file... <center><b><big>Cannot be saved!</big></b></center> Close Save As... <center><b><big>Delete this node?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> Tags OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> %1 Matches One Match No Match Replacement No Replacement One Replacement %1 Replacements Insert Link Image path Open image Scaling percentage Open Image... &Raise New Node FeatherNotes documents (*.fnx);;All Files (*) Untitled Select Text Color Select Background Color Deletion Tag(s) for this node Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Select Document Font Select Node Font Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to % Scale Image(s) untitled Error <center><b><big>Image cannot be saved! Retry?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> Save Image As... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Insert Table Rows: Columns: Print Document Export HTML Export: &Current node With all &sub-nodes &All nodes Output file: Select path Question The file already exists. Do you want to replace it? Save HTML As... HTML Files (*.html *.htm) Set Password Type password Retype password <center>Passwords were different. Retry!</center> Enter Password <center>Wrong password. Retry!</center> A lightweight notes manager based on Qt Author About FeatherNotes Translators See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. FeatherNotes::LineEdit Clear text (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences Window Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Remember window &size Start with this size: px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Remember &tree width Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Save &position Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Add to s&ystray The command line option --tray can be used instead of this. Start i&conified to tray Merge the tree view with its surroundings? Transparent t&ree view By default, the active widget style determines the size of toolbar icons. Small toolbar icons Do not show t&oolbar If the menubar is hidden, a menu button appears on the toolbar. Do not show &menubar Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Running &under Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Shifts (X × Y): Text &Wrap lines by default Auto-&indent by default This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Auto-&bracket A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. &Replace some characters while typing Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every minute(s) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Action Shortcut Default Warning: Ambiguous shortcut detected! The typed shortcut was reserved. Application restart is needed for changes to take effect. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help QObject New Node FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_ja.ts000066400000000000000000002132411374721712500257540ustar00rootroot00000000000000 FeatherNotes::AboutDialog License ライセンス FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes Next (F3) 次へ (F3) F3 Previous (F4) 前へ (F4) F4 Search... 検索... Search only in names (Ctrl+Shift+F7) ノード名のみで検索 (Ctrl+Shift+F7) Ctrl+Shift+F7 Search only in tags (Shift+F7) タグのみで検索 (Shift+F7) Shift+F7 Search in all nodes (F7) すべてのノードで検索 (F7) F7 Whole Word (F6) 完全に一致する単語のみ (F6) Whole Word 完全に一致する単語のみ F6 Match Case (F5) 大文字と小文字の区別 (F5) Match Case 大文字と小文字の区別 F5 &File ファイル(&F) &Edit 編集(&E) For&mat 書式(&M) &Tree ツリー(&T) &Options オプション(&O) &Search 検索(&S) &Help ヘルプ(&H) Find: 検索: Replace with: 置換: To be replaced 置換される文字 Replacing text 置換する文字 Previous (F9) 前へ (F9) F9 Next (F8) 次へ (F8) F8 Replace all (F10) すべて置換 (F10) F10 &Save 保存(&S) Save 保存 Ctrl+S &Open 開く(&O) Open a file ファイルを開く Ctrl+O &Undo 元に戻す(&U) Undo 元に戻す Ctrl+Z &Redo やり直す(&R) Redo やり直し Ctrl+Shift+Z &Find 検索(&F) Show/hide searchbar 検索バーの表示/非表示 Ctrl+F &Clear All Formats すべての書式をクリア(&C) Clear all formats すべての書式をクリアします Ctrl+E &Bold 太字(&B) Bold 太字 Ctrl+B &Italic 斜体(&I) Italic 斜体 Ctrl+I &Underline 下線(&U) Underline 下線 Ctrl+U &Strike Through 取り消し線(&S) Strike through 取り消し線 Ctrl+T Te&xt Color 文字の色(&X) Text color 文字の色 Alt+Shift+T Back&ground Color 背景色(&G) Background color 背景色 Alt+Shift+B Options オプション &New Note 新しいノート(&N) Ctrl+Alt+Shift+N Save &As 名前を付けて保存(&A) Ctrl+Shift+S &Print 印刷(&P) Ctrl+P P&rint with Sub-Nodes サブノードの印刷(&R) Set Pass&word パスワードの設定(&W) &Quit 終了(&Q) Ctrl+Q &Cut 切り取り(&C) Ctrl+X C&opy コピー(&O) Ctrl+C &Paste 貼り付け(&P) Ctrl+V &Delete 削除(&D) &Select All すべて選択(&S) Ctrl+A E&mbed Image 画像の埋め込み(&M) Embed Image 画像の埋め込み Ctrl+Alt+Shift+I E&xpand All すべて展開 Ctrl+Shift+Down Collap&se All すべて折りたたむ(&S) Ctrl+Shift+Up &Append Sibling 下にノードを追加(&A) Ctrl+N Append &Child 子ノードを追加(&C) Ctrl+Shift+N &Delete Node ノードの削除(&D) Ctrl+D Move &Up 上へ移動(&U) Alt+Up Move Do&wn 下へ移動(&W) Alt+Down Re&name Node ノード名の変更 Ctrl+Shift+R Tree Pr&operties ツリーのプロパティ(&O) Ctrl+Shift+D Document &Font &Wrap Lines 行を折り返す(&W) Ctrl+W &Auto-Indentation 自動インデント(&A) Ctrl+Shift+I &Preferences 設定(&P) Ctrl+Shift+P Find and &Replace 検索と置換(&R) Ctrl+R Ctrl+H &About このアプリケーションについて(&A) Pr&int All Nodes すべてのノードを印刷(&I) Superscrip&t 上付き文字(&T) Superscript 上付き文字 Alt+Shift+U Subscri&pt 下付き文字(&P) Subscript 下付き文字 Alt+Shift+S C&enter Align center 中央揃え Alt+Shift+Down &Right Align right 右揃え Alt+Shift+Right &Left 左揃え(&L) Align left 左揃え Alt+Shift+Left Alt+Shift+← &Justify 両端揃え(&J) Justify 両端揃え Alt+Shift+Up &Prepend Sibling 上にノードを追加(&P) Ctrl+M Move &Left 左へ移動(&L) Alt+Left Alt+← Move &Right 右へ移動(&R) Alt+Right h&2 Header 2 ヘッダー 2 Ctrl+2 h&1 Header 1 ヘッダー 1 Ctrl+1 h&3 Header 3 ヘッダー 3 Ctrl+3 &Node Font ノードのフォント(&N) Node Font ノードのフォント Scale I&mage(s) 画像の拡大縮小(&M) Paste &HTML HTML で貼り付け(&H) Ctrl+Shift+V &Tags タグ(&T) Ctrl+Shift+T Insert Lin&k リンクの挿入(&K) Ctrl+L C&opy Link リンクのコピー(&O) I&nsert Table 表の挿入(&N) Ctrl+Alt+Shift+T Append Row 下に行を追加 Delete Row 行の削除 Append Column 右に列を追加 Delete Column 列の削除 Merge Cells セルの結合 Prepend Row 上に行を追加 Prepend Column 左に列を追加 Export &HTML Save Ima&ge(s) 画像の保存(&G) RTL Ctrl+Alt+Shift+Left Ctrl+Alt+Shift+← LTR Ctrl+Alt+Shift+Right Menu Node &Icon ノードのアイコン(&I) Ctrl+Shift+C Check Spelling F2 Document &Colors Paste Date and Time Node Icon ノードのアイコン &Raise/Hide 表示/隠す(&R) <center><b><big>New note?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>このドキュメントを本当に破棄して、</i></center> <center><i>空のものを作成しますか?</i></center> Yes はい No <center><b><big>Save changes?</big></b></center> <center><b><big>変更内容を保存しますか?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>ドキュメントが変更されました。</i></center> <center><i>The document has been removed.</i></center> <center><i>ドキュメントは削除されました。</i></center> Discard changes 変更の破棄 Cancel キャンセル Open file... <center><b><big>Cannot be saved!</big></b></center> <center><b><big>保存できませんでした!</big></b></center> Close 閉じる Save As... 名前を付けて保存... <center><b><big>Delete this node?</big></b></center> <center><b><big>このノードを削除しますか?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>警告!</i></b></center> <center>この操作は元に戻せません。</center> Tags タグ OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>メインノード:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>すべてのノード:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>ノート:</b> <i>%1</i><br><b>メインノード:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>すべてのノード:</b> <i>%3</i> %1 Matches %1 個が一致 One Match 1 個が一致 No Match 一致せず Replacement 置換します No Replacement 置換されません One Replacement 置換 1 個 %1 Replacements 置換 %1 個 Insert Link Image path 画像の場所 Open image Scaling percentage 拡大率 Open Image... &Raise 表示(&R) New Node FeatherNotes documents (*.fnx);;All Files (*) FeatherNotes 文書 (*.fnx);;すべてのファイル (*) Untitled 無題 Select Text Color Select Background Color Deletion 削除 Tag(s) for this node ノードのタグ Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) 画像ファイル (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;すべてのファイル (*) Select Document Font Select Node Font Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to 拡大率 % Scale Image(s) 画像の拡大縮小 untitled 無題 Error <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>画像を保存できません! 再試行しますか?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>たぶん適切な拡張子を選択していないか、</center> <center>書き込み権限がありません。</center><p></p> Save Image As... 名前を付けて画像を保存... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) 画像ファイル (*.png *.jpg *.jpeg *.bmp);;すべてのファイル (*) Insert Table Rows: 行: Columns: 列: Print Document 文書の印刷 Export HTML Export: &Current node 現在のノード(&C) With all &sub-nodes 現在のノードとすべてのサブノード(&S) &All nodes すべてのノード(&A) Output file: 出力ファイル: Select path パスの選択 Question The file already exists. Do you want to replace it? Save HTML As... HTMLで名前を付けて保存... HTML Files (*.html *.htm) HTML ファイル (*.html *.htm) Set Password Type password Retype password パスワードの再入力 <center>Passwords were different. Retry!</center> <center>パスワードが違います。再入力して下さい!</center> Enter Password <center>Wrong password. Retry!</center> <center>間違ったパスワードです。再入力して下さい!</center> A lightweight notes manager A lightweight notes manager based on Qt Qt ベース Author About FeatherNotes FeatherNotes について Translators 翻訳者 See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. FeatherNotes::LineEdit Clear text (Ctrl+K) テキストの消去 (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences 設定 Window ウィンドウ Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! このダイアログを閉じて終了した後に ウィンドウのサイズを保存します。 サイズを固定するにはチェックを外して下さい! Remember window &size ウィンドウサイズを記憶する(&S) Start with this size: 起動時のサイズ: px ピクセル Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Remember &tree width Remember &tree width Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Save &position Save &position Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Add to s&ystray Add to s&ystray The command line option --tray can be used instead of this. The command line option --tray can be used instead of this. Start i&conified to tray 起動時にトレイに入れる(&C) Merge the tree view with its surroundings? Merge the tree view with its surroundings? Transparent t&ree view Transparent t&ree view By default, the active widget style determines the size of toolbar icons. By default, the active widget style determines the size of toolbar icons. Small toolbar icons ツールバーのアイコンを小さくする Do not show t&oolbar ツールバーを表示しない(&T) If the menubar is hidden, a menu button appears on the toolbar. メニューバーを表示しない場合は、 ツールバーにメニューボタンが表示されます。 Do not show &menubar Do not show &menubar Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Running &under Enlightenment? Enlightenment 環境で実行していますか? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Shifts (X × Y): Shifts (X × Y): Text テキスト &Wrap lines by default &Wrap lines by default Auto-&indent by default Auto-&indent by default This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Auto-&bracket Auto-&bracket A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. &Replace some characters while typing Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every &Auto-save every minute(s) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Shortcuts Action Shortcut Shortcut Default Warning: Ambiguous shortcut detected! Warning: Ambiguous shortcut detected! The typed shortcut was reserved. The typed shortcut was reserved. Application restart is needed for changes to take effect. Application restart is needed for changes to take effect. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: 置換: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help QObject New Node FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_lt.ts000066400000000000000000002155061374721712500260070ustar00rootroot00000000000000 FeatherNotes::AboutDialog License Licencija FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes Next (F3) Kitas (F3) F3 Previous (F4) Ankstesnis (F4) F4 Search... Ieškoti... Search only in names (Ctrl+Shift+F7) Ieškoti tik pavadinimuose (Ctrl(Vald)+Shift(Lyg2)+F7) Ctrl+Shift+F7 Ctrl(Vald)+Shift(Lyg2)+F7 Search only in tags (Shift+F7) Ieškoti tik žymėse (Shift(Lyg2)+F7) Shift+F7 Shift(Lyg2)+F7 Search in all nodes (F7) Ieškoti visuose mazguose (F7) F7 Whole Word (F6) Visas žodis (F6) Whole Word Visas žodis F6 Match Case (F5) Skirti raidžių dydį (F5) Match Case Skirti raidžių dydį F5 &File &Failas &Edit &Taisa For&mat For&matavimas &Tree &Medis &Options &Parinktys &Search Paieš&ka &Help Ž&inynas Find: Rasti: Replace with: Kuo pakeisti: To be replaced Bus pakeista Replacing text Tekstas, kuriuo keičiama Previous (F9) Ankstesnis (F9) F9 Next (F8) Kitas (F8) F8 Replace all (F10) Pakeisti visus (F10) F10 &Save Į&rašyti Save Įrašyti Ctrl+S Ctrl(Vald)+S &Open A&tverti Open a file Atverti failą Ctrl+O Ctrl(Vald)+O &Undo A&tšaukti Undo Atšaukti Ctrl+Z Ctrl(Vald)+Z &Redo &Grąžinti Redo Grąžinti Ctrl+Shift+Z Ctrl(Vald)+Shift(Lyg2)+Z &Find &Rasti Show/hide searchbar Rodyti/slėpti paieškos juostą Ctrl+F Ctrl(Vald)+F &Clear All Formats &Išvalyti visą formatavimą Clear all formats Išvalyti visą formatavimą Ctrl+E Ctrl(Vald)+E &Bold &Pusjuodis Bold Pusjuodis Ctrl+B Ctrl(Vald)+B &Italic &Kursyvas Italic Kursyvas Ctrl+I Ctrl(Vald)+I &Underline Pa&brauktas Underline Pabrauktas Ctrl+U Ctrl(Vald)+U &Strike Through Pe&rbrauktas Strike through Perbrauktas Ctrl+T Ctrl(Vald)+T Te&xt Color Te&ksto spalva Text color Teksto spalva Alt+Shift+T Alt+Shift(Lyg2)+T Back&ground Color &Fono spalva Background color Fono spalva Alt+Shift+B Alt+Shift(Lyg2)+B Options Parinktys &New Note &Nauji užrašai Ctrl+Alt+Shift+N Ctrl(Vald)+Alt+Shift(Lyg2)+N Save &As Įrašyti k&aip Ctrl+Shift+S Ctrl(Vald)+Shift(Lyg2)+S &Print S&pausdinti Ctrl+P Ctrl(Vald)+P P&rint with Sub-Nodes Spaus&dinti su pomazgiais Set Pass&word Nustatyti s&laptažodį &Quit &Išeiti Ctrl+Q Ctrl(Vald)+Q &Cut Iš&kirpti Ctrl+X Ctrl(Vald)+X C&opy K&opijuoti Ctrl+C Ctrl(Vald)+C &Paste Į&dėti Ctrl+V Ctrl(Vald)+V &Delete Iš&trinti &Select All Ž&ymėti viską Ctrl+A Ctrl(Vald)+A E&mbed Image Įtaisyti pa&veikslą Embed Image Įtaisyti paveikslą Ctrl+Alt+Shift+I Ctrl(Vald)+Alt+Shift(Lyg2)+I E&xpand All Viską išsk&leisti Ctrl+Shift+Down Ctrl(Vald)+Shift(Lyg2)+Žemyn Collap&se All Viską s&uskleisti Ctrl+Shift+Up Ctrl(Vald)+Shift(Lyg2)+Aukštyn &Append Sibling Pridėti &giminingą žemiau Ctrl+N Ctrl(Vald)+N Append &Child Pridėti pa&valdųjį Ctrl+Shift+N Ctrl(Vald)+Shift(Lyg2)+N &Delete Node &Ištrinti mazgą Ctrl+D Ctrl(Vald)+D Move &Up Pa&kelti Alt+Up Alt+Aukštyn Move Do&wn N&uleisti Alt+Down Alt+Žemyn Re&name Node Pervadi&nti mazgą Ctrl+Shift+R Ctrl(Vald)+Shift(Lyg2)+R Tree Pr&operties Medžio sa&vybės Ctrl+Shift+D Ctrl(Vald)+Shift(Lyg2)+D Document &Font Dokumento šri&ftas &Wrap Lines Skai&dyti eilutes Ctrl+W Ctrl(Vald)+W &Auto-Indentation &Automatinė įtrauka Ctrl+Shift+I Ctrl(Vald)+Shift(Lyg2)+I &Preferences &Nuostatos Ctrl+Shift+P Ctrl(Vald)+Shift(Lyg2)+P Find and &Replace Rasti ir pa&keisti Ctrl+R Ctrl(Vald)+R Ctrl+H Ctrl(Vald)+H &About &Apie Pr&int All Nodes Spausd&inti visus mazgus Superscrip&t Viršu&tinis indeksas Superscript Viršutinis indeksas Alt+Shift+U Alt+Shift(Lyg2)+U Subscri&pt A&patinis indeksas Subscript Apatinis indeksas Alt+Shift+S Alt+Shift(Lyg2)+S C&enter C&entre Align center Lygiuoti centre Alt+Shift+Down Alt+Shift(Lyg2)+Žemyn &Right &Dešinėje Align right Lygiuoti dešinėje Alt+Shift+Right Alt+Shift(Lyg2)+Dešinėn &Left &Kairėje Align left Lygiuoti kairėje Alt+Shift+Left Alt+Shift(Lyg2)+Kairėn &Justify &Abipusė lygiuotė Justify Abipusė lygiuotė Alt+Shift+Up Alt+Shift(Lyg2)+Aukštyn &Prepend Sibling &Pridėti giminingą aukščiau Ctrl+M Ctrl(Vald)+M Move &Left Perkelti ka&irėn Alt+Left Alt+Kairėn Move &Right Perkelti d&ešinėn Alt+Right Alt+Dešinėn h&2 Header 2 Antraštė 2 Ctrl+2 Ctrl(Vald)+2 h&1 Header 1 Antraštė 1 Ctrl+1 Ctrl(Vald)+1 h&3 Header 3 Antraštė 3 Ctrl+3 Ctrl(Vald)+3 &Node Font &Mazgo šriftas Node Font Mazgo šriftas Scale I&mage(s) Keisti pa&veikslo(-ų) mastelį Paste &HTML Įdėti &HTML Ctrl+Shift+V Ctrl(Vald)+Shift(Lyg2)+V &Tags Ž&ymės Ctrl+Shift+T Ctrl(Vald)+Shift(Lyg2)+T Insert Lin&k Įterpti nuoro&dą Ctrl+L Ctrl(Vald)+L C&opy Link K&opijuoti nuorodą I&nsert Table Į&terpti lentelę Ctrl+Alt+Shift+T Ctrl(Vald)+Alt+Shift(Lyg2)+T Append Row Pridėti eilutę apačioje Delete Row Ištrinti eilutę Append Column Pridėti stulpelį dešinėje Delete Column Ištrinti stulpelį Merge Cells Sulieti langelius Prepend Row Pridėti eilutę aukščiau Prepend Column Pridėti stulpelį kairėje Export &HTML Eksportuoti &HTML Save Ima&ge(s) Įrašyti paveiks&lą(-us) RTL Iš dešinės į kairę Ctrl+Alt+Shift+Left Ctrl(Vald)+Alt+Shift(Lyg2)+Kairėn LTR Iš kairės į dešinę Ctrl+Alt+Shift+Right Ctrl(Vald)+Alt+Shift(Lyg2)+Dešinėn Menu Meniu Node &Icon Mazgo p&iktograma Ctrl+Shift+C Ctrl(Vald)+Shift(Lyg2)+C Check Spelling F2 Document &Colors Paste Date and Time Node Icon Mazgo piktograma &Raise/Hide &Iškelti/Slėpti <center><b><big>New note?</big></b></center> <center><b><big>Nauji užrašai?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>Ar tikrai norite užverti šį dokumentą</i></center> <center><i>ir sukurti tuščią?</i></center> Yes Taip No Ne <center><b><big>Save changes?</big></b></center> <center><b><big>Įrašyti pakeitimus?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>Dokumentas buvo modifikuotas.</i></center> <center><i>The document has been removed.</i></center> <center><i>Dokumentas pašalintas.</i></center> Discard changes Atmesti pakeitimus Cancel Atsisakyti Open file... Atverti failą... <center><b><big>Cannot be saved!</big></b></center> <center><b><big>Nepavyksta įrašyti!</big></b></center> Close Užverti Save As... Įrašyti kaip... <center><b><big>Delete this node?</big></b></center> <center><b><big>Ištrinti šį mazgą?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>Įspėjimas!</i></b></center> <center>Šio veiksmo neįmanoma bus atšaukti.</center> Tags Žymės OK Gerai <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Pagrindinių mazgų:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Viso mazgų:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>Užrašai:</b> <i>%1</i><br><b>Pagrindinių mazgų:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Viso mazgų:</b> <i>%3</i> %1 Matches %1 atitikmenys(-ų) One Match Vienas atitikmuo No Match Atitikmenų nėra Replacement Pakeitimas No Replacement Jokių pakeitimų One Replacement Vienas pakeitimas %1 Replacements %1 pakeitimų(-ai) Insert Link Įterpti nuorodą Image path Paveikslo kelias Open image Atverti paveikslą Scaling percentage Mastelio keitimo procentinė dalis Open Image... Atverti paveikslą... &Raise &Iškelti New Node Naujas mazgas FeatherNotes documents (*.fnx);;All Files (*) FeatherNotes dokumentai (*.fnx);;Visi failai (*) Untitled Be pavadinimo Select Text Color Pasirinkti teksto spalvą Select Background Color Pasirinkti fono spalvą Deletion Ištrynimas Tag(s) for this node Šio mazgo žymė(-s) Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Paveikslo failai (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;Visi failai (*) Select Document Font Pasirinkti dokumento šriftą Select Node Font Pasirinkti mazgo šriftą Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to Keisti mastelį į % Scale Image(s) Keisti paveikslo(-ų) mastelį untitled be pavadinimo Error Klaida <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>Nepavyksta įrašyti paveikslo! Bandyti dar kartą?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>Galbūt, nepasirinkote tinkamo prievardžio</center> <center>arba neturite leidimų rašyti.</center><p></p> Save Image As... Įrašyti paveikslą kaip... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Paveikslo failai (*.png *.jpg *.jpeg *.bmp);;Visi failai (*) Insert Table Įterpti lentelę Rows: Eilučių: Columns: Stulpelių: Print Document Spausdinti dokumentą Export HTML Eksportuoti HTML Export: Eksportuoti: &Current node &Esamą mazgą With all &sub-nodes Su visais &pomazgiais &All nodes &Visus mazgus Output file: Išvesties failas: Select path Pasirinkti kelią Question The file already exists. Do you want to replace it? Save HTML As... Įrašyti HTML kaip... HTML Files (*.html *.htm) HTML failai (*.html *.htm) Set Password Nustatyti slaptažodį Type password Įrašykite slaptažodį Retype password Pakartokite slaptažodį <center>Passwords were different. Retry!</center> <center>Slaptažodžiai buvo skirtingi. Bandykite dar kartą!</center> Enter Password Įveskite slaptažodį <center>Wrong password. Retry!</center> <center>Neteisingas slaptažodis. Bandykite dar kartą!</center> A lightweight notes manager Supaprastinta užrašų tvarkytuvė based on Qt pagrįsta Qt Author Autorius About FeatherNotes Apie FeatherNotes Translators Vertėjai See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. dar žinomas kaip FeatherNotes::LineEdit Clear text (Ctrl+K) Išvalyti tekstą (Ctrl(Vald)+K) Ctrl+K Clear text Ctrl(Vald)+K FeatherNotes::PrefDialog Preferences Nuostatos Window Langas Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Įrašo lango dydį užvėrus šį dialogą, o taip pat išeinant iš programos. Nuimkite žymėjimą, norėdami nustatyti fiksuotą dydį! Remember window &size Prisiminti lango &dydį Start with this size: Pradėti šiuo dydžiu: px piks. Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Įrašo medžio plotį užvėrus šį dialogą, o taip pat išeinant iš programos. Nuimkite žymėjimą, norėdami palikti pločio santykį 170/530. Remember &tree width Prisiminti &medžio plotį Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Įrašo poziciją užverus šį dialogą, o taip pat išeinant iš programos. (Tai gali neveikti tinkamai GTK+ darbalaukio aplinkose, tokiose kaip Unity ir Cinnamon.) Save &position Įrašyti &poziciją Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Apsprendžia ar turėtų būti naudojama dėklo piktograma. Jei pažymėta, užvėrus programą per pavadinimo juostoje esantį užvėrimo mygtuką, iš jos nebus išeita, o jos langas bus suskleistas į sistemos dėklo piktogramą. Tam, kad įsigaliotų, reikalauja paleisti FeatherNotes iš naujo. Add to s&ystray Pridėti į sis&temos dėklą The command line option --tray can be used instead of this. Vietoj to, gali būti naudojama komandų eilutės parinktis --tray. Start i&conified to tray Paleisti &suskleistą į dėklą Merge the tree view with its surroundings? Sulieti medžių rodinį su jo aplinka? Transparent t&ree view Permatomas me&džių rodinys By default, the active widget style determines the size of toolbar icons. Pagal numatymą, aktyvus valdiklių stilius nustato įrankių juostos piktogramų dydį. Small toolbar icons Mažos įrankių juostos piktogramos Do not show t&oolbar Nerodyti į&rankių juostos If the menubar is hidden, a menu button appears on the toolbar. Jei meniu juosta yra paslėpta, įrankių juostoje atsiranda meniu mygtukas. Do not show &menubar Nerodyti &meniu juostos Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Pažymėkite tai, jei naudojate programą Enlightenment aplinkoje (ar, galbūt, kitoje darbalaukio aplinkoje), kad lengviau galėtumėte naudoti sistemos dėklo piktogramą! Running &under Enlightenment? Programa paleista E&nlightenment aplinkoje? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Kai kurios darbalaukio aplinkos (tokios kaip Enlightenment) gali neteisingai pranešti apie lango poziciją. Jei tai yra tas atvejis, tuomet čia galite pabandyti ištaisyti šią problemą. Jeigu skydelis yra viršuje ar apačioje, turėtų būti nustatyta Y koordinatė; jeigu jis yra kairėje ar dešinėje, turėtų būti nustatyta X koordinatė. Pasirinkę koordinačių poslinkius, padėkite langą į tinkamą poziciją ir paleiskite FeatherNotes iš naujo! Shifts (X × Y): Poslinkiai (X × Y): Text Tekstas &Wrap lines by default Pagal numatymą, s&kaidyti eilutes Auto-&indent by default Pagal numatymą, daryti automatinę į&trauką This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Tai apima įvairius skliaustelius, riestinius skliaustus ir kabutes. Tam, kad įsigaliotų, reikalauja paleisti FeatherNotes iš naujo. Auto-&bracket Automatiniai skl&iaustai A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. Naudotojui rašant, esant tinkamoms aplinkybėms, trys taškai yra pakeičiami daugtaškiu, o dvigubas brūkšnelis ilguoju brūkšniu ir t.t. &Replace some characters while typing &Rašant, pakeisti kai kuriuos simbolius Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every &Automatiškai įrašyti kas minute(s) minutes(-ių) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Spartieji klavišai Action Veiksmas Shortcut Spartusis klavišas Default Numatytieji Warning: Ambiguous shortcut detected! Įspėjimas: Aptiktas dviprasmiškas spartusis klavišas! The typed shortcut was reserved. Įrašytas spartusis klavišas buvo rezervuotas. Application restart is needed for changes to take effect. Tam, kad įsigaliotų pakeitimai, reikia paleisti programą iš naujo. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Kuo pakeisti: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help Žinynas QObject New Node Naujas mazgas FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_nb_NO.ts000066400000000000000000002071741374721712500263650ustar00rootroot00000000000000 FeatherNotes::AboutDialog License FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes Next (F3) F3 Previous (F4) F4 Search... Search only in names (Ctrl+Shift+F7) Ctrl+Shift+F7 Search only in tags (Shift+F7) Shift+F7 Search in all nodes (F7) F7 Whole Word (F6) Whole Word F6 Match Case (F5) Match Case F5 &File &Edit For&mat &Tree &Options &Search &Help Find: Replace with: To be replaced Replacing text Previous (F9) F9 Next (F8) F8 Replace all (F10) F10 &Save Save Ctrl+S &Open Open a file Ctrl+O &Undo Undo Ctrl+Z &Redo Redo Ctrl+Shift+Z &Find Show/hide searchbar Ctrl+F &Clear All Formats Clear all formats Ctrl+E &Bold Bold Ctrl+B &Italic Italic Ctrl+I &Underline Underline Ctrl+U &Strike Through Strike through Ctrl+T Te&xt Color Text color Alt+Shift+T Back&ground Color Background color Alt+Shift+B Options &New Note Ctrl+Alt+Shift+N Save &As Ctrl+Shift+S &Print Ctrl+P P&rint with Sub-Nodes Set Pass&word &Quit Ctrl+Q &Cut Ctrl+X C&opy Ctrl+C &Paste Ctrl+V &Delete &Select All Ctrl+A E&mbed Image Embed Image Ctrl+Alt+Shift+I E&xpand All Ctrl+Shift+Down Collap&se All Ctrl+Shift+Up &Append Sibling Ctrl+N Append &Child Ctrl+Shift+N &Delete Node Ctrl+D Move &Up Alt+Up Move Do&wn Alt+Down Re&name Node Ctrl+Shift+R Tree Pr&operties Ctrl+Shift+D Document &Font &Wrap Lines Ctrl+W &Auto-Indentation Ctrl+Shift+I &Preferences Ctrl+Shift+P Find and &Replace Ctrl+R Ctrl+H &About Pr&int All Nodes Superscrip&t Superscript Alt+Shift+U Subscri&pt Subscript Alt+Shift+S C&enter Align center Alt+Shift+Down &Right Align right Alt+Shift+Right &Left Align left Alt+Shift+Left &Justify Justify Alt+Shift+Up &Prepend Sibling Ctrl+M Move &Left Alt+Left Move &Right Alt+Right h&2 Header 2 Ctrl+2 h&1 Header 1 Ctrl+1 h&3 Header 3 Ctrl+3 &Node Font Node Font Scale I&mage(s) Paste &HTML Ctrl+Shift+V &Tags Ctrl+Shift+T Insert Lin&k Ctrl+L C&opy Link I&nsert Table Ctrl+Alt+Shift+T Append Row Delete Row Append Column Delete Column Merge Cells Prepend Row Prepend Column Export &HTML Save Ima&ge(s) RTL Ctrl+Alt+Shift+Left LTR Ctrl+Alt+Shift+Right Menu Node &Icon Ctrl+Shift+C Check Spelling F2 Document &Colors Paste Date and Time Node Icon &Raise/Hide <center><b><big>New note?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> Yes No <center><b><big>Save changes?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>The document has been removed.</i></center> Discard changes Cancel Open file... <center><b><big>Cannot be saved!</big></b></center> Close Save As... <center><b><big>Delete this node?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> Tags OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> %1 Matches One Match No Match Replacement No Replacement One Replacement %1 Replacements Insert Link Image path Open image Scaling percentage Open Image... &Raise New Node FeatherNotes documents (*.fnx);;All Files (*) Untitled Select Text Color Select Background Color Deletion Tag(s) for this node Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Select Document Font Select Node Font Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to % Scale Image(s) untitled Error <center><b><big>Image cannot be saved! Retry?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> Save Image As... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Insert Table Rows: Columns: Print Document Export HTML Export: &Current node With all &sub-nodes &All nodes Output file: Select path Question The file already exists. Do you want to replace it? Save HTML As... HTML Files (*.html *.htm) Set Password Type password Retype password <center>Passwords were different. Retry!</center> Enter Password <center>Wrong password. Retry!</center> A lightweight notes manager based on Qt Author About FeatherNotes Translators See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. FeatherNotes::LineEdit Clear text (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences Window Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Remember window &size Start with this size: px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Remember &tree width Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Save &position Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Add to s&ystray The command line option --tray can be used instead of this. Start i&conified to tray Merge the tree view with its surroundings? Transparent t&ree view By default, the active widget style determines the size of toolbar icons. Small toolbar icons Do not show t&oolbar If the menubar is hidden, a menu button appears on the toolbar. Do not show &menubar Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Running &under Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Shifts (X × Y): Text &Wrap lines by default Auto-&indent by default This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Auto-&bracket A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. &Replace some characters while typing Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every minute(s) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Action Shortcut Default Warning: Ambiguous shortcut detected! The typed shortcut was reserved. Application restart is needed for changes to take effect. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help QObject New Node FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_nl.ts000066400000000000000000002133421374721712500257750ustar00rootroot00000000000000 FeatherNotes::AboutDialog License Licentie FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes Next (F3) Volgende (F3) F3 Previous (F4) Volgende (F4) F4 Search... Zoeken... Search only in names (Ctrl+Shift+F7) Alleen namen doorzoeken (Ctrl+Shift+F7) Ctrl+Shift+F7 Search only in tags (Shift+F7) Alleen labels doorzoeken (Shift+F7) Shift+F7 Search in all nodes (F7) Alle notities doorzoeken (F7) F7 Whole Word (F6) Volledig woord (F6) Whole Word Volledig woord F6 Match Case (F5) Overeenkomstig met hoofdlettergebruik (F5) Match Case Overeenkomstig met hoofdlettergebruik F5 &File &Bestand &Edit B&ewerken For&mat Op&maak &Tree &Boomweergave &Options &Opties &Search &Zoeken &Help &Hulp Find: Zoeken: Replace with: Vervangen door: To be replaced Te vervangen Replacing text Bezig met vervangen van tekst Previous (F9) Vorige (F9) F9 Next (F8) Volgende (F8) F8 Replace all (F10) Alles vervangen (F10) F10 &Save &Sla op Save Sla op Ctrl+S &Open &Open Open a file Open een bestand Ctrl+O &Undo Maak &ongedaan Undo Maak ongedaan Ctrl+Z &Redo &Opnieuw Redo Opnieuw Ctrl+Shift+Z &Find &Zoeken Show/hide searchbar Zoekbalk tonen/verbergen Ctrl+F &Clear All Formats Alle opmaak &wissen Clear all formats Alle opmaak wissen Ctrl+E &Bold &Vetgedrukt Bold Vetgedrukt Ctrl+B &Italic Curs&ief Italic Cursief Ctrl+I &Underline &Onderstrepen Underline Onderstrepen Ctrl+U &Strike Through &Doorhalen Strike through Doorhalen Ctrl+T Te&xt Color Te&kstkleur Text color Tekstkleur Alt+Shift+T Back&ground Color Achter&grondkleur Background color Achtergrondkleur Alt+Shift+B Options Opties &New Note &Nieuwe notitie Ctrl+Alt+Shift+N Save &As Opslaan &als Ctrl+Shift+S &Print &Afdrukken Ctrl+P P&rint with Sub-Nodes Onderliggende notities ook afd&rukken Set Pass&word &Wachtwoord instellen &Quit &Afsluiten Ctrl+Q &Cut &Knippen Ctrl+X C&opy K&opiëren Ctrl+C &Paste &Plakken Ctrl+V &Delete &Verwijderen &Select All &Selecteer alles Ctrl+A E&mbed Image Afbeelding i&nvoegen Embed Image Afbeelding invoegen Ctrl+Alt+Shift+I E&xpand All Alles &uitklappen Ctrl+Shift+Down Collap&se All Alles &inklappen Ctrl+Shift+Up Ctrl+Shift+pijltje omhoog &Append Sibling Gelijksoortige &toekennen Ctrl+N Append &Child Sub &toekennen Ctrl+Shift+N &Delete Node Node verwij&deren Ctrl+D Move &Up &Omhoog verplaatsen Alt+Up Alt+pijltje omhoog Move Do&wn Omlaag &verplaatsen Alt+Down Alt+pijltje omlaag Re&name Node Node&naam wijzigen Ctrl+Shift+R Tree Pr&operties B&oomweergave-eigenschappen Ctrl+Shift+D Document &Font Document&lettertype &Wrap Lines Regels o&mslaan Ctrl+W &Auto-Indentation &Automatisch inspringen Ctrl+Shift+I &Preferences &Voorkeuren Ctrl+Shift+P Find and &Replace Zoeken en ve&rvangen Ctrl+R Ctrl+H &About &Over Pr&int All Nodes Alle not&ities afdrukken Superscrip&t Bovenschrif&t Superscript Bovenschrift Alt+Shift+U Subscri&pt Onderschri&ft Subscript Onderschrift Alt+Shift+S C&enter C&entreren Align center Gecentreerd uitlijnen Alt+Shift+Down Alt+Shift+pijltje omlaag &Right &Rechts Align right Rechts uitlijnen Alt+Shift+Right Alt+Shift+pijltje naar rechts &Left &Links Align left Links uitlijnen Alt+Shift+Left Alt+Shift+pijltje naar links &Justify U&itvullen Justify Uitvullen Alt+Shift+Up Alt+Shift+pijltje omhoog &Prepend Sibling Gelijksoortige &bijvoegen Ctrl+M Move &Left Naar &links verplaatsen Alt+Left Alt+pijltje naar links Move &Right Naar &rechts verplaatsen Alt+Right Alt+pijltje naar rechts h&2 k&2 Header 2 Kop 2 Ctrl+2 h&1 k&1 Header 1 Kop 1 Ctrl+1 h&3 k&3 Header 3 Kop 3 Ctrl+3 &Node Font &Nodelettertype Node Font Nodelettertype Scale I&mage(s) Grootte van afbeeldi&ng(en) wijzigen Paste &HTML &HTML plakken Ctrl+Shift+V &Tags &Labels Ctrl+Shift+T Insert Lin&k Lin&k invoegen Ctrl+L C&opy Link Link k&opiëren I&nsert Table Tabel i&nvoegen Ctrl+Alt+Shift+T Append Row Rij toevoegen Delete Row Rij verwijderen Append Column Kolom toevoegen Delete Column Kolom verwijderen Merge Cells Cellen samenvoegen Prepend Row Rij erboven invoegen Prepend Column Kolom erboven invoegen Export &HTML &HTML exporteren Save Ima&ge(s) Afbeeldin&g(en) opslaan RTL RNL Ctrl+Alt+Shift+Left Ctrl+Alt+Shift+pijltje links LTR LNR Ctrl+Alt+Shift+Right Ctrl+Alt+Shift+pijltje rechts Menu Node &Icon Nodep&ictogram Ctrl+Shift+C Check Spelling F2 Document &Colors Paste Date and Time Node Icon Nodepictogram &Raise/Hide Tonen/Ve&rbergen <center><b><big>New note?</big></b></center> <center><b><big>Nieuwe notitie?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>Weet je zeker dat je dit document wilt sluiten</i></center> <center><i>en een nieuw, leeg document wilt maken?</i></center> Yes Ja No Nee <center><b><big>Save changes?</big></b></center> <center><b><big>Wijzigingen opslaan?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>Het document is bewerkt.</i></center> <center><i>The document has been removed.</i></center> <center><i>Het document is verwijderd.</i></center> Discard changes Wijzigingen verwerpen Cancel Annuleren Open file... Bestand openen... <center><b><big>Cannot be saved!</big></b></center> <center><b><big>Opslaan mislukt!</big></b></center> Close Sluiten Save As... Opslaan als... <center><b><big>Delete this node?</big></b></center> <center><b><big>Deze node verwijderen?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>Waarschuwing!</i></b></center> <center>Deze actie kan niet ongedaan worden gemaakt.</center> Tags Labels OK Oké <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Hoofdnotities:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Alle notities:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>Notitie:</b> <i>%1</i><br><b>Hoofdnodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Alle nodes:</b> <i>%3</i> %1 Matches %1 overeenkomsten One Match Eén overeenkomst No Match Geen overeenkomst(en) Replacement Vervanging No Replacement Geen vervanging(en) One Replacement Eén vervanging %1 Replacements %1 vervangingen Insert Link Link invoegen Image path Afbeeldingspad Open image Afbeelding openen Scaling percentage Schaalpercentage Open Image... Afbeelding openen... &Raise Naa&r voren brengen New Node Nieuwe node FeatherNotes documents (*.fnx);;All Files (*) FeatherNotes-documenten (*.fnx);;Alle bestanden (*) Untitled Naamloos Select Text Color Kies tekstkleur Select Background Color Kies achtergrondkleur Deletion Verwijdering Tag(s) for this node Label(s) van deze node Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Afbeeldingsbestanden (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;Alle bestanden (*) Select Document Font Kies documentsformaat Select Node Font Kies lettertype voor node Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to Schalen naar % Scale Image(s) Afbeelding(en) schalen untitled naamloos Error Fout <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>De afbeelding kan niet worden opgeslagen! Wil je het opnieuw proberen?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>Misschien heb je een ongeldige extensie gekozen</center> <center>of geen schrijftoegang.</center><p></p> Save Image As... Afbeelding opslaan als... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Afbeeldingsbestanden (*.png *.jpg *.jpeg *.bmp);;Alle bestanden (*) Insert Table Tabel invoegen Rows: Rijen: Columns: Kolommen: Print Document Document afdrukken Export HTML HTML exporteren Export: Exporteren: &Current node &Huidige node With all &sub-nodes Inclu&sief alle onderliggende nodes &All nodes &Alle nodes Output file: Uitvoerbestand: Select path Kies pad Question The file already exists. Do you want to replace it? Save HTML As... HTML opslaan als... HTML Files (*.html *.htm) HTML-bestanden (*.html *.htm) Set Password Wachtwoord instellen Type password Typ het gewenste wachtwoord Retype password Typ het wachtwoord opnieuw <center>Passwords were different. Retry!</center> <center>De wachtwoorden komen niet overeen. Probeer het opnieuw!</center> Enter Password Voer wachtwoord in <center>Wrong password. Retry!</center> <center>Verkeerd wachtwoord. Probeer het opnieuw!</center> A lightweight notes manager Een lichte notitiebeheerder based on Qt gebaseerd op Qt Author Maker About FeatherNotes Over FeatherNotes Translators Vertalers See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. ook bekend als FeatherNotes::LineEdit Clear text (Ctrl+K) Tekst wissen (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences Voorkeuren Window Venster Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Slaat de vensterafmetingen op, zowel na het sluiten van dit venster als bij het afsluiten van het programma. Vink dit uit om vaste afmetingen in te stellen! Remember window &size Ven&sterafmetingen onthouden Start with this size: Opstarten met deze afmetingen: px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Slaat de breedte van de boomweergave op, zowel na het sluiten van dit venster als bij het afsluiten van het programma. Vink dit uit voor een breedteverhouding van 170/530. Remember &tree width Breed&te van boomweergave onthouden Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Onthoudt de positie, zowel na het sluiten van dit venster als bij het afsluiten van het programma. (Dit werkt mogelijk niet goed in GTK+-werkomgevingen als Unity en Cinnamon.) Save &position &Positie onthouden Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Bepaalt of er wel of geen systeemvakpictogram moet worden gebruikt. Als dit wordt aangevinkt, dan wordt het venster, bij afsluiten, geminimaliseerd naar het systeemvak in plaats van afgesloten. Herstart FeatherNotes om de wijziging toe te passen. Add to s&ystray S&ysteemvakpictogram tonen The command line option --tray can be used instead of this. De opdrachtregeloptie --tray kan eveneens worden gebruikt. Start i&conified to tray Gem&inimaliseerd in systeemvak opstarten Merge the tree view with its surroundings? Wil je de boomweergave laten opgaan in de omgeving? Transparent t&ree view Doorzich&tige boomweergave By default, the active widget style determines the size of toolbar icons. Standaard bepaalt de actieve widgetstijl de grootte van de werkbalkpictogrammen. Small toolbar icons Kleine werkbalkpictogrammen Do not show t&oolbar Werkbalk nie&t tonen If the menubar is hidden, a menu button appears on the toolbar. Als de menubalk verborgen is, dan verschijnt er een menuknop op de werkbalk. Do not show &menubar &Menubalk niet tonen Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Vink dit aan op Enlightenment (kan ook op andere werkomgevingen) om gebruik van het systeemvakpictogram eenvoudiger te maken! Running &under Enlightenment? Gebr&uik je Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Sommige werkomgevingen (zoals Enlightenment) geven de vensterpositie niet altijd goed door. Als dat het geval is, dan kun je hier proberen om het probleem op te lossen. Als het paneel onder- of bovenaan staat, dan moet het Y-coördinaat worden ingesteld; als het links of rechts staat, dan moet het X-coördinaat worden ingesteld. Plaats, na het kiezen van de coördinaten, het venster op de juiste positie en herstart FeatherNotes! Shifts (X × Y): Posities (X × Y): Text Tekst &Wrap lines by default Regels altijd om&slaan Auto-&indent by default Altijd automatisch &inspringen This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Dit beslaat enkele/dubbele aanhalingstekens en ronde/vierkante haakjes. Herstart FeatherNotes om de instelling toe te passen. Auto-&bracket Automatische &haakjes A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. Drie puntjes wordt vervangen door een beletselteken, twee liggende streepjes worden vervangen door een kastlijntje, etc. wanneer de gebruiker onder bepaalde omstandigheden aan het typen is. &Replace some characters while typing &Vervang bepaalde karakters tijdens het typen Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every &Automatisch opslaan, elke minute(s) minu(u)t(en) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Sneltoetsen Action Actie Shortcut Sneltoets Default Standaard Warning: Ambiguous shortcut detected! Waarschuwing: dubbelzinnige sneltoets gedetecteerd! The typed shortcut was reserved. Deze sneltoets is gereserveerd. Application restart is needed for changes to take effect. Herstart het programma om de wijzigingen toe te passen. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Vervangen door: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help Hulp QObject New Node Nieuwe node FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_pl.ts000066400000000000000000002111431374721712500257740ustar00rootroot00000000000000 FeatherNotes::AboutDialog License Licencja FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes FeatherNotes Next (F3) Następne (F3) F3 F3 Previous (F4) Poprzednie (F4) F4 F4 Search... Szukaj… Search only in names (Ctrl+Shift+F7) Szukaj tylko w nazwach (Ctrl+Shift+F7) Ctrl+Shift+F7 Ctrl+Shift+F7 Search only in tags (Shift+F7) Szukaj tylko w tagach (Shift+F7) Shift+F7 Shift+F7 Search in all nodes (F7) Szukaj we wszystkich węzłach (F7) F7 F7 Whole Word (F6) Pełny wyraz (F6) Whole Word Pełny wyraz F6 F6 Match Case (F5) Dopasuj (F5) Match Case Dopasuj F5 F5 &File &Plik &Edit &Edytuj For&mat For&matowanie &Tree &Drzewo &Options &Opcje &Search &Szukaj &Help &Pomoc Find: Szukaj: Replace with: Zastąp z: To be replaced Do zastąpienia Replacing text Tekst zastępujący Previous (F9) Poprzednie (F9) F9 F9 Next (F8) Następne (F8) F8 F8 Replace all (F10) Zastąp wszystkie (F10) F10 F10 &Save Zapi&sz Save Zapisz Ctrl+S Ctrl+S &Open &Otwórz Open a file Otwórz plik Ctrl+O Ctrl+O &Undo &Cofnij Undo Cofnij Ctrl+Z Ctrl+Z &Redo Powtó&rz Redo Powtórz Ctrl+Shift+Z Ctrl+Shift+Z &Find &Szukaj Show/hide searchbar Pokaż/ukryj pasek wyszukiwania Ctrl+F Ctrl+F &Clear All Formats Wy&czyść całe formatowanie Clear all formats Wyczyść całe formatowanie Ctrl+E Ctrl+E &Bold Pogru&bienie Bold Pogrubienie Ctrl+B Ctrl+B &Italic Pochylen&ie Italic Pochylenie Ctrl+I Ctrl+I &Underline &Podkreślenie Underline Podkreślenie Ctrl+U Ctrl+U &Strike Through P&rzekreślenie Strike through Przekreślenie Ctrl+T Ctrl+T Te&xt Color &Kolor tekstu Text color Kolor tekstu Alt+Shift+T Alt+Shift+T Back&ground Color Ko&lor tła Background color Kolor tła Alt+Shift+B Alt+Shift+B Options Opcje &New Note &Nowa notatka Ctrl+Alt+Shift+N Ctrl+Alt+Shift+N Save &As Z&apisz jako Ctrl+Shift+S Ctrl+Shift+S &Print Wy&drukuj Ctrl+P Ctrl+P P&rint with Sub-Nodes Wydrukuj z węzłami pochodnymi Set Pass&word Usta&w hasło &Quit &Zakończ Ctrl+Q Ctrl+Q &Cut &Wytnij Ctrl+X Ctrl+X C&opy K&opiuj Ctrl+C Ctrl+C &Paste W&klej Ctrl+V Ctrl+V &Delete &Usuń &Select All Zaznacz wszy&stko Ctrl+A Ctrl+A E&mbed Image &Osadź obraz Embed Image Osadź obraz Ctrl+Alt+Shift+I Ctrl+Alt+Shift+I E&xpand All Rozwiń &wszystko Ctrl+Shift+Down Ctrl+Shift+Down Collap&se All Zwiń wszy&stko Ctrl+Shift+Up Ctrl+Shift+Up &Append Sibling Umieść bliźni&aka Ctrl+N Ctrl+N Append &Child Umieść dzie&cko Ctrl+Shift+N Ctrl+Shift+N &Delete Node &Usuń węzeł Ctrl+D Ctrl+D Move &Up Przenieś w &górę Alt+Up Alt+Up Move Do&wn Przenieś &w dół Alt+Down Alt+Down Re&name Node Zmień &nazwę węzła Ctrl+Shift+R Ctrl+Shift+R Tree Pr&operties Właściw&ości drzewa Ctrl+Shift+D Ctrl+Shift+D Document &Font &Czcionka dokumentu &Wrap Lines Zawijaj &wiersze Ctrl+W Ctrl+W &Auto-Indentation &Automatyczne wcięcia Ctrl+Shift+I Ctrl+Shift+I &Preferences &Preferencje Ctrl+Shift+P Ctrl+Shift+P Find and &Replace &Znajdź i zastąp Ctrl+R Ctrl+R Ctrl+H Ctrl+H &About O progr&amie Pr&int All Nodes Wydrukuj wszystk&ie węzły Superscrip&t Indeks &górny Superscript Indeks górny Alt+Shift+U Alt+Shift+U Subscri&pt Indeks &dolny Subscript Indeks dolny Alt+Shift+S Alt+Shift+S C&enter &Wyśrodkuj Align center Wyrównaj do środka Alt+Shift+Down Alt+Shift+Down &Right Wyrównaj do p&rawej Align right Wyrównaj do prawej Alt+Shift+Right Alt+Shift+Right &Left Wyrównaj do &lewej Align left Wyrównaj do lewej Alt+Shift+Left Alt+Shift+Left &Justify Wy&justuj Justify Wyjustuj Alt+Shift+Up Alt+Shift+Up &Prepend Sibling &Poprzedź bliźniakiem Ctrl+M Ctrl+M Move &Left Przenieś w &lewo Alt+Left Alt+Left Move &Right Przenieś w p&rawo Alt+Right Alt+Right h&2 h&2 Header 2 Nagłówek 2 Ctrl+2 Ctrl+2 h&1 h&1 Header 1 Nagłówek 1 Ctrl+1 Ctrl+1 h&3 h&3 Header 3 Nagłówek 3 Ctrl+3 Ctrl+3 &Node Font Czcio&nka węzła Node Font Czcionka węzła Scale I&mage(s) &Skaluj obraz(y) Paste &HTML Wklej &HTML Ctrl+Shift+V Ctrl+Shift+V &Tags &Tagi Ctrl+Shift+T Ctrl+Shift+T Insert Lin&k Umieść odnośni&k Ctrl+L Ctrl+L C&opy Link Sk&opiuj odnośnik I&nsert Table &Umieść tabelę Ctrl+Alt+Shift+T Ctrl+Alt+Shift+T Append Row Umieść rząd Delete Row Usuń rząd Append Column Umieść kolumnę Delete Column Usuń kolumnę Merge Cells Połącz komórki Prepend Row Poprzedź rzędem Prepend Column Poprzedź kolumną Export &HTML Eksportuj &HTML Save Ima&ge(s) &Zapisz obraz(y) RTL Od prawej do lewej Ctrl+Alt+Shift+Left Ctrl+Alt+Shift+Left LTR Od lewej do prawej Ctrl+Alt+Shift+Right Ctrl+Alt+Shift+Right Menu Menu Node &Icon &Ikona węzła Ctrl+Shift+C Ctrl+Shift+C Check Spelling F2 F2 Document &Colors Paste Date and Time Node Icon Ikona węzła &Raise/Hide Wznieś/Uk&ryj <center><b><big>New note?</big></b></center> <center><b><big>Nowa notatka?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>Czy na pewno chcesz zamknąć ten dokument</i></center> <center><i>i utworzyć nowy?</i></center> Yes Tak No Nie <center><b><big>Save changes?</big></b></center> <center><b><big>Zapisać zmiany?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>Ten dokument został zmodyfikowany.</i></center> <center><i>The document has been removed.</i></center> <center><i>Ten dokument został usunięty.</i></center> Discard changes Odrzuć zmiany Cancel Anuluj Open file... Otwórz plik… <center><b><big>Cannot be saved!</big></b></center> <center><b><big>Nie można zapisać!</big></b></center> Close Zamknij Save As... Zapisz jako… <center><b><big>Delete this node?</big></b></center> <center><b><big>Usunąć ten węzeł?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>Ostrzeżenie!</i></b></center> <center>Nie możesz tego cofnąć.</center> Tags Tagi OK OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Główne węzły:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Wszystkie węzły:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>Notatka:</b> <i>%1</i><br><b>Główne węzły:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Wszystkie węzły:</b> <i>%3</i> %1 Matches %1 wystąpienia One Match Jedno wystąpienie No Match Brak wystąpień Replacement Zastąpienie No Replacement Bez zamiennika One Replacement Jeden zamiennik %1 Replacements %1 zamienniki Insert Link Wstaw odnośnik Image path Ścieżka obrazu Open image Otwórz obraz Scaling percentage Skalowanie procentowo Open Image... Otwórz obraz… &Raise &Podnieś New Node Nowa gałąź FeatherNotes documents (*.fnx);;All Files (*) Dokumenty FeatherNotes (*.fnx);;Wszystkie pliki (*) Untitled Bez tytułu Select Text Color Select Background Color Deletion Usuwanie Tag(s) for this node Tag(i) dla tego węzła Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Pliki obrazów (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;Wszystkie pliki (*) Select Document Font Select Node Font Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to Skaluj do % % Scale Image(s) Skaluj obraz(y) untitled bez tytułu Error <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>Nie udało się zapisać obrazu! Spróbować ponownie?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>Może wybrałeś złe rozszerzenie</center> <center>lub nie masz uprawnień do zapisu?</center><p></p> Save Image As... Zapisz obraz jako… Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Pliki obrazów (*.png *.jpg *.jpeg *.bmp);;Wszystkie pliki (*) Insert Table Wstaw tabelę Rows: Rzędy: Columns: Kolumny: Print Document Wydrukuj dokument Export HTML Eksportuj HTML Export: Eksportuj: &Current node Obe&cny węzeł With all &sub-nodes Ze w&szystkimi węzłami pochodnymi &All nodes &Wszystkie węzły Output file: Plik wyjściowy: Select path Wybierz ścieżkę Question The file already exists. Do you want to replace it? Save HTML As... Zapisz HTML jako… HTML Files (*.html *.htm) Pliki HTML (*.html *.htm) Set Password Ustaw hasło Type password Wprowadź hasło Retype password Wprowadź hasło ponownie <center>Passwords were different. Retry!</center> <center>Hasła nie pasują do siebie. Spróbuj ponownie!</center> Enter Password Wprowadź hasło <center>Wrong password. Retry!</center> <center>Nieprawidłowe hasło. Spróbuj ponownie!</center> A lightweight notes manager Lekki menedżer notatek based on Qt oparty o Qt Author Autor About FeatherNotes O FeatherNotes Translators Tłumacze See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. aka. FeatherNotes::LineEdit Clear text (Ctrl+K) Wyczyść tekst (Ctrl+K) Ctrl+K Clear text Ctrl+K FeatherNotes::PrefDialog Preferences Preferencje Window Okno Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Zapisuje rozmiar okna po zamknięciu tego okna i przy wyjściu. Odznacz, aby pozostawić stały rozmiar! Remember window &size &Zapamiętaj rozmiar okna Start with this size: Rozpocznij z tym rozmiarem: px piks. Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Remember &tree width Zapamię&taj szerokość drzewa Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Zapisuje położenie po zamknięciu tego okna i po wyjściu. (Może to nie działać na DE opartych o GTK+, np. Unity i Cinnamon.) Save &position Zapisz &położenie Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Add to s&ystray Dodaj do zasobnika s&ystemu The command line option --tray can be used instead of this. Zamiast tego możesz skorzystać z opcji wiersza poleceń --tray. Start i&conified to tray Uru&chamiaj jako ikona w zasobniku Merge the tree view with its surroundings? Transparent t&ree view By default, the active widget style determines the size of toolbar icons. Small toolbar icons Do not show t&oolbar Nie p&okazuj paska narzędzi If the menubar is hidden, a menu button appears on the toolbar. Jeżeli pasek menu jest ukryty, przycisk menu pojawi się na pasku zadań. Do not show &menubar Nie pokazuj paska &menu Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Zaznacz to pod Enlightenment (lub innym DE) aby łatwiej korzystać z ikony w zasobniku! Running &under Enlightenment? &Uruchamiasz na Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Shifts (X × Y): Text Tekst &Wrap lines by default Domyślnie za&wijaj wiersze Auto-&indent by default Domyśln&ie twórz automatyczne wcięcia This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Obejmuje to nawiasy, nawiasy klamrowe i cudzysłowy. Musisz uruchomić ponownie FeatherNotes, aby uzyskać efekt. Auto-&bracket Automatyczne &nawiasy A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. &Replace some characters while typing Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every &Automatycznie zapisuj co minute(s) minut(y) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Action Shortcut Default Warning: Ambiguous shortcut detected! The typed shortcut was reserved. Application restart is needed for changes to take effect. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Zastąp z: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help Pomoc QObject New Node Nowy węzeł FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_pt_BR.ts000066400000000000000000002140061374721712500263700ustar00rootroot00000000000000 FeatherNotes::AboutDialog License Licença FeatherNotes::ColorLabel Click to change color. Clique para alterar a cor. Select Color Selecione a cor FeatherNotes::FN FeatherNotes FeatherNotes Next (F3) Próximo (F3) F3 F3 Previous (F4) Anterior (F4) F4 F4 Search... Pesquisar... Search only in names (Ctrl+Shift+F7) Pesquisar somente em nomes (Ctrl+Shift+F7) Ctrl+Shift+F7 Ctrl+Shift+F7 Search only in tags (Shift+F7) Pesquisar somente em tags (Shift+F7) Shift+F7 Shift+F7 Search in all nodes (F7) Pesquisar em todos os nós (F7) F7 F7 Whole Word (F6) Palavra Inteira (F6) Whole Word Palavra Inteira F6 F6 Match Case (F5) Caso de Compatibilidade (F5) Match Case Caso de Compatibilidade F5 F5 &File &Arquivo &Edit &Editar For&mat For&matar &Tree &Árvore &Options &Opções &Search &Pesquisa &Help &Ajuda Find: Encontrar: Replace with: Substituir com: To be replaced Para ser substituído Replacing text Substituir texto Previous (F9) Anterior (F9) F9 F9 Next (F8) Próximo (F8) F8 F8 Replace all (F10) Substituir todos (F10) F10 F10 &Save &Salvar Save Salvar Ctrl+S Ctrl+S &Open &Abrir Open a file Abrir um arquivo Ctrl+O Ctrl+O &Undo &Desfazer Undo Desfazer Ctrl+Z Ctrl+Z &Redo &Refazer Redo Refazer Ctrl+Shift+Z &Find &Encontrar Show/hide searchbar Exibir/ocultar barra de pesquisa Ctrl+F &Clear All Formats &Limpar Todos Formatos Clear all formats Limpar todos formatos Ctrl+E &Bold &Negrito Bold Negrito Ctrl+B &Italic &Itálico Italic Itálico Ctrl+I &Underline &Sublinhado Underline Sublinhado Ctrl+U &Strike Through &Tachado Strike through Tachado Ctrl+T Te&xt Color Cor do Te&xto Text color Cor do texto Alt+Shift+T Back&ground Color Cor de Plano de &Fundo Background color Cor de plano de fundo Alt+Shift+B Options Opções &New Note &Nova Nota Ctrl+Alt+Shift+N Save &As Salvar &Como Ctrl+Shift+S &Print &Imprimir Ctrl+P P&rint with Sub-Nodes Imp&rimir com Sub-Nós Set Pass&word Configurar &Senha &Quit &Sair Ctrl+Q &Cut &Recortar Ctrl+X C&opy C&opiar Ctrl+C &Paste &Colar Ctrl+V &Delete &Excluir &Select All &Selecionar Todos Ctrl+A E&mbed Image In&corporar Imagem Embed Image Inserir Imagem Ctrl+Alt+Shift+I E&xpand All E&xpandir Todos Ctrl+Shift+Down Collap&se All Reco&lher Todos Ctrl+Shift+Up &Append Sibling &Acrescentar Irmão Ctrl+N Append &Child Acrescentar &Filho Ctrl+Shift+N &Delete Node &Excluir Nó Ctrl+D Move &Up Mover &Acima Alt+Up Move Do&wn Mover Abai&xo Alt+Down Re&name Node Re&nomear Nó Ctrl+Shift+R Tree Pr&operties Pr&opriedades da Árvore Ctrl+Shift+D Document &Font &Fonte do Documento &Wrap Lines &Linhas de Quebra Automática Ctrl+W &Auto-Indentation &Indentação Automática Ctrl+Shift+I &Preferences &Preferências Ctrl+Shift+P Find and &Replace Encontrar e &Substituir Ctrl+R Ctrl+H &About &Sobre Pr&int All Nodes Impr&imir Todos Nós Superscrip&t Sobrescrit&o Superscript Sobrescrito Alt+Shift+U Subscri&pt Subscri&to Subscript Subscrito Alt+Shift+S C&enter C&entralizado Align center Alinhar no centro Alt+Shift+Down &Right À &Direita Align right Alinhar na direita Alt+Shift+Right Alt+Shift+Seta direita &Left À &Esquerda Align left Alinhar na esquerda Alt+Shift+Left Alt+Shift+Seta esquerda &Justify &Justificado Justify Justificado Alt+Shift+Up &Prepend Sibling &Preferir Irmão Ctrl+M Move &Left Mover para &Esquerda Alt+Left Alt+Seta esquerda Move &Right Mover para &Direita Alt+Right h&2 Header 2 Cabeçalho 2 Ctrl+2 h&1 Header 1 Cabeçalho 1 Ctrl+1 h&3 Header 3 Cabeçalho 3 Ctrl+3 &Node Font &Fonte do Nó Node Font Fonte do Nó Scale I&mage(s) Escala de I&magem(ns) Paste &HTML Colar &HTML Ctrl+Shift+V &Tags Ctrl+Shift+T Insert Lin&k Inserir Lin&k Ctrl+L C&opy Link C&opiar Link I&nsert Table I&nserir Tabela Ctrl+Alt+Shift+T Append Row Acrescentar Linha Delete Row Excluir Linha Append Column Acrescentar Coluna Delete Column Excluir Coluna Merge Cells Mesclar Células Prepend Row Prefixar Linha Prepend Column Prefixar Coluna Export &HTML Exportar &HTML Save Ima&ge(s) Salvar Ima&gem(ns) RTL Direita para Esquerda Ctrl+Alt+Shift+Left Ctrl+Alt+Shift+Seta esquerda LTR Esquerda para Direita Ctrl+Alt+Shift+Right Ctrl+Alt+Shift+Seta direita Menu Node &Icon &Ícone do Nó Ctrl+Shift+C Check Spelling Verificar Ortografia F2 F2 Document &Colors &Cores do Documento Paste Date and Time Colar Data e Hora Node Icon Ícone do Nó &Raise/Hide &Aumentar/ocultar <center><b><big>New note?</big></b></center> <center><b><big>Nova nota?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>Você realmente quer deixar este documento</i></center> <center><i>e criar um em branco?</i></center> Yes Sim No Não <center><b><big>Save changes?</big></b></center> <center><b><big>Salvar alterações?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>O documento foi modificado.</i></center> <center><i>The document has been removed.</i></center> <center><i>O documento foi removido.</i></center> Discard changes Descartar alterações Cancel Cancelar Open file... Abrir arquivo... <center><b><big>Cannot be saved!</big></b></center> <center><b><big>Não pode ser salvo!</big></b></center> Close Fechar Save As... Salvar Como... <center><b><big>Delete this node?</big></b></center> <center><b><big>Excluir este nó?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>Atenção!</i></b></center> <center>Essa ação não pode ser desfeita.</center> Tags OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Principais nós:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Todos os nós:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>Nota:</b> <i>%1</i><br><b>Principais nós:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Todos os nós:</b> <i>%3</i> %1 Matches %1 Correspondências One Match Uma correspondência No Match Sem correspondência Replacement Substituição No Replacement Nenhuma substituição One Replacement Uma substituição %1 Replacements %1 Substituições Insert Link Inserir link Image path Caminho da imagem Open image Abrir imagem Scaling percentage Escala de porcentagem Open Image... Abrir imagem... &Raise &Aumentar New Node Novo Nó FeatherNotes documents (*.fnx);;All Files (*) Documentos do FeatherNotes (*.fnx);;Todos os Arquivos (*) Untitled Sem título Select Text Color Selecionar Cor do Texto Select Background Color Selecionar Cor de Fundo Deletion Exclusão Tag(s) for this node Tag(s) para este nó Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Arquivos de imagem (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Select Document Font Selecionar Fonte do Documento Select Node Font Selecionar Fonte do Nó Set Document Colors Definir Cores do Documento These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Essas cores serão aplicadas a novos nós.<br>Eles podem ou não afetar os nós existentes,<br>mas a reabertura do documento é recomendada. Background color: Cor de fundo: Text color: Cor do texto: The first 1000 replacements are highlighted. As primeiras 1000 substituições são destacadas. Scale to Escala para % Scale Image(s) Escala da Imagem(ns) untitled sem título Error Erro <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>Imagem não pode ser salva! Tentar novamente?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>Talvez você não tenha escolhido uma extensão adequada</center> <center>ou não tem permissão de gravação.</center><p></p> Save Image As... Salvar Imagem Como... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Arquivos de imagem (*.png *.jpg *.jpeg *.bmp);;Todos os Arquivos (*) Insert Table Inserir Tabela Rows: Linhas: Columns: Colunas: Print Document Imprimir Documento Export HTML Exportar HTML Export: Exportar: &Current node &Nó atual With all &sub-nodes Com todos os &sub-nós &All nodes &Todos os nós Output file: Arquivo de saída: Select path Selecionar caminho Question Questão The file already exists. Do you want to replace it? O arquivo já existe. Você deseja substituir? Save HTML As... Salvar HTML Como... HTML Files (*.html *.htm) Arquivos HTML (*.html *.htm) Set Password Definir Senha Type password Digite a senha Retype password Redigite a senha <center>Passwords were different. Retry!</center> <center>As senhas não conferem. Tente novamente!</center> Enter Password Digite a senha <center>Wrong password. Retry!</center> <center>Senha incorreta. Tente novamente!</center> A lightweight notes manager Um gerenciador de notas leve based on Qt baseado no Qt Author Autor About FeatherNotes Sobre FeatherNotes Translators Tradutores See Preferences → Text → Spell Checking! Veja em Preferências → Texto → Verificação Ortográfica! You need to add a Hunspell dictionary. Você precisa adicionar um dicionário Hunspell. The Hunspell dictionary does not exist. O dicionário Hunspell não existe. The Hunspell dictionary is not accompanied by an affix file. O dicionário Hunspell não é acompanhado por um arquivo afixo. No misspelling from text cursor. Sem erros ortográficos do cursor de texto. Spell Checking Verificando Ortografia aka. FeatherNotes::LineEdit Clear text (Ctrl+K) Limpar texto (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences Preferências Window Janela Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Salva o tamanho da janela após fechar este diálogo e também ao sair. Desmarque para definir um tamanho fixo! Remember window &size Memorizar &tamanho da janela Start with this size: Iniciar com esse tamanho: px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Salva a largura da árvore após fechar este diálogo e também ao sair. Desmarque para uma taxa de largura de 170/530. Remember &tree width Memorizar largura da Ár&vore Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Salva a posição depois de fechar este diálogo e também ao sair. (Isso pode não funcionar corretamente sob GTK+ DE's como Unity e Cinnamon.) Save &position Salvar &posição Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Decide se um ícone da bandeja do sistema deve ser usado. Se marcado, o botão de fechar da barra de título iconifica a janela para a bandeja do sistema em vez de sair. Necessário reiniciar o FeatherNotes para entrar em vigor. Add to s&ystray Adicionar à área de no&tificação The command line option --tray can be used instead of this. A opção de linha de comando --tray pode ser usado em vez disso. Start i&conified to tray Iniciar mi&nimizado para bandeja Merge the tree view with its surroundings? Mesclar a visualização da árvore com o seu arredor? Transparent t&ree view Visualização de á&rvore transparente By default, the active widget style determines the size of toolbar icons. Por padrão, o estilo de widget ativo determina o tamanho dos ícones da barra de ferramentas. Small toolbar icons Ícones pequenos na barra de ferramenta Do not show t&oolbar Não exibir barra de f&erramenta If the menubar is hidden, a menu button appears on the toolbar. Se a barra de menu estiver oculta, um botão de menu aparecerá na barra de ferramentas. Do not show &menubar Não exibir barra de &menu Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Verifique isso em Enlightenment (ou, provavelmente, outro DE) para usar o ícone da bandeja do sistema mais facilmente! Running &under Enlightenment? Executando em E&nlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Alguns DE's (como o Enlightenment) podem não relatar a posição da janela corretamente. Se for esse o caso, você pode tentar corrigir o problema aqui. Se o painel estiver na parte inferior ou superior, a coordenada Y deve ser definida; se estiver à esquerda ou à direita, a coordenada X deve ser definida. Depois de escolher o deslocamento das coordenadas, coloque a janela em uma posição adequada e reinicie o FeatherNotes! Shifts (X × Y): Deslocamento (X × Y): Text Texto &Wrap lines by default &Quebra de linhas por padrão Auto-&indent by default &Indentação automática por padrão This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Isso abrange parênteses, chaves, colchetes e citações. Necessário reiniciar o FeatherNotes para entrar em vigor. Auto-&bracket &Colchete automático A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. Um período triplo é substituído por uma elipse, um hífen duplo com um traço longo, etc. Enquanto o usuário está digitando e em circunstâncias adequadas. &Replace some characters while typing &Substitua alguns caracteres enquanto digita Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Usado para colar a data e a hora. Deixe em branco para o padrão do sistema. Entra em vigor após fechar esta caixa de diálogo. Date and time format: Formato de data e hora: &Auto-save every Salvar tudo &automaticamente minute(s) minuto(s) Spell Checking Verificação Ortográfica A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Um dicionário Hunspell tem um nome que termina com ".dic" e deve estar ao lado de um arquivo afixo com o mesmo nome, mas terminando com ".aff". Hunspell dictionary path: Endereço do dicionário Hunspell: Add dictionary... Adicionar dicionário... Files Arquivos Start with the last opened file Iniciar com o último arquivo aberto Shortcuts Atalhos Action Ação Shortcut Atalho Default Padrão Warning: Ambiguous shortcut detected! Atenção: Atalho ambíguo detectado! The typed shortcut was reserved. O atalho digitado foi reservado. Application restart is needed for changes to take effect. A reinicialização do aplicativo é necessária para que as alterações entrem em vigor. Hunspell Dictionary Files (*.dic) Arquivos de Dicionário Hunspell (*.dic) FeatherNotes::SpellDialog Unknown word: Palavra desconhecida: Add To Dictionary Adicionar ao Dicionário Replace with: Substituir com: Ignore Once Ignorar Uma Vez Ignore All Ignorar Tudo Correct Once Corrigir Uma Vez Correct All Corrigir Tudo FeatherNotes::helpDialog Help Ajuda QObject New Node Novo Nó FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_pt_PT.ts000066400000000000000000001745001374721712500264140ustar00rootroot00000000000000 FeatherNotes::AboutDialog License FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes Next (F3) F3 Previous (F4) F4 Search... Search only in names (Ctrl+Shift+F7) Ctrl+Shift+F7 Search only in tags (Shift+F7) Shift+F7 Search in all nodes (F7) F7 Whole Word (F6) Whole Word F6 Match Case (F5) Match Case F5 &File &Edit For&mat &Tree &Options &Search &Help Find: Replace with: To be replaced Replacing text Previous (F9) F9 Next (F8) F8 Replace all (F10) F10 &Save Save Ctrl+S &Open Open a file Ctrl+O &Undo Undo Ctrl+Z &Redo Redo Ctrl+Shift+Z &Find Show/hide searchbar Ctrl+F &Clear All Formats Clear all formats Ctrl+E &Bold Bold Ctrl+B &Italic Italic Ctrl+I &Underline Underline Ctrl+U &Strike Through Strike through Ctrl+T Te&xt Color Text color Alt+Shift+T Back&ground Color Background color Alt+Shift+B Options &New Note Ctrl+Alt+Shift+N Save &As Ctrl+Shift+S &Print Ctrl+P P&rint with Sub-Nodes Set Pass&word &Quit Ctrl+Q &Cut Ctrl+X C&opy Ctrl+C &Paste Ctrl+V &Delete &Select All Ctrl+A E&mbed Image Embed Image Ctrl+Alt+Shift+I E&xpand All Ctrl+Shift+Down Collap&se All Ctrl+Shift+Up &Append Sibling Ctrl+N Append &Child Ctrl+Shift+N &Delete Node Ctrl+D Move &Up Alt+Up Move Do&wn Alt+Down Re&name Node Ctrl+Shift+R Tree Pr&operties Ctrl+Shift+D Document &Font &Wrap Lines Ctrl+W &Auto-Indentation Ctrl+Shift+I &Preferences Ctrl+Shift+P Find and &Replace Ctrl+R Ctrl+H &About Pr&int All Nodes Superscrip&t Superscript Alt+Shift+U Subscri&pt Subscript Alt+Shift+S C&enter Align center Alt+Shift+Down &Right Align right Alt+Shift+Right &Left Align left Alt+Shift+Left &Justify Justify Alt+Shift+Up &Prepend Sibling Ctrl+M Move &Left Alt+Left Move &Right Alt+Right h&2 Header 2 Ctrl+2 h&1 Header 1 Ctrl+1 h&3 Header 3 Ctrl+3 &Node Font Node Font Scale I&mage(s) Paste &HTML Ctrl+Shift+V &Tags Ctrl+Shift+T Insert Lin&k Ctrl+L C&opy Link I&nsert Table Ctrl+Alt+Shift+T Append Row Delete Row Append Column Delete Column Merge Cells Prepend Row Prepend Column Export &HTML Save Ima&ge(s) RTL Ctrl+Alt+Shift+Left LTR Ctrl+Alt+Shift+Right Menu Node &Icon Ctrl+Shift+C Check Spelling F2 Document &Colors Paste Date and Time Node Icon &Raise/Hide <center><b><big>New note?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> Yes No <center><b><big>Save changes?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>The document has been removed.</i></center> Discard changes Cancel Open file... <center><b><big>Cannot be saved!</big></b></center> Close Save As... <center><b><big>Delete this node?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> Tags OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> %1 Matches One Match No Match Replacement No Replacement One Replacement %1 Replacements Insert Link Image path Open image Scaling percentage Open Image... &Raise New Node FeatherNotes documents (*.fnx);;All Files (*) Untitled Select Text Color Select Background Color Deletion Tag(s) for this node Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Select Document Font Select Node Font Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to % Scale Image(s) untitled Error <center><b><big>Image cannot be saved! Retry?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> Save Image As... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Insert Table Rows: Columns: Print Document Export HTML Export: &Current node With all &sub-nodes &All nodes Output file: Select path Question The file already exists. Do you want to replace it? Save HTML As... HTML Files (*.html *.htm) Set Password Type password Retype password <center>Passwords were different. Retry!</center> Enter Password <center>Wrong password. Retry!</center> A lightweight notes manager based on Qt Author About FeatherNotes Translators See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. FeatherNotes::LineEdit Clear text (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences Window Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Remember window &size Start with this size: px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Remember &tree width Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Save &position Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Add to s&ystray The command line option --tray can be used instead of this. Start i&conified to tray Merge the tree view with its surroundings? Transparent t&ree view By default, the active widget style determines the size of toolbar icons. Small toolbar icons Do not show t&oolbar If the menubar is hidden, a menu button appears on the toolbar. Do not show &menubar Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Running &under Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Shifts (X × Y): Text &Wrap lines by default Auto-&indent by default This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Auto-&bracket A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. &Replace some characters while typing Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every minute(s) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Action Shortcut Default Warning: Ambiguous shortcut detected! The typed shortcut was reserved. Application restart is needed for changes to take effect. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help QObject New Node FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_ru.ts000066400000000000000000002240731374721712500260150ustar00rootroot00000000000000 FeatherNotes::AboutDialog License Лицензия FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes FeatherNotes Next (F3) Следующая (F3) F3 F3 Previous (F4) Предыдущая (F4) F4 F4 Search... Поиск... Search only in names (Ctrl+Shift+F7) Искать только в именах (Ctrl+Shift+F7) Ctrl+Shift+F7 Ctrl+Shift+F7 Search only in tags (Shift+F7) Искать только в тегах (Shift+F7) Shift+F7 Shift+F7 Search in all nodes (F7) Искать во всех заметках (F7) F7 F7 Whole Word (F6) Слово целиком (F6) Whole Word Слово целиком F6 F6 Match Case (F5) С учётом регистра (F5) Match Case С учётом регистра F5 F5 &File &Файл &Edit &Правка For&mat Фор&мат &Tree &Дерево &Options Па&раметры &Search &Поиск &Help &Справка Find: Найти: Replace with: Заменить на: To be replaced Подлежит замене Replacing text Заменяющий текст Previous (F9) Предыдущий (F9) F9 F9 Next (F8) Далее (F8) F8 F8 Replace all (F10) Заменить всё (F10) F10 F10 &Save &Сохранить Save Сохранить Ctrl+S Ctrl+S &Open &Открыть Open a file Открыть файл Ctrl+O Ctrl+O &Undo &Отменить Undo Отменить Ctrl+Z Ctrl+Z &Redo &Повторить Redo Повторить Ctrl+Shift+Z Ctrl+Shift+Z &Find &Найти Show/hide searchbar Показать/скрыть строку поиска Ctrl+F Ctrl+F &Clear All Formats &Очистить форматирование Clear all formats Очистить форматирование Ctrl+E Ctrl+E &Bold Полу&жирный Bold Полужирный Ctrl+B Ctrl+B &Italic К&урсив Italic Курсив Ctrl+I Ctrl+I &Underline По&дчёркнутый Underline Подчёркнутый Ctrl+U Ctrl+U &Strike Through &Зачёркнутый Strike through Зачёркнутый Ctrl+T Ctrl+T Te&xt Color Цвет текс&та Text color Цвет текста Alt+Shift+T Alt+Shift+T Back&ground Color Цвет фо&на Background color Цвет фона Alt+Shift+B Alt+Shift+B Options Параметры &New Note &Новая заметка Ctrl+Alt+Shift+N Ctrl+Alt+Shift+N Save &As Сохранить &как Ctrl+Shift+S Ctrl+Shift+S &Print &Печать Ctrl+P Ctrl+P P&rint with Sub-Nodes Пе&чать со вложенными заметками Set Pass&word Установить па&роль &Quit &Выйти Ctrl+Q Ctrl+Q &Cut &Вырезать Ctrl+X Ctrl+X C&opy &Копировать Ctrl+C Ctrl+C &Paste &Вставить Ctrl+V Ctrl+V &Delete &Удалить &Select All &Выделить всё Ctrl+A Ctrl+A E&mbed Image В&ставить изображение Embed Image Вставить изображение Ctrl+Alt+Shift+I Ctrl+Alt+Shift+I E&xpand All &Развернуть всё Ctrl+Shift+Down Ctrl+Shift+Down Collap&se All Сверну&ть всё Ctrl+Shift+Up Ctrl+Shift+Up &Append Sibling &Добавить заметку снизу Ctrl+N Ctrl+N Append &Child Вложить &заметку Ctrl+Shift+N Ctrl+Shift+N &Delete Node &Удалить заметку Ctrl+D Ctrl+D Move &Up Переместить вв&ерх Alt+Up Alt+Up Move Do&wn Переместить вни&з Alt+Down Alt+Down Re&name Node Пере&именовать заметку Ctrl+Shift+R Ctrl+Shift+R Tree Pr&operties &Свойства дерева Ctrl+Shift+D Ctrl+Shift+D Document &Font &Шрифт документа &Wrap Lines &Переносить строки Ctrl+W Ctrl+W &Auto-Indentation &Автоматический отступ Ctrl+Shift+I Ctrl+Shift+I &Preferences &Настройки Ctrl+Shift+P Ctrl+Shift+P Find and &Replace Н&айти и заменить Ctrl+R Ctrl+R Ctrl+H Ctrl+H &About &О программе Pr&int All Nodes Пе&чать всех заметок Superscrip&t Верхний &индекс Superscript Верхний индекс Alt+Shift+U Alt+Shift+U Subscri&pt Нижний &индекс Subscript Нижний индекс Alt+Shift+S Alt+Shift+S C&enter По &центру Align center По центру Alt+Shift+Down Alt+Shift+Down &Right &По правому краю Align right По правому краю Alt+Shift+Right Alt+Shift+Right &Left &По левому краю Align left По левому краю Alt+Shift+Left Alt+Shift+Left &Justify По &ширине Justify По ширине Alt+Shift+Up Alt+Shift+Up &Prepend Sibling &Добавить заметку сверху Ctrl+M Ctrl+M Move &Left Переместить &влево Alt+Left Alt+Влево Move &Right Переместить &вправо Alt+Right Alt+Вправо h&2 Заголовок &2 Header 2 Заголовок 2 Ctrl+2 Ctrl+2 h&1 Заголовок &1 Header 1 Заголовок 1 Ctrl+1 Ctrl+1 h&3 Заголовок &3 Header 3 Заголовок 3 Ctrl+3 Ctrl+3 &Node Font &Шрифт заметки Node Font Шрифт заметки Scale I&mage(s) Масштаб изобра&жения(-й) Paste &HTML Вставить &HTML Ctrl+Shift+V Ctrl+Shift+V &Tags &Теги Ctrl+Shift+T Ctrl+Shift+T Insert Lin&k Вставить ссыл&ку Ctrl+L Ctrl+L C&opy Link К&опировать ссылку I&nsert Table В&ставить таблицу Ctrl+Alt+Shift+T Ctrl+Alt+Shift+T Append Row Добавить строку снизу Delete Row Удалить строку Append Column Добавить столбец справа Delete Column Удалить столбец Merge Cells Объединить ячейки Prepend Row Добавить строку сверху Prepend Column Добавить столбец слева Export &HTML Экспорт &HTML Save Ima&ge(s) Сохранить изобра&жение(-я) RTL Письмо справа налево Ctrl+Alt+Shift+Left Ctrl+Alt+Shift+Left LTR Письмо слева направо Ctrl+Alt+Shift+Right Ctrl+Alt+Shift+Right Menu Меню Node &Icon &Значок заметки Ctrl+Shift+C Ctrl+Shift+C Check Spelling F2 F2 Document &Colors Paste Date and Time Node Icon Значок заметки &Raise/Hide &Раскрыть/Свернуть <center><b><big>New note?</big></b></center> <center><b><big>Новая заметка?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>Вы действительно хотите оставить этот документ</i></center> <center><i>и создать пустой?</i></center> Yes Да No Нет <center><b><big>Save changes?</big></b></center> <center><b><big>Сохранить изменения?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>Документ был изменён.</i></center> <center><i>The document has been removed.</i></center> <center><i>Документ был удалён.</i></center> Discard changes Забыть изменения Cancel Отмена Open file... Открыть файл... <center><b><big>Cannot be saved!</big></b></center> <center><b><big>Сохранение невозможно!</big></b></center> Close Закрыть Save As... Сохранить как... <center><b><big>Delete this node?</big></b></center> <center><b><big>Удалить эту заметку?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>Внимание!</i></b></center> <center>Это действие нельзя отменить.</center> Tags Теги OK ОК <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Основных заметок:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Всего заметок:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>Информация:</b> <i>%1</i><br><b>Основных заметок:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>Всего заметок:</b> <i>%3</i> %1 Matches %1 совпадений One Match Одно совпадение No Match Нет совпадений Replacement Замена No Replacement Без замены One Replacement Одна замена %1 Replacements %1 замены Insert Link Вставить ссылку Image path Путь к изображению Open image Открыть изображение Scaling percentage Процент масштабирования Open Image... Открыть изображение... &Raise &Поднять New Node Новая заметка FeatherNotes documents (*.fnx);;All Files (*) Документы FeatherNotes (*.fnx);;Все файлы (*) Untitled Безымянный Select Text Color Выбор цвета текста Select Background Color Выбор цвета фона Deletion Удаление Tag(s) for this node Тег(и) этой заметки Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Файлы изображений (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;Все файлы (*) Select Document Font Выбор шрифта документа Select Node Font Выбор шрифта заметки Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to Масштабировать до % % Scale Image(s) Масштаб изображения(-ий) untitled безымянный Error Ошибка <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>Не удалось сохранить изображение! Повторить попытку?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>Возможно, вы выбрали неправильное расширение</center> <center>или у вас недостаточно прав на запись.</center><p></p> Save Image As... Сохранить изображение как... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Файлы изображений (*.png *.jpg *.jpeg *.bmp);;Все файлы (*) Insert Table Вставить таблицу Rows: Строк: Columns: Столбцов: Print Document Печать документа Export HTML Экспорт HTML Export: Экспорт: &Current node &Текущая заметка With all &sub-nodes Со всеми &вложенными заметками &All nodes &Все заметки Output file: Выходной файл: Select path Выберите путь Question The file already exists. Do you want to replace it? Save HTML As... Сохранить HTML как... HTML Files (*.html *.htm) Файлы HTML (*.html *.htm) Set Password Задать пароль Type password Введите пароль Retype password Повторите ввод пароля <center>Passwords were different. Retry!</center> <center>Пароли не совпадают. Повторите попытку!</center> Enter Password Введите пароль <center>Wrong password. Retry!</center> <center>Неверный пароль. Повторите попытку!</center> A lightweight notes manager Легковесный менеджер заметок based on Qt основан на Qt Author Автор About FeatherNotes О FeatherNotes Translators Переводчики See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. альтернативное имя. FeatherNotes::LineEdit Clear text (Ctrl+K) Удалить текст (Ctrl+K) Ctrl+K Clear text Ctrl+K FeatherNotes::PrefDialog Preferences Настройки Window Окно Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Сохраняет размер окна после закрытия этого диалога, а также после выхода. Снимите флажок, чтобы зафиксировать размер! Remember window &size Запомнить размер &окна Start with this size: Начать с данного размера: px пикс Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Сохраняет ширину дерева после закрытия этого диалога, а также после выхода. Снимите флажок для ширины 170/530. Remember &tree width Запомнить ширину &дерева Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Сохраняет расположение после закрытия этого диалога, а также после выхода. (Может работать некорректно в окружениях рабочего стола, основанных на GTK+, таких как Unity или Cinnamon.) Save &position Сохранить &расположение Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Если флажок установлен, нажатие на кнопку закрытия, вместо выхода, свернёт окно в системный лоток. Для вступления в силу потребуется перезапуск FeatherNotes. Add to s&ystray Добавить в системный &лоток The command line option --tray can be used instead of this. Вместо этого можно использовать опцию командной строки --tray. Start i&conified to tray Запускать с&вёрнутым в лоток Merge the tree view with its surroundings? Объединить вид дерева с текущим окружением? Transparent t&ree view Прозрачный вид &дерева By default, the active widget style determines the size of toolbar icons. По умолчанию, активный стиль виджетов определяет размер значков панели инструментов. Small toolbar icons Маленькие значки панели инструментов Do not show t&oolbar Скрыть панель &инструментов If the menubar is hidden, a menu button appears on the toolbar. При скрытии панели меню, кнопка меню расположится на панели инструментов. Do not show &menubar Скрыть &панель меню Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Поставьте флажок если вы используете Enlightenment (возможно, другое DE), для более удобного использования значка в системном лотке! Running &under Enlightenment? Вы используете &среду Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! В некоторых DE (например, в Enlightenment) окно приложения может быть размещено некорректно. Если вы столкнулись с этой проблемой попытайтесь решить её здесь. Если панель расположена снизу или сверху, скорректируйте Y-координату; при расположении панели слева или справа, скорректируйте X-координату. Скорректировав координаты, расположите окно правильно, а затем перезапустите FeatherNotes! Shifts (X × Y): Сдвиг (X × Y): Text Текст &Wrap lines by default &Выделять линии по умолчанию Auto-&indent by default &Автоматический отступ по умолчанию This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Это касается круглых, фигурных, квадратных скобок и кавычек. Для вступления в силу потребуется перезапуск FeatherNotes. Auto-&bracket &Автоматическое закрытие скобок A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. Три точки заменяются многоточием, двойной дефис — длинным тире и т.д. во время ввода текста и при определённых условиях. &Replace some characters while typing &Заменять некоторые символы при вводе Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every &Сохранять каждые minute(s) минут(-ы) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Комбинации клавиш Action Действие Shortcut Комбинация клавиш Default По умолчанию Warning: Ambiguous shortcut detected! Внимание: обнаружена неоднозначная комбинация! The typed shortcut was reserved. Введённая комбинация клавиш уже используется. Application restart is needed for changes to take effect. Для вступления изменений в силу перезапустите приложение. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Заменить на: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help Справка QObject New Node Новая заметка FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_sk_SK.ts000066400000000000000000001766041374721712500264070ustar00rootroot00000000000000 FeatherNotes::AboutDialog License Licencia FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes Next (F3) Ďalšie (F3) F3 Previous (F4) Predošlé (F4) F4 Search... Hľadať... Search only in names (Ctrl+Shift+F7) Hľadať iba v menách (Ctrl+Shift+F7) Ctrl+Shift+F7 Search only in tags (Shift+F7) Hľadať iba v zankoch (Shift+F7) Shift+F7 Search in all nodes (F7) Hľadať vo všetkých vláknach (F7) F7 Whole Word (F6) Celé slovo (F6) Whole Word Celé slová F6 Match Case (F5) Rozoznávať veľké/malé písmo (F5) Match Case Prípad zhody F5 &File &Súbor &Edit &Editovať For&mat &Formát &Tree &Strom &Options &Možnosti &Search &Hľadať &Help &Pomoc Find: Nájsť: Replace with: Nahradiť s: To be replaced K nahradeniu Replacing text Nahradiť text Previous (F9) Predošlý (F9) F9 Next (F8) Ďalší (F8) F8 Replace all (F10) Nahradiť všetko (F10) F10 &Save &Uložiť Save Uložiť Ctrl+S &Open &Otvoriť Open a file Otvoriť súbor Ctrl+O &Undo &Späť Undo Späť Ctrl+Z &Redo &Opakovať Redo Opakovať Ctrl+Shift+Z &Find &Nájsť Show/hide searchbar Zobraziť/skryť panel vyhľadávania Ctrl+F &Clear All Formats &Vymazať všetky formátovania Clear all formats Vymazať všetky formátovania Ctrl+E &Bold &Tučné Bold Tučné Ctrl+B &Italic &Kurzíva Italic Kurzíva Ctrl+I &Underline &Podčiarknuté Underline Podčiarknuté Ctrl+U &Strike Through &Prečiarknuté Strike through Prečiarknuté Ctrl+T Te&xt Color &Text farba Text color Farba textu Alt+Shift+T Back&ground Color &Farba pozadia Background color Farba pozadia Alt+Shift+B Options Možnosti &New Note &Nová poznámka Ctrl+Alt+Shift+N Save &As &Uložiť ako Ctrl+Shift+S &Print &Tlačiť Ctrl+P P&rint with Sub-Nodes Set Pass&word &Nastaviť heslo &Quit &Ukončiť Ctrl+Q &Cut &Vystrihnúť Ctrl+X C&opy &Kopírovať Ctrl+C &Paste &Prilepiť Ctrl+V &Delete &Vymazať &Select All &Vybrať všetko Ctrl+A E&mbed Image Embed Image Ctrl+Alt+Shift+I E&xpand All Ctrl+Shift+Down Collap&se All Ctrl+Shift+Up &Append Sibling Ctrl+N Append &Child Ctrl+Shift+N &Delete Node Ctrl+D Move &Up Alt+Up Move Do&wn Alt+Down Re&name Node Ctrl+Shift+R Tree Pr&operties Ctrl+Shift+D Document &Font &Wrap Lines Ctrl+W &Auto-Indentation Ctrl+Shift+I &Preferences Ctrl+Shift+P Find and &Replace Ctrl+R Ctrl+H &About Pr&int All Nodes Superscrip&t Superscript Alt+Shift+U Subscri&pt Subscript Alt+Shift+S C&enter Align center Alt+Shift+Down &Right Align right Alt+Shift+Right &Left Align left Alt+Shift+Left &Justify Justify Alt+Shift+Up &Prepend Sibling Ctrl+M Move &Left Alt+Left Move &Right Alt+Right h&2 Header 2 Ctrl+2 h&1 Header 1 Ctrl+1 h&3 Header 3 Ctrl+3 &Node Font Node Font Scale I&mage(s) Paste &HTML Ctrl+Shift+V &Tags Ctrl+Shift+T Insert Lin&k Ctrl+L C&opy Link I&nsert Table Ctrl+Alt+Shift+T Append Row Delete Row Append Column Delete Column Merge Cells Prepend Row Prepend Column Export &HTML Save Ima&ge(s) RTL Ctrl+Alt+Shift+Left LTR Ctrl+Alt+Shift+Right Menu Node &Icon Ctrl+Shift+C Check Spelling F2 Document &Colors Paste Date and Time Node Icon &Raise/Hide <center><b><big>New note?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> Yes No <center><b><big>Save changes?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>The document has been removed.</i></center> Discard changes Cancel Open file... <center><b><big>Cannot be saved!</big></b></center> Close Save As... <center><b><big>Delete this node?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> Tags OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> %1 Matches One Match No Match Replacement No Replacement One Replacement %1 Replacements Insert Link Image path Open image Scaling percentage Open Image... &Raise New Node FeatherNotes documents (*.fnx);;All Files (*) Untitled Select Text Color Select Background Color Deletion Tag(s) for this node Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Select Document Font Select Node Font Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to % Scale Image(s) untitled Error <center><b><big>Image cannot be saved! Retry?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> Save Image As... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Insert Table Rows: Columns: Print Document Export HTML Export: &Current node With all &sub-nodes &All nodes Output file: Select path Question The file already exists. Do you want to replace it? Save HTML As... HTML Files (*.html *.htm) Set Password Type password Retype password <center>Passwords were different. Retry!</center> Enter Password <center>Wrong password. Retry!</center> A lightweight notes manager based on Qt Author About FeatherNotes Translators See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. FeatherNotes::LineEdit Clear text (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences Window Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Remember window &size Start with this size: px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Remember &tree width Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Save &position Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Add to s&ystray The command line option --tray can be used instead of this. Start i&conified to tray Merge the tree view with its surroundings? Transparent t&ree view By default, the active widget style determines the size of toolbar icons. Small toolbar icons Do not show t&oolbar If the menubar is hidden, a menu button appears on the toolbar. Do not show &menubar Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Running &under Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Shifts (X × Y): Text &Wrap lines by default Auto-&indent by default This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Auto-&bracket A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. &Replace some characters while typing Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every minute(s) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts Action Shortcut Default Warning: Ambiguous shortcut detected! The typed shortcut was reserved. Application restart is needed for changes to take effect. Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Nahradiť s: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help QObject New Node FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_zh_CN.ts000066400000000000000000002103311374721712500263600ustar00rootroot00000000000000 FeatherNotes::AboutDialog License 许可证 FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes 羽毛笔笔记 Next (F3) 下一项(F3) F3 F3 Previous (F4) 上一项 (F4) F4 F4 Search... 搜索... Search only in names (Ctrl+Shift+F7) 仅在名称中搜索 (Ctrl+Shift+F7) Ctrl+Shift+F7 Ctrl+Shift+F7 Search only in tags (Shift+F7) 仅在Tags中搜索 (Shift+F7) Shift+F7 Shift+F7 Search in all nodes (F7) 在所有笔记中查找 (F7) F7 F7 Whole Word (F6) 精确模式 (F6) Whole Word 精确模式 F6 F6 Match Case (F5) 区分大小写 (F5) Match Case 区分大小写 F5 F5 &File 文件 &Edit 编辑 For&mat 格式 &Tree 目录 &Options 选项 &Search 搜索 &Help 帮助 Find: 查找: Replace with: 替换为: To be replaced 替换 Replacing text 替换文本 Previous (F9) 上一项 (F9) F9 F9 Next (F8) 下一项 (F8) F8 F8 Replace all (F10) 全部替换 (F10) F10 F10 &Save 保存 Save 保存 Ctrl+S Ctrl+S &Open 打开 Open a file 打开文件 Ctrl+O Ctrl+O &Undo 撤销 Undo 撤销 Ctrl+Z Ctrl+Z &Redo 重做 Redo 重做 Ctrl+Shift+Z Ctrl+Shift+Z &Find 查找 Show/hide searchbar 显示/隐藏 搜索条 Ctrl+F Ctrl+F &Clear All Formats 清除所有格式 Clear all formats 清除所有格式 Ctrl+E Ctrl+E &Bold 加粗 Bold 加粗 Ctrl+B Ctrl+B &Italic 斜体 Italic 斜体 Ctrl+I Ctrl+I &Underline 下划线 Underline 下划线 Ctrl+U Ctrl+U &Strike Through 删除线 Strike through 删除线 Ctrl+T Ctrl+T Te&xt Color 文本颜色 Text color 文本颜色 Alt+Shift+T Alt+Shift+T Back&ground Color 背景颜色 Background color 背景颜色 Alt+Shift+B Alt+Shift+B Options 选项 &New Note 新笔记 Ctrl+Alt+Shift+N Ctrl+Alt+Shift+N Save &As 另存为 Ctrl+Shift+S Ctrl+Shift+S &Print 打印 Ctrl+P Ctrl+P P&rint with Sub-Nodes 打印目录下所有笔记 Set Pass&word 设置密码 &Quit 退出 Ctrl+Q Ctrl+Q &Cut 剪切 Ctrl+X Ctrl+X C&opy 复制 Ctrl+C Ctrl+C &Paste 粘贴 Ctrl+V Ctrl+V &Delete 删除 &Select All 全选 Ctrl+A Ctrl+A E&mbed Image 插入图片 Embed Image 插入图片 Ctrl+Alt+Shift+I Ctrl+Alt+Shift+I E&xpand All 全部展开 Ctrl+Shift+Down Ctrl+Shift+Down Collap&se All 全部收起 Ctrl+Shift+Up Ctrl+Shift+Up &Append Sibling 在下方添加 Ctrl+N Ctrl+N Append &Child 添加子目录 Ctrl+Shift+N Ctrl+Shift+N &Delete Node 删除笔记 Ctrl+D Ctrl+D Move &Up 上移 Alt+Up Alt+Up Move Do&wn 下移 Alt+Down Alt+Down Re&name Node 修改名称 Ctrl+Shift+R Ctrl+Shift+R Tree Pr&operties 目录属性 Ctrl+Shift+D Ctrl+Shift+D Document &Font 设置字体 &Wrap Lines 自动换行 Ctrl+W Ctrl+W &Auto-Indentation 自动缩进 Ctrl+Shift+I Ctrl+Shift+I &Preferences 偏好设置 Ctrl+Shift+P Ctrl+Shift+P Find and &Replace 查找并替换 Ctrl+R Ctrl+R Ctrl+H Ctrl+H &About 关于 Pr&int All Nodes 打印所有笔记 Superscrip&t 上标字 Superscript 上标字 Alt+Shift+U Alt+Shift+U Subscri&pt 下标字 Subscript 下标字 Alt+Shift+S Alt+Shift+S C&enter 居中对齐 Align center 居中对齐 Alt+Shift+Down Alt+Shift+Down &Right 右对齐 Align right 右对齐 Alt+Shift+Right Alt+Shift+Right &Left 左对齐 Align left 左对齐 Alt+Shift+Left Alt+Shift+Left &Justify 两端对齐 Justify 两端对齐 Alt+Shift+Up Alt+Shift+Up &Prepend Sibling 在上方新建笔记 Ctrl+M Ctrl+M Move &Left 向左移动 Alt+Left Alt+Left Move &Right 向右移动 Alt+Right Alt+Right h&2 标题2 Header 2 标题2 Ctrl+2 Ctrl+2 h&1 标题1 Header 1 标题1 Ctrl+1 Ctrl+1 h&3 标题3 Header 3 标题3 Ctrl+3 Ctrl+3 &Node Font 目录字体 Node Font 目录字体 Scale I&mage(s) 缩放图片 Paste &HTML 粘贴HTML Ctrl+Shift+V Ctrl+Shift+V &Tags &Tags Ctrl+Shift+T Ctrl+Shift+T Insert Lin&k 插入链接 Ctrl+L Ctrl+L C&opy Link 复制链接 I&nsert Table 插入表格 Ctrl+Alt+Shift+T Ctrl+Alt+Shift+T Append Row 添加行 Delete Row 删除行 Append Column 添加列 Delete Column 删除列 Merge Cells 合并单元格 Prepend Row 在上方插入行 Prepend Column 在前方插入列 Export &HTML 导出HTML Save Ima&ge(s) 保存图片 RTL 右对齐 Ctrl+Alt+Shift+Left Ctrl+Alt+Shift+Left LTR 左对齐 Ctrl+Alt+Shift+Right Ctrl+Alt+Shift+Right Menu 菜单栏 Node &Icon 目录图标 Ctrl+Shift+C Ctrl+Shift+C Check Spelling F2 F2 Document &Colors Paste Date and Time Node Icon 目录图标 &Raise/Hide 升起/隐藏 <center><b><big>New note?</big></b></center> <center><b><big>新建笔记?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> <center><i>你真的想离开这个文档吗</i></center> <center><i>并创建一个空文档?</i></center> Yes No <center><b><big>Save changes?</big></b></center> <center><b><big>保存更改?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>文档已经被修改.</i></center> <center><i>The document has been removed.</i></center> <center><i>文档已被删除.</i></center> Discard changes 放弃更改 Cancel 取消 Open file... 打开文件... <center><b><big>Cannot be saved!</big></b></center> <center><b><big>无法保存!</big></b></center> Close 关闭 Save As... 另存为... <center><b><big>Delete this node?</big></b></center> <center><b><big>删除这个节点?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> <center><b><i>警告!</i></b></center> <center>此操作无法撤消.</center> Tags Tags OK 确定 <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>主节点:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>全部节点:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> <b>注意:</b> <i>%1</i><br><b>主节点:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>全部节点:</b> <i>%3</i> %1 Matches %1 项匹配 One Match 一项匹配 No Match 无匹配 Replacement 替换 No Replacement 没有替换 One Replacement 1处替换 %1 Replacements %1 替换 Insert Link 插入链接 Image path 图片地址 Open image 打开图片 Scaling percentage 百分比 Open Image... 打开图片... &Raise 升起 New Node 新笔记 FeatherNotes documents (*.fnx);;All Files (*) 羽毛笔笔记 文档 (*.fnx);;所有文件 (*) Untitled 无标题 Select Text Color 选择文本颜色 Select Background Color 选择背景颜色 Deletion 删除 Tag(s) for this node 此节点的Tags(s) Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) 图片文件 (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;所有文件 (*) Select Document Font 选择文档字体 Select Node Font 选择节点字体 Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to 缩放至 % % Scale Image(s) 缩放图片(s) untitled 无标题 Error 错误 <center><b><big>Image cannot be saved! Retry?</big></b></center> <center><b><big>图片无法保存! 重试?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> <center>可能您没有选择适当的扩展名</center> <center>或没有写入权限.</center><p></p> Save Image As... 图片另存为... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) 图像文件 (*.png *.jpg *.jpeg *.bmp);;所有文件(*) Insert Table 插入表格 Rows: 行: Columns: 列: Print Document 打印文档 Export HTML 导出HTML Export: 导出: &Current node 当前节点 With all &sub-nodes 包含所有子节点 &All nodes 所有节点 Output file: 导入文件: Select path 选择目录 Question The file already exists. Do you want to replace it? Save HTML As... HTML另存为... HTML Files (*.html *.htm) HTML 文件 (*.html *.htm) Set Password 设置密码 Type password 输入密码 Retype password 再次输入密码 <center>Passwords were different. Retry!</center> <center>两次密码不同. 请重试!</center> Enter Password 输入密码 <center>Wrong password. Retry!</center> <center>密码错误. 请重试!</center> A lightweight notes manager 轻量级笔记管理器 based on Qt 基于Qt Author 作者 About FeatherNotes 关于羽毛笔笔记 Translators 翻译 See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. 混号 FeatherNotes::LineEdit Clear text (Ctrl+K) 清除文本 (Ctrl+K) Ctrl+K Clear text Ctrl+K FeatherNotes::PrefDialog Preferences 首选项 Window 窗口 Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! 关闭后保存窗口大小 这个对话框也会退出。 取消选中可设置固定大小! Remember window &size 记住窗口尺寸 Start with this size: 用这个尺寸启动: px px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. 关闭后保存目录宽度 这个对话框也会退出。 取消选中宽度比为170/530。 Remember &tree width 记住目录宽度 Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) 关闭后保存位置 这个对话框也会退出。 (在GTK+ DE's Unity 和 Cinnamon桌面环境下可能无法正常工作) Save &position 保存位置 Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. 是否应使用托盘图标。 如果选中,点击关闭按钮将最小化到 系统托盘而不是退出。 需要重新启动羽毛笔笔记才能生效。 Add to s&ystray 添加到系统托盘 The command line option --tray can be used instead of this. 命令行选项--tray 可以用来代替这个。 Start i&conified to tray 开始图标化到托盘 Merge the tree view with its surroundings? 将树视图与其周围环境合并? Transparent t&ree view 透明目录 By default, the active widget style determines the size of toolbar icons. 默认情况下,活动小部件样式确定 工具栏图标的大小。 Small toolbar icons 工具栏小图标 Do not show t&oolbar 不显示工具栏 If the menubar is hidden, a menu button appears on the toolbar. 如果菜单栏是隐藏的, 工具栏上会出现一个菜单按钮。 Do not show &menubar 不显示菜单栏 Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! 检查在Enlightenment下运行时(或者,可能是另一个DE) 可以更容易地使用托盘图标! Running &under Enlightenment? 在Enlightenment下运行? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! 一些DE(如 Enlightenment)可能不会报告窗口位置 正确地。如果是这样的话,你可以试着在这里解决这个问题。 如果面板位于底部或顶部,则应设置Y坐标; 如果在左侧或右侧,则应设置X坐标。 选择坐标变换后,将窗口放在适当的位置 定位然后重新启动羽毛笔记! Shifts (X × Y): 移位(X×Y): Text 文本 &Wrap lines by default 默认情况下换行 Auto-&indent by default 默认情况下自动缩进 This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. 这包括括号、大括号、括号和引号。 需要重新启动羽毛笔记才能生效。 Auto-&bracket 自动引号 A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. 三个句点替换为省略号, 当用户在适当的情况下打字时, 带有长破折号等的双连字符。 &Replace some characters while typing 键入时替换某些字符 Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every 自动保存间隔 minute(s) 分钟(s) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts 快捷键 Action 功能 Shortcut 快捷键 Default 默认 Warning: Ambiguous shortcut detected! 警告:检测到不明确的快捷键! The typed shortcut was reserved. 已保留键入的快捷键。 Application restart is needed for changes to take effect. 要使更改生效,需要重新启动应用程序。 Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: 替换为: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help 帮助 QObject New Node 新笔记 FeatherNotes-0.8.0/feathernotes/data/translations/feathernotes_zh_HANT.ts000066400000000000000000001751551374721712500266300ustar00rootroot00000000000000 FeatherNotes::AboutDialog License 許可證 FeatherNotes::ColorLabel Click to change color. Select Color FeatherNotes::FN FeatherNotes Next (F3) 下一個 (F3) F3 Previous (F4) 上一個 (F4) F4 Search... 搜尋... Search only in names (Ctrl+Shift+F7) 僅憑名稱搜尋 (Ctrl+Shift+F7) Ctrl+Shift+F7 Search only in tags (Shift+F7) 僅憑標籤搜尋 (Shift+F7) Shift+F7 Search in all nodes (F7) 在全部節點搜尋 (F7) F7 Whole Word (F6) 整字 (F6) Whole Word 整字 F6 Match Case (F5) Match Case F5 &File &Edit For&mat &Tree &Options &Search &Help Find: Replace with: To be replaced Replacing text Previous (F9) F9 Next (F8) F8 Replace all (F10) F10 &Save Save Ctrl+S &Open Open a file Ctrl+O &Undo Undo Ctrl+Z &Redo Redo Ctrl+Shift+Z &Find Show/hide searchbar Ctrl+F &Clear All Formats Clear all formats Ctrl+E &Bold Bold Ctrl+B &Italic Italic Ctrl+I &Underline Underline Ctrl+U &Strike Through Strike through Ctrl+T Te&xt Color Text color Alt+Shift+T Back&ground Color Background color Alt+Shift+B Options &New Note Ctrl+Alt+Shift+N Save &As Ctrl+Shift+S &Print Ctrl+P P&rint with Sub-Nodes Set Pass&word &Quit Ctrl+Q &Cut Ctrl+X C&opy Ctrl+C &Paste Ctrl+V &Delete &Select All Ctrl+A E&mbed Image Embed Image Ctrl+Alt+Shift+I E&xpand All Ctrl+Shift+Down Collap&se All Ctrl+Shift+Up &Append Sibling Ctrl+N Append &Child Ctrl+Shift+N &Delete Node Ctrl+D Move &Up Alt+Up Move Do&wn Alt+Down Re&name Node Ctrl+Shift+R Tree Pr&operties Ctrl+Shift+D Document &Font &Wrap Lines Ctrl+W &Auto-Indentation Ctrl+Shift+I &Preferences Ctrl+Shift+P Find and &Replace Ctrl+R Ctrl+H &About Pr&int All Nodes Superscrip&t Superscript Alt+Shift+U Subscri&pt Subscript Alt+Shift+S C&enter Align center Alt+Shift+Down &Right Align right Alt+Shift+Right &Left Align left Alt+Shift+Left &Justify Justify Alt+Shift+Up &Prepend Sibling Ctrl+M Move &Left Alt+Left Move &Right Alt+Right h&2 Header 2 Ctrl+2 h&1 Header 1 Ctrl+1 h&3 Header 3 Ctrl+3 &Node Font Node Font Scale I&mage(s) Paste &HTML Ctrl+Shift+V &Tags Ctrl+Shift+T Insert Lin&k Ctrl+L C&opy Link I&nsert Table Ctrl+Alt+Shift+T Append Row Delete Row Append Column Delete Column Merge Cells Prepend Row Prepend Column Export &HTML Save Ima&ge(s) RTL Ctrl+Alt+Shift+Left LTR Ctrl+Alt+Shift+Right Menu Node &Icon Ctrl+Shift+C Check Spelling F2 Document &Colors Paste Date and Time Node Icon &Raise/Hide <center><b><big>New note?</big></b></center> <center><i>Do you really want to leave this document</i></center> <center><i>and create an empty one?</i></center> Yes No <center><b><big>Save changes?</big></b></center> <center><i>The document has been modified.</i></center> <center><i>The document has been removed.</i></center> Discard changes Cancel Open file... <center><b><big>Cannot be saved!</big></b></center> Close Save As... <center><b><big>Delete this node?</big></b></center> <center><b><i>Warning!</i></b></center> <center>This action cannot be undone.</center> Tags OK <b>Main nodes:</b> <i>%1</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%2</i> <b>Note:</b> <i>%1</i><br><b>Main nodes:</b> <i>%2</i>&nbsp;&nbsp;&nbsp;&nbsp;<b>All nodes:</b> <i>%3</i> %1 Matches One Match No Match Replacement No Replacement One Replacement %1 Replacements Insert Link Image path Open image Scaling percentage Open Image... &Raise New Node FeatherNotes documents (*.fnx);;All Files (*) Untitled Select Text Color Select Background Color Deletion Tag(s) for this node Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*) Select Document Font Select Node Font Set Document Colors These colors will be applied to new nodes.<br>They may or may not affect existing nodes<br>but document reopening is recommended. Background color: Text color: The first 1000 replacements are highlighted. Scale to % Scale Image(s) untitled Error <center><b><big>Image cannot be saved! Retry?</big></b></center> <center>Maybe you did not choose a proper extension</center> <center>or do not have write permission.</center><p></p> Save Image As... Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*) Insert Table Rows: Columns: Print Document Export HTML Export: &Current node With all &sub-nodes &All nodes Output file: Select path Question The file already exists. Do you want to replace it? Save HTML As... HTML Files (*.html *.htm) Set Password Type password Retype password <center>Passwords were different. Retry!</center> Enter Password <center>Wrong password. Retry!</center> A lightweight notes manager based on Qt Author About FeatherNotes Translators See Preferences → Text → Spell Checking! You need to add a Hunspell dictionary. The Hunspell dictionary does not exist. The Hunspell dictionary is not accompanied by an affix file. No misspelling from text cursor. Spell Checking aka. FeatherNotes::LineEdit Clear text (Ctrl+K) Ctrl+K Clear text FeatherNotes::PrefDialog Preferences Window Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Remember window &size Start with this size: px Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Remember &tree width Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Save &position Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Add to s&ystray The command line option --tray can be used instead of this. Start i&conified to tray Merge the tree view with its surroundings? Transparent t&ree view By default, the active widget style determines the size of toolbar icons. Small toolbar icons Do not show t&oolbar If the menubar is hidden, a menu button appears on the toolbar. Do not show &menubar Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Running &under Enlightenment? Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Shifts (X × Y): Text &Wrap lines by default Auto-&indent by default This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Auto-&bracket A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. &Replace some characters while typing Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: &Auto-save every minute(s) Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: Add dictionary... Files Start with the last opened file Shortcuts 快捷鍵 Action 行為 Shortcut 快捷鍵 Default 默認 Warning: Ambiguous shortcut detected! 警告:檢測到不明確的快捷方式! The typed shortcut was reserved. 輸入的快捷方式已保留。 Application restart is needed for changes to take effect. 變更生效需要程式重新啓動。 Hunspell Dictionary Files (*.dic) FeatherNotes::SpellDialog Unknown word: Add To Dictionary Replace with: Ignore Once Ignore All Correct Once Correct All FeatherNotes::helpDialog Help QObject New Node FeatherNotes-0.8.0/feathernotes/domitem.cpp000066400000000000000000000250501374721712500207520ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #include #include "domitem.h" namespace FeatherNotes { DomItem::DomItem (QDomNode &node, int row, DomItem *parent) { domNode = node; // Record the item's location within its parent. rowNumber = row; parentItem = parent; } /*************************/ DomItem::~DomItem() { QHash::iterator it; for (it = childItems.begin(); it != childItems.end(); ++it) delete it.value(); } /*************************/ QDomNode DomItem::node() const { return domNode; } /*************************/ DomItem *DomItem::parent() { return parentItem; } /*************************/ DomItem *DomItem::child (int i) { if (childItems.contains (i)) return childItems[i]; int k = 0; QDomNodeList list; /* when this node is a QDomDocument... */ if (!domNode.firstChildElement ("feathernotes").isNull()) /* ... find the children of */ list = domNode.firstChildElement ("feathernotes").childNodes(); else { list = domNode.childNodes(); /* if there's a text, it'll be the first child */ if (!list.isEmpty() && !list.at (0).isElement()) k = 1; } if (i >= 0 && i + k < list.count()) { QDomNode childNode = list.item (i + k); DomItem *childItem = new DomItem (childNode, i, this); childItems[i] = childItem; return childItem; } return nullptr; } /*************************/ int DomItem::childCount() { int N = 0; while (child (N)) ++N; return N; } /*************************/ int DomItem::row() { return rowNumber; } /*************************/ void DomItem::addChild (DomItem *item) { QDomNode itemNode; if (item) itemNode = item->node(); else { /*QDomElement e = QDomDocument().createElement ("node"); e.setAttribute ("name", "New Node");*/ QDomDocument doc; doc.setContent (QString (""), false); itemNode = doc.documentElement(); } int k = 0; QDomNodeList list; if (!domNode.firstChildElement ("feathernotes").isNull()) { domNode.firstChildElement ("feathernotes").appendChild (itemNode); list = domNode.firstChildElement ("feathernotes").childNodes(); } else { domNode.appendChild (itemNode); list = domNode.childNodes(); if (!list.isEmpty() && !list.at (0).isElement()) k = 1; } if (item) { childItems[list.count() - k - 1] = item; childItems[list.count() - k - 1]->rowNumber = list.count() - k - 1; childItems[list.count() - k - 1]->parentItem = this; } } /*************************/ void DomItem::insertAt (int n, DomItem *item) { if (n < 0 || n >= childCount()) return; QDomNode itemNode; if (item) itemNode = item->node(); else { QDomDocument doc; doc.setContent (QString (""), false); itemNode = doc.documentElement(); } int k = 0; QDomNodeList list; if (!domNode.firstChildElement ("feathernotes").isNull()) { domNode.firstChildElement ("feathernotes").insertBefore (itemNode, child (n)->node()); list = domNode.firstChildElement ("feathernotes").childNodes(); } else { domNode.insertBefore (itemNode, child (n)->node()); list = domNode.childNodes(); if (!list.isEmpty() && !list.at (0).isElement()) k = 1; } /* back up the nth value before creating it anew */ DomItem *tmp = childItems[n]; if (!item) { QDomNode childNode = list.item (n + k); DomItem *childItem = new DomItem (childNode, n, this); childItems[n] = childItem; } else { childItems[n] = item; childItems[n]->rowNumber = n; childItems[n]->parentItem = this; } /* now, move down the values for all indexes > n */ DomItem* tmp1 = nullptr; for (int i = n + 1; i + k < list.count(); ++i) { if (childItems.contains (i)) { tmp1 = childItems[i]; childItems[i] = tmp; tmp = tmp1; } else // the last index childItems[i] = tmp; /* we only need to correct the row number */ childItems[i]->rowNumber = i; } } /*************************/ void DomItem::moveUp (int n) { if (n <= 0 || n >= childCount()) return; if (!domNode.firstChildElement ("feathernotes").isNull()) domNode.firstChildElement ("feathernotes").insertBefore (child (n)->node(), child (n - 1)->node()); else domNode.insertBefore (child (n)->node(), child (n - 1)->node()); DomItem *tmp = childItems[n - 1]; childItems[n - 1] = childItems[n]; childItems[n - 1]->rowNumber = n - 1; childItems[n] = tmp; childItems[n]->rowNumber = n; } /*************************/ // Move the nth child of this item above it as its sibling. void DomItem::moveLeft (int n) { if (n < 0 || n >= childCount()) return; DomItem *p = parent(); /* do nothing if this is the root row */ if (!p) return; int pK = 0; QDomNodeList pList; if (!p->domNode.firstChildElement ("feathernotes").isNull()) { p->domNode.firstChildElement ("feathernotes").insertBefore (child (n)->node(), domNode); pList = p->domNode.firstChildElement ("feathernotes").childNodes(); } else { p->domNode.insertBefore (child (n)->node(), domNode); pList = p->domNode.childNodes(); if (!pList.isEmpty() && !pList.at (0).isElement()) pK = 1; } int k = 0; QDomNodeList list = domNode.childNodes(); if (!list.isEmpty() && !list.at (0).isElement()) k = 1; /******************************** The child should be removed. See takeChild() below. ********************************/ /* first, back up the first child */ DomItem *del = childItems[n]; for (int i = n; i + k < list.count(); ++i) { childItems[i] = childItems[i + 1]; childItems[i]->rowNumber = i; } childItems.remove (list.count() - k); /********************************* A child should be inserted into the parent's children at row(). See insertAt() above. *********************************/ /* back up the item at row() */ DomItem *tmp = p->childItems[row()]; /* replace the item at row() with the backed-up first child and correct its member variables */ p->childItems[row()] = del; p->childItems[row()]->parentItem = p; p->childItems[row()]->rowNumber = row(); DomItem* tmp1 = nullptr; for (int i = row() + 1; i + pK < pList.count(); ++i) { if (p->childItems.contains (i)) { tmp1 = p->childItems[i]; p->childItems[i] = tmp; tmp = tmp1; } else p->childItems[i] = tmp; p->childItems[i]->rowNumber = i; } } /*************************/ void DomItem::moveDown (int n) { if (n < 0 || n >= childCount() - 1) return; if (!domNode.firstChildElement ("feathernotes").isNull()) domNode.firstChildElement ("feathernotes").insertAfter (child (n)->node(), child (n + 1)->node()); else domNode.insertAfter (child (n)->node(), child (n + 1)->node()); DomItem *tmp = childItems[n]; childItems[n] = childItems[n + 1]; childItems[n]->rowNumber = n; childItems[n + 1] = tmp; childItems[n + 1]->rowNumber = n + 1; } /*************************/ // Make the nth child of this item the last child of the child above it. void DomItem::moveRight (int n) { if (n <= 0 || n >= childCount()) return; child (n - 1)->node().appendChild (child (n)->node()); // or: childItems[n - 1]->domNode.appendChild (childItems[n]->domNode); int k = 0; QDomNodeList list; if (!domNode.firstChildElement ("feathernotes").isNull()) list = domNode.firstChildElement ("feathernotes").childNodes(); else { list = domNode.childNodes(); if (!list.isEmpty() && !list.at (0).isElement()) k = 1; } int cK = 0; QDomNodeList cList = child (n - 1)->node().childNodes(); if (!cList.isEmpty() && !cList.at (0).isElement()) cK = 1; /***************************** The node should be removed *****************************/ DomItem *del = childItems.value (n); /* now, move up the values for all indexes >= n */ for (int i = n; i + k < list.count(); ++i) { childItems[i] = childItems[i + 1]; childItems[i]->rowNumber = i; } childItems.remove (list.count() - k); /************************************** A child should be inserted after all children of the node above this one. **************************************/ child (n - 1)->childItems[cList.count() - cK - 1] = del; child (n - 1)->childItems[cList.count() - cK - 1]->parentItem = child (n - 1); child (n - 1)->childItems[cList.count() - cK - 1]->rowNumber = cList.count() - cK - 1; } /*************************/ DomItem *DomItem::takeChild (int n) { if (n < 0 || n >= childCount()) return nullptr; int k = 0; QDomNodeList list; if (!domNode.firstChildElement ("feathernotes").isNull()) { domNode.firstChildElement ("feathernotes").removeChild (child (n)->node()); list = domNode.firstChildElement ("feathernotes").childNodes(); } else { domNode.removeChild (child (n)->node()); list = domNode.childNodes(); if (!list.isEmpty() && !list.at (0).isElement()) k = 1; } DomItem *res = childItems.value (n); /* now, move up the values for all indexes >= n */ for (int i = n; i + k < list.count(); ++i) { childItems[i] = childItems[i + 1]; childItems[i]->rowNumber = i; } childItems.remove (list.count() - k); return res; } } FeatherNotes-0.8.0/feathernotes/domitem.h000066400000000000000000000025761374721712500204270ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef DOMITEM_H #define DOMITEM_H #include #include namespace FeatherNotes { class DomItem { public: DomItem (QDomNode &node, int row, DomItem *parent = nullptr); ~DomItem(); DomItem *child (int i); int childCount(); DomItem *parent(); QDomNode node() const; int row(); void addChild (DomItem *item); void insertAt (int n, DomItem *item); void moveUp (int n); void moveLeft (int n); void moveDown (int n); void moveRight (int n); DomItem *takeChild(int n); private: QDomNode domNode; QHash childItems; DomItem *parentItem; int rowNumber; }; } #endif // DOMITEM_H FeatherNotes-0.8.0/feathernotes/dommodel.cpp000066400000000000000000000263361374721712500211240ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #include #include #include "domitem.h" #include "dommodel.h" namespace FeatherNotes { DomModel::DomModel (QDomDocument document, QObject *parent) : QAbstractItemModel (parent), domDocument (document), dropIndex_ (QModelIndex()), dropRow_ (-1), dragged_ (nullptr) { rootItem_ = new DomItem (domDocument, 0); } /*************************/ DomModel::~DomModel() { delete rootItem_; } /*************************/ int DomModel::columnCount (const QModelIndex &/*parent*/) const { return 1; } /*************************/ QVariant DomModel::data (const QModelIndex &indx, int role) const { if (!indx.isValid()) return QVariant(); if (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::DecorationRole) return QVariant(); DomItem *item = static_cast(indx.internalPointer()); QDomNode node = item->node(); /*QTextStream out (stdout); out << node.nodeType() << "\n";*/ QDomNamedNodeMap attributeMap = node.attributes(); if (indx.column() == 0) { if (role == Qt::DecorationRole) { QString str = attributeMap.namedItem ("icon").nodeValue(); if (str.isEmpty()) return QVariant(); QImage image; image.loadFromData (QByteArray::fromBase64 (str.toUtf8())); return QVariant (QIcon (QPixmap::fromImage (image))); } return attributeMap.namedItem ("name").nodeValue(); } else return QVariant(); } /*************************/ bool DomModel::setData (const QModelIndex &indx, const QVariant &value, int role) { if (indx.isValid() && role == Qt::EditRole) { DomItem *item = static_cast(indx.internalPointer()); QDomNode node = item->node(); QDomNamedNodeMap attributeMap = node.attributes(); QString str = value.toString(); if (attributeMap.namedItem ("name").nodeValue() != str) { attributeMap.namedItem ("name").setNodeValue (str); emit dataChanged (indx, indx); return true; } } return false; } /*************************/ Qt::ItemFlags DomModel::flags (const QModelIndex &indx) const { if (!indx.isValid()) return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled; return QAbstractItemModel::flags (indx) | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } /*************************/ QModelIndex DomModel::index (int row, int column, const QModelIndex &parent) const { if (!hasIndex (row, column, parent)) return QModelIndex(); DomItem *parentItem; if (!parent.isValid()) parentItem = rootItem_; else parentItem = static_cast(parent.internalPointer()); DomItem *childItem = parentItem->child (row); if (childItem) return createIndex (row, column, childItem); else return QModelIndex(); } /*************************/ QModelIndex DomModel::parent (const QModelIndex &child) const { if (!child.isValid()) return QModelIndex(); DomItem *childItem = static_cast(child.internalPointer()); DomItem *parentItem = childItem->parent(); if (parentItem == rootItem_) return QModelIndex(); return createIndex (parentItem->row(), 0, parentItem); } /*************************/ int DomModel::rowCount (const QModelIndex &parent) const { if (parent.column() > 0) return 0; DomItem *parentItem; if (!parent.isValid()) parentItem = rootItem_; else parentItem = static_cast(parent.internalPointer()); return parentItem->childCount(); } /*************************/ bool DomModel::insertRows (int row, int count, const QModelIndex &parent) { if (row < 0) return true; emit layoutAboutToBeChanged(); beginInsertRows (parent, row, row + count - 1); DomItem *parentItem; if (!parent.isValid()) parentItem = rootItem_; else parentItem = static_cast(parent.internalPointer()); if (rowCount (parent) == 0 || row >= rowCount (parent)) { for (int i = 0; i < count; ++i) parentItem->addChild (dragged_); } else// if (row < rowCount (parent)) { for (int i = 0; i < count; ++i) parentItem->insertAt (row, dragged_); } endInsertRows(); /* we need this because the nodes may be nested */ emit layoutChanged(); emit treeChanged(); if (dropRow_ > -1) { emit droppedAtIndex (index (dropRow_, 0, parent)); // announce the DND end /* DND is finished; reset its variables */ dropRow_ = -1; dropIndex_ = QModelIndex(); dragged_ = nullptr; } return true; } /*************************/ bool DomModel::removeRows (int row, int count, const QModelIndex &parent) { if (row < 0 || rowCount (parent) == 0) return true; /* workaround for Qt's drop indicator pointing to an incorrect position */ if (dropRow_ > row && dropIndex_ == parent) --dropRow_; /* no redundant operation */ if (dropRow_ == row && dropIndex_ == parent) return true; if (dropRow_ > -1) emit dragStarted (index (dropRow_, 0, parent)); // announce the DND start beginRemoveRows (parent, row, row + count - 1); DomItem *parentItem; if (!parent.isValid()) parentItem = rootItem_; else parentItem = static_cast(parent.internalPointer()); for (int k = 0; k < count; ++k) { /* maybe it's about DND */ dragged_ = parentItem->takeChild (row + (count - 1 - k)); if (dropRow_ == -1) { /* no DND but deletion */ delete dragged_; dragged_ = nullptr; } } endRemoveRows(); emit treeChanged(); if (dropRow_ > -1) insertRows (dropRow_, 1, dropIndex_); return true; } /*************************/ bool DomModel::moveUpRow (int row, const QModelIndex &parent) { if (row <= 0 || rowCount (parent) == 0) return true; beginMoveRows (parent, row, row, parent, row - 1); DomItem *parentItem; if (!parent.isValid()) parentItem = rootItem_; else parentItem = static_cast(parent.internalPointer()); parentItem->moveUp (row); endMoveRows(); emit treeChanged(); return true; } /*************************/ bool DomModel::moveLeftRow (int row, const QModelIndex &parent) { if (row < 0 || rowCount (parent) == 0) return true; /* move this row above its parent */ beginMoveRows (parent, row, row, parent.parent(), parent.row()); DomItem *parentItem; if (!parent.isValid()) parentItem = rootItem_; else parentItem = static_cast(parent.internalPointer()); parentItem->moveLeft (row); endMoveRows(); emit treeChanged(); return true; } /*************************/ bool DomModel::moveDownRow (int row, const QModelIndex &parent) { if (row < 0 || rowCount (parent) == 0 || row == rowCount (parent) - 1) return true; beginMoveRows (parent, row + 1, row + 1, parent, row); DomItem *parentItem; if (!parent.isValid()) parentItem = rootItem_; else parentItem = static_cast(parent.internalPointer()); parentItem->moveDown (row); endMoveRows(); emit treeChanged(); return true; } /*************************/ bool DomModel::moveRightRow (int row, const QModelIndex &parent) { if (row <= 0 || rowCount (parent) == 0) return true; /* move this row to the bottom of its above node's children */ QModelIndex aboveIndex = index (row - 1, 0, parent); beginMoveRows (parent, row, row, aboveIndex, rowCount (aboveIndex)); DomItem *parentItem; if (!parent.isValid()) parentItem = rootItem_; else parentItem = static_cast(parent.internalPointer()); parentItem->moveRight (row); endMoveRows(); emit treeChanged(); return true; } /*************************/ Qt::DropActions DomModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } /*************************/ bool DomModel::dropMimeData (const QMimeData*, Qt::DropAction action, int row, int column, const QModelIndex &parent) { if (action == Qt::IgnoreAction) return true; if (column > 0) return false; /* here we just set DND variables because we want removeRows() to be called before insertRows() */ if (row == -1) dropRow_ = 0; else dropRow_ = row; dropIndex_ = parent; return true; } /*************************/ // Give a list of all descendants of a valid index. // The farther is a descendant, the greater is its index position in the list. QModelIndexList DomModel::allDescendants (const QModelIndex &ancestor) const { QModelIndexList descendants; if (!ancestor.isValid()) return descendants; // empty for (int i = 0; i < rowCount (ancestor) ; ++i) descendants << index (i, 0, ancestor); for (int i = 0; i < descendants.count(); ++i) descendants << allDescendants (descendants[i]); return descendants; } /*************************/ // Find the visually "adjacent" node of this node in the tree. QModelIndex DomModel::adjacentIndex (const QModelIndex &indx, bool down) const { QModelIndex rslt; if (down) { /* if this index has a child, return it... */ if (hasChildren (indx)) return index (0, 0, indx); else // ... otherwise, see if it has a lower sibling... { if (!(rslt = sibling (indx.row() + 1, 0, indx)).isValid()) { /* ... and if it doesn't have any, go to its parent and search for its next sibling */ QModelIndex p; if (!(p = parent (indx)).isValid()) return QModelIndex(); while (!(rslt = sibling (p.row() + 1, 0, p)).isValid()) { if (!(p = parent (p)).isValid()) return QModelIndex(); } } } } else { /* see if this index has an upper sibling... */ if (!(rslt = sibling (indx.row() - 1, 0, indx)).isValid()) rslt = parent (indx); else // .. and if it does, return its farthest descendant { QModelIndexList list = allDescendants (rslt); if (list.isEmpty()) list << rslt; rslt = list.last(); } } return rslt; } } FeatherNotes-0.8.0/feathernotes/dommodel.h000066400000000000000000000053601374721712500205630ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef DOMMODEL_H #define DOMMODEL_H #include #include #include #include namespace FeatherNotes { class DomItem; class DomModel : public QAbstractItemModel { Q_OBJECT public: DomModel (QDomDocument document, QObject *parent = nullptr); ~DomModel(); QVariant data (const QModelIndex &indx, int role) const; bool setData (const QModelIndex &indx, const QVariant &value, int role = Qt::EditRole); Qt::ItemFlags flags (const QModelIndex &indx) const; QModelIndex index (int row, int column, const QModelIndex &parent = QModelIndex()) const; QModelIndex parent (const QModelIndex &child) const; int rowCount (const QModelIndex &parent = QModelIndex()) const; int columnCount (const QModelIndex &parent = QModelIndex()) const; bool insertRows (int row, int count, const QModelIndex &parent = QModelIndex()); bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()); bool moveUpRow (int row, const QModelIndex &parent = QModelIndex()); bool moveLeftRow (int row, const QModelIndex &parent = QModelIndex()); bool moveDownRow (int row, const QModelIndex &parent = QModelIndex()); bool moveRightRow (int row, const QModelIndex &parent = QModelIndex()); Qt::DropActions supportedDropActions() const; bool dropMimeData (const QMimeData*, Qt::DropAction action, int row, int column, const QModelIndex &parent); QModelIndexList allDescendants (const QModelIndex &ancestor) const; QModelIndex adjacentIndex (const QModelIndex &indx, bool down) const; QDomDocument domDocument; signals: void treeChanged(); // For informing the user. void dragStarted (const QModelIndex &draggedIndex); // The index isn't needed but is used as a safeguard. void droppedAtIndex (const QModelIndex &droppedIndex); private: DomItem *rootItem_; /* DND variables: */ QModelIndex dropIndex_; int dropRow_; DomItem *dragged_; }; } #endif // DOMMODEL_H FeatherNotes-0.8.0/feathernotes/feathernotes.pro000066400000000000000000000071611374721712500220240ustar00rootroot00000000000000QT += core gui \ xml \ widgets \ printsupport \ svg haiku|macx { TARGET = FeatherNotes } else { TARGET = feathernotes } TEMPLATE = app CONFIG += c++11 SOURCES += main.cpp \ colorLabel.cpp \ fn.cpp \ find.cpp \ domitem.cpp \ dommodel.cpp \ lineedit.cpp \ pref.cpp \ textedit.cpp \ simplecrypt.cpp \ vscrollbar.cpp \ svgicons.cpp HEADERS += fn.h \ colorLabel.h \ domitem.h \ dommodel.h \ textedit.h \ lineedit.h \ pref.h \ spinbox.h \ simplecrypt.h \ vscrollbar.h \ settings.h \ help.h \ filedialog.h \ treeview.h \ messagebox.h \ svgicons.h FORMS += fn.ui \ prefDialog.ui \ helpDialog.ui \ about.ui RESOURCES += data/fn.qrc contains(WITHOUT_X11, YES) { message("Compiling without X11...") } else:unix:!macx:!haiku { QT += x11extras SOURCES += x11.cpp HEADERS += x11.h LIBS += -lX11 DEFINES += HAS_X11 } contains(WITH_HUNSPELL, YES) { LIBS += -lhunspell SOURCES += spellDialog.cpp spellChecker.cpp HEADERS += spellDialog.h spellChecker.h FORMS += spellDialog.ui DEFINES += HAS_HUNSPELL } unix { #TRANSLATIONS exists($$[QT_INSTALL_BINS]/lrelease) { TRANSLATIONS = $$system("find data/translations/ -name 'feathernotes_*.ts'") updateqm.input = TRANSLATIONS updateqm.output = data/translations/translations/${QMAKE_FILE_BASE}.qm updateqm.commands = $$[QT_INSTALL_BINS]/lrelease ${QMAKE_FILE_IN} -qm data/translations/translations/${QMAKE_FILE_BASE}.qm updateqm.CONFIG += no_link target_predeps QMAKE_EXTRA_COMPILERS += updateqm } } else:win32 { #TRANSLATIONS exists($$[QT_INSTALL_BINS]/lrelease.exe) { TRANSLATIONS = $$system("dir /b /S feathernotes_*.ts") updateqm.input = TRANSLATIONS updateqm.output = data\\translations\\translations\\${QMAKE_FILE_BASE}.qm updateqm.commands = $$[QT_INSTALL_BINS]/lrelease ${QMAKE_FILE_IN} -qm data\\translations\\translations\\${QMAKE_FILE_BASE}.qm updateqm.CONFIG += no_link target_predeps QMAKE_EXTRA_COMPILERS += updateqm } } unix:!macx:!haiku { #VARIABLES isEmpty(PREFIX) { PREFIX = /usr } BINDIR = $$PREFIX/bin DATADIR =$$PREFIX/share DEFINES += DATADIR=\\\"$$DATADIR\\\" PKGDATADIR=\\\"$$PKGDATADIR\\\" #MAKE INSTALL target.path =$$BINDIR mime.path = $$DATADIR/mime/packages mime.files += ./data/$${TARGET}.xml desktop.path = $$DATADIR/applications desktop.files += ./data/$${TARGET}.desktop appIcon.path = $$DATADIR/icons/hicolor/scalable/apps appIcon.files += ./data/$${TARGET}.svg fileIcon.path = $$DATADIR/icons/hicolor/scalable/mimetypes fileIcon.files += ./data/text-feathernotes-fnx.svg trans.path = $$DATADIR/feathernotes trans.files += data/translations/translations INSTALLS += target mime desktop appIcon fileIcon trans } else:macx { #VARIABLES isEmpty(PREFIX) { PREFIX = /Applications/ } BINDIR = $$PREFIX DATADIR = "$$BINDIR/$$TARGET".app DEFINES += DATADIR=\\\"$$DATADIR\\\" PKGDATADIR=\\\"$$PKGDATADIR\\\" #MAKE INSTALL target.path =$$BINDIR trans.path = $$DATADIR/feathernotes trans.files += data/translations/translations INSTALLS += target trans } else:haiku { #VARIABLES isEmpty(PREFIX) { PREFIX = /boot/home/config/non-packaged/apps/FeatherNotes } BINDIR = $$PREFIX #MAKE INSTALL target.path =$$BINDIR trans.path = $$PREFIX trans.files += data/translations/translations INSTALLS += target trans } FeatherNotes-0.8.0/feathernotes/filedialog.h000066400000000000000000000040221374721712500210540ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef FILEDIALOG_H #define FILEDIALOG_H #include #include #include namespace FeatherNotes { /* We want auto-scrolling to selected file. */ class FileDialog : public QFileDialog { Q_OBJECT public: FileDialog (QWidget *parent) : QFileDialog (parent) { tView = nullptr; p = parent; setViewMode (QFileDialog::Detail); //setOption (QFileDialog::DontUseNativeDialog); } void autoScroll() { tView = findChild("treeView"); if (tView) connect (tView->model(), &QAbstractItemModel::layoutChanged, this, &FileDialog::scrollToSelection); } protected: void showEvent(QShowEvent * event) { if (p) QTimer::singleShot (0, this, &FileDialog::center); QFileDialog::showEvent (event); } private slots: void scrollToSelection() { if (tView) { QModelIndexList iList = tView->selectionModel()->selectedIndexes(); if (!iList.isEmpty()) tView->scrollTo (iList.at (0), QAbstractItemView::PositionAtCenter); } } void center() { move (p->x() + p->width()/2 - width()/2, p->y() + p->height()/2 - height()/ 2); } private: QTreeView *tView; QWidget *p; }; } #endif // FILEDIALOG_H FeatherNotes-0.8.0/feathernotes/find.cpp000066400000000000000000000524411374721712500202400ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #include "fn.h" #include "ui_fn.h" #include "dommodel.h" #include #include namespace FeatherNotes { /************************************************************************ ***** Qt's backward search has some bugs. Therefore, we do our own ***** ***** backward search by using the following two static functions. ***** ************************************************************************/ static bool findBackwardInBlock (const QTextBlock &block, const QString &str, int offset, QTextCursor &cursor, QTextDocument::FindFlags flags) { Qt::CaseSensitivity cs = !(flags & QTextDocument::FindCaseSensitively) ? Qt::CaseInsensitive : Qt::CaseSensitive; QString text = block.text(); text.replace (QChar::Nbsp, QLatin1Char (' ')); /* WARNING: QString::lastIndexOf() returns -1 if the position, from which the backward search is done, is the position of the block's last cursor. The following workaround compensates for this illogical behavior. */ if (offset > 0 && offset == text.length()) -- offset; int idx = -1; while (offset >= 0 && offset <= text.length()) { idx = text.lastIndexOf (str, offset, cs); if (idx == -1) return false; if (flags & QTextDocument::FindWholeWords) { const int start = idx; const int end = start + str.length(); if ((start != 0 && text.at (start - 1).isLetterOrNumber()) || (end != text.length() && text.at (end).isLetterOrNumber())) { // if this is not a whole word, continue the backward search offset = idx - 1; idx = -1; continue; } } cursor.setPosition (block.position() + idx); cursor.setPosition (cursor.position() + str.length(), QTextCursor::KeepAnchor); return true; } return false; } static bool findBackward (const QTextDocument *txtdoc, const QString &str, QTextCursor &cursor, QTextDocument::FindFlags flags) { if (!str.isEmpty() && !cursor.isNull()) { int pos = cursor.anchor() - str.size(); // we don't want a match with the cursor inside it if (pos >= 0) { QTextBlock block = txtdoc->findBlock (pos); int blockOffset = pos - block.position(); while (block.isValid()) { if (findBackwardInBlock (block, str, blockOffset, cursor, flags)) return true; block = block.previous(); blockOffset = block.length() - 1; // newline is included in QTextBlock::length() } } } cursor = QTextCursor(); return false; } /*************************/ // This method extends the searchable strings to those with line breaks. // It also corrects the behavior of Qt's backward search. QTextCursor FN::finding (const QString& str, const QTextCursor& start, QTextDocument::FindFlags flags) const { /* let's be consistent first */ if (ui->stackedWidget->currentIndex() == -1 || str.isEmpty()) return QTextCursor(); // null cursor TextEdit *textEdit = qobject_cast< TextEdit *>(ui->stackedWidget->currentWidget()); QTextDocument *txtdoc = textEdit->document(); QTextCursor res = QTextCursor (start); if (str.contains ('\n')) { QTextCursor cursor = start; QTextCursor found; QStringList sl = str.split ("\n"); int i = 0; Qt::CaseSensitivity cs = !(flags & QTextDocument::FindCaseSensitively) ? Qt::CaseInsensitive : Qt::CaseSensitive; QString subStr; if (!(flags & QTextDocument::FindBackward)) { /* this loop searches for the consecutive occurrences of newline separated strings */ while (i < sl.count()) { if (i == 0) // the first string { subStr = sl.at (0); /* when the first string is empty... */ if (subStr.isEmpty()) { /* ... search anew from the next block */ cursor.movePosition (QTextCursor::EndOfBlock); res.setPosition (cursor.position()); if (!cursor.movePosition (QTextCursor::NextBlock)) return QTextCursor(); ++i; } else { if ((found = txtdoc->find (subStr, cursor, flags)).isNull()) return QTextCursor(); cursor.setPosition (found.position()); /* if the match doesn't end the block... */ while (!cursor.atBlockEnd()) { /* ... move the cursor to right and search until a match is found */ cursor.movePosition (QTextCursor::EndOfBlock); cursor.setPosition (cursor.position() - subStr.length()); if ((found = txtdoc->find (subStr, cursor, flags)).isNull()) return QTextCursor(); cursor.setPosition (found.position()); } res.setPosition (found.anchor()); if (!cursor.movePosition (QTextCursor::NextBlock)) return QTextCursor(); ++i; } } else if (i != sl.count() - 1) // middle strings { /* when the next block's test isn't the next string... */ if (QString::compare (cursor.block().text(), sl.at (i), cs) != 0) { /* ... reset the loop cautiously */ cursor.setPosition (res.position()); if (!cursor.movePosition (QTextCursor::NextBlock)) return QTextCursor(); i = 0; continue; } if (!cursor.movePosition (QTextCursor::NextBlock)) return QTextCursor(); ++i; } else // the last string (i == sl.count() - 1) { subStr = sl.at (i); if (subStr.isEmpty()) break; if (!(flags & QTextDocument::FindWholeWords)) { /* when the last string doesn't start the next block... */ if (!cursor.block().text().startsWith (subStr, cs)) { /* ... reset the loop cautiously */ cursor.setPosition (res.position()); if (!cursor.movePosition (QTextCursor::NextBlock)) return QTextCursor(); i = 0; continue; } cursor.setPosition (cursor.anchor() + subStr.count()); break; } else { if ((found = txtdoc->find (subStr, cursor, flags)).isNull() || found.anchor() != cursor.position()) { cursor.setPosition (res.position()); if (!cursor.movePosition (QTextCursor::NextBlock)) return QTextCursor(); i = 0; continue; } cursor.setPosition (found.position()); break; } } } res.setPosition (cursor.position(), QTextCursor::KeepAnchor); } else // backward search { cursor.setPosition (cursor.anchor()); int endPos = cursor.position(); while (i < sl.count()) { if (i == 0) // the last string { subStr = sl.at (sl.count() - 1); if (subStr.isEmpty()) { cursor.movePosition (QTextCursor::StartOfBlock); endPos = cursor.position(); if (!cursor.movePosition (QTextCursor::PreviousBlock)) return QTextCursor(); cursor.movePosition (QTextCursor::EndOfBlock); ++i; } else { if (!findBackward (txtdoc, subStr, cursor, flags)) return QTextCursor(); /* if the match doesn't start the block... */ while (cursor.anchor() > cursor.block().position()) { /* ... move the cursor to left and search backward until a match is found */ cursor.setPosition (cursor.block().position() + subStr.count()); if (!findBackward (txtdoc, subStr, cursor, flags)) return QTextCursor(); } endPos = cursor.position(); if (!cursor.movePosition (QTextCursor::PreviousBlock)) return QTextCursor(); cursor.movePosition (QTextCursor::EndOfBlock); ++i; } } else if (i != sl.count() - 1) // the middle strings { if (QString::compare (cursor.block().text(), sl.at (sl.count() - i - 1), cs) != 0) { // reset the loop if the block text doesn't match cursor.setPosition (endPos); if (!cursor.movePosition (QTextCursor::PreviousBlock)) return QTextCursor(); cursor.movePosition (QTextCursor::EndOfBlock); i = 0; continue; } if (!cursor.movePosition (QTextCursor::PreviousBlock)) return QTextCursor(); cursor.movePosition (QTextCursor::EndOfBlock); ++i; } else // the first string { subStr = sl.at (0); if (subStr.isEmpty()) break; if (!(flags & QTextDocument::FindWholeWords)) { /* when the first string doesn't end the previous block... */ if (!cursor.block().text().endsWith (subStr, cs)) { /* ... reset the loop */ cursor.setPosition (endPos); if (!cursor.movePosition (QTextCursor::PreviousBlock)) return QTextCursor(); cursor.movePosition (QTextCursor::EndOfBlock); i = 0; continue; } cursor.setPosition (cursor.anchor() - subStr.count()); break; } else { found = cursor; // block end if (!findBackward (txtdoc, subStr, found, flags) || found.position() != cursor.position()) { cursor.setPosition (endPos); if (!cursor.movePosition (QTextCursor::PreviousBlock)) return QTextCursor(); cursor.movePosition (QTextCursor::EndOfBlock); i = 0; continue; } cursor.setPosition (found.anchor()); break; } } } res.setPosition (cursor.anchor()); res.setPosition (endPos, QTextCursor::KeepAnchor); } } else // there's no line break { if (!(flags & QTextDocument::FindBackward)) res = txtdoc->find (str, start, flags); else findBackward (txtdoc, str, res, flags); } return res; } /*************************/ void FN::find() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; if (ui->tagsButton->isChecked()) { findInTags(); return; } else closeTagsDialog(); if (ui->namesButton->isChecked()) { findInNames(); return; } TextEdit *textEdit = qobject_cast< TextEdit *>(cw); disconnect (textEdit->verticalScrollBar(), &QAbstractSlider::valueChanged, this, &FN::scrolled); disconnect (textEdit->horizontalScrollBar(), &QAbstractSlider::valueChanged, this, &FN::scrolled); disconnect (textEdit, &TextEdit::resized, this, &FN::hlight); disconnect (textEdit, &QTextEdit::textChanged, this, &FN::hlight); QString txt = ui->lineEdit->text(); searchEntries_[textEdit] = txt; if (txt.isEmpty()) { /* remove all yellow and green highlights */ QList extraSelections; greenSels_[textEdit] = extraSelections; // not needed textEdit->setExtraSelections (extraSelections); return; } bool backwardSearch = false; QTextCursor start = textEdit->textCursor(); if (QObject::sender() == ui->prevButton) { backwardSearch = true; if (searchingOtherNode_) start.movePosition (QTextCursor::End, QTextCursor::MoveAnchor); } else // Next button or Enter is pressed { if (searchingOtherNode_) start.movePosition (QTextCursor::Start, QTextCursor::MoveAnchor); } searchingOtherNode_ = false; reallySetSearchFlags (false); QTextDocument::FindFlags newFlags = searchFlags_; if (backwardSearch) newFlags = searchFlags_ | QTextDocument::FindBackward; QTextCursor found = finding (txt, start, newFlags); QModelIndex nxtIndx; if (found.isNull()) { if (!ui->everywhereButton->isChecked() || model_->rowCount() == 1) { if (backwardSearch) start.movePosition (QTextCursor::End, QTextCursor::MoveAnchor); else start.movePosition (QTextCursor::Start, QTextCursor::MoveAnchor); found = finding (txt, start, newFlags); } else { /* go to the next node... */ nxtIndx = ui->treeView->currentIndex(); QString text; /* ... but skip nodes that don't contain the search string */ Qt::CaseSensitivity cs = Qt::CaseInsensitive; if (ui->caseButton->isChecked()) cs = Qt::CaseSensitive; while (!text.contains (txt, cs)) { nxtIndx = model_->adjacentIndex (nxtIndx, !backwardSearch); if (!nxtIndx.isValid()) { // search again from the first/last index if (!backwardSearch) nxtIndx = model_->index (0, 0); else nxtIndx = model_->index (model_->rowCount() - 1, 0); } DomItem *item = static_cast(nxtIndx.internalPointer()); if (TextEdit *thisTextEdit = widgets_.value (item)) text = thisTextEdit->toPlainText(); // the node text may have been edited else { QDomNodeList list = item->node().childNodes(); text = list.item (0).nodeValue(); } if (nxtIndx == ui->treeView->currentIndex()) { // the current index is reached again; stop the search if (!text.contains (txt, cs)) nxtIndx = QModelIndex(); break; } } } } if (!found.isNull()) { start.setPosition (found.anchor()); start.setPosition (found.position(), QTextCursor::KeepAnchor); textEdit->setTextCursor (start); } /* matches highlights should come here, after the text area is scrolled */ hlight(); connect (textEdit->verticalScrollBar(), &QAbstractSlider::valueChanged, this, &FN::scrolled); connect (textEdit->horizontalScrollBar(), &QAbstractSlider::valueChanged, this, &FN::scrolled); connect (textEdit, &TextEdit::resized, this, &FN::hlight); connect (textEdit, &QTextEdit::textChanged, this, &FN::hlight); if (nxtIndx.isValid()) { searchingOtherNode_ = true; ui->treeView->setCurrentIndex (nxtIndx); // selChanged() is called immediately textEdit = qobject_cast< TextEdit *>(ui->stackedWidget->currentWidget()); ui->lineEdit->setText (txt); searchEntries_[textEdit] = txt; find(); } } /*************************/ // Highlight found matches in the visible part of the text. void FN::hlight() const { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); const QString txt = searchEntries_[textEdit]; if (txt.isEmpty()) return; QList extraSelections; /* prepend green highlights */ extraSelections.append (greenSels_[textEdit]); QColor yellow = qGray(fgColor_.rgb()) > 127 ? QColor (Qt::darkYellow) : QColor (Qt::yellow); QTextCursor found; /* first put a start cursor at the top left edge... */ QPoint Point (0, 0); QTextCursor start = textEdit->cursorForPosition (Point); /* ... then move it backward by the search text length */ int startPos = start.position() - txt.length(); if (startPos >= 0) start.setPosition (startPos); else start.setPosition (0); int w = textEdit->geometry().width(); int h = textEdit->geometry().height(); /* get the visible text to check if the search string is inside it */ Point = QPoint (w, h); QTextCursor end = textEdit->cursorForPosition (Point); int endPos = end.position() + txt.length(); end.movePosition (QTextCursor::End); if (endPos <= end.position()) end.setPosition (endPos); QTextCursor visCur = start; visCur.setPosition (end.position(), QTextCursor::KeepAnchor); const QString str = visCur.selection().toPlainText(); // '\n' is included in this way Qt::CaseSensitivity cs = ui->caseButton->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive; if (str.contains (txt, cs)) // don't waste time if the searched text isn't visible { while (!(found = finding (txt, start, searchFlags_)).isNull()) { QTextEdit::ExtraSelection extra; extra.format.setBackground (yellow); extra.format.setFontUnderline (true); extra.format.setUnderlineStyle (QTextCharFormat::WaveUnderline); extra.format.setUnderlineColor (fgColor_); extra.cursor = found; extraSelections.append (extra); start.setPosition (found.position()); if (textEdit->cursorRect (start).top() >= h) break; } } textEdit->setExtraSelections (extraSelections); } /*************************/ void FN::rehighlight (TextEdit *textEdit) { if (!searchEntries_[textEdit].isEmpty()) hlight(); } /*************************/ void FN::reallySetSearchFlags (bool h) { searchFlags_ = QTextDocument::FindFlags(); if (ui->wholeButton->isChecked()) searchFlags_ = QTextDocument::FindWholeWords; if (ui->caseButton->isChecked()) searchFlags_ |= QTextDocument::FindCaseSensitively; /* deselect text for consistency */ if (QObject::sender() == ui->caseButton || (QObject::sender() == ui->wholeButton)) { for (int i = 0; i < ui->stackedWidget->count(); ++i) { TextEdit *textEdit = qobject_cast< TextEdit *>(ui->stackedWidget->widget (i)); QTextCursor start = textEdit->textCursor(); start.setPosition (start.anchor()); textEdit->setTextCursor (start); } } if (h) hlight(); } /*************************/ void FN::setSearchFlags() { reallySetSearchFlags (true); } } FeatherNotes-0.8.0/feathernotes/fn.cpp000066400000000000000000006136061374721712500177310ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016-2020 * * FeatherNotes 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. * * FeatherNotes 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 . */ #include "fn.h" #include "ui_fn.h" #include "ui_about.h" #include "dommodel.h" #include "spinbox.h" #include "simplecrypt.h" #include "settings.h" #include "help.h" #include "filedialog.h" #include "messagebox.h" #include "svgicons.h" #include "pref.h" #include "colorLabel.h" #ifdef HAS_HUNSPELL #include "spellChecker.h" #include "spellDialog.h" #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAS_X11 #if defined Q_WS_X11 || defined Q_OS_LINUX || defined Q_OS_OPENBSD || defined Q_OS_NETBSD || defined Q_OS_HURD #include #endif #include "x11.h" #endif namespace FeatherNotes { static QSize TOOLBAR_ICON_SIZE; // Regex of an embedded image (should be checked for the image): static const QRegularExpression EMBEDDED_IMG (R"(<\s*img(?=\s)[^<>]*(?<=\s)src\s*=\s*"data:[^<>]*;base64\s*,[a-zA-Z0-9+=/\s]+"[^<>]*/*>)"); // Stylesheet of a customized document: static const QString DOC_STYLESHEET ("body{background-color: %1; color: %2;}"); FN::FN (const QStringList& message, QWidget *parent) : QMainWindow (parent), ui (new Ui::FN) { #ifdef HAS_X11 // For now, the lack of x11 is seen as wayland. #if defined Q_WS_X11 || defined Q_OS_LINUX || defined Q_OS_FREEBSD || defined Q_OS_OPENBSD || defined Q_OS_NETBSD || defined Q_OS_HURD isX11_ = QX11Info::isPlatformX11(); #else isX11_ = false; #endif // defined Q_WS_X11 #else isX11_ = false; #endif // HAS_X11 ui->setupUi (this); imgScale_ = 100; TOOLBAR_ICON_SIZE = ui->mainToolBar->iconSize(); QStyledItemDelegate *delegate = new QStyledItemDelegate (this); ui->treeView->setItemDelegate (delegate); ui->treeView->setContextMenuPolicy (Qt::CustomContextMenu); /* NOTE: The auto-saving timer starts only when a new note is created, a file is opened, or it is enabled in Preferences. It saves the doc only if it belongs to an existing file that needs saving. */ autoSave_ = -1; saveNeeded_ = 0; timer_ = new QTimer (this); connect (timer_, &QTimer::timeout, this, &FN::autoSaving); /* appearance */ setAttribute (Qt::WA_AlwaysShowToolTips); ui->statusBar->setVisible (false); defaultFont_ = QFont ("Monospace"); defaultFont_.setPointSize (qMax (font().pointSize(), 9)); nodeFont_ = font(); bgColor_ = QColor (Qt::white); fgColor_ = QColor (Qt::black); /* search bar */ ui->lineEdit->setVisible (false); ui->nextButton->setVisible (false); ui->prevButton->setVisible (false); ui->caseButton->setVisible (false); ui->wholeButton->setVisible (false); ui->everywhereButton->setVisible (false); ui->tagsButton->setVisible (false); ui->namesButton->setVisible (false); searchingOtherNode_ = false; rplOtherNode_ = false; replCount_ = 0; /* replace dock */ ui->dockReplace->setVisible (false); model_ = new DomModel (QDomDocument(), this); ui->treeView->setModel (model_); /* get the default (customizable) shortcuts before any change */ static const QStringList excluded = {"actionCut", "actionCopy", "actionPaste", "actionSelectAll"}; const auto allMenus = ui->menuBar->findChildren(); for (auto thisMenu : allMenus) { const auto menuActions = thisMenu->actions(); for (auto menuAction : menuActions) { QKeySequence seq = menuAction->shortcut(); if (!seq.isEmpty() && !excluded.contains (menuAction->objectName())) defaultShortcuts_.insert (menuAction, seq); } } /* exceptions */ defaultShortcuts_.insert (ui->actionPrintNodes, QKeySequence()); defaultShortcuts_.insert (ui->actionPrintAll, QKeySequence()); defaultShortcuts_.insert (ui->actionExportHTML, QKeySequence()); defaultShortcuts_.insert (ui->actionPassword, QKeySequence()); defaultShortcuts_.insert (ui->actionDocFont, QKeySequence()); defaultShortcuts_.insert (ui->actionNodeFont, QKeySequence()); defaultShortcuts_.insert (ui->actionDocColors, QKeySequence()); defaultShortcuts_.insert (ui->actionDate, QKeySequence()); reservedShortcuts_ /* QTextEdit */ << QKeySequence (Qt::CTRL + Qt::SHIFT + Qt::Key_Z).toString() << QKeySequence (Qt::CTRL + Qt::Key_Z).toString() << QKeySequence (Qt::CTRL + Qt::Key_X).toString() << QKeySequence (Qt::CTRL + Qt::Key_C).toString() << QKeySequence (Qt::CTRL + Qt::Key_V).toString() << QKeySequence (Qt::CTRL + Qt::Key_A).toString() << QKeySequence (Qt::SHIFT + Qt::Key_Insert).toString() << QKeySequence (Qt::SHIFT + Qt::Key_Delete).toString() << QKeySequence (Qt::CTRL + Qt::Key_Insert).toString() << QKeySequence (Qt::CTRL + Qt::Key_Left).toString() << QKeySequence (Qt::CTRL + Qt::Key_Right).toString() << QKeySequence (Qt::CTRL + Qt::Key_Up).toString() << QKeySequence (Qt::CTRL + Qt::Key_Down).toString() << QKeySequence (Qt::CTRL + Qt::Key_Home).toString() << QKeySequence (Qt::CTRL + Qt::Key_End).toString() << QKeySequence (Qt::CTRL + Qt::SHIFT + Qt::Key_Up).toString() << QKeySequence (Qt::CTRL + Qt::SHIFT + Qt::Key_Down).toString() << QKeySequence (Qt::META + Qt::Key_Up).toString() << QKeySequence (Qt::META + Qt::Key_Down).toString() << QKeySequence (Qt::META + Qt::SHIFT + Qt::Key_Up).toString() << QKeySequence (Qt::META + Qt::SHIFT + Qt::Key_Down).toString() /* search and replacement */ << QKeySequence (Qt::Key_F3).toString() << QKeySequence (Qt::Key_F4).toString() << QKeySequence (Qt::Key_F5).toString() << QKeySequence (Qt::Key_F6).toString() << QKeySequence (Qt::Key_F7).toString() << QKeySequence (Qt::Key_F8).toString() << QKeySequence (Qt::Key_F9).toString() << QKeySequence (Qt::Key_F10).toString() << QKeySequence (Qt::Key_F11).toString() << QKeySequence (Qt::CTRL + Qt::SHIFT + Qt::Key_W).toString() << QKeySequence (Qt::SHIFT + Qt::Key_F7).toString() << QKeySequence (Qt::CTRL + Qt::SHIFT + Qt::Key_F7).toString() /* zooming */ << QKeySequence (Qt::CTRL + Qt::Key_Equal).toString() << QKeySequence (Qt::CTRL + Qt::Key_Plus).toString() << QKeySequence (Qt::CTRL + Qt::Key_Minus).toString() << QKeySequence (Qt::CTRL + Qt::Key_0).toString() /* text tabulation */ << QKeySequence (Qt::SHIFT + Qt::Key_Enter).toString() << QKeySequence (Qt::SHIFT + Qt::Key_Return).toString() << QKeySequence (Qt::CTRL + Qt::Key_Tab).toString() << QKeySequence (Qt::CTRL + Qt::META + Qt::Key_Tab).toString() /* used by LineEdit as well as QTextEdit */ << QKeySequence (Qt::CTRL + Qt::Key_K).toString(); readShortcuts(); QHash::const_iterator it = customActions_.constBegin(); while (it != customActions_.constEnd()) { // NOTE: Custom shortcuts are saved in the PortableText format. if (QAction *action = findChild(it.key())) action->setShortcut (QKeySequence (it.value(), QKeySequence::PortableText)); ++it; } shownBefore_ = false; splitterSizes_ = QByteArray::fromBase64 ("AAAA/wAAAAEAAAACAAAAqgAAAhIB/////wEAAAABAA=="); remSize_ = true; remSplitter_ = true; remPosition_ = true; wrapByDefault_ = true; indentByDefault_ = true; transparentTree_ = false; smallToolbarIcons_ = false; noToolbar_ = false; noMenubar_ = false; autoBracket_ = false; autoReplace_ = false; openLastFile_ = false; treeViewDND_ = false; readAndApplyConfig(); QWidget* spacer = new QWidget(); spacer->setSizePolicy (QSizePolicy::Expanding, QSizePolicy::Preferred); ui->mainToolBar->insertWidget (ui->actionMenu, spacer); QMenu *menu = new QMenu (ui->mainToolBar); menu->addMenu (ui->menuFile); menu->addMenu (ui->menuEdit); menu->addMenu (ui->menuFormat); menu->addMenu (ui->menuTree); menu->addMenu (ui->menuOptions); menu->addMenu (ui->menuSearch); menu->addMenu (ui->menuHelp); ui->actionMenu->setMenu(menu); QList tbList = ui->mainToolBar->findChildren(); if (!tbList.isEmpty()) tbList.at (tbList.count() - 1)->setPopupMode (QToolButton::InstantPopup); if (hasTray_) quitting_ = false; else quitting_ = true; QActionGroup *aGroup = new QActionGroup (this); ui->actionLeft->setActionGroup (aGroup); ui->actionCenter->setActionGroup (aGroup); ui->actionRight->setActionGroup (aGroup); ui->actionJust->setActionGroup (aGroup); QActionGroup *aGroup1 = new QActionGroup (this); ui->actionLTR->setActionGroup (aGroup1); ui->actionRTL->setActionGroup (aGroup1); /* signal connections */ connect (ui->treeView, &QWidget::customContextMenuRequested, this, &FN::showContextMenu); connect (ui->treeView, &TreeView::FNDocDropped, this, &FN::openFNDoc); connect (ui->actionNew, &QAction::triggered, this, &FN::newNote); connect (ui->actionOpen, &QAction::triggered, this, &FN::openFile); connect (ui->actionSave, &QAction::triggered, this, &FN::saveFile); connect (ui->actionSaveAs, &QAction::triggered, this, &FN::saveFile); connect (ui->actionPassword, &QAction::triggered, this, &FN::setPswd); connect (ui->actionPrint, &QAction::triggered, this, &FN::txtPrint); connect (ui->actionPrintNodes, &QAction::triggered, this, &FN::txtPrint); connect (ui->actionPrintAll, &QAction::triggered, this, &FN::txtPrint); connect (ui->actionExportHTML, &QAction::triggered, this, &FN::exportHTML); connect (ui->actionUndo, &QAction::triggered, this, &FN::undoing); connect (ui->actionRedo, &QAction::triggered, this, &FN::redoing); connect (ui->actionCut, &QAction::triggered, this, &FN::cutText); connect (ui->actionCopy, &QAction::triggered, this, &FN::copyText); connect (ui->actionPaste, &QAction::triggered, this, &FN::pasteText); connect (ui->actionPasteHTML, &QAction::triggered, this, &FN::pasteHTML); connect (ui->actionDelete, &QAction::triggered, this, &FN::deleteText); connect (ui->actionSelectAll, &QAction::triggered, this, &FN::selectAllText); connect (ui->actionDate, &QAction::triggered, this, &FN::insertDate); connect (ui->actionBold, &QAction::triggered, this, &FN::makeBold); connect (ui->actionItalic, &QAction::triggered, this, &FN::makeItalic); connect (ui->actionUnderline, &QAction::triggered, this, &FN::makeUnderlined); connect (ui->actionStrike, &QAction::triggered, this, &FN::makeStriked); connect (ui->actionSuper, &QAction::triggered, this, &FN::makeSuperscript); connect (ui->actionSub, &QAction::triggered, this, &FN::makeSubscript); connect (ui->actionTextColor, &QAction::triggered, this, &FN::textColor); connect (ui->actionBgColor, &QAction::triggered, this, &FN::bgColor); connect (ui->actionClear, &QAction::triggered, this, &FN::clearFormat); connect (ui->actionH3, &QAction::triggered, this, &FN::makeHeader); connect (ui->actionH2, &QAction::triggered, this, &FN::makeHeader); connect (ui->actionH1, &QAction::triggered, this, &FN::makeHeader); connect (ui->actionLink, &QAction::triggered, this, &FN::insertLink); connect (ui->actionCopyLink, &QAction::triggered, this, &FN::copyLink); connect (ui->actionEmbedImage, &QAction::triggered, this, &FN::embedImage); connect (ui->actionImageScale, &QAction::triggered, this, &FN::scaleImage); connect (ui->actionImageSave, &QAction::triggered, this, &FN::saveImage); connect (ui->actionTable, &QAction::triggered, this, &FN::addTable); connect (ui->actionTableMergeCells, &QAction::triggered, this, &FN::tableMergeCells); connect (ui->actionTablePrependRow, &QAction::triggered, this, &FN::tablePrependRow); connect (ui->actionTableAppendRow, &QAction::triggered, this, &FN::tableAppendRow); connect (ui->actionTablePrependCol, &QAction::triggered, this, &FN::tablePrependCol); connect (ui->actionTableAppendCol, &QAction::triggered, this, &FN::tableAppendCol); connect (ui->actionTableDeleteRow, &QAction::triggered, this, &FN::tableDeleteRow); connect (ui->actionTableDeleteCol, &QAction::triggered, this, &FN::tableDeleteCol); connect(aGroup, &QActionGroup::triggered, this,&FN::textAlign); connect(aGroup1, &QActionGroup::triggered, this, &FN::textDirection); connect (ui->actionExpandAll, &QAction::triggered, this, &FN::expandAll); connect (ui->actionCollapseAll, &QAction::triggered, this, &FN::collapseAll); connect (ui->actionNewSibling, &QAction::triggered, this, &FN::newNode); connect (ui->actionNewChild, &QAction::triggered, this, &FN::newNode); connect (ui->actionPrepSibling, &QAction::triggered, this, &FN::newNode); connect (ui->actionDeleteNode, &QAction::triggered, this, &FN::deleteNode); connect (ui->actionMoveUp, &QAction::triggered, this, &FN::moveUpNode); connect (ui->actionMoveDown, &QAction::triggered, this, &FN::moveDownNode); if (QApplication::layoutDirection() == Qt::RightToLeft) { connect (ui->actionMoveLeft, &QAction::triggered, this, &FN::moveRightNode); connect (ui->actionMoveRight, &QAction::triggered, this, &FN::moveLeftNode); } else { connect (ui->actionMoveLeft, &QAction::triggered, this, &FN::moveLeftNode); connect (ui->actionMoveRight, &QAction::triggered, this, &FN::moveRightNode); } connect (ui->actionTags, &QAction::triggered, this, &FN::handleTags); connect (ui->actionRenameNode, &QAction::triggered, this, &FN::renameNode); connect (ui->actionNodeIcon, &QAction::triggered, this, &FN::nodeIcon); connect (ui->actionProp, &QAction::triggered, this, &FN::toggleStatusBar); connect (ui->actionDocFont, &QAction::triggered, this, &FN::textFontDialog); connect (ui->actionNodeFont, &QAction::triggered, this, &FN::nodeFontDialog); connect (ui->actionDocColors, &QAction::triggered, this, &FN::docColorDialog); connect (ui->actionWrap, &QAction::triggered, this, &FN::toggleWrapping); connect (ui->actionIndent, &QAction::triggered, this, &FN::toggleIndent); connect (ui->actionPref, &QAction::triggered, this, &FN::prefDialog); connect (ui->actionFind, &QAction::triggered, this, &FN::showHideSearch); connect (ui->nextButton, &QAbstractButton::clicked, this, &FN::find); connect (ui->prevButton, &QAbstractButton::clicked, this, &FN::find); connect (ui->lineEdit, &QLineEdit::returnPressed, this, &FN::find); connect (ui->wholeButton, &QAbstractButton::clicked, this, &FN::setSearchFlags); connect (ui->caseButton, &QAbstractButton::clicked, this, &FN::setSearchFlags); connect (ui->everywhereButton, &QAbstractButton::toggled, this, &FN::allBtn); connect (ui->tagsButton, &QAbstractButton::toggled, this, &FN::tagsAndNamesBtn); connect (ui->namesButton, &QAbstractButton::toggled, this, &FN::tagsAndNamesBtn ); connect (ui->actionReplace, &QAction::triggered, this, &FN::replaceDock); connect (ui->dockReplace, &QDockWidget::visibilityChanged, this, &FN::closeReplaceDock); connect (ui->dockReplace, &QDockWidget::topLevelChanged, this, &FN::resizeDock); connect (ui->rplNextButton, &QAbstractButton::clicked, this, &FN::replace); connect (ui->rplPrevButton, &QAbstractButton::clicked, this, &FN::replace); connect (ui->allButton, &QAbstractButton::clicked, this, &FN::replaceAll); connect (ui->actionAbout, &QAction::triggered, this, &FN::aboutDialog); connect (ui->actionHelp, &QAction::triggered, this, &FN::showHelpDialog); #ifdef HAS_HUNSPELL connect (ui->actionCheckSpelling, &QAction::triggered, this, &FN::checkSpelling); #else ui->actionCheckSpelling->setVisible (false); #endif /* Once the tray icon is created, it'll persist even if the systray disappears temporarily. But for the tray icon to be created, the systray should exist. Hence, we wait 1 min for the systray at startup. */ tray_ = nullptr; trayCounter_ = 0; if (hasTray_) { if (QSystemTrayIcon::isSystemTrayAvailable()) createTrayIcon(); else { QTimer *trayTimer = new QTimer (this); trayTimer->setSingleShot (true); trayTimer->setInterval (5000); connect (trayTimer, &QTimer::timeout, this, &FN::checkTray); trayTimer->start(); ++trayCounter_; } } QShortcut *focusSwitcher = new QShortcut (QKeySequence (Qt::Key_Escape), this); connect (focusSwitcher, &QShortcut::activated, [this] { if (QWidget *cw = ui->stackedWidget->currentWidget()) { if (cw->hasFocus()) ui->treeView->viewport()->setFocus(); else cw->setFocus(); } }); QShortcut *fullscreen = new QShortcut (QKeySequence (Qt::Key_F11), this); connect (fullscreen, &QShortcut::activated, this, &FN::fullScreening); QShortcut *defaultsize = new QShortcut (QKeySequence (Qt::CTRL + Qt::SHIFT + Qt::Key_W), this); connect (defaultsize, &QShortcut::activated, this, &FN::defaultSize); QShortcut *zoomin = new QShortcut (QKeySequence (Qt::CTRL + Qt::Key_Equal), this); QShortcut *zoominPlus = new QShortcut (QKeySequence (Qt::CTRL + Qt::Key_Plus), this); QShortcut *zoomout = new QShortcut (QKeySequence (Qt::CTRL + Qt::Key_Minus), this); QShortcut *unzoom = new QShortcut (QKeySequence (Qt::CTRL + Qt::Key_0), this); connect (zoomin, &QShortcut::activated, this, &FN::zoomingIn); connect (zoominPlus, &QShortcut::activated, this, &FN::zoomingIn); connect (zoomout, &QShortcut::activated, this, &FN::zoomingOut); connect (unzoom, &QShortcut::activated, this, &FN::unZooming); /* parse the message */ QString filePath; if (message.isEmpty()) { if (!hasTray_ || !minToTray_) show(); } else { if (message.at (0) != "--min" && message.at (0) != "-m" && message.at (0) != "--tray" && message.at (0) != "-t") { if (!hasTray_ || !minToTray_) show(); filePath = message.at (0); } else { if (message.at (0) == "--min" || message.at (0) == "-m") showMinimized(); else if (!hasTray_) show(); if (message.count() > 1) filePath = message.at (1); } } /* always an absolute path */ if (!filePath.isEmpty()) { if (filePath.startsWith ("file://")) filePath = QUrl (filePath).toLocalFile(); filePath = QDir::current().absoluteFilePath (filePath); filePath = QDir::cleanPath (filePath); } else filePath = xmlPath_; fileOpen (filePath, true); /*dummyWidget = nullptr; if (hasTray_) dummyWidget = new QWidget();*/ setAcceptDrops (true); } /*************************/ FN::~FN() { if (timer_) { if (timer_->isActive()) timer_->stop(); delete timer_; } delete tray_; // also deleted at closeEvent() (this is for Ctrl+C in terminal) tray_ = nullptr; delete ui; } /*************************/ bool FN::close() { QObject *sender = QObject::sender(); if (sender != nullptr && sender->objectName() == "trayQuit" && findChildren().count() > 0) { // don't respond to the tray icon when there's a dialog raise(); activateWindow(); return false; } quitting_ = true; return QWidget::close(); } /*************************/ void FN::closeEvent (QCloseEvent *event) { if (!quitting_) { event->ignore(); if (!isMaximized() && !isFullScreen()) { position_.setX (geometry().x()); position_.setY (geometry().y()); } if (tray_ && QSystemTrayIcon::isSystemTrayAvailable()) QTimer::singleShot (0, this, &QWidget::hide); else QTimer::singleShot (0, this, &QWidget::showMinimized); return; } if (timer_->isActive()) timer_->stop(); bool keep = false; if (ui->stackedWidget->currentIndex() > -1) { if (!xmlPath_.isEmpty() && (!QFile::exists (xmlPath_) || !QFileInfo (xmlPath_).isFile())) { if (tray_) { if (underE_ && QObject::sender() != nullptr && QObject::sender()->objectName() == "trayQuit") { if (!isVisible()) { activateTray(); QCoreApplication::processEvents(); } else { raise(); activateWindow(); } } else if (!underE_ && (!isVisible() || !isActiveWindow())) { activateTray(); QCoreApplication::processEvents(); } } if (unSaved (false)) keep = true; } else if (saveNeeded_) { if (tray_) { if (underE_ && QObject::sender() != nullptr && QObject::sender()->objectName() == "trayQuit") { if (!isVisible()) { activateTray(); QCoreApplication::processEvents(); } else { raise(); activateWindow(); } } else if (!underE_ && (!isVisible() || !isActiveWindow())) { activateTray(); QCoreApplication::processEvents(); } } if (unSaved (true)) keep = true; } } if (keep) { if (tray_) quitting_ = false; if (autoSave_ >= 1) timer_->start (autoSave_ * 1000 * 60); event->ignore(); } else { writeGeometryConfig(); delete tray_; // otherwise the app won't quit under KDE tray_ = nullptr; event->accept(); } } /*************************/ void FN::checkTray() { if (QTimer *trayTimer = qobject_cast(sender())) { if (QSystemTrayIcon::isSystemTrayAvailable()) { trayTimer->deleteLater(); createTrayIcon(); trayCounter_ = 0; // not needed } else if (trayCounter_ < 12) { trayTimer->start(); ++trayCounter_; } else { trayTimer->deleteLater(); show(); } } } /*************************/ void FN::createTrayIcon() { QIcon icn = QIcon::fromTheme ("feathernotes"); if (icn.isNull()) icn = QIcon (":icons/feathernotes.svg"); tray_ = new QSystemTrayIcon (icn, this); if (xmlPath_.isEmpty()) tray_->setToolTip ("FeatherNotes"); else { QString shownName = QFileInfo (xmlPath_).fileName(); if (shownName.endsWith (".fnx")) shownName.chop (4); tray_->setToolTip ("

" + shownName + "

"); } QMenu *trayMenu = new QMenu (this); /* we don't want shortcuts to be shown here */ QAction *actionshowMainWindow = trayMenu->addAction (tr ("&Raise/Hide")); if (underE_) actionshowMainWindow->setText (tr ("&Raise")); connect (actionshowMainWindow, &QAction::triggered, this, &FN::activateTray); /* use system icons with the tray menu because it gets its style from the panel */ QAction *actionNewTray = trayMenu->addAction (QIcon::fromTheme ("document-new"), tr ("&New Note")); QAction *actionOpenTray = trayMenu->addAction (QIcon::fromTheme ("document-open"), tr ("&Open")); trayMenu->addSeparator(); QAction *antionQuitTray = trayMenu->addAction (QIcon::fromTheme ("application-exit"), tr ("&Quit")); connect (actionNewTray, &QAction::triggered, this, &FN::newNote); connect (actionOpenTray, &QAction::triggered, this, &FN::openFile); connect (antionQuitTray, &QAction::triggered, this, &FN::close); actionshowMainWindow->setObjectName ("raiseHide"); actionNewTray->setObjectName ("trayNew"); actionOpenTray->setObjectName ("trayOpen"); antionQuitTray->setObjectName ("trayQuit"); tray_->setContextMenu (trayMenu); tray_->setVisible (true); connect (tray_, &QSystemTrayIcon::activated, this, &FN::trayActivated ); /*QShortcut *toggleTray = new QShortcut (QKeySequence (tr ("Ctrl+Shift+M", "Minimize to tray")), this); connect (toggleTray, &QShortcut::activated, this, &FN::activateTray);*/ } /*************************/ void FN::showContextMenu (const QPoint &p) { QModelIndex index = ui->treeView->indexAt (p); if (!index.isValid()) return; QMenu menu; menu.addAction (ui->actionPrepSibling); menu.addAction (ui->actionNewSibling); menu.addAction (ui->actionNewChild); menu.addAction (ui->actionDeleteNode); menu.addSeparator(); menu.addAction (ui->actionTags); menu.addAction (ui->actionNodeIcon); menu.addAction (ui->actionRenameNode); menu.exec (ui->treeView->viewport()->mapToGlobal (p)); } /*************************/ void FN::fullScreening() { setWindowState (windowState() ^ Qt::WindowFullScreen); } /*************************/ void FN::defaultSize() { if (isMaximized() || isFullScreen()) return; /*if (isMaximized() && isFullScreen()) showMaximized(); if (isMaximized()) showNormal();*/ if (size() != startSize_) { //setVisible (false); resize (startSize_); //QTimer::singleShot (250, this, &QWidget::showNormal); } QList sizes; sizes << 170 << 530; ui->splitter->setSizes (sizes); } /*************************/ void FN::zoomingIn() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); textEdit->zooming (1.f); } /*************************/ void FN::zoomingOut() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); textEdit->zooming (-1.f); rehighlight (textEdit); } /*************************/ void FN::unZooming() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); textEdit->setFont (defaultFont_); #if (QT_VERSION >= QT_VERSION_CHECK(5,11,0)) QFontMetricsF metrics (defaultFont_); textEdit->setTabStopDistance (4 * metrics.horizontalAdvance (' ')); #elif (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) QFontMetricsF metrics (defaultFont_); textEdit->setTabStopDistance (4 * metrics.width (' ')); #else QFontMetrics metrics (defaultFont_); textEdit->setTabStopWidth (4 * metrics.width (' ')); #endif /* this may be a zoom-out */ rehighlight (textEdit); } /*************************/ void FN::resizeEvent (QResizeEvent *event) { if (remSize_ && windowState() == Qt::WindowNoState) winSize_ = event->size(); QWidget::resizeEvent (event); } /*************************/ void FN::newNote() { QObject *sender = QObject::sender(); if (sender != nullptr && sender->objectName() == "trayNew" && findChildren().count() > 0) { // don't respond to the tray icon when there's a dialog raise(); activateWindow(); return; } closeTagsDialog(); if (timer_->isActive()) timer_->stop(); if (tray_) { if (underE_ && sender != nullptr && sender->objectName() == "trayNew") { if (!isVisible()) { activateTray(); QCoreApplication::processEvents(); } else { raise(); activateWindow(); } } else if (!underE_ && (!isVisible() || !isActiveWindow())) { activateTray(); QCoreApplication::processEvents(); } } if (!xmlPath_.isEmpty() && !QFile::exists (xmlPath_)) { if (unSaved (false)) { if (autoSave_ >= 1) timer_->start (autoSave_ * 1000 * 60); return; } } else if (saveNeeded_) { if (unSaved (true)) { if (autoSave_ >= 1) timer_->start (autoSave_ * 1000 * 60); return; } } /* show user a prompt */ if (!xmlPath_.isEmpty()) { MessageBox msgBox; msgBox.setIcon (QMessageBox::Question); msgBox.setWindowTitle ("FeatherNotes"); // kwin sets an ugly title msgBox.setText (tr ("
New note?
")); msgBox.setInformativeText (tr ("
Do you really want to leave this document
\n"\ "
and create an empty one?
")); msgBox.setStandardButtons (QMessageBox::Yes | QMessageBox::No); msgBox.changeButtonText (QMessageBox::Yes, tr ("Yes")); msgBox.changeButtonText (QMessageBox::No, tr ("No")); msgBox.setDefaultButton (QMessageBox::No); msgBox.setParent (this, Qt::Dialog); msgBox.setWindowModality (Qt::WindowModal); msgBox.show(); msgBox.move (x() + width()/2 - msgBox.width()/2, y() + height()/2 - msgBox.height()/ 2); switch (msgBox.exec()) { case QMessageBox::Yes: break; case QMessageBox::No: default: if (autoSave_ >= 1) timer_->start (autoSave_ * 1000 * 60); return; } } QDomDocument doc; QDomProcessingInstruction inst = doc.createProcessingInstruction ("xml", "version=\'1.0\' encoding=\'utf-8\'"); doc.insertBefore(inst, QDomNode()); QDomElement root = doc.createElement ("feathernotes"); root.setAttribute ("txtfont", defaultFont_.toString()); root.setAttribute ("nodefont", nodeFont_.toString()); if (bgColor_ != QColor (Qt::white)) root.setAttribute ("bgcolor", bgColor_.name()); else root.removeAttribute ("bgcolor"); if (fgColor_ != QColor (Qt::black)) root.setAttribute ("fgcolor", fgColor_.name()); else root.removeAttribute ("fgcolor"); doc.appendChild (root); QDomElement e = doc.createElement ("node"); e.setAttribute ("name", tr ("New Node")); root.appendChild (e); showDoc (doc); xmlPath_ = QString(); setTitle (xmlPath_); /* may be saved later */ if (autoSave_ >= 1) timer_->start (autoSave_ * 1000 * 60); docProp(); } /*************************/ void FN::setTitle (const QString& fname) { QFileInfo fileInfo; if (fname.isEmpty() || !(fileInfo = QFileInfo (fname)).exists()) { setWindowTitle (QString ("[*]%1").arg ("FeatherNotes")); if (tray_) tray_->setToolTip ("FeatherNotes"); return; } QString shownName = fileInfo.fileName(); if (shownName.endsWith (".fnx")) shownName.chop (4); QString path (fileInfo.dir().path()); setWindowTitle (QString ("[*]%1 (%2)").arg (shownName).arg (path)); if (tray_) { tray_->setToolTip ("

" + shownName + "

"); } } /*************************/ bool FN::unSaved (bool modified) { int unsaved = false; MessageBox msgBox; msgBox.setIcon (QMessageBox::Warning); msgBox.setText (tr ("
Save changes?
")); if (modified) msgBox.setInformativeText (tr ("
The document has been modified.
")); else msgBox.setInformativeText (tr ("
The document has been removed.
")); msgBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); msgBox.changeButtonText (QMessageBox::Save, tr ("Save")); msgBox.changeButtonText (QMessageBox::Discard, tr ("Discard changes")); msgBox.changeButtonText (QMessageBox::Cancel, tr ("Cancel")); msgBox.setDefaultButton (QMessageBox::Save); msgBox.setParent (this, Qt::Dialog); msgBox.setWindowModality (Qt::WindowModal); /* enforce a central position */ msgBox.show(); msgBox.move (x() + width()/2 - msgBox.width()/2, y() + height()/2 - msgBox.height()/ 2); switch (msgBox.exec()) { case QMessageBox::Save: if (!saveFile()) unsaved = true; break; case QMessageBox::Discard: // false break; case QMessageBox::Cancel: // true default: unsaved = true; break; } return unsaved; } /*************************/ void FN::enableActions (bool enable) { ui->actionSaveAs->setEnabled (enable); ui->actionPrint->setEnabled (enable); ui->actionPrintNodes->setEnabled (enable); ui->actionPrintAll->setEnabled (enable); ui->actionExportHTML->setEnabled (enable); ui->actionPassword->setEnabled (enable); ui->actionPaste->setEnabled (enable); ui->actionPasteHTML->setEnabled (enable); ui->actionSelectAll->setEnabled (enable); ui->actionDate->setEnabled (enable); ui->actionClear->setEnabled (enable); ui->actionBold->setEnabled (enable); ui->actionItalic->setEnabled (enable); ui->actionUnderline->setEnabled (enable); ui->actionStrike->setEnabled (enable); ui->actionSuper->setEnabled (enable); ui->actionSub->setEnabled (enable); ui->actionTextColor->setEnabled (enable); ui->actionBgColor->setEnabled (enable); ui->actionLeft->setEnabled (enable); ui->actionCenter->setEnabled (enable); ui->actionRight->setEnabled (enable); ui->actionJust->setEnabled (enable); ui->actionLTR->setEnabled (enable); ui->actionRTL->setEnabled (enable); ui->actionH3->setEnabled (enable); ui->actionH2->setEnabled (enable); ui->actionH1->setEnabled (enable); ui->actionEmbedImage->setEnabled (enable); ui->actionTable->setEnabled (enable); ui->actionExpandAll->setEnabled (enable); ui->actionCollapseAll->setEnabled (enable); ui->actionPrepSibling->setEnabled (enable); ui->actionNewSibling->setEnabled (enable); ui->actionNewChild->setEnabled (enable); ui->actionDeleteNode->setEnabled (enable); ui->actionMoveUp->setEnabled (enable); ui->actionMoveDown->setEnabled (enable); ui->actionMoveLeft->setEnabled (enable); ui->actionMoveRight->setEnabled (enable); ui->actionTags->setEnabled (enable); ui->actionRenameNode->setEnabled (enable); ui->actionNodeIcon->setEnabled (enable); ui->actionDocFont->setEnabled (enable); ui->actionNodeFont->setEnabled (enable); ui->actionWrap->setEnabled (enable); ui->actionIndent->setEnabled (enable); ui->actionFind->setEnabled (enable); ui->actionReplace->setEnabled (enable); if (!enable) { ui->actionUndo->setEnabled (false); ui->actionRedo->setEnabled (false); } } /*************************/ void FN::showDoc (QDomDocument &doc) { if (saveNeeded_) { saveNeeded_ = 0; ui->actionSave->setEnabled (false); setWindowModified (false); } while (ui->stackedWidget->count() > 0) { widgets_.clear(); searchEntries_.clear(); greenSels_.clear(); QWidget *cw = ui->stackedWidget->currentWidget(); TextEdit *textEdit = qobject_cast< TextEdit *>(cw); ui->stackedWidget->removeWidget (cw); delete textEdit; textEdit = nullptr; } QDomElement root = doc.firstChildElement ("feathernotes"); QString fontStr = root.attribute ("txtfont"); if (!fontStr.isEmpty()) defaultFont_.fromString (fontStr); else // defaultFont_ may have changed by the user { defaultFont_ = QFont ("Monospace"); defaultFont_.setPointSize (qMax (font().pointSize(), 9)); } fontStr = root.attribute ("nodefont"); if (!fontStr.isEmpty()) nodeFont_.fromString (fontStr); else // nodeFont_ may have changed by the user nodeFont_ = font(); QColor bgColor; QString docColor = root.attribute ("bgcolor"); if (!docColor.isEmpty()) bgColor = QColor (docColor); if (bgColor.isValid()) bgColor_ = bgColor; else bgColor_ = QColor (Qt::white); QColor fgColor; docColor = root.attribute ("fgcolor"); if (!docColor.isEmpty()) fgColor = QColor (docColor); if (fgColor.isValid()) fgColor_ = fgColor; else fgColor_ = QColor (Qt::black); DomModel *newModel = new DomModel (doc, this); QItemSelectionModel *m = ui->treeView->selectionModel(); ui->treeView->setModel (newModel); ui->treeView->setFont (nodeFont_); delete m; /* first connect to selectionChanged()... */ connect (ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &FN::selChanged); /* ... and then, select the first row */ ui->treeView->setCurrentIndex (newModel->index(0, 0)); ui->treeView->expandAll(); delete model_; model_ = newModel; connect (model_, &QAbstractItemModel::dataChanged, this, &FN::nodeChanged); connect (model_, &DomModel::treeChanged, this, &FN::noteModified); connect (model_, &DomModel::treeChanged, this, &FN::docProp); connect (model_, &DomModel::treeChanged, this, &FN::closeTagsDialog); connect (model_, &DomModel::dragStarted, [this] (const QModelIndex &draggedIndex) { if (draggedIndex == ui->treeView->currentIndex()) { treeViewDND_ = true; ui->treeView->setAutoScroll (false); } }); connect (model_, &DomModel::droppedAtIndex, [this] (const QModelIndex &droppedIndex) { ui->treeView->setAutoScroll (true); ui->treeView->setCurrentIndex (droppedIndex); treeViewDND_ = false; }); /* enable widgets */ if (!ui->actionSaveAs->isEnabled()) enableActions (true); } /*************************/ void FN::fileOpen (const QString &filePath, bool startup) { if (!filePath.isEmpty()) { QFile file (filePath); if (file.open (QIODevice::ReadOnly)) { QTextStream in (&file); QString cntnt = in.readAll(); file.close(); SimpleCrypt crypto (Q_UINT64_C(0xc9a25eb1610eb104)); QString decrypted = crypto.decryptToString (cntnt); if (decrypted.isEmpty()) decrypted = cntnt; QDomDocument document; if (document.setContent (decrypted)) { QDomElement root = document.firstChildElement ("feathernotes"); if (root.isNull()) { if (startup) xmlPath_.clear(); return; } pswrd_ = root.attribute ("pswrd"); if (!pswrd_.isEmpty() && !isPswrdCorrect()) { if (startup) xmlPath_.clear(); return; } showDoc (document); if (xmlPath_ != filePath) { xmlPath_ = filePath; QTimer::singleShot (0, this, [this] () { rememberLastOpenedFile(); }); } setTitle (xmlPath_); docProp(); } else if (startup) xmlPath_.clear(); } else if (startup) xmlPath_.clear(); } /* start the timer (again) if file opening is done or canceled */ if (!xmlPath_.isEmpty() && autoSave_ >= 1) timer_->start (autoSave_ * 1000 * 60); } /*************************/ void FN::openFile() { QObject *sender = QObject::sender(); if (sender != nullptr && sender->objectName() == "trayOpen" && findChildren().count() > 0) { // don't respond to the tray icon when there's a dialog raise(); activateWindow(); return; } closeTagsDialog(); if (timer_->isActive()) timer_->stop(); if (tray_) { if (underE_ && sender != nullptr && sender->objectName() == "trayOpen") { if (!isVisible()) { activateTray(); QCoreApplication::processEvents(); } else { raise(); activateWindow(); } } else if (!underE_ && (!isVisible() || !isActiveWindow())) { activateTray(); QCoreApplication::processEvents(); } } if (!xmlPath_.isEmpty() && !QFile::exists (xmlPath_)) { if (unSaved (false)) { if (autoSave_ >= 1) timer_->start (autoSave_ * 1000 * 60); return; } } else if (saveNeeded_) { if (unSaved (true)) { if (autoSave_ >= 1) timer_->start (autoSave_ * 1000 * 60); return; } } QString path; if (!xmlPath_.isEmpty()) { if (QFile::exists (xmlPath_)) path = xmlPath_; else { QDir dir = QFileInfo (xmlPath_).absoluteDir(); if (!dir.exists()) dir = QDir::home(); path = dir.path(); } } else { QDir dir = QDir::home(); path = dir.path(); } QString filePath; FileDialog dialog (this); dialog.setAcceptMode (QFileDialog::AcceptOpen); dialog.setWindowTitle (tr ("Open file...")); dialog.setFileMode (QFileDialog::ExistingFiles); dialog.setNameFilter (tr ("FeatherNotes documents (*.fnx);;All Files (*)")); if (QFileInfo (path).isDir()) dialog.setDirectory (path); else { dialog.setDirectory (path.section ("/", 0, -2)); // workaround for KDE dialog.selectFile (path); dialog.autoScroll(); } if (dialog.exec()) filePath = dialog.selectedFiles().at (0); /* fileOpen() restarts auto-saving even when opening is canceled */ fileOpen (filePath); } /*************************/ void FN::openFNDoc (const QString &filePath) { if (filePath.isEmpty()) return; // impossible closeTagsDialog(); if (timer_->isActive()) timer_->stop(); if (!xmlPath_.isEmpty() && !QFile::exists (xmlPath_)) { if (unSaved (false)) { if (autoSave_ >= 1) timer_->start (autoSave_ * 1000 * 60); return; } } else if (saveNeeded_) { if (unSaved (true)) { if (autoSave_ >= 1) timer_->start (autoSave_ * 1000 * 60); return; } } /* TextEdit::insertFromMimeData() should first return */ QTimer::singleShot (0, this, [this, filePath] () { fileOpen (filePath); raise(); activateWindow(); }); } /*************************/ void FN::dragMoveEvent (QDragMoveEvent *event) { if (event->mimeData()->hasUrls()) { const auto urls = event->mimeData()->urls(); for (const QUrl &url : urls) { if (url.fileName().endsWith (".fnx")) { event->acceptProposedAction(); return; } QMimeDatabase mimeDatabase; QMimeType mimeType = mimeDatabase.mimeTypeForFile (QFileInfo (url.toLocalFile())); if (mimeType.name() == "text/feathernotes-fnx") { event->acceptProposedAction(); return; } } } event->ignore(); } /*************************/ void FN::dragEnterEvent (QDragEnterEvent *event) { if (event->mimeData()->hasUrls()) { const auto urls = event->mimeData()->urls(); for (const QUrl &url : urls) { if (url.fileName().endsWith (".fnx")) { event->acceptProposedAction(); return; } QMimeDatabase mimeDatabase; QMimeType mimeType = mimeDatabase.mimeTypeForFile (QFileInfo (url.toLocalFile())); if (mimeType.name() == "text/feathernotes-fnx") { event->acceptProposedAction(); return; } } } event->ignore(); } /*************************/ void FN::dropEvent (QDropEvent *event) { if (event->mimeData()->hasUrls()) { const auto urls = event->mimeData()->urls(); for (const QUrl &url : urls) { if (url.fileName().endsWith (".fnx")) { openFNDoc (url.path()); break; } QMimeDatabase mimeDatabase; QMimeType mimeType = mimeDatabase.mimeTypeForFile (QFileInfo (url.toLocalFile())); if (mimeType.name() == "text/feathernotes-fnx") { openFNDoc (url.path()); break; } } } event->acceptProposedAction(); } /*************************/ void FN::autoSaving() { if (xmlPath_.isEmpty() || saveNeeded_ == 0 || !QFile::exists (xmlPath_)) // the file is deleted (but might be restored later) { return; } fileSave (xmlPath_); } /*************************/ void FN::notSaved() { MessageBox msgBox (QMessageBox::Warning, tr ("FeatherNotes"), tr ("
Cannot be saved!
"), QMessageBox::Close, this); msgBox.changeButtonText (QMessageBox::Close, tr ("Close")); msgBox.exec(); } /*************************/ void FN::setNodesTexts() { /* first set the default font */ QDomElement root = model_->domDocument.firstChildElement ("feathernotes"); root.setAttribute ("txtfont", defaultFont_.toString()); root.setAttribute ("nodefont", nodeFont_.toString()); if (bgColor_ != QColor (Qt::white)) root.setAttribute ("bgcolor", bgColor_.name()); else root.removeAttribute ("bgcolor"); if (fgColor_ != QColor (Qt::black)) root.setAttribute ("fgcolor", fgColor_.name()); else root.removeAttribute ("fgcolor"); if (!pswrd_.isEmpty()) root.setAttribute ("pswrd", pswrd_); else root.removeAttribute ("pswrd"); QHash::iterator it; for (it = widgets_.begin(); it != widgets_.end(); ++it) { if (!it.value()->document()->isModified()) continue; QString txt; /* don't write useless HTML code */ if (!it.value()->toPlainText().isEmpty()) { /* unzoom the text if it's zoomed */ if (it.value()->document()->defaultFont() != defaultFont_) { QTextDocument *tempDoc = it.value()->document()->clone(); tempDoc->setDefaultFont (defaultFont_); txt = tempDoc->toHtml(); delete tempDoc; } else txt = it.value()->toHtml(); } DomItem *item = it.key(); QDomNodeList list = item->node().childNodes(); if (list.isEmpty()) { /* if this node doesn't have any child, append a text child node to it... */ QDomText t = model_->domDocument.createTextNode (txt); item->node().appendChild (t); } else if (list.item (0).isElement()) { /* ... but if its first child is an element node, insert the text node before that node... */ QDomText t = model_->domDocument.createTextNode (txt); item->node().insertBefore (t, list.item (0)); } else if (list.item (0).isText()) /* ... finally, if this node's first child is a text node, replace its text */ list.item (0).setNodeValue (txt); } } /*************************/ bool FN::saveFile() { int index = ui->stackedWidget->currentIndex(); if (index == -1) return false; QString fname = xmlPath_; if (fname.isEmpty() || !QFile::exists (fname)) { if (fname.isEmpty()) { QDir dir = QDir::home(); fname = dir.filePath (tr ("Untitled") + ".fnx"); } else { QDir dir = QFileInfo (fname).absoluteDir(); if (!dir.exists()) dir = QDir::home(); /* add the file name */ fname = dir.filePath (QFileInfo (fname).fileName()); } /* use Save-As for Save or saving */ if (QObject::sender() != ui->actionSaveAs) { FileDialog dialog (this); dialog.setAcceptMode (QFileDialog::AcceptSave); dialog.setWindowTitle (tr ("Save As...")); dialog.setFileMode (QFileDialog::AnyFile); dialog.setNameFilter (tr ("FeatherNotes documents (*.fnx);;All Files (*)")); dialog.setDirectory (fname.section ("/", 0, -2)); // workaround for KDE dialog.selectFile (fname); dialog.autoScroll(); if (dialog.exec()) { fname = dialog.selectedFiles().at (0); if (fname.isEmpty() || QFileInfo (fname).isDir()) return false; } else return false; } } if (QObject::sender() == ui->actionSaveAs) { FileDialog dialog (this); dialog.setAcceptMode (QFileDialog::AcceptSave); dialog.setWindowTitle (tr ("Save As...")); dialog.setFileMode (QFileDialog::AnyFile); dialog.setNameFilter (tr ("FeatherNotes documents (*.fnx);;All Files (*)")); dialog.setDirectory (fname.section ("/", 0, -2)); // workaround for KDE dialog.selectFile (fname); dialog.autoScroll(); if (dialog.exec()) { fname = dialog.selectedFiles().at (0); if (fname.isEmpty() || QFileInfo (fname).isDir()) return false; } else return false; } bool overwrite (fname == xmlPath_); if (!fileSave (fname)) { notSaved(); return false; } else if (!overwrite) rememberLastOpenedFile(); return true; } /*************************/ bool FN::fileSave (const QString &filePath) { QFile outputFile (filePath); if (pswrd_.isEmpty()) { if (outputFile.open (QIODevice::WriteOnly)) { /* now, it's the time to set the nodes' texts */ setNodesTexts(); QTextStream outStream (&outputFile); model_->domDocument.save (outStream, 1); outputFile.close(); if (xmlPath_ != filePath) { xmlPath_ = filePath; setTitle (xmlPath_); } QHash::iterator it; for (it = widgets_.begin(); it != widgets_.end(); ++it) it.value()->document()->setModified (false); if (saveNeeded_) { saveNeeded_ = 0; ui->actionSave->setEnabled (false); setWindowModified (false); } docProp(); } else return false; } else { if (outputFile.open (QFile::WriteOnly)) { setNodesTexts(); SimpleCrypt crypto (Q_UINT64_C (0xc9a25eb1610eb104)); QString encrypted = crypto.encryptToString (model_->domDocument.toString()); QTextStream out (&outputFile); out << encrypted; outputFile.close(); if (xmlPath_ != filePath) { xmlPath_ = filePath; setTitle (xmlPath_); } QHash::iterator it; for (it = widgets_.begin(); it != widgets_.end(); ++it) it.value()->document()->setModified (false); if (saveNeeded_) { saveNeeded_ = 0; ui->actionSave->setEnabled (false); setWindowModified (false); } docProp(); } else return false; } return true; } /*************************/ void FN::undoing() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; /* remove green highlights */ QHash >::iterator it; for (it = greenSels_.begin(); it != greenSels_.end(); ++it) { QList extraSelectionsIth; greenSels_[it.key()] = extraSelectionsIth; it.key()->setExtraSelections (QList()); } qobject_cast< TextEdit *>(cw)->undo(); } /*************************/ void FN::redoing() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; qobject_cast< TextEdit *>(cw)->redo(); } /*************************/ void FN::cutText() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; qobject_cast< TextEdit *>(cw)->cut(); } /*************************/ void FN::copyText() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; qobject_cast< TextEdit *>(cw)->copy(); } /*************************/ void FN::pasteText() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; qobject_cast< TextEdit *>(cw)->paste(); } /*************************/ void FN::pasteHTML() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); textEdit->setAcceptRichText (true); textEdit->paste(); textEdit->setAcceptRichText (false); } /*************************/ void FN::deleteText() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); if (!textEdit->isReadOnly()) textEdit->insertPlainText (""); } /*************************/ void FN::selectAllText() { if (QWidget *cw = ui->stackedWidget->currentWidget()) qobject_cast< TextEdit *>(cw)->selectAll(); } /*************************/ void FN::insertDate() { if (QWidget *cw = ui->stackedWidget->currentWidget()) { qobject_cast< TextEdit *>(cw)->insertPlainText (QDateTime::currentDateTime().toString (dateFormat_.isEmpty() ? locale().dateTimeFormat() : dateFormat_)); } } /*************************/ TextEdit *FN::newWidget() { TextEdit *textEdit = new TextEdit; //textEdit->autoIndentation = true; // auto-indentation is enabled by default textEdit->autoBracket = autoBracket_; textEdit->autoReplace = autoReplace_; if (bgColor_ == QColor (Qt::white) && fgColor_ == QColor (Qt::black)) { QPalette p = QApplication::palette(); QColor hCol = p.color(QPalette::Active, QPalette::Highlight); QBrush brush = p.window(); if (brush.color().value() <= 120) { if (236 - qGray (hCol.rgb()) < 30) textEdit->setStyleSheet ("QTextEdit {" "color: black;" "selection-color: black;" "selection-background-color: rgb(200, 200, 200);}"); else textEdit->setStyleSheet ("QTextEdit {" "color: black;}"); textEdit->viewport()->setStyleSheet (".QWidget {" "color: black;" "background-color: rgb(236, 236, 236);}"); } else { if (255 - qGray (hCol.rgb()) < 30) textEdit->setStyleSheet ("QTextEdit {" "color: black;" "selection-color: black;" "selection-background-color: rgb(200, 200, 200);}"); else textEdit->setStyleSheet ("QTextEdit {" "color: black;}"); textEdit->viewport()->setStyleSheet (".QWidget {" "color: black;" "background-color: rgb(255, 255, 255);}"); } } else { textEdit->document()->setDefaultStyleSheet (DOC_STYLESHEET.arg (bgColor_.name(), fgColor_.name())); if (fgColor_ != QColor (Qt::black)) textEdit->CSSTextColor = fgColor_; // only for a workaround (see TextEdit::undo) } textEdit->setAcceptRichText (false); textEdit->viewport()->setMouseTracking (true); textEdit->setContextMenuPolicy (Qt::CustomContextMenu); /* we want consistent widgets */ textEdit->setFont (defaultFont_); // needed when the application font changes textEdit->document()->setDefaultFont (defaultFont_); #if (QT_VERSION >= QT_VERSION_CHECK(5,11,0)) QFontMetricsF metrics (defaultFont_); textEdit->setTabStopDistance (4 * metrics.horizontalAdvance (' ')); #elif (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) QFontMetricsF metrics (defaultFont_); textEdit->setTabStopDistance (4 * metrics.width (' ')); #else QFontMetrics metrics (defaultFont_); textEdit->setTabStopWidth (4 * metrics.width (' ')); #endif int index = ui->stackedWidget->currentIndex(); ui->stackedWidget->insertWidget (index + 1, textEdit); ui->stackedWidget->setCurrentWidget (textEdit); if (!ui->actionWrap->isChecked()) textEdit->setLineWrapMode (QTextEdit::NoWrap); if (!ui->actionIndent->isChecked()) textEdit->autoIndentation = false; connect (textEdit, &QTextEdit::copyAvailable, ui->actionCut, &QAction::setEnabled); connect (textEdit, &QTextEdit::copyAvailable, ui->actionCopy, &QAction::setEnabled); connect (textEdit, &QTextEdit::copyAvailable, ui->actionDelete, &QAction::setEnabled); connect (textEdit, &QTextEdit::copyAvailable, ui->actionLink, &QAction::setEnabled); connect (textEdit, &QTextEdit::copyAvailable, this, &FN::setCursorInsideSelection); connect (textEdit, &TextEdit::imageDropped, this, &FN::imageEmbed); connect (textEdit, &TextEdit::FNDocDropped, this, &FN::openFNDoc); connect (textEdit, &TextEdit::zoomedOut, this, &FN::rehighlight); connect (textEdit, &QWidget::customContextMenuRequested, this, &FN::txtContextMenu); /* The remaining connections to QTextEdit signals are in selChanged(). */ /* I don't know why, under KDE, when a text is selected for the first time, it may not be copied to the selection clipboard. Perhaps it has something to do with Klipper. I neither know why the following line is a workaround but it can cause a long delay when FeatherNotes is started. */ //QApplication::clipboard()->text (QClipboard::Selection); return textEdit; } /*************************/ // If some text is selected and the cursor is put somewhere inside // the selection with mouse, Qt may not emit currentCharFormatChanged() // when it should, as if the cursor isn't really set. The following method // really sets the text cursor and can be used as a workaround for this bug. void FN::setCursorInsideSelection (bool sel) { if (!sel) { if (QWidget *cw = ui->stackedWidget->currentWidget()) { TextEdit *textEdit = qobject_cast< TextEdit *>(cw); /* WARNING: Qt4 didn't need disconnecting. Why?! */ disconnect (textEdit, &QTextEdit::copyAvailable, this, &FN::setCursorInsideSelection); QTextCursor cur = textEdit->textCursor(); textEdit->setTextCursor (cur); connect (textEdit, &QTextEdit::copyAvailable, this, &FN::setCursorInsideSelection); } } } /*************************/ void FN::txtContextMenu (const QPoint &p) { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); QTextCursor cur = textEdit->textCursor(); bool hasSel = cur.hasSelection(); /* set the text cursor at the position of right clicking if there's no selection */ if (!hasSel) { cur = textEdit->cursorForPosition (p); textEdit->setTextCursor (cur); } linkAtPos_ = textEdit->anchorAt (p); QMenu *menu = textEdit->createStandardContextMenu (p); bool sepAdded (false); const QList list = menu->actions(); int copyIndx = -1, pasteIndx = -1; for (int i = 0; i < list.count(); ++i) { const auto thisAction = list.at (i); /* remove the shortcut strings because shortcuts may change */ QString txt = thisAction->text(); if (!txt.isEmpty()) txt = txt.split ('\t').first(); if (!txt.isEmpty()) thisAction->setText (txt); /* find appropriate places for actionCopyLink and actionPasteHTML */ if (thisAction->objectName() == "edit-copy") copyIndx = i; else if (thisAction->objectName() == "edit-paste") pasteIndx = i; } if (!linkAtPos_.isEmpty()) { if (copyIndx > -1 && copyIndx + 1 < list.count()) menu->insertAction (list.at (copyIndx + 1), ui->actionCopyLink); else { menu->addSeparator(); menu->addAction (ui->actionCopyLink); } } if (pasteIndx > -1 && pasteIndx + 1 < list.count()) menu->insertAction (list.at (pasteIndx + 1), ui->actionPasteHTML); else { menu->addAction (ui->actionPasteHTML); menu->addSeparator(); sepAdded = true; } if (hasSel) { if (!sepAdded) { menu->addSeparator(); sepAdded = true; } menu->addAction (ui->actionLink); if (isImageSelected()) { menu->addSeparator(); menu->addAction (ui->actionImageScale); menu->addAction (ui->actionImageSave); } menu->addSeparator(); } if (!sepAdded) menu->addSeparator(); menu->addAction (ui->actionEmbedImage); menu->addAction (ui->actionTable); txtTable_ = cur.currentTable(); if (txtTable_) { menu->addSeparator(); if (cur.hasComplexSelection()) menu->addAction (ui->actionTableMergeCells); else { menu->addAction (ui->actionTablePrependRow); menu->addAction (ui->actionTableAppendRow); menu->addAction (ui->actionTablePrependCol); menu->addAction (ui->actionTableAppendCol); menu->addAction (ui->actionTableDeleteRow); menu->addAction (ui->actionTableDeleteCol); } } menu->addSeparator(); menu->addAction (ui->actionCheckSpelling); menu->addSeparator(); menu->addAction (ui->actionDate); menu->exec (textEdit->viewport()->mapToGlobal (p)); delete menu; txtTable_ = nullptr; } /*************************/ void FN::copyLink() { QClipboard *clipboard = QApplication::clipboard(); clipboard->setText (linkAtPos_); } /*************************/ void FN::selChanged (const QItemSelection &selected, const QItemSelection& /*deselected*/) { if (selected.isEmpty()) // if the last node is closed { if (ui->lineEdit->isVisible()) showHideSearch(); if (ui->dockReplace->isVisible()) replaceDock(); enableActions (false); /*if (QWidget *widget = ui->stackedWidget->currentWidget()) widget->setVisible (false);*/ return; } /*else if (deselected.isEmpty()) // a row is selected after Ctrl + left click { if (QWidget *widget = ui->stackedWidget->currentWidget()) widget->setVisible (true); enableActions (true); }*/ if (treeViewDND_) return; /* if a widget is paired with this DOM item, show it; otherwise create a widget and pair it with the item */ QModelIndex index = selected.indexes().at (0); TextEdit *textEdit = nullptr; bool found = false; QHash::iterator it; for (it = widgets_.begin(); it != widgets_.end(); ++it) { if (it.key() == static_cast(index.internalPointer())) { found = true; break; } } if (found) { textEdit = it.value(); ui->stackedWidget->setCurrentWidget (textEdit); QString txt = searchEntries_[textEdit]; /* change the search entry's text only if the search isn't done in tags or names */ if (!ui->tagsButton->isChecked() && !ui->namesButton->isChecked()) { ui->lineEdit->setText (txt); if (!txt.isEmpty()) hlight(); } } else { QString text; DomItem *item = static_cast(index.internalPointer()); QDomNodeList list = item->node().childNodes(); text = list.item (0).nodeValue(); /* this is needed for text zooming */ static const QString htmlStr ("\n" ""); QRegularExpressionMatch match; bool defaulrDocColor (bgColor_ == QColor (Qt::white) && fgColor_ == QColor (Qt::black)); if (defaulrDocColor) { static const QRegularExpression htmlRegex (R"(^,;.:\-={}\s"]+;:\-\s"']+>)"); if (text.indexOf (htmlRegex, 0, &match) > -1) text.replace (0, match.capturedLength(), htmlStr); } textEdit = newWidget(); textEdit->setHtml (text); if (!defaulrDocColor) { /* To enable the default stylesheet, we should set the HTML text of the document. Setting the HTML text of the editor above is needed for empty nodes. */ QString str = textEdit->document()->toHtml(); static const QRegularExpression htmlRegex1 (R"(^,;.:\-={}\s"]+((

)?)?)"); if (str.indexOf (htmlRegex1, 0, &match) > -1) str.replace (0, match.capturedLength(), htmlStr); textEdit->document()->setHtml (str); QTextCursor cur = textEdit->textCursor(); cur.setPosition (0); textEdit->setTextCursor (cur); textEdit->document()->setModified (false); } connect (textEdit->document(), &QTextDocument::modificationChanged, this, &FN::setSaveEnabled); connect (textEdit->document(), &QTextDocument::undoAvailable, this, &FN::setUndoEnabled); connect (textEdit->document(), &QTextDocument::redoAvailable, this, &FN::setRedoEnabled); connect (textEdit, &QTextEdit::currentCharFormatChanged, this, &FN::formatChanged); connect (textEdit, &QTextEdit::cursorPositionChanged, this, &FN::alignmentChanged); connect (textEdit, &QTextEdit::cursorPositionChanged, this, &FN::directionChanged); /* focus the text widget only if a document is opened just now */ if (widgets_.isEmpty()) textEdit->setFocus(); widgets_[static_cast(index.internalPointer())] = textEdit; searchEntries_[textEdit] = QString(); greenSels_[textEdit] = QList(); if (!ui->tagsButton->isChecked() && !ui->namesButton->isChecked()) { ui->lineEdit->setText (QString()); } } ui->actionUndo->setEnabled (textEdit->document()->isUndoAvailable()); ui->actionRedo->setEnabled (textEdit->document()->isRedoAvailable()); bool textIsSelected = textEdit->textCursor().hasSelection(); ui->actionCopy->setEnabled (textIsSelected); ui->actionCut->setEnabled (textIsSelected); ui->actionDelete->setEnabled (textIsSelected); ui->actionLink->setEnabled (textIsSelected); formatChanged (textEdit->currentCharFormat()); alignmentChanged(); directionChanged(); } /*************************/ void FN::setSaveEnabled (bool modified) { if (modified) noteModified(); else { if (saveNeeded_) --saveNeeded_; if (saveNeeded_ == 0) { ui->actionSave->setEnabled (false); setWindowModified (false); } } } /*************************/ void FN::setUndoEnabled (bool enabled) { ui->actionUndo->setEnabled (enabled); } /*************************/ void FN::setRedoEnabled (bool enabled) { ui->actionRedo->setEnabled (enabled); } /*************************/ void FN::formatChanged (const QTextCharFormat &format) { ui->actionSuper->setChecked (format.verticalAlignment() == QTextCharFormat::AlignSuperScript ? true : false); ui->actionSub->setChecked (format.verticalAlignment() == QTextCharFormat::AlignSubScript ? true : false); if (format.fontWeight() == QFont::Bold) ui->actionBold->setChecked (true); else ui->actionBold->setChecked (false); ui->actionItalic->setChecked (format.fontItalic()); ui->actionUnderline->setChecked (format.fontUnderline()); ui->actionStrike->setChecked (format.fontStrikeOut()); } /*************************/ void FN::alignmentChanged() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; Qt::Alignment a = qobject_cast< TextEdit *>(cw)->alignment(); if (a & Qt::AlignLeft) { if (a & Qt::AlignAbsolute) ui->actionLeft->setChecked (true); else // get alignment from text layout direction { QTextCursor cur = qobject_cast< TextEdit *>(cw)->textCursor(); QTextBlockFormat fmt = cur.blockFormat(); if (fmt.layoutDirection() == Qt::LeftToRight) ui->actionLeft->setChecked (true); else if (fmt.layoutDirection() == Qt::RightToLeft) ui->actionRight->setChecked (true); else // Qt::LayoutDirectionAuto { /* textDirection() returns either Qt::LeftToRight or Qt::RightToLeft (-> qtextobject.cpp) */ QTextBlock blk = cur.block(); if (blk.textDirection() == Qt::LeftToRight) ui->actionLeft->setChecked (true); else ui->actionRight->setChecked (true); } } } else if (a & Qt::AlignHCenter) ui->actionCenter->setChecked (true); else if (a & Qt::AlignRight) { if (a & Qt::AlignAbsolute) ui->actionRight->setChecked (true); else // get alignment from text layout direction { QTextCursor cur = qobject_cast< TextEdit *>(cw)->textCursor(); QTextBlockFormat fmt = cur.blockFormat(); if (fmt.layoutDirection() == Qt::RightToLeft) ui->actionRight->setChecked (true); else if (fmt.layoutDirection() == Qt::LeftToRight) ui->actionLeft->setChecked (true); else // Qt::LayoutDirectionAuto { QTextBlock blk = cur.block(); if (blk.textDirection() == Qt::LeftToRight) ui->actionLeft->setChecked (true); else ui->actionRight->setChecked (true); } } } else if (a & Qt::AlignJustify) ui->actionJust->setChecked (true); } /*************************/ void FN::directionChanged() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; QTextCursor cur = qobject_cast< TextEdit *>(cw)->textCursor(); QTextBlockFormat fmt = cur.blockFormat(); if (fmt.layoutDirection() == Qt::LeftToRight) ui->actionLTR->setChecked (true); else if (fmt.layoutDirection() == Qt::RightToLeft) ui->actionRTL->setChecked (true); else // Qt::LayoutDirectionAuto { QTextBlock blk = cur.block(); if (blk.textDirection() == Qt::LeftToRight) ui->actionLTR->setChecked (true); else ui->actionRTL->setChecked (true); } } /*************************/ void FN::mergeFormatOnWordOrSelection (const QTextCharFormat &format) { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); QTextCursor cursor = textEdit->textCursor(); if (!cursor.hasSelection()) cursor.select (QTextCursor::WordUnderCursor); cursor.mergeCharFormat (format); /* correct the pressed states of the format buttons if necessary */ formatChanged (textEdit->currentCharFormat()); } /*************************/ void FN::makeBold() { QTextCharFormat fmt; fmt.setFontWeight (ui->actionBold->isChecked() ? QFont::Bold : QFont::Normal); mergeFormatOnWordOrSelection (fmt); } /*************************/ void FN::makeItalic() { QTextCharFormat fmt; fmt.setFontItalic (ui->actionItalic->isChecked()); mergeFormatOnWordOrSelection (fmt); } /*************************/ void FN::makeUnderlined() { QTextCharFormat fmt; fmt.setFontUnderline (ui->actionUnderline->isChecked()); mergeFormatOnWordOrSelection (fmt); } /*************************/ void FN::makeStriked() { QTextCharFormat fmt; fmt.setFontStrikeOut (ui->actionStrike->isChecked()); mergeFormatOnWordOrSelection (fmt); } /*************************/ void FN::makeSuperscript() { QTextCharFormat fmt; fmt.setVerticalAlignment (ui->actionSuper->isChecked() ? QTextCharFormat::AlignSuperScript : QTextCharFormat::AlignNormal); mergeFormatOnWordOrSelection (fmt); } /*************************/ void FN::makeSubscript() { QTextCharFormat fmt; fmt.setVerticalAlignment (ui->actionSub->isChecked() ? QTextCharFormat::AlignSubScript : QTextCharFormat::AlignNormal); mergeFormatOnWordOrSelection (fmt); } /*************************/ void FN::textColor() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; QColor color; if ((color = qobject_cast< TextEdit *>(cw)->textColor()) == fgColor_) { if (lastTxtColor_.isValid()) color = lastTxtColor_; } color = QColorDialog::getColor (color, this, tr ("Select Text Color")); if (!color.isValid()) return; lastTxtColor_ = color; QTextCharFormat fmt; fmt.setForeground (color); mergeFormatOnWordOrSelection (fmt); } /*************************/ void FN::bgColor() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; QColor color; if ((color = qobject_cast< TextEdit *>(cw)->textBackgroundColor()) == QColor (Qt::black)) // this is a Qt bug { if (lastBgColor_.isValid()) color = lastBgColor_; } color = QColorDialog::getColor (color, this, tr ("Select Background Color")); if (!color.isValid()) return; lastBgColor_ = color; QTextCharFormat fmt; fmt.setBackground (color); mergeFormatOnWordOrSelection (fmt); } /*************************/ void FN::clearFormat() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; QTextCursor cur = qobject_cast< TextEdit *>(cw)->textCursor(); if (!cur.hasSelection()) cur.select (QTextCursor::WordUnderCursor); QTextCharFormat fmt; if (fgColor_ != QColor (Qt::black)) fmt.setForeground (fgColor_); cur.setCharFormat (fmt); } /*************************/ void FN::textAlign (QAction *a) { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); if (a == ui->actionLeft) textEdit->setAlignment (Qt::Alignment (Qt::AlignLeft | Qt::AlignAbsolute)); else if (a == ui->actionCenter) textEdit->setAlignment (Qt::AlignHCenter); else if (a == ui->actionRight) textEdit->setAlignment (Qt::Alignment (Qt::AlignRight | Qt::AlignAbsolute)); else if (a == ui->actionJust) textEdit->setAlignment (Qt::AlignJustify); } /*************************/ void FN::textDirection (QAction *a) { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; QTextBlockFormat fmt; if (a == ui->actionLTR) fmt.setLayoutDirection (Qt::LeftToRight); else if (a == ui->actionRTL) fmt.setLayoutDirection (Qt::RightToLeft); QTextCursor cur = qobject_cast< TextEdit *>(cw)->textCursor(); if (!cur.hasSelection()) cur.select (QTextCursor::WordUnderCursor); cur.mergeBlockFormat (fmt); alignmentChanged(); } /*************************/ void FN::makeHeader() { int index = ui->stackedWidget->currentIndex(); if (index == -1) return; QTextCharFormat fmt; if (QObject::sender() == ui->actionH3) fmt.setProperty (QTextFormat::FontSizeAdjustment, 1); else if (QObject::sender() == ui->actionH2) fmt.setProperty (QTextFormat::FontSizeAdjustment, 2); else// if (QObject::sender() == ui->actionH1) fmt.setProperty (QTextFormat::FontSizeAdjustment, 3); mergeFormatOnWordOrSelection (fmt); } /*************************/ void FN::expandAll() { ui->treeView->expandAll(); } /*************************/ void FN::collapseAll() { ui->treeView->collapseAll(); } /*************************/ void FN::newNode() { closeTagsDialog(); QModelIndex index = ui->treeView->currentIndex(); if (QObject::sender() == ui->actionNewSibling) { QModelIndex pIndex = model_->parent (index); model_->insertRow (index.row() + 1, pIndex); } else if (QObject::sender() == ui->actionPrepSibling) { QModelIndex pIndex = model_->parent (index); model_->insertRow (index.row(), pIndex); } else //if (QObject::sender() == ui->actionNewChild) { model_->insertRow (model_->rowCount (index), index); ui->treeView->expand (index); } } /*************************/ void FN::deleteNode() { closeTagsDialog(); MessageBox msgBox; msgBox.setIcon (QMessageBox::Question); msgBox.setWindowTitle (tr ("Deletion")); msgBox.setText (tr ("
Delete this node?
")); msgBox.setInformativeText (tr ("
Warning!
\n
This action cannot be undone.
")); msgBox.setStandardButtons (QMessageBox::Yes | QMessageBox::No); msgBox.changeButtonText (QMessageBox::Yes, tr ("Yes")); msgBox.changeButtonText (QMessageBox::No, tr ("No")); msgBox.setDefaultButton (QMessageBox::No); msgBox.show(); msgBox.move (x() + width()/2 - msgBox.width()/2, y() + height()/2 - msgBox.height()/ 2); switch (msgBox.exec()) { case QMessageBox::Yes: break; case QMessageBox::No: default: return; } QModelIndex index = ui->treeView->currentIndex(); /* remove all widgets paired with this node or its descendants */ QModelIndexList list = model_->allDescendants (index); list << index; for (int i = 0; i < list.count(); ++i) { QHash::iterator it = widgets_.find (static_cast(list.at (i).internalPointer())); if (it != widgets_.end()) { TextEdit *textEdit = it.value(); if (saveNeeded_ && textEdit->document()->isModified()) --saveNeeded_; searchEntries_.remove (textEdit); greenSels_.remove (textEdit); ui->stackedWidget->removeWidget (textEdit); delete textEdit; widgets_.remove (it.key()); } } /* now, really remove the node */ QModelIndex pIndex = model_->parent (index); model_->removeRow (index.row(), pIndex); } /*************************/ void FN::moveUpNode() { closeTagsDialog(); QModelIndex index = ui->treeView->currentIndex(); QModelIndex pIndex = model_->parent (index); if (index.row() == 0) return; model_->moveUpRow (index.row(), pIndex); } /*************************/ void FN::moveLeftNode() { closeTagsDialog(); QModelIndex index = ui->treeView->currentIndex(); QModelIndex pIndex = model_->parent (index); if (!pIndex.isValid()) return; model_->moveLeftRow (index.row(), pIndex); } /*************************/ void FN::moveDownNode() { closeTagsDialog(); QModelIndex index = ui->treeView->currentIndex(); QModelIndex pIndex = model_->parent (index); if (index.row() == model_->rowCount (pIndex) - 1) return; model_->moveDownRow (index.row(), pIndex); } /*************************/ void FN::moveRightNode() { closeTagsDialog(); QModelIndex index = ui->treeView->currentIndex(); QModelIndex pIndex = model_->parent (index); if (index.row() == 0) return; model_->moveRightRow (index.row(), pIndex); } /*************************/ // Add or edit tags. void FN::handleTags() { QModelIndex index = ui->treeView->currentIndex(); DomItem *item = static_cast(index.internalPointer()); QDomNode node = item->node(); QDomNamedNodeMap attributeMap = node.attributes(); QString tags = attributeMap.namedItem ("tag").nodeValue(); QDialog *dialog = new QDialog (this); dialog->setWindowTitle (tr ("Tags")); QGridLayout *grid = new QGridLayout; grid->setSpacing (5); grid->setContentsMargins (5, 5, 5, 5); LineEdit *lineEdit = new LineEdit(); lineEdit->returnOnClear = false; lineEdit->setMinimumWidth (250); lineEdit->setText (tags); lineEdit->setToolTip ("

" + tr ("Tag(s) for this node") + "

"); connect (lineEdit, &QLineEdit::returnPressed, dialog, &QDialog::accept); QSpacerItem *spacer = new QSpacerItem (1, 5); QPushButton *cancelButton = new QPushButton (symbolicIcon::icon (":icons/dialog-cancel.svg"), tr ("Cancel")); QPushButton *okButton = new QPushButton (symbolicIcon::icon (":icons/dialog-ok.svg"), tr ("OK")); connect (cancelButton, &QAbstractButton::clicked, dialog, &QDialog::reject); connect (okButton, &QAbstractButton::clicked, dialog, &QDialog::accept); grid->addWidget (lineEdit, 0, 0, 1, 3); grid->addItem (spacer, 1, 0); grid->addWidget (cancelButton, 2, 1, Qt::AlignRight); grid->addWidget (okButton, 2, 2, Qt::AlignCenter); grid->setColumnStretch (0, 1); grid->setRowStretch (1, 1); dialog->setLayout (grid); /*dialog->resize (dialog->minimumWidth(), dialog->minimumHeight());*/ /*dialog->show(); dialog->move (x() + width()/2 - dialog->width(), y() + height()/2 - dialog->height());*/ QString newTags; switch (dialog->exec()) { case QDialog::Accepted: newTags = lineEdit->text(); delete dialog; break; case QDialog::Rejected: default: delete dialog; return; } if (newTags != tags) { closeTagsDialog(); if (newTags.isEmpty()) node.toElement().removeAttribute ("tag"); else node.toElement().setAttribute ("tag", newTags); noteModified(); } } /*************************/ void FN::renameNode() { ui->treeView->edit (ui->treeView->currentIndex()); } /*************************/ void FN::nodeIcon() { QDialog *dlg = new QDialog (this); dlg->setWindowTitle (tr ("Node Icon")); QGridLayout *grid = new QGridLayout; grid->setSpacing (5); dlg->setContentsMargins (5, 5, 5, 5); LineEdit *ImagePathEntry = new LineEdit(); ImagePathEntry->returnOnClear = false; ImagePathEntry->setMinimumWidth (200); ImagePathEntry->setToolTip (tr ("Image path")); connect (ImagePathEntry, &QLineEdit::returnPressed, dlg, &QDialog::accept); QToolButton *openBtn = new QToolButton(); openBtn->setIcon (symbolicIcon::icon (":icons/document-open.svg")); openBtn->setToolTip (tr ("Open image")); connect (openBtn, &QAbstractButton::clicked, dlg, [=] { QString path; if (!xmlPath_.isEmpty()) { QDir dir = QFileInfo (xmlPath_).absoluteDir(); if (!dir.exists()) dir = QDir::home(); path = dir.path(); } else { QDir dir = QDir::home(); path = dir.path(); } QString file; FileDialog dialog (this); dialog.setAcceptMode (QFileDialog::AcceptOpen); dialog.setWindowTitle (tr ("Open Image...")); dialog.setFileMode (QFileDialog::ExistingFiles); dialog.setNameFilter (tr ("Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*)")); dialog.setDirectory (path); if (dialog.exec()) { QStringList files = dialog.selectedFiles(); if (files.count() > 0) file = files.at (0); } ImagePathEntry->setText (file); }); QSpacerItem *spacer = new QSpacerItem (1, 10, QSizePolicy::Minimum, QSizePolicy::MinimumExpanding); QPushButton *cancelButton = new QPushButton (symbolicIcon::icon (":icons/dialog-cancel.svg"), tr ("Cancel")); QPushButton *okButton = new QPushButton (symbolicIcon::icon (":icons/dialog-ok.svg"), tr ("OK")); connect (cancelButton, &QAbstractButton::clicked, dlg, &QDialog::reject); connect (okButton, &QAbstractButton::clicked, dlg, &QDialog::accept); grid->addWidget (ImagePathEntry, 0, 0, 1, 4); grid->addWidget (openBtn, 0, 4, Qt::AlignCenter); grid->addItem (spacer, 1, 0); grid->addWidget (cancelButton, 2, 2, Qt::AlignRight); grid->addWidget (okButton, 2, 3, 1, 2, Qt::AlignCenter); grid->setColumnStretch (1, 1); dlg->setLayout (grid); dlg->resize (dlg->sizeHint()); QString imagePath; switch (dlg->exec()) { case QDialog::Accepted: imagePath = ImagePathEntry->text(); delete dlg; break; case QDialog::Rejected: default: delete dlg; return; } QModelIndex index = ui->treeView->currentIndex(); DomItem *item = static_cast(index.internalPointer()); QDomNode node = item->node(); QString curIcn = node.toElement().attribute ("icon"); if (imagePath.isEmpty()) { if (!curIcn.isEmpty()) { node.toElement().removeAttribute ("icon"); emit ui->treeView->dataChanged (index, index); noteModified(); } } else { QFile file (imagePath); if (file.open (QIODevice::ReadOnly)) { QDataStream in (&file); QByteArray rawarray; QDataStream datastream (&rawarray, QIODevice::WriteOnly); char a; while (in.readRawData (&a, 1) != 0) datastream.writeRawData (&a, 1); file.close(); QByteArray base64array = rawarray.toBase64(); const QString icn = QString (base64array); if (curIcn != icn) { node.toElement().setAttribute ("icon", icn); emit ui->treeView->dataChanged (index, index); noteModified(); } } } } /*************************/ void FN::toggleStatusBar() { if (ui->statusBar->isVisible()) { QLabel *statusLabel = ui->statusBar->findChild(); ui->statusBar->removeWidget (statusLabel); if (statusLabel) { delete statusLabel; statusLabel = nullptr; } ui->statusBar->setVisible (false); return; } int rows = model_->rowCount(); int allNodes = 0; if (rows > 0) { QModelIndex indx = model_->index (0, 0, QModelIndex()); while ((indx = model_->adjacentIndex (indx, true)).isValid()) ++allNodes; ++allNodes; } QLabel *statusLabel = new QLabel(); statusLabel->setTextInteractionFlags (Qt::TextSelectableByMouse); if (xmlPath_.isEmpty()) { statusLabel->setText (tr ("Main nodes: %1" "    All nodes: %2") .arg (rows).arg (allNodes)); } else { statusLabel->setText (tr ("Note: %1
" "Main nodes: %2" "    All nodes: %3") .arg (xmlPath_).arg (rows).arg (allNodes)); } ui->statusBar->addWidget (statusLabel); ui->statusBar->setVisible (true); } /*************************/ void FN::docProp() { if (!ui->statusBar->isVisible()) return; QList list = ui->statusBar->findChildren(); if (list.isEmpty()) return; QLabel *statusLabel = list.at (0); int rows = model_->rowCount(); int allNodes = 0; if (rows > 0) { QModelIndex indx = model_->index (0, 0, QModelIndex()); while ((indx = model_->adjacentIndex (indx, true)).isValid()) ++allNodes; ++allNodes; } if (xmlPath_.isEmpty()) { statusLabel->setText (tr ("Main nodes: %1" "    All nodes: %2") .arg (rows).arg (allNodes)); } else { statusLabel->setText (tr ("Note: %1
" "Main nodes: %2" "    All nodes: %3") .arg (xmlPath_).arg (rows).arg (allNodes)); } } /*************************/ void FN::setNewFont (DomItem *item, const QTextCharFormat &fmt) { QString text; QDomNodeList list = item->node().childNodes(); if (!list.item (0).isText()) return; text = list.item (0).nodeValue(); if (!text.startsWith ("document()->setDefaultFont (defaultFont_); textEdit->setHtml (text); /* paragraph font, merged with body font */ QTextCursor cursor = textEdit->textCursor(); cursor.select (QTextCursor::Document); cursor.mergeCharFormat (fmt); text = textEdit->toHtml(); list.item (0).setNodeValue (text); delete textEdit; } /*************************/ void FN::textFontDialog() { bool ok; QFont newFont = QFontDialog::getFont (&ok, defaultFont_, this, tr ("Select Document Font")); if (ok) { QFont font (newFont.family(), newFont.pointSize()); defaultFont_ = font; noteModified(); QTextCharFormat fmt; fmt.setFont (defaultFont_); /* change the font for all shown nodes FIXME: Text zooming won't work until the document is reloaded. */ QHash::iterator it; for (it = widgets_.begin(); it != widgets_.end(); ++it) { it.value()->setFont (defaultFont_); // needed when the application font changes it.value()->document()->setDefaultFont (defaultFont_); QTextCursor cursor = it.value()->textCursor(); cursor.select (QTextCursor::Document); cursor.mergeCharFormat (fmt); #if (QT_VERSION >= QT_VERSION_CHECK(5,11,0)) QFontMetricsF metrics (defaultFont_); it.value()->setTabStopDistance (4 * metrics.horizontalAdvance (' ')); #elif (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) QFontMetricsF metrics (defaultFont_); it.value()->setTabStopDistance (4 * metrics.width (' ')); #else QFontMetrics metrics (defaultFont_); it.value()->setTabStopWidth (4 * metrics.width (' ')); #endif } /* also, change the font for all nodes that aren't shown yet */ for (int i = 0; i < model_->rowCount (QModelIndex()); ++i) { QModelIndex index = model_->index (i, 0, QModelIndex()); DomItem *item = static_cast(index.internalPointer()); if (!widgets_.contains (item)) setNewFont (item, fmt); QModelIndexList list = model_->allDescendants (index); for (int j = 0; j < list.count(); ++j) { item = static_cast(list.at (j).internalPointer()); if (!widgets_.contains (item)) setNewFont (item, fmt); } } /* rehighlight found matches for this node because the font may be smaller now */ if (QWidget *cw = ui->stackedWidget->currentWidget()) { TextEdit *textEdit = qobject_cast< TextEdit *>(cw); rehighlight (textEdit); } } } /*************************/ void FN::nodeFontDialog() { bool ok; QFont newFont = QFontDialog::getFont (&ok, nodeFont_, this, tr ("Select Node Font")); if (ok) { nodeFont_ = newFont; noteModified(); ui->treeView->setFont (nodeFont_); } } /*************************/ void FN::docColorDialog() { QColor oldBgColor = bgColor_; QColor oldFgColor = fgColor_; QDialog *dialog = new QDialog (this); dialog->setWindowTitle (tr ("Set Document Colors")); QGridLayout *grid = new QGridLayout; grid->setSpacing (5); grid->setContentsMargins (5, 10, 5, 5); QGridLayout *colorLayout = new QGridLayout; colorLayout->setSpacing (5); colorLayout->setContentsMargins (0, 10, 0, 0); QLabel *label = new QLabel ("
" + tr ("These colors will be applied to new nodes.
They may or may not affect existing nodes
but document reopening is recommended.") + "
"); QLabel *bgLabel = new QLabel (tr ("Background color:")); ColorLabel *bgColorLabel = new ColorLabel(); bgColorLabel->setColor (bgColor_); colorLayout->addWidget (bgLabel, 0, 0); colorLayout->addWidget (bgColorLabel, 0, 1); QLabel *fgLabel = new QLabel (tr ("Text color:")); ColorLabel *fgColorLabel = new ColorLabel(); fgColorLabel->setColor (fgColor_); colorLayout->addWidget (fgLabel, 1, 0); colorLayout->addWidget (fgColorLabel, 1, 1); colorLayout->setColumnStretch (1, 1); QSpacerItem *spacer = new QSpacerItem (1, 10); QPushButton *cancelButton = new QPushButton (symbolicIcon::icon (":icons/dialog-cancel.svg"), tr ("Cancel")); QPushButton *okButton = new QPushButton (symbolicIcon::icon (":icons/dialog-ok.svg"), tr ("OK")); connect (cancelButton, &QAbstractButton::clicked, dialog, &QDialog::reject); connect (okButton, &QAbstractButton::clicked, dialog, &QDialog::accept); okButton->setDefault (true); grid->addWidget (label, 0, 0, 1, 2); grid->addLayout (colorLayout, 1, 0, 1, 2); grid->addItem (spacer, 2, 0); grid->addWidget (cancelButton, 3, 0, Qt::AlignRight); grid->addWidget (okButton, 3, 1, Qt::AlignCenter); grid->setColumnStretch (0, 1); grid->setRowStretch (2, 1); dialog->setLayout (grid); QHash::iterator it; switch (dialog->exec()) { case QDialog::Accepted: bgColor_ = bgColorLabel->getColor(); fgColor_ = fgColorLabel->getColor(); if (bgColor_ != oldBgColor || fgColor_ != oldFgColor) noteModified(); delete dialog; break; case QDialog::Rejected: default: delete dialog; break; } } /*************************/ void FN::noteModified() { if (model_->rowCount() == 0) // if the last node is closed { ui->actionSave->setEnabled (false); setWindowModified (false); } else { if (saveNeeded_ == 0) { ui->actionSave->setEnabled (true); setWindowModified (true); } ++saveNeeded_; } } /*************************/ void FN::nodeChanged (const QModelIndex&, const QModelIndex&) { noteModified(); } /*************************/ void FN::showHideSearch() { bool visibility = ui->lineEdit->isVisible(); if (QObject::sender() == ui->actionFind && visibility && !ui->lineEdit->hasFocus()) { ui->lineEdit->setFocus(); ui->lineEdit->selectAll(); return; } ui->lineEdit->setVisible (!visibility); ui->nextButton->setVisible (!visibility); ui->prevButton->setVisible (!visibility); ui->caseButton->setVisible (!visibility); ui->wholeButton->setVisible (!visibility); ui->everywhereButton->setVisible (!visibility); ui->tagsButton->setVisible (!visibility); ui->namesButton->setVisible (!visibility); if (!visibility) ui->lineEdit->setFocus(); else { ui->dockReplace->setVisible (false); // no replace dock without searchbar if (QWidget *cw = ui->stackedWidget->currentWidget()) { /* return focus to the document */ qobject_cast< TextEdit *>(cw)->setFocus(); /* cancel search */ QHash::iterator it; for (it = searchEntries_.begin(); it != searchEntries_.end(); ++it) { ui->lineEdit->setText (QString()); it.value() = QString(); disconnect (it.key()->verticalScrollBar(), &QAbstractSlider::valueChanged, this, &FN::scrolled); disconnect (it.key()->horizontalScrollBar(), &QAbstractSlider::valueChanged, this, &FN::scrolled); disconnect (it.key(), &TextEdit::resized, this, &FN::hlight); disconnect (it.key(), &QTextEdit::textChanged, this, &FN::hlight); QList extraSelections; greenSels_[it.key()] = extraSelections; it.key()->setExtraSelections (extraSelections); } ui->everywhereButton->setChecked (false); ui->tagsButton->setChecked (false); ui->namesButton->setChecked (false); } } } /*************************/ void FN::findInNames() { QString txt = ui->lineEdit->text(); if (txt.isEmpty()) return; QModelIndex indx = ui->treeView->currentIndex(); bool down = true; bool found = false; if (QObject::sender() == ui->prevButton) down = false; Qt::CaseSensitivity cs = Qt::CaseInsensitive; if (ui->caseButton->isChecked()) cs = Qt::CaseSensitive; QRegularExpression regex; if (ui->wholeButton->isChecked()) { if (cs == Qt::CaseInsensitive) regex.setPatternOptions (QRegularExpression::CaseInsensitiveOption); regex.setPattern (QString ("\\b%1\\b").arg (QRegularExpression::escape (txt))); while ((indx = model_->adjacentIndex (indx, down)).isValid()) { if (model_->data (indx, Qt::DisplayRole).toString().indexOf (regex) != -1) { found = true; break; } } } else { while ((indx = model_->adjacentIndex (indx, down)).isValid()) { if (model_->data (indx, Qt::DisplayRole).toString().contains (txt, cs)) { found = true; break; } } } /* if nothing is found, search again from the first/last index to the current index */ if (!indx.isValid()) { if (down) indx = model_->index (0, 0); else indx = model_->index (model_->rowCount() - 1, 0); if (indx == ui->treeView->currentIndex()) return; if (ui->wholeButton->isChecked()) { if (model_->data (indx, Qt::DisplayRole).toString().indexOf (regex) != -1) found = true; else { while ((indx = model_->adjacentIndex (indx, down)).isValid()) { if (indx == ui->treeView->currentIndex()) return; if (model_->data (indx, Qt::DisplayRole).toString().indexOf (regex) != -1) { found = true; break; } } } } else { if (model_->data (indx, Qt::DisplayRole).toString().contains (txt, cs)) found = true; else { while ((indx = model_->adjacentIndex (indx, down)).isValid()) { if (indx == ui->treeView->currentIndex()) return; if (model_->data (indx, Qt::DisplayRole).toString().contains (txt, cs)) { found = true; break; } } } } } if (found) ui->treeView->setCurrentIndex (indx); } /*************************/ void FN::clearTagsList (int) { tagsList_.clear(); } /*************************/ void FN::selectRow (QListWidgetItem *item) { QList list = findChildren(); if (list.isEmpty()) return; QList list1; for (int i = 0; i < list.count(); ++i) { list1 = list.at (i)->findChildren(); if (!list1.isEmpty()) break; } if (list1.isEmpty()) return; QListWidget *listWidget = list1.at (0); ui->treeView->setCurrentIndex (tagsList_.at (listWidget->row (item))); } /*************************/ void FN::chooseRow (int row) { ui->treeView->setCurrentIndex (tagsList_.at (row)); } /*************************/ void FN::findInTags() { QString txt = ui->lineEdit->text(); if (txt.isEmpty()) return; /* close any existing tag matches dialog */ QList list = findChildren(); for (int i = 0; i < list.count(); ++i) { QList list1 = list.at (i)->findChildren(); if (!list1.isEmpty()) { /* this also deletes the dialog */ list.at (i)->done (QDialog::Rejected); break; } } QModelIndex nxtIndx = model_->index (0, 0, QModelIndex()); DomItem *item = static_cast(nxtIndx.internalPointer()); QDomNode node = item->node(); QDomNamedNodeMap attributeMap = node.attributes(); QString tags = attributeMap.namedItem ("tag").nodeValue(); while (nxtIndx.isValid()) { item = static_cast(nxtIndx.internalPointer()); node = item->node(); attributeMap = node.attributes(); tags = attributeMap.namedItem ("tag").nodeValue(); if (tags.contains (txt, Qt::CaseInsensitive)) tagsList_.append (nxtIndx); nxtIndx = model_->adjacentIndex (nxtIndx, true); } int matches = tagsList_.count(); QDialog *TagsDialog = new QDialog (this); TagsDialog->setAttribute (Qt::WA_DeleteOnClose, true); if (matches > 1) TagsDialog->setWindowTitle (tr ("%1 Matches").arg (matches)); else if (matches == 1) TagsDialog->setWindowTitle (tr ("One Match")); else TagsDialog->setWindowTitle (tr ("No Match")); QGridLayout *grid = new QGridLayout; grid->setSpacing (5); grid->setContentsMargins (5, 5, 5, 5); QListWidget *listWidget = new QListWidget(); listWidget->setSelectionMode (QAbstractItemView::SingleSelection); connect (listWidget, &QListWidget::itemActivated, this, &FN::selectRow); connect (listWidget, &QListWidget::currentRowChanged, this, &FN::chooseRow); QPushButton *closeButton = new QPushButton (symbolicIcon::icon (":icons/dialog-cancel.svg"), tr ("Close")); connect (closeButton, &QAbstractButton::clicked, TagsDialog, &QDialog::reject); connect (TagsDialog, &QDialog::finished, this, &FN::clearTagsList); for (int i = 0; i < matches; ++i) new QListWidgetItem (model_->data (tagsList_.at (i), Qt::DisplayRole).toString(), listWidget); grid->addWidget (listWidget, 0, 0); grid->addWidget (closeButton, 1, 0, Qt::AlignRight); TagsDialog->setLayout (grid); /*TagsDialog->resize (TagsDialog->minimumWidth(), TagsDialog->minimumHeight());*/ TagsDialog->show(); /*TagsDialog->move (x() + width()/2 - TagsDialog->width(), y() + height()/2 - TagsDialog->height());*/ TagsDialog->raise(); TagsDialog->raise(); TagsDialog->activateWindow(); } /*************************/ // Closes tag matches dialog. void FN::closeTagsDialog() { QList list = findChildren(); for (int i = 0; i < list.count(); ++i) { QList list1 = list.at (i)->findChildren(); if (!list1.isEmpty()) // the only non-modal dialog (tag dialog) has a list widget { list.at (i)->done (QDialog::Rejected); break; } } } /*************************/ void FN::scrolled (int) const { hlight(); } /*************************/ void FN::allBtn (bool checked) { if (checked) { ui->tagsButton->setChecked (false); ui->namesButton->setChecked (false); } } /*************************/ void FN::tagsAndNamesBtn (bool checked) { int index = ui->stackedWidget->currentIndex(); if (index == -1) return; if (checked) { /* first clear all search info except the search entry's text but don't do redundant operations */ if (!ui->tagsButton->isChecked() || !ui->namesButton->isChecked()) { QHash::iterator it; for (it = searchEntries_.begin(); it != searchEntries_.end(); ++it) { it.value() = QString(); disconnect (it.key()->verticalScrollBar(), &QAbstractSlider::valueChanged, this, &FN::scrolled); disconnect (it.key()->horizontalScrollBar(), &QAbstractSlider::valueChanged, this, &FN::scrolled); disconnect (it.key(), &TextEdit::resized, this, &FN::hlight); disconnect (it.key(), &QTextEdit::textChanged, this, &FN::hlight); QList extraSelections; greenSels_[it.key()] = extraSelections; it.key()->setExtraSelections (extraSelections); } } else // then uncheck the other radio buttons { if (QObject::sender() == ui->tagsButton) ui->namesButton->setChecked (false); else ui->tagsButton->setChecked (false); } ui->everywhereButton->setChecked (false); } if (QObject::sender() == ui->tagsButton) { ui->prevButton->setEnabled (!checked); ui->wholeButton->setEnabled (!checked); ui->caseButton->setEnabled (!checked); } } /*************************/ void FN::replaceDock() { if (!ui->dockReplace->isVisible()) { if (!ui->lineEdit->isVisible()) // replace dock needs searchbar { ui->lineEdit->setVisible (true); ui->nextButton->setVisible (true); ui->prevButton->setVisible (true); ui->caseButton->setVisible (true); ui->wholeButton->setVisible (true); ui->everywhereButton->setVisible (true); ui->tagsButton->setVisible (true); ui->namesButton->setVisible (true); } ui->dockReplace->setWindowTitle (tr ("Replacement")); ui->dockReplace->setVisible (true); ui->dockReplace->setTabOrder (ui->lineEditFind, ui->lineEditReplace); ui->dockReplace->setTabOrder (ui->lineEditReplace, ui->rplNextButton); ui->dockReplace->raise(); ui->dockReplace->activateWindow(); if (!ui->lineEditFind->hasFocus()) ui->lineEditFind->setFocus(); return; } ui->dockReplace->setVisible (false); // closeReplaceDock(false) is automatically called here } /*************************/ // When the dock is closed with its titlebar button, // clear the replacing text and remove green highlights. void FN::closeReplaceDock (bool visible) { if (visible || !isVisible() || isMinimized()) return; txtReplace_.clear(); /* remove green highlights */ QHash >::iterator it; for (it = greenSels_.begin(); it != greenSels_.end(); ++it) { QList extraSelectionsIth; greenSels_[it.key()] = extraSelectionsIth; it.key()->setExtraSelections (QList()); } hlight(); /* return focus to the document */ if (ui->stackedWidget->count() > 0) qobject_cast< TextEdit *>(ui->stackedWidget->currentWidget())->setFocus(); } /*************************/ // Resize the floating dock widget to its minimum size. void FN::resizeDock (bool topLevel) { if (topLevel) ui->dockReplace->resize (ui->dockReplace->minimumWidth(), ui->dockReplace->minimumHeight()); } /*************************/ void FN::replace() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); ui->dockReplace->setWindowTitle (tr ("Replacement")); QString txtFind = ui->lineEditFind->text(); if (txtFind.isEmpty()) return; if (txtReplace_ != ui->lineEditReplace->text()) { txtReplace_ = ui->lineEditReplace->text(); /* remove previous green highlights if the replacing text is changed */ QHash >::iterator it; for (it = greenSels_.begin(); it != greenSels_.end(); ++it) { QList extraSelectionsIth; greenSels_[it.key()] = extraSelectionsIth; it.key()->setExtraSelections (QList()); } } bool backwardSearch = false; QTextCursor start = textEdit->textCursor(); if (QObject::sender() == ui->rplNextButton) { if (rplOtherNode_) start.movePosition (QTextCursor::Start, QTextCursor::MoveAnchor); } else// if (QObject::sender() == ui->rplPrevButton) { backwardSearch = true; if (rplOtherNode_) start.movePosition (QTextCursor::End, QTextCursor::MoveAnchor); } QTextCursor found; if (!backwardSearch) found = finding (txtFind, start, searchFlags_); else found = finding (txtFind, start, searchFlags_ | QTextDocument::FindBackward); QList extraSelections = greenSels_[textEdit]; QModelIndex nxtIndx; if (found.isNull()) { if (ui->everywhereButton->isChecked()) { nxtIndx = ui->treeView->currentIndex(); Qt::CaseSensitivity cs = Qt::CaseInsensitive; if (ui->caseButton->isChecked()) cs = Qt::CaseSensitive; QString text; while (!text.contains (txtFind, cs)) { nxtIndx = model_->adjacentIndex (nxtIndx, !backwardSearch); if (!nxtIndx.isValid()) break; DomItem *item = static_cast(nxtIndx.internalPointer()); if (TextEdit *thisTextEdit = widgets_.value (item)) text = thisTextEdit->toPlainText(); // the node text may have been edited else { QDomNodeList list = item->node().childNodes(); text = list.item (0).nodeValue(); } } } rplOtherNode_ = false; } else { QColor green = qGray(fgColor_.rgb()) > 127 ? QColor (Qt::darkGreen) : QColor (Qt::green); int pos; QTextCursor tmp = start; start.setPosition (found.anchor()); pos = found.anchor(); start.setPosition (found.position(), QTextCursor::KeepAnchor); textEdit->setTextCursor (start); textEdit->insertPlainText (txtReplace_); if (rplOtherNode_) { /* the value of this boolean should be set to false but, in addition, we shake the splitter as a workaround for what seems to be a bug that makes ending parts of texts disappear after a text insertion */ QList sizes = ui->splitter->sizes(); QList newSizes; newSizes << sizes.first() + 1 << sizes.last() - 1; ui->splitter->setSizes (newSizes); ui->splitter->setSizes (sizes); rplOtherNode_ = false; } start = textEdit->textCursor(); // at the end of txtReplace_ tmp.setPosition (pos); tmp.setPosition (start.position(), QTextCursor::KeepAnchor); QTextEdit::ExtraSelection extra; extra.format.setBackground (green); extra.format.setUnderlineStyle (QTextCharFormat::WaveUnderline); extra.format.setUnderlineColor (fgColor_); extra.cursor = tmp; extraSelections.append (extra); if (QObject::sender() != ui->rplNextButton) { /* With the cursor at the end of the replacing text, if the backward replacement is repeated and the text is matched again (which is possible when the replacing and replaced texts are the same, case-insensitively), the replacement won't proceed. So, the cursor should be moved. */ start.setPosition (start.position() - txtReplace_.length()); textEdit->setTextCursor (start); } } greenSels_[textEdit] = extraSelections; textEdit->setExtraSelections (extraSelections); hlight(); if (nxtIndx.isValid()) { rplOtherNode_ = true; ui->treeView->setCurrentIndex (nxtIndx); replace(); } } /*************************/ void FN::replaceAll() { QString txtFind = ui->lineEditFind->text(); if (txtFind.isEmpty()) return; Qt::CaseSensitivity cs = Qt::CaseInsensitive; if (ui->caseButton->isChecked()) cs = Qt::CaseSensitive; QModelIndex nxtIndx; /* start with the first node when replacing everywhere */ if (!rplOtherNode_ && ui->everywhereButton->isChecked()) { nxtIndx = model_->index (0, 0); DomItem *item = static_cast(nxtIndx.internalPointer()); QString text; if (TextEdit *thisTextEdit = widgets_.value (item)) text = thisTextEdit->toPlainText(); // the node text may have been edited else { QDomNodeList list = item->node().childNodes(); text = list.item (0).nodeValue(); } while (!text.contains (txtFind, cs)) { nxtIndx = model_->adjacentIndex (nxtIndx, true); if (!nxtIndx.isValid()) { ui->dockReplace->setWindowTitle (tr ("No Match")); return; } item = static_cast(nxtIndx.internalPointer()); if (TextEdit *thisTextEdit = widgets_.value (item)) text = thisTextEdit->toPlainText(); else { QDomNodeList list = item->node().childNodes(); text = list.item (0).nodeValue(); } } rplOtherNode_ = true; ui->treeView->setCurrentIndex (nxtIndx); nxtIndx = QModelIndex(); } QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); if (txtReplace_ != ui->lineEditReplace->text()) { txtReplace_ = ui->lineEditReplace->text(); QHash >::iterator it; for (it = greenSels_.begin(); it != greenSels_.end(); ++it) { QList extraSelectionsIth; greenSels_[it.key()] = extraSelectionsIth; it.key()->setExtraSelections (QList()); } } QTextCursor orig = textEdit->textCursor(); orig.setPosition (orig.anchor()); textEdit->setTextCursor (orig); QColor green = qGray(fgColor_.rgb()) > 127 ? QColor (Qt::darkGreen) : QColor (Qt::green); int pos; QTextCursor found; QTextCursor start = orig; start.beginEditBlock(); start.setPosition (0); QTextCursor tmp = start; QTextEdit::ExtraSelection extra; extra.format.setBackground (green); extra.format.setUnderlineStyle (QTextCharFormat::WaveUnderline); extra.format.setUnderlineColor (fgColor_); QList extraSelections = greenSels_[textEdit]; while (!(found = finding (txtFind, start, searchFlags_)).isNull()) { start.setPosition (found.anchor()); pos = found.anchor(); start.setPosition (found.position(), QTextCursor::KeepAnchor); start.insertText (txtReplace_); if (rplOtherNode_) { QList sizes = ui->splitter->sizes(); QList newSizes; newSizes << sizes.first() + 1 << sizes.last() - 1; ui->splitter->setSizes (newSizes); ui->splitter->setSizes (sizes); rplOtherNode_ = false; } if (replCount_ < 1000) { tmp.setPosition (pos); tmp.setPosition (start.position(), QTextCursor::KeepAnchor); extra.cursor = tmp; extraSelections.append (extra); } start.setPosition (start.position()); ++replCount_; } rplOtherNode_ = false; greenSels_[textEdit] = extraSelections; start.endEditBlock(); textEdit->setExtraSelections (extraSelections); hlight(); if (ui->everywhereButton->isChecked() && model_->rowCount() > 1) { nxtIndx = ui->treeView->currentIndex(); QString text; while (!text.contains (txtFind, cs)) { nxtIndx = model_->adjacentIndex (nxtIndx, true); if (!nxtIndx.isValid()) break; DomItem *item = static_cast(nxtIndx.internalPointer()); if (TextEdit *thisTextEdit = widgets_.value (item)) text = thisTextEdit->toPlainText(); else { QDomNodeList list = item->node().childNodes(); text = list.item (0).nodeValue(); } } } if (nxtIndx.isValid()) { rplOtherNode_ = true; ui->treeView->setCurrentIndex (nxtIndx); replaceAll(); } else { if (replCount_ == 0) ui->dockReplace->setWindowTitle (tr ("No Replacement")); else if (replCount_ == 1) ui->dockReplace->setWindowTitle (tr ("One Replacement")); else { ui->dockReplace->setWindowTitle (tr ("%1 Replacements").arg (replCount_)); if (replCount_ > 1000 && !txtReplace_.isEmpty()) { MessageBox msgBox (QMessageBox::Information, tr ("FeatherNotes"), "
" + tr ("The first 1000 replacements are highlighted.") + "
", QMessageBox::Close, this); msgBox.changeButtonText (QMessageBox::Close, tr ("Close")); msgBox.setParent (this, Qt::Dialog); msgBox.setWindowModality (Qt::WindowModal); msgBox.exec(); } } replCount_ = 0; } } /*************************/ void FN::showEvent (QShowEvent *event) { /* To position the main window correctly with translucency when it's shown for the first time, we use setGeometry() inside showEvent(). */ if (!shownBefore_ && !event->spontaneous()) { shownBefore_ = true; if (remPosition_) { QSize theSize = (remSize_ ? winSize_ : startSize_); setGeometry (position_.x() - (underE_ ? EShift_.width() : 0), position_.y() - (underE_ ? EShift_.height() : 0), theSize.width(), theSize.height()); } } QWidget::showEvent (event); } /*************************/ void FN::showAndFocus() { show(); raise(); activateWindow(); if (ui->stackedWidget->count() > 0) qobject_cast< TextEdit *>(ui->stackedWidget->currentWidget())->setFocus(); // to bypass focus stealing prevention QTimer::singleShot (0, this, &FN::stealFocus); } /*************************/ void FN::stealFocus() { if (QWindow *win = windowHandle()) win->requestActivate(); } /*************************/ void FN::trayActivated (QSystemTrayIcon::ActivationReason r) { if (!tray_) return; if (r != QSystemTrayIcon::Trigger) return; if (QObject::sender() == tray_ && findChildren().count() > 0) { // don't respond to the tray icon when there's a dialog raise(); activateWindow(); return; } if (!isVisible()) { /* make the widget an independent window again */ /*if (parent() != nullptr) setParent (nullptr, Qt::Window); QTimer::singleShot (0, this, SLOT (show()));*/ show(); #ifdef HAS_X11 if (isX11_ && onWhichDesktop (winId()) != fromDesktop()) moveToCurrentDesktop (winId()); #endif showAndFocus(); } #ifdef HAS_X11 else if (!isX11_ || onWhichDesktop (winId()) == fromDesktop()) { if (isX11_ && underE_) { hide(); QTimer::singleShot (250, this, &QWidget::show); return; } QRect sr; if (QWindow *win = windowHandle()) { if (QScreen *sc = win->screen()) sr = sc->virtualGeometry(); } if (sr.isNull()) { if (QScreen *pScreen = QApplication::primaryScreen()) sr = pScreen->virtualGeometry(); } QRect g = geometry(); if (g.x() >= sr.left() && g.x() + g.width() <= sr.left() + sr.width() && g.y() >= sr.top() && g.y() + g.height() <= sr.top() + sr.height()) { if (isActiveWindow()) { if (!isMaximized() && !isFullScreen()) { position_.setX (g.x()); position_.setY (g.y()); } /* instead of hiding the window in the ususal way, reparent it to preserve its state info */ //setParent (dummyWidget, Qt::SubWindow); QTimer::singleShot (0, this, &QWidget::hide); } else { if (isMinimized()) showNormal(); showAndFocus(); } } else { hide(); setGeometry (position_.x(), position_.y(), g.width(), g.height()); QTimer::singleShot (0, this, &FN::showAndFocus); } } else { if (isX11_) moveToCurrentDesktop (winId()); if (isMinimized()) showNormal(); showAndFocus(); } #else /* without X11, just iconify the window */ else QTimer::singleShot (0, this, &QWidget::hide); #endif } /*************************/ void FN::activateTray() { QObject *sender = QObject::sender(); if (sender != nullptr && sender->objectName() == "raiseHide" && findChildren().count() > 0) { // don't respond to the tray icon when there's a dialog raise(); activateWindow(); return; } trayActivated (QSystemTrayIcon::Trigger); } /*************************/ void FN::insertLink() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); QTextCursor cur = textEdit->textCursor(); if (!cur.hasSelection()) return; /* only if the position is after the anchor, the format will be detected correctly */ int pos, anch; QTextCursor cursor = cur; if ((pos = cur.position()) < (anch = cur.anchor())) { cursor.setPosition (pos); cursor.setPosition (anch, QTextCursor::KeepAnchor); } QTextCharFormat format = cursor.charFormat(); QString href = format.anchorHref(); QDialog *dialog = new QDialog (this); dialog->setWindowTitle (tr ("Insert Link")); QGridLayout *grid = new QGridLayout; grid->setSpacing (5); grid->setContentsMargins (5, 5, 5, 5); /* needed widgets */ LineEdit *linkEntry = new LineEdit(); linkEntry->returnOnClear = false; linkEntry->setMinimumWidth (250); linkEntry->setText (href); connect (linkEntry, &QLineEdit::returnPressed, dialog, &QDialog::accept); QSpacerItem *spacer = new QSpacerItem (1, 5); QPushButton *cancelButton = new QPushButton (symbolicIcon::icon (":icons/dialog-cancel.svg"), tr ("Cancel")); connect (cancelButton, &QAbstractButton::clicked, dialog, &QDialog::reject); QPushButton *okButton = new QPushButton (symbolicIcon::icon (":icons/dialog-ok.svg"), tr ("OK")); connect (okButton, &QAbstractButton::clicked, dialog, &QDialog::accept); /* fit in the grid */ grid->addWidget (linkEntry, 0, 0, 1, 3); grid->addItem (spacer, 1, 0); grid->addWidget (cancelButton, 2, 1, Qt::AlignRight); grid->addWidget (okButton, 2, 2, Qt::AlignRight); grid->setColumnStretch (0, 1); grid->setRowStretch (1, 1); /* show the dialog */ dialog->setLayout (grid); /*dialog->resize (dialog->minimumWidth(), dialog->minimumHeight());*/ /*dialog->show(); dialog->move (x() + width()/2 - dialog->width(), y() + height()/2 - dialog->height());*/ QString address; switch (dialog->exec()) { case QDialog::Accepted: address = linkEntry->text(); delete dialog; break; case QDialog::Rejected: default: delete dialog; return; } if (!address.isEmpty()) { format.setAnchor (true); format.setFontUnderline (true); format.setFontItalic (true); format.setForeground (QColor (0, 0, 255)); } else { format.setAnchor (false); format.setFontUnderline (false); format.setFontItalic (false); format.setForeground (QBrush()); } format.setAnchorHref (address); cur.mergeCharFormat (format); } /*************************/ void FN::embedImage() { int index = ui->stackedWidget->currentIndex(); if (index == -1) return; QDialog *dialog = new QDialog (this); dialog->setWindowTitle (tr ("Embed Image")); QGridLayout *grid = new QGridLayout; grid->setSpacing (5); grid->setContentsMargins (5, 5, 5, 5); /* create the needed widgets */ ImagePathEntry_ = new LineEdit(); ImagePathEntry_->returnOnClear = false; ImagePathEntry_->setMinimumWidth (200); ImagePathEntry_->setToolTip (tr ("Image path")); connect (ImagePathEntry_, &QLineEdit::returnPressed, dialog, &QDialog::accept); QToolButton *openBtn = new QToolButton(); openBtn->setIcon (symbolicIcon::icon (":icons/document-open.svg")); openBtn->setToolTip (tr ("Open image")); connect (openBtn, &QAbstractButton::clicked, this, &FN::setImagePath); QLabel *label = new QLabel(); label->setText (tr ("Scale to")); SpinBox *spinBox = new SpinBox(); spinBox->setRange (1, 200); spinBox->setValue (imgScale_); spinBox->setSuffix (tr ("%")); spinBox->setToolTip (tr ("Scaling percentage")); connect (spinBox, &QAbstractSpinBox::editingFinished, dialog, &QDialog::accept); QSpacerItem *spacer = new QSpacerItem (1, 10); QPushButton *cancelButton = new QPushButton (symbolicIcon::icon (":icons/dialog-cancel.svg"), tr ("Cancel")); QPushButton *okButton = new QPushButton (symbolicIcon::icon (":icons/dialog-ok.svg"), tr ("OK")); connect (cancelButton, &QAbstractButton::clicked, dialog, &QDialog::reject); connect (okButton, &QAbstractButton::clicked, dialog, &QDialog::accept); /* make the widgets fit in the grid */ grid->addWidget (ImagePathEntry_, 0, 0, 1, 4); grid->addWidget (openBtn, 0, 4, Qt::AlignCenter); grid->addWidget (label, 1, 0, Qt::AlignRight); grid->addWidget (spinBox, 1, 1, Qt::AlignLeft); grid->addItem (spacer, 2, 0); grid->addWidget (cancelButton, 3, 2, Qt::AlignRight); grid->addWidget (okButton, 3, 3, 1, 2, Qt::AlignCenter); grid->setColumnStretch (1, 1); grid->setRowStretch (2, 1); /* show the dialog */ dialog->setLayout (grid); /*dialog->resize (dialog->minimumWidth(), dialog->minimumHeight());*/ //dialog->setFixedHeight (dialog->sizeHint().height()); /*dialog->show(); dialog->move (x() + width()/2 - dialog->width(), y() + height()/2 - dialog->height());*/ switch (dialog->exec()) { case QDialog::Accepted: lastImgPath_ = ImagePathEntry_->text(); imgScale_ = spinBox->value(); delete dialog; ImagePathEntry_ = nullptr; break; case QDialog::Rejected: default: lastImgPath_ = ImagePathEntry_->text(); delete dialog; ImagePathEntry_ = nullptr; return; } imageEmbed (lastImgPath_); } /*************************/ void FN::imageEmbed (const QString &path) { if (path.isEmpty()) return; QFile file (path); if (!file.open (QIODevice::ReadOnly)) return; /* read the data serialized from the file */ QDataStream in (&file); QByteArray rawarray; QDataStream datastream (&rawarray, QIODevice::WriteOnly); char a; /* copy between the two data streams */ while (in.readRawData (&a, 1) != 0) datastream.writeRawData (&a, 1); file.close(); QByteArray base64array = rawarray.toBase64(); QImage img = QImage (path); QSize imgSize = img.size(); int w, h; if (QObject::sender() == ui->actionEmbedImage) { w = imgSize.width() * imgScale_ / 100; h = imgSize.height() * imgScale_ / 100; } else { w = imgSize.width(); h = imgSize.height(); } TextEdit *textEdit = qobject_cast< TextEdit *>(ui->stackedWidget->currentWidget()); //QString ("") textEdit->insertHtml (QString ("") .arg (QString (base64array)) .arg (w) .arg (h)); raise(); activateWindow(); } /*************************/ void FN::setImagePath (bool) { QString path; if (!lastImgPath_.isEmpty()) { if (QFile::exists (lastImgPath_)) path = lastImgPath_; else { QDir dir = QFileInfo (lastImgPath_).absoluteDir(); if (!dir.exists()) dir = QDir::home(); path = dir.path(); } } else path = QDir::home().path(); QString imagePath; FileDialog dialog (this); dialog.setAcceptMode (QFileDialog::AcceptOpen); dialog.setWindowTitle (tr ("Open Image...")); dialog.setFileMode (QFileDialog::ExistingFiles); dialog.setNameFilter (tr ("Image Files (*.svg *.png *.jpg *.jpeg *.bmp *.gif);;All Files (*)")); if (QFileInfo (path).isDir()) dialog.setDirectory (path); else { dialog.setDirectory (path.section ("/", 0, -2)); // workaround for KDE dialog.selectFile (path); dialog.autoScroll(); } if (dialog.exec()) { QStringList files = dialog.selectedFiles(); if (files.count() > 0) imagePath = files.at (0); } if (!imagePath.isEmpty()) ImagePathEntry_->setText (imagePath); } /*************************/ bool FN::isImageSelected() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return false; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); QTextCursor cur = textEdit->textCursor(); if (!cur.hasSelection()) return false; QTextDocumentFragment docFrag = cur.selection(); QString txt = docFrag.toHtml(); if (txt.contains (QRegularExpression (EMBEDDED_IMG))) return true; return false; } /*************************/ void FN::scaleImage() { QDialog *dialog = new QDialog (this); dialog->setWindowTitle (tr ("Scale Image(s)")); QGridLayout *grid = new QGridLayout; grid->setSpacing (5); grid->setContentsMargins (5, 5, 5, 5); QLabel *label = new QLabel(); label->setText (tr ("Scale to")); SpinBox *spinBox = new SpinBox(); spinBox->setRange (1, 200); spinBox->setSuffix (tr ("%")); spinBox->setToolTip (tr ("Scaling percentage")); connect (spinBox, &QAbstractSpinBox::editingFinished, dialog, &QDialog::accept); QSpacerItem *spacer = new QSpacerItem (1, 10); QPushButton *cancelButton = new QPushButton (symbolicIcon::icon (":icons/dialog-cancel.svg"), tr ("Cancel")); QPushButton *okButton = new QPushButton (symbolicIcon::icon (":icons/dialog-ok.svg"), tr ("OK")); connect (cancelButton, &QAbstractButton::clicked, dialog, &QDialog::reject); connect (okButton, &QAbstractButton::clicked, dialog, &QDialog::accept); grid->addWidget (label, 0, 0, Qt::AlignRight); grid->addWidget (spinBox, 0, 1, 1, 2, Qt::AlignLeft); grid->addItem (spacer, 1, 0); grid->addWidget (cancelButton, 2, 1, 1, 2, Qt::AlignRight); grid->addWidget (okButton, 2, 3, Qt::AlignCenter); grid->setColumnStretch (1, 1); grid->setRowStretch (1, 1); TextEdit *textEdit = qobject_cast< TextEdit *>(ui->stackedWidget->currentWidget()); QTextCursor cur = textEdit->textCursor(); QTextDocumentFragment docFrag = cur.selection(); if (docFrag.isEmpty()) return; QString txt = docFrag.toHtml(); QRegularExpression imageExp (R"((?<=\s)src\s*=\s*"data:[^<>]*;base64\s*,[a-zA-Z0-9+=/\s]+)"); QRegularExpressionMatch match; QSize imageSize; int W = 0, H = 0; int startIndex = txt.indexOf (EMBEDDED_IMG, 0, &match); if (startIndex == -1) return; QString str = txt.mid (startIndex, match.capturedLength()); int indx = str.lastIndexOf (imageExp, -1, &match); QString imgStr = str.mid (indx, match.capturedLength()); imgStr.remove (QRegularExpression (R"(src\s*=\s*"data:[^<>]*;base64\s*,)")); QImage image; if (image.loadFromData (QByteArray::fromBase64 (imgStr.toUtf8()))) imageSize = image.size(); if (imageSize.isEmpty()) return; int scale = 100; /* first, check the (last) width */ if ((indx = str.lastIndexOf (QRegularExpression (R"(width\s*=\s*"\s*(\+|-){0,1}[0-9]+\s*")"), -1, &match)) != -1) { bool ok; str = str.mid (indx, match.capturedLength()); str.remove (QRegularExpression (R"(width\s*=\s*"\s*)")); str.remove (QRegularExpression (R"(\s*")")); W = str.toInt(&ok); if (!ok) W = 0; W = qMax (W, 0); scale = 100 * W / imageSize.width(); } /* if there's no width, check the (last) height */ else if ((indx = str.lastIndexOf (QRegularExpression (R"(height\s*=\s*"\s*(\+|-){0,1}[0-9]+\s*")"), -1, &match)) != -1) { bool ok; str = str.mid (indx, match.capturedLength()); str.remove (QRegularExpression (R"(height\s*=\s*"\s*)")); str.remove (QRegularExpression (R"(\s*")")); H = str.toInt(&ok); if (!ok) H = 0; H = qMax (H, 0); scale = 100 * H / imageSize.height(); } spinBox->setValue (scale); /* show the dialog */ dialog->setLayout (grid); /*dialog->resize (dialog->minimumWidth(), dialog->minimumHeight());*/ /*dialog->show(); dialog->move (x() + width()/2 - dialog->width(), y() + height()/2 - dialog->height());*/ switch (dialog->exec()) { case QDialog::Accepted: scale = spinBox->value(); delete dialog; break; case QDialog::Rejected: default: delete dialog; return; } while ((indx = txt.indexOf (EMBEDDED_IMG, startIndex, &match)) != -1) { str = txt.mid (indx, match.capturedLength()); if (imageSize.isEmpty()) // already calculated for the first image { QRegularExpressionMatch imageMatch; int pos = str.lastIndexOf (imageExp, -1, &imageMatch); if (pos == -1) { startIndex = indx + match.capturedLength(); continue; } imgStr = str.mid (pos, imageMatch.capturedLength()); imgStr.remove (QRegularExpression (R"(src\s*=\s*"data:[^<>]*;base64\s*,)")); QImage image; if (!image.loadFromData (QByteArray::fromBase64 (imgStr.toUtf8()))) { startIndex = indx + match.capturedLength(); continue; } imageSize = image.size(); if (imageSize.isEmpty()) return; } W = imageSize.width() * scale / 100; H = imageSize.height() * scale / 100; txt.replace (indx, match.capturedLength(), "").arg (W).arg (H)); imageSize = QSize(); // for the next image /* since the text is changed, startIndex should be found again */ indx = txt.indexOf (EMBEDDED_IMG, startIndex, &match); startIndex = indx + match.capturedLength(); } cur.insertHtml (txt); } /*************************/ void FN::saveImage() { TextEdit *textEdit = qobject_cast< TextEdit *>(ui->stackedWidget->currentWidget()); QTextCursor cur = textEdit->textCursor(); QTextDocumentFragment docFrag = cur.selection(); if (docFrag.isEmpty()) return; QString txt = docFrag.toHtml(); QString path; if (!xmlPath_.isEmpty()) { QDir dir = QFileInfo (xmlPath_).absoluteDir(); if (!dir.exists()) dir = QDir::home(); path = dir.path(); QString shownName = QFileInfo (xmlPath_).fileName(); if (shownName.endsWith (".fnx")) shownName.chop (4); path += "/" + shownName; } else { QDir dir = QDir::home(); path = dir.path(); path += "/" + tr ("untitled"); } QRegularExpression imageExp (R"((?<=\s)src\s*=\s*"data:[^<>]*;base64\s*,[a-zA-Z0-9+=/\s]+)"); int indx; int startIndex = 0; int n = 1; QString extension = "png"; QRegularExpressionMatch match; while ((indx = txt.indexOf (EMBEDDED_IMG, startIndex, &match)) != -1) { QString str = txt.mid (indx, match.capturedLength()); startIndex = indx + match.capturedLength(); indx = str.lastIndexOf (imageExp, -1, &match); if (indx == -1) continue; str = str.mid (indx, match.capturedLength()); str.remove (QRegularExpression (R"(src\s*=\s*"data:[^<>]*;base64\s*,)")); QImage image; if (!image.loadFromData (QByteArray::fromBase64 (str.toUtf8()))) continue; bool retry (true); bool err (false); while (retry) { if (err) { MessageBox msgBox; msgBox.setIcon (QMessageBox::Question); msgBox.setWindowTitle (tr ("Error")); msgBox.setText (tr ("
Image cannot be saved! Retry?
")); msgBox.setInformativeText (tr ("
Maybe you did not choose a proper extension
\n"\ "
or do not have write permission.

")); msgBox.setStandardButtons (QMessageBox::Yes | QMessageBox::No); msgBox.changeButtonText (QMessageBox::Yes, tr ("Yes")); msgBox.changeButtonText (QMessageBox::No, tr ("No")); msgBox.setDefaultButton (QMessageBox::No); msgBox.setParent (this, Qt::Dialog); msgBox.setWindowModality (Qt::WindowModal); msgBox.show(); msgBox.move (x() + width()/2 - msgBox.width()/2, y() + height()/2 - msgBox.height()/ 2); switch (msgBox.exec()) { case QMessageBox::Yes: break; case QMessageBox::No: default: retry = false; // next image without saving this one break; } } if (retry) { QString fname; FileDialog dialog (this); dialog.setAcceptMode (QFileDialog::AcceptSave); dialog.setWindowTitle (tr ("Save Image As...")); dialog.setFileMode (QFileDialog::AnyFile); dialog.setNameFilter (tr ("Image Files (*.png *.jpg *.jpeg *.bmp);;All Files (*)")); dialog.setDirectory (path.section ("/", 0, -2)); // workaround for KDE dialog.selectFile (QString ("%1-%2.%3").arg (path).arg (n).arg (extension)); dialog.autoScroll(); if (dialog.exec()) { fname = dialog.selectedFiles().at (0); if (fname.isEmpty() || QFileInfo (fname).isDir()) { err = true; continue; } } else return; if (image.save (fname)) { lastImgPath_ = fname; QFileInfo info = QFileInfo (lastImgPath_); QString shownName = info.fileName(); extension = shownName.split (".").last(); shownName.chop (extension.count() + 1); /* if the name ends with a number following a dash, use it; otherwise, increase the number by one */ int m = 0; QRegularExpression exp ("-[1-9]+[0-9]*"); indx = shownName.lastIndexOf (QRegularExpression ("-[1-9]+[0-9]*"), -1, &match); if (indx > -1 && indx == shownName.count() - match.capturedLength()) { QString number = shownName.split ("-").last(); shownName.chop (number.count() + 1); m = number.toInt() + 1; } n = m > n ? m : n + 1; path = info.dir().path() + "/" + shownName; retry = false; // next image after saving this one } else err = true; } } } } /*************************/ void FN::addTable() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; QDialog *dialog = new QDialog (this); dialog->setWindowTitle (tr ("Insert Table")); QGridLayout *grid = new QGridLayout; grid->setSpacing (5); grid->setContentsMargins (5, 5, 5, 5); QLabel *labelRow = new QLabel(); labelRow->setText (tr ("Rows:")); SpinBox *spinBoxRow = new SpinBox(); spinBoxRow->setRange (1, 100); spinBoxRow->setValue (1); connect (spinBoxRow, &QAbstractSpinBox::editingFinished, dialog, &QDialog::accept); QLabel *labelCol = new QLabel(); labelCol->setText (tr ("Columns:")); SpinBox *spinBoxCol = new SpinBox(); spinBoxCol->setRange (1, 100); spinBoxCol->setValue (1); connect (spinBoxCol, &QAbstractSpinBox::editingFinished, dialog, &QDialog::accept); QSpacerItem *spacer = new QSpacerItem (1, 10); QPushButton *cancelButton = new QPushButton (symbolicIcon::icon (":icons/dialog-cancel.svg"), tr ("Cancel")); QPushButton *okButton = new QPushButton (symbolicIcon::icon (":icons/dialog-ok.svg"), tr ("OK")); connect (cancelButton, &QAbstractButton::clicked, dialog, &QDialog::reject); connect (okButton, &QAbstractButton::clicked, dialog, &QDialog::accept); grid->addWidget (labelRow, 0, 0, Qt::AlignRight); grid->addWidget (spinBoxRow, 0, 1, 1, 2, Qt::AlignLeft); grid->addWidget (labelCol, 1, 0, Qt::AlignRight); grid->addWidget (spinBoxCol, 1, 1, 1, 2, Qt::AlignLeft); grid->addItem (spacer, 2, 0); grid->addWidget (cancelButton, 3, 0, 1, 2, Qt::AlignRight); grid->addWidget (okButton, 3, 2, Qt::AlignLeft); grid->setColumnStretch (1, 2); grid->setRowStretch (2, 1); dialog->setLayout (grid); /*dialog->resize (dialog->minimumWidth(), dialog->minimumHeight());*/ /*dialog->show(); dialog->move (x() + width()/2 - dialog->width(), y() + height()/2 - dialog->height());*/ int rows = 0; int columns = 0; switch (dialog->exec()) { case QDialog::Accepted: rows = spinBoxRow->value(); columns = spinBoxCol->value(); delete dialog; break; case QDialog::Rejected: default: delete dialog; return; } TextEdit *textEdit = qobject_cast< TextEdit *>(cw); QTextCursor cur = textEdit->textCursor(); QTextTableFormat tf; tf.setCellPadding (3); QTextTable *table = cur.insertTable (rows, columns); table->setFormat (tf); } /*************************/ void FN::tableMergeCells() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); QTextCursor cur = textEdit->textCursor(); txtTable_->mergeCells (cur); } /*************************/ void FN::tablePrependRow() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); QTextCursor cur = textEdit->textCursor(); QTextTableCell tableCell = txtTable_->cellAt (cur); txtTable_->insertRows (tableCell.row(), 1); } /*************************/ void FN::tableAppendRow() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); QTextCursor cur = textEdit->textCursor(); QTextTableCell tableCell = txtTable_->cellAt (cur); txtTable_->insertRows (tableCell.row() + 1, 1); } /*************************/ void FN::tablePrependCol() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); QTextCursor cur = textEdit->textCursor(); QTextTableCell tableCell = txtTable_->cellAt (cur); txtTable_->insertColumns (tableCell.column(), 1); } /*************************/ void FN::tableAppendCol() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); QTextCursor cur = textEdit->textCursor(); QTextTableCell tableCell = txtTable_->cellAt (cur); txtTable_->insertColumns (tableCell.column() + 1, 1); } /*************************/ void FN::tableDeleteRow() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); QTextCursor cur = textEdit->textCursor(); QTextTableCell tableCell = txtTable_->cellAt (cur); txtTable_->removeRows (tableCell.row(), 1); } /*************************/ void FN::tableDeleteCol() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; TextEdit *textEdit = qobject_cast< TextEdit *>(cw); QTextCursor cur = textEdit->textCursor(); QTextTableCell tableCell = txtTable_->cellAt (cur); txtTable_->removeColumns (tableCell.column(), 1); } /*************************/ void FN::toggleWrapping() { int count = ui->stackedWidget->count(); if (count == 0) return; if (ui->actionWrap->isChecked()) { for (int i = 0; i < count; ++i) qobject_cast< TextEdit *>(ui->stackedWidget->widget (i))->setLineWrapMode (QTextEdit::WidgetWidth); } else { for (int i = 0; i < count; ++i) qobject_cast< TextEdit *>(ui->stackedWidget->widget (i))->setLineWrapMode (QTextEdit::NoWrap); } hlight(); } /*************************/ void FN::toggleIndent() { int count = ui->stackedWidget->count(); if (count == 0) return; if (ui->actionIndent->isChecked()) { for (int i = 0; i < count; ++i) qobject_cast< TextEdit *>(ui->stackedWidget->widget (i))->autoIndentation = true; } else { for (int i = 0; i < count; ++i) qobject_cast< TextEdit *>(ui->stackedWidget->widget (i))->autoIndentation = false; } } /*************************/ void FN::prefDialog() { /* first, update settings because another FeatherNotes window may have changed them */ readAndApplyConfig (false); PrefDialog dlg (this); dlg.exec(); } /*************************/ QByteArray FN::getSpltiterState() const { return ui->splitter->saveState(); } /*************************/ void FN::makeTreeTransparent (bool trans) { if (trans) { if (!transparentTree_) { transparentTree_ = true; ui->treeView->setFrameShape (QFrame::NoFrame); if (ui->treeView->viewport()) { QPalette p = ui->treeView->palette(); p.setColor (QPalette::Base, QColor (Qt::transparent)); p.setColor (QPalette::Text, p.color (QPalette::WindowText)); ui->treeView->setPalette (p); ui->treeView->viewport()->setAutoFillBackground (false); } } } else { if (transparentTree_) { transparentTree_ = false; ui->treeView->setFrameShape (QFrame::StyledPanel); if (ui->treeView->viewport()) { ui->treeView->setPalette (QPalette()); ui->treeView->viewport()->setAutoFillBackground (true); } } } } /*************************/ void FN::setToolBarIconSize (bool small) { if (small) { if (!smallToolbarIcons_) { smallToolbarIcons_ = true; ui->mainToolBar->setIconSize (QSize (16, 16)); } } else { if (smallToolbarIcons_) { smallToolbarIcons_ = false; ui->mainToolBar->setIconSize (TOOLBAR_ICON_SIZE); } } } /*************************/ void FN::showToolbar (bool show) { ui->mainToolBar->setVisible (show); noToolbar_ = !show; } /*************************/ void FN::showMenubar (bool show) { ui->menuBar->setVisible (show); ui->actionMenu->setVisible (!show); noMenubar_ = !show; } /*************************/ void FN::setUnderE (bool yes) { if (yes) { if (!underE_) { underE_ = true; if (tray_) { if (QAction *actionshowMainWindow = tray_->contextMenu()->findChild("raiseHide")) actionshowMainWindow->setText (tr ("&Raise")); } } } else { if (underE_) { underE_ = false; if (tray_) { if (QAction *actionshowMainWindow = tray_->contextMenu()->findChild("raiseHide")) actionshowMainWindow->setText (tr ("&Raise/Hide")); } } } } /*************************/ void FN::updateCustomizableShortcuts() { QHash::const_iterator iter = defaultShortcuts_.constBegin(); QList cn = customActions_.keys(); while (iter != defaultShortcuts_.constEnd()) { const QString name = iter.key()->objectName(); iter.key()->setShortcut (cn.contains (name) ? QKeySequence (customActions_.value (name), QKeySequence::PortableText) : iter.value()); ++ iter; } } /*************************/ void FN::readShortcuts() { /* NOTE: We don't read the custom shortcuts from global config files because we want the user to be able to restore their default values. */ Settings tmp ("feathernotes", "fn"); Settings settings (tmp.fileName(), QSettings::NativeFormat); settings.beginGroup ("shortcuts"); QStringList actions = settings.childKeys(); for (int i = 0; i < actions.size(); ++i) { QVariant v = settings.value (actions.at (i)); bool isValid; QString vs = validatedShortcut (v, &isValid); if (isValid) customActions_.insert (actions.at (i), vs); else // remove the key on writing config uncustomizedActions_ << actions.at (i); } settings.endGroup(); } /*************************/ QString FN::validatedShortcut (const QVariant v, bool *isValid) { static QStringList added; if (v.isValid()) { QString str = v.toString(); if (str.isEmpty()) { // it means the removal of a shortcut *isValid = true; return QString(); } if (!QKeySequence (str, QKeySequence::PortableText).toString().isEmpty()) { if (!reservedShortcuts_.contains (str) // prevent ambiguous shortcuts at startup as far as possible && !added.contains (str)) { *isValid = true; added << str; return str; } } } *isValid = false; return QString(); } /*************************/ void FN::readAndApplyConfig (bool startup) { QSettings settings ("feathernotes", "fn"); /************** *** Window *** **************/ settings.beginGroup ("window"); startSize_ = settings.value ("startSize", QSize (700, 500)).toSize(); if (startSize_.isEmpty()) startSize_ = QSize (700, 500); if (settings.value ("size").toString() == "none") { remSize_ = false; // true by default if (startup) resize (startSize_); } else { remSize_ = true; winSize_ = settings.value ("size", QSize (700, 500)).toSize(); if (winSize_.isEmpty()) winSize_ = QSize (700, 500); if (startup) resize (winSize_); } if (settings.value ("splitterSizes").toString() == "none") remSplitter_ = false; // true by default else { remSplitter_ = true; splitterSizes_ = settings.value ("splitterSizes", splitterSizes_).toByteArray(); } if (startup) ui->splitter->restoreState (splitterSizes_); if (settings.value ("position").toString() == "none") remPosition_ = false; // true by default else { remPosition_ = true; position_ = settings.value ("position", QPoint (0, 0)).toPoint(); } prefSize_ = settings.value ("prefSize").toSize(); hasTray_ = settings.value ("hasTray").toBool(); // false by default minToTray_ = settings.value ("minToTray").toBool(); // false by default bool bv = settings.value ("underE").toBool(); // false by default if (startup) underE_ = bv; else setUnderE (bv); if (settings.contains ("Shift")) EShift_ = settings.value ("Shift").toSize(); else EShift_ = QSize (0, 0); if (settings.value ("transparentTree").toBool()) // false by default makeTreeTransparent (true); else if (!startup) makeTreeTransparent (false); if (settings.value ("smallToolbarIcons").toBool()) // false by default setToolBarIconSize (true); else if (!startup) setToolBarIconSize (false); noToolbar_ = settings.value ("noToolbar").toBool(); // false by default noMenubar_ = settings.value ("noMenubar").toBool(); // false by default if (noToolbar_ && noMenubar_) { // we don't want to hide all actions noToolbar_ = false; noMenubar_ = true; } ui->mainToolBar->setVisible (!noToolbar_); ui->menuBar->setVisible (!noMenubar_); ui->actionMenu->setVisible (noMenubar_); if (startup) { QIcon icn; icn = symbolicIcon::icon (":icons/go-down.svg"); ui->nextButton->setIcon (icn); ui->rplNextButton->setIcon (icn); ui->actionMoveDown->setIcon (icn); icn = symbolicIcon::icon (":icons/go-up.svg"); ui->prevButton->setIcon (icn); ui->rplPrevButton->setIcon (icn); ui->actionMoveUp->setIcon (icn); ui->allButton->setIcon (symbolicIcon::icon (":icons/arrow-down-double.svg")); icn = symbolicIcon::icon (":icons/document-save.svg"); ui->actionSave->setIcon (icn); ui->actionImageSave->setIcon (icn); ui->actionOpen->setIcon (symbolicIcon::icon (":icons/document-open.svg")); ui->actionUndo->setIcon (symbolicIcon::icon (":icons/edit-undo.svg")); ui->actionRedo->setIcon (symbolicIcon::icon (":icons/edit-redo.svg")); ui->actionFind->setIcon (symbolicIcon::icon (":icons/edit-find.svg")); ui->actionClear->setIcon (symbolicIcon::icon (":icons/edit-clear.svg")); ui->actionBold->setIcon (symbolicIcon::icon (":icons/format-text-bold.svg")); ui->actionItalic->setIcon (symbolicIcon::icon (":icons/format-text-italic.svg")); ui->actionUnderline->setIcon (symbolicIcon::icon (":icons/format-text-underline.svg")); ui->actionStrike->setIcon (symbolicIcon::icon (":icons/format-text-strikethrough.svg")); ui->actionTextColor->setIcon (symbolicIcon::icon (":icons/format-text-color.svg")); icn = symbolicIcon::icon (":icons/format-fill-color.svg"); ui->actionBgColor->setIcon (icn); ui->actionDocColors->setIcon (icn); ui->actionNew->setIcon (symbolicIcon::icon (":icons/document-new.svg")); ui->actionSaveAs->setIcon (symbolicIcon::icon (":icons/document-save-as.svg")); icn = symbolicIcon::icon (":icons/document-print.svg"); ui->actionPrint->setIcon (icn); ui->actionPrintNodes->setIcon (icn); ui->actionPrintAll->setIcon (icn); ui->actionPassword->setIcon (symbolicIcon::icon (":icons/document-encrypt.svg")); ui->actionQuit->setIcon (symbolicIcon::icon (":icons/application-exit.svg")); ui->actionCut->setIcon (symbolicIcon::icon (":icons/edit-cut.svg")); ui->actionCopy->setIcon (symbolicIcon::icon (":icons/edit-copy.svg")); icn = symbolicIcon::icon (":icons/edit-paste.svg"); ui->actionPaste->setIcon (icn); ui->actionPasteHTML->setIcon (icn); ui->actionDelete->setIcon (symbolicIcon::icon (":icons/edit-delete.svg")); ui->actionSelectAll->setIcon (symbolicIcon::icon (":icons/edit-select-all.svg")); ui->actionDate->setIcon (symbolicIcon::icon (":icons/document-open-recent.svg")); icn = symbolicIcon::icon (":icons/image-x-generic.svg"); ui->actionEmbedImage->setIcon (icn); ui->actionImageScale->setIcon (icn); ui->actionNodeIcon->setIcon (icn); ui->actionExpandAll->setIcon (symbolicIcon::icon (":icons/expand.svg")); ui->actionCollapseAll->setIcon (symbolicIcon::icon (":icons/collapse.svg")); ui->actionDeleteNode->setIcon (symbolicIcon::icon (":icons/user-trash.svg")); icn = symbolicIcon::icon (":icons/edit-rename.svg"); ui->actionRenameNode->setIcon (icn); ui->namesButton->setIcon (icn); ui->actionProp->setIcon (symbolicIcon::icon (":icons/document-properties.svg")); icn = symbolicIcon::icon (":icons/preferences-desktop-font.svg"); ui->actionDocFont->setIcon (icn); ui->actionNodeFont->setIcon (icn); ui->actionPref->setIcon (symbolicIcon::icon (":icons/preferences-system.svg")); ui->actionReplace->setIcon (symbolicIcon::icon (":icons/edit-find-replace.svg")); ui->actionHelp->setIcon (symbolicIcon::icon (":icons/help-contents.svg")); ui->actionAbout->setIcon (symbolicIcon::icon (":icons/help-about.svg")); ui->actionSuper->setIcon (symbolicIcon::icon (":icons/format-text-superscript.svg")); ui->actionSub->setIcon (symbolicIcon::icon (":icons/format-text-subscript.svg")); ui->actionCenter->setIcon (symbolicIcon::icon (":icons/format-justify-center.svg")); ui->actionRight->setIcon (symbolicIcon::icon (":icons/format-justify-right.svg")); ui->actionLeft->setIcon (symbolicIcon::icon (":icons/format-justify-left.svg")); ui->actionJust->setIcon (symbolicIcon::icon (":icons/format-justify-fill.svg")); ui->actionMoveLeft->setIcon (symbolicIcon::icon (":icons/go-previous.svg")); ui->actionMoveRight->setIcon (symbolicIcon::icon (":icons/go-next.svg")); icn = symbolicIcon::icon (":icons/zoom-in.svg"); ui->actionH1->setIcon (icn); ui->actionH2->setIcon (icn); ui->actionH3->setIcon (icn); icn = symbolicIcon::icon (":icons/tag.svg"); ui->actionTags->setIcon (icn); ui->tagsButton->setIcon (icn); ui->actionLink->setIcon (symbolicIcon::icon (":icons/insert-link.svg")); ui->actionCopyLink->setIcon (symbolicIcon::icon (":icons/link.svg")); ui->actionTable->setIcon (symbolicIcon::icon (":icons/insert-table.svg")); ui->actionTableAppendRow->setIcon (symbolicIcon::icon (":icons/edit-table-insert-row-below.svg")); ui->actionTableAppendCol->setIcon (symbolicIcon::icon (":icons/edit-table-insert-column-right.svg")); ui->actionTableDeleteRow->setIcon (symbolicIcon::icon (":icons/edit-table-delete-row.svg")); ui->actionTableDeleteCol->setIcon (symbolicIcon::icon (":icons/edit-table-delete-column.svg")); ui->actionTableMergeCells->setIcon (symbolicIcon::icon (":icons/edit-table-cell-merge.svg")); ui->actionTablePrependRow->setIcon (symbolicIcon::icon (":icons/edit-table-insert-row-above.svg")); ui->actionTablePrependCol->setIcon (symbolicIcon::icon (":icons/edit-table-insert-column-left.svg")); ui->actionRTL->setIcon (symbolicIcon::icon (":icons/format-text-direction-rtl.svg")); ui->actionLTR->setIcon (symbolicIcon::icon (":icons/format-text-direction-ltr.svg")); ui->actionMenu->setIcon (symbolicIcon::icon (":icons/application-menu.svg")); ui->actionPrepSibling->setIcon (symbolicIcon::icon (":icons/sibling-above.svg")); ui->actionNewSibling->setIcon (symbolicIcon::icon (":icons/sibling-below.svg")); ui->actionNewChild->setIcon (symbolicIcon::icon (":icons/child.svg")); ui->everywhereButton->setIcon (symbolicIcon::icon (":icons/all.svg")); ui->wholeButton->setIcon (symbolicIcon::icon (":icons/whole.svg")); ui->caseButton->setIcon (symbolicIcon::icon (":icons/case.svg")); icn = QIcon::fromTheme ("feathernotes"); if (icn.isNull()) icn = QIcon (":icons/feathernotes.svg"); setWindowIcon (icn); } settings.endGroup(); /************ *** Text *** ************/ settings.beginGroup ("text"); if (settings.value ("noWrap").toBool()) { wrapByDefault_ = false; // true by default if (startup) ui->actionWrap->setChecked (false); } else wrapByDefault_ = true; if (settings.value ("noIndent").toBool()) { indentByDefault_ = false; // true by default if (startup) ui->actionIndent->setChecked (false); } else indentByDefault_ = true; autoBracket_ = settings.value ("autoBracket").toBool(); // false by default autoReplace_ = settings.value ("autoReplace").toBool(); // false by default dateFormat_ = settings.value ("dateFormat").toString(); int as = settings.value ("autoSave", -1).toInt(); if (startup) autoSave_ = as; else if (autoSave_ != as) { autoSave_ = as; if (autoSave_ >= 1) timer_->start (autoSave_ * 1000 * 60); else if (timer_->isActive()) timer_->stop(); } openLastFile_ = settings.value ("openLastFile").toBool(); // false by default if (openLastFile_) xmlPath_ = settings.value ("lastOpenedFile").toString(); #ifdef HAS_HUNSPELL dictPath_ = settings.value ("dictionaryPath").toString(); #endif settings.endGroup(); } /*************************/ void FN::writeGeometryConfig() { Settings settings ("feathernotes", "fn"); settings.beginGroup ("window"); if (remSize_) settings.setValue ("size", winSize_); else settings.setValue ("size", "none"); settings.setValue ("startSize", startSize_); if (remSplitter_) settings.setValue ("splitterSizes", ui->splitter->saveState()); else settings.setValue ("splitterSizes", "none"); if (remPosition_) { QPoint CurrPos; if (isVisible() && !isMaximized() && !isFullScreen()) { CurrPos.setX (geometry().x()); CurrPos.setY (geometry().y()); } else CurrPos = position_; settings.setValue ("position", CurrPos); } else settings.setValue ("position", "none"); settings.setValue ("prefSize", prefSize_); settings.endGroup(); } /*************************/ void FN::rememberLastOpenedFile() { if (openLastFile_ && !xmlPath_.isEmpty()) // a file has been opened { Settings settings ("feathernotes", "fn"); settings.beginGroup ("text"); settings.setValue ("lastOpenedFile", xmlPath_); settings.endGroup(); } } /*************************/ void FN::writeConfig() { Settings settings ("feathernotes", "fn"); if (!settings.isWritable()) return; /************** *** Window *** **************/ settings.beginGroup ("window"); settings.setValue ("hasTray", hasTray_); settings.setValue ("minToTray", minToTray_); settings.setValue ("underE", underE_); settings.setValue ("Shift", EShift_); settings.setValue ("transparentTree", transparentTree_); settings.setValue ("smallToolbarIcons", smallToolbarIcons_); settings.setValue ("noToolbar", noToolbar_); settings.setValue ("noMenubar", noMenubar_); settings.endGroup(); /************ *** Text *** ************/ settings.beginGroup ("text"); settings.setValue ("noWrap", !wrapByDefault_); settings.setValue ("noIndent", !indentByDefault_); settings.setValue ("autoBracket", autoBracket_); settings.setValue ("autoReplace", autoReplace_); settings.setValue ("dateFormat", dateFormat_); settings.setValue ("autoSave", autoSave_); if (autoSave_ >= 1) timer_->start (autoSave_ * 1000 * 60); else if (timer_->isActive()) timer_->stop(); settings.setValue ("openLastFile", openLastFile_); #ifdef HAS_HUNSPELL settings.setValue ("dictionaryPath", dictPath_); #endif settings.endGroup(); /***************** *** Shortcuts *** *****************/ settings.beginGroup ("shortcuts"); for (int i = 0; i < uncustomizedActions_.size(); ++i) settings.remove (uncustomizedActions_.at (i)); QHash::const_iterator it = customActions_.constBegin(); while (it != customActions_.constEnd()) { settings.setValue (it.key(), it.value()); ++it; } settings.endGroup(); } /*************************/ void FN::txtPrint() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; QApplication::setOverrideCursor (QCursor(Qt::WaitCursor)); /* choose an appropriate name and directory */ QDir dir = QDir::home(); if (!xmlPath_.isEmpty()) dir = QFileInfo (xmlPath_).absoluteDir(); QModelIndex indx = ui->treeView->currentIndex(); QString fname; if (QObject::sender() == ui->actionPrintAll) { if (xmlPath_.isEmpty()) fname = tr ("Untitled"); else { fname = QFileInfo (xmlPath_).fileName(); if (fname.endsWith (".fnx")) fname.chop (4); } } else if ((fname = model_->data (indx, Qt::DisplayRole).toString()).isEmpty()) fname = tr ("Untitled"); fname = dir.filePath (fname); QPrinter printer (QPrinter::HighResolution); if (printer.outputFormat() == QPrinter::PdfFormat) printer.setOutputFileName (fname.append (".pdf")); /*else if (printer.outputFormat() == QPrinter::PostScriptFormat) printer.setOutputFileName (fname.append (".ps"));*/ QPrintDialog *dlg = new QPrintDialog (&printer, this); dlg->setWindowTitle (tr ("Print Document")); QTextDocument *doc = nullptr; bool newDocCreated = false; if (QObject::sender() == ui->actionPrint) { doc = qobject_cast< TextEdit *>(cw) ->document(); } else { QString text; if (QObject::sender() == ui->actionPrintNodes) { indx = ui->treeView->currentIndex(); QModelIndex sibling = model_->sibling (indx.row() + 1, 0, indx); while (indx != sibling) { text.append (nodeAddress (indx)); DomItem *item = static_cast(indx.internalPointer()); if (TextEdit *thisTextEdit = widgets_.value (item)) text.append (thisTextEdit->toHtml()); // the node text may have been edited else { QDomNodeList lst = item->node().childNodes(); text.append (lst.item (0).nodeValue()); } indx = model_->adjacentIndex (indx, true); } } else// if (QObject::sender() == ui->actionPrintAll) { indx = model_->index (0, 0, QModelIndex()); while (indx.isValid()) { text.append (nodeAddress (indx)); DomItem *item = static_cast(indx.internalPointer()); if (TextEdit *thisTextEdit = widgets_.value (item)) text.append (thisTextEdit->toHtml()); else { QDomNodeList lst = item->node().childNodes(); text.append (lst.item (0).nodeValue()); } indx = model_->adjacentIndex (indx, true); } } doc = new QTextDocument(); if (bgColor_ != QColor (Qt::white) || fgColor_ != QColor (Qt::black)) doc->setDefaultStyleSheet (DOC_STYLESHEET.arg (bgColor_.name(), fgColor_.name())); newDocCreated = true; doc->setHtml (text); } QTimer::singleShot (0, this, []() { // wait for the dialog if (QGuiApplication::overrideCursor() != nullptr) QApplication::restoreOverrideCursor(); }); if (dlg->exec() == QDialog::Accepted) { QApplication::setOverrideCursor (QCursor(Qt::WaitCursor)); doc->print (&printer); } delete dlg; if (newDocCreated) delete doc; if (QGuiApplication::overrideCursor() != nullptr) QApplication::restoreOverrideCursor(); } /*************************/ void FN::exportHTML() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; QDialog *dialog = new QDialog (this); dialog->setWindowTitle (tr ("Export HTML")); QGridLayout *grid = new QGridLayout; grid->setSpacing (5); grid->setContentsMargins (5, 5, 5, 5); QGroupBox *groupBox = new QGroupBox (tr ("Export:")); QRadioButton *radio1 = new QRadioButton (tr ("&Current node")); radio1->setChecked (true); QRadioButton *radio2 = new QRadioButton (tr ("With all &sub-nodes")); QRadioButton *radio3 = new QRadioButton (tr ("&All nodes")); QVBoxLayout *vbox = new QVBoxLayout; vbox->addWidget (radio1); vbox->addWidget (radio2); vbox->addWidget (radio3); connect (radio1, &QAbstractButton::toggled, this, &FN::setHTMLName); connect (radio2, &QAbstractButton::toggled, this, &FN::setHTMLName); connect (radio3, &QAbstractButton::toggled, this, &FN::setHTMLName); vbox->addStretch (1); groupBox->setLayout (vbox); QLabel *label = new QLabel(); label->setText (tr ("Output file:")); htmlPahEntry_ = new LineEdit(); htmlPahEntry_->returnOnClear = false; htmlPahEntry_->setMinimumWidth (150); QModelIndex indx = ui->treeView->currentIndex(); QDir dir = QDir::home(); if (!xmlPath_.isEmpty()) dir = QFileInfo (xmlPath_).absoluteDir(); QString fname; if ((fname = model_->data (indx, Qt::DisplayRole).toString()).isEmpty()) fname = tr ("Untitled"); fname.append (".html"); fname = dir.filePath (fname); htmlPahEntry_->setText (fname); connect (htmlPahEntry_, &QLineEdit::returnPressed, dialog, &QDialog::accept); QToolButton *openBtn = new QToolButton(); openBtn->setIcon (symbolicIcon::icon (":icons/document-open.svg")); openBtn->setToolTip (tr ("Select path")); connect (openBtn, &QAbstractButton::clicked, this, &FN::setHTMLPath); QSpacerItem *spacer = new QSpacerItem (1, 5); QPushButton *cancelButton = new QPushButton (symbolicIcon::icon (":icons/dialog-cancel.svg"), tr ("Cancel")); connect (cancelButton, &QAbstractButton::clicked, dialog, &QDialog::reject); QPushButton *okButton = new QPushButton (symbolicIcon::icon (":icons/dialog-ok.svg"), tr ("OK")); connect (okButton, &QAbstractButton::clicked, dialog, &QDialog::accept); grid->addWidget (groupBox, 0, 0, 1, 2); grid->addWidget (label, 1, 0); grid->addWidget (htmlPahEntry_, 1, 1, 1, 3); grid->addWidget (openBtn, 1, 4, Qt::AlignLeft); grid->addItem (spacer, 2, 0); grid->addWidget (cancelButton, 3, 1, Qt::AlignRight); grid->addWidget (okButton, 3, 2, 1, 3, Qt::AlignRight); grid->setColumnStretch (1, 1); grid->setRowStretch (2, 1); dialog->setLayout (grid); /*dialog->resize (dialog->minimumWidth(), dialog->minimumHeight());*/ /*dialog->show(); dialog->move (x() + width()/2 - dialog->width(), y() + height()/2 - dialog->height());*/ int sel = 0; bool prompt = true; while (prompt) { switch (dialog->exec()) { case QDialog::Accepted: if (radio2->isChecked()) sel = 1; else if (radio3->isChecked()) sel = 2; else sel = 0; fname = htmlPahEntry_->text(); if (QFile::exists (fname)) { prompt = QMessageBox::No == QMessageBox::question (this, tr ("Question"), tr ("The file already exists.\nDo you want to replace it?\n")); if (prompt) continue; } prompt = false; QApplication::setOverrideCursor (QCursor(Qt::WaitCursor)); delete dialog; htmlPahEntry_ = nullptr; break; case QDialog::Rejected: default: if (QGuiApplication::overrideCursor() != nullptr) QApplication::restoreOverrideCursor(); prompt = false; delete dialog; htmlPahEntry_ = nullptr; return; } } QTextDocument *doc = nullptr; bool newDocCreated = false; if (sel == 0) doc = qobject_cast< TextEdit *>(cw)->document(); else { QString text; if (sel == 1) { indx = ui->treeView->currentIndex(); QModelIndex sibling = model_->sibling (indx.row() + 1, 0, indx); while (indx != sibling) { text.append (nodeAddress (indx)); DomItem *item = static_cast(indx.internalPointer()); if (TextEdit *thisTextEdit = widgets_.value (item)) text.append (thisTextEdit->toHtml()); // the node text may have been edited else { QDomNodeList lst = item->node().childNodes(); text.append (lst.item (0).nodeValue()); } indx = model_->adjacentIndex (indx, true); } } else// if (sel == 2) { indx = model_->index (0, 0, QModelIndex()); while (indx.isValid()) { text.append (nodeAddress (indx)); DomItem *item = static_cast(indx.internalPointer()); if (TextEdit *thisTextEdit = widgets_.value (item)) text.append (thisTextEdit->toHtml()); else { QDomNodeList lst = item->node().childNodes(); text.append (lst.item (0).nodeValue()); } indx = model_->adjacentIndex (indx, true); } } doc = new QTextDocument(); if (bgColor_ != QColor (Qt::white) || fgColor_ != QColor (Qt::black)) doc->setDefaultStyleSheet (DOC_STYLESHEET.arg (bgColor_.name(), fgColor_.name())); newDocCreated = true; doc->setHtml (text); } QTextDocumentWriter writer (fname, "html"); bool success = false; success = writer.write (doc); if (newDocCreated) delete doc; if (QGuiApplication::overrideCursor() != nullptr) QApplication::restoreOverrideCursor(); if (!success) { QString str = writer.device()->errorString (); MessageBox msgBox (QMessageBox::Warning, tr ("FeatherNotes"), tr ("
Cannot be saved!
"), QMessageBox::Close, this); msgBox.changeButtonText (QMessageBox::Close, tr ("Close")); msgBox.setInformativeText (QString ("
%1.
").arg (str)); msgBox.setParent (this, Qt::Dialog); msgBox.setWindowModality (Qt::WindowModal); msgBox.exec(); } } /*************************/ QString FN::nodeAddress (QModelIndex index) { QString res; if (!index.isValid()) return res; res.prepend (model_->data (index, Qt::DisplayRole).toString()); QModelIndex indx = model_->parent (index); while (indx.isValid()) { res.prepend (QString ("%1 > ").arg (model_->data (indx, Qt::DisplayRole).toString())); indx = model_->parent (indx); } if (fgColor_ != QColor (Qt::black)) res = QString ("

%2


").arg (fgColor_.name(), res); else res = QString ("

%1


").arg (res); return res; } /*************************/ void FN::setHTMLName (bool checked) { if (!checked) return; QList list = findChildren(); if (list.isEmpty()) return; QList list1; int i = 0; for (i = 0; i < list.count(); ++i) { list1 = list.at (i)->findChildren(); if (!list1.isEmpty()) break; } if (list1.isEmpty()) return; int index = list1.indexOf (qobject_cast< QRadioButton *>(QObject::sender())); /* choose an appropriate name */ QModelIndex indx = ui->treeView->currentIndex(); QString fname; if (index == 2) { if (xmlPath_.isEmpty()) fname = tr ("Untitled"); else { fname = QFileInfo (xmlPath_).fileName(); if (fname.endsWith (".fnx")) fname.chop (4); } } else if ((fname = model_->data (indx, Qt::DisplayRole).toString()).isEmpty()) fname = tr ("Untitled"); fname.append (".html"); QString str = htmlPahEntry_->text(); QStringList strList = str.split ("/"); if (strList.count() == 1) { QDir dir = QDir::home(); if (!xmlPath_.isEmpty()) dir = QFileInfo (xmlPath_).absoluteDir(); fname = dir.filePath (fname); } else { QString last = strList.last(); int lstIndex = str.lastIndexOf (last); fname = str.replace (lstIndex, last.count(), fname); } htmlPahEntry_->setText (fname); } /*************************/ void FN::setHTMLPath (bool) { QString path; if ((path = htmlPahEntry_->text()).isEmpty()) path = QDir::home().filePath (tr ("Untitled") + ".html"); QString HTMLPath; FileDialog dialog (this); dialog.setAcceptMode (QFileDialog::AcceptSave); dialog.setWindowTitle (tr ("Save HTML As...")); dialog.setFileMode (QFileDialog::AnyFile); dialog.setNameFilter (tr ("HTML Files (*.html *.htm)")); dialog.setDirectory (path.section ("/", 0, -2)); // workaround for KDE dialog.selectFile (path); dialog.autoScroll(); if (dialog.exec()) { HTMLPath = dialog.selectedFiles().at (0); if (HTMLPath.isEmpty() || QFileInfo (HTMLPath).isDir()) return; } else return; htmlPahEntry_->setText (HTMLPath); } /*************************/ void FN::setPswd() { int index = ui->stackedWidget->currentIndex(); if (index == -1) return; QDialog *dialog = new QDialog (this); dialog->setWindowTitle (tr ("Set Password")); QGridLayout *grid = new QGridLayout; grid->setSpacing (5); grid->setContentsMargins (5, 5, 5, 5); LineEdit *lineEdit1 = new LineEdit(); lineEdit1->setMinimumWidth (200); lineEdit1->setEchoMode (QLineEdit::Password); lineEdit1->setPlaceholderText (tr ("Type password")); connect (lineEdit1, &QLineEdit::returnPressed, this, &FN::reallySetPswrd); LineEdit *lineEdit2 = new LineEdit(); lineEdit2->returnOnClear = false; lineEdit2->setEchoMode (QLineEdit::Password); lineEdit2->setPlaceholderText (tr ("Retype password")); connect (lineEdit2, &QLineEdit::returnPressed, this, &FN::reallySetPswrd); QLabel *label = new QLabel(); QSpacerItem *spacer = new QSpacerItem (1, 10); QPushButton *cancelButton = new QPushButton (symbolicIcon::icon (":icons/dialog-cancel.svg"), tr ("Cancel")); QPushButton *okButton = new QPushButton (symbolicIcon::icon (":icons/dialog-ok.svg"), tr ("OK")); connect (cancelButton, &QAbstractButton::clicked, dialog, &QDialog::reject); connect (okButton, &QAbstractButton::clicked, this, &FN::reallySetPswrd); grid->addWidget (lineEdit1, 0, 0, 1, 3); grid->addWidget (lineEdit2, 1, 0, 1, 3); grid->addWidget (label, 2, 0, 1, 3); grid->addItem (spacer, 3, 0); grid->addWidget (cancelButton, 4, 0, 1, 2, Qt::AlignRight); grid->addWidget (okButton, 4, 2, Qt::AlignCenter); grid->setColumnStretch (1, 1); grid->setRowStretch (3, 1); label->setVisible (false); dialog->setLayout (grid); /*dialog->resize (dialog->minimumWidth(), dialog->minimumHeight());*/ /*dialog->show(); dialog->move (x() + width()/2 - dialog->width(), y() + height()/2 - dialog->height());*/ switch (dialog->exec()) { case QDialog::Accepted: if (pswrd_ != lineEdit1->text()) { pswrd_ = lineEdit1->text(); noteModified(); } delete dialog; break; case QDialog::Rejected: default: delete dialog; break; } } /*************************/ void FN::reallySetPswrd() { QList list = findChildren(); if (list.isEmpty()) return; QList listEdit; int i = 0; for (i = 0; i < list.count(); ++i) { listEdit = list.at (i)->findChildren(); if (!listEdit.isEmpty()) break; } if (listEdit.isEmpty()) return; if (listEdit.count() < 2) return; QList listLabel = list.at (i)->findChildren(); if (listLabel.isEmpty()) return; QList listBtn = list.at (i)->findChildren(); if (listBtn.isEmpty()) return; listBtn.at (0)->setDefault (false); // don't interfere LineEdit *lineEdit1 = listEdit.at (0); LineEdit *lineEdit2 = listEdit.at (1); if (QObject::sender() == lineEdit1) { listLabel.at (0)->setVisible (false); lineEdit2->setFocus(); return; } if (lineEdit1->text() != lineEdit2->text()) { listLabel.at (0)->setText (tr ("
Passwords were different. Retry!
")); listLabel.at (0)->setVisible (true); } else list.at (i)->accept(); } /*************************/ bool FN::isPswrdCorrect() { if (tray_) { if (underE_ && QObject::sender() == nullptr) // opened by command line { if (!isVisible()) { activateTray(); QCoreApplication::processEvents(); } else // not needed really { raise(); activateWindow(); } } else if (!underE_&& (!isVisible() || !isActiveWindow())) { activateTray(); QCoreApplication::processEvents(); } } QDialog *dialog = new QDialog (this); dialog->setWindowTitle (tr ("Enter Password")); QGridLayout *grid = new QGridLayout; grid->setSpacing (5); grid->setContentsMargins (5, 5, 5, 5); LineEdit *lineEdit = new LineEdit(); lineEdit->setMinimumWidth (200); lineEdit->setEchoMode (QLineEdit::Password); lineEdit->setPlaceholderText (tr ("Enter Password")); connect (lineEdit, &QLineEdit::returnPressed, this, &FN::checkPswrd); QLabel *label = new QLabel(); QSpacerItem *spacer = new QSpacerItem (1, 5); QPushButton *cancelButton = new QPushButton (symbolicIcon::icon (":icons/dialog-cancel.svg"), tr ("Cancel")); QPushButton *okButton = new QPushButton (symbolicIcon::icon (":icons/dialog-ok.svg"), tr ("OK")); connect (cancelButton, &QAbstractButton::clicked, dialog, &QDialog::reject); connect (okButton, &QAbstractButton::clicked, this, &FN::checkPswrd); grid->addWidget (lineEdit, 0, 0, 1, 3); grid->addWidget (label, 1, 0, 1, 3); grid->addItem (spacer, 2, 0); grid->addWidget (cancelButton, 3, 0, 1, 2, Qt::AlignRight); grid->addWidget (okButton, 3, 2, Qt::AlignCenter); grid->setColumnStretch (1, 1); grid->setRowStretch (2, 1); label->setVisible (false); dialog->setLayout (grid); /*dialog->resize (dialog->minimumWidth(), dialog->minimumHeight());*/ /*dialog->show(); dialog->move (x() + width()/2 - dialog->width(), y() + height()/2 - dialog->height());*/ bool res = true; switch (dialog->exec()) { case QDialog::Accepted: if (pswrd_ != lineEdit->text()) res = false; delete dialog; break; case QDialog::Rejected: default: delete dialog; res = false; break; } return res; } /*************************/ void FN::checkPswrd() { QList list = findChildren(); if (list.isEmpty()) return; QList listEdit; int i = 0; for (i = 0; i < list.count(); ++i) { listEdit = list.at (i)->findChildren(); if (!listEdit.isEmpty()) break; } if (listEdit.isEmpty()) return; QList listLabel = list.at (i)->findChildren(); if (listLabel.isEmpty()) return; QList listBtn = list.at (i)->findChildren(); if (listBtn.isEmpty()) return; listBtn.at (0)->setDefault (false); // don't interfere if (listEdit.at (0)->text() != pswrd_) { listLabel.at (0)->setText (tr ("
Wrong password. Retry!
")); listLabel.at (0)->setVisible (true); } else list.at (i)->accept(); } /*************************/ void FN::aboutDialog() { class AboutDialog : public QDialog { public: #if (QT_VERSION >= QT_VERSION_CHECK(5,15,0)) explicit AboutDialog (QWidget* parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()) : QDialog (parent, f) { #else explicit AboutDialog (QWidget* parent = nullptr, Qt::WindowFlags f = nullptr) : QDialog (parent, f) { #endif aboutUi.setupUi (this); aboutUi.textLabel->setOpenExternalLinks (true); } void setTabTexts (const QString& first, const QString& sec) { aboutUi.tabWidget->setTabText (0, first); aboutUi.tabWidget->setTabText (1, sec); } void setMainIcon (const QIcon& icn) { aboutUi.iconLabel->setPixmap (icn.pixmap (64, 64)); } void settMainTitle (const QString& title) { aboutUi.titleLabel->setText (title); } void setMainText (const QString& txt) { aboutUi.textLabel->setText (txt); } private: Ui::AboutDialog aboutUi; }; AboutDialog dialog (this); QIcon FPIcon = QIcon::fromTheme ("feathernotes"); if (FPIcon.isNull()) FPIcon = QIcon (":icons/feathernotes.svg"); dialog.setMainIcon (FPIcon); dialog.settMainTitle (QString ("
%1 %2

").arg (qApp->applicationName()).arg (qApp->applicationVersion())); dialog.setMainText ("
" + tr ("A lightweight notes manager") + "
\n
" + tr ("based on Qt") + "

" + tr ("Author")+": Pedram Pourang (" + tr ("aka.") + " Tsu Jan)

"); dialog.setTabTexts (tr ("About FeatherNotes"), tr ("Translators")); dialog.setWindowTitle (tr ("About FeatherNotes")); dialog.setWindowModality (Qt::WindowModal); dialog.exec(); } /*************************/ void FN::showHelpDialog() { FHelp *dlg = new FHelp (this); dlg->resize (ui->stackedWidget->size().expandedTo (ui->treeView->size())); switch (dlg->exec()) { case QDialog::Rejected: default: delete dlg; break; } } /*************************/ #ifdef HAS_HUNSPELL static inline void moveToWordStart (QTextCursor& cur, bool forward) { const QString blockText = cur.block().text(); const int l = blockText.length(); int indx = cur.positionInBlock(); if (indx < l) { QChar ch = blockText.at (indx); while (!ch.isLetterOrNumber() && ch != '\'' && ch != '-' && ch != QChar (QChar::Nbsp) && ch != QChar (0x200C)) { cur.movePosition (QTextCursor::NextCharacter); ++indx; if (indx == l) { if (cur.movePosition (QTextCursor::NextBlock)) moveToWordStart (cur, forward); return; } ch = blockText.at (indx); } } if (!forward && indx > 0) { QChar ch = blockText.at (indx - 1); while (ch.isLetterOrNumber() || ch == '\'' || ch == '-' || ch == QChar (QChar::Nbsp) || ch == QChar (0x200C)) { cur.movePosition (QTextCursor::PreviousCharacter); --indx; ch = blockText.at (indx); if (indx == 0) break; } } } static inline void selectWord (QTextCursor& cur) { moveToWordStart (cur, true); const QString blockText = cur.block().text(); const int l = blockText.length(); int indx = cur.positionInBlock(); if (indx < l) { QChar ch = blockText.at (indx); while (ch.isLetterOrNumber() || ch == '\'' || ch == '-' || ch == QChar (QChar::Nbsp) || ch == QChar (0x200C)) { cur.movePosition (QTextCursor::NextCharacter, QTextCursor::KeepAnchor); ++indx; if (indx == l) break; ch = blockText.at (indx); } } /* no dash, single quote mark or number at the start */ while (!cur.selectedText().isEmpty() && (cur.selectedText().at (0) == '-' || cur.selectedText().at (0) == '\'' || cur.selectedText().at (0).isNumber())) { int p = cur.position(); cur.setPosition (cur.anchor() + 1); cur.setPosition (p, QTextCursor::KeepAnchor); } /* no dash or single quote mark at the end */ while (!cur.selectedText().isEmpty() && (cur.selectedText().endsWith ("-") || cur.selectedText().endsWith ("\'"))) { cur.setPosition (cur.position() - 1, QTextCursor::KeepAnchor); } } void FN::spellingCheckingMsg (const QString &msg, bool hasInfo) { MessageBox msgBox; if (hasInfo) { msgBox.setIcon (QMessageBox::Warning); msgBox.setText ("
" + msg + "
"); msgBox.setInformativeText ("
" + tr ("See Preferences → Text → Spell Checking!") + "
"); } else { msgBox.setIcon (QMessageBox::Information); msgBox.setText ("
" + msg + "
"); } msgBox.setStandardButtons (QMessageBox::Close); msgBox.changeButtonText (QMessageBox::Close, tr ("Close")); msgBox.setParent (this, Qt::Dialog); msgBox.setWindowModality (Qt::WindowModal); msgBox.exec(); } void FN::checkSpelling() { QWidget *cw = ui->stackedWidget->currentWidget(); if (!cw) return; auto dictPath = dictPath_; if (dictPath.isEmpty()) { spellingCheckingMsg (tr ("You need to add a Hunspell dictionary."), true); return; } if (!QFile::exists (dictPath)) { spellingCheckingMsg (tr ("The Hunspell dictionary does not exist."), true); return; } if (dictPath.endsWith (".dic")) dictPath = dictPath.left (dictPath.size() - 4); const QString affixFile = dictPath + ".aff"; if (!QFile::exists (affixFile)) { spellingCheckingMsg (tr ("The Hunspell dictionary is not accompanied by an affix file."), true); return; } QString confPath = QStandardPaths::writableLocation (QStandardPaths::ConfigLocation); if (!QFile (confPath + "/feathernotes").exists()) // create config dir if needed QDir (confPath).mkpath (confPath + "/feathernotes"); QString userDict = confPath + "/feathernotes/userDict-" + dictPath.section ("/", -1); TextEdit *textEdit = qobject_cast(cw); QTextCursor cur = textEdit->textCursor(); cur.setPosition (cur.anchor()); moveToWordStart (cur, false); selectWord (cur); QString word = cur.selectedText(); while (word.isEmpty()) { if (!cur.movePosition (QTextCursor::NextCharacter)) { spellingCheckingMsg (tr ("No misspelling from text cursor."), false); return; } selectWord (cur); word = cur.selectedText(); } SpellChecker *spellChecker = new SpellChecker (dictPath, userDict); while (spellChecker->spell (word)) { cur.setPosition (cur.position()); if (cur.atEnd()) { delete spellChecker; spellingCheckingMsg (tr ("No misspelling from text cursor."), false); return; } if (cur.movePosition (QTextCursor::NextCharacter)) selectWord (cur); word = cur.selectedText(); while (word.isEmpty()) { cur.setPosition (cur.anchor()); if (!cur.movePosition (QTextCursor::NextCharacter)) { delete spellChecker; spellingCheckingMsg (tr ("No misspelling from text cursor."), false); return; } selectWord (cur); word = cur.selectedText(); } } textEdit->setTextCursor (cur); textEdit->ensureCursorVisible(); SpellDialog dlg (spellChecker, word, this); dlg.setWindowTitle (tr ("Spell Checking")); connect (&dlg, &SpellDialog::spellChecked, [&dlg, textEdit] (int res) { QTextCursor cur = textEdit->textCursor(); if (!cur.hasSelection()) return; // impossible QString word = cur.selectedText(); QString corrected; switch (res) { case SpellDialog::CorrectOnce: cur.insertText (dlg.replacement()); break; case SpellDialog::IgnoreOnce: break; case SpellDialog::CorrectAll: /* remember this corretion */ dlg.spellChecker()->addToCorrections (word, dlg.replacement()); cur.insertText (dlg.replacement()); break; case SpellDialog::IgnoreAll: /* always ignore the selected word */ dlg.spellChecker()->ignoreWord (word); break; case SpellDialog::AddToDict: /* not only ignore it but also add it to user dictionary */ dlg.spellChecker()->addToUserWordlist (word); break; } /* check the next word */ cur.setPosition (cur.position()); if (cur.atEnd()) { textEdit->setTextCursor (cur); textEdit->ensureCursorVisible(); dlg.close(); return; } if (cur.movePosition (QTextCursor::NextCharacter)) selectWord (cur); word = cur.selectedText(); while (word.isEmpty()) { cur.setPosition (cur.anchor()); if (!cur.movePosition (QTextCursor::NextCharacter)) { textEdit->setTextCursor (cur); textEdit->ensureCursorVisible(); dlg.close(); return; } selectWord (cur); word = cur.selectedText(); } while (dlg.spellChecker()->spell (word) || !(corrected = dlg.spellChecker()->correct (word)).isEmpty()) { if (!corrected.isEmpty()) { cur.insertText (corrected); corrected = QString(); } else cur.setPosition (cur.position()); if (cur.atEnd()) { textEdit->setTextCursor (cur); textEdit->ensureCursorVisible(); dlg.close(); return; } if (cur.movePosition (QTextCursor::NextCharacter)) selectWord (cur); word = cur.selectedText(); while (word.isEmpty()) { cur.setPosition (cur.anchor()); if (!cur.movePosition (QTextCursor::NextCharacter)) { textEdit->setTextCursor (cur); textEdit->ensureCursorVisible(); dlg.close(); return; } selectWord (cur); word = cur.selectedText(); } } textEdit->setTextCursor (cur); textEdit->ensureCursorVisible(); dlg.checkWord (word); }); dlg.exec(); delete spellChecker; } #endif /*************************/ bool FN::event (QEvent *event) { if (event->type() == QEvent::StyleChange) { /* when the style changes in runtime, the text color of a transparent side pane should be set to its window text color again because the latter may have changed */ if (transparentTree_ && ui->treeView->viewport()) { QPalette p = ui->treeView->palette(); p.setColor (QPalette::Text, p.color (QPalette::WindowText)); ui->treeView->setPalette (p); } } /* NOTE: This is a workaround for an old Qt bug, because of which, QTimer may not work after resuming from suspend or hibernation. */ else if (event->type() == QEvent::WindowActivate && timer_->isActive() && timer_->remainingTime() <= 0) { if (autoSave_ >= 1) { autoSaving(); timer_->start (autoSave_ * 1000 * 60); } } return QMainWindow::event (event); } } FeatherNotes-0.8.0/feathernotes/fn.h000066400000000000000000000271531374721712500173720ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016-2020 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef FN_H #define FN_H //#include // too much #include #include #include #include "textedit.h" #include "domitem.h" #include "lineedit.h" namespace FeatherNotes { namespace Ui { class FN; } class DomModel; class FN : public QMainWindow { Q_OBJECT public: explicit FN (const QStringList& message, QWidget *parent = nullptr); ~FN(); void writeGeometryConfig(); void rememberLastOpenedFile(); void writeConfig(); bool isSizeRem() const { return remSize_; } void remSize (bool rem) { remSize_ = rem; } QSize getWinSize() const { return winSize_; } void setWinSize (const QSize &size) { winSize_ = size; } QSize getStartSize() const { return startSize_; } void setStartSize (const QSize &size) { startSize_ = size; } bool isSplitterRem() const { return remSplitter_; } void remSplitter (bool rem) { remSplitter_ = rem; } QByteArray getSpltiterState() const; void setSplitterSizes (const QByteArray &sizes) { splitterSizes_ = sizes; } QSize getPrefSize() const { return prefSize_; } void setPrefSize (const QSize &s) { prefSize_ = s; } bool isPositionRem() const { return remPosition_; } void remPosition (bool rem) { remPosition_ = rem; } void setPosition (const QPoint &pos) { position_ = pos; } bool isUnderE() const { return underE_; } void setUnderE (bool yes); QSize EShift() const { return EShift_; } void setEShift (QSize shift) { EShift_ = shift; } bool hasTray() const { return hasTray_; } void useTray (bool use) { hasTray_ = use; } bool doesMinToTray() const { return minToTray_; } void minToTray (bool yes) { minToTray_ = yes; } bool hasTransparentTree() const { return transparentTree_; } void makeTreeTransparent (bool trans); bool hasSmallToolbarIcons() const { return smallToolbarIcons_; } void setToolBarIconSize (bool small); bool withoutToolbar() const { return noToolbar_; } bool withoutMenubar() const { return noMenubar_; } void showToolbar (bool show); void showMenubar (bool show); bool isWrappedByDefault() const { return wrapByDefault_; } void wrapByDefault (bool wrap) { wrapByDefault_ = wrap; } bool isIndentedByDefault() const { return indentByDefault_; } void indentByDefault (bool indent) { indentByDefault_ = indent; } bool hasAutoBracket() const { return autoBracket_; } void autoBracket (bool yes) { autoBracket_ = yes; } bool hasAutoReplace() const { return autoReplace_; } void autoReplace (bool yes) { autoReplace_ = yes; } QString getDateFormat() const { return dateFormat_; } void setDateFormat (const QString &format) { dateFormat_ = format; } int getAutoSave() const { return autoSave_; } void setAutoSave (int interval) { autoSave_ = interval; } void updateCustomizableShortcuts(); QHash customShortcutActions() const { return customActions_; } void setActionShortcut (const QString &action, const QString &shortcut) { customActions_.insert (action, shortcut); } void removeShortcut (const QString &action) { customActions_.remove (action); uncustomizedActions_ << action; } QHash defaultShortcuts() const { return defaultShortcuts_; } QStringList reservedShortcuts() const { return reservedShortcuts_; } bool openLastFile() const { return openLastFile_; } void setOpenLastFile (bool openLastFile) { openLastFile_ = openLastFile; } #ifdef HAS_HUNSPELL QString getDictPath() const { return dictPath_; } void setDictPath (const QString& dictPath) { dictPath_ = dictPath; } #endif private slots: bool close(); void checkTray(); void showContextMenu (const QPoint &p); void fullScreening(); void defaultSize(); void rehighlight (TextEdit *textEdit); void zoomingIn(); void zoomingOut(); void unZooming(); void newNote(); void openFile(); void openFNDoc (const QString &filePath); void autoSaving(); bool saveFile(); void undoing(); void redoing(); void cutText(); void copyText(); void pasteText(); void pasteHTML(); void deleteText(); void selectAllText(); void insertDate(); void setCursorInsideSelection (bool sel); void txtContextMenu (const QPoint &p); void copyLink(); void selChanged (const QItemSelection &selected, const QItemSelection&); void setSaveEnabled (bool modified); void setUndoEnabled (bool enabled); void setRedoEnabled (bool enabled); void formatChanged (const QTextCharFormat &format); void alignmentChanged(); void directionChanged(); void makeBold(); void makeItalic(); void makeUnderlined(); void makeStriked(); void makeSuperscript(); void makeSubscript(); void textColor(); void bgColor(); void clearFormat(); void textAlign (QAction *a); void textDirection (QAction *a); void makeHeader(); void insertLink(); void embedImage(); void imageEmbed (const QString &path); void setImagePath (bool); void scaleImage(); void saveImage(); void addTable(); void tableMergeCells(); void tablePrependRow(); void tableAppendRow(); void tablePrependCol(); void tableAppendCol(); void tableDeleteRow(); void tableDeleteCol(); void expandAll(); void collapseAll(); void newNode(); void deleteNode(); void moveUpNode(); void moveLeftNode(); void moveDownNode(); void moveRightNode(); void handleTags(); void renameNode(); void nodeIcon(); void toggleStatusBar(); void textFontDialog(); void nodeFontDialog(); void docColorDialog(); void toggleWrapping(); void toggleIndent(); void prefDialog(); void noteModified(); void docProp(); void nodeChanged (const QModelIndex&, const QModelIndex&); void showHideSearch(); void clearTagsList (int); void selectRow (QListWidgetItem *item); void chooseRow (int row); void find(); void hlight() const; void scrolled (int) const; void setSearchFlags(); void allBtn (bool checked); void tagsAndNamesBtn (bool checked); void replaceDock(); void closeReplaceDock (bool visible); void resizeDock (bool topLevel); void replace(); void replaceAll(); void showAndFocus(); void stealFocus(); void trayActivated (QSystemTrayIcon::ActivationReason r); void activateTray(); void txtPrint(); void exportHTML(); void setHTMLName (bool checked); void setHTMLPath (bool); void setPswd(); void reallySetPswrd(); void checkPswrd(); void aboutDialog(); void showHelpDialog(); void closeTagsDialog(); #ifdef HAS_HUNSPELL void checkSpelling(); #endif private: void enableActions (bool enable); void fileOpen (const QString &filePath, bool startup = false); bool fileSave (const QString &filePath); void createTrayIcon(); void closeEvent (QCloseEvent *event); void resizeEvent (QResizeEvent *event); void showEvent (QShowEvent *event); void showDoc (QDomDocument &doc); void setTitle (const QString& fname); void notSaved(); void setNodesTexts(); bool unSaved (bool modified); TextEdit *newWidget(); void mergeFormatOnWordOrSelection (const QTextCharFormat &format); void setNewFont (DomItem *item, const QTextCharFormat &fmt); QTextCursor finding (const QString& str, const QTextCursor& start, QTextDocument::FindFlags flags) const; void findInTags(); void reallySetSearchFlags (bool h); void findInNames(); bool isImageSelected(); void readShortcuts(); QString validatedShortcut (const QVariant v, bool *isValid); void readAndApplyConfig (bool startup = true); QString nodeAddress (QModelIndex index); bool isPswrdCorrect(); void dragMoveEvent (QDragMoveEvent *event); void dragEnterEvent (QDragEnterEvent *event); void dropEvent (QDropEvent *event); bool event (QEvent *event); #ifdef HAS_HUNSPELL void spellingCheckingMsg (const QString &msg, bool hasInfo); #endif Ui::FN *ui; bool isX11_; //QWidget *dummyWidget; // For hiding the main window while keeping all its state info. QSystemTrayIcon *tray_; bool quitting_; int trayCounter_; // Used when waiting for the system tray to be created at startup. int saveNeeded_; QFont defaultFont_, nodeFont_; QColor bgColor_, fgColor_; QColor lastTxtColor_, lastBgColor_; DomModel *model_; QString xmlPath_; LineEdit *ImagePathEntry_, *htmlPahEntry_; /* By pairing each widget with a DOM item, we won't need to worry about keeping the correspondence between widgets and nodes: */ QHash widgets_; QTextDocument::FindFlags searchFlags_; // Whole word and case sensitivity flags. QHash searchEntries_; // Search entries, one for each QTextEdit. bool searchingOtherNode_; // Needed when jumping to another node during search. bool rplOtherNode_; // Like above but for replacement. int replCount_; // Needed for counting replacements in all nodes. QHash > greenSels_; // For replaced matches. QString txtReplace_; // The replacing text. QModelIndexList tagsList_; QString linkAtPos_; // Text hyperlink at the right-click position. QTextTable *txtTable_; // Text table at the right-click position. int imgScale_; QString lastImgPath_; bool shownBefore_, remSize_, remSplitter_, remPosition_, hasTray_, minToTray_, wrapByDefault_, indentByDefault_, transparentTree_, smallToolbarIcons_, noToolbar_, noMenubar_, autoBracket_, autoReplace_, openLastFile_, treeViewDND_; QString dateFormat_; int autoSave_; QPoint position_; // Excluding the window frame. QSize winSize_, startSize_, prefSize_; //QList splitterSizes_; QByteArray splitterSizes_; QTimer *timer_; QString pswrd_; bool underE_; // Is FeatherNotes running under Enlightenment? QSize EShift_; // The shift Enlightenment's panel creates (a bug?). QHash customActions_; QHash defaultShortcuts_; QStringList uncustomizedActions_, reservedShortcuts_; #ifdef HAS_HUNSPELL QString dictPath_; #endif }; } #endif // FN_H FeatherNotes-0.8.0/feathernotes/fn.ui000066400000000000000000001106141374721712500175530ustar00rootroot00000000000000 FeatherNotes::FN 0 0 700 500 FeatherNotes 0 0 0 0 0 0 Qt::Horizontal 2 2 3 0 Qt::NoFocus Next (F3) F3 true Qt::NoFocus Previous (F4) F4 true 150 0 Search... 3 Qt::NoFocus Search only in names (Ctrl+Shift+F7) Ctrl+Shift+F7 Qt::NoFocus Search only in tags (Shift+F7) Shift+F7 false Qt::NoFocus Search in all nodes (F7) F7 false 3 Qt::NoFocus Match Case (F5) Match Case F5 true Qt::NoFocus Whole Word (F6) Whole Word F6 true 0 0 700 21 Qt::PreventContextMenu &File &Edit For&mat &Tree &Options &Search &Help Qt::PreventContextMenu false TopToolBarArea false QDockWidget::DockWidgetClosable|QDockWidget::DockWidgetFloatable Qt::BottomDockWidgetArea 8 5 0 5 0 0 2 0 Find: Replace with: 150 0 To be replaced 150 0 Replacing text Qt::NoFocus Previous (F9) F9 true Qt::NoFocus Next (F8) F8 true Qt::NoFocus Replace all (F10) F10 true false &Save Save Ctrl+S &Open Open a file Ctrl+O false &Undo Undo Ctrl+Z false &Redo Redo Ctrl+Shift+Z false &Find Show/hide searchbar Ctrl+F false &Clear All Formats Clear all formats Ctrl+E true false &Bold Bold Ctrl+B true false &Italic Italic Ctrl+I true false &Underline Underline Ctrl+U true false &Strike Through Strike through Ctrl+T false Te&xt Color Text color Alt+Shift+T false Back&ground Color Background color Alt+Shift+B Options &New Note Ctrl+Alt+Shift+N false Save &As Ctrl+Shift+S false &Print Ctrl+P false P&rint with Sub-Nodes false Set Pass&word &Quit Ctrl+Q false &Cut Ctrl+X false C&opy Ctrl+C false &Paste Ctrl+V false &Delete false &Select All Ctrl+A false E&mbed Image Embed Image Ctrl+Alt+Shift+I false E&xpand All Ctrl+Shift+Down false Collap&se All Ctrl+Shift+Up false &Append Sibling Ctrl+N false Append &Child Ctrl+Shift+N false &Delete Node Ctrl+D false Move &Up Alt+Up false Move Do&wn Alt+Down false Re&name Node Ctrl+Shift+R Tree Pr&operties Ctrl+Shift+D false Document &Font true true false &Wrap Lines Ctrl+W true true false &Auto-Indentation Ctrl+Shift+I &Preferences Ctrl+Shift+P false Find and &Replace Ctrl+R &Help Ctrl+H &About false Pr&int All Nodes true false Superscrip&t Superscript Alt+Shift+U true false Subscri&pt Subscript Alt+Shift+S true false C&enter Align center Alt+Shift+Down true false &Right Align right Alt+Shift+Right true false &Left Align left Alt+Shift+Left true false &Justify Justify Alt+Shift+Up false &Prepend Sibling Ctrl+M false Move &Left Alt+Left false Move &Right Alt+Right false h&2 Header 2 Ctrl+2 false h&1 Header 1 Ctrl+1 false h&3 Header 3 Ctrl+3 false &Node Font Node Font Scale I&mage(s) false Paste &HTML Ctrl+Shift+V false &Tags Ctrl+Shift+T false Insert Lin&k Ctrl+L C&opy Link false I&nsert Table Ctrl+Alt+Shift+T Append Row Delete Row Append Column Delete Column Merge Cells Prepend Row Prepend Column false Export &HTML Save Ima&ge(s) true false RTL Ctrl+Alt+Shift+Left true false LTR Ctrl+Alt+Shift+Right Menu Menu false Node &Icon Ctrl+Shift+C Check Spelling Check Spelling F2 Document &Colors false Paste Date and Time Paste Date and Time FeatherNotes::LineEdit QLineEdit
lineedit.h
FeatherNotes::TreeView QTreeView
treeview.h
actionQuit triggered() FN close() -1 -1 323 198
FeatherNotes-0.8.0/feathernotes/help.h000066400000000000000000000011461374721712500177110ustar00rootroot00000000000000#ifndef HELP_H #define HELP_H #include #include #include "ui_helpDialog.h" namespace FeatherNotes { namespace Ui { class helpDialog; } class FHelp : public QDialog { Q_OBJECT public: FHelp (QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()) : QDialog (parent, f), ui (new Ui::helpDialog) { ui->setupUi (this); QPushButton *closelButton = ui->buttonBox->button (QDialogButtonBox::Close); connect (closelButton, &QAbstractButton::clicked, this, &QDialog::reject); } ~FHelp() { delete ui; } private: Ui::helpDialog *ui; }; } #endif // HELP_H FeatherNotes-0.8.0/feathernotes/helpDialog.ui000066400000000000000000001051361374721712500212230ustar00rootroot00000000000000 FeatherNotes::helpDialog 0 0 400 300 Help <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-size:medium; font-weight:400; font-style:normal;"> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">General</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You could easily get familiar with <span style=" font-weight:600;">FeatherNotes</span> by using its toolbar buttons, menubar items and right-click menus. What follows is about those usages that may not be obvious at first glance. </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">Text and Document</span> </p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FeatherNotes</span> supports rich text. The text can be formatted by using the toolbar buttons, the menu-items of the <span style=" font-weight:600; font-style:italic;">Format</span> menu, or their shortcuts.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Images can be inserted into text by using the related toolbar button or menu-item, or by drag-and-drop (see below). If the toolbar button or menu-item is used, images could be scaled before insertion.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Images can be selected by the mouse cursor like ordinary text. If an image is selected, its right-click menu will contain <span style=" font-weight:600; font-style:italic;">&quot;Scale Image(s)&quot;</span> and <span style=" font-weight:600; font-style:italic;">&quot;Save Images(s)&quot;</span> items that could be used to scale or save it. The same items will be shown if multiple images are selected.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Tables can be inserted into text by using the right-click menu or the <span style=" font-weight:600; font-style:italic;">&quot;Insert Table&quot;</span> menu-item on the <span style=" font-weight:600; font-style:italic;">Format</span> menu. They can also be edited from the right-click menu in various ways.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">It is also possible to select some text and add a link (bookmark) to it by using the <span style=" font-weight:600; font-style:italic;">&quot;Insert Link&quot;</span> item on the <span style=" font-weight:600; font-style:italic;">Format</span> or right-click menu. A link can be an Internet address or the path of a local file. In the latter case, if the link is clicked, its corresponding file will be opened by the app associated with its mime type. For example, if you add the path of a <span style=" font-weight:600;">FeatherNotes</span> document as a link, it will be opened by another instance of <span style=" font-weight:600;">FeatherNotes</span>.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A <span style=" font-weight:600;">FeatherNotes</span> document can be protected by a password. The contents of a password-protected <span style=" font-weight:600;">FeatherNotes</span> document will not be readable until it is opened by <span style=" font-weight:600;">FeatherNotes</span> after entering its password. The password protection is suitable <span style=" font-weight:600;">ONLY</span> for ordinary usage. If you want a very strong protection that cannot be broken by hackers who may have access to your computer, please use another method!</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">Nodes</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The <span style=" font-weight:600; font-style:italic;">Tree</span> menubar item contains all node actions.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Nodes can also be renamed by double clicking on them or pressing F2 when they have focus. Each node has a right-click menu with some useful actions.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Optionally, any image can be set as the icon of a node from its right-click menu or the <span style=" font-weight:600; font-style:italic;">Tree</span> menu. The icon size is determined by the active Qt widget style but is usually 16 px and the chosen image is scaled to that size. Once the image is set, it will be included in the <span style=" font-weight:600;">FeatherNotes</span> document, so that there will be no dependency on the external image.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Nodes can have hidden strings called <span style=" font-weight:600; font-style:italic;">&quot;tags&quot;</span>. A tag can be a short description or any kind of information that seems suitable to the user. Tags can be added from node right-click menus or the <span style=" font-weight:600; font-style:italic;">Tree</span> menu. They can be searched by checking the <span style=" font-weight:600; font-style:italic;">&quot;Tags&quot;</span> radio-button on the search bar and then, entering a text into the search entry and pressing <span style=" font-style:italic;">Enter</span> or <span style=" font-style:italic;">F3</span> (see <span style=" font-style:italic;">'Searching and Replacing'</span> below).</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">Drag-and-Drop</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Nodes can be dragged and dropped between other nodes or on them. In the latter case, they will be appended as child nodes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You could open a <span style=" font-weight:600;">FeatherNotes</span> document by dragging and dropping it into a <span style=" font-weight:600;">FeatherNotes</span> window too.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Also images can be dragged from outside <span style=" font-weight:600;">FeatherNotes</span> and dropped into its text-edit pane.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">Tray Icon</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The tray icon is disabled by default. It can be enabled by <span style=" font-weight:600; font-style:italic;">Preferences dialog → Window → &quot;Add to systray&quot;</span>. Then, <span style=" font-weight:600;">FeatherNotes</span> could be started iconified if the checkbox <span style=" font-weight:600; font-style:italic;">&quot;Start iconified to tray&quot;</span> is checked.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">Exporting and Printing</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The current node, with or without its sub-nodes, or the whole <span style=" font-weight:600;">FeatherNotes</span> document can be printed or exported to PDF or HTML from the <span style=" font-weight:600; font-style:italic;">File</span> menu. The <span style=" font-weight:600; font-style:italic;">Export HTML</span> dialog has three radio buttons for exporting different parts of the document.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">Searching and Replacing</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Search can be done in node text, node names or node tags. There are three radio-buttons on the search bar:</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(1) The <span style=" font-weight:600; font-style:italic;">&quot;Names&quot;</span> radio-button is for searching in node names;</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(2) The <span style=" font-weight:600; font-style:italic;">&quot;Tags&quot;</span> radio-button can be used for searching tags; and</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(3) If the <span style=" font-weight:600; font-style:italic;">&quot;All&quot;</span> radio-button is checked, the search will be done in the texts of all nodes.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If none of these radio-buttons is checked, the search will be done in the text of the current node.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">On searching tags, a list dialog containing the found matches will be shown. Clicking on a list item activates its corresponding node.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To remove the yellow highlights after finishing a text search, you could</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">* Click on the <span style=" font-weight:600; font-style:italic;">&quot;Clear&quot;</span> icon of the search entry, or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">* Press <span style=" font-style:italic;">Ctrl+K</span> while the search entry has focus, or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">* Empty the search entry and press <span style=" font-style:italic;">Enter</span> or <span style=" font-style:italic;">F3</span> in it, or</p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">* Hide the search bar.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The <span style=" font-weight:600; font-style:italic;">Replace</span> docked window respects the settings for <span style=" font-weight:600; font-style:italic;">&quot;Match Case&quot;</span>, <span style=" font-weight:600; font-style:italic;">&quot;Whole Word&quot;</span> and <span style=" font-weight:600; font-style:italic;">&quot;All&quot;</span> on the search bar. It can be detached from the main window. To remove the green highlights after replacing text, you could either hide/close the 'Replace' docked window or do as in the case of removing yellow search highlights (without closing the dock).</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">Status Bar</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The status bar shows some information about the current <span style=" font-weight:600;">FeatherNotes</span> document and can be toggled with the item &quot;Tree Properties&quot; on the <span style=" font-weight:600; font-style:italic;">Tree</span> menu.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">Wheel Scrolling</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For fast mouse wheel scrolling, put the cursor on the scrollbar. If it is on the text, the scrolling speed will be normal. If, in addition, the Shift key is pressed, the text will scroll with minimum speed.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wheel scrolling is always smooth.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">General Background and Text Colors</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The default background and text colors of all nodes are white and black respectively. It is possible to change these colors for new nodes in <span style=" font-weight:600; font-style:italic;">Options → Document Colors</span>. The changes are saved to the document itself, so that different <span style=" font-weight:600;">FeatherNotes</span> documents can have different background and text colors.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the background and text colors are changed for an existing <span style=" font-weight:600;">FeatherNotes</span> document, its new nodes will have those colors but its existing nodes might or might not. It is possible that if you save and reopen the document, the existing nodes will get the new colors but there is no guarantee that the text color of the existing nodes will be changed automatically.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> Therefore, when you want general colors other than white and black for a document's background and text respectively, it is better to change the colors before creating and saving the document. <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> The background and text colors are respected when a <span style=" font-weight:600;">FeatherNotes</span> document is exported to PDF/HTML. <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:x-large; font-weight:600;">Hidden Keyboard Shortcuts</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <table border="1" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px;" cellspacing="2" cellpadding="3"> <tr> <td> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:large; font-weight:600;">Shortcut</span></p></td> <td> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:large; font-weight:600;">Alternative</span></p></td> <td> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:large; font-weight:600;">Action</span></p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Escape</p></td> <td></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Give the focus to the text-edit if it is not focused; otherwise, take away the focus from it and give it to the side pane (tree view)</p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ctrl+=</p></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ctrl + mouse wheel</p></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Zoom in</p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ctrl+-</p></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ctrl + mouse wheel</p></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Zoom out</p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ctrl+0</p></td> <td></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Reset zooming</p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">F11</p></td> <td></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">(Un-)Fullscreen</p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ctrl+Shift+W</p></td> <td></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Resize window to start size (700×500 by default)</p></td></tr> <tr> <td colspan="3"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600; font-style:italic;">In the following, the text-edit should be focused</p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Shift+Mouse Wheel</p></td> <td></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Scroll up/down with minimum speed</p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Insert</p></td> <td></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Toggle overwrite mode</p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Tab</p></td> <td></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ordinary text tabulation</p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ctrl+Tab</p></td> <td></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">4-space text tabulation</p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ctrl+Meta+Tab</p></td> <td></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2-space text tabulation</p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Shift+Tab</p></td> <td></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Backtab (the reverse of Tab)</p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Shift+Meta+Tab</p></td> <td></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">2-space Backtab, as far as possible</p></td></tr> <tr> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Shift+Enter</p></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Shift+Return</p></td> <td> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Insert newline with the non-letter prefix of the current line (to create lists easily)</p></td></tr></table> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">All other shortcuts can be found on menus or as tooltips and most of them can be customized in <span style=" font-weight:600; font-style:italic;">Preferences</span> dialog.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> Qt::TextSelectableByMouse Qt::Horizontal QDialogButtonBox::Close FeatherNotes-0.8.0/feathernotes/lineedit.cpp000066400000000000000000000047211374721712500211130ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #include "lineedit.h" #include #include namespace FeatherNotes { LineEdit::LineEdit (QWidget *parent) : QLineEdit (parent) { klear = nullptr; returnOnClear = true; setClearButtonEnabled (true); QList list = findChildren(); if (list.isEmpty()) return; QToolButton *clearButton = list.at (0); if (clearButton) { clearButton->setToolTip (tr ("Clear text (Ctrl+K)")); connect (clearButton, &QAbstractButton::clicked, this, &LineEdit::Klear); } connect (this, &QLineEdit::editingFinished, this, &LineEdit::unfocused); connect (this, &LineEdit::receivedFocus, this, &LineEdit::focused); } /*************************/ LineEdit::~LineEdit() { delete klear; } /*************************/ void LineEdit::focusInEvent (QFocusEvent * ev) { /* first do what QLineEdit does */ QLineEdit::focusInEvent (ev); emit receivedFocus(); } /*************************/ void LineEdit::Klear() { if (!qobject_cast(QObject::sender())) clear(); /* we'll need this for clearing found matches highlighting because the compiler won't know that clearButton is a QObject */ if (returnOnClear) returnPressed(); } /*************************/ void LineEdit::unfocused() { /* filter out pressing of Return or Enter */ if (hasFocus()) return; if (klear) { disconnect (klear, &QShortcut::activated, this, &LineEdit::Klear); delete klear; klear = nullptr; } } /*************************/ void LineEdit::focused() { if (klear) return; klear = new QShortcut (QKeySequence (tr ("Ctrl+K", "Clear text")), this); connect (klear, &QShortcut::activated, this, &LineEdit::Klear); } } FeatherNotes-0.8.0/feathernotes/lineedit.h000066400000000000000000000030451374721712500205560ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef LINEEDIT_H #define LINEEDIT_H #include #include #include namespace FeatherNotes { class LineEdit : public QLineEdit { Q_OBJECT public: LineEdit (QWidget *parent = nullptr); ~LineEdit(); bool returnOnClear; signals: void receivedFocus(); protected: virtual void keyPressEvent (QKeyEvent *event) { /* because of a bug in Qt5, the non-breaking space (ZWNJ) isn't inserted with SHIFT+SPACE */ if (event->key() == 0x200c) { insert (QChar (0x200C)); event->accept(); return; } QLineEdit::keyPressEvent (event); } void focusInEvent (QFocusEvent *ev); private slots: void Klear(); void unfocused(); void focused(); private: QShortcut *klear; }; } #endif // LINEEDIT_H FeatherNotes-0.8.0/feathernotes/main.cpp000066400000000000000000000074161374721712500202460ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016-2020 * * FeatherNotes 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. * * FeatherNotes 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 . */ #include // signal.h in C #include #include #include #include #include #include "fn.h" void handleQuitSignals (const std::vector& quitSignals) { auto handler = [](int sig) ->void { Q_UNUSED (sig); //printf("\nUser signal = %d.\n", sig); QCoreApplication::quit(); }; for (int sig : quitSignals ) signal (sig, handler); // handle these signals by quitting gracefully } int main(int argc, char *argv[]) { const QString name = "FeatherNotes"; const QString version = "0.8.0"; const QString option = QString::fromUtf8 (argv[1]); if (option == "--help" || option == "-h") { QTextStream out (stdout); out << "FeatherNotes - Lightweight Qt hierarchical notes-manager\n"\ "\nUsage:\n feathernotes [options] [file] "\ "Open the specified file\nOptions:\n"\ "--version or -v Show version information and exit.\n"\ "--help Show this help and exit\n"\ "-m, --min Start minimized\n"\ "-t, --tray Start iconified to tray if there is a tray icon\n\n"; return 0; } else if (option == "--version" || option == "-v") { QTextStream out (stdout); out << name << " " << version #if (QT_VERSION >= QT_VERSION_CHECK(5,15,0)) << Qt::endl; #else << endl; #endif return 0; } QApplication app (argc, argv); app.setApplicationName (name); app.setApplicationVersion (version); #if not defined (Q_OS_WIN) handleQuitSignals ({SIGQUIT, SIGINT, SIGTERM, SIGHUP}); // -> https://en.wikipedia.org/wiki/Unix_signal #endif app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); QStringList langs (QLocale::system().uiLanguages()); QString lang; // bcp47Name() doesn't work under vbox if (!langs.isEmpty()) lang = langs.first().replace ('-', '_'); QTranslator qtTranslator; if (!qtTranslator.load ("qt_" + lang, QLibraryInfo::location (QLibraryInfo::TranslationsPath))) { // shouldn't be needed if (!langs.isEmpty()) { lang = langs.first().split (QLatin1Char ('_')).first(); qtTranslator.load ("qt_" + lang, QLibraryInfo::location (QLibraryInfo::TranslationsPath)); } } app.installTranslator (&qtTranslator); QTranslator FPTranslator; #if defined (Q_OS_HAIKU) FPTranslator.load ("feathernotes_" + lang, "/translations"); #elif defined (Q_OS_WIN) FPTranslator.load ("feathernotes_" + lang, qApp->applicationDirPath() + "\\..\\data\\translations\\translations"); #else FPTranslator.load ("feathernotes_" + lang, QStringLiteral (DATADIR) + "/feathernotes/translations"); #endif app.installTranslator (&FPTranslator); QStringList message; if (argc > 1) { message << QString::fromUtf8 (argv[1]); if (argc > 2) message << QString::fromUtf8 (argv[2]); } FeatherNotes::FN w (message); //w.show(); return app.exec(); } FeatherNotes-0.8.0/feathernotes/messagebox.h000066400000000000000000000052731374721712500211230ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef MESSAGEBOX_H #define MESSAGEBOX_H #include #include #include #include namespace FeatherNotes { /* QMessageBox::setButtonText() is obsolete while we want custom texts, especially for translation. We also want to set the width according to the informative text. */ class MessageBox : public QMessageBox { Q_OBJECT public: MessageBox (QWidget *parent = nullptr) : QMessageBox (parent) {} MessageBox (Icon icon, const QString &title, const QString &text, StandardButtons buttons = NoButton, QWidget *parent = nullptr, Qt::WindowFlags f = Qt::Dialog/* | Qt::MSWindowsFixedSizeDialogHint*/) : QMessageBox (icon, title, text, buttons, parent, f) {} void changeButtonText (QMessageBox::StandardButton btn, const QString &text) { if (QAbstractButton *abtn = button (btn)) abtn->setText (text); } void setInformativeText (const QString &text) { QMessageBox::setInformativeText (text); if (!text.isEmpty()) // set an appropriate width { if (QGridLayout *lo = qobject_cast< QGridLayout *>(layout())) { int tw = 0; QString t (text); /* we suppose that

isn't used inside the text */ t.remove (QRegularExpression (R"(|||||)")); t.replace ("
", "\n"); QStringList l = t.split ('\n'); // deal with newlines for (int i = 0; i < l.size(); i++) #if (QT_VERSION >= QT_VERSION_CHECK(5,11,0)) tw = qMax (tw, QFontMetrics (font()).horizontalAdvance (l[i])); #else tw = qMax (tw, QFontMetrics (font()).width (l[i])); #endif lo->setColumnMinimumWidth (lo->columnCount() - 1, tw + 10); } } } }; } #endif // MESSAGEBOX_H FeatherNotes-0.8.0/feathernotes/pref.cpp000066400000000000000000000621551374721712500202570ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2019 * * FeatherNotes 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. * * FeatherNotes 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 . */ #include "pref.h" #include "ui_prefDialog.h" #include "fn.h" #ifdef HAS_HUNSPELL #include "filedialog.h" #endif #include #include #include #include #include namespace FeatherNotes { static QHash OBJECT_NAMES; static QHash DEFAULT_SHORTCUTS; /*************************/ FNKeySequenceEdit::FNKeySequenceEdit (QWidget *parent) : QKeySequenceEdit (parent) {} void FNKeySequenceEdit::keyPressEvent (QKeyEvent *event) { // also a workaround for a Qt bug that makes Meta a non-modifier clear(); // no multiple shortcuts /* don't create a shortcut without modifier because this is a text editor but make exceptions for Fx keys */ int k = event->key(); if ((k < Qt::Key_F1 || k > Qt::Key_F35) && (event->modifiers() == Qt::NoModifier || event->modifiers() == Qt::KeypadModifier)) { return; } QKeySequenceEdit::keyPressEvent (event); } /*************************/ Delegate::Delegate (QObject *parent) : QStyledItemDelegate (parent) {} QWidget* Delegate::createEditor (QWidget *parent, const QStyleOptionViewItem& /*option*/, const QModelIndex& /*index*/) const { return new FNKeySequenceEdit (parent); } /*************************/ bool Delegate::eventFilter (QObject *object, QEvent *event) { QWidget *editor = qobject_cast(object); if (editor && event->type() == QEvent::KeyPress) { int k = static_cast(event)->key(); if (k == Qt::Key_Return || k == Qt::Key_Enter) { emit QAbstractItemDelegate::commitData (editor); emit QAbstractItemDelegate::closeEditor (editor); return true; } } return QStyledItemDelegate::eventFilter (object, event); } /*************************/ PrefDialog::PrefDialog (QWidget *parent) : QDialog (parent), ui (new Ui::PrefDialog) { ui->setupUi (this); parent_ = parent; ui->promptLabel->setStyleSheet ("QLabel {background-color: #7d0000; color: white; border-radius: 3px; margin: 2px; padding: 5px;}"); ui->promptLabel->hide(); promptTimer_ = nullptr; Delegate *del = new Delegate (ui->tableWidget); ui->tableWidget->setItemDelegate (del); ui->tableWidget->horizontalHeader()->setSectionResizeMode (QHeaderView::Stretch); ui->tableWidget->horizontalHeader()->setSectionsClickable (true); ui->tableWidget->sortByColumn (0, Qt::AscendingOrder); QSize ag; FN *win = static_cast(parent_); if (win) { /************** *** Window *** **************/ if (QWindow *window = parent->windowHandle()) { if (QScreen *sc = window->screen()) ag = sc->availableGeometry().size(); } if (!ag.isValid()) ag = QSize (0, 0); /* window size */ ui->winSpinX->setMaximum (ag.width()); ui->winSpinY->setMaximum (ag.height()); ui->winSizeBox->setChecked (win->isSizeRem()); if (win->isSizeRem()) { ui->winSpinX->setValue (win->getWinSize().width()); ui->winSpinY->setValue (win->getWinSize().height()); ui->winSpinX->setEnabled (false); ui->winSpinY->setEnabled (false); ui->winLabel->setEnabled (false); ui->winXLabel->setEnabled (false); } else { ui->winSpinX->setValue (win->getStartSize().width()); ui->winSpinY->setValue (win->getStartSize().height()); } connect (ui->winSpinX, static_cast(&QSpinBox::valueChanged), this, &PrefDialog::prefSize); connect (ui->winSpinY, static_cast(&QSpinBox::valueChanged), this, &PrefDialog::prefSize); connect (ui->winSizeBox, &QCheckBox::stateChanged, this, &PrefDialog::prefSize); /* splitter position */ ui->splitterSizeBox->setChecked (win->isSplitterRem()); connect (ui->splitterSizeBox, &QCheckBox::stateChanged, win, [win] (int checked) { if (checked == Qt::Checked) { win->remSplitter (true); win->setSplitterSizes (win->getSpltiterState()); } else if (checked == Qt::Unchecked) win->remSplitter (false); }); /* window position */ ui->positionBox->setChecked (win->isPositionRem()); connect (ui->positionBox, &QCheckBox::stateChanged, win, [this, win] (int checked) { if (checked == Qt::Checked) { win->remPosition (true); win->setPosition (win->geometry().topLeft()); if (win->isUnderE()) { ui->ELabel->setEnabled (true); ui->XLabel->setEnabled (true); ui->ESpinX->setEnabled (true); ui->ESpinY->setEnabled (true); } } else if (checked == Qt::Unchecked) { win->remPosition (false); if (win->isUnderE()) { ui->ELabel->setEnabled (false); ui->XLabel->setEnabled (false); ui->ESpinX->setEnabled (false); ui->ESpinY->setEnabled (false); } } }); /* use tray */ ui->hasTrayBox->setChecked (win->hasTray()); hasTray_ = win->hasTray(); connect (ui->hasTrayBox, &QCheckBox::stateChanged, win, [this, win] (int checked) { win->useTray (checked == Qt::Checked); showPrompt(); }); connect (ui->hasTrayBox, &QAbstractButton::toggled, ui->minTrayBox, &QWidget::setEnabled); /* iconify into tray */ ui->minTrayBox->setChecked (win->doesMinToTray()); if (!win->hasTray()) ui->minTrayBox->setDisabled (true); connect (ui->minTrayBox, &QCheckBox::stateChanged, win, [win] (int checked) { win->minToTray (checked == Qt::Checked); }); /* transparent tree view */ ui->transparentTree->setChecked (win->hasTransparentTree()); connect (ui->transparentTree, &QCheckBox::stateChanged, win, [win] (int checked) { win->makeTreeTransparent (checked == Qt::Checked); }); /* small toolbar icons */ ui->smallToolbarIcons->setChecked (win->hasSmallToolbarIcons()); connect (ui->smallToolbarIcons, &QCheckBox::stateChanged, win, [win] (int checked) { win->setToolBarIconSize (checked == Qt::Checked); }); /* hide toolbar or menubar */ ui->noToolbar->setChecked (win->withoutToolbar()); ui->noMenubar->setChecked (win->withoutMenubar()); connect (ui->noToolbar, &QCheckBox::stateChanged, win, [this, win] (int checked) { if (checked == Qt::Checked) { win->showToolbar (false); ui->noMenubar->setChecked (false); } else if (checked == Qt::Unchecked) win->showToolbar (true); }); connect (ui->noMenubar, &QCheckBox::stateChanged, win, [this, win] (int checked) { if (checked == Qt::Checked) { win->showMenubar (false); ui->noToolbar->setChecked (false); } else if (checked == Qt::Unchecked) win->showMenubar (true); }); /* Enlightenment */ ui->EBox->setChecked (win->isUnderE()); ui->ESpinX->setValue (win->EShift().width()); ui->ESpinY->setValue (win->EShift().height()); if (!win->isUnderE() || !win->isPositionRem()) { ui->ELabel->setDisabled (true); ui->ESpinX->setDisabled (true); ui->XLabel->setDisabled (true); ui->ESpinY->setDisabled (true); } connect (ui->ESpinX, static_cast(&QSpinBox::valueChanged), win, [win] (int value) { win->setEShift (QSize (value, win->EShift().height())); // takes effect in FN::showEvent() }); connect (ui->ESpinY, static_cast(&QSpinBox::valueChanged), win, [win] (int value) { win->setEShift (QSize (win->EShift().width(), value)); // takes effect in FN::showEvent() }); connect (ui->EBox, &QCheckBox::stateChanged, win, [this, win] (int checked) { bool isChecked (checked == Qt::Checked); win->setUnderE (isChecked); ui->ESpinX->setEnabled (isChecked); ui->ESpinY->setEnabled (isChecked); ui->ELabel->setEnabled (isChecked); ui->XLabel->setEnabled (isChecked); if (isChecked) win->setEShift (QSize (ui->ESpinX->value(), ui->ESpinY->value())); }); /************ *** Text *** ************/ /* wrapping */ ui->wrapBox->setChecked (win->isWrappedByDefault()); connect (ui->wrapBox, &QCheckBox::stateChanged, win, [win] (int checked) { win->wrapByDefault (checked == Qt::Checked); }); /* indentation */ ui->indentBox->setChecked (win->isIndentedByDefault()); connect (ui->indentBox, &QCheckBox::stateChanged, win, [win] (int checked) { win->indentByDefault (checked == Qt::Checked); }); /* auto-bracket */ ui->autoBracketBox->setChecked (win->hasAutoBracket()); autoBracket_ = win->hasAutoBracket(); connect (ui->autoBracketBox, &QCheckBox::stateChanged, win, [this, win] (int checked) { win->autoBracket (checked == Qt::Checked); showPrompt(); }); /* auto-replace */ ui->autoReplaceBox->setChecked (win->hasAutoReplace()); autoReplace_ = win->hasAutoReplace(); connect (ui->autoReplaceBox, &QCheckBox::stateChanged, win, [this, win] (int checked) { win->autoReplace (checked == Qt::Checked); showPrompt(); }); ui->dateEdit->setPlaceholderText (locale().dateTimeFormat()); ui->dateEdit->setText (win->getDateFormat()); /* auto-saving */ ui->autoSaveSpinBox->setRange (1, 60); // not needed if (win->getAutoSave() > -1) { ui->autoSaveSpinBox->setValue (win->getAutoSave()); ui->autoSaveBox->setChecked (true); } else { ui->autoSaveSpinBox->setEnabled (false); ui->autoSaveSpinBox->setValue (5); } connect (ui->autoSaveSpinBox, static_cast(&QSpinBox::valueChanged), win, [win] (int value) { win->setAutoSave (value); // will take effect at closeEvent() }); connect (ui->autoSaveBox, &QCheckBox::stateChanged, win, [this, win] (int checked) { if (checked == Qt::Checked) { ui->autoSaveSpinBox->setEnabled (true); win->setAutoSave (ui->autoSaveSpinBox->value()); } else if (checked == Qt::Unchecked) { ui->autoSaveSpinBox->setEnabled (false); win->setAutoSave (-1); } }); /* starting with the last opened file */ ui->lastFileBox->setChecked (win->openLastFile()); connect (ui->lastFileBox, &QCheckBox::stateChanged, win, [win] (int checked) { win->setOpenLastFile (checked == Qt::Checked); }); /* spell checking */ #ifdef HAS_HUNSPELL ui->dictEdit->setText (win->getDictPath()); connect (ui->dictButton, &QAbstractButton::clicked, this, &PrefDialog::addDict); connect (ui->dictEdit, &QLineEdit::editingFinished, this, &PrefDialog::addDict); #else ui->dictGroupBox->setVisible (false); #endif /***************** *** Shortcuts *** *****************/ if (DEFAULT_SHORTCUTS.isEmpty()) { // NOTE: Shortcut strings hould be in the PortableText format. const auto defaultShortcuts = win->defaultShortcuts(); QHash::const_iterator iter = defaultShortcuts.constBegin(); while (iter != defaultShortcuts.constEnd()) { const QString name = iter.key()->objectName(); DEFAULT_SHORTCUTS.insert (name, iter.value().toString()); OBJECT_NAMES.insert (iter.key()->text().remove ("&"), name); ++ iter; } } QHash ca = win->customShortcutActions(); QList keys = ca.keys(); QHash::const_iterator iter = OBJECT_NAMES.constBegin(); while (iter != OBJECT_NAMES.constEnd()) { shortcuts_.insert (iter.key(), keys.contains (iter.value()) ? ca.value (iter.value()) : DEFAULT_SHORTCUTS.value (iter.value())); ++ iter; } QList val = shortcuts_.values(); for (int i = 0; i < val.size(); ++i) { if (!val.at (i).isEmpty() && val.indexOf (val.at (i), i + 1) > -1) { showPrompt (tr ("Warning: Ambiguous shortcut detected!"), false); break; } } ui->tableWidget->setRowCount (shortcuts_.size()); ui->tableWidget->setSortingEnabled (false); int index = 0; QHash::const_iterator it = shortcuts_.constBegin(); while (it != shortcuts_.constEnd()) { QTableWidgetItem *item = new QTableWidgetItem (it.key()); item->setFlags (item->flags() & ~Qt::ItemIsEditable & ~Qt::ItemIsSelectable); ui->tableWidget->setItem (index, 0, item); /* shortcut texts should added in the NativeText format */ ui->tableWidget->setItem (index, 1, new QTableWidgetItem (QKeySequence (it.value(), QKeySequence::PortableText) .toString (QKeySequence::NativeText))); ++ it; ++ index; } ui->tableWidget->setSortingEnabled (true); ui->tableWidget->setCurrentCell (0, 1); connect (ui->tableWidget, &QTableWidget::itemChanged, this, &PrefDialog::onShortcutChange); connect (ui->defaultButton, &QAbstractButton::clicked, this, &PrefDialog::restoreDefaultShortcuts); ui->defaultButton->setDisabled (ca.isEmpty()); } if (QPushButton *closeBtn = ui->buttonBox->button (QDialogButtonBox::Close)) { closeBtn->setAutoDefault (true); closeBtn->setDefault (true); connect (closeBtn, &QAbstractButton::clicked, this, &QDialog::close); } connect (this, &QDialog::rejected, this, &PrefDialog::onClosing); if (QPushButton *helpBtn = ui->buttonBox->button (QDialogButtonBox::Help)) { connect (helpBtn, &QAbstractButton::clicked, [] () { QWhatsThis::enterWhatsThisMode(); }); } const QString EToolTip = ui->ELabel->toolTip(); ui->ESpinX->setToolTip (EToolTip); ui->ESpinY->setToolTip (EToolTip); ui->XLabel->setToolTip (EToolTip); /* set tooltip as "whatsthis" */ const auto widgets = findChildren(); for (QWidget *w : widgets) { QString tip = w->toolTip(); if (!tip.isEmpty()) { w->setWhatsThis (tip.replace ('\n', ' ').replace (" ", "\n\n")); /* for the tooltip mess in Qt 5.12 */ w->setToolTip ("

" + w->toolTip() + "

"); } } if (win) { ag -= win->window()->frameGeometry().size() - win->window()->geometry().size(); if (win->getPrefSize().isEmpty()) resize (sizeHint().boundedTo(ag)); else resize (win->getPrefSize().boundedTo(ag)); } else resize (sizeHint().boundedTo(ag)); // impossible } /*************************/ PrefDialog::~PrefDialog() { if (promptTimer_) { promptTimer_->stop(); delete promptTimer_; } delete ui; ui = nullptr; } /*************************/ void PrefDialog::closeEvent (QCloseEvent *event) { onClosing(); event->accept(); } /*************************/ void PrefDialog::onClosing() { if (FN *win = static_cast(parent_)) { QHash::const_iterator it = newShortcuts_.constBegin(); while (it != newShortcuts_.constEnd()) { if (DEFAULT_SHORTCUTS.value (it.key()) == it.value()) win->removeShortcut (it.key()); else win->setActionShortcut (it.key(), it.value()); ++it; } win->updateCustomizableShortcuts(); QString format = ui->dateEdit->text(); /* if "\n" is typed in the line-edit, interpret it as a newline because we're on Linux */ if (!format.isEmpty()) format.replace ("\\n", "\n"); win->setDateFormat (format); win->setPrefSize (size()); win->writeConfig(); win->writeGeometryConfig(); win->rememberLastOpenedFile(); } } /*************************/ void PrefDialog::prefSize (int value) { FN *win = static_cast(parent_); if (win == nullptr) return; if (qobject_cast(QObject::sender())) { if (value == Qt::Checked) { win->remSize (true); win->setWinSize (win->size()); ui->winSpinX->setEnabled (false); ui->winSpinY->setEnabled (false); ui->winLabel->setEnabled (false); ui->winXLabel->setEnabled (false); } else if (value == Qt::Unchecked) { win->remSize (false); win->setStartSize (win->getWinSize()); ui->winSpinX->setEnabled (true); ui->winSpinY->setEnabled (true); ui->winLabel->setEnabled (true); ui->winXLabel->setEnabled (true); } } else if (ui->winSpinX == qobject_cast(QObject::sender())) win->setStartSize (QSize (ui->winSpinX->value(), win->getStartSize().height())); else if (ui->winSpinY == qobject_cast(QObject::sender())) win->setStartSize (QSize (win->getStartSize().width(), ui->winSpinY->value())); } /*************************/ // NOTE: Custom shortcuts will be saved in the PortableText format. void PrefDialog::onShortcutChange (QTableWidgetItem *item) { FN *win = static_cast(parent_); if (win == nullptr) return; QString desc = ui->tableWidget->item (ui->tableWidget->currentRow(), 0)->text(); QString txt = item->text(); if (!txt.isEmpty()) { /* the QKeySequenceEdit text is in the NativeText format but it should be converted into the PortableText format for saving */ QKeySequence keySeq (txt); txt = keySeq.toString(); } if (!txt.isEmpty() && win->reservedShortcuts().contains (txt) && DEFAULT_SHORTCUTS.value (OBJECT_NAMES.value (desc)) != txt) // always true { showPrompt (tr ("The typed shortcut was reserved."), true); disconnect (ui->tableWidget, &QTableWidget::itemChanged, this, &PrefDialog::onShortcutChange); item->setText (shortcuts_.value (desc)); connect (ui->tableWidget, &QTableWidget::itemChanged, this, &PrefDialog::onShortcutChange); } else { shortcuts_.insert (desc, txt); newShortcuts_.insert (OBJECT_NAMES.value (desc), txt); /* check for ambiguous shortcuts */ bool ambiguous = false; QList val = shortcuts_.values(); for (int i = 0; i < val.size(); ++i) { if (!val.at (i).isEmpty() && val.indexOf (val.at (i), i + 1) > -1) { showPrompt (tr ("Warning: Ambiguous shortcut detected!"), false); ambiguous = true; break; } } if (!ambiguous && ui->promptLabel->isVisible()) { prevtMsg_ = QString(); showPrompt(); } /* also set the state of the Default button */ QHash::const_iterator it = shortcuts_.constBegin(); while (it != shortcuts_.constEnd()) { if (DEFAULT_SHORTCUTS.value (OBJECT_NAMES.value (it.key())) != it.value()) { ui->defaultButton->setEnabled (true); return; } ++it; } ui->defaultButton->setEnabled (false); } } /*************************/ void PrefDialog::restoreDefaultShortcuts() { FN *win = static_cast(parent_); if (win == nullptr) return; if (newShortcuts_.isEmpty() && win->customShortcutActions().isEmpty()) { // do nothing if there's no custom shortcut return; } disconnect (ui->tableWidget, &QTableWidget::itemChanged, this, &PrefDialog::onShortcutChange); int cur = ui->tableWidget->currentColumn() == 0 ? 0 : ui->tableWidget->currentRow(); ui->tableWidget->setSortingEnabled (false); newShortcuts_ = DEFAULT_SHORTCUTS; int index = 0; QMutableHashIterator it (shortcuts_); while (it.hasNext()) { it.next(); ui->tableWidget->item (index, 0)->setText (it.key()); QString s = DEFAULT_SHORTCUTS.value (OBJECT_NAMES.value (it.key())); ui->tableWidget->item (index, 1)->setText (s); it.setValue (s); ++ index; } ui->tableWidget->setSortingEnabled (true); ui->tableWidget->setCurrentCell (cur, 1); connect (ui->tableWidget, &QTableWidget::itemChanged, this, &PrefDialog::onShortcutChange); ui->defaultButton->setEnabled (false); if (ui->promptLabel->isVisible()) { prevtMsg_ = QString(); showPrompt(); } } /*************************/ void PrefDialog::showPrompt (const QString& str, bool temporary) { FN *win = static_cast(parent_); if (win == nullptr) return; if (!str.isEmpty()) { // show the provided message ui->promptLabel->setText ("" + str + ""); if (temporary) // show it temporarily { if (promptTimer_ == nullptr) { promptTimer_ = new QTimer(); promptTimer_->setSingleShot (true); connect (promptTimer_, &QTimer::timeout, [this] { if (!prevtMsg_.isEmpty() && ui->tabWidget->currentIndex() == 3) // Shortcuts page { // show the previous message if it exists ui->promptLabel->setText (prevtMsg_); } else showPrompt(); }); } promptTimer_->start (3300); } else prevtMsg_ = "" + str + ""; } else if (hasTray_ != win->hasTray() || autoBracket_ != win->hasAutoBracket() || autoReplace_ != win->hasAutoReplace()) { ui->promptLabel->setText ("" + tr ("Application restart is needed for changes to take effect.") + ""); } else { if (prevtMsg_.isEmpty()) // clear prompt { ui->promptLabel->clear(); ui->promptLabel->hide(); return; } else // show the previous message ui->promptLabel->setText (prevtMsg_); } ui->promptLabel->show(); } /*************************/ #ifdef HAS_HUNSPELL void PrefDialog::addDict() { FN *win = static_cast(parent_); if (win == nullptr) return; if (QObject::sender() == ui->dictEdit) { win->setDictPath (ui->dictEdit->text()); return; } FileDialog dialog (this); dialog.setAcceptMode (QFileDialog::AcceptOpen); dialog.setWindowTitle (tr ("Add dictionary...")); dialog.setFileMode (QFileDialog::ExistingFile); dialog.setNameFilter (tr ("Hunspell Dictionary Files (*.dic)")); QString path = ui->dictEdit->text(); if (path.isEmpty()) { path = "/usr/share/hunspell"; if (!QFileInfo (path).isDir()) path = "/usr/local/share/hunspell"; } if (QFileInfo (path).isDir()) dialog.setDirectory (path); else if (QFile::exists (path)) { dialog.setDirectory (path.section ("/", 0, -2)); dialog.selectFile (path); dialog.autoScroll(); } if (dialog.exec()) { const QStringList files = dialog.selectedFiles(); if (!files.isEmpty()) { ui->dictEdit->setText (files.at (0)); win->setDictPath (files.at (0)); } } } #endif } FeatherNotes-0.8.0/feathernotes/pref.h000066400000000000000000000042251374721712500177160ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2019 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef PREF_H #define PREF_H #include #include #include #include #include namespace FeatherNotes { class FNKeySequenceEdit : public QKeySequenceEdit { Q_OBJECT public: FNKeySequenceEdit (QWidget *parent = nullptr); protected: virtual void keyPressEvent (QKeyEvent *event); }; class Delegate : public QStyledItemDelegate { Q_OBJECT public: Delegate (QObject *parent = nullptr); virtual QWidget* createEditor (QWidget *parent, const QStyleOptionViewItem&, const QModelIndex&) const; protected: virtual bool eventFilter (QObject *object, QEvent *event); }; namespace Ui { class PrefDialog; } class PrefDialog : public QDialog { Q_OBJECT public: explicit PrefDialog (QWidget *parent = nullptr); ~PrefDialog(); private slots: void onClosing(); void prefSize (int value); void onShortcutChange (QTableWidgetItem *item); void restoreDefaultShortcuts(); #ifdef HAS_HUNSPELL void addDict(); #endif private: void closeEvent (QCloseEvent *event); void showPrompt (const QString& str = QString(), bool temporary = false); Ui::PrefDialog *ui; QWidget * parent_; QHash shortcuts_, newShortcuts_; QString prevtMsg_; bool hasTray_, autoBracket_, autoReplace_; QTimer *promptTimer_; }; } #endif // PREF_H FeatherNotes-0.8.0/feathernotes/prefDialog.ui000066400000000000000000000466151374721712500212350ustar00rootroot00000000000000 FeatherNotes::PrefDialog 0 0 400 386 Preferences 0 true Window Saves window size after closing this dialog and also on exit. Uncheck to set a fixed size! Remember window &size Start with this size: px × px Qt::Horizontal QSizePolicy::MinimumExpanding 5 5 Saves tree width after closing this dialog and also on exit. Uncheck for a width ratio of 170/530. Remember &tree width Saves position after closing this dialog and also on exit. (This may not work correctly under GTK+ DE's like Unity and Cinnamon.) Save &position Decides whether a systray icon should be used. If checked, the titlebar close button iconifies the window to the systray instead of quitting. Needs restarting of FeatherNotes to take effect. Add to s&ystray Qt::Horizontal QSizePolicy::Fixed 22 5 The command line option --tray can be used instead of this. Start i&conified to tray Merge the tree view with its surroundings? Transparent t&ree view By default, the active widget style determines the size of toolbar icons. Small toolbar icons Do not show t&oolbar If the menubar is hidden, a menu button appears on the toolbar. Do not show &menubar Check this under Enlightenment (or, probably, another DE) to use the systray icon more easily! Running &under Enlightenment? Qt::Horizontal QSizePolicy::Fixed 22 5 Some DE's (like Enlightenment) may not report the window position correctly. If that is the case, you could try to fix the problem here. If the panel is on the bottom or top, the Y-coordinate should be set; if it is on the left or right, the X-coordinate should be set. After choosing the coordinate shifts, put the window in a proper position and then restart FeatherNotes! Shifts (X × Y): px × px Qt::Horizontal QSizePolicy::MinimumExpanding 5 5 Qt::Vertical QSizePolicy::MinimumExpanding 5 1 Text &Wrap lines by default Auto-&indent by default This covers parentheses, braces, brackets and quotes. Needs restarting of FeatherNotes to take effect. Auto-&bracket A triple period is replaced with an ellipsis, a double hyphen with a long dash, etc. while the user is typing and under proper circumstances. &Replace some characters while typing Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. Date and time format: Used for pasting the date and time. Leave empty for the system default. Takes effect after closing this dialog. true &Auto-save every minute(s) 1 60 5 Qt::Horizontal QSizePolicy::MinimumExpanding 5 5 Spell Checking A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". Hunspell dictionary path: A Hunspell dictionary has a name that ends with ".dic" and should be alongside an affix file with the same name but ending with ".aff". true Add dictionary... ... Qt::Vertical QSizePolicy::MinimumExpanding 5 1 Files Start with the last opened file Qt::Vertical 5 1 Shortcuts QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::SelectedClicked true QAbstractItemView::SingleSelection false Action Shortcut Default false Qt::AlignCenter Qt::NoTextInteraction Qt::Horizontal QDialogButtonBox::Close|QDialogButtonBox::Help FeatherNotes-0.8.0/feathernotes/settings.h000066400000000000000000000026011374721712500206160ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef SETTINGS_H #define SETTINGS_H #include namespace FeatherNotes { // Prevent redundant writings! class Settings : public QSettings { Q_OBJECT public: Settings (const QString &organization, const QString &application = QString(), QObject *parent = nullptr) : QSettings (organization, application, parent) {} Settings (const QString &fileName, QSettings::Format format, QObject *parent = nullptr) : QSettings (fileName, format, parent) {} void setValue (const QString &key, const QVariant &v) { if (value (key) == v) return; QSettings::setValue (key, v); } }; } #endif // SETTINGS_H FeatherNotes-0.8.0/feathernotes/simplecrypt.cpp000066400000000000000000000175741374721712500217030ustar00rootroot00000000000000/* Copyright (c) 2011, Andre Somers All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Rathenau Instituut, Andre Somers nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANDRE SOMERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include "simplecrypt.h" #include #include #include #include #include #include namespace FeatherNotes { SimpleCrypt::SimpleCrypt(): m_key(0), m_compressionMode(CompressionAuto), m_protectionMode(ProtectionChecksum), m_lastError(ErrorNoError) { srand(static_cast(QDateTime::currentMSecsSinceEpoch() & 0xFFFF)); } SimpleCrypt::SimpleCrypt(quint64 key): m_key(key), m_compressionMode(CompressionAuto), m_protectionMode(ProtectionChecksum), m_lastError(ErrorNoError) { srand(static_cast(QDateTime::currentMSecsSinceEpoch() & 0xFFFF)); splitKey(); } void SimpleCrypt::setKey(quint64 key) { m_key = key; splitKey(); } void SimpleCrypt::splitKey() { m_keyParts.clear(); m_keyParts.resize(8); for (int i=0;i<8;i++) { quint64 part = m_key; for (int j=i; j>0; j--) part = part >> 8; part = part & 0xff; m_keyParts[i] = static_cast(part); } } QByteArray SimpleCrypt::encryptToByteArray(const QString& plaintext) { QByteArray plaintextArray = plaintext.toUtf8(); return encryptToByteArray(plaintextArray); } QByteArray SimpleCrypt::encryptToByteArray(QByteArray plaintext) { if (m_keyParts.isEmpty()) { qWarning() << "No key set."; m_lastError = ErrorNoKeySet; return QByteArray(); } QByteArray ba = plaintext; CryptoFlags flags = CryptoFlagNone; if (m_compressionMode == CompressionAlways) { ba = qCompress(ba, 9); //maximum compression flags |= CryptoFlagCompression; } else if (m_compressionMode == CompressionAuto) { QByteArray compressed = qCompress(ba, 9); if (compressed.count() < ba.count()) { ba = compressed; flags |= CryptoFlagCompression; } } QByteArray integrityProtection; if (m_protectionMode == ProtectionChecksum) { flags |= CryptoFlagChecksum; QDataStream s(&integrityProtection, QIODevice::WriteOnly); s << qChecksum(ba.constData(), static_cast(ba.length())); } else if (m_protectionMode == ProtectionHash) { flags |= CryptoFlagHash; QCryptographicHash hash(QCryptographicHash::Sha1); hash.addData(ba); integrityProtection += hash.result(); } //prepend a random char to the string char randomChar = char(rand() & 0xFF); ba = randomChar + integrityProtection + ba; int pos(0); char lastChar(0); int cnt = ba.count(); while (pos < cnt) { ba[pos] = ba.at(pos) ^ m_keyParts.at(pos % 8) ^ lastChar; lastChar = ba.at(pos); ++pos; } QByteArray resultArray; resultArray.append(char(0x03)); //version for future updates to algorithm resultArray.append(char(flags)); //encryption flags resultArray.append(ba); m_lastError = ErrorNoError; return resultArray; } QString SimpleCrypt::encryptToString(const QString& plaintext) { QByteArray plaintextArray = plaintext.toUtf8(); QByteArray cypher = encryptToByteArray(plaintextArray); //QString cypherString = QString::fromAscii(cypher.toBase64()); QString cypherString = QString::fromLatin1(cypher.toBase64()); return cypherString; } QString SimpleCrypt::encryptToString(QByteArray plaintext) { QByteArray cypher = encryptToByteArray(plaintext); //QString cypherString = QString::fromAscii(cypher.toBase64()); QString cypherString = QString::fromLatin1(cypher.toBase64()); return cypherString; } QString SimpleCrypt::decryptToString(const QString &cyphertext) { //QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toAscii()); QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1()); QByteArray plaintextArray = decryptToByteArray(cyphertextArray); QString plaintext = QString::fromUtf8(plaintextArray, plaintextArray.size()); return plaintext; } QString SimpleCrypt::decryptToString(QByteArray cypher) { QByteArray ba = decryptToByteArray(cypher); QString plaintext = QString::fromUtf8(ba, ba.size()); return plaintext; } QByteArray SimpleCrypt::decryptToByteArray(const QString& cyphertext) { //QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toAscii()); QByteArray cyphertextArray = QByteArray::fromBase64(cyphertext.toLatin1()); QByteArray ba = decryptToByteArray(cyphertextArray); return ba; } QByteArray SimpleCrypt::decryptToByteArray(QByteArray cypher) { if (m_keyParts.isEmpty()) { qWarning() << "No key set."; m_lastError = ErrorNoKeySet; return QByteArray(); } QByteArray ba = cypher; if( cypher.count() < 3 ) return QByteArray(); char version = ba.at(0); if (version !=3) { //we only work with version 3 m_lastError = ErrorUnknownVersion; //qWarning() << "Invalid version or not a cyphertext."; return QByteArray(); } CryptoFlags flags = CryptoFlags(ba.at(1)); ba = ba.mid(2); int pos(0); int cnt(ba.count()); char lastChar = 0; while (pos < cnt) { char currentChar = ba[pos]; ba[pos] = ba.at(pos) ^ lastChar ^ m_keyParts.at(pos % 8); lastChar = currentChar; ++pos; } ba = ba.mid(1); //chop off the random number at the start bool integrityOk(true); if (flags.testFlag(CryptoFlagChecksum)) { if (ba.length() < 2) { m_lastError = ErrorIntegrityFailed; return QByteArray(); } quint16 storedChecksum; { QDataStream s(&ba, QIODevice::ReadOnly); s >> storedChecksum; } ba = ba.mid(2); quint16 checksum = qChecksum(ba.constData(), static_cast(ba.length())); integrityOk = (checksum == storedChecksum); } else if (flags.testFlag(CryptoFlagHash)) { if (ba.length() < 20) { m_lastError = ErrorIntegrityFailed; return QByteArray(); } QByteArray storedHash = ba.left(20); ba = ba.mid(20); QCryptographicHash hash(QCryptographicHash::Sha1); hash.addData(ba); integrityOk = (hash.result() == storedHash); } if (!integrityOk) { m_lastError = ErrorIntegrityFailed; return QByteArray(); } if (flags.testFlag(CryptoFlagCompression)) ba = qUncompress(ba); m_lastError = ErrorNoError; return ba; } } FeatherNotes-0.8.0/feathernotes/simplecrypt.h000066400000000000000000000234211374721712500213340ustar00rootroot00000000000000/* Copyright (c) 2011, Andre Somers All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Rathenau Instituut, Andre Somers nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANDRE SOMERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef SIMPLECRYPT_H #define SIMPLECRYPT_H #include #include #include namespace FeatherNotes { /** @short Simple encryption and decryption of strings and byte arrays This class provides a simple implementation of encryption and decryption of strings and byte arrays. @warning The encryption provided by this class is NOT strong encryption. It may help to shield things from curious eyes, but it will NOT stand up to someone determined to break the encryption. Don't say you were not warned. The class uses a 64 bit key. Simply create an instance of the class, set the key, and use the encryptToString() method to calculate an encrypted version of the input string. To decrypt that string again, use an instance of SimpleCrypt initialized with the same key, and call the decryptToString() method with the encrypted string. If the key matches, the decrypted version of the string will be returned again. If you do not provide a key, or if something else is wrong, the encryption and decryption function will return an empty string or will return a string containing nonsense. lastError() will return a value indicating if the method was succesful, and if not, why not. SimpleCrypt is prepared for the case that the encryption and decryption algorithm is changed in a later version, by prepending a version identifier to the cypertext. */ class SimpleCrypt { public: /** CompressionMode describes if compression will be applied to the data to be encrypted. */ enum CompressionMode { CompressionAuto, /*!< Only apply compression if that results in a shorter plaintext. */ CompressionAlways, /*!< Always apply compression. Note that for short inputs, a compression may result in longer data */ CompressionNever /*!< Never apply compression. */ }; /** IntegrityProtectionMode describes measures taken to make it possible to detect problems with the data or wrong decryption keys. Measures involve adding a checksum or a cryptograhpic hash to the data to be encrypted. This increases the length of the resulting cypertext, but makes it possible to check if the plaintext appears to be valid after decryption. */ enum IntegrityProtectionMode { ProtectionNone, /*!< The integerity of the encrypted data is not protected. It is not really possible to detect a wrong key, for instance. */ ProtectionChecksum,/*!< A simple checksum is used to verify that the data is in order. If not, an empty string is returned. */ ProtectionHash /*!< A cryptographic hash is used to verify the integrity of the data. This method produces a much stronger, but longer check */ }; /** Error describes the type of error that occured. */ enum Error { ErrorNoError, /*!< No error occurred. */ ErrorNoKeySet, /*!< No key was set. You can not encrypt or decrypt without a valid key. */ ErrorUnknownVersion, /*!< The version of this data is unknown, or the data is otherwise not valid. */ ErrorIntegrityFailed /*!< The integrity check of the data failed. Perhaps the wrong key was used. */ }; /** Constructor. Constructs a SimpleCrypt instance without a valid key set on it. */ SimpleCrypt(); /** Constructor. Constructs a SimpleCrypt instance and initializes it with the given @arg key. */ explicit SimpleCrypt(quint64 key); /** (Re-) initializes the key with the given @arg key. */ void setKey(quint64 key); /** Returns true if SimpleCrypt has been initialized with a key. */ bool hasKey() const {return !m_keyParts.isEmpty();} /** Sets the compression mode to use when encrypting data. The default mode is Auto. Note that decryption is not influenced by this mode, as the decryption recognizes what mode was used when encrypting. */ void setCompressionMode(CompressionMode mode) {m_compressionMode = mode;} /** Returns the CompressionMode that is currently in use. */ CompressionMode compressionMode() const {return m_compressionMode;} /** Sets the integrity mode to use when encrypting data. The default mode is Checksum. Note that decryption is not influenced by this mode, as the decryption recognizes what mode was used when encrypting. */ void setIntegrityProtectionMode(IntegrityProtectionMode mode) {m_protectionMode = mode;} /** Returns the IntegrityProtectionMode that is currently in use. */ IntegrityProtectionMode integrityProtectionMode() const {return m_protectionMode;} /** Returns the last error that occurred. */ Error lastError() const {return m_lastError;} /** Encrypts the @arg plaintext string with the key the class was initialized with, and returns a cyphertext the result. The result is a base64 encoded version of the binary array that is the actual result of the string, so it can be stored easily in a text format. */ QString encryptToString(const QString& plaintext) ; /** Encrypts the @arg plaintext QByteArray with the key the class was initialized with, and returns a cyphertext the result. The result is a base64 encoded version of the binary array that is the actual result of the encryption, so it can be stored easily in a text format. */ QString encryptToString(QByteArray plaintext) ; /** Encrypts the @arg plaintext string with the key the class was initialized with, and returns a binary cyphertext in a QByteArray the result. This method returns a byte array, that is useable for storing a binary format. If you need a string you can store in a text file, use encryptToString() instead. */ QByteArray encryptToByteArray(const QString& plaintext) ; /** Encrypts the @arg plaintext QByteArray with the key the class was initialized with, and returns a binary cyphertext in a QByteArray the result. This method returns a byte array, that is useable for storing a binary format. If you need a string you can store in a text file, use encryptToString() instead. */ QByteArray encryptToByteArray(QByteArray plaintext) ; /** Decrypts a cyphertext string encrypted with this class with the set key back to the plain text version. If an error occured, such as non-matching keys between encryption and decryption, an empty string or a string containing nonsense may be returned. */ QString decryptToString(const QString& cyphertext) ; /** Decrypts a cyphertext string encrypted with this class with the set key back to the plain text version. If an error occured, such as non-matching keys between encryption and decryption, an empty string or a string containing nonsense may be returned. */ QByteArray decryptToByteArray(const QString& cyphertext) ; /** Decrypts a cyphertext binary encrypted with this class with the set key back to the plain text version. If an error occured, such as non-matching keys between encryption and decryption, an empty string or a string containing nonsense may be returned. */ QString decryptToString(QByteArray cypher) ; /** Decrypts a cyphertext binary encrypted with this class with the set key back to the plain text version. If an error occured, such as non-matching keys between encryption and decryption, an empty string or a string containing nonsense may be returned. */ QByteArray decryptToByteArray(QByteArray cypher) ; //enum to describe options that have been used for the encryption. Currently only one, but //that only leaves room for future extensions like adding a cryptographic hash... enum CryptoFlag{CryptoFlagNone = 0, CryptoFlagCompression = 0x01, CryptoFlagChecksum = 0x02, CryptoFlagHash = 0x04 }; Q_DECLARE_FLAGS(CryptoFlags, CryptoFlag) private: void splitKey(); quint64 m_key; QVector m_keyParts; CompressionMode m_compressionMode; IntegrityProtectionMode m_protectionMode; Error m_lastError; }; Q_DECLARE_OPERATORS_FOR_FLAGS(SimpleCrypt::CryptoFlags) } #endif // SimpleCrypt_H FeatherNotes-0.8.0/feathernotes/spellChecker.cpp000066400000000000000000000067511374721712500217270ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2020 * * FeatherNotes 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. * * FeatherNotes 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 . */ #include "spellChecker.h" #include #include #include #include #include #include namespace FeatherNotes { SpellChecker::SpellChecker (const QString& dictionaryPath, const QString& userDictionary) { userDictionary_ = userDictionary; QString dictFile = dictionaryPath + ".dic"; QString affixFile = dictionaryPath + ".aff"; QByteArray dictFilePathBA = dictFile.toLocal8Bit(); QByteArray affixFilePathBA = affixFile.toLocal8Bit(); hunspell_ = new Hunspell (affixFilePathBA.constData(), dictFilePathBA.constData()); QString encoding = "UTF-8"; QFile _affixFile (affixFile); if (_affixFile.open (QIODevice::ReadOnly)) { QTextStream stream (&_affixFile); QRegularExpression encDetector ("^\\s*SET\\s+([A-Z0-9\\-]+)\\s*", QRegularExpression::CaseInsensitiveOption); QRegularExpressionMatch match; for (QString line = stream.readLine(); !line.isEmpty(); line = stream.readLine()) { if (line.indexOf (encDetector, 0, &match) > -1) { encoding = match.captured (1); break; } } _affixFile.close(); } codec_ = QTextCodec::codecForName (encoding.toLatin1().constData()); if (!userDictionary_.isEmpty()) { QFile userDictonaryFile (userDictionary_); if (userDictonaryFile.open (QIODevice::ReadOnly)) { QTextStream stream (&userDictonaryFile); for (QString word = stream.readLine(); !word.isEmpty(); word = stream.readLine()) ignoreWord (word); userDictonaryFile.close(); } } } /*************************/ SpellChecker::~SpellChecker() { delete hunspell_; } /*************************/ bool SpellChecker::spell (const QString& word) { return hunspell_->spell (word.toStdString()); } /*************************/ QStringList SpellChecker::suggest (const QString& word) { const std::vector strSuggestions = hunspell_->suggest (word.toStdString()); QStringList suggestions; for (auto str : strSuggestions) suggestions << QString::fromStdString (str); return suggestions; } /*************************/ void SpellChecker::ignoreWord (const QString& word) { hunspell_->add (codec_->fromUnicode (word).toStdString()); } /*************************/ void SpellChecker::addToUserWordlist (const QString& word) { ignoreWord (word); if (!userDictionary_.isEmpty()) { QFile userDictonaryFile (userDictionary_); if (userDictonaryFile.open (QIODevice::Append)) { QTextStream stream (&userDictonaryFile); stream << word << "\n"; userDictonaryFile.close(); } } } } FeatherNotes-0.8.0/feathernotes/spellChecker.h000066400000000000000000000030511374721712500213620ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2020 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef SPELLCHECKER_H #define SPELLCHECKER_H #include #include class Hunspell; namespace FeatherNotes { class SpellChecker { public: SpellChecker (const QString& dictionaryPath, const QString& userDictionary); ~SpellChecker(); bool spell (const QString& word); QStringList suggest (const QString& word); void ignoreWord (const QString& word); void addToUserWordlist (const QString& word); void addToCorrections (const QString& misspelled, const QString& correct) { corrections_.insert (misspelled, correct); } QString correct (const QString& misspelled) const { return corrections_.value (misspelled); } private: Hunspell *hunspell_; QString userDictionary_; QTextCodec *codec_; QHash corrections_; }; } #endif // SPELLCHECKER_H FeatherNotes-0.8.0/feathernotes/spellDialog.cpp000066400000000000000000000076201374721712500215560ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2020 * * FeatherNotes 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. * * FeatherNotes 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 . */ #include "spellDialog.h" #include "ui_spellDialog.h" #include "spellChecker.h" #include #include namespace FeatherNotes { SpellDialog::SpellDialog (SpellChecker *spellChecker, const QString& word, QWidget *parent) : QDialog (parent), ui (new Ui::SpellDialog) { ui->setupUi (this); setWindowModality (Qt::WindowModal); QWidget::setTabOrder (ui->replace, ui->listWidget); QWidget::setTabOrder (ui->listWidget, ui->ignoreOnce); QWidget::setTabOrder (ui->ignoreOnce, ui->ignoreAll); QWidget::setTabOrder (ui->ignoreAll, ui->correctOnce); QWidget::setTabOrder (ui->correctOnce, ui->correctAll); QWidget::setTabOrder (ui->correctAll, ui->addToDict); ui->ignoreOnce->setShortcut (QKeySequence (Qt::Key_F3)); ui->ignoreOnce->setToolTip (QKeySequence (Qt::Key_F3).toString (QKeySequence::NativeText)); ui->ignoreAll->setShortcut (QKeySequence (Qt::Key_F4)); ui->ignoreAll->setToolTip (QKeySequence (Qt::Key_F4).toString (QKeySequence::NativeText)); ui->correctOnce->setShortcut (QKeySequence (Qt::Key_F5)); ui->correctOnce->setToolTip (QKeySequence (Qt::Key_F5).toString (QKeySequence::NativeText)); ui->correctAll->setShortcut (QKeySequence (Qt::Key_F6)); ui->correctAll->setToolTip (QKeySequence (Qt::Key_F6).toString (QKeySequence::NativeText)); ui->addToDict->setShortcut (QKeySequence (Qt::Key_F7)); ui->addToDict->setToolTip (QKeySequence (Qt::Key_F7).toString (QKeySequence::NativeText)); spellChecker_ = spellChecker; connect (ui->correctOnce, &QAbstractButton::clicked, [this] {emit spellChecked (SpellAction::CorrectOnce);}); connect (ui->ignoreOnce, &QAbstractButton::clicked, [this] {emit spellChecked (SpellAction::IgnoreOnce);}); connect (ui->correctAll, &QAbstractButton::clicked, [this] {emit spellChecked (SpellAction::CorrectAll);}); connect (ui->ignoreAll, &QAbstractButton::clicked, [this] {emit spellChecked (SpellAction::IgnoreAll);}); connect (ui->addToDict, &QAbstractButton::clicked, [this] {emit spellChecked (SpellAction::AddToDict);}); connect (ui->listWidget, &QListWidget::currentTextChanged, ui->replace, &QLineEdit::setText); checkWord (word); if (parent != nullptr) { if (QWindow *win = parent->windowHandle()) { if (QScreen *sc = win->screen()) { QSize ag = sc->availableGeometry().size() - (parent->window()->frameGeometry().size() - parent->window()->geometry().size()); resize (size().boundedTo (ag)); } } } } /*************************/ SpellDialog::~SpellDialog() { delete ui; ui = nullptr; } /*************************/ QString SpellDialog::replacement() const { return ui->replace->text(); } /*************************/ void SpellDialog::checkWord (const QString &word) { if (word.isEmpty()) return; ui->replace->clear(); ui->listWidget->clear(); ui->misspelledLabel->setText (QString ("%1").arg (word)); QStringList suggestions = spellChecker_->suggest (word); ui->listWidget->addItems (suggestions); if (!suggestions.isEmpty()) ui->listWidget->setCurrentRow (0, QItemSelectionModel::Select); } } FeatherNotes-0.8.0/feathernotes/spellDialog.h000066400000000000000000000026421374721712500212220ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2020 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef SPELLDIALOG_H #define SPELLDIALOG_H #include namespace FeatherNotes { class SpellChecker; namespace Ui { class SpellDialog; } class SpellDialog : public QDialog { Q_OBJECT public: enum SpellAction {CorrectOnce, IgnoreOnce, CorrectAll, IgnoreAll, AddToDict}; explicit SpellDialog (SpellChecker *spellChecker, const QString &word, QWidget *parent = nullptr); ~SpellDialog(); SpellChecker * spellChecker() const { return spellChecker_; } QString replacement() const; void checkWord(const QString &word); signals: void spellChecked (int result); private: Ui::SpellDialog *ui; SpellChecker *spellChecker_; }; } #endif // SPELLDIALOG_H FeatherNotes-0.8.0/feathernotes/spellDialog.ui000066400000000000000000000124011374721712500214020ustar00rootroot00000000000000 FeatherNotes::SpellDialog 0 0 700 400 Dialog 5 Unknown word: 0 0 200 0 Add To Dictionary Replace with: 0 0 Ignore Once 0 0 Ignore All Qt::Vertical QSizePolicy::Fixed 5 22 0 0 Correct Once 0 0 Correct All Qt::Vertical QSizePolicy::MinimumExpanding 5 5 Qt::Horizontal QDialogButtonBox::Close buttonBox clicked(QAbstractButton*) spellDialog close() 316 260 286 274 FeatherNotes-0.8.0/feathernotes/spinbox.h000066400000000000000000000026071374721712500204460ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef SPINBOX_H #define SPINBOX_H #include namespace FeatherNotes { /* Forget about the focus-out event and emit the signal editingFinished() only if Return/Enter is pressed. */ class SpinBox : public QSpinBox { public: SpinBox (QWidget *p = nullptr) : QSpinBox (p) {} bool event (QEvent *event) { #ifdef QT_KEYPAD_NAVIGATION if (event->type() == QEvent::EnterEditFocus || event->type() == QEvent::LeaveEditFocus) { return QWidget::event(event); } else #endif return QSpinBox::event (event); } protected: void focusOutEvent (QFocusEvent*) {return;} }; } #endif // SPINBOX_H FeatherNotes-0.8.0/feathernotes/svgicons.cpp000066400000000000000000000062101374721712500211440ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2018 * * FeatherNotes 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. * * FeatherNotes 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 . * * @license GPL-3.0+ */ #include #include #include #include #include #include #include #include #include #include "svgicons.h" namespace FeatherNotes { class symbolicIconEngine : public QIconEngine { public: symbolicIconEngine (const QString &file) : fileName (file) {} ~symbolicIconEngine() override {} symbolicIconEngine* clone() const override { return new symbolicIconEngine (fileName); } void paint (QPainter *painter, const QRect& rect, QIcon::Mode mode, QIcon::State state) override { Q_UNUSED (state) QColor col; if (mode == QIcon::Disabled) col = QApplication::palette().color (QPalette::Disabled, QPalette::WindowText); else if (mode == QIcon::Selected) col = QApplication::palette().highlightedText().color(); else col = QApplication::palette().windowText().color(); QString key = fileName + "-" + QString::number (rect.width()) + "-" + QString::number (rect.height()) + "-" + col.name(); QPixmap pix; if (!QPixmapCache::find (key, &pix)) { pix = QPixmap (rect.width(), rect.height()); pix.fill (Qt::transparent); if (!fileName.isEmpty()) { QSvgRenderer renderer; QFile f (fileName); QByteArray bytes; if (f.open (QIODevice::ReadOnly)) bytes = f.readAll(); if (!bytes.isEmpty()) bytes.replace ("#000", col.name().toLatin1()); renderer.load (bytes); QPainter p (&pix); renderer.render (&p, QRect (0, 0, rect.width(), rect.height())); } QPixmapCache::insert (key, pix); } painter->drawPixmap (rect.topLeft(), pix); } QPixmap pixmap (const QSize& size, QIcon::Mode mode, QIcon::State state) override { QPixmap pix (size); pix.fill (Qt::transparent); QPainter painter (&pix); paint (&painter, QRect (QPoint (0, 0), size), mode, state); return pix; } private: QString fileName; }; QIcon symbolicIcon::icon (const QString& fileName) { return QIcon (new symbolicIconEngine (fileName)); } } FeatherNotes-0.8.0/feathernotes/svgicons.h000066400000000000000000000017141374721712500206150ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2018 * * FeatherNotes 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. * * FeatherNotes 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 . * * @license GPL-3.0+ */ #ifndef SVGICONS_H #define SVGICONS_H #include namespace FeatherNotes { namespace symbolicIcon { QIcon icon (const QString& fileName); } } #endif // SVGICONS_H FeatherNotes-0.8.0/feathernotes/textedit.cpp000066400000000000000000001134511374721712500211510ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016-2020 * * FeatherNotes 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. * * FeatherNotes 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 . */ #include "textedit.h" #include #include #include #include #include #include #include #include #include #include #include #include #define SCROLL_FRAMES_PER_SEC 50 #define SCROLL_DURATION 200 // in ms static const int scrollAnimFrames = SCROLL_FRAMES_PER_SEC * SCROLL_DURATION / 1000; namespace FeatherNotes { TextEdit::TextEdit (QWidget *parent) : QTextEdit (parent) { autoIndentation = true; autoBracket = false; autoReplace = false; textTab_ = " "; // the default text tab is four spaces pressPoint = QPoint(); scrollTimer_ = nullptr; VScrollBar *vScrollBar = new VScrollBar; setVerticalScrollBar (vScrollBar); #if (QT_VERSION == QT_VERSION_CHECK(5,14,0)) /* workaround */ HScrollBar *hScrollBar = new HScrollBar; setHorizontalScrollBar (hScrollBar); #endif } /*************************/ TextEdit::~TextEdit() { if (scrollTimer_) { disconnect (scrollTimer_, &QTimer::timeout, this, &TextEdit::scrollSmoothly); scrollTimer_->stop(); delete scrollTimer_; } } /*************************/ // Finds the (remaining) spaces that should be inserted with Ctrl+Tab. QString TextEdit::remainingSpaces (const QString& spaceTab, const QTextCursor& cursor) const { QTextCursor tmp = cursor; QString txt = cursor.block().text().left (cursor.positionInBlock()); QFontMetricsF fm = QFontMetricsF (document()->defaultFont()); #if (QT_VERSION >= QT_VERSION_CHECK(5,11,0)) qreal spaceL = fm.horizontalAdvance (" "); #else qreal spaceL = fm.width (" "); #endif int n = 0, i = 0; while ((i = txt.indexOf("\t", i)) != -1) { // find tab widths in terms of spaces tmp.setPosition (tmp.block().position() + i); qreal x = static_cast(cursorRect (tmp).right()); tmp.setPosition (tmp.position() + 1); x = static_cast(cursorRect (tmp).right()) - x; n += qMax (qRound (qAbs (x) / spaceL) - 1, 0); // x is negative for RTL ++i; } n += txt.count(); n = spaceTab.count() - n % spaceTab.count(); QString res; for (int i = 0 ; i < n; ++i) res += " "; return res; } /*************************/ // Returns a cursor that selects the spaces to be removed by a backtab. // If "twoSpace" is true, a 2-space backtab will be applied as far as possible. QTextCursor TextEdit::backTabCursor (const QTextCursor& cursor, bool twoSpace) const { QTextCursor tmp = cursor; tmp.movePosition (QTextCursor::StartOfBlock); /* find the start of the real text */ const QString blockText = cursor.block().text(); int indx = 0; QRegularExpressionMatch match; if (blockText.indexOf (QRegularExpression (R"(^\s+)"), 0, &match) > -1) indx = match.capturedLength(); else return tmp; int txtStart = cursor.block().position() + indx; QString txt = blockText.left (indx); QFontMetricsF fm = QFontMetricsF (document()->defaultFont()); #if (QT_VERSION >= QT_VERSION_CHECK(5,11,0)) qreal spaceL = fm.horizontalAdvance (" "); #else qreal spaceL = fm.width (" "); #endif int n = 0, i = 0; while ((i = txt.indexOf("\t", i)) != -1) { // find tab widths in terms of spaces tmp.setPosition (tmp.block().position() + i); qreal x = static_cast(cursorRect (tmp).right()); tmp.setPosition (tmp.position() + 1); x = static_cast(cursorRect (tmp).right()) - x; n += qMax (qRound (qAbs (x) / spaceL) - 1, 0); ++i; } n += txt.count(); n = n % textTab_.count(); if (n == 0) n = textTab_.count(); if (twoSpace) n = qMin (n, 2); tmp.setPosition (txtStart); if (blockText.at (indx - 1) == QChar (QChar::Space)) tmp.setPosition (txtStart - n, QTextCursor::KeepAnchor); else // the previous character is a tab { qreal x = static_cast(cursorRect (tmp).right()); tmp.setPosition (txtStart - 1, QTextCursor::KeepAnchor); x -= static_cast(cursorRect (tmp).right()); n -= qRound (qAbs (x) / spaceL); if (n < 0) n = 0; // impossible without "twoSpace" tmp.setPosition (tmp.position() - n, QTextCursor::KeepAnchor); } return tmp; } /*************************/ static inline bool isOnlySpaces (const QString &str) { int i = 0; while (i < str.size()) { // always skip the starting spaces QChar ch = str.at (i); if (ch == QChar (QChar::Space) || ch == QChar (QChar::Tabulation)) ++i; else return false; } return true; } void TextEdit::keyPressEvent (QKeyEvent *event) { if (event->modifiers() == Qt::ControlModifier && !isReadOnly() && event->key() == Qt::Key_Z) { // only for a workaround (see TextEdit::undo) if (document()->isUndoAvailable()) undo(); event->accept(); return; } if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { QTextCursor cur = textCursor(); QString selTxt = cur.selectedText(); if (autoReplace && selTxt.isEmpty()) { const int p = cur.positionInBlock(); if (p > 1) { cur.beginEditBlock(); cur.movePosition (QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, 2); const QString sel = cur.selectedText(); if (!sel.endsWith (".")) { if (sel == "--") { QTextCursor prevCur = cur; prevCur.setPosition (cur.position()); prevCur.movePosition (QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); if (prevCur.selectedText() != "-") cur.insertText ("—"); } else if (sel == "->") cur.insertText ("→"); else if (sel == "<-") cur.insertText ("←"); else if (sel == ">=") cur.insertText ("≥"); else if (sel == "<=") cur.insertText ("≤"); } else if (p > 2) { cur = textCursor(); cur.movePosition (QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, 3); const QString sel = cur.selectedText(); if (sel == "...") { QTextCursor prevCur = cur; prevCur.setPosition (cur.position()); if (p > 3) { prevCur.movePosition (QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); if (prevCur.selectedText() != ".") cur.insertText ("…"); } else cur.insertText ("…"); } } cur.endEditBlock(); cur = textCursor(); // reset the current cursor } } bool isBracketed (false); QString prefix, indent; bool withShift (event->modifiers() & Qt::ShiftModifier); /* with Shift+Enter, find the non-letter prefix */ if (withShift) { cur.clearSelection(); setTextCursor (cur); const QString blockText = cur.block().text(); int i = 0; int curBlockPos = cur.position() - cur.block().position(); while (i < curBlockPos) { QChar ch = blockText.at (i); if (!ch.isLetterOrNumber()) { prefix += ch; ++i; } else break; } /* still check if a letter or number follows */ if (i < curBlockPos) { QChar c = blockText.at (i); if (c.isLetter()) { if (i + 1 < curBlockPos && !prefix.isEmpty() && !prefix.at (prefix.size() - 1).isSpace() && blockText.at (i + 1).isSpace()) { // non-letter and non-space character -> singlle letter -> space prefix = blockText.left (i + 2); QChar cc = QChar (c.unicode() + 1); if (cc.isLetter()) prefix.replace (c, cc); } else if (i + 2 < curBlockPos && !blockText.at (i + 1).isLetterOrNumber() && !blockText.at (i + 1).isSpace() && blockText.at (i + 2).isSpace()) { // singlle letter -> non-letter and non-space character -> space prefix = blockText.left (i + 3); QChar cc = QChar (c.unicode() + 1); if (cc.isLetter()) prefix.replace (c, cc); } } else if (c.isNumber()) { // making lists with numbers QString num; while (i < curBlockPos) { QChar ch = blockText.at (i); if (ch.isNumber()) { num += ch; ++i; } else { if (!num.isEmpty()) { QChar ch = blockText.at (i); if (ch.isSpace()) { // non-letter and non-space character -> number -> space if (!prefix.isEmpty() && !prefix.at (prefix.size() - 1).isSpace()) num = locale().toString (locale().toInt (num) + 1) + ch; else num = QString(); } else if (i + 1 < curBlockPos && !ch.isLetterOrNumber() && !ch.isSpace() && blockText.at (i + 1).isSpace()) { // number -> non-letter and non-space character -> space num = locale().toString (locale().toInt (num) + 1) + ch + blockText.at (i + 1); } else num = QString(); } break; } } if (i < curBlockPos) // otherwise, it'll be just a number prefix += num; } } } else { /* find the indentation */ if (autoIndentation) indent = computeIndentation (cur); /* check whether a bracketed text is selected so that the cursor position is at its start */ QTextCursor anchorCur = cur; anchorCur.setPosition (cur.anchor()); if (autoBracket && cur.position() == cur.selectionStart() && !cur.atBlockStart() && !anchorCur.atBlockEnd()) { cur.setPosition (cur.position()); cur.movePosition (QTextCursor::PreviousCharacter); cur.movePosition (QTextCursor::NextCharacter, QTextCursor::KeepAnchor, selTxt.size() + 2); QString selTxt1 = cur.selectedText(); if (selTxt1 == "{" + selTxt + "}" || selTxt1 == "(" + selTxt + ")") isBracketed = true; cur = textCursor(); // reset the current cursor } } if (withShift || autoIndentation || isBracketed) { cur.beginEditBlock(); /* first press Enter normally... */ cur.insertText (QChar (QChar::ParagraphSeparator)); /* ... then, insert indentation... */ cur.insertText (indent); /* ... and handle Shift+Enter or brackets */ if (withShift) cur.insertText (prefix); else if (isBracketed) { cur.movePosition (QTextCursor::PreviousBlock); cur.movePosition (QTextCursor::EndOfBlock); int start = -1; QStringList lines = selTxt.split (QChar (QChar::ParagraphSeparator)); if (lines.size() == 1) { cur.insertText (QChar (QChar::ParagraphSeparator)); cur.insertText (indent); start = cur.position(); if (!isOnlySpaces (lines. at (0))) cur.insertText (lines. at (0)); } else // multi-line { for (int i = 0; i < lines.size(); ++i) { if (i == 0 && isOnlySpaces (lines. at (0))) continue; cur.insertText (QChar (QChar::ParagraphSeparator)); if (i == 0) { cur.insertText (indent); start = cur.position(); } else if (i == 1 && start == -1) start = cur.position(); // the first line was only spaces cur.insertText (lines. at (i)); } } cur.setPosition (start, start >= cur.block().position() ? QTextCursor::MoveAnchor : QTextCursor::KeepAnchor); setTextCursor (cur); } cur.endEditBlock(); ensureCursorVisible(); event->accept(); return; } } else if (event->key() == Qt::Key_ParenLeft || event->key() == Qt::Key_BraceLeft || event->key() == Qt::Key_BracketLeft || event->key() == Qt::Key_QuoteDbl) { if (autoBracket) { QTextCursor cursor = textCursor(); bool autoB (false); if (!cursor.hasSelection()) { if (cursor.atBlockEnd()) autoB = true; else { QTextCursor tmp = cursor; tmp.movePosition (QTextCursor::NextCharacter, QTextCursor::KeepAnchor); if (!tmp.selectedText().at (0).isLetterOrNumber()) autoB = true; } } else if (cursor.position() == cursor.selectionStart()) autoB = true; if (autoB) { int pos = cursor.position(); int anch = cursor.anchor(); cursor.beginEditBlock(); cursor.setPosition (anch); if (event->key() == Qt::Key_ParenLeft) { cursor.insertText (")"); cursor.setPosition (pos); cursor.insertText ("("); } else if (event->key() == Qt::Key_BraceLeft) { cursor.insertText ("}"); cursor.setPosition (pos); cursor.insertText ("{"); } else if (event->key() == Qt::Key_BracketLeft) { cursor.insertText ("]"); cursor.setPosition (pos); cursor.insertText ("["); } else// if (event->key() == Qt::Key_QuoteDbl) { cursor.insertText ("\""); cursor.setPosition (pos); cursor.insertText ("\""); } /* select the text and set the cursor at its start */ cursor.setPosition (anch + 1, QTextCursor::MoveAnchor); cursor.setPosition (pos + 1, QTextCursor::KeepAnchor); cursor.endEditBlock(); /* WARNING: Why does putting "setTextCursor()" before "endEditBlock()" cause a crash with huge lines? Most probably, a Qt bug. */ setTextCursor (cursor); event->accept(); return; } } } else if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Right) { /* when text is selected, use arrow keys to go to the start or end of the selection */ QTextCursor cursor = textCursor(); if (event->modifiers() == Qt::NoModifier && cursor.hasSelection()) { QString str = cursor.selectedText(); if (event->key() == Qt::Key_Left) { if (str.isRightToLeft()) cursor.setPosition (cursor.selectionEnd()); else cursor.setPosition (cursor.selectionStart()); } else { if (str.isRightToLeft()) cursor.setPosition(cursor.selectionStart()); else cursor.setPosition(cursor.selectionEnd()); } cursor.clearSelection(); setTextCursor (cursor); event->accept(); return; } } else if (event->key() == Qt::Key_Tab) { QTextCursor cursor = textCursor(); int newLines = cursor.selectedText().count (QChar (QChar::ParagraphSeparator)); if (newLines > 0) { cursor.beginEditBlock(); cursor.setPosition (qMin (cursor.anchor(), cursor.position())); // go to the first block cursor.movePosition (QTextCursor::StartOfBlock); for (int i = 0; i <= newLines; ++i) { /* skip all spaces to align the real text */ int indx = 0; QRegularExpressionMatch match; if (cursor.block().text().indexOf (QRegularExpression (R"(^\s+)"), 0, &match) > -1) indx = match.capturedLength(); cursor.setPosition (cursor.block().position() + indx); if (event->modifiers() & Qt::ControlModifier) { cursor.insertText (remainingSpaces (event->modifiers() & Qt::MetaModifier ? " " : textTab_, cursor)); } else cursor.insertText ("\t"); if (!cursor.movePosition (QTextCursor::NextBlock)) break; // not needed } cursor.endEditBlock(); event->accept(); return; } else if (event->modifiers() & Qt::ControlModifier) { QTextCursor tmp (cursor); tmp.setPosition (qMin (tmp.anchor(), tmp.position())); cursor.insertText (remainingSpaces (event->modifiers() & Qt::MetaModifier ? " " : textTab_, tmp)); event->accept(); return; } } else if (event->key() == Qt::Key_Backtab) { QTextCursor cursor = textCursor(); int newLines = cursor.selectedText().count (QChar (QChar::ParagraphSeparator)); cursor.setPosition (qMin (cursor.anchor(), cursor.position())); cursor.beginEditBlock(); cursor.movePosition (QTextCursor::StartOfBlock); for (int i = 0; i <= newLines; ++i) { if (cursor.atBlockEnd()) { if (!cursor.movePosition (QTextCursor::NextBlock)) break; // not needed continue; } cursor = backTabCursor (cursor, event->modifiers() & Qt::MetaModifier ? true : false); cursor.removeSelectedText(); if (!cursor.movePosition (QTextCursor::NextBlock)) break; // not needed } cursor.endEditBlock(); /* otherwise, do nothing with SHIFT+TAB */ event->accept(); return; } else if (event->key() == Qt::Key_Insert) { if (event->modifiers() == Qt::NoModifier || event->modifiers() == Qt::KeypadModifier) { setOverwriteMode (!overwriteMode()); if (!overwriteMode()) { setCursorWidth (1); update(); // otherwise, a part of the thick cursor might remain } else setCursorWidth (QFontMetrics(font()).averageCharWidth()); event->accept(); return; } } /* because of a bug in Qt5, the non-breaking space (ZWNJ) isn't inserted with SHIFT+SPACE */ else if (event->key() == 0x200c) { insertPlainText (QChar (0x200C)); event->accept(); return; } else if (event->key() == Qt::Key_Space) { if (autoReplace && event->modifiers() == Qt::NoModifier) { QTextCursor cur = textCursor(); if (!cur.hasSelection()) { const int p = cur.positionInBlock(); if (p > 1) { cur.beginEditBlock(); cur.movePosition (QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, 2); const QString selTxt = cur.selectedText(); if (!selTxt.endsWith (".")) { if (selTxt == "--") { QTextCursor prevCur = cur; prevCur.setPosition (cur.position()); prevCur.movePosition (QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); if (prevCur.selectedText() != "-") cur.insertText ("—"); } else if (selTxt == "->") cur.insertText ("→"); else if (selTxt == "<-") cur.insertText ("←"); else if (selTxt == ">=") cur.insertText ("≥"); else if (selTxt == "<=") cur.insertText ("≤"); } else if (p > 2) { cur = textCursor(); cur.movePosition (QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, 3); const QString selTxt = cur.selectedText(); if (selTxt == "...") { QTextCursor prevCur = cur; prevCur.setPosition (cur.position()); if (p > 3) { prevCur.movePosition (QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor); if (prevCur.selectedText() != ".") cur.insertText ("…"); } else cur.insertText ("…"); } } cur.endEditBlock(); } } } } else if (event->key() == Qt::Key_Home) { if (!(event->modifiers() & Qt::ControlModifier)) { // Qt's default behavior isn't acceptable QTextCursor cur = textCursor(); int p = cur.positionInBlock(); int indx = 0; QRegularExpressionMatch match; if (cur.block().text().indexOf (QRegularExpression ("^\\s+"), 0, &match) > -1) indx = match.capturedLength(); if (p > 0) { if (p <= indx) p = 0; else p = indx; } else p = indx; cur.setPosition (p + cur.block().position(), event->modifiers() & Qt::ShiftModifier ? QTextCursor::KeepAnchor : QTextCursor::MoveAnchor); setTextCursor (cur); ensureCursorVisible(); event->accept(); return; } } QTextEdit::keyPressEvent (event); } /*************************/ QString TextEdit::computeIndentation (const QTextCursor& cur) const { QTextCursor cusror = cur; if (cusror.hasSelection()) {// this is more intuitive to me if (cusror.anchor() <= cusror.position()) cusror.setPosition (cusror.anchor()); else cusror.setPosition (cusror.position()); } QTextCursor tmp = cusror; tmp.movePosition (QTextCursor::StartOfBlock); QString str; if (tmp.atBlockEnd()) return str; int pos = tmp.position(); tmp.setPosition (++pos, QTextCursor::KeepAnchor); QString selected; while (!tmp.atBlockEnd() && tmp <= cusror && ((selected = tmp.selectedText()) == " " || (selected = tmp.selectedText()) == "\t")) { str.append (selected); tmp.setPosition (pos); tmp.setPosition (++pos, QTextCursor::KeepAnchor); } if (tmp.atBlockEnd() && tmp <= cusror && ((selected = tmp.selectedText()) == " " || (selected = tmp.selectedText()) == "\t")) { str.append (selected); } return str; } /*************************/ // Emit resized(). void TextEdit::resizeEvent (QResizeEvent *e) { QTextEdit::resizeEvent (e); emit resized(); } /*************************/ // Show links as tooltips. bool TextEdit::event (QEvent *e) { if (e->type() == QEvent::ToolTip) { QHelpEvent *helpEvent = static_cast(e); QString str = anchorAt (helpEvent->pos()); if (!str.isEmpty()) QToolTip::showText (helpEvent->globalPos(), "

" + str + "

"); else { QToolTip::hideText(); e->ignore(); } return true; } return QTextEdit::event (e); } /*************************/ bool TextEdit::canInsertFromMimeData (const QMimeData *source) const { if (source->hasImage() || source->hasUrls()) return true; else return QTextEdit::canInsertFromMimeData (source); } /*************************/ void TextEdit::insertFromMimeData (const QMimeData *source) { if (source->hasImage()) { QImage image = qvariant_cast(source->imageData()); if (!image.isNull()) { QByteArray rawarray; QBuffer buffer (&rawarray); buffer.open (QIODevice::WriteOnly); image.save (&buffer, "PNG"); buffer.close(); insertHtml (QString ("") .arg (QString (rawarray.toBase64()))); } } else if (source->hasUrls()) { const auto urls = source->urls(); for (const QUrl &url : urls) { QMimeDatabase mimeDatabase; QMimeType mimeType = mimeDatabase.mimeTypeForFile (QFileInfo (url.toLocalFile())); QByteArray ba = mimeType.name().toUtf8(); if (QImageReader::supportedMimeTypes().contains (ba)) emit imageDropped (url.path()); else { if (url.fileName().endsWith (".fnx") || mimeType.name() == "text/feathernotes-fnx") { emit FNDocDropped (url.path()); return; // only open the first file } else textCursor().insertText (url.toString()); } } } else QTextEdit::insertFromMimeData (source); } /*************************/ void TextEdit::mouseMoveEvent (QMouseEvent *e) { QTextEdit::mouseMoveEvent (e); QString str = anchorAt (e->pos()); if (!str.isEmpty()) viewport()->setCursor (Qt::PointingHandCursor); else viewport()->setCursor (Qt::IBeamCursor); } /*************************/ void TextEdit::mousePressEvent (QMouseEvent *e) { /* On triple clicking, select the current block without selecting its newline and start and end whitespaces, if any. */ if (tripleClickTimer_.isValid()) { if (!tripleClickTimer_.hasExpired (qApp->doubleClickInterval()) && e->buttons() == Qt::LeftButton) { tripleClickTimer_.invalidate(); QTextCursor txtCur = textCursor(); const QString blockText = txtCur.block().text(); const int l = blockText.length(); txtCur.movePosition (QTextCursor::StartOfBlock); int i = 0; while (i < l && blockText.at (i).isSpace()) ++i; /* WARNING: QTextCursor::movePosition() can be a mess with RTL but QTextCursor::setPosition() works fine. */ if (i < l) { txtCur.setPosition (txtCur.position() + i); int j = l; while (j > i && blockText.at (j - 1).isSpace()) --j; txtCur.setPosition (txtCur.position() + j - i, QTextCursor::KeepAnchor); } else txtCur.setPosition (txtCur.position() + i, QTextCursor::KeepAnchor); setTextCursor (txtCur); return; } tripleClickTimer_.invalidate(); } QTextEdit::mousePressEvent (e); pressPoint = e->pos(); } /*************************/ void TextEdit::mouseReleaseEvent (QMouseEvent *e) { QTextEdit::mouseReleaseEvent (e); /* give only a plain text to the selection clipboard */ QTextCursor cursor = textCursor(); if (cursor.hasSelection()) { QClipboard *cl = QApplication::clipboard(); if (cl->supportsSelection()) cl->setText (cursor.selection().toPlainText(), QClipboard::Selection); } QString str = anchorAt (e->pos()); if (!str.isEmpty() && cursorForPosition (e->pos()) == cursorForPosition (pressPoint)) { QUrl url (str); if (url.isRelative()) // treat relative URLs as local paths url = QUrl::fromUserInput (str, "/", QUrl::AssumeLocalFile); /* QDesktopServices::openUrl() may resort to "xdg-open", which isn't the best choice. "gio" is always reliable, so we check it first. */ if (!QProcess::startDetached ("gio", QStringList() << "open" << url.toString())) QDesktopServices::openUrl (url); } pressPoint = QPoint(); } /*************************/ void TextEdit::mouseDoubleClickEvent (QMouseEvent *e) { tripleClickTimer_.start(); QTextEdit::mouseDoubleClickEvent (e); } /*************************/ void TextEdit::wheelEvent (QWheelEvent *e) { if (e->modifiers() & Qt::ControlModifier) { float delta = e->angleDelta().y() / 120.f; zooming (delta); return; } /* smooth scrolling */ if (e->spontaneous() && e->source() == Qt::MouseEventNotSynthesized) { #if (QT_VERSION >= QT_VERSION_CHECK(5,12,0)) bool horizontal (e->angleDelta().x() != 0); #else bool horizontal (e->orientation() == Qt::Horizontal); #endif QScrollBar* sbar = horizontal ? horizontalScrollBar() : verticalScrollBar(); if (sbar) { int delta = horizontal ? e->angleDelta().x() : e->angleDelta().y(); if (e->modifiers() & Qt::ShiftModifier) // scrolling with minimum speed delta /= QApplication::wheelScrollLines(); if ((delta > 0 && sbar->value() == sbar->minimum()) || (delta < 0 && sbar->value() == sbar->maximum())) { return; // the scrollbar can't move } if (!scrollTimer_) { scrollTimer_ = new QTimer(); scrollTimer_->setTimerType (Qt::PreciseTimer); connect (scrollTimer_, &QTimer::timeout, this, &TextEdit::scrollSmoothly); } /* set the data for inertial scrolling */ scrollData data; data.delta = delta; data.leftFrames = scrollAnimFrames; data.vertical = !horizontal; queuedScrollSteps_.append (data); scrollTimer_->start (1000 / SCROLL_FRAMES_PER_SEC); return; } } /* as in QTextEdit::wheelEvent() */ QAbstractScrollArea::wheelEvent (e); updateMicroFocus(); } /*************************/ void TextEdit::scrollSmoothly() { int totalDeltaH = 0, totalDeltaV = 0; QList::iterator it = queuedScrollSteps_.begin(); while (it != queuedScrollSteps_.end()) { int delta = qRound (static_cast(it->delta) / static_cast(scrollAnimFrames)); int remainingDelta = it->delta - (scrollAnimFrames - it->leftFrames) * delta; if (qAbs (delta) >= qAbs (remainingDelta)) { // this is the last frame or, due to rounding, there can be no more frame if (it->vertical) totalDeltaV += remainingDelta; else totalDeltaH += remainingDelta; it = queuedScrollSteps_.erase (it); } else { if (it->vertical) totalDeltaV += delta; else totalDeltaH += delta; -- it->leftFrames; ++it; } } if (totalDeltaH != 0 && horizontalScrollBar()) { #if (QT_VERSION >= QT_VERSION_CHECK(5,12,0)) QWheelEvent eventH (QPointF(), QPointF(), QPoint(), #if (QT_VERSION == QT_VERSION_CHECK(5,14,0)) QPoint (totalDeltaH, 0), #else QPoint (0, totalDeltaH), #endif Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); #else QWheelEvent eventH (QPointF(), QPointF(), totalDeltaH, Qt::NoButton, Qt::NoModifier, Qt::Vertical); #endif QCoreApplication::sendEvent (horizontalScrollBar(), &eventH); } if (totalDeltaV != 0 && verticalScrollBar()) { #if (QT_VERSION >= QT_VERSION_CHECK(5,12,0)) QWheelEvent eventV (QPointF(), QPointF(), QPoint(), QPoint (0, totalDeltaV), Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false); #else QWheelEvent eventV (QPointF(), QPointF(), totalDeltaV, Qt::NoButton, Qt::NoModifier, Qt::Vertical); #endif QCoreApplication::sendEvent (verticalScrollBar(), &eventV); } /* update text selection if the left mouse button is pressed (-> QPlainTextEdit::timerEvent) */ if (QApplication::mouseButtons() & Qt::LeftButton) { const QPoint globalPos = QCursor::pos(); QPoint pos = viewport()->mapFromGlobal (globalPos); QMouseEvent ev (QEvent::MouseMove, pos, viewport()->mapTo (viewport()->topLevelWidget(), pos), globalPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); mouseMoveEvent (&ev); } if (queuedScrollSteps_.empty()) scrollTimer_->stop(); } /*************************/ void TextEdit::zooming (float range) { if (range == 0.f) return; QFont f = document()->defaultFont(); const float newSize = static_cast(f.pointSizeF()) + range; if (newSize <= 0) return; f.setPointSizeF (static_cast(newSize)); setFont (f); #if (QT_VERSION >= QT_VERSION_CHECK(5,11,0)) QFontMetricsF metrics (f); setTabStopDistance (4 * metrics.horizontalAdvance (' ')); #elif (QT_VERSION >= QT_VERSION_CHECK(5,10,0)) QFontMetricsF metrics (f); setTabStopDistance (4 * metrics.width (' ')); #else QFontMetrics metrics (f); setTabStopWidth (4 * metrics.width (' ')); #endif /* if this is a zoom-out, the text will need to be formatted and/or highlighted again */ if (range < 0) emit zoomedOut (this); } /*************************/ void TextEdit::undo() { QTextEdit::undo(); /* This is a workaround for a weird Qt bug: If some text is pasted at the document start, the pasting is undone and then, some text is pasted at the document start again, the text color of the document stylesheet will be ignored. */ if (CSSTextColor.isValid()) { QTextCursor cur = textCursor(); if (cur.atStart() && cur.atEnd()) { QTextCharFormat fmt; fmt.setForeground (CSSTextColor); cur.setBlockCharFormat (fmt); } } } } FeatherNotes-0.8.0/feathernotes/textedit.h000066400000000000000000000054521374721712500206170ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016-2020 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef TEXTEDIT_H #define TEXTEDIT_H #include #include #include #include #include #include #include #include "vscrollbar.h" namespace FeatherNotes { /* Here, I subclassed QTextEdit to gain control over pressing Enter and have auto-indentation. I also replaced its vertical scrollbar for faster wheel scrolling when the mouse cursor is on the scrollbar. */ class TextEdit : public QTextEdit { Q_OBJECT public: TextEdit (QWidget *parent = nullptr); ~TextEdit(); void zooming (float range); bool autoIndentation; bool autoBracket; bool autoReplace; QColor CSSTextColor; // used internally for a workaround signals: void resized(); void imageDropped (const QString &path); void FNDocDropped (const QString &path); void zoomedOut (TextEdit *textEdit); // needed for reformatting text public slots: void undo(); protected: void keyPressEvent (QKeyEvent *event); bool canInsertFromMimeData (const QMimeData *source) const; void insertFromMimeData (const QMimeData *source); void mouseMoveEvent (QMouseEvent *e); void mousePressEvent (QMouseEvent *e); void mouseReleaseEvent (QMouseEvent *e); void mouseDoubleClickEvent (QMouseEvent *e); void resizeEvent (QResizeEvent *e); bool event (QEvent *e); virtual void wheelEvent (QWheelEvent *e); private slots: void scrollSmoothly(); private: QString computeIndentation (const QTextCursor& cur) const; QString remainingSpaces (const QString& spaceTab, const QTextCursor& cursor) const; QTextCursor backTabCursor(const QTextCursor& cursor, bool twoSpace) const; QString textTab_; // text tab in terms of spaces QPoint pressPoint; QElapsedTimer tripleClickTimer_; /**************************** ***** Smooth scrolling ***** ****************************/ struct scrollData { int delta; int leftFrames; bool vertical; }; QList queuedScrollSteps_; QTimer *scrollTimer_; }; } #endif // TEXTEDIT_H FeatherNotes-0.8.0/feathernotes/treeview.h000066400000000000000000000133141374721712500206130ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef TREEVIEW_H #define TREEVIEW_H #include #include #include #include #include #include namespace FeatherNotes { /* We don't want Ctrl + left click to deselect a selected node in the single-selection mode. In addition, we want to open FeatherNotes docs by DND. */ class TreeView : public QTreeView { Q_OBJECT public: TreeView (QWidget *parent = nullptr) : QTreeView (parent) { setDragDropMode (QAbstractItemView::InternalMove); setHeaderHidden (true); setAnimated (true); setDragEnabled (true); setAcceptDrops (true); setDropIndicatorShown (true); setDefaultDropAction (Qt::IgnoreAction); setSelectionMode (QAbstractItemView::SingleSelection); setSelectionBehavior (QAbstractItemView::SelectRows); setAlternatingRowColors (false); setVerticalScrollMode (QAbstractItemView::ScrollPerItem); setHorizontalScrollMode (QAbstractItemView::ScrollPerPixel); setAutoScroll (true); setEditTriggers (QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed); setTextElideMode (Qt::ElideRight); } signals: void FNDocDropped (const QString &path); protected: /* see "qabstractitemview.cpp" */ virtual QItemSelectionModel::SelectionFlags selectionCommand (const QModelIndex &index, const QEvent *event = nullptr) const { Qt::KeyboardModifiers keyModifiers = Qt::NoModifier; if (event) { switch (event->type()) { case QEvent::MouseButtonDblClick: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: case QEvent::KeyPress: case QEvent::KeyRelease: keyModifiers = (static_cast(event))->modifiers(); break; default: keyModifiers = QApplication::keyboardModifiers(); } } if (selectionMode() == QAbstractItemView::SingleSelection && (keyModifiers & Qt::ControlModifier) && selectionModel()->isSelected (index)) return QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows; else return QTreeView::selectionCommand (index, event); } virtual void dragEnterEvent (QDragEnterEvent *event) { if (event->mimeData()->hasUrls()) { bool FNDocFound (false); const auto urls = event->mimeData()->urls(); for (const QUrl &url : urls) { if (url.fileName().endsWith (".fnx")) { FNDocFound = true; event->acceptProposedAction(); break; } QMimeDatabase mimeDatabase; QMimeType mimeType = mimeDatabase.mimeTypeForFile (QFileInfo (url.toLocalFile())); if (mimeType.name() == "text/feathernotes-fnx") { FNDocFound = true; event->acceptProposedAction(); break; } } if (!FNDocFound) { event->ignore(); return; } } QTreeView::dragEnterEvent (event); } virtual void dropEvent (QDropEvent *event) { if (event->mimeData()->hasUrls()) { const auto urls = event->mimeData()->urls(); for (const QUrl &url : urls) { if (url.fileName().endsWith (".fnx")) { emit FNDocDropped (url.path()); break; } QMimeDatabase mimeDatabase; QMimeType mimeType = mimeDatabase.mimeTypeForFile (QFileInfo (url.toLocalFile())); if (mimeType.name() == "text/feathernotes-fnx") { emit FNDocDropped (url.path()); break; } } } QTreeView::dropEvent (event); } virtual void mousePressEvent (QMouseEvent *event) { /* get the global press position if it's inside an item to know whether there will be a real mouse movement at mouseMoveEvent() */ if (event->buttons() == Qt::LeftButton && qApp->keyboardModifiers() == Qt::NoModifier) { if (indexAt (event->pos()).isValid()) itemPressPoint_ = event->globalPos(); else itemPressPoint_ = QPoint(); } else itemPressPoint_ = QPoint(); QTreeView::mousePressEvent (event); } virtual void mouseMoveEvent (QMouseEvent *event) { /* prevent dragging if there is no real mouse movement */ if (event->buttons() == Qt::LeftButton && event->globalPos() == itemPressPoint_) return; QTreeView::mouseMoveEvent (event); } private: QPoint itemPressPoint_; }; } #endif // TREEVIEW_H FeatherNotes-0.8.0/feathernotes/vscrollbar.cpp000066400000000000000000000045161374721712500214710ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #include "vscrollbar.h" #include #if (QT_VERSION != QT_VERSION_CHECK(5,14,0)) #include #endif namespace FeatherNotes { VScrollBar::VScrollBar (QWidget *parent) : QScrollBar (parent) { defaultWheelSpeed = QApplication::wheelScrollLines(); if (defaultWheelSpeed == 0) // in case something's wrong defaultWheelSpeed = 3; } /*************************/ bool VScrollBar::event (QEvent *event) { if (event->type() == QEvent::Enter) QApplication::setWheelScrollLines (102); else if (event->type() == QEvent::Leave /* Apparently, the Qt5 hover bug is never going to be fixed! */ || (QApplication::wheelScrollLines() != defaultWheelSpeed && !rect().contains (mapFromGlobal (QCursor::pos())))) { QApplication::setWheelScrollLines (defaultWheelSpeed); } return QScrollBar::event (event); } /*************************/ #if (QT_VERSION == QT_VERSION_CHECK(5,14,0)) void HScrollBar::wheelEvent (QWheelEvent *event) { if (event->angleDelta().x() == 0) { int deltaY = event->angleDelta().y(); if (deltaY != 0) { QWheelEvent e (event->pos(), event->globalPos(), event->pixelDelta(), QPoint (deltaY, 0), event->buttons(), event->modifiers(), event->phase(), event->source()); QCoreApplication::sendEvent (this, &e); return; } } QScrollBar::wheelEvent (event); } #endif } FeatherNotes-0.8.0/feathernotes/vscrollbar.h000066400000000000000000000026621374721712500211360ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef VSCROLLBAR_H #define VSCROLLBAR_H #include #if (QT_VERSION == QT_VERSION_CHECK(5,14,0)) #include #endif namespace FeatherNotes { /* We want faster mouse wheel scrolling when the mouse cursor in on the scrollbar. */ class VScrollBar : public QScrollBar { Q_OBJECT public: VScrollBar (QWidget *parent = nullptr); protected: bool event (QEvent *event); private: int defaultWheelSpeed; }; #if (QT_VERSION == QT_VERSION_CHECK(5,14,0)) /* Workaround. */ class HScrollBar : public QScrollBar { Q_OBJECT public: HScrollBar (QWidget *parent = nullptr) : QScrollBar (parent) {}; protected: void wheelEvent (QWheelEvent *event); }; #endif } #endif // VSCROLLBAR_H FeatherNotes-0.8.0/feathernotes/x11.cpp000066400000000000000000000115411374721712500177250ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #include #include "x11.h" #if defined Q_WS_X11 || defined Q_OS_LINUX || defined Q_OS_OPENBSD || defined Q_OS_NETBSD || defined Q_OS_HURD #include #include #endif namespace FeatherNotes { /************************************************************* *** These are all X11 related functions FeatherNotes uses *** *** because Qt is not rooted enough in X11. *** *************************************************************/ // Get the curent virtual desktop. long fromDesktop() { long res = -1; #if defined Q_WS_X11 || defined Q_OS_LINUX || defined Q_OS_OPENBSD || defined Q_OS_NETBSD || defined Q_OS_HURD Display *disp = QX11Info::display(); if (!disp) return res; Atom actual_type; int actual_format; long unsigned nitems; long unsigned bytes; long *data = nullptr; int status; /* QX11Info::appRootWindow() or even RootWindow (disp, 0) could be used instead of XDefaultRootWindow (disp) */ status = XGetWindowProperty (disp, XDefaultRootWindow (disp), XInternAtom (disp, "_NET_CURRENT_DESKTOP", True), 0, (~0L), False, AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes, (unsigned char**)&data); if (status != Success) return res; if (data) { res = *data; XFree (data); } #endif return res; } /*************************/ // Get the desktop of a window. long onWhichDesktop (Window w) { long res = -1; #if defined Q_WS_X11 || defined Q_OS_LINUX || defined Q_OS_OPENBSD || defined Q_OS_NETBSD || defined Q_OS_HURD Display *disp = QX11Info::display(); if (!disp) return res; Atom wm_desktop = XInternAtom (disp, "_NET_WM_DESKTOP", False); Atom type_ret; int fmt_ret; unsigned long nitems_ret; unsigned long bytes_after_ret; long *desktop = nullptr; int status = XGetWindowProperty (disp, w, wm_desktop, 0, 1, False, XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret, (unsigned char**)&desktop); if (status != Success) return res; if (desktop) { res = (long)desktop[0]; XFree (desktop); } #endif return res; } /*************************/ // Adapted from gdk_x11_window_move_to_current_desktop(), // which was defined in gdkwindow-x11.c. void moveToCurrentDesktop (Window w) { #if defined Q_WS_X11 || defined Q_OS_LINUX || defined Q_OS_OPENBSD || defined Q_OS_NETBSD || defined Q_OS_HURD Display *disp = QX11Info::display(); if (!disp) return; Atom type_ret; int fmt_ret; unsigned long nitems_ret; unsigned long bytes_after_ret; long *desktop = nullptr; long *current_desktop; int status = XGetWindowProperty (disp, XDefaultRootWindow (disp), XInternAtom (disp, "_NET_CURRENT_DESKTOP", False), 0, 1, False, XA_CARDINAL, &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret, (unsigned char**)&desktop); if (status != Success) return; if (type_ret == XA_CARDINAL) { XClientMessageEvent xclient; current_desktop = desktop; memset (&xclient, 0, sizeof (xclient)); xclient.type = ClientMessage; xclient.serial = 0; xclient.send_event = True; xclient.window = w; xclient.message_type = XInternAtom (disp, "_NET_WM_DESKTOP", False); xclient.format = 32; xclient.data.l[0] = *current_desktop; xclient.data.l[1] = 0; xclient.data.l[2] = 0; xclient.data.l[3] = 0; xclient.data.l[4] = 0; XSendEvent (disp, XDefaultRootWindow (disp), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient); XFree (current_desktop); } else if (desktop) XFree (desktop); #endif } } FeatherNotes-0.8.0/feathernotes/x11.h000066400000000000000000000022031374721712500173650ustar00rootroot00000000000000/* * Copyright (C) Pedram Pourang (aka Tsu Jan) 2016 * * FeatherNotes 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. * * FeatherNotes 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 . */ #ifndef X11_H #define X11_H #if defined Q_WS_X11 || defined Q_OS_LINUX || defined Q_OS_OPENBSD || defined Q_OS_NETBSD || defined Q_OS_HURD #include #endif namespace FeatherNotes { #if defined Q_WS_X11 || defined Q_OS_LINUX || defined Q_OS_OPENBSD || defined Q_OS_NETBSD || defined Q_OS_HURD long fromDesktop(); #endif long onWhichDesktop (Window w); void moveToCurrentDesktop (Window w); } #endif // X11_H FeatherNotes-0.8.0/fn.pro000066400000000000000000000001171374721712500152430ustar00rootroot00000000000000SUBDIRS += feathernotes TEMPLATE = subdirs CONFIG += qt \ warn_on FeatherNotes-0.8.0/screenshots/000077500000000000000000000000001374721712500164575ustar00rootroot00000000000000FeatherNotes-0.8.0/screenshots/FeatherNotes.png000066400000000000000000002453711374721712500215700ustar00rootroot00000000000000PNG  IHDRy pHYs+ IDATxw\ߦkX@7lϳg+rgEbz! o߼}vfvKHHH$?~"3+@ .,3svN.4 sggF;MB6 1XSl*k\Z wܭ7-*YI^+B rߺh,<{̜ȶ),*LnorOMM&&r: FM+bUG%TW{D1 Z!Fz`c)"@ bYGJB(/bТuuM VV)kONH2j91RBP=%zKuyZ =r6 EyhZCKa!-6~. Hi1I+(,XX&How6A! I2P*z aymD9v޽3朕WW? CճwҳGggl ngnc{uޙzsvXS佻sޗM%@*,Ґ&U@@)~.p amŪQn_˫kܾcEH$3f$m-*~,6af:^^9 & %?5͡)S9i?;vsN˧fҹ/,>~RL OUbaONNyדy=NW&S}M1BXR"0aANf|W% D~Ń؛m"^S_t-/ԝVgӦwWǪ4LU{yܙ:7("ih/9\\"b)P[5xH /P(Q(j~AJdԨ_H;m :o^V$%(z$ׄ$u0O{{3ү#to3 a򫛙ÝޯZYQjm}r/=N%,{آգ 7-MORUf-wMHBvһX#OMUU) qnFT4 OUT#FZCP*IA0\"*KDB&C[Geֽ}߲n.P;3X\uر:2cwp ։A]K-$NR gd<451 WWy49#?gˇ}[@%@v.E5il6@~jcĘFy03zѷ`looP @ޜy39ҵT+~h"sE;٦ʼn\~~Vl(Uz3*9;:H=V 1̀^>ܞI t.MdNZ)AŘuwSE!8.4R7B940JBJ-ih͛N։~-hF7niyiZSΘ1CȍnMnʙڇho\^0yp+ȶMpD$}ĸLu)%qy8S@2rCȒz3}]XϏn9Uɹ Ҽ[D ӯ tu˟K(*TUYSu385nhvv:yoN^J9AA# ZFֺq)`czn5sYٶ դ}Eyꭋr%)?ߟG<$&qdÛR>VeO)Թy3Wwv^`ժw/s36 z_9}_6W\ jkǶ<1g_vq#yA5K1JǓW;=8$@Π"!bD4 BfZꆑ#ѨPR$IallVvPi&feI<#v6ho߾iӦh4 r,Rh`OMH{s^P[&I mD"'HrQF/Ӫ#.B!A ˩Y?N i>)&^pŵbW__KJKt>qڐTNJSZvyw1܂f ~#.Ma:ZLPT͇HVm~DȉEfzQADqGߠ9k9Kl`9H  }n\,`PE;t2^Ur0.6"9ZPR ώyƤBes ŒAYaqҙs֟MvaQW!'(Q?XY0t 5X3IbY"ˑ TTM(YlOe$ŢܵKk=ܱ]n][ֳW+"N 1ǖ,ĩ| Rb}SLvŮٳ=I]c^: |nßeIx vԁ X$3(7mb5d(沋d֜u:yX})Q\1_0d;¡8Y*ce@ X L  onݗUU։M$r29+s.PrQ][׆vj@9H,VwoW#*@I* Q$B\.$IxP&`&'P@gΜ97vXLT|XVuKvJ爈԰ C&;h~a`!H06'_KdGDr8'[ڰɲ'&A3ew.S{ؒ[{XPX]Gx`OʽڀGUܡ>)e|u0g wlC[ˁzI|i_Dq[yt8%N£bnJluB3phc=}_PHVU*df țgޤ_&wvtu9tsOk,$x\$ 5ں-59o;d]tu> ؘ$R£V[BBΘg{KΘT ILafei K& KfO/qƾS~1|UJ3E%RO0tJK[7K?{OIߣé/qRX.Vk lzffL|eQP*UR:-uɡdr|OZerA i4I|>D"x4 KVVr~~>˔jq^b(O̰ ?-G>Zy H{2] Lz1Ieض+xgnoHfEҕ$QueT0vv10-kVv,|$?cd e,&@d|"w݂i^ȴ-g&e@`~ҊdLB|R@rr<PRRX~!O8fko P\` P| aC2 qx v0I#)Qk# /K2tb@JTdA57̎~% I)) ;Õ%`l>gYK'dTFH 7݊qy(fڥPV}Q*QVQRNx:dޖUգ958zUsuv(KDBAT Ȳ܉Ƭ̛le |^@IbR> s3GϟJ,-)mHk699qtIsvvHR\u)ll) NJv9`֖NJ8U ÎJ54g|INf;8P@٤ +3H99@%@XJDʕ(HΛle n-6L$I`Óq̞ҽ2{v|~$[G'8i$NT$& ҿ 'yl )%E*Յ WIReՋYIx;Zdه$l!쥴ZUԤ}5eWc +I=hbN}ePL^ _"+iUy+[Lz\A4"P}ӾNvV?9P RqBŨ4-ssssssNY*R@Rz`A~#@Yc,"w-$fJ7k1'1$Փfk @2JEXoa#s$C3SێE@gR+ PTX$Hs3{mG3۸:ipH Ivq$U:milk" IrpII I;'g&H9)UDJ}h6) $hOf}%V,PИ$$vܴBRωm VC(t-$ڳRRS  (+  @s)/PMT4G(M1Al' `AfO~(1 gG+TH''s$RqbfZ ?) $@ 'aɼc& vs<;j%;2;ٳi)"xye4"M] j2 Ac703lSl'1C)xs5<hCs8$+ XO$Yv ԴRQyIH3030&hkɽ],&j/ߊ~_PQ?9z:T*UNY[e,:Q2B0Z i( n saPy6tdq%&aaII$|yt7c(v6'~ L&9 w==GPx%y@GGQ%/G7'dP)e1[;{jDq:N.y" hlŤHNj}t7}(v6rΕu$s$0$H;D4:MR=X]afMKG(s1ĽyBW6L!;LHœ]\zVǽO?g7ѓ\ڕH* :lI5yWQnBƞ޽vi1zpl{8߻,Xv4$ߺG@746s  I[{6@iLm'ܶ#*8^%쀕=3,ĉI-ENS~ (}3j.Vy,]IבPOM)ۈl _0ݺt f+Xxd;z4UrJd~`vnXO\ u dXՖD|tej٬\$IR4:]BP(*45ѦR8.ō |wU"̪ 9NmΦ߇92͜;K>ދ-(N#l7yDn[ղmjk~{>ȖF/EŘ3JKMOBZ9ܵ [ͩgGmٷkv1v`m->ͱ۷kG?_)[i1>J{W}]+ی>(7-j%_2m=OdSŷ5~y<bڪ 7gKq  b'bkk"qJ%k| br̚7srudIb.AGd[T,+ %_6-=w:l`s\G7/+_|bRZ"~_v?VQyοl}Y;l@.WWyo9TvGܫi$~h99ni'g߳,BWgK!8mhL 'h5|B ;߼xNtc{彖B]GKS'[j|9oErDߊCvHiɘftjժsGr."'^)sز͈YRzC9a 74v'waNL3N\Um1y HvU5/yj[`7οn IJ@K0rp@f3z4)M/ gHUX8..)Vnz{ GTa۰$ާK]KW5Oׯc%o{86Y>c1_?)ML~2ls@Ř B;`_{ m{<Ƕ'Wq=Quin9cF-0LW@`$y|.UHpD0{H9-,Ki$bZ.UC9].,zV6TCUv.+E?y7[svDág/w $":]dhST $xŷ ڵ\>߂$)5CԀC]#_ힸ*;o ,!MZ:hY&WI 0Q QX˱ s2^~bW @4a0dFxXh'[-DA]*d@VEP4@ SK J_*pi I5Ȫڷ8C@ )bH\t@#!& B$)qI-MAVE#&T*un=mRո[O:~qWArѫ]PXX|y F3摑5ޮSV?D * Vff.d׮))6M\neED8. ~&9MLS SM,TRTV*MKT.KK)ܚq8Ǐx@ضmI ^/׭]&g9sh1a p !!*aefLX!EBU݁q2FA3z IDAT.FfL[oX?t5kTP,Xoh9]|K V%(fhhvBGգGZZZ;uE>Ei$"a2mRSS$[t .h;#?QܒVJ7bcׯ]lG?ʖ#`| ø/ǟ;'Ϟ3I2iܚǧ0 _EEn*C+wU78v?ZEWvܬKJJ:wCi~fֽ{+C4"P#\\u8T>?77gϞW--))5z+''kfڹk=;4".Рh4 X,Uk6j1U?EW@ShF}$5>j4ӬdЪQK#h2A#YjLmB 222V\U:jL.##CS_?b4Iю=@RuFN*޽}+5E8F|zPj:ñw>|sˡ^x|BuT]P=III_߾> ǔն*uF-Y[6б+lmm"p-$xs) i TjYj||Zn3`ϟ~ollܬYN޸v{ Ej`!WVV4Ϡ|=bE#RTTwwk۔de8|wo՟;Ax@@UK޹}K#`Aq4rWooi~l٠ؿ6`|F%śJqmHTW{|NApޝw:ӧ*dvHxVYt:}U"p'֭Zd՚>( 8FWHl}C5P.z+n+! WzJ ԬcU)4BHvlk`HЂO&jCB߿6uC. W@mެg[㱵V 2W /DDqk"=#Nk$ecccRfo4fͅ g:vrcIIvuҥ1E5(9Ւ%+]\虜taillQF4 D5Wݩ1Y37''VJUwvФ)=#"ުaUε$c6eʏB2/JuIWڂ^zYllĉ/_>I*oƷRJ\wѠXjX?VRG-ŋg'L0IøG8С<=J7߽{sjD;rAU Gj:r# FSAOT_ |ܬVA6S A"!/?b_~mkkq ,ٸa͇j?q( 0aBN=zhItȑ4k׶v@o߾ǎ 6_"jvVD:$;+KRWS cH sUd0ðC^7;I]1W-UMxe,yƪE]]eee^x5==-"-'1snL&sʼ'J=UO|>EmDPjUyTFR++V gʣ"=g[1֯[5rԘXDGcRBdㆵ;v57ܴq^{9]5i~i$+ ]W9 k6SA>... @Μ>w{4ׯ^tՏHN?$9a⤲O$ Awhz,$1!^jܚ5qP 0um?`.]؟7+II A{eEike:џ|PWW[Re { zt邲Df WtzR]]>EE.[򻋋o߾YKi1#xq7>efàU\KY٪h$٦ ƾ}X3hE**,XzY7Tyw`ײ3*9RlcVv 3lk^y!bKܠĉPȇ&&Ԉ兰D&|Hx~~zksgJ\?Httc9K.r~Iy9*W,?zP'O͘9ǧeQ( =P V2QWenׯ_ZtuZZ iJd 0.`k)M q5Sw@y%nv "M͚[yiHPU8mRmިWeݑ}{?3*K$.W7"9~ 0Q.Qʥ+tb2c8~?*766 !!5e׮\tEUxyڰs[T**h;pА۷oD"DHtNXCC/jD`X{عs۶1{<ؾoeMͫ^`|^+4o޲8.4ˡOowFT5+dܸYhjwj+%P֏UшZTECKJ#\׻7nUfHӥ(EeiQJl^5gVj6g$ Wκ#v,sFhVh9k֯Lk)L <1D?r]xCQrUjO5%5RƎбSgsP$9ⅳ^PADj >wؑ 6: hu4eQΜ9u)K ^ZZ(uqpcs &2ҫrekǪ`:'4) KMFqqCk@4=F澰P'+IL*~r27o/?ouO("jU"+lG # 1 u[N A ZuoUDmO߫Ջ" 0P^RU&8@  !F-㦺6,YzGB YY.f :Q)S$$ b݁ ">=Zh2`IxQ^/"BR֏aZ}:EAשMdUf5@ k( @ ,#=u@ ]Ckh 4^G ķtm P8 IR(idw@ !4ٙk$IF}djj֬Y3 ŋ6qϹ9-[@SY$IX@ 64YfE$I6XW\\cNO&… }l>~/_Hܶ}{ܚŋ1@ 8wd^v/_|WOյkGO8z Hܶ}WO Dwkׯ6]@*2m ~}hh'ݿnU˖.ۻwϢE #޿_dtJX;vןYdÇ_r񂽽=a2@ FLHqI1FӓO40/*y匼wu#Jmٲ!8[o߹}c)-Zޭ#Gq1cƸ200e蘘H<{ȑ#۷o`0ƌqqq*|l6\u 5{G}=}NjKJX,VYbVf~orKJbEI$١/Y% e񧨨(iH$˷-,166hfroCw4E te̙۶m3wo%[YY@ TD3#L&Ⴧe)ُ<ܹ3Je2"H^PP@cu233*ȴڼimnUsjf|8b211NNI/q0 t̙=^zٽ{7 2+ ;vg@ B3ህiSnvق蘘.bh1 -[| ㅅgϜp϶%ɧO uiիܽ{Sc6iRл/_B 8ܹQQQ{mfgkKәLfJj1'xADQQQxx8ˍOHx9zzzzzh2@ ;)(hl'??K_L0^/3ZPb6wΜ:ӼE+Wqܲ^^^֭]bexxxUvvv+;oXqSNҵ_v4 믿5?zX_߹s,_­y ޾W^%p-Zةϟ1s@ 5gϞ۱shB¿yxʊ@ oX !!!=wQF2nnne36@ R'B:dH]HF 큺.aȺGACk[{7R((ACtvZp>9gSl]_\I'k\{{F6j5x\ "g =l~ض](`,--8/TC웳|ˢjA #H8M5k}nm 333P;oPtos3]cî>3.fDOp"^R!FúT5"ϠRo3Z *b7gohHDh='X<= 5*O85'L.p{s_1ƹ9$ܮWmg˩ycu멓[c+\ӂV?| V~=m(䟙aONp|lpӋڑrŲ-LJ_U;Hb dv:]^iIa3{c>5Y GRgq5'k>4^غsP 6D<;p#CK?{-!w.Q5"Ϯ'W>Cƙuc}V\5~ޔ^fګ&2n[_]pTWQ!q3lSgVUAX?w߼#@u|,fcֶs'`[nu{gRIa3{^?6-Udӵ1V,Q8Rȗ|]|#akc,=E pә^Pq4[ ~~kQ lBDs?rywYXSzD™I> gF6tV48]C+řtgΓ[S]To&tQG_)ڞCǯ CjAnpg+2ƭ;J A:k6A}u|.iw?r ݆@Cst&d̽GٍW}rɲ<5=|@@ G ײYi)-@yi𮓈D>_`5*HJt:b*(s[E14<]1oknm)7kSI_~6aO<;}twW#4MG(bT ]"*1Kn.YE"6f[eC؍gB A ?hY,)1Q,c Ic1bd=LbϤke((666::7l{^^^k4knΝ;vco^s\.۷ׯx!&S"F]"yh΁avԳԏEн/Lge 'Ok{" 133Y1X_[MY}$?ҳfjjRDXّu[IvD] H$k#ug?mOȃNOzq1T=ŨȃY _J,] J:laaQ, ~>r x"IT!jijՎ_,E8kkʚ:x˖-OKKѣ5k$ɳΎ9}0fW(T*ϋlnncP&OeL:s_?aw߽H'oЁ'_$ܲM(j8҈2&Bo[sD]?ڷ|MmnmꅨNi 89 9wWωb3SWYU-0]3*H[9]w@(kօLnn*'"^ֶ ]:?\״`(ήk1c$''q_'Q(&{tf0f3g|ݻQ(1W^ Oرʋ@  бnz\\"$ izRb/* ʯ@|B®ݻcb|~|BBS_{q1 ? ù\n|Bqӣ0@ ѝM0XRė)_6ҸBuPڵ/,,\beBBѽE @ 1TÕw7!,?Rfw1A ܑF;F#X'_ߍ)Ehu'CC [#`M #҅8X<ڊ fhDm:} @ @ w G@40(A p@ DD#ի|ϏUDRfB D‘& _|^w-rՃn~]R7C~ر1~gIǎ}7<9'@  gY2sZruO}?20_')?3n_[^.N@ D 8Xj }َnh?xyw#nI *CWEp~@"`ϕ~@ uOhTKYAT [aw iX*ܹAAA|o~O7 7fw/ԐZWgwJbs $˨ՔT .%n2:W{2+a4rCU%?'#_\/"2UN ㉓b^?vVOOW<ouOLOvm'M°Ʒ8=L (r=uyzY| (r`P(Ij>$6` ?Z, S,;M?)P[?U&;~M- k>j':%`lYIP_=g>)' k@̻}# EMcvo|מ}ivY:߻`,-_9R7FPTT>uxB?lǗum\G'yuwqQmgwGU5(%bb/1* kvƮI]XPDwcb-3r p<3Ӷ,U=e>Mf@ m[~7ovqCW幙A8YFCзl]iڵndيL-rtݨ7-]VL} EMqDQ}FT-]rɲJ{M1ӯeԩӹs'׶ME"a`Pgff6mZF 4mrΝ|+_>zhKx%xt^اżz/ߥc>˳M}e:~+:GUߣniTN`{ W th}.CMNd8Vj~ *E$\ϞEl彛3 jtЮnܥwk\^Zo_b.9.:^+/2gyO87[GW:Hqȴm+r6:2lMbvĤg/Gzx`;p͛}r)S&wX(|7pl6[,|a[,V@rr+=zDӴN4hPKyQ׬YӦMmԨN?@sqV1z/q KlzHS:5uMX1C mڱIE;H+ut,|YN1n{Q]^yY&T- >->*껹S/xmF[,@EtKےF?ou`FQ!-VU}qzmۖ˵ѻøqfmGb{X/}}BCQurxtP~SӃ*Cwܹ>bܽs'G<= ts߿޽p4i2Spw@@@@@l޸iӼ];w rED:b@~;Nڋ9owىHEl=1R煉g}\I^Ce1E;rWCi#+ǫ=iХS :y|v$lbx;<{N$ξШ+7c,{WF b7$I8|7re&6 Y1}CJ8WO3 AáCGRI9ϏM!)by7ð<_)$aUVGpK.TT߾]|> 8 I_ٮ}L3 mk /q?VN=fšaeww+ɕtJ7\}RI'| H.hQmƇHxz/^ߘfK'/j {6bvFHJtm;?ˢz&Nb;E_WXw^)s )Tŋ@V֝=׷J1Z Aߎ2ovl76ݽ{ "ч8qĉ6lwOW&93I/T$ɭ[#"4;{,1: GMQ%7%Fj{;wsɷ;zuYr-Xկ2ԟ*Q/M:ZX]D-6KgYcN!nTm7Lwi';o; !VN-Z s-F $zU./ݙ[pc |[h7U^ =r!2l @kTYιᮾAA,! *e0  p R J G  *ee75:bo}]5CAT ynz۳gnNةWq! *uGʕ+w5a4Zm~?L4E6}mAA_Fp8.pa\.o ѳ哒ڶk__noh0p HLջba#A!̘9KX؉D{k^h{FvޭTƍ_˿v~=z/ AW~8'njs+%BUW3 >sѣF}+c'Oɔ =55uѢEn&(_ݻ>RiS7_}8ph4^v5 Aͱ1InNG:uwB0,f};vrrSnŋBCC9N}*UaXRS@ __@}S4 De:qsw?r$IR%=<=0 |L)/pm[7wwsH>Rs}{<|/^x j 2~ LЕvk PÑgʹG&IR{{(p h44M<=r9M٬Q?R3 N(Ny];w$$HL< =;Mi*5E}HHl ZܳglnР>˽{2 ޺mٳgCBBޓGjfX\.W^vM&UZٙac8V6[,"i { I>.TtԋÿkkAnH)x݄o#ۻMd=y(=-T*F.<=8H$p8!Y66A7ʴg@a<^*=!c\guowRjË= q}K^(=|eͅaq=m RTVggIroYvM?nݺU֭,5,kX@TGT;wԹS~_IΈa^%J c0T*-#nbܳY4xK~MN7Llr&aFxSIOi`Ui5}[e״dn4lj3aȢJji ilD/mdL@06#1E.|͠R 0 à,cuIZPfX lLX2duK*_}i2ScŅnbVQ+{b<Ǽ='~tut ֖ծ+=5!S7J#?yZ%%93Ӝc};R}  ϰ}T׶.0}SoR8{8RjzG8!@uno]a dqqqA_Y*k0 s4>> I /_2/PEbZ3;CJNkrpVk IDAT eh- Y*b0DGmz0Ad$؊K01d XeӫuV'0[,s 9K8%:qGC|1e(툲UZJw/7}`ϟ5g_ݘ'G@puP#''~O(G{蕽ĉ3ˈWci3ݱ]YK]#z&gUUELNN$ AqbS7#0UOTII+&06cN(^C"F@( 6 eB&M(Jt:{z:(ޞ7BP6dt]ja ,M$rx<ǁi#UX,0Н7_g G6yЯ" ((u +3X_Ukn#qX/* 9KlD1b77ѻB7AQMJ|8PčEbCYj"?l&@8B'^ ? W$Η_g,xRjJ5"啅\(uek ##vsVʤV4j(EQ`xL] '%VعZ>[M* UqzzvOd=.껥ڶCXHA1<9C`g>}s`85A9N.R2jL&OŁ9b^} (-#hzERG?4IdF./pʤR  U%T^lC)I mQgk17m6{nm#]oUK\:[c"sxbY~oĠ^->suܯ=@q7.uwŜVw>o$(B_N*vUϮ;7ȧ箖Xn]]{(͋G&" dx =C*x3vt〨=9b''+BD^1?j #.`9d6ahJڬQ ˻7{/ŗ9qS-d^a?ĐahÛ,W(uI%hF61\]mjTFFV.wʌV@.rxU–.jQbb]1 V !|o^bUaH%s^V3vkh|+y0?*ddgPsq𚳇|z_ϸ@6;"Fwܙ|xmtE3sL{`(j {mFooo7o&ŋb,X}];wkSRRl6;rB;֭[UzLqҔ^|S> HJP( R4٬T %2rr>>YbTh4CDfBUpT6`&q͛s{w9;9FdWl6[*|ҾQ֐$)H-\reɓ?%K<ީ7oDϋٞgŇ{yyXVJ?O[|'OJrr׭xs/?a@PF\ &!:x; >R$3'k0 wW HW7yƟHH8nP Zj="ݭITҤi "'Nʩ?}$\Ye%a{?|bl^5k[cǎs3%ܹE;YE^^^7UBZZ 00p~cX- qPڠ׬YC t}pCBB.\gճ+x&SyYŋe2~+W6IDQ4l6 lQ4fs|a |0@960il2a8vPݥKX``_|F=OgclAx\.}ZW^p8 `6M&0,7a knԼׯ͚ZXrhY-VЊ,%LhQl4H$N# Gg.Z{F  AYYY_ J82!2rBd$éRS7j貥FEoubdd&.J2!z>$88:z^4Ґ3gaf5EǍ;}̣G]]]jպ}GT>/j "#'fqcVn>;yo\QH)zqT:}Ƭ#)j^=yԺu[CqN: hۦ}6m*Ul[c7?zl| lJ$e͖*YRm0L&SaVZ7ݻf޼yk@ gΔ˕+zjUnܰ^}~B$\|`Zy<6l$g^|nzK/(d T{۶nOOOKMOKTRxg޽K1d6/_mÆV JQVk|r*JH_ J?);b6|ԩs"qK/ltrr?z$kj׮}pޣ箭[lMF\%6lTfl6_RzFfώ|;~h_0aDZ}eիW?ruk||j 6b+9qr~jժ>i:uq(ƍs5j?tҩmcYO>ڭ[)o޾r8l{k}(Ϟ=ѣ#/_bs۰pAd6h0G&ML.3bq۶mɳ0OFFƎ6irҜ,Y7fAh4A( a4M߸qi7|kR(0o(:fG񣟧MFQD$:<6vZdƾ^{qN]RYzzz Ae Gʺ<ƍ뾾5΁JѣK/ѳMyՉc:tV{,EL\6{?xy?sپ1mHQԃ9n B2ߖYVUt:V/ \.`_#Iak޼E@@+B%G4E("0]uSʕvnp0X,D"n{b\\\pP )ӾX,-aY"U*UڷrA}LДŤ:rV(Vd~}|0 +Wst8TbNrRi7 24|\+8*j|b^y"uMtdҩ"zф  J?M\N(Ʀi (0 O\äO]n AAWjb/\\^=G2AAз \굙gƍE" L.aa4|}ˑGy[nƍ_zÚAAP pc9Wb#ٛc/_WWfm۾ATV,'[~!CpY22v?pǏٞԶ]5v~3%pk֮mwLdffFSnlܴ~c}|kop:Q *+#,  2E߿V5&z^ffLl6GN}쬈1<=~]**jnf4MVV# \JHRtws*J.j >… 9ϝ?ݱc.ۯo_r3%ώiio߾9bH$RJ޽O$&o#F]]Z  *|E#o__?7({|LؔJeFFF݃CC֮[gXbqs4iڳg"GARpӿsZ PQ4D*ڷ_t( L&Jp qT"^;d2YfMEGڹS }A{G1Aď-D[K[lcN yŲg^ܠA}KƋ4M\\\VYjiN*3899a HIO ~ic˅ܾ17' ;do͚5EE-YtI5jXxgǏWuVkV^˲K4kjXW>axOOϭ[#"4;{,>_s  (0 j|Cr[Joںu֭[٥o9X|y2[YA@@AW#l8Bfqğ1A}y,n%Υ  J )+& IQz#7/jz htz$Iz }iERv+ *[`8m2Y/_@@@r8It E\V*M&08O4W>ooU֊Nyj9g(k~h0/iNPd劬?r E6Aڼ Vf+r>!`XJG2k i0`Ѣ%*U9cN-Pe2[ZhշfѾu IDATmbr̅@QޱAGBQV")ԉc,{;wA+\.<~z:ww)S&:@PPH]-oz2A_ uykz]H,_/ͮw`6 $Eb(8Mz$) EHq/ V+a4Iq\ H EQb9fdVAQZÇ-)>fZaVիW8Z6++ԜsFqi$)6mz%}YٳZ,_-yT&k٢ݻw` zB- hXl@=qƵGyk~pBp+LF6mO5E"ܨ޽cǟ4Ax{L8޽{~~~?~SV+AtxmڲXKvFX>o߾Un=6sؑS'V+˛8qJW._ *xU|{ErS"') E۲U۷왤ܕl*4/O{k Eϭf$A~Թ;<Ųeܢr\.eZ-d2mݺ0tp߹QHҶoYhV߿\\އHL<ѤIӓ'Z8#J *}$ŕ(| UR/_ӦMvrr)̾d4̘>5&:M붵jlD={1<^^}?OL&DϛۦM;/$E Ǝb`*|[B޽zxVÖ{xDqcG/^Kjt<\11Q{z hjٚ7o2gȉ+V7 r, ԩ{X$];w<|pٲţF;s& r3yщ K* BP0 m4s<={;q:9wd D.V5EVtd!G!IǷT*{7oߪT &4tb1Sp$$t:ŋhκ~j&~]k3vx>_hrEJtwwuZn04mb񠠐&f!IL^]_ erK=zx@B,vZt+6jEQ{iD&H8_}#X,BZ͛7lǏݹs$m/\ I:u$If0  .bD,پ]TV]$Ji?O( (Alλ4a4MQ(j*̷ iiTXi FaϞ] fA`XEV+Սf"E@QFZ9 EQɹ0zf˳`/\(Ç\|)=> OvW/޽өsؽwxLJ#ժU0ʕ+9byJrȱʈ H6wΜ} =$M%$IR_88^bŧOX,HDӴjH%Aly<å(juwsA( fdhisfx~0YB4A(AzZp۷IS66Mdr9|>4V(Z-VNo_ M'"'N)9b}>1b899'<bdzm6i EbBa4jM{[):u)yUMwL4ٳg <l6}63Ss/˗;v <ŋǏ'4lؐb9Be))s6?W>G!X񫓓իWywd\n#4u;wfP܁:\J,vRTN>|@(`fߋa8M77MQ?~0G$b±֭ی=F(fgg9s:1qaB ;;]4pa8<|cl6_v|rkm ɓ'4=|4E z`"P/]svɟ~2~۷45mbyl lq0̩' ۃd}SZƌgGvڵm۶۷[, V`K..ArE= FYxɱpէO1<oΝZ_/_~wYz a3gֵ+`T7n6;~?p`Ŋ/?EQV޽{JZڴiSwo_xtʕ+߿?}@P(IΙ6cSqС}y\.jjZNj7c@}Ak-W Λ7۶-=HӴgq&,^=^0\D>Ka溹uy!I lZ1. &E"H$?ȳ:0Ae=,...8(15lܸqĈs̱_ɫV:{l6m>RÓ'OL&Shhh4M/YWNk3lk*%f n}UC Ο;g5k LRRҤɓn\fnР߷RBC\$IaLKMcy3rׯ_[`3g֭jjaz6~JJ7o-ZHK3AL_N>MZ&bJ%b'FA#ټgϞ0Lv)޽;ڹsGj0 ,K$ٮV^:jHWWʕ+6Db=N:;wxm۴?_$XxQ6h J۴nS^.WF۶ixXXX,xܾcP  0ͩii&\n-6mb/cXFFo\}%1ECT Jc H1QLL:UvB6QJ.P(:t [l{ A.GXV͖t5RYze˖gժUׯH BfzWWۍF#Id2=LF}'fb>1 p݂nnjyl6$i>pX{Vw/I{a4P E˗+o0}WԹD"={n_6o Ui-4qX.m4ڌjBƗFmR$sc"Fbx2w'8 kpl6ر˗b~3gfΜFUΞ;Wjlr/8jDjjښ5k.]ҨQ#ط_vvvVV*׊i>yTܨux{{;yC5j#`|,?fP*u (I-;bi )0&t@A#Gr8 knf3wwaC믛lɔ5͑G̙+ lذ1;;ŋG6!%g6NŊ9ÏW&9} 55KviB3_x25f a HX n^FY   *9l6ɋ- eƍ11y<^Gp&MpѢ-[8޻W9z5 ӷ{5|}>RX$̏;wmۼh>w|dD>n*FʠgQ"bJk']'tj5V C`<A5rD:uLf) ,},n06hB͘ ]LjP*f7<}i2穔6U_A a A_};b4 J4i4' Q'')(E61 嚵朎ic/h@ A1ȓǏR h"H@̀YTA``,,˻;|Lo^! J4JH4? PFNAE@;bggqp-ܝ 3ϼw̛PIl@1E H 0$(!_0EߪIE0,=FT) 0e1\/ HrhL ̎ m`I@wxڈiA ;2f10E.M[9̅)i%T0 EA^  n9#3 \`s:^2+Ac,{ ރr͙;n+Thպo;wW8hĉr_x˗/7b-Z:q$q̝ۤi*N<… {)_bn7dj;ujаȑ; gϩQSuΞ=i׮]0ppj;ȲupL``q,RT"0'+U9a+Ul=j*h;c*{vkfK(ʲ\Juk,_|Ҥɕ+W~y+So |o!s̝;/۷e>_|w˔.A+Wz2㸫W-UUy={]nͫW3vxw*h0mڌRJOx{l A8˲ңg6m'C].`vOp 5keˊx+_z-k8w5q!Þy,+<ߦMkwpʥpӫH۴n{…ɓUUu{ Yo }?zH6 qڴ3APdȄ?z} @|4˨u\7󧦦e>8Դ46*J( }kX۶-[&=&9%Z]iipM~޶Mn{_͚1r?:x蛃vi Ju .W˲n>|챲oFT杭[mܸfS'ݸ~ &NYV /=r;4MK/%'AVQI3*Wtwԁ`lݺ:>#ȿ]ڑ͘ѣ;wd)O3_}flN/V,*w)R$GsUU]zE(oMFݮ4-I,$I4m0a2q\?sEY3F199Y[hQ}4"<)jI\~7|rFOؿOUUϟ?Wb%xKWE| #F:yd*UزeoQU~hي?cŢ /_aQǎ^M37oرgA k?U'%%?REQ*VTnfM?s`U^ca11v\w()Sf䨱ӧMz} bXuO+mݢٻϽ{,UT~Q+V\{Ǐ{vmYQɝ C\\\T*V駟Μ9v,ջw}o 8D/ŊPݠa?sQƥ$h*Vԩ%Y8pHV^ q\}{:nWJ}{ᥪU۷-] qqq?n5nΞ={/3oyd25.siժUKIIvZ Z1Cǎ{nw~WA)n4?ekז.>l6 eNqkX6q!H(RTӴT,..._رSԃ_vah SS3j֭woz_̧hc1k\4qMSC!rdjrjiۮ?A|ZV\j,nћC:|w#Yf.T}G2 9aJ,aخ]2۴n7<1 -z:v:m4KdYP}Ĥ$S֓[lUU~e;χEݺuϿu&{VU5--u58ut:u??sbŏo}d2Nq%{7oVZۅ߰,yKÆ3 0 oiT((SlbU(J(EUݱ}۝=zvpiz Nھ}[(6iҬ_|8EwU6nZC>Xtl6cbb`0~>jM+VJQUm-o Q ȿңKGV묙{1|xzuq3zĉԩ[dɒM5=v?5j4mҤg^ *UP#+6t]ti[111$>FUkd!$Ijذŋ?)Ҟݻ5nˎ,Kj4-IJh~WrVt7^Qd0\E K* F 'pףLNJ۫ HU͚Ȓ mӝ{D$$p_NQ3>;, IDAT~}eʶjfdYRU (ݻvED _zojjj(ouyaY6q0o3 Kq:.4E7vܸYl}O'Ng([WY6DMgϮ[*U2\RӴYUU^/8.B vؚ:|0F A$'~S4M;{ܲ~hl.QV`p߾}=Ͽf#r1MU%ӦKTOx{QF6'O_!`޶]'Mfs׮O8W[,mq\| 6_zo6m5 xvA$IsveC.WرS5$Y쓵-V,aCl\\\ZZZy#sApi=7LIIq8}n߾]~(+Q?=رc 4mtaw1煦i$RcX?׮]عk{nظAS'O̙n߻ +RRR$Q\Ïlܰ񣚦[]s~b=ϯl?b&F$ PUuO+_|y/^P4Y.uC }GYfd$HBI40A`f6 D9 ˎ@CN( .\Xn,Ν\ o:?RET(ƿxĥK={h4fдMStF'ڞݻqӶCdnFp;$I4M۱}[FO?vRA%,9)1/$~/y,W_iE(ÉWnGna>iŋ^p>c E:lPM8RfZVU@"HA7]QXCrA)P:_Y$_A$_P(4~;_ti옑< Վ  P:  H>C  @#nڴcN+_/޽{P <""%ƏԱӞݻسG[l<;G-BUAA Yof~=ڷо}c8KLL2_EAڑK.qפI.  #kGKQjoY0{$ZOòe%JM  ?-$,/ݫ]pE ͚5a'bcc*  E#=he˖l6 r9yAA"ӑW_yeжm[޳&y tAA?^x>&&/2ehU栁Q.  "q]zGlիW^z*  \EA?# XUkޭsD"˲̅$Iƈ̣`ՒA@ ł~#F$CBlHU5 pL&#MܼM4htUU|5eYbAn+@(d4, a,0If)'ſ?iGf$x$̲AY4 L&hT%-)ÇJLJܼiý#r8IMf!G_BA YBQ5b0fΜ]j5UUwloW1rtrRẃ`Y 's<\>,4 ð.EN妴(Ŏ3'qk=rDɒ3g͙ϗ˺{)CQ ^p᧟V?vd*xDJG {Ԃd65t{+VޣWժվ3EQa>Eid2e$Q%Ee ØL&4^^~݃qa -Z^RȴasaM6L$I !eif i_HSYU(CF6,+4ED""ANU f1DȲ$˪#` yYQ5H/jO [DޟyJ7yK`4HMu{i"պUgiJ;z9 YS޶mkjZƍ_eHh|WXq/aفE%ŗvIM7b@8y!% #qqֈ|Γ6ra L\ z$5:1!8OV5n6JFUU`$ȱl#k1qѣgS'O.n(pgNLcƕ,Uja><}m$ŊنOs,U$)))i5/tAU'n/qpCH!lHbOz˕Rrǎ>bTrr[CMaoz'iLU1c6_IWwYwzzc8СY.zUMug7_LF/M#F:wܹ)]f!~c4i3M=`v]UЁ?3ی4>/O4fE,*ea0Z;E;-+E'/,ΌP=a^l]g#lʕ_8=q 4iN҂.V'g )1|^5nΝ޼w8^n wXl!{ph22GG.x~H@SC0 _i)q<$޿s̞x56nڶtُUTv⍛߰^v(, !N&43n_;q\޽?&FO/ـfI #EQ8 x*$0Hޟ4)w@ p ۷i$EQ hga SFE2l&ӵYe,˒$}qꝩ6zZ䤤^sE o1cA8ڻn6Reܹu/_Bm~۹S?̙3uZR5z4꒥Kk=Yz_~Ug| *Dž/I<̘O:y` Сcg.{}ʕ|*Y:^oʕ+GQsFE{pw,RCwǴpFR85k"jլ䓵؏}6j,J,˭Z2L `p{`r"3a-NHȜ ݫ"JQԪd ˖*]f̘QQQphMWNpq`EG0sn/:wyn߾-Mdd6n#R]0y%KlURe5111˗/4irʕbcgϙ۬YU+Wxe}7nܿԩSGlؠajU{ðt,0LE;~̘qp81$IWgɒe4$&\G$^되8^gР!^xaw qן Y~ӡC}2 WV ҫ10bߛ?ے)&$}}_x|^U+Ξ9 -V ϟ  ½/TBa53qAN \Ia^5pt㫯0Ϳm@1cMESygO;Wqf~`,|W_~q[iUʊ ȿ#}F f>& >‹Ǎ}ꩧ lZfW?dɒ /b۶m;D~_\MQ ܪ/#'^'iO'1sL=1+ MS5 @ C%&B`x˪bfm7f{9*h(!wjP19l4Eʹ}鯃p(c i)AmUľ^lVjL^1!k׮m԰AAx={ȩ& Lp0  yE0+ C8B =2m+RqCvF$ߥ\65zUH\AG#:Ьiy>=y,ɟ~̙3j׮Ͳ^{ǔ(Qb٪n߱ޯ^3G<[d`Eo4E57{kV-1JPXKwCSeYs{+M@m#fc)(J@\ދ7h,8evFn #HMDy$ǘsUZu@A+*56Κ4:,as (JFXbm )b( SF~j,IFS.hr8'uKϮ+IJ,ДEZ-xF*>}0knA ( ?=--D0G3Lɒ0 ۵k@ݻwWV-..p$Y8Z<`&oᐨ 7E'8r'FGo߅ZMDYn{`eE'A%>$ jL.k4USyĪF:o3KO>^T45`uMNen)y `͘VFbza5Ut 0il4M74G'YVTq 4U%.I$$Eܦ#56*c"IB(fJRN$p7J 6NV#>ӤI% H)(ȰÇ 0LҥǎTڊ4mҤg^ *UP]ÇᄄoYL'Nw 4U[[7 1ۭ 䲊H ol MT$IBl <08I3Ȣ$ z NR4MmytyAUp6팁ar_r[TVMj4cY IB\XHNP4c`$jI4e)ze|TEhh6Q4Mă| ȅ8^EQIQ4cYhY1[}GPV)\+Rd>Ȇo{14=a&Wgmg,~O?%IQpiT! DI0bc` >FD a8I3`06yZWI40tzJ\0_j̽ \iFRE4EQ4EB|;0Ym\T4($r^ê'?MYYFcGD]Y`+]YI~I@ dEjryS/4ca ω,noC Q~pMpd%U9w'pAyEbNV?6$Y_e7 pdf62MeYV50dV5K2(iiU!s#`-ERy_'Dw{K~f',nr)GnO+cj6׎yl5\AґB4;co 1f5g7M9%'u%f|t7;ٽ @XҀd:a78I}i, %*c l iRf#>6R Ϛ *eiSr+Ud( Vb:){ay^ƌW٪5l85i Hґ‹DlAJ aA3iJPF Gt`2ӡ{N 8cD i##I`| "dgD52DQ:ocf1 д{x6@ 0{ЇףxpB:53gY4-2sl&:ޕamDI\HMMi*Dmw{GAc *"#2m:m JlH ,Tp&Bn5azsaytPȿdY})!_@6: ƱyAf}Am2G&B2ib";}EGY"4T#c8(/ɘMϓLp=ڞMfMI 4:sHs /\ =k!HaґM z|䶯 p4zgNe?O۷mfAB=@vzAqD;"P|XhPUiA 2cPZDf`-_eeϊ?'pa F5i%!\X!LvH6&L)D$;J\ ($p>+fZr8x"`w20C 9c y]740EU>0(/"eI0a88m5Zz`cka_LJ4آ b"%6-) _Aiq rʵk6`+Z{š5k6nOթ3jh{6EF W_]Aj?A))p϶2ejV6jW_Y0f#9n8͑NY##H|5}[a#dZHb)*ʜ?䇂ݻ/֪UW\~_{o׮K.۵ץ %K~#~ d3ztΝv;Eء{qfMZ;Ϣ&oLW(DΨ(I^"Iɤ6NIP&EA$ JjE^zwΝNnѢS`ΨdYzHFA$ J:rZ5kN>#>.|rΘkׯߣ*m۴]ӧOϿRŊ%TFA$ n:۷~F۶m[3PuTXfg9x1}<8we_jXSR\9y~] HjG ֯_c;t^b}yd2MpdvOv(+Rp\C:tOHXGE?|eߟ?w6qᰢ9bKW4?,[rEcp8 N7.Q‰}8e9vGGGgW_k,\zw&p\(AB#^#~Z׳~Z=qa#Nt,ǻxU '&OpŊ= ِ MS&Io1beYiZ4$V,+Džyh|`PPUkԨtΝH~F 6ܼyC.Wj(M&^:97oi5cb9ŕ{ΙW]tǹ\id֓q6*&KEgA 5zM_cЏz=\jՏ& 4LI5Me|xhz:ұcgv$c?IRnj.]r,K֛iTMk֬y^}bcc~5?YeY~;tDiM45kK6lr110zmytɛe_f?N߳iz ^y *$YVKf >|P:^n;CYmVՖyO\||TbRsg6t.Zcqq%KZ`a͛s%=A $%UU!EQUUD Vp׫w`t:6m2a„.W#;tE23o΄ o7I|ɜ7.]!Co;zi7~ ovl6[[WNZ9OTMNNvZ杚li2kJ*E)^>$ ,. vFɲ4`k6nɓ_d﷛S֮ 60۩iSS]Λ80_B_[DI fMhZT(A_s;%_ѷxP7O)(з%)T:$7qdzcǎ!-Zf#>om=z([f߯^d{p v:'=?>b7ިTb~o_SLLrd"ܹiibK:vگ +pСAz-[17k[CMYA~  |s5 DQӬ,-Vktܜ׋ܛ,+@D8.X!C~dfR}j٬Vj7f_A &Mvڵ6((5:trv㌊jִs_iZrr?6[X+@`E@z 2eVY~yrL\(,^&)gޗ/] d ȣVґ/X CYnzWX{'ON:lٲK.͟mQD$1 `e'OҵsuԩRJL[,@V+aօ KjՏz qX0qⲥKNg~6A{77O,_N{u:ͦEI5|帋,VÐw..6O_x ]|Szo)۰w^y*P+0q!KD$зN_Lcy~LĞ˛NtD5o3s ^1o~>J[l;Fen)(]Ys. >}v>/Y&6Ac~DuZi6Gǯ>/bU~I\ѿ{dV g"f&N/ȡ磞>^%nxQUڥT}sוsŽcPvC~ -sA8@yi)Oj=P3RȿWk/Q?=JjM6XÇv0Aw_~(m 2vkfn䋕"{ѱ0`^bʱN>T3L<U0sj2- ؗ??#^q W>0| WjDti蔗?>OHFW+|7?.?wcG?;'666K WM"fNZûm2߸ՎdEwڒ_\ =y+4a3T5E2?60?7fƈ#Xp-&@WoU~熶kΌ?>Þ"[?c*8arA[4 `r&e$ PdEGe ڼfسϖ _iR8td;F)+"_8<~7L͚Up'Ƅ2pjʪPaC!9.H]rPN 4dIdڟ+W&ky [q$QزrcXN5#GގA #M y=^2Xuw*bl—ʇZw.L㈙m6 ܖEm,+W|FI}@*U(_;TT ß^**Vč j$ElQ|  N2TD;劦*U>,8*q '*@mv g$Yo͎(#5z;]c:s ^]q|x'Sqm}cNN}{C^V… v! h}7pDvUP ۵ג^ӏr⨫1ET~ Щ#:݂ʥ\_ڳSm Kڴ/.92J5K?"q-׊/{].v}c&@H!iij>yRc?{z **"ػرF{%Kk{ŮnC:)jᏻٙ7޼t}F[mћm@ e"SڤKt* |yx X =MTH'kR'jl"w/Bq-VRǹK6$@",FMyJ4si7"۾;`oDIs5磘^їi\4$hۉ }ْc{6\u=JQ[${umݺrEdz;mtCo,ҧ?s+_K";tfWkt-&'۷{Ťouikn݊]kT~i`~%iBog"ubgu,@;??+*C^NÇ͛HJJr^oߡW>Ѩr1X9laYqe<)(4]f4PO" kPA014a8ʠ8H*x<+ԧ쨕/2)lvQJ2y"L&3̖}+t]S୦ O]i1Y1G隡e]ҾK?8|kϿx4m<<.]̚a oA9~|V3QuTNmgߍcp]6Qyᶁ :yc\i -QvMݜnցv_ⴎ+`_:}s {NLT4l6cxov yɒǍW\]]۷o'9i98f>:9_YM*dREore]g1;gVrU:'= cԛYB"pŊ _am^xq?IiJ}~{ϸ{Lr=댤D>b ҦIH`DkzH?\V8 wxպ7Wˠ.$b'(VZv}FmmV>E/_k߁;o曦>}L)Q_\BGr@ o!iZHV5r+ܥ Λ@ڎ߇Ww * +6ICsbd4FɞJshAm}a\0R.n#ǔۙs뿜>*M kx?a iZsۺyK/8?L8zy- IDATQڛ/w}o.Z}d2s Zԧ&[@Afg߷莮t_]op"é-rIa8c{Q= |$>0vfUco`8|Gмywqi[$"UZsg޿uuO^X&Ցgf~i%/]J VƋ/Ə߭[;cO_d2=}dΝ bvοv}0cO0qµWFӞ={4L/^_Ǐ}Ç;n#ݿwo˖-2 L `|"v%$!,<^> k6Q!x" \P`<Pl01H*׻=GRRRRtsET9BaBa^hmz iZ W9H[mrb +Q0[5r:B0lF>ڔOkܺOXM HeYSx{z=9eמ˷ Cc7:4MaY»dzR|_f{D83}kO3Pz7F0ϛWW5qU*X=sh O΋4/a8`_uaibcvl3AM6mZ.fB^VM4i0>/qfs}wFoГ$)Qīȿϟ4c3gҹ3A 6(mڐ^2Y(UbŒ5k͚ݾs;LT޽ݻCRk-ڻwC Bf(+'b4E@HF^3O ɲrc6S!^o23p_*R"O9ρ'C͹0Pꐙf0P) jєLЁg JĜ1Yg@(0"̊\d X2E ]!c IFʅ_$?v z.shw-n<Tl9B NGez;Kߨ쓿Dp8-,t:@Ql=fH/f֚~3gFKeӗm3oIb;U*kH1W$J] l*%ӅGԪ+NZdԏ&g,:WLTe22U{o߼ޠa#WP%K|>0 EE&)I%zH(JHH vj(|rVk &BY KQ6% *r>6:Ŗ0L)}xzDK`|XDcY3墎Gb0јǰ+(+e@Pa "OkeEb{c$9a?͔eSW~V[?/KbȏՒhآ`qʴg.K93]@kɦ;٫1Fl=AaZ?"T2~EKU3U/qns"Ro>3KFmqvڃԣX1-ڠ퇧hB H$ZMf@ % LNeyQ%3_^=yC{tA{3:OKkաcxǎT,|u˫.[&Z4o`B_Ю]ܚ4ix{ 8.6\.sX5+VH$:.{k,cHNԱ"<},Fh4BTaMF$ X 6H/͚r| SvH..OQ9lf xrib1_d|xNڨ5"7cKC3qh.a-Xp5Yhpr""IBHH^N|d`E&0&b1@,N&Kr,%'%SL(b d8N b$Vd6Є k/+Ed ;IB![Or0WB2D|&_?/AזؽuMztJ_w%b5xC7ֵvBk?i2 I!}A>bW]gu0H) 3#5DL_\CX4- *{ӅoԞ;cS L{}&/;5ˉx^,;K ڱ}.~J:y(.Nhhi_:Ν; EG/_}iB!7 r'{ڵk:u"]jieM&SpY\տт$Bj'&&\|83Le˖[WwrSVH~`U6v.Fv>>t7d=?-<s WgR\#;xSl_6??-"e%udSÜwsijvq^}~G=ISOl8ޮmŗkV9k7`hw$e͛7Kh.^v~ztFMM6wĄEF 'Lj4l6IOe˖oJ*Ӻ`X㹸x2d5=i0˖-/?lHVs} ʗ-ukTVw?7Y Z#Hܥ3F+<(LPqb0ѤHB0 !819SxOkS*5OUG>oWsf2uߒ|ߪJTpoGz:5|!>>5sI+v*]$ժ7µNNEoEN PrUnӤ}q";n<_nzt>h8C&LM+ zU Ü8qaFe˖5+l`hǏ[>qA5޽}{`a7iZReeu$#M6;s 11ҥJI$#GSKl[n޿x3F&+CR9{ Oљ8, \X8{xDz+%s*%pw 5Z+(dϟ?H/_[=E!!՜+kBB2;/V*> dux78.\7Swn- |T2u@ XlG^oz;2y IRN.Zǁf#E0f BiL& xIIn\l1 ð,KD<h<=af2BN Ø-"^)BljCܬLq5,BQ2 !Rx h 2?K|1D.)ybp 2k3||Em#) ZjLuC3r{_i2P;-=e}1vgtTT$G>pSf>mlޡ+'^(:m+UO?4wѻ3>Лg) $﨩Ǟv) 2 OFE݄UTշ1]]/4]IR*o܈n۶۷o0av*U|ՎD"ӧOV'֭{7V&hݽ۪UZ!'O#HJ@R/[17ݻWܯP(R&&ͦ&Mo߶F5k}5B"rɣC|`8I?O$bbLo^Tō*/dp>"+Re>~Z¹o&Wm`E.P u W(aQȬ]dycNf xY<:cZ:p AM hhKiy ;!HTj`~Cˋ+$ѩ:O sur{^3F h&WGA֤/4]$ؗΦ;{aU[llԸkj5˲qp}i~{j7U$%)׮-,Ձv,1'L?Gl^*G9fݏ>yB?6TBWkG5.js2[Rx50hƔsҽ֣FˈJu^}vaNg&c@1.k6a@ 4>:b܋Afx;t|JAF&M|@ 31J'>;"'0.*xښL@,V=kVժNP@  ęq$jޣG{G{G{ȧQvO fNEFc}X%K޾y}ztJ`08qxyľ@ φ3&%7k# )HZ;@pa cA(ڪT*ј(˲oҴY={ئ͚ϛsau_n]lK- ^+={R7HHH1rdjC֮[G4l߱SO[[xM@|Κ?Q'mvǒu2mz6gYJsmX;^\Ngԩ+V\xQ@@MNyFx#?>huT1qdJfy ʕtbrr҈#}}|ڵkwŋ@ gZG0R+@wBljjezNBV 8|q27 nj-[{G!g^8n=:uY@ ֭l~xzzvŋ{)+e9ҭk2eʸ8оnÇ? A&wvUT_@|vZG>ls0Sȋqxc8J_ٿA)_GSzL9$|ݻ[,#GN4y E}S7(*))yƍvﶗX, Ib=A$4LEkzzzbPT/_ة]lժV`\]]Q@ 第!^]X]s]m0K鹵mF ںE1e,s?О>,M(6ixUKSG{֭rlllv -)9UY) nneʔkvwِM@ 9`Z.Nا,kBKi"᝟iY[h ϔl1LǏHNN+vðݺn߱Zt4˲:ܹs̱VQ- &ts1En6*` Ȟ@ _]yXI)DZE`9@ J:([s:CQtN߽{ݻdsvFT*s$J#g3mxs#9*8^yrww)/W1$ApdB,U&u-02S4&t {\:U$/>o,B,{_Z4*?d2tfpL3Lc} XMLT9MӉtM RT*sȌ@ |7Q!UլQcެ9DRZU0L.aFILJHP&&*U*ЦCRf"u 6UNIJJ6-Rɤ3x<֪ @婐HJLT*aP*Vk/afWW׏JZ*:QT**.t2o]T0qrϞ:tgۥRYUŒT% WRG&J(1k|+)]jG6I2>B5k/\|ƍ(>&`'%dDcάILx.]'l -_Z1څw` XۚU]l6f=.ZoG<|~V-.]p]P(͚3{n6oQo:/\p6o²(Z6A#_ %Jׯ_U`/)SԤsF-QdjϻÈ=znܰ8FIHjY$#,r<)pgBYi$!| 8EYcYP e|T*!IR{z'xlL-Z:tXod(`01 bX MJQ$Iڳýtѿ6Xa؈|$Cԫ[Ç8ިT&dR%b[Ӧ-$RɉGJR G_]t-[nwc2dV,Hr2|e1<{j1AR*%%Օ'ӄa3#..?Ymzaܹ?ſ{@ :wᄄQ[6omBƏ/?rϡZ-$cbn0E˰:`8cǶgNa6nw<~4fByػw*^Ć ʕK}. //oFa) mvFMRԾCr+ܽ{^BQTDDOR^[]v!m5]E6opye[~lV5rċq*5Õ`Yh0%&&d:ujf٬={U9sڨ"Q׮=0 x*޹s{v>bQ__>mz\zUXٳvmcnju]pqqɭ,gıܡCM+ojxM8v[id -? jʖ-yFJ^z㸿vlɢE 0̙SPˋeɓƭZ,ctQFT*JjiYNd 8BJVMNIx{xzz7j}} {xѯO>0aoWnذիSL;fĿϞYV{II*U+)*UJUR^W@_uUTo޸mw)UTR(PDYݳ|5rěOO.YmTj=5zp:mi{۷ɲT*Տ>ݻw=F,`=}O?nnn&)uB,lذqe߽=|J]r~N0LwnܹBԋh4e9wo޹s;UM6KdRY*6oޠh9_v=\3(1n,{&M@.#m.rNFsٌq|9kq]åKtE.hպر=pА͛7U͝ =˖)w)?oC Iu\ٲ?.2$MqW(VZYl7n;bŊuN?CA,Xs;&*T*6}KgϚo޼'#b}vUT)*򀇇Ν;inŊ ?Ys7oXAARijAcƌzLIσ ]]U5o²l\'p/6R_ atN>_BC*T v!!Yڪ'O1W.0֭N]t&2R$Ilۛ$:/^|S2uɓB_Y*<~"E,?Q%%)={JKT*IE,$Aq,].$''wԹsg3[) Љ&W\С#A,۷;w2̹sg;޽=p`ﴩ3˗/^zI:|:U@?օ>bV};&~v3v۶Ϟe\Âx%->/K(dɒwpsSL11;wi |'$q>/J}u…{$a5>$5+W.7iڬf7o(UB _ XB">&GDD۵m;tע#]v/+UѳW^ݺu%Ir„nn3O۽gmw֨ꈈ%>66v;osww }6]bH%RYD=/ /,e2L&@h/#A̞=+99dɒjuj*$M[mҥK$.on :`0r[ƍ,Y痘Y\|&@Px Ο?%Rw^C/<3F! RGhѢȀ4a? :mͭ_j)Z讝=ju{D$''{{{H```FUBre}ڳB A YM,g @A .2:k+@:HA Q u@ D!@ LV~lq|cP k2F1[[5\B YG@2;r$yv٥,_ Oz@;WʹeY62%CPpKxߎ_7a~/&r??'w$@ x$I8#_;欹k"ٺybGLzҾ[g}p:[iQ[]¾srh˲?SdI@䆋H$d@|8?I<[sh^y|bv9/ ā1IxY"^(H8V$d2@bX( >.@|E8a/]7]@X~^(|X.!b$rP(Jb@ Dv@ 9Ш$$/\cǎ+W}+xEǷ'ᘈ~X `aYdA ] k$=j4i҈#vѫW^8|^~0N%[_\CD#LE-uU:S9xx YnHu9s@7G"׈ԑ>;0K!˲'ONII8.oWoa>ƽ anu9,0cYpڍS|f٭#$I s6X%IV@ o '#E,%UTx񢋋 03gΜ5k?"xHr=!S!*ذ7|=_4ma}{ h$bE} {'Ʉ^~Jq~L!ɳLV&v}35'X_túi"ccw{u5Vj:Mf~CӪ4Y=-^س ㄅpa)Ud:zݻe2͛7?.EJɴ1 V.]ĊW yd|o-[=]lݐp,ORZ &륍sumSj9eU-ʬyAZ$/$_β4^(PREU8Cs|OA*RCA@ $Κm۶-XI&jl6AÐH @N IJDYGakNHbq`G7w.?R K}&v$*WƬwwm4>~(nO@ UK.\dɒ͛ɓ'q)nZ^2ɫRܻ_gZVpQliM<Uk:*~@`LHQqZ=9>0iYYU^b_l'A=j_@|8YE$I^eڵyB_M{]yg y j|ݻ}n[")h_XViۜ-'Ɋdpl:ޥ;{5a@]xER=2̍}2=)m,r&'TVǁc@|:-Kرc'Le˖KsF]$@ 8'+=y%o{Lz>aZLB@H]HsAQܞ܍RԣE51 Y*m.HA "#NA;@ ,cG@  Y=@ C @ B#MASTn $/mWt<|4Y""3|'hڨur?$;">V|=w*SskVIAwS8$ZW܎>5ZT+hD0l˸C'!xX˞z/#1ʨظ`^{}Z*57sEPY>;{D, qh1x"Yl юWgҥal1ae~l oW4>{T TTVΘ1sڵ&/_3}ΛwJ&޾}{͚+/_h!JOѝx9!3ny` s(9>d3WRyY-OC7'0"Ϳњpi ߿t),.IhotqݦWO f>NaULwt n>iڕmV=`}riKTt|؝%ujAcݾ]:I}SPul\f,^1{ˢ ǧvSil˃@R&I~=& dLc6r":h ¯e{Mچ ͇ [0cUU):4e$uuܶ(`>޺҇I96eʨB>b4j|ۣc,a*#mm ,s+sӞ?d4DMvSd9FTmF3oNP6&}E2}êxUudYT^)]-sz)?f IY.'w $ cDŁs3||duU1TXt6^_aE8آ"LӝV,Eһ[l5qWcfaa9N(PfJ@˽s|e/) M/`IQ{ZlKt\~'rr]Z`}TI;Fsuo|KFȖa+]HHHA~kG-5 n"^nۺo>)7W={+*D7n'޿~q-h4ڨQ?3bS'OqN}g5256`24Jqtu/`2KSϴ6{bR*s?/9flqς}=|{;vZ9܈+Jzh}tCMxb)fi;|<:ػk)ܪ}}w¨.k!Ǿ6*&>XxltD%륺Ou`yb7o)=<<@kʘ9rg_)&m4EszCi߸.o`g$8(24fBsidE.~*^faayyVqU@% $wsxtb22QGHZom:f-{`V6:" UzyFÅW{'tQӻ W4|J}}=DPZ/R)< \mm]@ (}|_X|IqQq|ݥwrwi {w3𪊊;؈@&KdLjМ8Q?* d. G>qlY,nt#$FG<>JzҥznW-p%yk>.sYAx c 0["nUG3qQkBk1"*NO%{rߋY3"V62A) Ywb5"Q=disFn&uv OyLۅ;.~Sf_ΐ* W/#YD 0dRq+xwΙ9r:WGƒ$,7뤏tx @&(N~eYHOFhI7{xVoen``zTɚ*=4#YažűQѬ>.oEꣂ#7[Vz U|\fWN+++|AcccuM ߙ?#WcҸG Fe5LF@]{ <΋o:ДF󡃍L~Nzkto(Pr^}7Ջgt'ӝU8U_ t2e֨ <*;~f!--7ѾBa0_yw#WJ\.iZd?useI=lD]noqVoT<4qWYo;t0:!v 0YGu3+**gΐ4)pm[w}^2 ΄o wm6-cξ_תLxP&u."N.f.>yHA[mUb5ccUYF!5##UFcSS}dx>fFMMbpqq466޺}kEU$"D"=ب,--}~麻[(5\{y@>VZ^]˥2rv. \&#7۳+&ɑnKg2_( f2:]GAq5ʕϭ\y@m'bpX|z*/J9م> zwt!R./#G'J<j `+$|I-IrZPV[E@KK9}f,E@KK I?$}fOُ/ T*mBdEP(VŖu=rVDI^,0ȠYII9$#eeeǛ @U6v‚0gld\ ɗVE?:kӠsx,()d<~ԁKUu@pڝs>|?8pp`ccsܹ!C/UU.tGRRh4$iT b!miNNs1Ҡ_-H^kZP"| Ih4@^^@\rss4$-(PvyuHN4-$𾰎him-\l_Xw9-q%9|kjJx}= ȶn4,F;:' П&4`Yxo8U!5eUᑹ4i\_ҽXq䋗dgR]5 N\ۉUE7662J}SEp8/OO/ϯ:D7 wȎekFb0;{ezCлE34(:]`ЕM'N49}flB&HAok71*@TiL^bmwÍ@L]W-<.WЦ4G3<үm.P^mm%N c'EH:h,|وI4)y{S{Xόf<ХmQCgcx>D@~k&vvV>x`؆=uV ;O$f⢷H؁;&.7~@qiW8CxДljF0svx'57s)b՘# ҝ$œm x/_.b4}'&I~"NN\ۤ~ lV(w_])e?qz/+>LS(b2 ػvw'*B&\FEӵ31Y8[ykQ+CyY歋U];=O^MM _ZZvM]YY"k>?0=\5C$GXvHi1`jq"T=4H~تވNMP&8H,3OVnnZ]/]'j;Y`ɻ=7dM*s:.n~Sś,eactQ{ô×O'zt{| }N\zn2c" XM&nf.6Am[ hGO1$=sw">vxFt5KD..f(/7^qԽgٷ ))>~{nD011Ԟ;l:d5a6&aP|Ok~ʣy\9@q>, hVxMxhdGm֐7 3xip؇I>}o}U?~tI˰q?9i gz͙O/.fB7^ |4Qo C-D %{|63H?Ioy}ӑ% z~Ξ{#A6X|eD A?/|]A{y]ͧvOoi rz?$u\~zL_aUon8dNn[Gof ͘L[d%m=(.G;`{%3 .kKF=Flߴ&/燆޵ g#4|mONYJlP?ܭM2ޒxe>WN"()ԦUg LKoSv,YVï-RQMMW 0␐#%ONzzɦuuu+l;"bU6Ai!g LaG.OeW~\CR˕! WX޴t?VE񊃫M .5U <˾]G bْ-K-O?ok!S}Ic{O=`a}A ]ҎݕaaoZ/x x96m_j( *rpD?n F-`ScjpZa{?xbSNr/ZcP/ꃓ{hM)ظ7n.V͋*ޥYͅwkdbonGKfq4g~fwߒgm6y͸SCWIQpC'p$%(#w܎:JzAY3wcfvL{OI"= MA5 ~;ZKv2zf ?Ϙ9W u3ٗdt=38_\ԅb 9u_3kҶZ}~d!^xXSVV& \q TRMhS1uOGu8Qu^Lşmo%!aׯ35|]<\HW9`ޕ\KSմ۹8/3@ڡ0B';OK .ul Fġ^:/emc\gX=VOs7ΕMT'@{Č#fȦT1$%Y g?787eԵN$u}G ˑHղ}-`2>5zO6 y 뢪,kAYC[C_(1ЖUiv\ @qz+*+ >K8 Qa6۾.ѳyn۵/xQs\/Wde<+Վ |%}Fh;"@\F5(]3Z~9ݸlw"mtA˅Y. zY;AeFA/0.W"[{l # ڑވ@ 466a7A* /vjGz! TU;A.d @^G 4pU(#AAVAUlbbBGHo$ZEAaQߑިs  =AA3C  JGAPA:=*gX>3vC!F  _3":lli  ˥KOq2$8(4$v/+cR/P2VYK"jhtooB55۶pHtɓE'OlY}JJJ%tߧ$恾>|x]`744t" _1"HPTJ~ $CCCLF$[.*/gQ>-ըYZΘs/^p7! ᐄgN>fUMM̙n޼abbғ! |T$$$|1353d$//ɝAD64'$& >;޼c ?0 GDwd:1(&--wa&%7nܼeKP`@'s|25uzǏu X! ۙ!B¢*((<p8ԡA@ ^MH$PKΥ#aaa.:t*ˡC/?w…Τ# ݎߑ]Qfwaaì:tGH0s UUե˖b!u1k@ 9Ao^OjgMgʱ4( 0h6m))/gϚar Ç[WWl޲%::m4?功555%E#.;Bx*djDoo  h})QRRx=5GcGlgǍ2##"'M)i.M! 3&j̙XE/$b(˂ 3IDATAAIDM{;~srrF!vm|Scc#CCBMMM\;Bjݻwk֮;~h'sJgR&ls֮]c 016aa7 +*_7nA߾,JVOSaHmׯq4R;Rg>@HAAAlllaa!hvvvk0 0mA&FFRS?|KJ~ jT&3PH=fB4b@ߕѿ' AAa-,>wA!%&9rp>hիW?,,,''IOOՕB׉DbYYYEEŴih4_zU__O|}}|]>?f̘#M  JL:BPTUU#"",--uuufeejii%$$͟?<==1 c0QQQ3g6Wddd̝;L& 9s横 ø\nqq+.^8`*>AA>1]7x8pEE$&&>\GGTWWl<?dyyy999[[ۜr,,,d2`HP0 %mttttttJJJzA]ԎBquuꈈ*//iٹJ޽{7==0$PQQ8z"ĖD^^㡮$ H/*/g8\.{xyyy"{^o;&`UQQ27ߌ䔔9s())UWW:teUKn!''G"˕e: tLeү: ''y<Sb2e׭qJڑʤAQ/^cfmm}M===]]].9p@C&yFBB|;;X8pIIIʭ" Hw`XeƏo:L[s= |H<:1#򕕕555$ LLL###l6H4448peVVӧMML}/dggw .p8UTAAׯ)H隚(AA[QQ1(/ &&&Ž-GL4M t$+- #UXNUUeҋ2JVzщʊ  H Љ& .s׮ >?sÇWWUU )wgѵOGGh5644(** OE "C\.U765عkWjj`eq? A+=G>AQQNII Վ  2W[[2/wf{4ipq33Ny BoҊ v_++E2MM-ADJKK;ebb!C>5㥤X? Y1cKJJ^ ~~;AYwxp A['uvg6>|e˛755-]ѣ؟gϞH(3}?{,`m3־s'۷\.W# \nEEŻwocc55i%+W| \S|@ŋ'O6m_]7l0330Lt X"A~xL!aEbXrI'EAQ<^H$jL%^]]=b{uSSSCBBTTzhjut b*bg⹮NEmE]ZR$|%E/ZoBG< LJDA騨(N:m۶;vl[%%'] \D/DHh LMMWZٓQɊѵ^23kA'Q( O)*d@p޽ka 1o@0?GpIQaO(+n*AAqjhXXxxА2ɺhW/^O-ug^^Çw;C4Nd CB# H"|Y>+WZ/ =z|iDӥt߬*(AAz#}}m&بq##- oFDZL&x]":}H=ዼ6tAAjS ~(O;^쨠vڜ|Ԫ ;  !<OJ@`)^rrryyy>td{tvAA>"''pZ܊OݾuBG^^IGGADbJ]`Xl"$dwjAAy󶡁 [mN='Σï]FVe! W@YYŋd@a;I*77?yi*ytϬAA܌ 6]nhh^D"JQﯯ߭vEo;<<%IENDB`